10 Commits
v2.4.0 ... main

Author SHA1 Message Date
1650b8a127 feat: 框架代码同步 (#342)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-07-29 10:11:54 +08:00
tk
e99cb2aff9 feat: 框架代码同步 2025-07-19 10:00:04 +08:00
tk
4f6d465602 refactor: ♻️ projectUsings
[skip ci]
2025-07-15 19:26:28 +08:00
tk
fe19289b79 feat: 钱包冻结解冻 2025-07-15 19:21:58 +08:00
tk
e4d71a516d 1 2025-07-10 15:05:00 +08:00
tk
c15abdc5bb 1 2025-07-10 15:05:00 +08:00
4a5a7b96fc fix: 🐛 build err (#337)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-07-09 11:19:46 +08:00
3f4f547338 fix: 🐛 编译错误 (#336)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-07-09 09:44:58 +08:00
d01ead8283 feat: 代码模板 (#335)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-07-08 16:04:15 +08:00
dc3249428a Merge pull request #333 from nsnail/release
chore(release): 2.4.0
2025-07-02 19:32:05 +08:00
312 changed files with 6967 additions and 2545 deletions

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/aspnet:9.0.5 AS base
FROM mcr.microsoft.com/dotnet/aspnet:9.0.7 AS base
WORKDIR /app
EXPOSE 8080
RUN apt update

View File

@ -13,7 +13,10 @@ USDT
中专
中共党员
为其中之一
交易
人工
人工审核
代码模板导出
以什么开始
以什么结束
作业名称
@ -38,6 +41,7 @@ USDT
响应体
响应状态码
唯一编码
处理中
备注
外国人居留证
外部错误
@ -52,13 +56,17 @@ USDT
小于
小于等于
小学
已冻结
已发送
已婚
已完成
已校验
已解冻
已读
并且
归属角色
归属部门
待执行
微信支付
成功
或者
@ -93,10 +101,12 @@ USDT
最后登录时间
未处理异常
未婚
未结算
未读
本人数据
本科
本部门和下级部门数据
本部门和下级部门数据
本部门和所有子部门数据
本部门数据
框架
比较数据库结构
@ -106,6 +116,7 @@ USDT
消息类型
港澳台通行证
用户代理
用户取消
用户名
用户导出
用户邀请导出
@ -116,15 +127,14 @@ USDT
登录名
登录日志导出
硕士
示例导出
离异
空闲
站内信导出
等于
等待发送
等待支付
管理员充值
管理员扣费
管理员赠送
管理模块
系统模块
绑定手机号码
@ -144,6 +154,8 @@ USDT
请求日志导出
调试
身份证
转账支出
转账收入
运行
追踪
追踪标识
@ -154,6 +166,7 @@ USDT
配置导出
重设密码
钱包交易导出
钱包冻结导出
链接
错误
随机排序

View File

@ -2,6 +2,7 @@
6位数字
8位以上数字字母组合
XML注释文件不存在
不能设置自己为上级
中文姓名
事务已回滚
事务已提交
@ -12,6 +13,7 @@ XML注释文件不存在
作业名称不能为空
允许的文件大小
允许的文件格式
冻结状态不正确
区号电话号码分机号
参数格式不正确
唯一编码不能为空
@ -31,6 +33,7 @@ XML注释文件不存在
性别不正确
手机号码不正确
手机号码不能为空
指定的上级为该账号的下级用户
接口编码不存在
支付宝账号
支付方式不正确
@ -58,25 +61,21 @@ XML注释文件不存在
未指定部门
未获取到待执行任务
档案可见性不正确
模块名称不能为空
模块类型不能为空
模块说明不能为空
此节点已下线
民族不正确
消息主题不能为空
消息内容不能为空
父节点不存在
用户不存在
用户名不符合要求
用户名不能为空
用户名不能是手机号码
用户名或密码错误
用户名长度4位以上
用户头像不能为空
用户编号不存在
登录用户
目标设备不能为空
短信验证请求不能为空
种子数据插入完成
站内信不存在
站内信状态不正确
站内信类型不正确
@ -111,12 +110,13 @@ XML注释文件不存在
部门可见
部门名称不能为空
配置文件初始化完毕
钱包余额不足
钱包可用余额不足
键值不能为空
键名称不能为空
随机延时结束时间不正确
随机延时起始时间不正确
非JSON字符串
此操作不被允许
验证数据不能为空
验证码不正确
验证码不能为空

View File

@ -0,0 +1 @@
示例导出

View File

@ -0,0 +1,16 @@
[
{
"Enabled": true,
"Gender": 1,
"Id": 694360665923594,
"Name": "老王",
"Sort": 100,
},
{
"Enabled": true,
"Gender": 2,
"Id": 694360665923595,
"Name": "媳妇儿",
"Sort": 100,
}
]

View File

@ -1,5 +1,5 @@
[
// ------------------------------ 主控面板 ------------------------------
// ------------------------------ 主控面板 /home ------------------------------
{
"Component": "home",
"Icon": "el-icon-house",
@ -8,9 +8,9 @@
"Path": "/home",
"Sort": 999,
"Title": "主控面板",
"Type": 1
"Type": 1,
},
// ------------------------------ 权限管理 ------------------------------
// ------------------------------ 权限管理 /power ------------------------------
{
"Icon": "el-icon-setting",
"Id": 373837917724677,
@ -18,96 +18,96 @@
"Path": "/power",
"Sort": 100,
"Title": "权限管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/user",
"Component": "sys/power/user",
"Icon": "el-icon-user",
"Id": 373837957840901,
"Name": "sys/user",
"Name": "sys/power/user",
"ParentId": 373837917724677,
"Path": "/power/user",
"Sort": 100,
"Title": "用户管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/role",
"Component": "sys/power/role",
"Icon": "sc-icon-role",
"Id": 373838018527237,
"Name": "sys/role",
"Name": "sys/power/role",
"ParentId": 373837917724677,
"Path": "/power/role",
"Sort": 99,
"Title": "角色管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/dept",
"Component": "sys/power/dept",
"Icon": "sc-icon-dept",
"Id": 373838045605893,
"Name": "sys/dept",
"Name": "sys/power/dept",
"ParentId": 373837917724677,
"Path": "/power/dept",
"Sort": 98,
"Title": "部门管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/menu",
"Component": "sys/power/menu",
"Icon": "el-icon-fold",
"Id": 373838070898693,
"Name": "sys/menu",
"Name": "sys/power/menu",
"ParentId": 373837917724677,
"Path": "/power/menu",
"Sort": 97,
"Title": "菜单管理",
"Type": 1
"Type": 1,
},
// ------------------------------ 财务管理 ------------------------------
// ------------------------------ 财务管理 /finance ------------------------------
{
"Icon": "el-icon-money",
"Id": 690906994118665,
"Name": "finance",
"Name": "sys/finance",
"Path": "/finance",
"Sort": 99,
"Title": "财务管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/wallet",
"Component": "sys/finance/wallet",
"Icon": "el-icon-wallet",
"Id": 690907673255942,
"Name": "sys/wallet",
"Name": "sys/finance/wallet",
"ParentId": 690906994118665,
"Path": "/finance/wallet",
"Sort": 100,
"Title": "钱包管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/trade",
"Component": "sys/finance/trade",
"Icon": "el-icon-calendar",
"Id": 690907673255943,
"Name": "sys/trade",
"Name": "sys/finance/trade",
"ParentId": 690906994118665,
"Path": "/finance/trade",
"Sort": 99,
"Title": "交易流水",
"Type": 1
"Type": 1,
},
{
"Component": "sys/order",
"Component": "sys/finance/order",
"Icon": "el-icon-shopping-cart",
"Id": 690907673255944,
"Name": "sys/order",
"Name": "sys/finance/order",
"ParentId": 690906994118665,
"Path": "/finance/order",
"Sort": 98,
"Title": "充值订单",
"Type": 1
"Title": "自助充值",
"Type": 1,
},
// ------------------------------ 营销管理 ------------------------------
// ------------------------------ 营销管理 /market ------------------------------
{
"Icon": "el-icon-share",
"Id": 692575802241032,
@ -115,67 +115,67 @@
"Path": "/market",
"Sort": 98,
"Title": "营销管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/invite",
"Component": "sys/market/invite",
"Icon": "el-icon-connection",
"Id": 692575802245126,
"Name": "sys/invite",
"Name": "sys/market/invite",
"ParentId": 692575802241032,
"Path": "/market/invite",
"Sort": 100,
"Title": "邀请管理",
"Type": 1
"Title": "粉丝管理",
"Type": 1,
},
// ------------------------------ 系统管理 ------------------------------
// ------------------------------ 系统管理 /system ------------------------------
{
"Icon": "sc-icon-app",
"Id": 485278637670422,
"Name": "sys",
"Path": "/sys",
"Name": "system",
"Path": "/system",
"Sort": 98,
"Title": "系统管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/config",
"Component": "sys/system/config",
"Icon": "el-icon-set-up",
"Id": 380415005847557,
"Name": "sys/config",
"Name": "sys/system/config",
"ParentId": 485278637670422,
"Path": "/system/config",
"Sort": 100,
"Title": "系统设置",
"Type": 1
"Type": 1,
},
{
"Component": "sys/job",
"Component": "sys/system/job",
"Icon": "sc-icon-scheduled-job",
"Id": 510067557638158,
"Name": "sys/job",
"Name": "sys/system/job",
"ParentId": 485278637670422,
"Path": "/system/job",
"Sort": 99,
"Title": "计划作业",
"Type": 1
"Type": 1,
},
{
"Component": "sys/dic",
"Component": "sys/system/dic",
"Icon": "sc-icon-dic",
"Id": 375315654221829,
"Name": "sys/dic",
"Name": "sys/system/dic",
"ParentId": 485278637670422,
"Path": "/system/dic",
"Sort": 98,
"Title": "字典管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/msg",
"Component": "sys/system/msg",
"Icon": "el-icon-message",
"Id": 482779610341392,
"Name": "sys/msg",
"Name": "sys/system/msg",
"ParentId": 485278637670422,
"Path": "/system/msg",
"Sort": 97,
@ -183,28 +183,28 @@
"Type": 1,
},
{
"Component": "sys/api",
"Component": "sys/system/api",
"Icon": "sc-icon-api",
"Id": 397880678895621,
"Name": "sys/api",
"Name": "sys/system/api",
"ParentId": 485278637670422,
"Path": "/system/api",
"Sort": 96,
"Title": "接口管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/cache",
"Component": "sys/system/cache",
"Icon": "sc-icon-memory",
"Id": 374911555702789,
"Name": "sys/cache",
"Name": "sys/system/cache",
"ParentId": 485278637670422,
"Path": "/system/cache",
"Sort": 95,
"Title": "缓存管理",
"Type": 1
"Type": 1,
},
// ------------------------------ 档案管理 ------------------------------
// ------------------------------ 档案管理 /archive ------------------------------
{
"Icon": "sc-icon-archive",
"Id": 616214756757512,
@ -212,20 +212,20 @@
"Path": "/archive",
"Sort": 97,
"Title": "档案管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/doc",
"Component": "sys/archive/doc",
"Icon": "el-icon-document",
"Id": 616214756757516,
"Name": "archive/doc",
"Name": "sys/archive/doc",
"ParentId": 616214756757512,
"Path": "/archive/doc",
"Sort": 100,
"Title": "文档管理",
"Type": 1
"Type": 1,
},
// ------------------------------ 日志管理 ------------------------------
// ------------------------------ 日志管理 /log ------------------------------
{
"Icon": "el-icon-tickets",
"Id": 374792687640581,
@ -233,7 +233,7 @@
"Path": "/log",
"Sort": 96,
"Title": "日志管理",
"Type": 1
"Type": 1,
},
{
"Component": "sys/log/operation",
@ -257,7 +257,7 @@
"Title": "登录日志",
"Type": 1,
},
// ------------------------------ 开发管理 ------------------------------
// ------------------------------ 开发管理 /dev ------------------------------
{
"Icon": "sc-icon-code",
"Id": 373838105399301,
@ -265,18 +265,29 @@
"Path": "/dev",
"Sort": 95,
"Title": "开发管理",
"Type": 1
"Type": 1,
},
{
"Component": "dev/code",
"Component": "sys/dev/code",
"Icon": "sc-icon-code2",
"Id": 373838147022853,
"Name": "dev/code",
"Name": "sys/dev/code",
"ParentId": 373838105399301,
"Path": "/dev/code",
"Sort": 100,
"Title": "代码生成",
"Type": 1
"Type": 1,
},
{
"Component": "sys/dev/template",
"Icon": "sc-icon-template",
"Id": 694076641718288,
"Name": "sys/dev/template",
"ParentId": 373838105399301,
"Path": "/dev/template",
"Sort": 99,
"Title": "页面模板",
"Type": 1,
},
{
"Id": 482777529417739,
@ -284,7 +295,7 @@
"Icon": "el-icon-eleme-filled",
"Name": "dev/element",
"Path": "https://element-plus.org/zh-CN/component/overview.html",
"Sort": 99,
"Sort": 98,
"Title": "Element",
"Type": 3,
},
@ -294,7 +305,7 @@
"Icon": "sc-icon-free-sql",
"Name": "dev/freesql",
"Path": "https://freesql.net/guide",
"Sort": 99,
"Sort": 97,
"Title": "FreeSql",
"Type": 3,
}

View File

@ -106,5 +106,17 @@
{
"ApiId": "api/sys/user.invite/query",
"RoleId": 371729946431493,
}
},
{
"ApiId": "api/sys/wallet.frozen/get",
"RoleId": 371729946431493,
},
{
"ApiId": "api/sys/wallet.frozen/paged.query",
"RoleId": 371729946431493,
},
{
"ApiId": "api/sys/wallet.frozen/count.by",
"RoleId": 371729946431493,
},
]

View File

@ -19,11 +19,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.13.1">
<PackageReference Include="Roslynator.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.12.0.118525">
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.15.0.120848">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -1,7 +1,7 @@
{
"version": "2.4.0",
"devDependencies": {
"cz-git": "^1.11.2",
"cz-git": "^1.12.0",
"commitizen": "^4.3.1",
"prettier": "^3.6.2",
"standard-version": "^9.5.0"
@ -11,4 +11,4 @@
"path": "node_modules/cz-git"
}
}
}
}

