|
@@ -54,25 +54,90 @@ namespace molilian.api.Controllers
|
|
|
end = start.AddDays(MaxRangeDays - 1);
|
|
end = start.AddDays(MaxRangeDays - 1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var list = new List<DeeplinkDailyReportRow>();
|
|
|
|
|
var accountName = string.IsNullOrWhiteSpace(channelName)
|
|
var accountName = string.IsNullOrWhiteSpace(channelName)
|
|
|
? "tool"
|
|
? "tool"
|
|
|
: channelName;
|
|
: channelName;
|
|
|
|
|
+ var reportChannels = GetReportChannels(channelName);
|
|
|
|
|
+ var channelNames = reportChannels
|
|
|
|
|
+ .Select(item => item.channel_name)
|
|
|
|
|
+ .ToList();
|
|
|
|
|
+ var channelTotals = channelNames.ToDictionary(
|
|
|
|
|
+ item => item,
|
|
|
|
|
+ _ => 0L,
|
|
|
|
|
+ StringComparer.OrdinalIgnoreCase
|
|
|
|
|
+ );
|
|
|
|
|
+ var dailyRows = new List<DeeplinkDailyReportRow>();
|
|
|
|
|
|
|
|
for (var date = start; date <= end; date = date.AddDays(1))
|
|
for (var date = start; date <= end; date = date.AddDays(1))
|
|
|
{
|
|
{
|
|
|
var dateKey = date.ToString("yyyyMMdd");
|
|
var dateKey = date.ToString("yyyyMMdd");
|
|
|
|
|
+ var channelStats = await GetChannelStatsAsync(reportChannels, dateKey);
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var item in channelStats)
|
|
|
|
|
+ {
|
|
|
|
|
+ channelTotals[item.channel_name] += item.total_count;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var reportDate = date.ToString("yyyy-MM-dd");
|
|
|
var row = new DeeplinkDailyReportRow
|
|
var row = new DeeplinkDailyReportRow
|
|
|
{
|
|
{
|
|
|
- report_date = date.ToString("yyyy-MM-dd"),
|
|
|
|
|
|
|
+ row_key = reportDate,
|
|
|
|
|
+ row_type = "daily",
|
|
|
|
|
+ report_date = reportDate,
|
|
|
total_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:{dateKey}"),
|
|
total_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:{dateKey}"),
|
|
|
success_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:success:{dateKey}"),
|
|
success_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:success:{dateKey}"),
|
|
|
fail_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:fail:{dateKey}")
|
|
fail_count = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:fail:{dateKey}")
|
|
|
};
|
|
};
|
|
|
- list.Add(row);
|
|
|
|
|
|
|
+ row.children = channelStats
|
|
|
|
|
+ .Select(item => new DeeplinkDailyReportRow
|
|
|
|
|
+ {
|
|
|
|
|
+ row_key = $"{reportDate}:{item.channel_name}",
|
|
|
|
|
+ row_type = "channel",
|
|
|
|
|
+ report_date = item.display_name,
|
|
|
|
|
+ channel_name = item.channel_name,
|
|
|
|
|
+ display_name = item.display_name,
|
|
|
|
|
+ total_count = item.total_count,
|
|
|
|
|
+ success_count = item.success_count,
|
|
|
|
|
+ fail_count = item.fail_count
|
|
|
|
|
+ })
|
|
|
|
|
+ .ToList();
|
|
|
|
|
+
|
|
|
|
|
+ dailyRows.Add(row);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var channels = channelTotals
|
|
|
|
|
+ .Where(item => !string.IsNullOrWhiteSpace(channelName) || item.Value > 0)
|
|
|
|
|
+ .OrderByDescending(item => item.Value)
|
|
|
|
|
+ .ThenBy(item => item.Key)
|
|
|
|
|
+ .Select(item => new DeeplinkDailyReportChannel
|
|
|
|
|
+ {
|
|
|
|
|
+ channel_name = item.Key,
|
|
|
|
|
+ display_name = GetDisplayName(reportChannels, item.Key),
|
|
|
|
|
+ total_count = item.Value
|
|
|
|
|
+ })
|
|
|
|
|
+ .ToList();
|
|
|
|
|
+
|
|
|
|
|
+ var activeChannelNames = channels
|
|
|
|
|
+ .Select(item => item.channel_name)
|
|
|
|
|
+ .ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var row in dailyRows)
|
|
|
|
|
+ {
|
|
|
|
|
+ row.children = (row.children ?? new List<DeeplinkDailyReportRow>())
|
|
|
|
|
+ .Where(item => activeChannelNames.Contains(item.channel_name))
|
|
|
|
|
+ .OrderByDescending(item => item.total_count)
|
|
|
|
|
+ .ThenBy(item => item.channel_name)
|
|
|
|
|
+ .ToList();
|
|
|
|
|
+
|
|
|
|
|
+ if (!row.children.Any())
|
|
|
|
|
+ {
|
|
|
|
|
+ row.children = null;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- list = list.OrderByDescending(item => item.report_date).ToList();
|
|
|
|
|
|
|
+ var list = dailyRows
|
|
|
|
|
+ .OrderByDescending(item => item.report_date)
|
|
|
|
|
+ .ToList();
|
|
|
|
|
|
|
|
var summary = new DeeplinkDailyReportSummary
|
|
var summary = new DeeplinkDailyReportSummary
|
|
|
{
|
|
{
|
|
@@ -88,18 +153,133 @@ namespace molilian.api.Controllers
|
|
|
list,
|
|
list,
|
|
|
count = list.Count,
|
|
count = list.Count,
|
|
|
summary,
|
|
summary,
|
|
|
|
|
+ channels,
|
|
|
maxRangeDays = MaxRangeDays
|
|
maxRangeDays = MaxRangeDays
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ private static List<DeeplinkDailyReportChannel> GetReportChannels(string channelName)
|
|
|
|
|
+ {
|
|
|
|
|
+ var channels = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
+
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var rules = new DBContext.Table("deeplink_parse_rule")
|
|
|
|
|
+ .Where("status=@status", new { status = 1 })
|
|
|
|
|
+ .Select<DeeplinkParseRuleDTO>();
|
|
|
|
|
+ if (rules != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (var rule in rules)
|
|
|
|
|
+ {
|
|
|
|
|
+ AddChannel(channels, rule.channel_name, rule.name);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch
|
|
|
|
|
+ {
|
|
|
|
|
+ // Channel names are display metadata. Redis statistics remain usable if this lookup fails.
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!string.IsNullOrWhiteSpace(channelName))
|
|
|
|
|
+ {
|
|
|
|
|
+ AddChannel(channels, channelName, channelName);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (var name in Enum.GetNames(typeof(TkChannelEnum)))
|
|
|
|
|
+ {
|
|
|
|
|
+ AddChannel(channels, name, name);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return channels
|
|
|
|
|
+ .OrderBy(item => item.Key)
|
|
|
|
|
+ .Select(item => new DeeplinkDailyReportChannel
|
|
|
|
|
+ {
|
|
|
|
|
+ channel_name = item.Key,
|
|
|
|
|
+ display_name = item.Value
|
|
|
|
|
+ })
|
|
|
|
|
+ .ToList();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static void AddChannel(
|
|
|
|
|
+ Dictionary<string, string> channels,
|
|
|
|
|
+ string channelName,
|
|
|
|
|
+ string displayName
|
|
|
|
|
+ )
|
|
|
|
|
+ {
|
|
|
|
|
+ if (string.IsNullOrWhiteSpace(channelName)) return;
|
|
|
|
|
+
|
|
|
|
|
+ var normalizedChannel = channelName.Trim();
|
|
|
|
|
+ if (normalizedChannel.Equals("all", StringComparison.OrdinalIgnoreCase)) return;
|
|
|
|
|
+ if (normalizedChannel.Equals("tool", StringComparison.OrdinalIgnoreCase)) return;
|
|
|
|
|
+ if (normalizedChannel.Equals("unknown", StringComparison.OrdinalIgnoreCase)) return;
|
|
|
|
|
+
|
|
|
|
|
+ var normalizedDisplay = string.IsNullOrWhiteSpace(displayName)
|
|
|
|
|
+ ? normalizedChannel
|
|
|
|
|
+ : displayName.Trim();
|
|
|
|
|
+
|
|
|
|
|
+ if (!channels.ContainsKey(normalizedChannel) ||
|
|
|
|
|
+ channels[normalizedChannel].Equals(normalizedChannel, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
+ {
|
|
|
|
|
+ channels[normalizedChannel] = normalizedDisplay;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static string GetDisplayName(
|
|
|
|
|
+ List<DeeplinkDailyReportChannel> channels,
|
|
|
|
|
+ string channelName
|
|
|
|
|
+ )
|
|
|
|
|
+ {
|
|
|
|
|
+ return channels
|
|
|
|
|
+ .FirstOrDefault(item => item.channel_name.Equals(
|
|
|
|
|
+ channelName,
|
|
|
|
|
+ StringComparison.OrdinalIgnoreCase
|
|
|
|
|
+ ))
|
|
|
|
|
+ ?.display_name ?? channelName;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static async Task<List<DeeplinkDailyReportChannel>> GetChannelStatsAsync(
|
|
|
|
|
+ List<DeeplinkDailyReportChannel> channels,
|
|
|
|
|
+ string dateKey
|
|
|
|
|
+ )
|
|
|
|
|
+ {
|
|
|
|
|
+ var tasks = channels.Select(async channel => new
|
|
|
|
|
+ DeeplinkDailyReportChannel
|
|
|
|
|
+ {
|
|
|
|
|
+ channel_name = channel.channel_name,
|
|
|
|
|
+ display_name = channel.display_name,
|
|
|
|
|
+ total_count = await TkLogCore.GetTotalAsync($":parse_total:{channel.channel_name}:{dateKey}"),
|
|
|
|
|
+ success_count = await TkLogCore.GetTotalAsync($":parse_total:{channel.channel_name}:success:{dateKey}"),
|
|
|
|
|
+ fail_count = await TkLogCore.GetTotalAsync($":parse_total:{channel.channel_name}:fail:{dateKey}")
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ var results = await Task.WhenAll(tasks);
|
|
|
|
|
+ return results.ToList();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public class DeeplinkDailyReportChannel
|
|
|
|
|
+ {
|
|
|
|
|
+ public string channel_name { get; set; } = string.Empty;
|
|
|
|
|
+ public string display_name { get; set; } = string.Empty;
|
|
|
|
|
+ public long total_count { get; set; } = 0;
|
|
|
|
|
+ public long success_count { get; set; } = 0;
|
|
|
|
|
+ public long fail_count { get; set; } = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public class DeeplinkDailyReportRow
|
|
public class DeeplinkDailyReportRow
|
|
|
{
|
|
{
|
|
|
|
|
+ public string row_key { get; set; } = string.Empty;
|
|
|
|
|
+ public string row_type { get; set; } = "daily";
|
|
|
public string report_date { get; set; } = string.Empty;
|
|
public string report_date { get; set; } = string.Empty;
|
|
|
|
|
+ public string channel_name { get; set; } = string.Empty;
|
|
|
|
|
+ public string display_name { get; set; } = string.Empty;
|
|
|
public long total_count { get; set; } = 0;
|
|
public long total_count { get; set; } = 0;
|
|
|
public long success_count { get; set; } = 0;
|
|
public long success_count { get; set; } = 0;
|
|
|
public long fail_count { get; set; } = 0;
|
|
public long fail_count { get; set; } = 0;
|
|
|
|
|
+ public List<DeeplinkDailyReportRow>? children { get; set; }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public class DeeplinkDailyReportSummary
|
|
public class DeeplinkDailyReportSummary
|