From 977b3a8a7e1b301b0653174b2d17c82293a9b2cb Mon Sep 17 00:00:00 2001 From: zpc Date: Wed, 4 Dec 2024 14:00:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppExtend/AppRequestConfig.cs | 2 +- .../Cache/CloudGamingCache.cs | 18 +- .../Cache/Special/AppConfigEntityCache.cs | 40 ++++ .../Cache/Special/GameEntityCache.cs | 22 ++- .../Cache/Special/ProductCacheEntityCache.cs | 4 +- .../Special/RedemptionCodeEntityCache.cs | 4 +- .../Cache/Special/SevenDayEntityCache.cs | 4 +- .../Config/AppConfigBLLExtend.cs | 101 ++-------- .../CloudGaming.Code/Monitor/MonitorBLL.cs | 14 +- .../Monitor/MonitorProcessor.cs | 3 +- .../Monitor/OrderMonitorProcessor.cs | 174 ++++++++++------ .../CloudGaming.DtoModel/AppConfigCache.cs | 186 ++++++++++++++++++ .../Db/Db_Ext/CloudGamingCBTContext.cs | 142 ++++++++++++- .../Db/Db_Ext/T_App_Channel.cs | 38 ++++ .../Db/Db_Ext/T_App_Config.cs | 47 +++-- .../Db/Db_Ext/T_Statistics_GameHour.cs | 58 ++++++ .../Db/Db_Ext/T_Statistics_OrderHour.cs | 58 ++++++ .../Db/Db_Ext/T_Statistics_UserHour.cs | 53 +++++ .../CacheHelper/CommonDataEntityCache.cs | 28 ++- .../Redis/RedisConnection.cs | 4 +- 20 files changed, 801 insertions(+), 199 deletions(-) create mode 100644 src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs create mode 100644 src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigCache.cs create mode 100644 src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Channel.cs create mode 100644 src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_GameHour.cs create mode 100644 src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_OrderHour.cs create mode 100644 src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_UserHour.cs diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs index 41df7bf..c86de6e 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs @@ -66,7 +66,7 @@ namespace CloudGaming.Code.AppExtend { if (!httpRequest.Headers.TryGetValue("Version", out var _version)) { - _version = "1.0.0"; + _version = "1.0.1"; } version = _version; } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs index 49063cd..b8b6522 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/CloudGamingCache.cs @@ -1,6 +1,7 @@ using AutoMapper; using CloudGaming.Code.Cache.Special; +using CloudGaming.DtoModel; using CloudGaming.DtoModel.Game; using CloudGaming.DtoModel.Mall; using CloudGaming.DtoModel.RedemptionCode; @@ -54,12 +55,23 @@ namespace CloudGaming.Code.Cache #region 配置缓存表 - private CommonDataEntityCache? _appConfigCache; + private CommonDataEntityCache? _appConfigCache; /// /// 配置缓存列表 /// - public List AppConfigList => GetCacheList(ref _appConfigCache); + public List AppConfigList + { + get + { + if (_appConfigCache == null) + { + _appConfigCache = new AppConfigEntityCache(_gamingBase.Dao, _gamingBase.RedisCache, _gamingBase.Mapper, _gamingBase.AppConfig); + } + return _appConfigCache.DataList ?? new List(); + } + } + #endregion @@ -261,7 +273,7 @@ namespace CloudGaming.Code.Cache /// /// 获取实体缓存 /// - public static CommonDataEntityCache GetDataEntityCache(CloudGamingBase cloudGamingBase, Expression>? expWhere = null, int cacheTime =36000) where T : class + public static CommonDataEntityCache GetDataEntityCache(CloudGamingBase cloudGamingBase, Expression>? expWhere = null, int cacheTime = 36000) where T : class { var typeLock = typeof(T); var namespaceKey = typeLock.Namespace; diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs new file mode 100644 index 0000000..9981715 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/AppConfigEntityCache.cs @@ -0,0 +1,40 @@ +using AutoMapper; + +using CloudGaming.AppConfigModel; +using CloudGaming.Code.DataAccess; +using CloudGaming.DtoModel; +using CloudGaming.DtoModel.Game; + +using HuanMeng.DotNetCore.CacheHelper; +using HuanMeng.DotNetCore.Redis; + +using StackExchange.Redis; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.Cache.Special +{ + /// + /// + /// + /// + /// + /// + /// + public class AppConfigEntityCache(DAO dao, IDatabase database, IMapper mapper, AppConfig appConfig) : RedisDataEntityCache(database, 0) + { + public override string key => $"cache:appconfig:list"; + + public override List GetDataList() + { + var list = dao.DaoExt.Context.T_App_Config.ToList(); + var appList = mapper.Map>(list); + return appList; + + } + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs index e912c4f..d2809fa 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/GameEntityCache.cs @@ -4,6 +4,7 @@ using Bogus; using CloudGaming.Code.Config; using CloudGaming.Code.DataAccess; +using CloudGaming.DtoModel; using CloudGaming.DtoModel.Game; using CloudGaming.GameModel.Db.Db_Game; @@ -38,23 +39,24 @@ namespace CloudGaming.Code.Cache.Special var gameCbtList = dao.DaoPhone.Context.T_GameCBT.AsNoTracking().Where(it => it.IsOnline).ToList() ?? new List(); var gameListDict = dao.DaoGame.Context.T_Game_List.AsNoTracking().ToDictionary(g => g.GameId); var gameChildList = dao.DaoGame.Context.T_Game_ChildList.AsNoTracking().ToList(); - var gameTypesDict = dao.DaoGame.Context.T_Game_Types.AsNoTracking().ToDictionary(type => type.TypeId); var gameTagsDict = dao.DaoGame.Context.T_Game_Tags.AsNoTracking().ToDictionary(tag => tag.TagId); //游戏分享头像 var gameUserShare = dao.DaoGame.Context.T_Game_UserShare.AsNoTracking().GroupBy(it => it.GameId).ToDictionary(it => it.Key, it => it.Last().NickName); - var appConfig = dao.DaoExt.Context.T_App_Config.AsNoTracking().Where(it => it.ConfigType == 3).ToList(); - var config = appConfig.GetAppConfig(3, 1, null); + //默认游戏钻石消耗 var defaultConsumeDiamondNumHour = 0; - if (!string.IsNullOrEmpty(config?.ConfigValue)) + var appConfig = dao.DaoExt.Context.T_App_Config.AsNoTracking().Where(it => it.ConfigType == 3).ToList(); + if (appConfig != null && appConfig.Count > 0) { - int.TryParse(config?.ConfigValue, out defaultConsumeDiamondNumHour); - } - //var lorem = new Bogus.DataSets.Lorem(locale: "zh_CN"); - var faker = new Faker("zh_CN"); - //f.r + var appConfigList = mapper.Map>(appConfig); + var config = appConfigList.GetAppConfig(3, 1, null); - //lorem. + if (!string.IsNullOrEmpty(config?.ConfigValue)) + { + int.TryParse(config?.ConfigValue, out defaultConsumeDiamondNumHour); + } + } + var faker = new Faker("zh_CN"); var gameInfos = gameCbtList .Where(gameCbt => gameListDict.ContainsKey(gameCbt.GameId)) .Select(gameCbt => diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs index 3f5a9ef..85de7c5 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/ProductCacheEntityCache.cs @@ -23,9 +23,9 @@ namespace CloudGaming.Code.Cache.Special; /// /// /// -public class ProductCacheEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, GameEntityCache.GameEntityCacheLock, 60 * 60 * 12) +public class ProductCacheEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, 60 * 60 * 12) { - public override string key => "App:Product"; + public override string key => "cache:Product:list"; /// /// diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs index 6561337..d8f2310 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/RedemptionCodeEntityCache.cs @@ -22,7 +22,7 @@ namespace CloudGaming.Code.Cache.Special; /// /// /// -public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, GameEntityCache.GameEntityCacheLock, 60 * 60 * 1) +public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database,60 * 60 * 1) { public override List GetDataList() { @@ -47,5 +47,5 @@ public class RedemptionCodeEntityCache(DAO dao, IDatabase database, IMapper mapp return sevenDayCache; } - public override string key => "App:RedemptionCode"; + public override string key => "cache:RedemptionCode:list"; } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs index 2e1e665..11eaea9 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Cache/Special/SevenDayEntityCache.cs @@ -22,7 +22,7 @@ namespace CloudGaming.Code.Cache.Special; /// /// /// -public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, GameEntityCache.GameEntityCacheLock, 60 * 60 * 24 * 7) +public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : RedisDataEntityCache(database, 60 * 60 * 24 * 7) { public override List GetDataList() { @@ -47,5 +47,5 @@ public class SevenDayEntityCache(DAO dao, IDatabase database, IMapper mapper) : return sevenDayCache; } - public override string key => "App:SevenDay"; + public override string key => "cache:SevenDay:list"; } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs index 986c724..de6ef8a 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs @@ -1,3 +1,5 @@ +using CloudGaming.DtoModel; + using System; using System.Collections.Generic; using System.Linq; @@ -18,24 +20,14 @@ public static class AppConfigBLLExtend /// /// /// - public static bool GetAppIsChecking(this List app_Configs, AppRequestConfig appRequestInfo) + public static bool GetAppIsChecking(this List app_Configs, AppRequestConfig appRequestInfo) { var config = GetAppConfig(app_Configs, 7, 1, appRequestInfo); - if (config == null || string.IsNullOrEmpty(config.ConfigValue)) + if (config == null) { return false; } - - var version = config.ConfigValue.Replace(".", ""); - if (!int.TryParse(version, out int versionNum)) - { - return false; - } - if (appRequestInfo.VersionNum >= versionNum) - { - return config.IsShow; - } - return false; + return config.IsEnabled; } /// @@ -46,9 +38,9 @@ public static class AppConfigBLLExtend /// /// /// - public static T_App_Config GetAppConfig(this List app_Configs, int cfgType, int cfgId, AppRequestConfig? appRequestInfo) + public static AppConfigCache GetAppConfig(this List app_Configs, int cfgType, int cfgId, AppRequestConfig? appRequestInfo) { - var list = GetAppCfgList(app_Configs, cfgType, cfgId, appRequestInfo?.Channel, appRequestInfo?.Platform, appRequestInfo?.Continent, appRequestInfo?.CountryName); + var list = GetAppCfgList(app_Configs, cfgType, cfgId, appRequestInfo?.Channel, appRequestInfo?.Platform, appRequestInfo.VersionNum, appRequestInfo?.Continent, appRequestInfo?.CountryName); return list.FirstOrDefault(); } @@ -60,9 +52,9 @@ public static class AppConfigBLLExtend /// /// /// - public static List GetAppCfgList(this List app_Configs, int cfgType, int cfgId, AppRequestConfig appRequestInfo) + public static List GetAppCfgList(this List app_Configs, int cfgType, int cfgId, AppRequestConfig appRequestInfo) { - return GetAppCfgList(app_Configs, cfgType, cfgId, appRequestInfo.Channel, appRequestInfo.Platform, appRequestInfo.Continent, appRequestInfo.CountryName); + return GetAppCfgList(app_Configs, cfgType, cfgId, appRequestInfo.Channel, appRequestInfo.Platform, appRequestInfo.VersionNum, appRequestInfo.Continent, appRequestInfo.CountryName); } /// @@ -73,80 +65,27 @@ public static class AppConfigBLLExtend /// /// /// + /// /// /// /// - public static List GetAppCfgList(this List app_Configs, int cfgType, int cfgId, string bossId, string plat = "", string continent = "", string countryName = "") + public static List GetAppCfgList(this List app_Configs, int cfgType, int cfgId, string bossId, string plat = "", int appVersion = 0, string continent = "", string countryName = "") { //有很多老配置,没有appid的参与 var lst = app_Configs.Where(it => it.ConfigType == cfgType && it.ConfigId == cfgId).ToList(); - #region 计算地区、国家 - if (!string.IsNullOrEmpty(continent)) - { - var tempList = lst.Where(it => !string.IsNullOrEmpty(it.Continent) && (it.Continent + ",").Contains(continent + ",")).ToList(); - if (tempList == null || tempList.Count == 0) - { - tempList = lst.Where(it => string.IsNullOrEmpty(it.Continent)).ToList(); - } - lst = tempList; - } - else - { - lst = lst.Where(it => string.IsNullOrEmpty(it.Continent)).ToList(); - } + // 计算地区、国家 + lst = lst.Where(it => it.IsContinentMatch(continent)).ToList(); + lst = lst.Where(it => it.IsCountryNameMatch(countryName)).ToList(); + // 计算平台 + lst = lst.Where(it => it.IsPlatformMatch(plat)).ToList(); - if (!string.IsNullOrEmpty(countryName)) - { - var tempList = lst.Where(it => !string.IsNullOrEmpty(it.CountryName) && (it.CountryName + ",").Contains(countryName + ",")).ToList(); - if (tempList == null || tempList.Count == 0) - { - tempList = lst.Where(it => string.IsNullOrEmpty(it.CountryName)).ToList(); - } - lst = tempList; - } - else - { - lst = lst.Where(it => string.IsNullOrEmpty(it.CountryName)).ToList(); - } - #endregion - - #region 计算平台 - - if (!string.IsNullOrEmpty(plat)) - { - var tempList = lst.Where(a => a.Plat != null && a.Plat == plat).ToList(); - if (tempList == null || tempList.Count == 0) - { - tempList = lst.Where(a => a.Plat == null || string.IsNullOrEmpty(a.Plat)).ToList(); - } - lst = tempList; - } - else - { - lst = lst.Where(a => a.Plat == null || string.IsNullOrEmpty(a.Plat)).ToList(); - } - #endregion - #region 计算渠道号 - if (!string.IsNullOrEmpty(bossId)) - { - - - var lsts = lst.Where(a => a.BossId != null && (a.BossId == bossId || a.BossId.Contains(bossId))).ToList(); - if (lsts == null || lsts.Count == 0) - { - lsts = lst.Where(it => it.BossId == null || string.IsNullOrEmpty(it.BossId)).ToList(); - } - lst = lsts; - - } - else - { - lst = lst.Where(it => it.BossId == null || string.IsNullOrEmpty(it.BossId)).ToList(); - } - #endregion + // 计算版本号 + lst = lst.Where(it => it.IsAppVersion(appVersion)).ToList(); + // 计算渠道号 + lst = lst.Where(it => it.IsChannelIdMatch(bossId)).ToList(); return lst; } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorBLL.cs index fa65a5c..0ad2a5c 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorBLL.cs @@ -55,7 +55,7 @@ public class MonitorBLL : CloudGamingBase List userLogin = new List(); List userRegistr = new List(); List userActive = new List(); - + var nowDay = int.Parse(DateTime.Now.ToString("yyyyMMdd")); while (curr <= endDate) { int day = int.Parse(curr.ToString("yyyyMMdd")); @@ -68,9 +68,20 @@ public class MonitorBLL : CloudGamingBase StatisticsDto _UserLogin = new StatisticsDto(currDateStr, 0, "全部"); StatisticsDto _userRegistr = new StatisticsDto(currDateStr, 0, "全部"); StatisticsDto _userActive = new StatisticsDto(currDateStr, 0, "全部"); + if (day == nowDay) + { + var m = AppConfig.GetAppMonitorInfo(); + _UserLogin.Value += m.TodayLoggedInUsers; + _userRegistr.Value += m.TodayRegisteredUsers; + _userActive.Value += 0; + + } foreach (var _channel in channels) { + + var item = _Statistics_Users.FirstOrDefault(it => it.Channel == _channel); + if (item == null) { item = new T_Statistics_User(); @@ -80,7 +91,6 @@ public class MonitorBLL : CloudGamingBase _userActive.Value += item.ActiveCount; //item.ActiveCount statisticsDtoUserList.Add(new StatisticsDto(currDateStr, item.LoginCount, item.Channel)); - statisticsDtoRegistrList.Add(new StatisticsDto(currDateStr, item.RegistrCount, item.Channel)); statisticsDtoActiveList.Add(new StatisticsDto(currDateStr, item.ActiveCount, item.Channel)); diff --git a/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs index 3a242cd..6a11540 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Monitor/MonitorProcessor.cs @@ -63,4 +63,5 @@ public class MonitorProcessor : AppJobBase appMonitorInfo.CurrentQueuedUsers = currentQueuedUsers; appMonitorInfo.CurrentPlayingUsers = currentPlayingUsers; } -} \ No newline at end of file +} + diff --git a/src/CloudGaming/Code/CloudGaming.Code/Monitor/OrderMonitorProcessor.cs b/src/CloudGaming/Code/CloudGaming.Code/Monitor/OrderMonitorProcessor.cs index 7b748b0..c9d96b8 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Monitor/OrderMonitorProcessor.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Monitor/OrderMonitorProcessor.cs @@ -8,68 +8,130 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace CloudGaming.Code.Monitor +namespace CloudGaming.Code.Monitor; + +/// +/// 订单数据统计 +/// +[QuartzTrigger("OrderMonitorProcessor", "* 25 4 * * ?")] +public class OrderMonitorProcessor : AppJobBase { - /// - /// 订单数据统计 - /// - [QuartzTrigger("UserMonitorProcessor", "* 25 4 * * ?")] - //[QuartzTrigger("OrderMonitorProcessor", "0 0/1 * * * ?")] - public class OrderMonitorProcessor : AppJobBase + public OrderMonitorProcessor(IServiceScopeFactory scopeFactory) : base(scopeFactory) { - public OrderMonitorProcessor(IServiceScopeFactory scopeFactory) : base(scopeFactory) + } + + public override async Task AppConfigProcessLoop(AppConfig appConfig, AppMonitorInfo appMonitorInfo, IServiceProvider serviceProvider, CloudGamingBase cloudGamingBase) + { + var dao = cloudGamingBase.Dao; + var now = DateTime.Now.AddDays(-1); + int day = int.Parse(now.ToString("yyyyMMdd")); + var nowDay = DateOnly.FromDateTime(now); + //意向订单次数 + var intendedOrder = await dao.DaoUser.Context.T_User_IntentOrder.Where(it => it.CreatedDay == day).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Count()); + + //支付订单次数 + var paidOrders = await dao.DaoUser.Context.T_User_Order.Where(it => it.PaymentDay == nowDay).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Count()); + + //支付金额 + var paidOrdersPrice = await dao.DaoUser.Context.T_User_Order.Where(it => it.PaymentDay == nowDay).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Sum(it => it.TotalPrice)); + //数据源 + var orderStatistics = await dao.DaoExt.Context.T_Statistics_Order + .Where(it => it.LoginDay == day) + .ToDictionaryAsync(it => it.Channel ?? ""); + + // 更新或创建统计记录 + void UpdateStatistics(string channel, int intendedOrderCount, int paidOrders, decimal rechargeAmount) { - } - - public override async Task AppConfigProcessLoop(AppConfig appConfig, AppMonitorInfo appMonitorInfo, IServiceProvider serviceProvider, CloudGamingBase cloudGamingBase) - { - var dao = cloudGamingBase.Dao; - var now = DateTime.Now.AddDays(-1); - int day = int.Parse(now.ToString("yyyyMMdd")); - var nowDay = DateOnly.FromDateTime(now); - //意向订单次数 - var intendedOrder = await dao.DaoUser.Context.T_User_IntentOrder.Where(it => it.CreatedDay == day).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Count()); - - //支付订单次数 - var paidOrders = await dao.DaoUser.Context.T_User_Order.Where(it => it.PaymentDay == nowDay).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Count()); - - //支付金额 - var paidOrdersPrice = await dao.DaoUser.Context.T_User_Order.Where(it => it.PaymentDay == nowDay).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Sum(it => it.TotalPrice)); - //数据源 - var orderStatistics = await dao.DaoExt.Context.T_Statistics_Order - .Where(it => it.LoginDay == day) - .ToDictionaryAsync(it => it.Channel ?? ""); - - // 更新或创建统计记录 - void UpdateStatistics(string channel, int intendedOrderCount, int paidOrders, decimal rechargeAmount) + if (!orderStatistics.TryGetValue(channel, out var statisticsUser)) { - if (!orderStatistics.TryGetValue(channel, out var statisticsUser)) + statisticsUser = new T_Statistics_Order() { - statisticsUser = new T_Statistics_Order() - { - RechargeAmount = 0, - Channel = channel, - CreatedAt = DateTime.Now, - IntendedOrderCount = 0, - PaidOrders = 0, - LoginDate = nowDay, - LoginDay = day, - UpdatedAt = DateTime.Now, - }; - dao.DaoExt.Context.T_Statistics_Order.Add(statisticsUser); - orderStatistics.Add(channel, statisticsUser); - } - statisticsUser.RechargeAmount = rechargeAmount; - statisticsUser.IntendedOrderCount = intendedOrderCount; - statisticsUser.PaidOrders = paidOrders; - statisticsUser.UpdatedAt = DateTime.Now; + RechargeAmount = 0, + Channel = channel, + CreatedAt = DateTime.Now, + IntendedOrderCount = 0, + PaidOrders = 0, + LoginDate = nowDay, + LoginDay = day, + UpdatedAt = DateTime.Now, + }; + dao.DaoExt.Context.T_Statistics_Order.Add(statisticsUser); + orderStatistics.Add(channel, statisticsUser); } - foreach (var item in intendedOrder) - { - UpdateStatistics(item.Key, item.Value, paidOrders.GetValueOrDefault(item.Key, 0), paidOrdersPrice.GetValueOrDefault(item.Key, 0)); - } - - await dao.DaoExt.Context.SaveChangesAsync(); + statisticsUser.RechargeAmount = rechargeAmount; + statisticsUser.IntendedOrderCount = intendedOrderCount; + statisticsUser.PaidOrders = paidOrders; + statisticsUser.UpdatedAt = DateTime.Now; } + foreach (var item in intendedOrder) + { + UpdateStatistics(item.Key, item.Value, paidOrders.GetValueOrDefault(item.Key, 0), paidOrdersPrice.GetValueOrDefault(item.Key, 0)); + } + + await dao.DaoExt.Context.SaveChangesAsync(); + } +} + +[QuartzTrigger("OrderHourMonitorProcessor", "0 5 * * * ?")] +public class OrderHourMonitorProcessor : AppJobBase +{ + public OrderHourMonitorProcessor(IServiceScopeFactory scopeFactory) : base(scopeFactory) + { + } + + public override async Task AppConfigProcessLoop(AppConfig appConfig, AppMonitorInfo appMonitorInfo, IServiceProvider serviceProvider, CloudGamingBase cloudGamingBase) + { + var dao = cloudGamingBase.Dao; + var now = DateTime.Now.AddHours(-1); + int day = int.Parse(now.ToString("yyyyMMdd")); + var newDayHour = now.Date.AddHours(now.Hour); + var oldDayHour = now.Date.AddHours(now.AddHours(1).Hour); + int dayHour = int.Parse(now.ToString("yyyyMMddHH")); + var nowDay = DateOnly.FromDateTime(now); + //意向订单次数 + var intendedOrder = await dao.DaoUser.Context.T_User_IntentOrder.Where(it => it.CreatedDay == day && it.CreatedAt >= newDayHour && it.CreatedAt <= oldDayHour).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Count()); + + //支付订单次数 + var paidOrders = await dao.DaoUser.Context.T_User_Order.Where(it => it.PaymentDay == nowDay && it.CreatedAt >= newDayHour && it.CreatedAt <= oldDayHour).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Count()); + + //支付金额 + var paidOrdersPrice = await dao.DaoUser.Context.T_User_Order.Where(it => it.PaymentDay == nowDay && it.CreatedAt >= newDayHour && it.CreatedAt <= oldDayHour).GroupBy(it => it.Channel).ToDictionaryAsync(it => it.Key ?? "", it => it.Sum(it => it.TotalPrice)); + //数据源 + var orderStatistics = await dao.DaoExt.Context.T_Statistics_OrderHour + .Where(it => it.LoginHour == dayHour) + .ToDictionaryAsync(it => it.Channel ?? ""); + + // 更新或创建统计记录 + void UpdateStatistics(string channel, int intendedOrderCount, int paidOrders, decimal rechargeAmount) + { + if (!orderStatistics.TryGetValue(channel, out var statisticsUser)) + { + statisticsUser = new T_Statistics_OrderHour() + { + RechargeAmount = 0, + Channel = channel, + CreatedAt = DateTime.Now, + IntendedOrderCount = 0, + PaidOrders = 0, + LoginDate = nowDay, + LoginDay = day, + UpdatedAt = DateTime.Now, + LoginHour = dayHour, + + }; + dao.DaoExt.Context.T_Statistics_OrderHour.Add(statisticsUser); + orderStatistics.Add(channel, statisticsUser); + } + statisticsUser.RechargeAmount = rechargeAmount; + statisticsUser.IntendedOrderCount = intendedOrderCount; + statisticsUser.PaidOrders = paidOrders; + statisticsUser.UpdatedAt = DateTime.Now; + } + foreach (var item in intendedOrder) + { + UpdateStatistics(item.Key, item.Value, paidOrders.GetValueOrDefault(item.Key, 0), paidOrdersPrice.GetValueOrDefault(item.Key, 0)); + } + + await dao.DaoExt.Context.SaveChangesAsync(); } } diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigCache.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigCache.cs new file mode 100644 index 0000000..bbceac7 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigCache.cs @@ -0,0 +1,186 @@ +using AutoMapper; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel; + +/// +/// +/// +[AutoMap(typeof(T_App_Config))] +public class AppConfigCache : T_App_Config +{ + private int? appVersionNum; + /// + /// 版本号 + /// + public int AppVersionNum + { + get + { + if (appVersionNum == null) + { + if (AppVersion == null || string.IsNullOrEmpty(AppVersion)) + { + appVersionNum = 0; + } + else + { + var tempAppVersion = AppVersion; + if (AppVersion.StartsWith("+") || AppVersion.StartsWith("-")) + { + tempAppVersion = AppVersion.Substring(1); + + } + tempAppVersion = tempAppVersion.Replace(".", ""); + if (int.TryParse(tempAppVersion, out var _appVersion)) + { + appVersionNum = _appVersion; + } + else + { + appVersionNum = -1; + } + } + } + return appVersionNum ?? -1; + } + } + + /// + /// 判断版本号 + /// + /// + /// + public bool IsAppVersion(string version) + { + if (version == null || string.IsNullOrEmpty(version)) + { + return IsAppVersion(0); + } + if (int.TryParse(version.Replace(".", ""), out var v)) + { + return IsAppVersion(version); + } + return false; + + } + /// + /// 判断版本号 + /// + /// + /// + public bool IsAppVersion(int version) + { + if (AppVersionNum == -1) + { + return false; + } + if (version == 0 && string.IsNullOrEmpty(AppVersion)) + { + return true; + } + else if (version == 0 && !string.IsNullOrEmpty(AppVersion)) + { + return false; + } + if (string.IsNullOrEmpty(AppVersion)) + { + return true; + } + + if (AppVersion.StartsWith("+")) + { + //大于 如 1.0.1< 1.0.2 + if (AppVersionNum < version) + { + return true; + } + return false; + } + + if (AppVersion.StartsWith("-")) + { + //小于 如 1.0.1< 1.0.2 + if (AppVersionNum > version) + { + return true; + } + return false; + } + if (AppVersionNum == version) + { + return true; + } + return false; + } + + + /// + /// 判断当前配置的洲是否匹配给定的洲。 + /// + /// 要匹配的洲名称。 + /// 如果匹配则返回 true,否则返回 false。 + public bool IsContinentMatch(string continent) + { + // 如果给定的洲不为空,则检查当前配置的洲是否包含给定的洲 + if (!string.IsNullOrEmpty(continent)) + { + return !string.IsNullOrEmpty(this.Continent) && (this.Continent + ",").Contains(continent + ","); + } + // 如果给定的洲为空,则检查当前配置的洲是否为空 + return string.IsNullOrEmpty(this.Continent); + } + + /// + /// 判断当前配置的国家是否匹配给定的国家。 + /// + /// 要匹配的国家名称。 + /// 如果匹配则返回 true,否则返回 false。 + public bool IsCountryNameMatch(string countryName) + { + // 如果给定的国家不为空,则检查当前配置的国家是否包含给定的国家 + if (!string.IsNullOrEmpty(countryName)) + { + return !string.IsNullOrEmpty(this.CountryName) && (this.CountryName + ",").Contains(countryName + ","); + } + // 如果给定的国家为空,则检查当前配置的国家是否为空 + return string.IsNullOrEmpty(this.CountryName); + } + + /// + /// 判断当前配置的平台是否匹配给定的平台。 + /// + /// 要匹配的平台名称。 + /// 如果匹配则返回 true,否则返回 false。 + public bool IsPlatformMatch(string plat) + { + // 如果给定的平台不为空,则检查当前配置的平台是否等于给定的平台 + if (!string.IsNullOrEmpty(plat)) + { + return (this.Plat == null || string.IsNullOrEmpty(this.Plat)) || this.Plat == plat; + } + // 如果给定的平台为空,则检查当前配置的平台是否为空 + return this.Plat == null || string.IsNullOrEmpty(this.Plat); + } + + /// + /// 判断当前配置的渠道号是否匹配给定的渠道号。 + /// + /// 要匹配的渠道号。 + /// 如果匹配则返回 true,否则返回 false。 + public bool IsChannelIdMatch(string bossId) + { + // 如果给定的渠道号不为空,则检查当前配置的渠道号是否包含或等于给定的渠道号 + if (!string.IsNullOrEmpty(bossId)) + { + return (this.ChannelId == null || string.IsNullOrEmpty(this.ChannelId)) || (this.ChannelId != null && (this.ChannelId == bossId || this.ChannelId.Contains(bossId))); + } + // 如果给定的渠道号为空,则检查当前配置的渠道号是否为空 + return this.ChannelId == null || string.IsNullOrEmpty(this.ChannelId); + } +} diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs index 4b3251c..a5d24eb 100644 --- a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/CloudGamingCBTContext.cs @@ -45,7 +45,12 @@ public partial class CloudGamingCBTContext : DbContext /// - /// App配置 + /// app渠道表 + /// + public virtual DbSet T_App_Channel { get; set; } + + /// + /// App配置表 /// public virtual DbSet T_App_Config { get; set; } @@ -64,16 +69,31 @@ public partial class CloudGamingCBTContext : DbContext /// public virtual DbSet T_Statistics_Game { get; set; } + /// + /// 游戏统计数据-每小时 + /// + public virtual DbSet T_Statistics_GameHour { get; set; } + /// /// 订单统计表 /// public virtual DbSet T_Statistics_Order { get; set; } + /// + /// 订单统计表 + /// + public virtual DbSet T_Statistics_OrderHour { get; set; } + /// /// 用户统计表 /// public virtual DbSet T_Statistics_User { get; set; } + /// + /// 用户统计表 + /// + public virtual DbSet T_Statistics_UserHour { get; set; } + /// /// 用户登录日志表,每天每个用户只有一条数据 /// @@ -94,17 +114,45 @@ public partial class CloudGamingCBTContext : DbContext } protected override void OnModelCreating(ModelBuilder modelBuilder) { + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__T_App_Ch__3214EC07E413C19A"); + + entity.ToTable(tb => tb.HasComment("app渠道表")); + + entity.Property(e => e.ChannelId) + .HasMaxLength(10) + .HasComment("渠道号"); + entity.Property(e => e.CreateAt) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.Desc) + .HasMaxLength(50) + .HasComment("备注"); + entity.Property(e => e.Name) + .HasMaxLength(255) + .HasComment("渠道名称"); + entity.Property(e => e.UpdateAt) + .HasComment("修改时间") + .HasColumnType("datetime"); + + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("PK_T_APP_CONFIG"); - entity.ToTable(tb => tb.HasComment("App配置")); + entity.ToTable(tb => tb.HasComment("App配置表")); - entity.Property(e => e.BossId) - .HasMaxLength(200) + entity.Property(e => e.ActionId).HasComment("配置值类型"); + entity.Property(e => e.AppVersion) + .HasMaxLength(20) + .HasComment("app版本号"); + entity.Property(e => e.ChannelId) + .HasMaxLength(100) .HasComment("渠道号") .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.ConfigId).HasComment("配置值"); + entity.Property(e => e.ConfigId).HasComment("配置Id"); entity.Property(e => e.ConfigType).HasComment("配置类型"); entity.Property(e => e.ConfigValue) .HasComment("配置值") @@ -117,21 +165,19 @@ public partial class CloudGamingCBTContext : DbContext .HasMaxLength(200) .HasComment("国家 例:中国") .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.CreatTime) + entity.Property(e => e.CreateTime) .HasComment("创建时间") .HasColumnType("datetime"); entity.Property(e => e.Desc) .HasComment("备注") .UseCollation("Chinese_PRC_CI_AS"); - entity.Property(e => e.ExtJson).HasComment("扩展信息"); - entity.Property(e => e.IsShow).HasComment("是否启用"); + entity.Property(e => e.IsEnabled).HasComment("是否启用"); entity.Property(e => e.Name) .HasMaxLength(200) .HasComment("配置名称") .UseCollation("Chinese_PRC_CI_AS"); entity.Property(e => e.Plat) - .HasMaxLength(100) - .IsUnicode(false) + .HasMaxLength(10) .HasComment("平台。安卓还是苹果") .UseCollation("Chinese_PRC_CI_AS"); entity.Property(e => e.UpdateTime) @@ -223,6 +269,30 @@ public partial class CloudGamingCBTContext : DbContext }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("_copy_1_copy_1"); + + entity.ToTable(tb => tb.HasComment("游戏统计数据-每小时")); + + entity.Property(e => e.Channel) + .HasMaxLength(10) + .HasComment("渠道号"); + entity.Property(e => e.CreatedAt) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.LoginDate).HasComment("日期"); + entity.Property(e => e.LoginDay).HasComment("天"); + entity.Property(e => e.LoginHour).HasComment("精确到小时"); + entity.Property(e => e.PlayGameCount).HasComment("用户玩游戏人数"); + entity.Property(e => e.PlayGameTimeCount).HasComment("用户玩游戏时长"); + entity.Property(e => e.StartGameCount).HasComment("启动游戏次数"); + entity.Property(e => e.UpdatedAt) + .HasComment("修改时间") + .HasColumnType("datetime"); + + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("_copy_3"); @@ -248,6 +318,32 @@ public partial class CloudGamingCBTContext : DbContext }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("_copy_3_copy_1"); + + entity.ToTable(tb => tb.HasComment("订单统计表")); + + entity.Property(e => e.Channel) + .HasMaxLength(10) + .HasComment("渠道号"); + entity.Property(e => e.CreatedAt) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.IntendedOrderCount).HasComment("意向订单次数"); + entity.Property(e => e.LoginDate).HasComment("日期"); + entity.Property(e => e.LoginDay).HasComment("天"); + entity.Property(e => e.LoginHour).HasComment("小时"); + entity.Property(e => e.PaidOrders).HasComment("支付订单次数"); + entity.Property(e => e.RechargeAmount) + .HasComment("支付订单金额") + .HasColumnType("decimal(18, 0)"); + entity.Property(e => e.UpdatedAt) + .HasComment("修改时间") + .HasColumnType("datetime"); + + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("PK__T_Statis__3214EC07FE2CF78F"); @@ -271,6 +367,32 @@ public partial class CloudGamingCBTContext : DbContext }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__T_Statis__3214EC07FE2CF78F_copy_1"); + + entity.ToTable(tb => tb.HasComment("用户统计表")); + + entity.Property(e => e.Channel) + .HasMaxLength(10) + .HasComment("渠道号"); + entity.Property(e => e.CreatedAt) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.LoginCount).HasComment("用户登录数"); + entity.Property(e => e.LoginDate).HasComment("日期"); + entity.Property(e => e.LoginDay).HasComment("天"); + entity.Property(e => e.LoginHour) + .HasMaxLength(255) + .IsUnicode(false) + .HasComment("小时"); + entity.Property(e => e.RegistrCount).HasComment("用户注册数"); + entity.Property(e => e.UpdatedAt) + .HasComment("修改时间") + .HasColumnType("datetime"); + + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("PK__T_User_L__3214EC0786EBC26A"); diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Channel.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Channel.cs new file mode 100644 index 0000000..76502cf --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Channel.cs @@ -0,0 +1,38 @@ +using System; + +namespace CloudGaming.GameModel.Db.Db_Ext; + +/// +/// app渠道表 +/// +public partial class T_App_Channel +{ + public T_App_Channel() { } + + public virtual int Id { get; set; } + + /// + /// 渠道名称 + /// + public virtual string Name { get; set; } = null!; + + /// + /// 渠道号 + /// + public virtual string ChannelId { get; set; } = null!; + + /// + /// 创建时间 + /// + public virtual DateTime CreateAt { get; set; } + + /// + /// 修改时间 + /// + public virtual DateTime UpdateAt { get; set; } + + /// + /// 备注 + /// + public virtual string? Desc { get; set; } +} diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs index e30fcd0..2cb7eda 100644 --- a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_App_Config.cs @@ -1,9 +1,9 @@ -using System; +using System; namespace CloudGaming.GameModel.Db.Db_Ext; /// -/// App配置 +/// App配置表 /// public partial class T_App_Config { @@ -16,41 +16,46 @@ public partial class T_App_Config /// public virtual int ConfigType { get; set; } + /// + /// 配置值类型 + /// + public virtual int ActionId { get; set; } + /// /// 配置值 /// - public virtual int ConfigId { get; set; } + public virtual string? ConfigValue { get; set; } /// /// 是否启用 /// - public virtual bool IsShow { get; set; } + public virtual bool IsEnabled { get; set; } + + /// + /// 配置名称 + /// + public virtual string Name { get; set; } = null!; /// /// 备注 /// public virtual string? Desc { get; set; } - /// - /// 修改时间 - /// - public virtual DateTime? UpdateTime { get; set; } - - /// - /// 创建时间 - /// - public virtual DateTime? CreatTime { get; set; } - /// /// 渠道号 /// - public virtual string? BossId { get; set; } + public virtual string? ChannelId { get; set; } /// /// 平台。安卓还是苹果 /// public virtual string? Plat { get; set; } + /// + /// app版本号 + /// + public virtual string? AppVersion { get; set; } + /// /// 州 例:亚洲 /// @@ -62,17 +67,17 @@ public partial class T_App_Config public virtual string? CountryName { get; set; } /// - /// 配置值 + /// 创建时间 /// - public virtual string? ConfigValue { get; set; } + public virtual DateTime CreateTime { get; set; } /// - /// 配置名称 + /// 修改时间 /// - public virtual string? Name { get; set; } + public virtual DateTime UpdateTime { get; set; } /// - /// 扩展信息 + /// 配置Id /// - public virtual string? ExtJson { get; set; } + public virtual int ConfigId { get; set; } } diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_GameHour.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_GameHour.cs new file mode 100644 index 0000000..4adc923 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_GameHour.cs @@ -0,0 +1,58 @@ +using System; + +namespace CloudGaming.GameModel.Db.Db_Ext; + +/// +/// 游戏统计数据-每小时 +/// +public partial class T_Statistics_GameHour +{ + public T_Statistics_GameHour() { } + + public virtual int Id { get; set; } + + /// + /// 日期 + /// + public virtual DateOnly LoginDate { get; set; } + + /// + /// 天 + /// + public virtual int LoginDay { get; set; } + + /// + /// 精确到小时 + /// + public virtual int LoginHour { get; set; } + + /// + /// 用户玩游戏时长 + /// + public virtual int PlayGameTimeCount { get; set; } + + /// + /// 用户玩游戏人数 + /// + public virtual int PlayGameCount { get; set; } + + /// + /// 启动游戏次数 + /// + public virtual int StartGameCount { get; set; } + + /// + /// 渠道号 + /// + public virtual string Channel { get; set; } = null!; + + /// + /// 创建时间 + /// + public virtual DateTime CreatedAt { get; set; } + + /// + /// 修改时间 + /// + public virtual DateTime UpdatedAt { get; set; } +} diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_OrderHour.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_OrderHour.cs new file mode 100644 index 0000000..b4e3f82 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_OrderHour.cs @@ -0,0 +1,58 @@ +using System; + +namespace CloudGaming.GameModel.Db.Db_Ext; + +/// +/// 订单统计表 +/// +public partial class T_Statistics_OrderHour +{ + public T_Statistics_OrderHour() { } + + public virtual int Id { get; set; } + + /// + /// 日期 + /// + public virtual DateOnly LoginDate { get; set; } + + /// + /// 天 + /// + public virtual int LoginDay { get; set; } + + /// + /// 小时 + /// + public virtual int LoginHour { get; set; } + + /// + /// 意向订单次数 + /// + public virtual int IntendedOrderCount { get; set; } + + /// + /// 支付订单次数 + /// + public virtual int PaidOrders { get; set; } + + /// + /// 支付订单金额 + /// + public virtual decimal RechargeAmount { get; set; } + + /// + /// 渠道号 + /// + public virtual string Channel { get; set; } = null!; + + /// + /// 创建时间 + /// + public virtual DateTime CreatedAt { get; set; } + + /// + /// 修改时间 + /// + public virtual DateTime UpdatedAt { get; set; } +} diff --git a/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_UserHour.cs b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_UserHour.cs new file mode 100644 index 0000000..13ad064 --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.GameModel/Db/Db_Ext/T_Statistics_UserHour.cs @@ -0,0 +1,53 @@ +using System; + +namespace CloudGaming.GameModel.Db.Db_Ext; + +/// +/// 用户统计表 +/// +public partial class T_Statistics_UserHour +{ + public T_Statistics_UserHour() { } + + public virtual int Id { get; set; } + + /// + /// 日期 + /// + public virtual DateOnly LoginDate { get; set; } + + /// + /// 天 + /// + public virtual int LoginDay { get; set; } + + /// + /// 小时 + /// + public virtual string LoginHour { get; set; } = null!; + + /// + /// 用户登录数 + /// + public virtual int LoginCount { get; set; } + + /// + /// 用户注册数 + /// + public virtual int RegistrCount { get; set; } + + /// + /// 渠道号 + /// + public virtual string Channel { get; set; } = null!; + + /// + /// 创建时间 + /// + public virtual DateTime CreatedAt { get; set; } + + /// + /// 修改时间 + /// + public virtual DateTime UpdatedAt { get; set; } +} diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs index bc7fac4..00353bd 100644 --- a/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs +++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/CacheHelper/CommonDataEntityCache.cs @@ -117,7 +117,7 @@ public abstract class RedisDataEntityCache : CommonDataEntityCache where T /// protected int cacheTime; - protected RedisDataEntityCache(IDatabase database, object lockObj, int cacheTime = 36000) : base(lockObj, cacheTime) + protected RedisDataEntityCache(IDatabase database,int cacheTime = 36000) : base(new object(), cacheTime) { this.lockObj = lockObj; this.cacheTime = cacheTime; @@ -133,7 +133,7 @@ public abstract class RedisDataEntityCache : CommonDataEntityCache where T /// /// 数据 /// - public virtual List DataList + public override List DataList { get { @@ -151,7 +151,14 @@ public abstract class RedisDataEntityCache : CommonDataEntityCache where T { tempDataList = GetDataList(); - database.StringSet(key, tempDataList, TimeSpan.FromSeconds(cacheTime)); + if (cacheTime == 0) + { + database.StringSet(key, tempDataList); + } + else + { + database.StringSet(key, tempDataList, TimeSpan.FromSeconds(cacheTime)); + } } _dataList = JsonConvert.DeserializeObject>(JsonConvert.SerializeObject(tempDataList)); database.KeyDeleteAsync($"lock:{key}").Wait(); @@ -181,21 +188,30 @@ public abstract class RedisDataEntityCache : CommonDataEntityCache where T public virtual bool ClearData() { - lock (lockObj) + if (database.StringSetLock($"lock:{key}", "", 5)) { database.KeyDelete(key); _dataList = null; + database.KeyDeleteAsync($"lock:{key}").Wait(); } return true; } public virtual void ReloadData() { - lock (lockObj) + if (database.StringSetLock($"lock:{key}", "", 5)) { var tempDataList = GetDataList(); - database.StringSet(key, tempDataList, TimeSpan.FromMinutes(cacheTime)); + if (cacheTime == 0) + { + database.StringSet(key, tempDataList); + } + else + { + database.StringSet(key, tempDataList, TimeSpan.FromSeconds(cacheTime)); + } _dataList = tempDataList; + database.KeyDeleteAsync($"lock:{key}").Wait(); } } } diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs index 4ef6490..22ab78e 100644 --- a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs +++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Redis/RedisConnection.cs @@ -182,7 +182,7 @@ namespace HuanMeng.DotNetCore.Redis /// /// /// - public static bool StringSet(this IDatabase database, string key, object value, TimeSpan? expiry) + public static bool StringSet(this IDatabase database, string key, object value, TimeSpan? expiry = null) { return database.StringSet(key, (value == null ? "" : JsonConvert.SerializeObject(value)), expiry, When.Always); } @@ -265,7 +265,7 @@ namespace HuanMeng.DotNetCore.Redis /// Redis 服务器实例 /// 匹配的模式(支持通配符) /// 匹配的键的数量 - public static int ScanKeysCount(this IServer server, string pattern,int database = -1) + public static int ScanKeysCount(this IServer server, string pattern, int database = -1) { int count = 0; long cursor = 0; // 游标,用于记录扫描进度