View File

@ -0,0 +1,24 @@
using NetAdmin.Domain;
using NetAdmin.Domain.Dto.Dependency;
namespace NetAdmin.Application.Extensions;
/// <summary>
/// FreeSql Select 扩展方法
/// </summary>
public static class ISelectExtensions
{
/// <summary>
/// 附加其他过滤条件
/// </summary>
public static ISelect<T> AppendOtherFilters<T, TQuery>(this ISelect<T> me, QueryReq<TQuery> req)
where TQuery : DataAbstraction, new()
{
if (req.IgnoreOwner) {
me = me.DisableGlobalFilter(Chars.FLG_FREE_SQL_GLOBAL_FILTER_SELF, Chars.FLG_FREE_SQL_GLOBAL_FILTER_DEPT
, Chars.FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_CHILDREN, Chars.FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_SON);
}
return me;
}
}

View File

@ -69,4 +69,9 @@ public interface ICrudModule<in TCreateReq, TCreateRsp, in TEditReq, TQueryReq,
/// 查询实体
/// </summary>
Task<IEnumerable<TQueryRsp>> QueryAsync(QueryReq<TQueryReq> req);
/// <summary>
/// 实体求和
/// </summary>
Task<decimal> SumAsync(QueryReq<TQueryReq> req);
}

View File

@ -1,13 +0,0 @@
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Tpl.Example;
namespace NetAdmin.Application.Modules.Tpl;
/// <summary>
/// 示例模块
/// </summary>
public interface IExampleModule : ICrudModule<CreateExampleReq, QueryExampleRsp // 创建类型
, EditExampleReq // 编辑类型
, QueryExampleReq, QueryExampleRsp // 查询类型
, DelReq // 删除类型
>;

View File

