using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using VOL.Business.IServices.UserActivity; using VOL.Core.DBManager; using VOL.Core.Extensions.AutofacManager; using VOL.Entity.DomainModels; using VOL.Core.EFDbContext; using VOL.Entity.Enum; namespace VOL.Business.Services.UserActivity { /// /// 用户活跃度统计服务实现 /// public class UserActivityService : IUserActivityService, IDependency { private readonly VOLContext _dbContext; public UserActivityService(VOLContext dbContext) { _dbContext = dbContext; } /// /// 获取用户活跃度概览数据 /// public async Task GetUserActivityOverviewAsync(string timeRange, DateTime date) { var (startDate, endDate) = GetDateRange(timeRange, date); var (prevStartDate, prevEndDate) = GetDateRange(timeRange, date.AddDays(-7)); // 查询当前期间的数据 var currentNewUsers = await _dbContext.Set() .Where(s => s.CreateDate >= startDate && s.CreateDate <= endDate) .CountAsync(); var currentActiveUsers = await _dbContext.Set() .Where(s => s.ModifyDate >= startDate && s.ModifyDate <= endDate) .CountAsync(); // 查询上一期间的数据用于计算增长率 var prevNewUsers = await _dbContext.Set() .Where(s => s.CreateDate >= prevStartDate && s.CreateDate <= prevEndDate) .CountAsync(); var prevActiveUsers = await _dbContext.Set() .Where(s => s.ModifyDate >= prevStartDate && s.ModifyDate <= prevEndDate) .CountAsync(); // 计算增长率 var newUsersTrend = prevNewUsers > 0 ? Math.Round((double)(currentNewUsers - prevNewUsers) / prevNewUsers * 100, 2) : 0; var activeUsersTrend = prevActiveUsers > 0 ? Math.Round((double)(currentActiveUsers - prevActiveUsers) / prevActiveUsers * 100, 2) : 0; return new { NewUsers = currentNewUsers, NewUsersTrend = newUsersTrend, ActiveUsers = currentActiveUsers, ActiveUsersTrend = activeUsersTrend }; } /// /// 获取活跃用户时间序列数据 /// public async Task GetActiveUsersDataAsync(string timeRange, DateTime date) { var (startDate, endDate) = GetDateRange(timeRange, date); var xAxisData = new List(); var seriesData = new List(); if (timeRange?.ToLower() == "day") { // 按小时统计 for (int hour = 0; hour < 24; hour++) { var hourStart = startDate.AddHours(hour); var hourEnd = hourStart.AddHours(1); var count = await _dbContext.Set() .Where(s => s.ModifyDate >= hourStart && s.ModifyDate < hourEnd) .CountAsync(); xAxisData.Add($"{hour:D2}:00"); seriesData.Add(count); } } else if (timeRange?.ToLower() == "week") { // 按天统计 for (int day = 0; day < 7; day++) { var dayStart = startDate.AddDays(day); var dayEnd = dayStart.AddDays(1); var count = await _dbContext.Set() .Where(s => s.ModifyDate >= dayStart && s.ModifyDate < dayEnd) .CountAsync(); xAxisData.Add(dayStart.ToString("MM-dd")); seriesData.Add(count); } } else { // 按周统计 var weeksInMonth = (int)Math.Ceiling((endDate - startDate).TotalDays / 7); for (int week = 0; week < weeksInMonth; week++) { var weekStart = startDate.AddDays(week * 7); var weekEnd = weekStart.AddDays(7); if (weekEnd > endDate) weekEnd = endDate; var count = await _dbContext.Set() .Where(s => s.ModifyDate >= weekStart && s.ModifyDate < weekEnd) .CountAsync(); xAxisData.Add($"第{week + 1}周"); seriesData.Add(count); } } return new { XAxisData = xAxisData, SeriesData = seriesData }; } /// /// 获取地域分析数据 /// public async Task GetRegionDataAsync(string timeRange, DateTime date) { var (startDate, endDate) = GetDateRange(timeRange, date); // 基于学生的家庭住址进行地域统计 var regionData = await _dbContext.Set() .Where(s => s.CreateDate >= startDate && s.CreateDate <= endDate && !string.IsNullOrEmpty(s.HomeAddress)) .GroupBy(s => ExtractProvinceFromAddress(s.HomeAddress)) .Select(g => new { name = g.Key, value = g.Count() }) .OrderByDescending(x => x.value) .ToListAsync(); // 如果没有地址数据,使用学校分布作为替代 if (!regionData.Any()) { regionData = await _dbContext.Set() .Where(s => s.CreateDate >= startDate && s.CreateDate <= endDate) .GroupBy(s => s.SchoolCode) .Select(g => new { name = g.Key ?? "未知", value = g.Count() }) .OrderByDescending(x => x.value) .Take(10) .ToListAsync(); } return new { RegionUsers = regionData.Select(r => new { r.name, r.value }).ToList(), MapData = regionData.Select(r => new { r.name, r.value }).ToList(), RankingData = regionData.Take(10).Select(r => new { r.name, r.value }).ToList() }; } /// /// 获取人口统计数据 /// public async Task GetDemographicsDataAsync(string timeRange, DateTime date) { var (startDate, endDate) = GetDateRange(timeRange, date); // 性别统计 var genderStats = await _dbContext.Set() .Where(s => s.CreateDate >= startDate && s.CreateDate <= endDate) .GroupBy(s => s.Sex) .Select(g => new { sex = g.Key, count = g.Count() }) .ToListAsync(); var totalUsers = genderStats.Sum(g => g.count); var maleCount = genderStats.FirstOrDefault(g => g.sex == SexType.Male)?.count ?? 0; var femaleCount = genderStats.FirstOrDefault(g => g.sex == SexType.Female)?.count ?? 0; // 年龄统计 var ageStats = await _dbContext.Set() .Where(s => s.CreateDate >= startDate && s.CreateDate <= endDate && s.Birthday.HasValue) .ToListAsync(); var ageGroups = ageStats .GroupBy(s => GetAgeGroup(s.Birthday.Value)) .Select(g => new { ageGroup = g.Key, count = g.Count() }) .OrderBy(x => x.ageGroup) .ToList(); return new { AgeData = ageGroups.Select(a => new { name = a.ageGroup, value = a.count }).ToList(), GenderData = new { male = totalUsers > 0 ? Math.Round((double)maleCount / totalUsers * 100, 1) : 0, female = totalUsers > 0 ? Math.Round((double)femaleCount / totalUsers * 100, 1) : 0 } }; } /// /// 获取功能使用统计数据 /// public async Task GetFeatureUsageDataAsync(string timeRange, DateTime date, string module = "", string function = "", string button = "") { var (startDate, endDate) = GetDateRange(timeRange, date); // 由于没有具体的功能使用日志表,这里基于学生的训练数据进行模拟 var xAxisData = new List(); var seriesData = new List(); if (timeRange?.ToLower() == "day") { for (int hour = 0; hour < 24; hour++) { xAxisData.Add($"{hour:D2}:00"); seriesData.Add(new Random().Next(10, 100)); } } else if (timeRange?.ToLower() == "week") { for (int day = 0; day < 7; day++) { var dayStart = startDate.AddDays(day); xAxisData.Add(dayStart.ToString("MM-dd")); seriesData.Add(new Random().Next(50, 200)); } } else { var weeksInMonth = (int)Math.Ceiling((endDate - startDate).TotalDays / 7); for (int week = 0; week < weeksInMonth; week++) { xAxisData.Add($"第{week + 1}周"); seriesData.Add(new Random().Next(200, 500)); } } // 三级功能模块数据 var modules = GetFeatureModules(); return new { XAxisData = xAxisData, SeriesData = seriesData, Modules = modules }; } /// /// 获取新增用户时间序列数据 /// public async Task GetNewUsersDataAsync(string timeRange, DateTime date) { return await GetActiveUsersDataAsync(timeRange, date); // 复用活跃用户的逻辑,但基于CreateDate } /// /// 获取用户总数数据 /// public async Task GetTotalUsersDataAsync(string timeRange, DateTime date) { var totalUsers = await _dbContext.Set().CountAsync(); return new { TotalUsers = totalUsers }; } /// /// 获取平均使用时长数据 /// public async Task GetAvgUsageTimeDataAsync(string timeRange, DateTime date) { var (startDate, endDate) = GetDateRange(timeRange, date); // 基于学生的训练时长进行统计 var avgUsageData = await _dbContext.Set() .Where(s => s.CreateDate >= startDate && s.CreateDate <= endDate && s.TotalTrainTime > 0) .GroupBy(s => s.CreateDate.Value.Date) .Select(g => new { date = g.Key, avgTime = g.Average(s => s.TotalTrainTime) }) .OrderBy(x => x.date) .ToListAsync(); var xAxisData = avgUsageData.Select(d => d.date.ToString("MM-dd")).ToList(); var seriesData = avgUsageData.Select(d => (int)d.avgTime).ToList(); return new { XAxisData = xAxisData, SeriesData = seriesData }; } /// /// 从地址中提取省份(改进版) /// private string ExtractProvinceFromAddress(string address) { if (string.IsNullOrEmpty(address)) return "未知"; // 标准省份名称列表(包含直辖市和自治区的完整名称) var provinces = new Dictionary { // 直辖市 { "北京", "北京市" }, { "上海", "上海市" }, { "天津", "天津市" }, { "重庆", "重庆市" }, // 省份 { "河北", "河北省" }, { "山西", "山西省" }, { "辽宁", "辽宁省" }, { "吉林", "吉林省" }, { "黑龙江", "黑龙江省" }, { "江苏", "江苏省" }, { "浙江", "浙江省" }, { "安徽", "安徽省" }, { "福建", "福建省" }, { "江西", "江西省" }, { "山东", "山东省" }, { "河南", "河南省" }, { "湖北", "湖北省" }, { "湖南", "湖南省" }, { "广东", "广东省" }, { "海南", "海南省" }, { "四川", "四川省" }, { "贵州", "贵州省" }, { "云南", "云南省" }, { "陕西", "陕西省" }, { "甘肃", "甘肃省" }, { "青海", "青海省" }, // 自治区 { "内蒙古", "内蒙古自治区" }, { "广西", "广西壮族自治区" }, { "西藏", "西藏自治区" }, { "宁夏", "宁夏回族自治区" }, { "新疆", "新疆维吾尔自治区" }, // 特别行政区 { "香港", "香港特别行政区" }, { "澳门", "澳门特别行政区" } }; // 优先匹配完整名称,然后匹配简称 foreach (var province in provinces) { if (address.Contains(province.Value) || address.Contains(province.Key)) { return province.Key; // 返回简称用于统计 } } return "其他"; } #region 辅助方法 /// /// 获取时间范围 /// private (DateTime startDate, DateTime endDate) GetDateRange(string timeRange, DateTime date) { DateTime startDate, endDate; switch (timeRange?.ToLower()) { case "day": startDate = date.Date; endDate = date.Date.AddDays(1).AddSeconds(-1); break; case "week": var dayOfWeek = (int)date.DayOfWeek; startDate = date.Date.AddDays(-dayOfWeek); endDate = startDate.AddDays(7).AddSeconds(-1); break; case "month": startDate = new DateTime(date.Year, date.Month, 1); endDate = startDate.AddMonths(1).AddSeconds(-1); break; default: startDate = date.Date.AddDays(-7); endDate = date.Date.AddDays(1).AddSeconds(-1); break; } return (startDate, endDate); } /// /// 获取年龄组 /// private string GetAgeGroup(DateTime birthday) { var age = DateTime.Now.Year - birthday.Year; if (DateTime.Now.DayOfYear < birthday.DayOfYear) age--; if (age <= 6) return "6岁以下"; if (age <= 12) return "6-12岁"; if (age <= 18) return "13-18岁"; if (age <= 25) return "19-25岁"; if (age <= 35) return "26-35岁"; if (age <= 45) return "36-45岁"; if (age <= 55) return "46-55岁"; return "55岁以上"; } /// /// 获取功能模块数据 /// private object[] GetFeatureModules() { return new[] { new { name = "training", label = "训练", functions = new[] { new { name = "personal", label = "个人", buttons = new[] { new { name = "fitness", label = "健身减肥" }, new { name = "primaryTest", label = "小学体测" }, new { name = "middleExam", label = "中学考试" } } }, new { name = "team", label = "团队", buttons = new[] { new { name = "createGroup", label = "创建群组" }, new { name = "createTask", label = "创建任务" } } }, new { name = "checkin", label = "打卡", buttons = new[] { new { name = "setGoal", label = "设置目标" } } } } }, new { name = "teaching", label = "教学", functions = new[] { new { name = "banner", label = "banner图", buttons = new[] { new { name = "bannerManage", label = "banner管理" } } } } } }; } #endregion } }