Расширена общая статистика по дням: Отзывы, Календари, Жалобы, Тикеты, Подписки #22

This commit is contained in:
2026-05-27 22:40:03 +03:00
parent 4444461ee3
commit 2dac5e5102
9 changed files with 250 additions and 39 deletions
+22
View File
@@ -3,6 +3,7 @@
-export([create/4, create/5, get_by_id/1, list_by_owner/1, update/2, delete/1]).
-export([count_calendars/0, list_all/0]).
-export([freeze/2, unfreeze/2]).
-export([count_calendars_by_date/2]).
%% ─────────────────────────────────────────────────────────────────
%% Значения по умолчанию для необязательных полей
@@ -152,6 +153,27 @@ freeze(Id, Reason) ->
unfreeze(Id, Reason) ->
update(Id, [{status, active}, {reason, Reason}]).
%%%-------------------------------------------------------------------
%%% @doc Подсчёт календарей, созданных в заданном временном диапазоне.
%%% @end
%%%-------------------------------------------------------------------
-spec count_calendars_by_date(From :: calendar:datetime(), To :: calendar:datetime()) ->
[{{pos_integer(), pos_integer(), pos_integer()}, non_neg_integer()}].
count_calendars_by_date(From, To) ->
All = mnesia:dirty_match_object(#calendar{_ = '_'}),
Filtered = lists:filter(fun(C) -> C#calendar.created_at >= From andalso
C#calendar.created_at =< To end, All),
Counts = lists:foldl(fun(C, Acc) ->
Day = date_part(C#calendar.created_at),
case lists:keyfind(Day, 1, Acc) of
false -> [{Day, 1} | Acc];
{Day, Cnt} -> lists:keyreplace(Day, 1, Acc, {Day, Cnt+1})
end
end, [], Filtered),
lists:sort(Counts).
date_part({{Y,M,D}, _}) -> {Y,M,D}.
%%%===================================================================
%%% ВНУТРЕННИЕ ФУНКЦИИ
%%%===================================================================
+23 -1
View File
@@ -3,6 +3,7 @@
-export([create/4, get_by_id/1, list_all/0, list_by_reporter/1, update_status/3, count_reports/0]).
-export([list_by_target/2, get_count_by_target/2]).
-export([count_reports_by_status/1, count_reports_resolved_by_admin/2, avg_resolution_time/1]).
-export([count_reports_by_date/2]).
%% ─────────────────────────────────────────────────────────────────
%% Значения по умолчанию для необязательных полей
@@ -156,4 +157,25 @@ avg_resolution_time(Status) ->
calendar:datetime_to_gregorian_seconds(R#report.created_at)
|| R <- Reports, R#report.resolved_at /= undefined]),
Total / length(Reports) / 3600.0
end.
end.
%%%-------------------------------------------------------------------
%%% @doc Подсчёт жалоб, созданных в заданном временном диапазоне.
%%% @end
%%%-------------------------------------------------------------------
-spec count_reports_by_date(From :: calendar:datetime(), To :: calendar:datetime()) ->
[{{pos_integer(), pos_integer(), pos_integer()}, non_neg_integer()}].
count_reports_by_date(From, To) ->
All = mnesia:dirty_match_object(#report{_ = '_'}),
Filtered = lists:filter(fun(R) -> R#report.created_at >= From andalso
R#report.created_at =< To end, All),
Counts = lists:foldl(fun(R, Acc) ->
Day = date_part(R#report.created_at),
case lists:keyfind(Day, 1, Acc) of
false -> [{Day, 1} | Acc];
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
end
end, [], Filtered),
lists:sort(Counts).
date_part({{Y,M,D}, _}) -> {Y,M,D}.
+22
View File
@@ -4,6 +4,7 @@
hide/2, unhide/2]).
-export([get_average_rating/2, has_user_reviewed/3]).
-export([count_reviews/0, list_all/0]).
-export([count_reviews_by_date/2]).
%% ─────────────────────────────────────────────────────────────────
%% Значения по умолчанию для необязательных полей
@@ -182,6 +183,27 @@ count_reviews() ->
list_all() ->
mnesia:dirty_match_object(#review{_ = '_'}).
%%%-------------------------------------------------------------------
%%% @doc Подсчёт отзывов, созданных в заданном временном диапазоне.
%%% @end
%%%-------------------------------------------------------------------
-spec count_reviews_by_date(From :: calendar:datetime(), To :: calendar:datetime()) ->
[{{pos_integer(), pos_integer(), pos_integer()}, non_neg_integer()}].
count_reviews_by_date(From, To) ->
All = mnesia:dirty_match_object(#review{_ = '_'}),
Filtered = lists:filter(fun(R) -> R#review.created_at >= From andalso
R#review.created_at =< To end, All),
Counts = lists:foldl(fun(R, Acc) ->
Day = date_part(R#review.created_at),
case lists:keyfind(Day, 1, Acc) of
false -> [{Day, 1} | Acc];
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
end
end, [], Filtered),
lists:sort(Counts).
date_part({{Y,M,D}, _}) -> {Y,M,D}.
%%%===================================================================
%%% ВНУТРЕННИЕ ФУНКЦИИ
%%%===================================================================
+23 -1
View File
@@ -4,6 +4,7 @@
-export([update_status/2, check_expired/0]).
-export([list_subscriptions/0, create_subscription/1, update_subscription/2, delete_subscription/1]).
-export([count_subscription/0]).
-export([count_subscriptions_by_date/2]).
-define(TRIAL_DAYS, 30).
@@ -292,4 +293,25 @@ parse_iso_datetime(Other) -> Other.
%%%-------------------------------------------------------------------
-spec count_subscription() -> non_neg_integer().
count_subscription() ->
mnesia:table_info(subscription, size).
mnesia:table_info(subscription, size).
%%%-------------------------------------------------------------------
%%% @doc Подсчёт подписок, созданных в заданном временном диапазоне.
%%% @end
%%%-------------------------------------------------------------------
-spec count_subscriptions_by_date(From :: calendar:datetime(), To :: calendar:datetime()) ->
[{{pos_integer(), pos_integer(), pos_integer()}, non_neg_integer()}].
count_subscriptions_by_date(From, To) ->
All = mnesia:dirty_match_object(#subscription{_ = '_'}),
Filtered = lists:filter(fun(S) -> S#subscription.created_at >= From andalso
S#subscription.created_at =< To end, All),
Counts = lists:foldl(fun(S, Acc) ->
Day = date_part(S#subscription.created_at),
case lists:keyfind(Day, 1, Acc) of
false -> [{Day, 1} | Acc];
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
end
end, [], Filtered),
lists:sort(Counts).
date_part({{Y,M,D}, _}) -> {Y,M,D}.
+23 -1
View File
@@ -7,7 +7,8 @@
-export([list_by_user/1]).
-export([count_tickets_by_status/1, avg_resolution_time/0, count_tickets_by_admin/2]).
-export([update_ticket/2]).
-export([delete_ticket/1]). % ← для admin_handler_ticket_by_id
-export([delete_ticket/1]).
-export([count_tickets_by_date/2]).
%% ─────────────────────────────────────────────────────────────────
%% Значения по умолчанию для необязательных полей
@@ -248,6 +249,27 @@ count_tickets_by_admin(AdminId, Status) ->
Match = #ticket{assigned_to = AdminId, status = Status, _ = '_'},
length(mnesia:dirty_match_object(Match)).
%%%-------------------------------------------------------------------
%%% @doc Подсчёт тикетов, созданных в заданном временном диапазоне.
%%% @end
%%%-------------------------------------------------------------------
-spec count_tickets_by_date(From :: calendar:datetime(), To :: calendar:datetime()) ->
[{{pos_integer(), pos_integer(), pos_integer()}, non_neg_integer()}].
count_tickets_by_date(From, To) ->
All = mnesia:dirty_match_object(#ticket{_ = '_'}),
Filtered = lists:filter(fun(T) -> T#ticket.first_seen >= From andalso
T#ticket.first_seen =< To end, All),
Counts = lists:foldl(fun(T, Acc) ->
Day = date_part(T#ticket.first_seen),
case lists:keyfind(Day, 1, Acc) of
false -> [{Day, 1} | Acc];
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
end
end, [], Filtered),
lists:sort(Counts).
date_part({{Y,M,D}, _}) -> {Y,M,D}.
%%%===================================================================
%%% ВНУТРЕННИЕ ФУНКЦИИ
%%%===================================================================
+30 -1
View File
@@ -5,7 +5,7 @@
-export([email_exists/1]).
-export([list_users/0]).
-export([block/2, unblock/2]).
-export([count_users/0, count_users_by_date/2, list_all/0]).
-export([count_users/0, count_users_by_date/2, count_pending_users/0, count_pending_users_by_date/2, list_all/0]).
-export([create_bot/2, delete_bot/1]).
%% ─────────────────────────────────────────────────────────────────
@@ -277,6 +277,35 @@ count_users_by_date(From, To) ->
end, [], Filtered),
lists:sort(Counts).
%%%-------------------------------------------------------------------
%%% @doc Количество неподтверждённых пользователей (status = pending).
%%% @end
%%%-------------------------------------------------------------------
-spec count_pending_users() -> non_neg_integer().
count_pending_users() ->
Match = #user{status = pending, _ = '_'},
length(mnesia:dirty_match_object(Match)).
%%%-------------------------------------------------------------------
%%% @doc Подсчёт неподтверждённых пользователей (status=pending) по дням.
%%% @end
%%%-------------------------------------------------------------------
-spec count_pending_users_by_date(From :: calendar:datetime(), To :: calendar:datetime()) ->
[{{pos_integer(), pos_integer(), pos_integer()}, non_neg_integer()}].
count_pending_users_by_date(From, To) ->
All = mnesia:dirty_match_object(#user{_ = '_'}),
Pending = lists:filter(fun(U) -> U#user.status =:= pending end, All),
Filtered = lists:filter(fun(U) -> U#user.created_at >= From andalso
U#user.created_at =< To end, Pending),
Counts = lists:foldl(fun(U, Acc) ->
Day = date_part(U#user.created_at),
case lists:keyfind(Day, 1, Acc) of
false -> [{Day, 1} | Acc];
{Day, C} -> lists:keyreplace(Day, 1, Acc, {Day, C+1})
end
end, [], Filtered),
lists:sort(Counts).
%%%-------------------------------------------------------------------
%%% @doc Выделить из datetime только дату `{Y,M,D}`.
%%% @end