@ -62,6 +62,23 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false);
}
/// <summary>
/// 唯一索引冲突处理
/// </summary>
protected static async Task OnUniqueIndexConflictAsync(Func<Task> actionTry, Func<Task> actionCatch = null)
{
try {
await actionTry().ConfigureAwait(false);
}
catch (Exception ex) when (ex.Message.Contains(Chars.FLG_DB_EXCEPTION_PRIMARY_KEY_CONFLICT) ||
ex.Message.Contains(Chars.FLG_DB_EXCEPTION_UNIQUE_CONSTRAINT_CONFLICT) ||
ex.Message.Contains(Chars.FLG_DB_EXCEPTION_IDX)) {
if (actionCatch != null) {
await actionCatch().ConfigureAwait(false);
}
}
}
/// <summary>
/// 更新实体
/// </summary>
@ -85,7 +102,8 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
whereExp ??= a => a.Id.Equals(newValue.Id);
var update = BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql);
if (disableGlobalDataFilter) {
update = update.DisableGlobalFilter(nameof(Chars.FLG_FREE_SQL_GLOBAL_FILTER_DATA));
update = update.DisableGlobalFilter(Chars.FLG_FREE_SQL_GLOBAL_FILTER_SELF, Chars.FLG_FREE_SQL_GLOBAL_FILTER_DEPT
, Chars.FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_CHILDREN, Chars.FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_SON);
}
return update.ExecuteEffectsAsync();
@ -106,8 +124,8 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
TEntity newValue //
, List<string> includeFields = null //
, List<string> excludeFields = null //
, Expression<Func<TEntity, bool>> whereExp = null //
, string whereSql = null //
, Expression<Func<TEntity, bool>> whereExp = null //
, string whereSql = null //
, bool ignoreVersion = false)
{
// 默认匹配主键

View File

@ -42,12 +42,7 @@ public abstract class ServiceBase : IScoped, IService
/// <summary>
/// 获取服务
/// </summary>
#pragma warning disable RCS1036
#pragma warning restore RCS1036
// ReSharper disable once MemberCanBeMadeStatic.Global
#pragma warning disable CA1822, S2325
protected T S<T>()
protected static T S<T>()
#pragma warning restore S2325, CA1822
where T : class
{

View File

@ -1,8 +0,0 @@
using NetAdmin.Application.Modules.Tpl;
namespace NetAdmin.Application.Services.Tpl.Dependency;
/// <summary>
/// 示例服务
/// </summary>
public interface IExampleService : IService, IExampleModule;

View File

@ -1,133 +0,0 @@
using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services.Tpl.Dependency;
using NetAdmin.Domain.DbMaps.Tpl;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Tpl.Example;
using NetAdmin.Domain.Extensions;
namespace NetAdmin.Application.Services.Tpl;
/// <inheritdoc cref="IExampleService" />
public sealed class ExampleService(BasicRepository<Tpl_Example, long> rpo) //
: RepositoryService<Tpl_Example, long, IExampleService>(rpo), IExampleService
{
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
req.ThrowIfInvalid();
var ret = 0;
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var item in req.Items) {
ret += await DeleteAsync(item).ConfigureAwait(false);
}
return ret;
}
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
return QueryInternal(req).WithNoLockNoWait().CountAsync();
}
/// <inheritdoc />
public async Task<IOrderedEnumerable<KeyValuePair<IImmutableDictionary<string, string>, int>>> CountByAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req with { Order = Orders.None })
.WithNoLockNoWait()
.GroupBy(req.GetToListExp<Tpl_Example>())
.ToDictionaryAsync(a => a.Count())
.ConfigureAwait(false);
return ret.Select(x => new KeyValuePair<IImmutableDictionary<string, string>, int>(
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);
}
/// <inheritdoc />
public async Task<QueryExampleRsp> CreateAsync(CreateExampleReq req)
{
req.ThrowIfInvalid();
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
return ret.Adapt<QueryExampleRsp>();
}
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
req.ThrowIfInvalid();
return Rpo.DeleteAsync(a => a.Id == req.Id);
}
/// <inheritdoc />
public async Task<QueryExampleRsp> EditAsync(EditExampleReq req)
{
req.ThrowIfInvalid();
#if DBTYPE_SQLSERVER
return (await UpdateReturnListAsync(req).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryExampleRsp>();
#else
return await UpdateAsync(req).ConfigureAwait(false) > 0 ? await GetAsync(new QueryExampleReq { Id = req.Id }).ConfigureAwait(false) : null;
#endif
}
/// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
return ExportAsync<QueryExampleReq, QueryExampleRsp>(QueryInternal, req, Ln.);
}
/// <inheritdoc />
public async Task<QueryExampleRsp> GetAsync(QueryExampleReq req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(new QueryReq<QueryExampleReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false);
return ret.Adapt<QueryExampleRsp>();
}
/// <inheritdoc />
public async Task<PagedQueryRsp<QueryExampleRsp>> PagedQueryAsync(PagedQueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
var list = await QueryInternal(req)
.Page(req.Page, req.PageSize)
.WithNoLockNoWait()
.Count(out var total)
.ToListAsync(req)
.ConfigureAwait(false);
return new PagedQueryRsp<QueryExampleRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryExampleRsp>>());
}
/// <inheritdoc />
public async Task<IEnumerable<QueryExampleRsp>> QueryAsync(QueryReq<QueryExampleReq> req)
{
req.ThrowIfInvalid();
var ret = await QueryInternal(req).WithNoLockNoWait().Take(req.Count).ToListAsync(req).ConfigureAwait(false);
return ret.Adapt<IEnumerable<QueryExampleRsp>>();
}
private ISelect<Tpl_Example> QueryInternal(QueryReq<QueryExampleReq> 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;
}
}

View File

@ -1,9 +0,0 @@
using NetAdmin.Application.Modules.Tpl;
using NetAdmin.Application.Services.Tpl.Dependency;
namespace NetAdmin.Cache.Tpl.Dependency;
/// <summary>
/// 示例缓存
/// </summary>
public interface IExampleCache : ICache<IDistributedCache, IExampleService>, IExampleModule;

View File

@ -1,71 +0,0 @@
using NetAdmin.Application.Services.Tpl.Dependency;
using NetAdmin.Cache.Tpl.Dependency;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Tpl.Example;
namespace NetAdmin.Cache.Tpl;
/// <inheritdoc cref="IExampleCache" />
public sealed class ExampleCache(IDistributedCache cache, IExampleService service)
: DistributedCache<IExampleService>(cache, service), IScoped, IExampleCache
{
/// <inheritdoc />
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
return Service.BulkDeleteAsync(req);
}
/// <inheritdoc />
public Task<long> CountAsync(QueryReq<QueryExampleReq> req)
{
return Service.CountAsync(req);
}
/// <inheritdoc />
public Task<IOrderedEnumerable<KeyValuePair<IImmutableDictionary<string, string>, int>>> CountByAsync(QueryReq<QueryExampleReq> req)
{
return Service.CountByAsync(req);
}
/// <inheritdoc />
public Task<QueryExampleRsp> CreateAsync(CreateExampleReq req)
{
return Service.CreateAsync(req);
}
/// <inheritdoc />
public Task<int> DeleteAsync(DelReq req)
{
return Service.DeleteAsync(req);
}
/// <inheritdoc />
public Task<QueryExampleRsp> EditAsync(EditExampleReq req)
{
return Service.EditAsync(req);
}
/// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryExampleReq> req)
{
return Service.ExportAsync(req);
}
/// <inheritdoc />
public Task<QueryExampleRsp> GetAsync(QueryExampleReq req)
{
return Service.GetAsync(req);
}
/// <inheritdoc />
public Task<PagedQueryRsp<QueryExampleRsp>> PagedQueryAsync(PagedQueryReq<QueryExampleReq> req)
{
return Service.PagedQueryAsync(req);
}
/// <inheritdoc />
public Task<IEnumerable<QueryExampleRsp>> QueryAsync(QueryReq<QueryExampleReq> req)
{
return Service.QueryAsync(req);
}
}

View File

@ -19,7 +19,7 @@ public sealed class UserNameAttribute : RegexAttribute
public override bool IsValid(object value)
{
if (!base.IsValid(value)) {
ErrorMessageResourceName = nameof(Ln.4);
ErrorMessageResourceName = nameof(Ln.);
return false;
}

View File

@ -3,14 +3,23 @@ namespace NetAdmin.Domain;
/// <summary>
/// 数据基类
/// </summary>
public abstract record DataAbstraction
public abstract record DataAbstraction : IValidatableObject
{
/// <summary>
/// 是否已验证
/// </summary>
protected bool HasValidated { get; set; }
/// <summary>
/// 如果数据校验失败,抛出异常
/// </summary>
/// <exception cref="NetAdminValidateException">NetAdminValidateException</exception>
public void ThrowIfInvalid()
{
if (HasValidated) {
return;
}
var validationResult = this.TryValidate();
if (!validationResult.IsValid) {
throw new NetAdminValidateException(validationResult.ValidationResults.ToDictionary( //
@ -45,4 +54,19 @@ public abstract record DataAbstraction
property.SetValue(this, s);
}
}
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
HasValidated = true;
return ValidateInternal(validationContext);
}
/// <summary>
/// 内部验证
/// </summary>
protected virtual IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
yield return ValidationResult.Success;
}
}

View File

@ -8,5 +8,5 @@ public interface IFieldSummary
/// <summary>
/// 备注
/// </summary>
string Summary { get; init; }
string Summary { get; set; }
}

View File

@ -79,5 +79,5 @@ public record Sys_Api : ImmutableEntity<string>, IFieldSummary
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
}

View File

@ -0,0 +1,89 @@
namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary>
/// 代码模板表
/// </summary>
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_CodeTemplate))]
public record Sys_CodeTemplate : VersionEntity, IFieldSort, IFieldSummary, IFieldEnabled, IFieldOwner
{
/// <summary>
/// 是否启用
/// </summary>
/// <example>true</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual bool Enabled { get; init; }
/// <summary>
/// 性别
/// </summary>
/// <example>Male</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual Genders? Gender { get; init; }
/// <summary>
/// 唯一编码
/// </summary>
/// <example>123456</example>
[Column(IsIdentity = false, IsPrimary = true, Position = 1)]
[CsvIgnore]
[JsonIgnore]
[Snowflake]
public override long Id { get; init; }
/// <summary>
/// 名称
/// </summary>
/// <example>老王</example>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
[CsvIgnore]
[JsonIgnore]
public virtual string Name { get; init; }
/// <summary>
/// 归属用户
/// </summary>
[CsvIgnore]
[JsonIgnore]
[Navigate(nameof(OwnerId))]
public Sys_User Owner { get; init; }
/// <summary>
/// 归属部门编号
/// </summary>
/// <example>370942943322181</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long? OwnerDeptId { get; init; }
/// <summary>
/// 归属用户编号
/// </summary>
/// <example>370942943322181</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long? OwnerId { get; init; }
/// <summary>
/// 排序值,越大越前
/// </summary>
/// <example>100</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long Sort { get; init; }
/// <summary>
/// 备注
/// </summary>
/// <example>备注文字</example>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; set; }
}

View File

@ -68,5 +68,5 @@ public record Sys_Dept : VersionEntity, IFieldEnabled, IFieldSummary, IFieldSort
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
}

View File

@ -45,7 +45,7 @@ public record Sys_DicContent : VersionEntity, IFieldEnabled, IFieldSummary
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
/// <summary>
/// 键值

