From 94d0b7028f8a0d31af67b435f5ed14f7eb2de0b4 Mon Sep 17 00:00:00 2001 From: tk Date: Thu, 26 Jun 2025 17:35:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20=E8=B4=A2=E5=8A=A1=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/res/NetAdmin.Fields.ln | 13 +- assets/res/NetAdmin.Statements.ln | 3 + assets/seed-data/Sys_Menu.json | 64 +++- assets/seed-data/Sys_RoleApi.json | 20 ++ assets/seed-data/Sys_RoleMenu.json | 20 ++ assets/seed-data/Sys_UserWallet.json | 12 + package.json | 2 +- .../Services/ServiceBase.cs | 19 +- .../Services/Tpl/ExampleService.cs | 3 +- .../DbMaps/Dependency/Fields/IFieldOwner.cs | 6 +- .../DbMaps/Sys/Sys_DocCatalog.cs | 6 +- .../DbMaps/Sys/Sys_DocContent.cs | 6 +- .../DbMaps/Sys/Sys_JobRecord.cs | 2 +- .../DbMaps/Sys/Sys_LoginLog.cs | 6 +- .../DbMaps/Sys/Sys_RequestLog.cs | 6 +- .../DbMaps/Sys/Sys_UserWallet.cs | 72 ++++ .../DbMaps/Sys/Sys_WalletTrade.cs | 80 +++++ .../Dto/Sys/UserWallet/CreateUserWalletReq.cs | 8 + .../Dto/Sys/UserWallet/EditUserWalletReq.cs | 15 + .../Dto/Sys/UserWallet/QueryUserWalletReq.cs | 21 ++ .../Dto/Sys/UserWallet/QueryUserWalletRsp.cs | 56 +++ .../Sys/WalletTrade/CreateWalletTradeReq.cs | 53 +++ .../Dto/Sys/WalletTrade/EditWalletTradeReq.cs | 11 + .../Sys/WalletTrade/QueryWalletTradeReq.cs | 13 + .../Sys/WalletTrade/QueryWalletTradeRsp.cs | 61 ++++ .../Attributes/TradeAttribute.cs | 13 + .../Enums/TradeDirections.cs | 22 ++ .../Enums/TradeTypes.cs | 33 ++ .../Modules/Sys/IUserWalletModule.cs | 12 + .../Modules/Sys/IWalletTradeModule.cs | 12 + .../Sys/Dependency/IUserWalletService.cs | 6 + .../Sys/Dependency/IWalletTradeService.cs | 6 + .../Services/Sys/ToolsService.cs | 2 +- .../Services/Sys/UserProfileService.cs | 2 +- .../Services/Sys/UserService.cs | 10 + .../Services/Sys/UserWalletService.cs | 145 ++++++++ .../Services/Sys/WalletTradeService.cs | 145 ++++++++ .../Sys/Dependency/IUserWalletCache.cs | 6 + .../Sys/Dependency/IWalletTradeCache.cs | 6 + .../Sys/UserWalletCache.cs | 68 ++++ .../Sys/WalletTradeCache.cs | 68 ++++ .../Controllers/Sys/UserWalletController.cs | 97 ++++++ .../Controllers/Sys/WalletTradeController.cs | 97 ++++++ .../Subscribers/OperationLogger.cs | 6 +- .../Utils/SqlAuditor.cs | 2 +- src/frontend/admin/package.json | 16 +- src/frontend/admin/src/api/sys/userwallet.js | 95 ++++++ src/frontend/admin/src/api/sys/wallettrade.js | 95 ++++++ src/frontend/admin/src/global.js | 3 + .../admin/src/layout/components/tasks.vue | 4 +- src/frontend/admin/src/locales/lang/en.js | 4 +- src/frontend/admin/src/locales/lang/zh-cn.js | 4 +- src/frontend/admin/src/utils/preload.js | 7 + src/frontend/admin/src/views/profile/logs.vue | 2 +- .../admin/src/views/sys/log/login/index.vue | 60 +++- .../src/views/sys/log/operation/index.vue | 2 +- .../admin/src/views/sys/trade/index.vue | 323 ++++++++++++++++++ .../admin/src/views/sys/trade/save.vue | 119 +++++++ .../admin/src/views/sys/user/index.vue | 4 +- .../admin/src/views/sys/user/save.vue | 12 +- .../admin/src/views/sys/wallet/index.vue | 315 +++++++++++++++++ .../admin/src/views/sys/wallet/save.vue | 124 +++++++ .../admin/src/views/sys/wallet/trade.vue | 91 +++++ 63 files changed, 2544 insertions(+), 72 deletions(-) create mode 100644 assets/seed-data/Sys_UserWallet.json create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_UserWallet.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_WalletTrade.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/CreateUserWalletReq.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/EditUserWalletReq.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletReq.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletRsp.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/CreateWalletTradeReq.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/EditWalletTradeReq.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeReq.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeRsp.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Infrastructure/Attributes/TradeAttribute.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeDirections.cs create mode 100644 src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeTypes.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IUserWalletModule.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IWalletTradeModule.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserWalletService.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IWalletTradeService.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserWalletService.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/WalletTradeService.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserWalletCache.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IWalletTradeCache.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/UserWalletCache.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/WalletTradeCache.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/UserWalletController.cs create mode 100644 src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/WalletTradeController.cs create mode 100644 src/frontend/admin/src/api/sys/userwallet.js create mode 100644 src/frontend/admin/src/api/sys/wallettrade.js create mode 100644 src/frontend/admin/src/views/sys/trade/index.vue create mode 100644 src/frontend/admin/src/views/sys/trade/save.vue create mode 100644 src/frontend/admin/src/views/sys/wallet/index.vue create mode 100644 src/frontend/admin/src/views/sys/wallet/save.vue create mode 100644 src/frontend/admin/src/views/sys/wallet/trade.vue diff --git a/assets/res/NetAdmin.Fields.ln b/assets/res/NetAdmin.Fields.ln index f4dc532f..ada9421b 100644 --- a/assets/res/NetAdmin.Fields.ln +++ b/assets/res/NetAdmin.Fields.ln @@ -17,7 +17,6 @@ 以什么结束 作业名称 作业状态 -密 信息 倒序排序 全部数据 @@ -45,6 +44,7 @@ 字典内容导出 宕机 客户端IP +密 小于 小于等于 小学 @@ -71,6 +71,8 @@ 接口路径 插入种子数据 操作系统 +支出 +收入 数据范围 文档内容 文档内容导出 @@ -99,6 +101,7 @@ 用户代理 用户名 用户导出 +用户钱包导出 电子邮箱 男 登录 @@ -111,11 +114,14 @@ 站内信导出 等于 等待发送 +管理员充值 +管理员扣费 管理模块 系统模块 绑定手机号码 结果非预期 群众 +自助充值 自定义 范围 菜单 @@ -128,16 +134,17 @@ 请求方式 请求日志导出 调试 -追踪 -追踪标识 身份证 运行 +追踪 +追踪标识 通知 邮箱号 部门名称 部门导出 配置导出 重设密码 +钱包交易导出 链接 错误 随机排序 diff --git a/assets/res/NetAdmin.Statements.ln b/assets/res/NetAdmin.Statements.ln index 810dd086..295cd5b2 100644 --- a/assets/res/NetAdmin.Statements.ln +++ b/assets/res/NetAdmin.Statements.ln @@ -5,6 +5,8 @@ XML注释文件不存在 中文姓名 事务已回滚 事务已提交 +交易失败 +交易金额不正确 人机校验请求不能为空 人机验证未通过 作业名称不能为空 @@ -108,6 +110,7 @@ XML注释文件不存在 部门可见 部门名称不能为空 配置文件初始化完毕 +钱包余额不足 键值不能为空 键名称不能为空 随机延时结束时间不正确 diff --git a/assets/seed-data/Sys_Menu.json b/assets/seed-data/Sys_Menu.json index 66bcd64b..4842d640 100644 --- a/assets/seed-data/Sys_Menu.json +++ b/assets/seed-data/Sys_Menu.json @@ -26,7 +26,7 @@ "Id": 373837957840901, "Name": "sys/user", "ParentId": 373837917724677, - "Path": "/sys/user", + "Path": "/power/user", "Sort": 100, "Title": "用户管理", "Type": 1 @@ -37,7 +37,7 @@ "Id": 373838018527237, "Name": "sys/role", "ParentId": 373837917724677, - "Path": "/sys/role", + "Path": "/power/role", "Sort": 99, "Title": "角色管理", "Type": 1 @@ -48,7 +48,7 @@ "Id": 373838045605893, "Name": "sys/dept", "ParentId": 373837917724677, - "Path": "/sys/dept", + "Path": "/power/dept", "Sort": 98, "Title": "部门管理", "Type": 1 @@ -59,18 +59,50 @@ "Id": 373838070898693, "Name": "sys/menu", "ParentId": 373837917724677, - "Path": "/sys/menu", + "Path": "/power/menu", "Sort": 97, "Title": "菜单管理", "Type": 1 }, + // ------------------------------ 财务管理 ------------------------------ + { + "Icon": "el-icon-money", + "Id": 690906994118665, + "Name": "finance", + "Path": "/finance", + "Sort": 99, + "Title": "财务管理", + "Type": 1 + }, + { + "Component": "sys/wallet", + "Icon": "el-icon-wallet", + "Id": 690907673255942, + "Name": "sys/wallet", + "ParentId": 690906994118665, + "Path": "/finance/wallet", + "Sort": 100, + "Title": "钱包管理", + "Type": 1 + }, + { + "Component": "sys/trade", + "Icon": "el-icon-calendar", + "Id": 690907673255943, + "Name": "sys/trade", + "ParentId": 690906994118665, + "Path": "/finance/trade", + "Sort": 99, + "Title": "交易流水", + "Type": 1 + }, // ------------------------------ 系统管理 ------------------------------ { "Icon": "sc-icon-App", "Id": 485278637670422, "Name": "sys", "Path": "/sys", - "Sort": 99, + "Sort": 98, "Title": "系统管理", "Type": 1 }, @@ -80,7 +112,7 @@ "Id": 380415005847557, "Name": "sys/config", "ParentId": 485278637670422, - "Path": "/sys/config", + "Path": "/system/config", "Sort": 100, "Title": "系统设置", "Type": 1 @@ -91,7 +123,7 @@ "Id": 510067557638158, "Name": "sys/job", "ParentId": 485278637670422, - "Path": "/sys/job", + "Path": "/system/job", "Sort": 99, "Title": "计划作业", "Type": 1 @@ -102,7 +134,7 @@ "Id": 375315654221829, "Name": "sys/dic", "ParentId": 485278637670422, - "Path": "/sys/dic", + "Path": "/system/dic", "Sort": 98, "Title": "字典管理", "Type": 1 @@ -113,7 +145,7 @@ "Id": 482779610341392, "Name": "sys/msg", "ParentId": 485278637670422, - "Path": "/sys/msg", + "Path": "/system/msg", "Sort": 97, "Title": "消息管理", "Type": 1, @@ -124,7 +156,7 @@ "Id": 397880678895621, "Name": "sys/api", "ParentId": 485278637670422, - "Path": "/sys/api", + "Path": "/system/api", "Sort": 96, "Title": "接口管理", "Type": 1 @@ -135,7 +167,7 @@ "Id": 374911555702789, "Name": "sys/cache", "ParentId": 485278637670422, - "Path": "/sys/cache", + "Path": "/system/cache", "Sort": 95, "Title": "缓存管理", "Type": 1 @@ -146,7 +178,7 @@ "Id": 616214756757512, "Name": "archive", "Path": "/archive", - "Sort": 98, + "Sort": 97, "Title": "档案管理", "Type": 1 }, @@ -167,7 +199,7 @@ "Id": 374792687640581, "Name": "log", "Path": "/log", - "Sort": 97, + "Sort": 96, "Title": "日志管理", "Type": 1 }, @@ -177,7 +209,7 @@ "Id": 485285246504976, "Name": "sys/log/operation", "ParentId": 374792687640581, - "Path": "/sys/log/operation", + "Path": "/log/operation", "Sort": 100, "Title": "操作日志", "Type": 1, @@ -188,7 +220,7 @@ "Id": 485285246504970, "Name": "sys/log/login", "ParentId": 374792687640581, - "Path": "/sys/log/login", + "Path": "/log/login", "Sort": 99, "Title": "登录日志", "Type": 1, @@ -199,7 +231,7 @@ "Id": 373838105399301, "Name": "dev", "Path": "/dev", - "Sort": 96, + "Sort": 95, "Title": "开发管理", "Type": 1 }, diff --git a/assets/seed-data/Sys_RoleApi.json b/assets/seed-data/Sys_RoleApi.json index c7ff88d1..f4aa37b0 100644 --- a/assets/seed-data/Sys_RoleApi.json +++ b/assets/seed-data/Sys_RoleApi.json @@ -58,5 +58,25 @@ { "ApiId": "api/sys/login.log/export", "RoleId": 371729946431493, + }, + { + "ApiId": "api/sys/user.wallet/paged.query", + "RoleId": 371729946431493, + }, + { + "ApiId": "api/sys/user.wallet/get", + "RoleId": 371729946431493, + }, + { + "ApiId": "api/sys/wallet.trade/paged.query", + "RoleId": 371729946431493, + }, + { + "ApiId": "api/sys/wallet.trade/count.by", + "RoleId": 371729946431493, + }, + { + "ApiId": "api/sys/wallet.trade/get", + "RoleId": 371729946431493, } ] \ No newline at end of file diff --git a/assets/seed-data/Sys_RoleMenu.json b/assets/seed-data/Sys_RoleMenu.json index 85c84e93..5e22653e 100644 --- a/assets/seed-data/Sys_RoleMenu.json +++ b/assets/seed-data/Sys_RoleMenu.json @@ -6,5 +6,25 @@ { "MenuId": 374967228141573, "RoleId": 371729946431493 + }, + { + "MenuId": 690906994118665, + "RoleId": 371729946431493 + }, + { + "MenuId": 690907673255942, + "RoleId": 371729946431493 + }, + { + "MenuId": 374792687640581, + "RoleId": 371729946431493 + }, + { + "MenuId": 485285246504970, + "RoleId": 371729946431493 + }, + { + "MenuId": 690907673255943, + "RoleId": 371729946431493 } ] \ No newline at end of file diff --git a/assets/seed-data/Sys_UserWallet.json b/assets/seed-data/Sys_UserWallet.json new file mode 100644 index 00000000..b09a7a58 --- /dev/null +++ b/assets/seed-data/Sys_UserWallet.json @@ -0,0 +1,12 @@ +[ + { + "Id": 370942943322181, + "OwnerDeptId": 372119301627909, + "OwnerId": 370942943322181, + }, + { + "Id": 560217289236492, + "OwnerDeptId": 372119301627909, + "OwnerId": 560217289236492, + } +] \ No newline at end of file diff --git a/package.json b/package.json index 56623bf0..7a4d71b6 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "devDependencies": { "cz-git": "^1.11.2", "commitizen": "^4.3.1", - "prettier": "^3.5.3", + "prettier": "^3.6.1", "standard-version": "^9.5.0" }, "config": { diff --git a/src/backend/NetAdmin/NetAdmin.Application/Services/ServiceBase.cs b/src/backend/NetAdmin/NetAdmin.Application/Services/ServiceBase.cs index 174c0e0e..c66da022 100644 --- a/src/backend/NetAdmin/NetAdmin.Application/Services/ServiceBase.cs +++ b/src/backend/NetAdmin/NetAdmin.Application/Services/ServiceBase.cs @@ -10,7 +10,7 @@ public abstract class ServiceBase : ServiceBase /// protected ServiceBase() // { - Logger = App.GetService>(); + Logger = S>(); } /// @@ -29,7 +29,7 @@ public abstract class ServiceBase : IScoped, IService /// protected ServiceBase() { - UserToken = App.GetService(); + UserToken = S(); ServiceId = Guid.NewGuid(); } @@ -38,4 +38,19 @@ public abstract class ServiceBase : IScoped, IService /// public ContextUserToken UserToken { get; set; } + + /// + /// 获取服务 + /// + #pragma warning disable RCS1036 + #pragma warning restore RCS1036 + + // ReSharper disable once MemberCanBeMadeStatic.Global + #pragma warning disable CA1822, S2325 + protected T S() + #pragma warning restore S2325, CA1822 + where T : class + { + return App.GetService(); + } } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs b/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs index 884b6406..2b4aa265 100644 --- a/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs +++ b/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs @@ -42,8 +42,9 @@ public sealed class ExampleService(BasicRepository rpo) // .ToDictionaryAsync(a => a.Count()) .ConfigureAwait(false); return ret.Select(x => new KeyValuePair, int>( - req.RequiredFields.ToImmutableDictionary(y => y, y => typeof(Tpl_Example).GetProperty(y)!.GetValue(x.Key)!.ToString()) + req.RequiredFields.ToImmutableDictionary(y => y, y => typeof(Tpl_Example).GetProperty(y)!.GetValue(x.Key)?.ToString()) , x.Value)) + .Where(x => x.Key.Any(y => !y.Value.NullOrEmpty())) .OrderByDescending(x => x.Value); } diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs index 91b45072..8431a54c 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs @@ -1,17 +1,17 @@ namespace NetAdmin.Domain.DbMaps.Dependency.Fields; /// -/// 拥有者字段接口 +/// 所有者字段接口 /// public interface IFieldOwner { /// - /// 拥有者部门编号 + /// 所有者部门编号 /// long? OwnerDeptId { get; init; } /// - /// 拥有者用户编号 + /// 所有者用户编号 /// long? OwnerId { get; init; } } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocCatalog.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocCatalog.cs index 44dc733a..774283cf 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocCatalog.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocCatalog.cs @@ -40,7 +40,7 @@ public record Sys_DocCatalog : VersionEntity, IFieldOwner public virtual string Name { get; init; } /// - /// 拥有者 + /// 所有者 /// [CsvIgnore] [JsonIgnore] @@ -48,7 +48,7 @@ public record Sys_DocCatalog : VersionEntity, IFieldOwner public Sys_User Owner { get; init; } /// - /// 拥有者部门编号 + /// 所有者部门编号 /// [Column] [CsvIgnore] @@ -56,7 +56,7 @@ public record Sys_DocCatalog : VersionEntity, IFieldOwner public virtual long? OwnerDeptId { get; init; } /// - /// 拥有者用户编号 + /// 所有者用户编号 /// [Column] [CsvIgnore] diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocContent.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocContent.cs index 66c0b461..e25e8f87 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocContent.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_DocContent.cs @@ -41,7 +41,7 @@ public record Sys_DocContent : VersionEntity, IFieldEnabled, IFieldOwner public virtual bool Enabled { get; init; } /// - /// 拥有者 + /// 所有者 /// [CsvIgnore] [JsonIgnore] @@ -49,7 +49,7 @@ public record Sys_DocContent : VersionEntity, IFieldEnabled, IFieldOwner public Sys_User Owner { get; init; } /// - /// 拥有者部门编号 + /// 所有者部门编号 /// [Column] [CsvIgnore] @@ -57,7 +57,7 @@ public record Sys_DocContent : VersionEntity, IFieldEnabled, IFieldOwner public virtual long? OwnerDeptId { get; init; } /// - /// 拥有者用户编号 + /// 所有者用户编号 /// [Column] [CsvIgnore] diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs index ef3be048..7d3d702b 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_JobRecord.cs @@ -35,7 +35,7 @@ public record Sys_JobRecord : LiteImmutableEntity public int HttpStatusCode { get; init; } /// - /// 拥有者信息 + /// 所有者信息 /// [CsvIgnore] [JsonIgnore] diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_LoginLog.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_LoginLog.cs index 29b2b499..b1ae265a 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_LoginLog.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_LoginLog.cs @@ -66,7 +66,7 @@ public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFiel public virtual string LoginUserName { get; protected init; } /// - /// 拥有者 + /// 所有者 /// [CsvIgnore] [JsonIgnore] @@ -74,7 +74,7 @@ public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFiel public Sys_User Owner { get; init; } /// - /// 拥有者部门编号 + /// 所有者部门编号 /// [Column] [CsvIgnore] @@ -82,7 +82,7 @@ public record Sys_LoginLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFiel public virtual long? OwnerDeptId { get; init; } /// - /// 拥有者用户编号 + /// 所有者用户编号 /// [Column] [CsvIgnore] diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs index ab1cc90e..db36a8d4 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs @@ -76,7 +76,7 @@ public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFi public virtual int HttpStatusCode { get; init; } /// - /// 拥有者 + /// 所有者 /// [CsvIgnore] [JsonIgnore] @@ -84,7 +84,7 @@ public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFi public Sys_User Owner { get; init; } /// - /// 拥有者部门编号 + /// 所有者部门编号 /// [Column] [CsvIgnore] @@ -92,7 +92,7 @@ public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFi public virtual long? OwnerDeptId { get; init; } /// - /// 拥有者用户编号 + /// 所有者用户编号 /// [Column] [CsvIgnore] diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_UserWallet.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_UserWallet.cs new file mode 100644 index 00000000..98ba6729 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_UserWallet.cs @@ -0,0 +1,72 @@ +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 用户钱包表 +/// +[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_UserWallet))] +public record Sys_UserWallet : LiteVersionEntity, IFieldOwner +{ + /// + /// 可用余额 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long AvailableBalance { get; init; } + + /// + /// 冻结余额 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long FrozenBalance { get; init; } + + /// + /// 所有者 + /// + [CsvIgnore] + [JsonIgnore] + [Navigate(nameof(OwnerId))] + public Sys_User Owner { get; init; } + + /// + /// 所有者部门编号 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerDeptId { get; init; } + + /// + /// 所有者用户编号 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerId { get; init; } + + /// + /// 总余额 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long TotalBalance { get; init; } + + /// + /// 总支出 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long TotalExpenditure { get; init; } + + /// + /// 总收入 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long TotalIncome { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_WalletTrade.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_WalletTrade.cs new file mode 100644 index 00000000..fa28739e --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_WalletTrade.cs @@ -0,0 +1,80 @@ +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 钱包交易表 +/// +[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_WalletTrade))] +public record Sys_WalletTrade : ImmutableEntity, IFieldOwner, IFieldSummary +{ + /// + /// 交易金额 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long Amount { get; init; } + + /// + /// 交易前余额 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long BalanceBefore { get; init; } + + /// + /// 业务订单号 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? BusinessOrderNumber { get; init; } + + /// + /// 所有者 + /// + [CsvIgnore] + [JsonIgnore] + [Navigate(nameof(OwnerId))] + public Sys_User Owner { get; init; } + + /// + /// 所有者部门编号 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerDeptId { get; init; } + + /// + /// 所有者用户编号 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerId { get; init; } + + /// + /// 备注 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [CsvIgnore] + [JsonIgnore] + public virtual string Summary { get; init; } + + /// + /// 交易方向 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual TradeDirections TradeDirection { get; init; } + + /// + /// 交易类型 + /// + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual TradeTypes TradeType { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/CreateUserWalletReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/CreateUserWalletReq.cs new file mode 100644 index 00000000..902113b8 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/CreateUserWalletReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.UserWallet; + +/// +/// 请求:创建用户钱包 +/// +public record CreateUserWalletReq : Sys_UserWallet; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/EditUserWalletReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/EditUserWalletReq.cs new file mode 100644 index 00000000..d1d5cd1e --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/EditUserWalletReq.cs @@ -0,0 +1,15 @@ +namespace NetAdmin.Domain.Dto.Sys.UserWallet; + +/// +/// 请求:编辑用户钱包 +/// +public record EditUserWalletReq : CreateUserWalletReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletReq.cs new file mode 100644 index 00000000..cd3d3b33 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletReq.cs @@ -0,0 +1,21 @@ +namespace NetAdmin.Domain.Dto.Sys.UserWallet; + +/// +/// 请求:查询用户钱包 +/// +public sealed record QueryUserWalletReq : Sys_UserWallet +{ + /// + /// 部门编号 + /// + public long DeptId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + /// 角色编号 + /// + public long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletRsp.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletRsp.cs new file mode 100644 index 00000000..7524925b --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/UserWallet/QueryUserWalletRsp.cs @@ -0,0 +1,56 @@ +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.Dto.Sys.UserWallet; + +/// +/// 响应:查询用户钱包 +/// +public record QueryUserWalletRsp : Sys_UserWallet +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long AvailableBalance { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long FrozenBalance { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override DateTime? ModifiedTime { get; init; } + + /// + public new virtual QueryUserRsp Owner { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? OwnerDeptId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? OwnerId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long TotalBalance { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long TotalExpenditure { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long TotalIncome { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/CreateWalletTradeReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/CreateWalletTradeReq.cs new file mode 100644 index 00000000..03298ca6 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/CreateWalletTradeReq.cs @@ -0,0 +1,53 @@ +namespace NetAdmin.Domain.Dto.Sys.WalletTrade; + +/// +/// 请求:创建钱包交易 +/// +public record CreateWalletTradeReq : Sys_WalletTrade, IValidatableObject +{ + private readonly TradeTypes _tradeType; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Amount { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? BusinessOrderNumber { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [Required] + [UserId] + [Range(1, long.MaxValue)] + public override long? OwnerId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + + /// + public override TradeDirections TradeDirection { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [EnumDataType(typeof(TradeTypes))] + public override TradeTypes TradeType { + get => _tradeType; + init { + _tradeType = value; + TradeDirection = value.Attr().Direction; + } + } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + var tradeDirection = TradeType.Attr().Direction; + if (Amount == 0 || (tradeDirection == TradeDirections.Income && Amount < 0) || (tradeDirection == TradeDirections.Expense && Amount > 0)) { + yield return new ValidationResult(Ln.交易金额不正确, [nameof(Amount)]); + } + + yield return ValidationResult.Success; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/EditWalletTradeReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/EditWalletTradeReq.cs new file mode 100644 index 00000000..294f9465 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/EditWalletTradeReq.cs @@ -0,0 +1,11 @@ +namespace NetAdmin.Domain.Dto.Sys.WalletTrade; + +/// +/// 请求:编辑钱包交易 +/// +public record EditWalletTradeReq : CreateWalletTradeReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeReq.cs new file mode 100644 index 00000000..913d7151 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.WalletTrade; + +/// +/// 请求:查询钱包交易 +/// +public sealed record QueryWalletTradeReq : Sys_WalletTrade +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeRsp.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeRsp.cs new file mode 100644 index 00000000..5d20164b --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/WalletTrade/QueryWalletTradeRsp.cs @@ -0,0 +1,61 @@ +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.Dto.Sys.WalletTrade; + +/// +/// 响应:查询钱包交易 +/// +public record QueryWalletTradeRsp : Sys_WalletTrade +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Amount { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long BalanceBefore { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? BusinessOrderNumber { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? CreatedUserId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CreatedUserName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [CsvIgnore] + public new virtual QueryUserRsp Owner { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? OwnerDeptId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? OwnerId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override TradeDirections TradeDirection { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override TradeTypes TradeType { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Infrastructure/Attributes/TradeAttribute.cs b/src/backend/NetAdmin/NetAdmin.Infrastructure/Attributes/TradeAttribute.cs new file mode 100644 index 00000000..622aa45e --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Infrastructure/Attributes/TradeAttribute.cs @@ -0,0 +1,13 @@ +namespace NetAdmin.Infrastructure.Attributes; + +/// +/// 交易方向特性 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Enum)] +public sealed class TradeAttribute : Attribute +{ + /// + /// 交易方向 + /// + public TradeDirections Direction { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeDirections.cs b/src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeDirections.cs new file mode 100644 index 00000000..07cd833c --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeDirections.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 交易方向 +/// +[Export] +public enum TradeDirections +{ + /// + /// 收入 + /// + [ResourceDescription(nameof(Ln.收入))] + Income = 4 + + , + + /// + /// 支出 + /// + [ResourceDescription(nameof(Ln.支出))] + Expense = 5 +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeTypes.cs b/src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeTypes.cs new file mode 100644 index 00000000..ba1fd3f3 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Infrastructure/Enums/TradeTypes.cs @@ -0,0 +1,33 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 交易类型 +/// +[Export] +public enum TradeTypes +{ + /// + /// 管理员充值 + /// + [ResourceDescription(nameof(Ln.管理员充值))] + [Trade(Direction = TradeDirections.Income)] + AdminDeposit = 1 + + , + + /// + /// 管理员扣费 + /// + [ResourceDescription(nameof(Ln.管理员扣费))] + [Trade(Direction = TradeDirections.Expense)] + AdminDeduct = 2 + + , + + /// + /// 自助充值 + /// + [ResourceDescription(nameof(Ln.自助充值))] + [Trade(Direction = TradeDirections.Income)] + SelfDeposit = 3 +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IUserWalletModule.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IUserWalletModule.cs new file mode 100644 index 00000000..a0d0dab5 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IUserWalletModule.cs @@ -0,0 +1,12 @@ +using NetAdmin.Domain.Dto.Sys.UserWallet; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 用户钱包模块 +/// +public interface IUserWalletModule : ICrudModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IWalletTradeModule.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IWalletTradeModule.cs new file mode 100644 index 00000000..1228079a --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IWalletTradeModule.cs @@ -0,0 +1,12 @@ +using NetAdmin.Domain.Dto.Sys.WalletTrade; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 钱包交易模块 +/// +public interface IWalletTradeModule : ICrudModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserWalletService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserWalletService.cs new file mode 100644 index 00000000..89dbc2ec --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserWalletService.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 用户钱包服务 +/// +public interface IUserWalletService : IService, IUserWalletModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IWalletTradeService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IWalletTradeService.cs new file mode 100644 index 00000000..d3415e58 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IWalletTradeService.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 钱包交易服务 +/// +public interface IWalletTradeService : IService, IWalletTradeModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs index e08c0e64..9e3b29d5 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs @@ -16,7 +16,7 @@ public sealed class ToolsService : ServiceBase, IToolsService public async Task ExecuteSqlAsync(ExecuteSqlReq req) { req.ThrowIfInvalid(); - var cmd = App.GetService().Ado.CommandFluent(req.Sql).CommandTimeout(req.TimeoutSecs).ExecuteArrayAsync(); + var cmd = S().Ado.CommandFluent(req.Sql).CommandTimeout(req.TimeoutSecs).ExecuteArrayAsync(); return req.WaitResult ? await cmd.ConfigureAwait(false) : null; } diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs index e6764bca..8fc2c723 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs @@ -175,7 +175,7 @@ public sealed class UserProfileService(BasicRepository rp // 默认仪表版 if (req.AppConfig == "[]") { - req.AppConfig = BuildAppConfig(App.GetService().Roles.ToDictionary(x => x.Id, x => x.DashboardLayout)); + req.AppConfig = BuildAppConfig(S().Roles.ToDictionary(x => x.Id, x => x.DashboardLayout)); } return UpdateAsync(req, [nameof(req.AppConfig)], null, a => a.Id == UserToken.Id, null, true); diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs index 9550e9a6..23563260 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs @@ -3,6 +3,7 @@ using NetAdmin.Domain.Contexts; using NetAdmin.Domain.DbMaps.Sys; using NetAdmin.Domain.Dto.Sys.User; using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.Domain.Dto.Sys.UserWallet; using NetAdmin.Domain.Dto.Sys.VerifyCode; using NetAdmin.Domain.Events.Sys; using NetAdmin.Domain.Extensions; @@ -13,6 +14,7 @@ namespace NetAdmin.SysComponent.Application.Services.Sys; public sealed class UserService( BasicRepository rpo // , IUserProfileService userProfileService // + , IUserWalletService userWalletService // , IVerifyCodeService verifyCodeService // , IEventPublisher eventPublisher) // : RepositoryService(rpo), IUserService @@ -112,6 +114,14 @@ public sealed class UserService( , AppConfig = appConfig }) .ConfigureAwait(false); + + // 钱包表 + _ = await userWalletService.CreateAsync(new CreateUserWalletReq() with // + { + Id = dbUser.Id, OwnerId = dbUser.Id, OwnerDeptId = dbUser.DeptId + }) + .ConfigureAwait(false); + var userList = await QueryAsync(new QueryReq { Filter = new QueryUserReq { Id = dbUser.Id } }).ConfigureAwait(false); // 发布用户创建事件 diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserWalletService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserWalletService.cs new file mode 100644 index 00000000..05ca18ea --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/UserWalletService.cs @@ -0,0 +1,145 @@ +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.UserWallet; +using NetAdmin.Domain.Extensions; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class UserWalletService(BasicRepository rpo) // + : RepositoryService(rpo), IUserWalletService +{ + /// + public async Task BulkDeleteAsync(BulkReq req) + { + req.ThrowIfInvalid(); + var ret = 0; + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var item in req.Items) { + ret += await DeleteAsync(item).ConfigureAwait(false); + } + + return ret; + } + + /// + public Task CountAsync(QueryReq req) + { + req.ThrowIfInvalid(); + return QueryInternal(req).WithNoLockNoWait().CountAsync(); + } + + /// + public async Task, int>>> CountByAsync(QueryReq req) + { + req.ThrowIfInvalid(); + var ret = await QueryInternal(req with { Order = Orders.None }) + .WithNoLockNoWait() + .GroupBy(req.GetToListExp()) + .ToDictionaryAsync(a => a.Count()) + .ConfigureAwait(false); + return ret.Select(x => new KeyValuePair, int>( + req.RequiredFields.ToImmutableDictionary( + y => y, y => typeof(Sys_UserWallet).GetProperty(y)!.GetValue(x.Key)?.ToString()), x.Value)) + .Where(x => x.Key.Any(y => !y.Value.NullOrEmpty())) + .OrderByDescending(x => x.Value); + } + + /// + public async Task CreateAsync(CreateUserWalletReq req) + { + req.ThrowIfInvalid(); + var ret = await Rpo.InsertAsync(req).ConfigureAwait(false); + return ret.Adapt(); + } + + /// + public Task DeleteAsync(DelReq req) + { + req.ThrowIfInvalid(); + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + public async Task EditAsync(EditUserWalletReq req) + { + req.ThrowIfInvalid(); + #if DBTYPE_SQLSERVER + return (await UpdateReturnListAsync(req).ConfigureAwait(false)).FirstOrDefault()?.Adapt(); + #else + return await UpdateAsync(req).ConfigureAwait(false) > 0 ? await GetAsync(new QueryUserWalletReq { Id = req.Id }).ConfigureAwait(false) : null; + #endif + } + + /// + public Task ExportAsync(QueryReq req) + { + req.ThrowIfInvalid(); + return ExportAsync(QueryInternal, req, Ln.用户钱包导出); + } + + /// + public async Task GetAsync(QueryUserWalletReq req) + { + req.ThrowIfInvalid(); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false); + return ret.Adapt(); + } + + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + req.ThrowIfInvalid(); + var list = await QueryInternal(req) + .Include(a => a.Owner) + .Page(req.Page, req.PageSize) + .WithNoLockNoWait() + .Count(out var total) + .ToListAsync(req) + .ConfigureAwait(false); + + return new PagedQueryRsp(req.Page, req.PageSize, total, list.Adapt>()); + } + + /// + public async Task> QueryAsync(QueryReq req) + { + req.ThrowIfInvalid(); + var ret = await QueryInternal(req).WithNoLockNoWait().Take(req.Count).ToListAsync(req).ConfigureAwait(false); + return ret.Adapt>(); + } + + private ISelect QueryInternal(QueryReq req) + { + IEnumerable deptIds = null; + if (req.Filter?.DeptId > 0) { + deptIds = Rpo.Orm.Select().Where(a => a.Id == req.Filter.DeptId).AsTreeCte().ToList(a => a.Id); + } + + return QueryInternal(req, deptIds); + } + + private ISelect QueryInternal(QueryReq req, IEnumerable deptIds) + { + var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereIf(req.Filter?.Id > 0, a => a.Id == req.Filter.Id) + .WhereIf(deptIds != null, a => deptIds.Contains(a.Owner.DeptId)) + .WhereIf( // + req.Filter?.RoleId > 0, a => a.Owner.Roles.Any(b => b.Id == req.Filter.RoleId)); + + // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault + switch (req.Order) { + case Orders.None: + return ret; + case Orders.Random: + return ret.OrderByRandom(); + } + + ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.Id); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/WalletTradeService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/WalletTradeService.cs new file mode 100644 index 00000000..0bc7ff62 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/WalletTradeService.cs @@ -0,0 +1,145 @@ +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.UserWallet; +using NetAdmin.Domain.Dto.Sys.WalletTrade; +using NetAdmin.Domain.Extensions; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class WalletTradeService(BasicRepository rpo) // + : RepositoryService(rpo), IWalletTradeService +{ + /// + public async Task BulkDeleteAsync(BulkReq req) + { + req.ThrowIfInvalid(); + var ret = 0; + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var item in req.Items) { + ret += await DeleteAsync(item).ConfigureAwait(false); + } + + return ret; + } + + /// + public Task CountAsync(QueryReq req) + { + req.ThrowIfInvalid(); + return QueryInternal(req).WithNoLockNoWait().CountAsync(); + } + + /// + public async Task, int>>> CountByAsync(QueryReq req) + { + req.ThrowIfInvalid(); + var ret = await QueryInternal(req with { Order = Orders.None }) + .WithNoLockNoWait() + .GroupBy(req.GetToListExp()) + .ToDictionaryAsync(a => a.Count()) + .ConfigureAwait(false); + return ret.Select(x => new KeyValuePair, int>( + req.RequiredFields.ToImmutableDictionary( + y => y, y => typeof(Sys_WalletTrade).GetProperty(y)!.GetValue(x.Key)?.ToString()), x.Value)) + .Where(x => x.Key.Any(y => !y.Value.NullOrEmpty())) + .OrderByDescending(x => x.Value); + } + + /// + public async Task CreateAsync(CreateWalletTradeReq req) + { + req.ThrowIfInvalid(); + var userWalletService = S(); + var wallet = await userWalletService.GetAsync(new QueryUserWalletReq { Id = req.OwnerId!.Value }).ConfigureAwait(false); + if (wallet.AvailableBalance + req.Amount < 0) { + throw new NetAdminInvalidOperationException(Ln.钱包余额不足); + } + + _ = await userWalletService.EditAsync(wallet.Adapt() with { + AvailableBalance = wallet.AvailableBalance + req.Amount + , TotalBalance = wallet.TotalBalance + req.Amount + }) + .ConfigureAwait(false) ?? throw new NetAdminUnexpectedException(Ln.交易失败); + var ret = await Rpo.InsertAsync(req with { BalanceBefore = wallet.AvailableBalance, OwnerDeptId = wallet.OwnerDeptId }).ConfigureAwait(false); + return ret.Adapt(); + } + + /// + public Task DeleteAsync(DelReq req) + { + req.ThrowIfInvalid(); + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + public async Task EditAsync(EditWalletTradeReq req) + { + req.ThrowIfInvalid(); + #if DBTYPE_SQLSERVER + return (await UpdateReturnListAsync(req).ConfigureAwait(false)).FirstOrDefault()?.Adapt(); + #else + return await UpdateAsync(req).ConfigureAwait(false) > 0 + ? await GetAsync(new QueryWalletTradeReq { Id = req.Id }).ConfigureAwait(false) + : null; + #endif + } + + /// + public Task ExportAsync(QueryReq req) + { + req.ThrowIfInvalid(); + return ExportAsync(QueryInternal, req, Ln.钱包交易导出); + } + + /// + public async Task GetAsync(QueryWalletTradeReq req) + { + req.ThrowIfInvalid(); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false); + return ret.Adapt(); + } + + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + req.ThrowIfInvalid(); + var list = await QueryInternal(req) + .Include(a => a.Owner) + .Page(req.Page, req.PageSize) + .WithNoLockNoWait() + .Count(out var total) + .ToListAsync(req) + .ConfigureAwait(false); + + return new PagedQueryRsp(req.Page, req.PageSize, total, list.Adapt>()); + } + + /// + public async Task> QueryAsync(QueryReq req) + { + req.ThrowIfInvalid(); + var ret = await QueryInternal(req).WithNoLockNoWait().Take(req.Count).ToListAsync(req).ConfigureAwait(false); + return ret.Adapt>(); + } + + private ISelect QueryInternal(QueryReq req) + { + var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter); + + // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault + switch (req.Order) { + case Orders.None: + return ret; + case Orders.Random: + return ret.OrderByRandom(); + } + + ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.Id); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserWalletCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserWalletCache.cs new file mode 100644 index 00000000..a2175194 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserWalletCache.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 用户钱包缓存 +/// +public interface IUserWalletCache : ICache, IUserWalletModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IWalletTradeCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IWalletTradeCache.cs new file mode 100644 index 00000000..ec5e1aec --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/IWalletTradeCache.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 钱包交易缓存 +/// +public interface IWalletTradeCache : ICache, IWalletTradeModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/UserWalletCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/UserWalletCache.cs new file mode 100644 index 00000000..c5a59d58 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/UserWalletCache.cs @@ -0,0 +1,68 @@ +using NetAdmin.Domain.Dto.Sys.UserWallet; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +public sealed class UserWalletCache(IDistributedCache cache, IUserWalletService service) + : DistributedCache(cache, service), IScoped, IUserWalletCache +{ + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CountAsync(QueryReq req) + { + return Service.CountAsync(req); + } + + /// + public Task, int>>> CountByAsync(QueryReq req) + { + return Service.CountByAsync(req); + } + + /// + public Task CreateAsync(CreateUserWalletReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task EditAsync(EditUserWalletReq req) + { + return Service.EditAsync(req); + } + + /// + public Task ExportAsync(QueryReq req) + { + return Service.ExportAsync(req); + } + + /// + public Task GetAsync(QueryUserWalletReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/WalletTradeCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/WalletTradeCache.cs new file mode 100644 index 00000000..a97020e2 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/WalletTradeCache.cs @@ -0,0 +1,68 @@ +using NetAdmin.Domain.Dto.Sys.WalletTrade; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +public sealed class WalletTradeCache(IDistributedCache cache, IWalletTradeService service) + : DistributedCache(cache, service), IScoped, IWalletTradeCache +{ + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CountAsync(QueryReq req) + { + return Service.CountAsync(req); + } + + /// + public Task, int>>> CountByAsync(QueryReq req) + { + return Service.CountByAsync(req); + } + + /// + public Task CreateAsync(CreateWalletTradeReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task EditAsync(EditWalletTradeReq req) + { + return Service.EditAsync(req); + } + + /// + public Task ExportAsync(QueryReq req) + { + return Service.ExportAsync(req); + } + + /// + public Task GetAsync(QueryWalletTradeReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/UserWalletController.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/UserWalletController.cs new file mode 100644 index 00000000..51cab216 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/UserWalletController.cs @@ -0,0 +1,97 @@ +using NetAdmin.Domain.Dto.Sys.UserWallet; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 用户钱包服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)] +public sealed class UserWalletController(IUserWalletCache cache) : ControllerBase(cache), IUserWalletModule +{ + /// + /// 批量删除用户钱包 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 用户钱包计数 + /// + public Task CountAsync(QueryReq req) + { + return Cache.CountAsync(req); + } + + /// + /// 用户钱包分组计数 + /// + public Task, int>>> CountByAsync(QueryReq req) + { + return Cache.CountByAsync(req); + } + + /// + /// 创建用户钱包 + /// + [Transaction] + public Task CreateAsync(CreateUserWalletReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除用户钱包 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 编辑用户钱包 + /// + [Transaction] + public Task EditAsync(EditUserWalletReq req) + { + return Cache.EditAsync(req); + } + + /// + /// 导出用户钱包 + /// + [NonAction] + public Task ExportAsync(QueryReq req) + { + return Cache.ExportAsync(req); + } + + /// + /// 获取单个用户钱包 + /// + public Task GetAsync(QueryUserWalletReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询用户钱包 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询用户钱包 + /// + [NonAction] + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/WalletTradeController.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/WalletTradeController.cs new file mode 100644 index 00000000..1efffb3b --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/WalletTradeController.cs @@ -0,0 +1,97 @@ +using NetAdmin.Domain.Dto.Sys.WalletTrade; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 钱包交易服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)] +public sealed class WalletTradeController(IWalletTradeCache cache) : ControllerBase(cache), IWalletTradeModule +{ + /// + /// 批量删除钱包交易 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 钱包交易计数 + /// + public Task CountAsync(QueryReq req) + { + return Cache.CountAsync(req); + } + + /// + /// 钱包交易分组计数 + /// + public Task, int>>> CountByAsync(QueryReq req) + { + return Cache.CountByAsync(req); + } + + /// + /// 创建钱包交易 + /// + [Transaction] + public Task CreateAsync(CreateWalletTradeReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除钱包交易 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 编辑钱包交易 + /// + [Transaction] + public Task EditAsync(EditWalletTradeReq req) + { + return Cache.EditAsync(req); + } + + /// + /// 导出钱包交易 + /// + [NonAction] + public Task ExportAsync(QueryReq req) + { + return Cache.ExportAsync(req); + } + + /// + /// 获取单个钱包交易 + /// + public Task GetAsync(QueryWalletTradeReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询钱包交易 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询钱包交易 + /// + [NonAction] + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs index b2f11563..3192cd40 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs @@ -45,21 +45,21 @@ public sealed class OperationLogger : IEventSubscriber // 插入登录日志 if (log.ApiPathCrc32 == Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD.Crc32()) { - _ = await App.GetService().CreateAsync(log.Adapt()).ConfigureAwait(false); + _ = await S().CreateAsync(log.Adapt()).ConfigureAwait(false); } } // 如果首尾日期不一致,要分别插入不同的日期分表 if (inserts[0].CreatedTime.Date != inserts[^1].CreatedTime.Date) { foreach (var dayInserts in inserts.GroupBy(x => x.CreatedTime.Date)) { - await App.GetService() + await S() .Insert(dayInserts.Select(x => x)) .ExecuteSqlBulkCopyAsync(tableName: $"{nameof(Sys_RequestLog)}_{dayInserts.Key:yyyyMMdd}") .ConfigureAwait(false); } } else { - await App.GetService() + await S() .Insert(inserts) .ExecuteSqlBulkCopyAsync(tableName: $"{nameof(Sys_RequestLog)}_{inserts[0].CreatedTime:yyyyMMdd}") .ConfigureAwait(false); diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Utils/SqlAuditor.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Utils/SqlAuditor.cs index 9fd72387..f3c08207 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Utils/SqlAuditor.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Utils/SqlAuditor.cs @@ -149,7 +149,7 @@ public sealed class SqlAuditor : ISingleton } /// - /// 设置拥有者 + /// 设置所有者 /// private static void SetOwner(AuditValueEventArgs e, ContextUserInfo userInfo) { diff --git a/src/frontend/admin/package.json b/src/frontend/admin/package.json index 6050b930..bb7996d1 100644 --- a/src/frontend/admin/package.json +++ b/src/frontend/admin/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@element-plus/icons-vue": "2.3.1", - "ace-builds": "1.42.0", - "aieditor": "1.3.9", + "ace-builds": "1.43.0", + "aieditor": "1.4.0", "axios": "1.10.0", "crypto-js": "4.2.0", "dayjs": "1.11.13", @@ -23,8 +23,8 @@ "nprogress": "0.2.0", "sortablejs": "1.15.6", "vkbeautify": "0.99.3", - "vue": "3.5.16", - "vue-i18n": "11.1.6", + "vue": "3.5.17", + "vue-i18n": "11.1.7", "vue-router": "4.5.1", "vue3-ace-editor": "2.2.4", "vue3-json-viewer": "2.4.0", @@ -32,12 +32,12 @@ "vuex": "4.1.0" }, "devDependencies": { - "@vitejs/plugin-vue": "5.2.4", - "prettier": "3.5.3", + "@vitejs/plugin-vue": "6.0.0", + "prettier": "3.6.1", "prettier-plugin-organize-attributes": "1.0.0", "sass": "1.89.2", - "terser": "5.43.0", - "vite": "6.3.5" + "terser": "5.43.1", + "vite": "7.0.0" }, "browserslist": [ "> 1%", diff --git a/src/frontend/admin/src/api/sys/userwallet.js b/src/frontend/admin/src/api/sys/userwallet.js new file mode 100644 index 00000000..1b56ab4f --- /dev/null +++ b/src/frontend/admin/src/api/sys/userwallet.js @@ -0,0 +1,95 @@ +/** + * 用户钱包服务 + * @module @/api/sys/user.wallet + */ +import config from '@/config' +import http from '@/utils/request' +export default { + /** + * 批量删除用户钱包 + */ + bulkDelete: { + url: `${config.API_URL}/api/sys/user.wallet/bulk.delete`, + name: `批量删除用户钱包`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 用户钱包计数 + */ + count: { + url: `${config.API_URL}/api/sys/user.wallet/count`, + name: `用户钱包计数`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 用户钱包分组计数 + */ + countBy: { + url: `${config.API_URL}/api/sys/user.wallet/count.by`, + name: `用户钱包分组计数`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 创建用户钱包 + */ + create: { + url: `${config.API_URL}/api/sys/user.wallet/create`, + name: `创建用户钱包`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 删除用户钱包 + */ + delete: { + url: `${config.API_URL}/api/sys/user.wallet/delete`, + name: `删除用户钱包`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 编辑用户钱包 + */ + edit: { + url: `${config.API_URL}/api/sys/user.wallet/edit`, + name: `编辑用户钱包`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 获取单个用户钱包 + */ + get: { + url: `${config.API_URL}/api/sys/user.wallet/get`, + name: `获取单个用户钱包`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 分页查询用户钱包 + */ + pagedQuery: { + url: `${config.API_URL}/api/sys/user.wallet/paged.query`, + name: `分页查询用户钱包`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/wallettrade.js b/src/frontend/admin/src/api/sys/wallettrade.js new file mode 100644 index 00000000..0a8cbc07 --- /dev/null +++ b/src/frontend/admin/src/api/sys/wallettrade.js @@ -0,0 +1,95 @@ +/** + * 钱包交易服务 + * @module @/api/sys/wallet.trade + */ +import config from '@/config' +import http from '@/utils/request' +export default { + /** + * 批量删除钱包交易 + */ + bulkDelete: { + url: `${config.API_URL}/api/sys/wallet.trade/bulk.delete`, + name: `批量删除钱包交易`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 钱包交易计数 + */ + count: { + url: `${config.API_URL}/api/sys/wallet.trade/count`, + name: `钱包交易计数`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 钱包交易分组计数 + */ + countBy: { + url: `${config.API_URL}/api/sys/wallet.trade/count.by`, + name: `钱包交易分组计数`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 创建钱包交易 + */ + create: { + url: `${config.API_URL}/api/sys/wallet.trade/create`, + name: `创建钱包交易`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 删除钱包交易 + */ + delete: { + url: `${config.API_URL}/api/sys/wallet.trade/delete`, + name: `删除钱包交易`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 编辑钱包交易 + */ + edit: { + url: `${config.API_URL}/api/sys/wallet.trade/edit`, + name: `编辑钱包交易`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 获取单个钱包交易 + */ + get: { + url: `${config.API_URL}/api/sys/wallet.trade/get`, + name: `获取单个钱包交易`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 分页查询钱包交易 + */ + pagedQuery: { + url: `${config.API_URL}/api/sys/wallet.trade/paged.query`, + name: `分页查询钱包交易`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/global.js b/src/frontend/admin/src/global.js index 4db354f3..12529e0b 100644 --- a/src/frontend/admin/src/global.js +++ b/src/frontend/admin/src/global.js @@ -60,6 +60,9 @@ export default { hasPermission: function (p) { return this.permissions.includes('*/*/*') || this.permissions.some((a) => a === p) }, + hasApiPermission: function (p) { + return this.apiPermissions.includes('*/*/*') || this.apiPermissions.some((a) => a === p) + }, } app.use(JsonViewer) diff --git a/src/frontend/admin/src/layout/components/tasks.vue b/src/frontend/admin/src/layout/components/tasks.vue index 235b7b62..9c407735 100644 --- a/src/frontend/admin/src/layout/components/tasks.vue +++ b/src/frontend/admin/src/layout/components/tasks.vue @@ -6,7 +6,7 @@ x.ignorePermissionControl) >= 0 ? ['*/*/*'] : tool.recursiveFindProperty(preloads[0]?.data, 'type', 'button').map((x) => x.tag) + global.apiPermissions = + global.user?.roles.findIndex((x) => x.ignorePermissionControl) >= 0 + ? ['*/*/*'] + : preloads[1]?.data?.roles + ?.map((x) => x.apiIds.join(',')) + ?.join(',') + .split(',') }, } \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/logs.vue b/src/frontend/admin/src/views/profile/logs.vue index 2dd2ec72..6203a2ce 100644 --- a/src/frontend/admin/src/views/profile/logs.vue +++ b/src/frontend/admin/src/views/profile/logs.vue @@ -1,6 +1,6 @@ diff --git a/src/frontend/admin/src/views/sys/log/login/index.vue b/src/frontend/admin/src/views/sys/log/login/index.vue index dbe768c5..d5ef56b3 100644 --- a/src/frontend/admin/src/views/sys/log/login/index.vue +++ b/src/frontend/admin/src/views/sys/log/login/index.vue @@ -74,10 +74,19 @@ (this.$refs.selectFilter.selected[key] = [''])) + if (this.showFilter) { + Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = [''])) + } + this.$refs.search.selectInputKey = 'id' + if (this.ownerId) this.$refs.search.selectInputKey = 'owner.id' }, //搜索 async onSearch(form) { @@ -255,6 +275,13 @@ export default { ) } + if (typeof form.dy.id === 'string' && form.dy.id.trim() !== '') { + this.query.dynamicFilter.filters.push({ + field: 'id', + operator: 'eq', + value: form.dy.id, + }) + } if (typeof form.dy.errorCode === 'string' && form.dy.errorCode.trim() !== '') { this.query.dynamicFilter.filters.push({ field: 'errorCode', @@ -279,6 +306,15 @@ export default { }) } + if (typeof form.dy['owner.id'] === 'string' && form.dy['owner.id'].trim() !== '') { + this.$refs.search.selectInputKey = 'owner.id' + this.query.dynamicFilter.filters.push({ + field: 'owner.id', + operator: 'eq', + value: form.dy['owner.id'], + }) + } + await this.$refs.table.upData() }, @@ -295,6 +331,15 @@ export default { }, }, async mounted() { + if (this.ownerId) { + this.$refs.search.selectInputKey = 'owner.id' + this.$refs.search.form.dy['owner.id'] = this.ownerId + this.$refs.search.keeps.push({ + field: 'owner.id', + value: this.ownerId, + type: 'dy', + }) + } if (this.keywords) { this.$refs.search.form.root.keywords = this.keywords this.$refs.search.keeps.push({ @@ -303,8 +348,9 @@ export default { type: 'root', }) } + this.onReset() }, - props: { keywords: { type: String }, showFilter: { type: Boolean, default: true } }, + props: { keywords: { type: String }, showFilter: { type: Boolean, default: true }, ownerId: { type: String } }, watch: {}, } diff --git a/src/frontend/admin/src/views/sys/log/operation/index.vue b/src/frontend/admin/src/views/sys/log/operation/index.vue index 762a8342..adac19f2 100644 --- a/src/frontend/admin/src/views/sys/log/operation/index.vue +++ b/src/frontend/admin/src/views/sys/log/operation/index.vue @@ -67,7 +67,7 @@ config: { props: { label: 'userName', value: 'id' } }, placeholder: '用户', style: 'width:15rem', - condition: () => $GLOBAL.hasPermission('sys/log/operation/user'), + condition: () => $GLOBAL.hasApiPermission('api/sys/user/query'), }, { multiple: true, diff --git a/src/frontend/admin/src/views/sys/trade/index.vue b/src/frontend/admin/src/views/sys/trade/index.vue new file mode 100644 index 00000000..6b0750f0 --- /dev/null +++ b/src/frontend/admin/src/views/sys/trade/index.vue @@ -0,0 +1,323 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/trade/save.vue b/src/frontend/admin/src/views/sys/trade/save.vue new file mode 100644 index 00000000..0b9ac35b --- /dev/null +++ b/src/frontend/admin/src/views/sys/trade/save.vue @@ -0,0 +1,119 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/user/index.vue b/src/frontend/admin/src/views/sys/user/index.vue index 1c6c1543..53cf0aed 100644 --- a/src/frontend/admin/src/views/sys/user/index.vue +++ b/src/frontend/admin/src/views/sys/user/index.vue @@ -116,8 +116,8 @@ + + + + + + @@ -259,12 +265,14 @@ import { defineAsyncComponent } from 'vue' const log = defineAsyncComponent(() => import('@/views/sys/log/operation')) +const trade = defineAsyncComponent(() => import('@/views/sys/trade')) +const wallet = defineAsyncComponent(() => import('@/views/sys/wallet')) const naArea = defineAsyncComponent(() => import('@/components/naArea')) const naDept = defineAsyncComponent(() => import('@/components/naDept')) const scUpload = defineAsyncComponent(() => import('@/components/scUpload')) const scSelect = defineAsyncComponent(() => import('@/components/scSelect')) export default { - components: { log, naArea, naDept, scUpload, scSelect }, + components: { log, naArea, naDept, scUpload, scSelect, trade, wallet }, data() { return { //表单数据 diff --git a/src/frontend/admin/src/views/sys/wallet/index.vue b/src/frontend/admin/src/views/sys/wallet/index.vue new file mode 100644 index 00000000..1b15ebf1 --- /dev/null +++ b/src/frontend/admin/src/views/sys/wallet/index.vue @@ -0,0 +1,315 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/wallet/save.vue b/src/frontend/admin/src/views/sys/wallet/save.vue new file mode 100644 index 00000000..005c980a --- /dev/null +++ b/src/frontend/admin/src/views/sys/wallet/save.vue @@ -0,0 +1,124 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/wallet/trade.vue b/src/frontend/admin/src/views/sys/wallet/trade.vue new file mode 100644 index 00000000..779f13f2 --- /dev/null +++ b/src/frontend/admin/src/views/sys/wallet/trade.vue @@ -0,0 +1,91 @@ + + + + + \ No newline at end of file