View File

@ -134,7 +134,7 @@ public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
/// <summary>
/// 执行用户

View File

@ -104,7 +104,7 @@ public record Sys_Role : VersionEntity, IFieldSort, IFieldEnabled, IFieldSummary
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
/// <summary>
/// 此角色下的用户集合

View File

@ -62,7 +62,7 @@ public record Sys_SiteMsg : VersionEntity, IRegister, IFieldSummary
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
/// <summary>
/// 消息主题

View File

@ -121,7 +121,7 @@ public record Sys_User : VersionEntity, IFieldSummary, IFieldEnabled, IRegister
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
/// <summary>
/// 授权验证Token全局唯一可以随时重置强制下线

View File

@ -46,6 +46,14 @@ public record Sys_UserInvite : VersionEntity, IFieldOwner
[JsonIgnore]
public virtual long? OwnerId { get; init; }
/// <summary>
/// 允许自助充值
/// </summary>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual bool SelfRechargeAllowed { get; init; }
/// <summary>
/// 用户
/// </summary>

View File

@ -46,14 +46,6 @@ public record Sys_UserWallet : LiteVersionEntity, IFieldOwner
[JsonIgnore]
public virtual long? OwnerId { get; init; }
/// <summary>
/// 总余额
/// </summary>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long TotalBalance { get; init; }
/// <summary>
/// 总支出
/// </summary>

View File

@ -0,0 +1,99 @@
using NetAdmin.Domain.Enums.Sys;
namespace NetAdmin.Domain.DbMaps.Sys;
/// <summary>
/// 钱包冻结表
/// </summary>
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_WalletFrozen))]
public record Sys_WalletFrozen : LiteVersionEntity, IFieldOwner, IFieldSummary
{
/// <summary>
/// 冻结金额
/// </summary>
/// <example>100</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long Amount { get; init; }
/// <summary>
/// 冻结前数值
/// </summary>
/// <example>100</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long FrozenBalanceBefore { get; init; }
/// <summary>
/// 冻结编号
/// </summary>
/// <example>123456</example>
[Column(IsIdentity = false, IsPrimary = true, Position = 1)]
[CsvIgnore]
[JsonIgnore]
[Snowflake]
public override long Id { get; init; }
/// <summary>
/// 归属用户
/// </summary>
[CsvIgnore]
[JsonIgnore]
[Navigate(nameof(OwnerId))]
public Sys_User Owner { get; init; }
/// <summary>
/// 归属部门编号
/// </summary>
/// <example>370942943322181</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long? OwnerDeptId { get; init; }
/// <summary>
/// 归属用户编号
/// </summary>
/// <example>370942943322181</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long? OwnerId { get; init; }
/// <summary>
/// 冻结原因
/// </summary>
/// <example>Trade</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual WalletFrozenReasons Reason { get; init; }
/// <summary>
/// 冻结状态
/// </summary>
/// <example>Frozen</example>
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual WalletFrozenStatues Status { get; init; }
/// <summary>
/// 备注
/// </summary>
/// <example>备注文字</example>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; set; }
/// <summary>
/// 钱包
/// </summary>
[CsvIgnore]
[JsonIgnore]
[Navigate(nameof(OwnerId))]
public Sys_UserWallet Wallet { get; init; }
}

View File

@ -12,7 +12,7 @@ public record Sys_WalletTrade : ImmutableEntity, IFieldOwner, IFieldSummary
[Column]
[CsvIgnore]
[JsonIgnore]
public virtual long Amount { get; init; }
public virtual long Amount { get; set; }
/// <summary>
/// 交易前余额
@ -60,7 +60,7 @@ public record Sys_WalletTrade : ImmutableEntity, IFieldOwner, IFieldSummary
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore]
[JsonIgnore]
public virtual string Summary { get; init; }
public virtual string Summary { get; set; }
/// <summary>
/// 交易方向

View File

@ -1,7 +0,0 @@
namespace NetAdmin.Domain.DbMaps.Tpl;
/// <summary>
/// 示例表
/// </summary>
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Tpl_Example))]
public record Tpl_Example : VersionEntity;

View File

@ -0,0 +1,22 @@
namespace NetAdmin.Domain.Dto.Dependency;
/// <summary>
/// 工作批请求
/// </summary>
public record JobReq : DataAbstraction
{
/// <summary>
/// 处理数量
/// </summary>
public int? Count { get; init; }
/// <summary>
/// n秒以前
/// </summary>
public int? SecondsAgo { get; init; }
/// <summary>
/// 直到n秒前
/// </summary>
public int? UntilSecondsAgo { get; init; }
}

View File

@ -22,6 +22,12 @@ public record QueryReq<T> : DataAbstraction
/// </summary>
public T Filter { get; init; }
/// <summary>
/// 忽略归属
/// </summary>
[JsonIgnore]
public bool IgnoreOwner { get; init; }
/// <summary>
/// 查询关键字
/// </summary>
@ -42,6 +48,23 @@ public record QueryReq<T> : DataAbstraction
/// </summary>
public string[] RequiredFields { get; init; }
/// <summary>
/// 求和表达式
/// </summary>
public Expression<Func<TEntity, long>> GetSumExp<TEntity>()
{
if (RequiredFields.NullOrEmpty()) {
return null;
}
var field = RequiredFields[0];
var leftParameter = Expression.Parameter(typeof(TEntity), "a");
var prop = typeof(TEntity).GetRecursiveProperty(field);
return prop == null || prop.GetCustomAttribute<DangerFieldAttribute>() != null
? null
: Expression.Lambda<Func<TEntity, long>>(CreatePropertyExpression(leftParameter, field), leftParameter);
}
/// <summary>
/// 列表表达式
/// </summary>
@ -52,21 +75,30 @@ public record QueryReq<T> : DataAbstraction
}
var expParameter = Expression.Parameter(typeof(TEntity), "a");
var bindings = new List<MemberBinding>();
var bindings = new List<(PropertyInfo, MemberInitExpression)>();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var field in RequiredFields) {
var prop = typeof(TEntity).GetProperty(field);
var prop = typeof(TEntity).GetRecursiveProperty(field);
if (prop == null || prop.GetCustomAttribute<DangerFieldAttribute>() != null) {
continue;
}
var propExp = Expression.Property(expParameter, prop);
var binding = Expression.Bind(prop, propExp);
bindings.Add(binding);
var parentPath = field[..field.LastIndexOf('.').Is(-1, field.Length)];
var parentProperty = typeof(TEntity).GetRecursiveProperty(parentPath);
var propExp = Expression.Property(Expression.Parameter(prop.DeclaringType!, parentPath), prop);
bindings.Add((parentProperty, Expression.MemberInit(Expression.New(prop.DeclaringType), Expression.Bind(prop, propExp))));
}
var expBody = Expression.MemberInit(Expression.New(typeof(TEntity)), bindings);
var expBody = Expression.MemberInit( //
Expression.New(typeof(TEntity))
, bindings.SelectMany(x => x.Item1.PropertyType == x.Item2.Type ? [Expression.Bind(x.Item1, x.Item2)] : x.Item2.Bindings.ToArray()));
return Expression.Lambda<Func<TEntity, TEntity>>(expBody, expParameter);
}
private static Expression CreatePropertyExpression(ParameterExpression param, string propertyPath)
{
return propertyPath.Split('.').Aggregate<string, Expression>(param, Expression.PropertyOrField);
}
}

View File

@ -31,5 +31,5 @@ public sealed record ExportApiRsp : QueryApiRsp
[CsvIndex(3)]
[CsvIgnore(false)]
[CsvName(nameof(Ln.接口描述))]
public override string Summary { get; init; }
public override string Summary { get; set; }
}

View File

@ -33,5 +33,5 @@ public record QueryApiRsp : Sys_Api
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
}

View File

@ -0,0 +1,30 @@
namespace NetAdmin.Domain.Dto.Sys.CodeTemplate;
/// <summary>
/// 请求:创建代码模板
/// </summary>
public record CreateCodeTemplateReq : Sys_CodeTemplate
{
/// <inheritdoc cref="IFieldEnabled.Enabled" />
public override bool Enabled { get; init; } = true;
/// <inheritdoc cref="Sys_CodeTemplate.Gender" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override Genders? Gender { get; init; }
/// <inheritdoc cref="Sys_CodeTemplate.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc cref="Sys_CodeTemplate.Name" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Name { get; init; }
/// <inheritdoc cref="IFieldSort.Sort" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Sort { get; init; }
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; set; }
}

View File

@ -0,0 +1,11 @@
namespace NetAdmin.Domain.Dto.Sys.CodeTemplate;
/// <summary>
/// 请求:编辑代码模板
/// </summary>
public sealed record EditCodeTemplateReq : CreateCodeTemplateReq
{
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -0,0 +1,11 @@
namespace NetAdmin.Domain.Dto.Sys.CodeTemplate;
/// <summary>
/// 请求:查询代码模板
/// </summary>
public sealed record QueryCodeTemplateReq : Sys_CodeTemplate
{
/// <inheritdoc cref="Sys_CodeTemplate.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
}

View File

@ -0,0 +1,72 @@
using NetAdmin.Domain.Dto.Sys.User;
namespace NetAdmin.Domain.Dto.Sys.CodeTemplate;
/// <summary>
/// 响应:查询代码模板
/// </summary>
public record QueryCodeTemplateRsp : Sys_CodeTemplate
{
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? CreatedUserId { get; init; }
/// <inheritdoc cref="IFieldCreatedUser.CreatedUserName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string CreatedUserName { get; init; }
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; }
/// <inheritdoc cref="Sys_CodeTemplate.Gender" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override Genders? Gender { get; init; }
/// <inheritdoc cref="Sys_CodeTemplate.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc cref="IFieldModifiedTime.ModifiedTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override DateTime? ModifiedTime { get; init; }
/// <inheritdoc cref="IFieldModifiedUser.ModifiedUserId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? ModifiedUserId { get; init; }
/// <inheritdoc cref="IFieldModifiedUser.ModifiedUserName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string ModifiedUserName { get; init; }
/// <inheritdoc cref="Sys_CodeTemplate.Name" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Name { get; init; }
/// <inheritdoc cref="Sys_CodeTemplate.Owner" />
public new virtual QueryUserRsp Owner { get; init; }
/// <inheritdoc cref="IFieldOwner.OwnerDeptId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerDeptId { get; init; }
/// <inheritdoc cref="IFieldOwner.OwnerId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="IFieldSort.Sort" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Sort { get; init; }
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; set; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -3,7 +3,7 @@ namespace NetAdmin.Domain.Dto.Sys.DepositOrder;
/// <summary>
/// 请求:创建充值订单
/// </summary>
public record CreateDepositOrderReq : Sys_DepositOrder, IValidatableObject
public record CreateDepositOrderReq : Sys_DepositOrder
{
/// <inheritdoc cref="Sys_DepositOrder.ActualPayAmount" />
public override long ActualPayAmount { get; init; }
@ -13,7 +13,7 @@ public record CreateDepositOrderReq : Sys_DepositOrder, IValidatableObject
/// <inheritdoc cref="Sys_DepositOrder.DepositPoint" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[Range(100, long.MaxValue)]
[Range(100, int.MaxValue)]
public override long DepositPoint { get; init; }
/// <inheritdoc cref="Sys_DepositOrder.PaymentMode" />
@ -25,7 +25,7 @@ public record CreateDepositOrderReq : Sys_DepositOrder, IValidatableObject
public override int ToPointRate { get; init; }
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
protected override IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
if (PaymentMode != PaymentModes.USDT) {
yield return new ValidationResult(Ln., [nameof(PaymentMode)]);

View File

@ -1,12 +0,0 @@
namespace NetAdmin.Domain.Dto.Sys.DepositOrder;
/// <summary>
/// 请求:到账确认
/// </summary>
public record ReceivedConfirmationReq : DataAbstraction
{
/// <summary>
/// 读取前n条记录
/// </summary>
public int ReadRecordCount { get; init; }
}

View File

@ -5,9 +5,8 @@ namespace NetAdmin.Domain.Dto.Sys.Dept;
/// </summary>
public record CreateDeptReq : Sys_Dept
{
/// <inheritdoc cref="IFieldEnabled.Enabled" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool Enabled { get; init; }
/// <inheritdoc />
public override bool Enabled { get; init; } = true;
/// <inheritdoc cref="Sys_Dept.Name" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
@ -24,5 +23,5 @@ public record CreateDeptReq : Sys_Dept
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
}

View File

@ -43,5 +43,5 @@ public sealed record ExportDeptRsp : QueryDeptRsp
[CsvIndex(3)]
[CsvIgnore(false)]
[CsvName(nameof(Ln.备注))]
public override string Summary { get; init; }
public override string Summary { get; set; }
}

View File

@ -34,7 +34,7 @@ public record QueryDeptRsp : Sys_Dept
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]

View File

@ -0,0 +1,47 @@
namespace NetAdmin.Domain.Dto.Sys.Dev;
/// <summary>
/// 信息:字段项信息
/// </summary>
public sealed record FieldItemInfo : DataAbstraction
{
/// <summary>
/// 数据库字段类型
/// </summary>
public string DbType { get; init; }
/// <summary>
/// 代码模板
/// </summary>
public string Example { get; init; }
/// <summary>
/// 可空
/// </summary>
public bool IsNullable { get; init; }
/// <summary>
/// 是否主键
/// </summary>
public bool IsPrimary { get; set; }
/// <summary>
/// 值类型
/// </summary>
public bool IsStruct { get; init; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; init; }
/// <summary>
/// 备注
/// </summary>
public string Summary { get; set; }
/// <summary>
/// 类型
/// </summary>
public string Type { get; init; }
}

View File

@ -6,20 +6,32 @@ namespace NetAdmin.Domain.Dto.Sys.Dev;
public sealed record GenerateCsCodeReq : DataAbstraction
{
/// <summary>
/// 模块名称
/// 基类
/// </summary>
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.模块名称不能为空))]
public string ModuleName { get; init; }
public string BaseClass { get; init; }
/// <summary>
/// 模块说明
/// 实体名称
/// </summary>
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.模块说明不能为空))]
public string ModuleRemark { get; init; }
public string EntityName { get; init; }
/// <summary>
/// 模块类型
/// 字段列表
/// </summary>
[Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.模块类型不能为空))]
public string Type { get; init; }
public IReadOnlyCollection<FieldItemInfo> FieldList { get; init; }
/// <summary>
/// 接口列表
/// </summary>
public string[] Interfaces { get; init; }
/// <summary>
/// 项目
/// </summary>
public string Project { get; init; }
/// <summary>
/// 描述
/// </summary>
public string Summary { get; set; }
}

View File

@ -0,0 +1,13 @@
namespace NetAdmin.Domain.Dto.Sys.Dev;
/// <summary>
/// 请求:获取所有数据类型
/// </summary>
public sealed record GetDotnetDataTypesReq : DataAbstraction
{
/// <summary>
/// 开始匹配
/// </summary>
[Required]
public string StartWith { get; init; }
}

View File

@ -21,7 +21,7 @@ public record CreateDicContentReq : Sys_DicContent
/// <inheritdoc cref="Sys_DicContent.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_DicContent.Value" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View File

@ -27,7 +27,7 @@ public sealed record ExportDicContentRsp : QueryDicContentRsp
[CsvIndex(4)]
[CsvIgnore(false)]
[CsvName(nameof(Ln.备注))]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc />
[CsvIndex(1)]

View File

@ -23,7 +23,7 @@ public record QueryDicContentRsp : Sys_DicContent
/// <inheritdoc cref="Sys_DicContent.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_DicContent.Value" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View File

@ -58,7 +58,7 @@ public record CreateJobReq : Sys_Job
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_Job.UserId" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]

View File

@ -112,7 +112,7 @@ public record QueryJobRsp : Sys_Job
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_Job.User" />
public new virtual QueryUserRsp User { get; init; }

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Domain.Dto.Sys.Role;
/// <summary>
/// 请求:创建角色
/// </summary>
public record CreateRoleReq : Sys_Role, IValidatableObject
public record CreateRoleReq : Sys_Role
{
/// <summary>
/// 角色-接口映射
@ -55,10 +55,10 @@ public record CreateRoleReq : Sys_Role, IValidatableObject
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
protected override IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
if (validationContext.MemberName != null) {
DashboardLayout = JsonSerializer.Serialize(JsonDocument.Parse(DashboardLayout));

View File

@ -63,7 +63,7 @@ public record QueryRoleRsp : Sys_Role
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]

View File

@ -46,7 +46,7 @@ public sealed record ExportSiteMsgRsp : QuerySiteMsgRsp
[CsvIndex(4)]
[CsvIgnore(false)]
[CsvName(nameof(Ln.消息摘要))]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc />
[CsvIndex(3)]

View File

@ -53,7 +53,7 @@ public record QuerySiteMsgRsp : Sys_SiteMsg
/// <inheritdoc cref="Sys_SiteMsg.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_SiteMsg.Title" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View File

@ -44,7 +44,7 @@ public abstract record CreateEditUserReq : Sys_User
/// <inheritdoc cref="Sys_User.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_User.UserName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.Dto.Sys.User;
/// <summary>
/// 请求:创建用户
/// </summary>
public sealed record CreateUserReq : CreateEditUserReq
public record CreateUserReq : CreateEditUserReq
{
/// <inheritdoc />
public override bool Enabled { get; init; } = true;

View File

@ -1,5 +1,6 @@
using NetAdmin.Domain.Dto.Sys.Dept;
using NetAdmin.Domain.Dto.Sys.Role;
using NetAdmin.Domain.Dto.Sys.UserInvite;
namespace NetAdmin.Domain.Dto.Sys.User;
@ -27,6 +28,11 @@ public record QueryUserRsp : Sys_User
/// <inheritdoc cref="Sys_User.Dept" />
public new virtual QueryDeptRsp Dept { get; init; }
/// <summary>
/// 本部门以及子部门编号
/// </summary>
public IReadOnlyCollection<long?> DeptIds { get; init; }
/// <inheritdoc cref="Sys_User.Email" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Email { get; init; }
@ -39,6 +45,9 @@ public record QueryUserRsp : Sys_User
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc cref="Sys_User.Invite" />
public new virtual QueryUserInviteRsp Invite { get; init; }
/// <inheritdoc cref="Sys_User.InviteCode" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string InviteCode { get; init; }
@ -56,7 +65,7 @@ public record QueryUserRsp : Sys_User
/// <inheritdoc cref="Sys_User.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_User.UserName" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

View File

@ -0,0 +1,8 @@
using NetAdmin.Domain.Dto.Sys.User;
namespace NetAdmin.Domain.Dto.Sys.UserInvite;
/// <summary>
/// 请求:创建粉丝账号
/// </summary>
public record CreateFansAccountReq : CreateUserReq;

View File

@ -8,4 +8,7 @@ public record CreateUserInviteReq : Sys_UserInvite
/// <inheritdoc cref="Sys_UserInvite.CommissionRatio" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override int CommissionRatio { get; init; }
/// <inheritdoc />
public override bool SelfRechargeAllowed { get; init; } = true;
}

View File

@ -8,4 +8,9 @@ public sealed record QueryUserInviteReq : Sys_UserInvite
/// <inheritdoc cref="EntityBase{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <summary>
/// 是否平面查询
/// </summary>
public bool IsPlainQuery { get; init; }
}

View File

@ -54,6 +54,10 @@ public record QueryUserInviteRsp : Sys_UserInvite
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="Sys_UserInvite.SelfRechargeAllowed" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool SelfRechargeAllowed { get; init; }
/// <inheritdoc cref="Sys_UserInvite.User" />
[CsvIgnore]
public new virtual QueryUserRsp User { get; init; }

View File

@ -0,0 +1,15 @@
namespace NetAdmin.Domain.Dto.Sys.UserInvite;
/// <summary>
/// 请求:修改粉丝角色
/// </summary>
public record SetFansRoleReq : Sys_UserInvite
{
/// <inheritdoc />
public override long Id { get; init; }
/// <summary>
/// 角色编号
/// </summary>
public long RoleId { get; init; }
}

View File

@ -0,0 +1,30 @@
namespace NetAdmin.Domain.Dto.Sys.UserInvite;
/// <summary>
/// 请求:设置上级
/// </summary>
public record SetInviterReq : Sys_UserInvite
{
/// <inheritdoc cref="EntityBase{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc />
[Required]
[Range(1, long.MaxValue)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
/// <inheritdoc />
protected override IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
if (OwnerId == Id) {
yield return new ValidationResult(Ln., [nameof(OwnerId)]);
}
yield return ValidationResult.Success;
}
}

View File

@ -1,16 +1,18 @@
using NetAdmin.Domain.DbMaps.Tpl;
namespace NetAdmin.Domain.Dto.Tpl.Example;
namespace NetAdmin.Domain.Dto.Sys.UserInvite;
/// <summary>
/// 响应:查询示例
/// 请求:设置允许自助充值
/// </summary>
public sealed record QueryExampleRsp : Tpl_Example
public record SetSelfRechargeAllowedReq : Sys_UserInvite
{
/// <inheritdoc cref="EntityBase{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc cref="Sys_UserInvite.SelfRechargeAllowed" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override bool SelfRechargeAllowed { get; init; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }

View File

@ -38,10 +38,6 @@ public record QueryUserWalletRsp : Sys_UserWallet
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="Sys_UserWallet.TotalBalance" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long TotalBalance { get; init; }
/// <inheritdoc cref="Sys_UserWallet.TotalExpenditure" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long TotalExpenditure { get; init; }

View File

@ -6,7 +6,7 @@ namespace NetAdmin.Domain.Dto.Sys.VerifyCode;
/// <summary>
/// 请求:发送验证码
/// </summary>
public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
public sealed record SendVerifyCodeReq : Sys_VerifyCode
{
/// <inheritdoc cref="Sys_VerifyCode.DestDevice" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
@ -35,7 +35,7 @@ public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject
public VerifyCaptchaReq VerifyCaptchaReq { get; init; }
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
protected override IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
ValidationResult validationResult;
switch (DeviceType) {

View File

@ -0,0 +1,33 @@
using NetAdmin.Domain.Enums.Sys;
namespace NetAdmin.Domain.Dto.Sys.WalletFrozen;
/// <summary>
/// 请求:创建钱包冻结
/// </summary>
public record CreateWalletFrozenReq : Sys_WalletFrozen
{
/// <inheritdoc cref="Sys_WalletFrozen.Amount" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Amount { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.OwnerId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.Reason" />
[EnumDataType(typeof(WalletFrozenReasons))]
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override WalletFrozenReasons Reason { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.Status" />
public override WalletFrozenStatues Status { get; init; } = WalletFrozenStatues.Frozen;
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; set; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -1,11 +1,11 @@
namespace NetAdmin.Domain.Dto.Tpl.Example;
namespace NetAdmin.Domain.Dto.Sys.WalletFrozen;
/// <summary>
/// 请求:编辑示例
/// 请求:编辑钱包冻结
/// </summary>
public record EditExampleReq : CreateExampleReq
public sealed record EditWalletFrozenReq : CreateWalletFrozenReq
{
/// <inheritdoc cref="EntityBase{T}.Id" />
/// <inheritdoc cref="Sys_WalletFrozen.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }

View File

@ -1,11 +1,9 @@
using NetAdmin.Domain.DbMaps.Tpl;
namespace NetAdmin.Domain.Dto.Tpl.Example;
namespace NetAdmin.Domain.Dto.Sys.WalletFrozen;
/// <summary>
/// 请求:查询示例
/// 请求:查询钱包冻结
/// </summary>
public sealed record QueryExampleReq : Tpl_Example
public sealed record QueryWalletFrozenReq : Sys_WalletFrozen
{
/// <inheritdoc cref="EntityBase{T}.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]

View File

@ -0,0 +1,57 @@
using NetAdmin.Domain.Dto.Sys.User;
using NetAdmin.Domain.Enums.Sys;
namespace NetAdmin.Domain.Dto.Sys.WalletFrozen;
/// <summary>
/// 响应:查询钱包冻结
/// </summary>
public record QueryWalletFrozenRsp : Sys_WalletFrozen
{
/// <inheritdoc cref="Sys_WalletFrozen.Amount" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Amount { get; init; }
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override DateTime CreatedTime { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.FrozenBalanceBefore" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long FrozenBalanceBefore { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
/// <inheritdoc cref="IFieldModifiedTime.ModifiedTime" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override DateTime? ModifiedTime { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.Owner" />
public new virtual QueryUserRsp Owner { get; init; }
/// <inheritdoc cref="IFieldOwner.OwnerDeptId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerDeptId { get; init; }
/// <inheritdoc cref="IFieldOwner.OwnerId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.Reason" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override WalletFrozenReasons Reason { get; init; }
/// <inheritdoc cref="Sys_WalletFrozen.Status" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override WalletFrozenStatues Status { get; init; }
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; set; }
/// <inheritdoc cref="IFieldVersion.Version" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Version { get; init; }
}

View File

@ -0,0 +1,11 @@
namespace NetAdmin.Domain.Dto.Sys.WalletFrozen;
/// <summary>
/// 请求:将状态设置为解冻
/// </summary>
public record SetStatusToThawedReq : Sys_WalletFrozen
{
/// <inheritdoc cref="Sys_WalletFrozen.Id" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Id { get; init; }
}

View File

@ -3,13 +3,11 @@ namespace NetAdmin.Domain.Dto.Sys.WalletTrade;
/// <summary>
/// 请求:创建钱包交易
/// </summary>
public record CreateWalletTradeReq : Sys_WalletTrade, IValidatableObject
public record CreateWalletTradeReq : Sys_WalletTrade
{
private readonly TradeTypes _tradeType;
/// <inheritdoc cref="Sys_WalletTrade.Amount" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Amount { get; init; }
public override long Amount { get; set; }
/// <inheritdoc cref="Sys_WalletTrade.BusinessOrderNumber" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
@ -24,7 +22,7 @@ public record CreateWalletTradeReq : Sys_WalletTrade, IValidatableObject
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_WalletTrade.TradeDirection" />
public override TradeDirections TradeDirection { get; init; }
@ -33,20 +31,23 @@ public record CreateWalletTradeReq : Sys_WalletTrade, IValidatableObject
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[EnumDataType(typeof(TradeTypes))]
public override TradeTypes TradeType {
get => _tradeType;
get;
init {
_tradeType = value;
field = value;
TradeDirection = value.Attr<TradeAttribute>().Direction;
}
}
/// <inheritdoc />
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
protected override IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
var tradeDirection = TradeType.Attr<TradeAttribute>().Direction;
if (Amount == 0 || (tradeDirection == TradeDirections.Income && Amount < 0) || (tradeDirection == TradeDirections.Expense && Amount > 0)) {
if (Amount == 0) {
yield return new ValidationResult(Ln., [nameof(Amount)]);
}
else if ((tradeDirection == TradeDirections.Income && Amount < 0) || (tradeDirection == TradeDirections.Expense && Amount > 0)) {
Amount = -Amount;
}
yield return ValidationResult.Success;
}

View File

@ -9,7 +9,7 @@ public record QueryWalletTradeRsp : Sys_WalletTrade
{
/// <inheritdoc cref="Sys_WalletTrade.Amount" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Amount { get; init; }
public override long Amount { get; set; }
/// <inheritdoc cref="Sys_WalletTrade.BalanceBefore" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
@ -49,7 +49,7 @@ public record QueryWalletTradeRsp : Sys_WalletTrade
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; init; }
public override string Summary { get; set; }
/// <inheritdoc cref="Sys_WalletTrade.TradeDirection" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]

View File

@ -0,0 +1,28 @@
namespace NetAdmin.Domain.Dto.Sys.WalletTrade;
/// <summary>
/// 请求:转账
/// </summary>
public record TransferReq : Sys_WalletTrade
{
/// <inheritdoc cref="Sys_WalletTrade.Amount" />
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public override long Amount { get; set; }
/// <inheritdoc cref="IFieldOwner.OwnerId" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Required]
[UserId]
[Range(1, long.MaxValue)]
public override long? OwnerId { get; init; }
/// <inheritdoc cref="IFieldSummary.Summary" />
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public override string Summary { get; set; }
/// <inheritdoc />
protected override IEnumerable<ValidationResult> ValidateInternal(ValidationContext validationContext)
{
yield return Amount <= 0 ? new ValidationResult(Ln., [nameof(Amount)]) : ValidationResult.Success;
}
}

View File

@ -1,8 +0,0 @@
using NetAdmin.Domain.DbMaps.Tpl;
namespace NetAdmin.Domain.Dto.Tpl.Example;
/// <summary>
/// 请求:创建示例
/// </summary>
public record CreateExampleReq : Tpl_Example;

View File

@ -15,10 +15,10 @@ public enum DataScopes
,
/// <summary>
/// 本部门和下级部门数据
/// 本部门和所有子部门数据
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.本部门和下级部门数据))]
DeptWithChild = 2
[ResourceDescription<Ln>(nameof(Ln.本部门和所有子部门数据))]
DeptWithChildren = 2
,
@ -43,4 +43,12 @@ public enum DataScopes
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.指定部门数据))]
SpecificDept = 5
,
/// <summary>
/// 本部门和下一级部门数据
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.本部门和下一级部门数据))]
DeptWithSon = 6
}

View File

@ -0,0 +1,22 @@
namespace NetAdmin.Domain.Enums.Sys;
/// <summary>
/// 钱包冻结原因
/// </summary>
[Export]
public enum WalletFrozenReasons
{
/// <summary>
/// 交易
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.交易))]
Trade = 1
,
/// <summary>
/// 人工
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.人工))]
Manual = 2
}

View File

@ -0,0 +1,22 @@
namespace NetAdmin.Domain.Enums.Sys;
/// <summary>
/// 钱包冻结状态
/// </summary>
[Export]
public enum WalletFrozenStatues
{
/// <summary>
/// 已冻结
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.已冻结))]
Frozen = 1
,
/// <summary>
/// 已解冻
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.已解冻))]
Thawed = 2
}

View File

@ -0,0 +1,13 @@
using NetAdmin.Domain.Dto.Sys.User;
namespace NetAdmin.Domain.Events.Sys;
/// <summary>
/// 用户注册事件
/// </summary>
public sealed record UserRegisteredEvent : EventData<UserInfoRsp>
{
/// <inheritdoc />
public UserRegisteredEvent(UserInfoRsp payLoad) //
: base(payLoad) { }
}

View File

@ -4,7 +4,7 @@
<ProjectReference Include="../NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CronExpressionDescriptor" Version="2.41.0"/>
<PackageReference Include="CronExpressionDescriptor" Version="2.44.0"/>
<PackageReference Include="Cronos" Version="0.11.0"/>
<PackageReference Include="NetAdmin.CsvHelper" Version="1.0.0"/>
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14"/>

View File

@ -1,102 +0,0 @@
using NetAdmin.Application.Modules.Tpl;
using NetAdmin.Application.Services.Tpl.Dependency;
using NetAdmin.Cache.Tpl.Dependency;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Tpl.Example;
using NetAdmin.Host.Attributes;
namespace NetAdmin.Host.Controllers.Tpl;
/// <summary>
/// 示例服务
/// </summary>
[ApiDescriptionSettings(nameof(Tpl), Module = nameof(Tpl))]
[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)]
public sealed class ExampleController(IExampleCache cache) : ControllerBase<IExampleCache, IExampleService>(cache), IExampleModule
{
/// <summary>
/// 批量删除示例
/// </summary>
[Transaction]
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
{
return Cache.BulkDeleteAsync(req);
}
/// <summary>
/// 示例计数
/// </summary>
public Task<long> CountAsync(QueryReq<QueryExampleReq> req)
{
return Cache.CountAsync(req);
}
/// <summary>
/// 示例分组计数
/// </summary>
public Task<IOrderedEnumerable<KeyValuePair<IImmutableDictionary<string, string>, int>>> CountByAsync(QueryReq<QueryExampleReq> req)
{
return Cache.CountByAsync(req);
}
/// <summary>
/// 创建示例
/// </summary>
[Transaction]
public Task<QueryExampleRsp> CreateAsync(CreateExampleReq req)
{
return Cache.CreateAsync(req);
}
/// <summary>
/// 删除示例
/// </summary>
[Transaction]
public Task<int> DeleteAsync(DelReq req)
{
return Cache.DeleteAsync(req);
}
/// <summary>
/// 编辑示例
/// </summary>
[Transaction]
public Task<QueryExampleRsp> EditAsync(EditExampleReq req)
{
return Cache.EditAsync(req);
}
/// <summary>
/// 导出示例
/// </summary>
[NonAction]
public Task<IActionResult> ExportAsync(QueryReq<QueryExampleReq> req)
{
return Cache.ExportAsync(req);
}
/// <summary>
/// 获取单个示例
/// </summary>
public Task<QueryExampleRsp> GetAsync(QueryExampleReq req)
{
return Cache.GetAsync(req);
}
/// <summary>
/// 分页查询示例
/// </summary>
public Task<PagedQueryRsp<QueryExampleRsp>> PagedQueryAsync(PagedQueryReq<QueryExampleReq> req)
{
return Cache.PagedQueryAsync(req);
}
/// <summary>
/// 查询示例
/// </summary>
[NonAction]
public Task<IEnumerable<QueryExampleRsp>> QueryAsync(QueryReq<QueryExampleReq> req)
{
return Cache.QueryAsync(req);
}
}

View File

@ -45,8 +45,7 @@ public abstract class ApiResultHandler<T>
/// <summary>
/// HTTP状态码处理
/// </summary>
#pragma warning disable ASA001, VSTHRD200
public Task OnResponseStatusCodes( //
public Task OnResponseStatusCodesAsync( //
HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings = null)
{
// 设置响应状态码
@ -54,8 +53,6 @@ public abstract class ApiResultHandler<T>
return Task.CompletedTask;
}
#pragma warning restore ASA001, VSTHRD200
/// <summary>
/// 请求成功
/// </summary>

View File

@ -5,7 +5,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NetAdmin.ApiSkin" Condition="'$(Configuration)' == 'Debug'" Version="1.0.1"/>
<PackageReference Include="NetAdmin.Spectre.Console.Cli" Version="1.0.1"/>
<PackageReference Include="NetAdmin.Spectre.Console.Cli" Version="1.0.3"/>
<PackageReference Include="prometheus-net.AspNetCore" Condition="'$(Configuration)' != 'Debug'" Version="8.2.1"/>
</ItemGroup>
</Project>

View File

@ -46,8 +46,11 @@ public static class Chars
public const string FLG_DB_FIELD_TYPE_VARCHAR_7 = "varchar(7)";
public const string FLG_DB_INDEX_PREFIX = "idx_{tablename}_";
public const string FLG_DB_TABLE_NAME_PREFIX = "";
public const string FLG_FREE_SQL_GLOBAL_FILTER_DATA = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DATA);
public const string FLG_DIC_CATALOG_NEW_USER_ROLE_CONFIG = "new-user-role-config";
public const string FLG_FREE_SQL_GLOBAL_FILTER_DELETE = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DELETE);
public const string FLG_FREE_SQL_GLOBAL_FILTER_DEPT = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DEPT);
public const string FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_CHILDREN = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_CHILDREN);
public const string FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_SON = nameof(FLG_FREE_SQL_GLOBAL_FILTER_DEPT_WITH_SON);
public const string FLG_FREE_SQL_GLOBAL_FILTER_MEMBER = nameof(FLG_FREE_SQL_GLOBAL_FILTER_MEMBER);
public const string FLG_FREE_SQL_GLOBAL_FILTER_SELF = nameof(FLG_FREE_SQL_GLOBAL_FILTER_SELF);
public const string FLG_FREE_SQL_GLOBAL_FILTER_TENANT = nameof(FLG_FREE_SQL_GLOBAL_FILTER_TENANT);
@ -108,7 +111,7 @@ public static class Chars
public const string RGX_TELEPHONE = """^((\d{3,4}\-)|)\d{7,8}(|([-\u8f6c]{1}\d{1,5}))$""";
public const string RGX_UP_AND_LOWER_NUMBER = """^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$""";
public const string RGX_URL = """^(https?|ftp):\/\/[^\s/$.?#].[^\s]*\.[^\s]{2,}$""";
public const string RGX_USERNAME = "^[a-zA-Z0-9_]{4,16}$";
public const string RGX_USERNAME = """^[\u4e00-\u9fa5a-zA-Z0-9_-]{2,16}$""";
public const string RGX_VERIFY_CODE = """^\d{4}$""";
public const string RGXL_CHINESE_NAME

View File

@ -0,0 +1,24 @@
namespace NetAdmin.Infrastructure.Enums;
/// <summary>
/// 管理员交易类型
/// </summary>
[Export]
public enum AdminTradeTypes
{
/// <summary>
/// 管理员赠送
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.管理员赠送))]
[Trade(Direction = TradeDirections.Income)]
AdminDeposit = 1
,
/// <summary>
/// 管理员扣费
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.管理员扣费))]
[Trade(Direction = TradeDirections.Expense)]
AdminDeduct = 2
}

View File

@ -7,9 +7,9 @@ namespace NetAdmin.Infrastructure.Enums;
public enum TradeTypes
{
/// <summary>
/// 管理员充值
/// 管理员赠送
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.管理员充值))]
[ResourceDescription<Ln>(nameof(Ln.管理员赠送))]
[Trade(Direction = TradeDirections.Income)]
AdminDeposit = 1
@ -30,4 +30,22 @@ public enum TradeTypes
[ResourceDescription<Ln>(nameof(Ln.自助充值))]
[Trade(Direction = TradeDirections.Income)]
SelfDeposit = 3
,
/// <summary>
/// 转账支出
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.转账支出))]
[Trade(Direction = TradeDirections.Expense)]
TransferExpense = 4
,
/// <summary>
/// 转账收入
/// </summary>
[ResourceDescription<Ln>(nameof(Ln.转账收入))]
[Trade(Direction = TradeDirections.Income)]
TransferIncome = 5
}

View File

@ -0,0 +1,32 @@
namespace NetAdmin.Infrastructure.Enums;
/// <summary>
/// 类型扩展方法
/// </summary>
public static class TypeExtensions
{
/// <summary>
/// 递归获取类型的属性
/// </summary>
/// <param name="type">要查找的类型</param>
/// <param name="propertyPath">属性路径,如"a.b.c"</param>
/// <returns>找到的属性信息如果路径中任何属性不存在则返回null</returns>
public static PropertyInfo GetRecursiveProperty(this Type type, string propertyPath)
{
var properties = propertyPath.Split('.');
PropertyInfo propertyInfo = null;
var currentType = type;
foreach (var propertyName in properties) {
propertyInfo = currentType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (propertyInfo == null) {
return null;
}
currentType = propertyInfo.PropertyType;
}
return propertyInfo;
}
}

View File

@ -24,9 +24,7 @@ public static class StringExtensions
/// <summary>
/// 去掉尾部字符串“Async”
/// </summary>
#pragma warning disable RCS1047, ASA002, VSTHRD200
public static string TrimSuffixAsync(this string me)
#pragma warning restore VSTHRD200, ASA002, RCS1047
public static string TrimAsyncSuffix(this string me)
{
return me.TrimSuffix("Async");
}
@ -34,7 +32,7 @@ public static class StringExtensions
/// <summary>
/// 去掉尾部字符串“Options”
/// </summary>
public static string TrimSuffixOptions(this string me)
public static string TrimOptionsSuffix(this string me)
{
return me.TrimSuffix("Options");
}

View File

@ -5,8 +5,8 @@
<ItemGroup>
<PackageReference Include="NetAdmin.FreeSql.DbContext" Version="1.1.7" Label="refs"/>
<PackageReference Include="NetAdmin.FreeSql.Provider.Sqlite" Version="1.1.7" Label="refs"/>
<PackageReference Include="Gurion" Version="1.2.15" Label="refs"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.6"/>
<PackageReference Include="Gurion" Version="1.2.16" Label="refs"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.7"/>
<PackageReference Include="Minio" Version="6.0.5"/>
<PackageReference Include="NSExt" Version="2.3.7"/>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.6"/>

View File

@ -5,7 +5,7 @@ namespace NetAdmin.Infrastructure.Utils;
/// </summary>
public static class PhoneNumberHelper
{
private static readonly IEnumerable<(string CallingCode, CountryCodes CountryCode)> _countryList;
private static readonly ImmutableList<(string CallingCode, CountryCodes CountryCode)> _countryList;
#pragma warning disable S3963
static PhoneNumberHelper()
@ -21,14 +21,20 @@ public static class PhoneNumberHelper
.OrderBy(x => x.Item1)
.ThenByDescending(x => x.x.Attr<CountryInfoAttribute>().IsPreferred)
.DistinctBy(x => x.Item1)
.OrderByDescending(x => x.Item1.Length);
.OrderByDescending(x => x.Item1.Length)
.ToImmutableList();
}
/// <summary>
/// 电话号码转国家代码
/// </summary>
public static CountryCodes PhoneNumberToCountryCode(string phoneNumber)
public static CountryCodes? PhoneNumberToCountryCode(string phoneNumber)
{
return _countryList.First(x => phoneNumber.Replace("+", string.Empty).Trim().StartsWith(x.CallingCode, StringComparison.Ordinal)).CountryCode;
phoneNumber = phoneNumber.Trim();
if (phoneNumber.StartsWith('+')) {
phoneNumber = phoneNumber[1..];
}
return _countryList.FirstOrDefault(x => phoneNumber.StartsWith(x.CallingCode, StringComparison.Ordinal)).CountryCode;
}
}

View File

@ -17,7 +17,7 @@ public sealed class XmlCommentReader : ISingleton
public XmlCommentReader(IOptions<SpecificationDocumentSettingsOptions> specificationDocumentSettings)
{
var xmlComments = specificationDocumentSettings.Value.XmlComments //
?? App.GetConfig<SpecificationDocumentSettingsOptions>(nameof(SpecificationDocumentSettingsOptions).TrimSuffixOptions())
?? App.GetConfig<SpecificationDocumentSettingsOptions>(nameof(SpecificationDocumentSettingsOptions).TrimOptionsSuffix())
.XmlComments;
foreach (var commentFile in xmlComments) {
var xmlDoc = new XmlDocument();

View File

@ -0,0 +1,12 @@
using NetAdmin.Domain.Dto.Sys.CodeTemplate;
namespace NetAdmin.SysComponent.Application.Modules.Sys;
/// <summary>
/// 代码模板模块
/// </summary>
public interface ICodeTemplateModule : ICrudModule<CreateCodeTemplateReq, QueryCodeTemplateRsp // 创建类型
, EditCodeTemplateReq // 编辑类型
, QueryCodeTemplateReq, QueryCodeTemplateRsp // 查询类型
, DelReq // 删除类型
>;

View File

@ -24,5 +24,5 @@ public interface IDepositOrderModule : ICrudModule<CreateDepositOrderReq, QueryD
/// <summary>
/// 到账确认
/// </summary>
Task<int> ReceivedConfirmationAsync(ReceivedConfirmationReq req);
Task<int> ReceivedConfirmationAsync(JobReq req);
}

View File

@ -21,4 +21,24 @@ public interface IDevModule
/// 生成接口代码
/// </summary>
Task GenerateJsCodeAsync();
/// <summary>
/// 获取实体项目列表
/// </summary>
Task<IEnumerable<Tuple<string, string>>> GetDomainProjectsAsync();
/// <summary>
/// 获取所有数据类型
/// </summary>
IEnumerable<string> GetDotnetDataTypes(GetDotnetDataTypesReq req);
/// <summary>
/// 获取实体基类列表
/// </summary>
IEnumerable<Tuple<string, string>> GetEntityBaseClasses();
/// <summary>
/// 获取字段接口列表
/// </summary>
IEnumerable<Tuple<string, string>> GetFieldInterfaces();
}

View File

@ -1,3 +1,5 @@
using NetAdmin.Domain.Dto.Sys.Dic.Content;
using NetAdmin.Domain.Dto.Sys.User;
using NetAdmin.Domain.Dto.Sys.UserInvite;
namespace NetAdmin.SysComponent.Application.Modules.Sys;
@ -11,8 +13,38 @@ public interface IUserInviteModule : ICrudModule<CreateUserInviteReq, QueryUserI
, DelReq // 删除类型
>
{
/// <summary>
/// 创建粉丝账号
/// </summary>
Task<QueryUserRsp> CreateFansAccountAsync(CreateFansAccountReq req);
/// <summary>
/// 获取自己是否允许自助充值
/// </summary>
Task<bool> GetSelfRechargeAllowedAsync();
/// <summary>
/// 查询可分配的角色
/// </summary>
Task<IEnumerable<QueryDicContentRsp>> QueryRolesAllowApplyAsync();
/// <summary>
/// 设置返佣比率
/// </summary>
Task<int> SetCommissionRatioAsync(SetCommissionRatioReq req);
/// <summary>
/// 修改粉丝角色
/// </summary>
Task<int> SetFansRoleAsync(SetFansRoleReq req);
/// <summary>
/// 设置上级
/// </summary>
Task<int> SetInviterAsync(SetInviterReq req);
/// <summary>
/// 设置允许自助充值
/// </summary>
Task<int> SetSelfRechargeAllowedAsync(SetSelfRechargeAllowedReq req);
}

Some files were not shown because too many files have changed in this diff Show More