diff --git a/assets/res/NetAdmin.Fields.ln b/assets/res/NetAdmin.Fields.ln index a5e83057..3acdc230 100644 --- a/assets/res/NetAdmin.Fields.ln +++ b/assets/res/NetAdmin.Fields.ln @@ -116,7 +116,7 @@ USDT 登录名 登录日志导出 硕士 -示例导出 +代码模板导出 离异 空闲 站内信导出 diff --git a/assets/res/YourSolution.AdmServer.Fields.ln b/assets/res/YourSolution.AdmServer.Fields.ln index e69de29b..8c136503 100644 --- a/assets/res/YourSolution.AdmServer.Fields.ln +++ b/assets/res/YourSolution.AdmServer.Fields.ln @@ -0,0 +1 @@ +示例导出 \ No newline at end of file diff --git a/assets/seed-data/Sys_CodeTemplate.json b/assets/seed-data/Sys_CodeTemplate.json new file mode 100644 index 00000000..d781e9ba --- /dev/null +++ b/assets/seed-data/Sys_CodeTemplate.json @@ -0,0 +1,16 @@ +[ + { + "Enabled": true, + "Gender": 1, + "Id": 694360665923594, + "Name": "老王", + "Sort": 100, + }, + { + "Enabled": true, + "Gender": 2, + "Id": 694360665923595, + "Name": "媳妇儿", + "Sort": 100, + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_Menu.json b/assets/seed-data/Sys_Menu.json index 49567e0c..7477665a 100644 --- a/assets/seed-data/Sys_Menu.json +++ b/assets/seed-data/Sys_Menu.json @@ -278,13 +278,24 @@ "Title": "代码生成", "Type": 1 }, + { + "Component": "sys/template", + "Icon": "sc-icon-template", + "Id": 694076641718288, + "Name": "dev/template", + "ParentId": 373838105399301, + "Path": "/dev/template", + "Sort": 99, + "Title": "页面模板", + "Type": 1 + }, { "Id": 482777529417739, "ParentId": 373838105399301, "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, } diff --git a/src/backend/NetAdmin/NetAdmin.Application/Modules/Tpl/IExampleModule.cs b/src/backend/NetAdmin/NetAdmin.Application/Modules/Tpl/IExampleModule.cs deleted file mode 100644 index 3088bf09..00000000 --- a/src/backend/NetAdmin/NetAdmin.Application/Modules/Tpl/IExampleModule.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NetAdmin.Domain.Dto.Dependency; -using NetAdmin.Domain.Dto.Tpl.Example; - -namespace NetAdmin.Application.Modules.Tpl; - -/// -/// 示例模块 -/// -public interface IExampleModule : ICrudModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/Dependency/IExampleService.cs b/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/Dependency/IExampleService.cs deleted file mode 100644 index 670d0f04..00000000 --- a/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/Dependency/IExampleService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using NetAdmin.Application.Modules.Tpl; - -namespace NetAdmin.Application.Services.Tpl.Dependency; - -/// -/// 示例服务 -/// -public interface IExampleService : IService, IExampleModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Cache/Tpl/Dependency/IExampleCache.cs b/src/backend/NetAdmin/NetAdmin.Cache/Tpl/Dependency/IExampleCache.cs deleted file mode 100644 index d887f95a..00000000 --- a/src/backend/NetAdmin/NetAdmin.Cache/Tpl/Dependency/IExampleCache.cs +++ /dev/null @@ -1,9 +0,0 @@ -using NetAdmin.Application.Modules.Tpl; -using NetAdmin.Application.Services.Tpl.Dependency; - -namespace NetAdmin.Cache.Tpl.Dependency; - -/// -/// 示例缓存 -/// -public interface IExampleCache : ICache, IExampleModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Cache/Tpl/ExampleCache.cs b/src/backend/NetAdmin/NetAdmin.Cache/Tpl/ExampleCache.cs deleted file mode 100644 index 36b76893..00000000 --- a/src/backend/NetAdmin/NetAdmin.Cache/Tpl/ExampleCache.cs +++ /dev/null @@ -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; - -/// -public sealed class ExampleCache(IDistributedCache cache, IExampleService service) - : DistributedCache(cache, service), IScoped, IExampleCache -{ - /// - 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(CreateExampleReq req) - { - return Service.CreateAsync(req); - } - - /// - public Task DeleteAsync(DelReq req) - { - return Service.DeleteAsync(req); - } - - /// - public Task EditAsync(EditExampleReq req) - { - return Service.EditAsync(req); - } - - /// - public Task ExportAsync(QueryReq req) - { - return Service.ExportAsync(req); - } - - /// - public Task GetAsync(QueryExampleReq 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.Domain/DbMaps/Sys/Sys_CodeTemplate.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_CodeTemplate.cs new file mode 100644 index 00000000..0bef2ece --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Sys/Sys_CodeTemplate.cs @@ -0,0 +1,89 @@ +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 代码模板表 +/// +[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_CodeTemplate))] +public record Sys_CodeTemplate : VersionEntity, IFieldSort, IFieldSummary, IFieldEnabled, IFieldOwner +{ + /// + /// 是否启用 + /// + /// true + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual bool Enabled { get; init; } + + /// + /// 性别 + /// + /// Male + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual Genders? Gender { get; init; } + + /// + /// 唯一编码 + /// + /// 123456 + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + [CsvIgnore] + [JsonIgnore] + [Snowflake] + public override long Id { get; init; } + + /// + /// 名称 + /// + /// 老王 + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + [CsvIgnore] + [JsonIgnore] + public virtual string Name { get; init; } + + /// + /// 归属用户 + /// + [CsvIgnore] + [JsonIgnore] + [Navigate(nameof(OwnerId))] + public Sys_User Owner { get; init; } + + /// + /// 归属部门编号 + /// + /// 370942943322181 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerDeptId { get; init; } + + /// + /// 归属用户编号 + /// + /// 370942943322181 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerId { get; init; } + + /// + /// 排序值,越大越前 + /// + /// 100 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long Sort { get; init; } + + /// + /// 备注 + /// + /// 备注文字 + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [CsvIgnore] + [JsonIgnore] + public virtual string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Tpl/Tpl_Example.cs b/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Tpl/Tpl_Example.cs deleted file mode 100644 index 1bcbaff2..00000000 --- a/src/backend/NetAdmin/NetAdmin.Domain/DbMaps/Tpl/Tpl_Example.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace NetAdmin.Domain.DbMaps.Tpl; - -/// -/// 示例表 -/// -[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Tpl_Example))] -public record Tpl_Example : VersionEntity; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/CreateCodeTemplateReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/CreateCodeTemplateReq.cs new file mode 100644 index 00000000..29810c4b --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/CreateCodeTemplateReq.cs @@ -0,0 +1,30 @@ +namespace NetAdmin.Domain.Dto.Sys.CodeTemplate; + +/// +/// 请求:创建代码模板 +/// +public record CreateCodeTemplateReq : Sys_CodeTemplate +{ + /// + public override bool Enabled { get; init; } = true; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override Genders? Gender { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/EditCodeTemplateReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/EditCodeTemplateReq.cs new file mode 100644 index 00000000..a9ebc5d5 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/EditCodeTemplateReq.cs @@ -0,0 +1,11 @@ +namespace NetAdmin.Domain.Dto.Sys.CodeTemplate; + +/// +/// 请求:编辑代码模板 +/// +public sealed record EditCodeTemplateReq : CreateCodeTemplateReq +{ + /// + [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/CodeTemplate/QueryCodeTemplateReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/QueryCodeTemplateReq.cs new file mode 100644 index 00000000..9eaab40e --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/QueryCodeTemplateReq.cs @@ -0,0 +1,11 @@ +namespace NetAdmin.Domain.Dto.Sys.CodeTemplate; + +/// +/// 请求:查询代码模板 +/// +public sealed record QueryCodeTemplateReq : Sys_CodeTemplate +{ + /// + [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/CodeTemplate/QueryCodeTemplateRsp.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/QueryCodeTemplateRsp.cs new file mode 100644 index 00000000..adb11b27 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/CodeTemplate/QueryCodeTemplateRsp.cs @@ -0,0 +1,72 @@ +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.Dto.Sys.CodeTemplate; + +/// +/// 响应:查询代码模板 +/// +public record QueryCodeTemplateRsp : Sys_CodeTemplate +{ + /// + [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 bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override Genders? Gender { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override DateTime? ModifiedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? ModifiedUserId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ModifiedUserName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { 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 Sort { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { 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/Dev/FieldItemInfo.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/FieldItemInfo.cs new file mode 100644 index 00000000..c108dc28 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/FieldItemInfo.cs @@ -0,0 +1,47 @@ +namespace NetAdmin.Domain.Dto.Sys.Dev; + +/// +/// 信息:字段项信息 +/// +public sealed record FieldItemInfo : DataAbstraction +{ + /// + /// 数据库字段类型 + /// + public string DbType { get; init; } + + /// + /// 代码模板 + /// + public string Example { get; init; } + + /// + /// 可空 + /// + public bool IsNullable { get; init; } + + /// + /// 是否主键 + /// + public bool IsPrimary { get; set; } + + /// + /// 值类型 + /// + public bool IsStruct { get; init; } + + /// + /// 名称 + /// + public string Name { get; init; } + + /// + /// 备注 + /// + public string Summary { get; init; } + + /// + /// 类型 + /// + public string Type { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs index 9b13f724..9e61b60b 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs @@ -1,4 +1,4 @@ -namespace NetAdmin.Domain.Dto.Sys.Dev; +namespace NetAdmin.Domain.Dto.Sys.Dev; /// /// 请求:生成后端代码 @@ -6,20 +6,32 @@ namespace NetAdmin.Domain.Dto.Sys.Dev; public sealed record GenerateCsCodeReq : DataAbstraction { /// - /// 模块名称 + /// 基类 /// - [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.模块名称不能为空))] - public string ModuleName { get; init; } + public string BaseClass { get; init; } /// - /// 模块说明 + /// 实体名称 /// - [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.模块说明不能为空))] - public string ModuleRemark { get; init; } + public string EntityName { get; init; } /// - /// 模块类型 + /// 字段列表 /// - [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.模块类型不能为空))] - public string Type { get; init; } + public IReadOnlyCollection FieldList { get; init; } + + /// + /// 接口列表 + /// + public string[] Interfaces { get; init; } + + /// + /// 项目 + /// + public string Project { get; init; } + + /// + /// 描述 + /// + public string Summary { get; init; } } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GetDotnetDataTypesReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GetDotnetDataTypesReq.cs new file mode 100644 index 00000000..24a07f46 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Sys/Dev/GetDotnetDataTypesReq.cs @@ -0,0 +1,13 @@ +namespace NetAdmin.Domain.Dto.Sys.Dev; + +/// +/// 请求:获取所有数据类型 +/// +public sealed record GetDotnetDataTypesReq : DataAbstraction +{ + /// + /// 开始匹配 + /// + [Required] + public string StartWith { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/CreateExampleReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/CreateExampleReq.cs deleted file mode 100644 index bf6eeb95..00000000 --- a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/CreateExampleReq.cs +++ /dev/null @@ -1,8 +0,0 @@ -using NetAdmin.Domain.DbMaps.Tpl; - -namespace NetAdmin.Domain.Dto.Tpl.Example; - -/// -/// 请求:创建示例 -/// -public record CreateExampleReq : Tpl_Example; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/EditExampleReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/EditExampleReq.cs deleted file mode 100644 index 7712bfde..00000000 --- a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/EditExampleReq.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace NetAdmin.Domain.Dto.Tpl.Example; - -/// -/// 请求:编辑示例 -/// -public record EditExampleReq : CreateExampleReq -{ - /// - [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/Tpl/Example/QueryExampleReq.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleReq.cs deleted file mode 100644 index dbeb8849..00000000 --- a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleReq.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NetAdmin.Domain.DbMaps.Tpl; - -namespace NetAdmin.Domain.Dto.Tpl.Example; - -/// -/// 请求:查询示例 -/// -public sealed record QueryExampleReq : Tpl_Example -{ - /// - [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/Tpl/Example/QueryExampleRsp.cs b/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleRsp.cs deleted file mode 100644 index 27e7dffe..00000000 --- a/src/backend/NetAdmin/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleRsp.cs +++ /dev/null @@ -1,17 +0,0 @@ -using NetAdmin.Domain.DbMaps.Tpl; - -namespace NetAdmin.Domain.Dto.Tpl.Example; - -/// -/// 响应:查询示例 -/// -public sealed record QueryExampleRsp : Tpl_Example -{ - /// - [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/NetAdmin.Domain.csproj b/src/backend/NetAdmin/NetAdmin.Domain/NetAdmin.Domain.csproj index 72489a64..4c1f3ac3 100644 --- a/src/backend/NetAdmin/NetAdmin.Domain/NetAdmin.Domain.csproj +++ b/src/backend/NetAdmin/NetAdmin.Domain/NetAdmin.Domain.csproj @@ -4,7 +4,7 @@ - + diff --git a/src/backend/NetAdmin/NetAdmin.Host/Controllers/Tpl/ExampleController.cs b/src/backend/NetAdmin/NetAdmin.Host/Controllers/Tpl/ExampleController.cs deleted file mode 100644 index 4af33d6d..00000000 --- a/src/backend/NetAdmin/NetAdmin.Host/Controllers/Tpl/ExampleController.cs +++ /dev/null @@ -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; - -/// -/// 示例服务 -/// -[ApiDescriptionSettings(nameof(Tpl), Module = nameof(Tpl))] -[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)] -public sealed class ExampleController(IExampleCache cache) : ControllerBase(cache), IExampleModule -{ - /// - /// 批量删除示例 - /// - [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(CreateExampleReq req) - { - return Cache.CreateAsync(req); - } - - /// - /// 删除示例 - /// - [Transaction] - public Task DeleteAsync(DelReq req) - { - return Cache.DeleteAsync(req); - } - - /// - /// 编辑示例 - /// - [Transaction] - public Task EditAsync(EditExampleReq req) - { - return Cache.EditAsync(req); - } - - /// - /// 导出示例 - /// - [NonAction] - public Task ExportAsync(QueryReq req) - { - return Cache.ExportAsync(req); - } - - /// - /// 获取单个示例 - /// - public Task GetAsync(QueryExampleReq 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.Host/Filters/ApiResultHandler.cs b/src/backend/NetAdmin/NetAdmin.Host/Filters/ApiResultHandler.cs index b8dc18f0..d887d514 100644 --- a/src/backend/NetAdmin/NetAdmin.Host/Filters/ApiResultHandler.cs +++ b/src/backend/NetAdmin/NetAdmin.Host/Filters/ApiResultHandler.cs @@ -45,8 +45,7 @@ public abstract class ApiResultHandler /// /// HTTP状态码处理 /// - #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 return Task.CompletedTask; } - #pragma warning restore ASA001, VSTHRD200 - /// /// 请求成功 /// diff --git a/src/backend/NetAdmin/NetAdmin.Host/NetAdmin.Host.csproj b/src/backend/NetAdmin/NetAdmin.Host/NetAdmin.Host.csproj index 60e3ca7c..71621734 100644 --- a/src/backend/NetAdmin/NetAdmin.Host/NetAdmin.Host.csproj +++ b/src/backend/NetAdmin/NetAdmin.Host/NetAdmin.Host.csproj @@ -5,7 +5,7 @@ - + \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj b/src/backend/NetAdmin/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj index ca37d4ee..e9859ceb 100644 --- a/src/backend/NetAdmin/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj +++ b/src/backend/NetAdmin/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/ICodeTemplateModule.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/ICodeTemplateModule.cs new file mode 100644 index 00000000..d2f2efe9 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/ICodeTemplateModule.cs @@ -0,0 +1,12 @@ +using NetAdmin.Domain.Dto.Sys.CodeTemplate; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 代码模板模块 +/// +public interface ICodeTemplateModule : ICrudModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs index cb3c2092..217993e5 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs @@ -21,4 +21,24 @@ public interface IDevModule /// 生成接口代码 /// Task GenerateJsCodeAsync(); + + /// + /// 获取实体项目列表 + /// + Task>> GetDomainProjectsAsync(); + + /// + /// 获取所有数据类型 + /// + IEnumerable GetDotnetDataTypes(GetDotnetDataTypesReq req); + + /// + /// 获取实体基类列表 + /// + IEnumerable> GetEntityBaseClasses(); + + /// + /// 获取字段接口列表 + /// + IEnumerable> GetFieldInterfaces(); } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/CodeTemplateService.cs similarity index 59% rename from src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs rename to src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/CodeTemplateService.cs index 2b4aa265..015f4397 100644 --- a/src/backend/NetAdmin/NetAdmin.Application/Services/Tpl/ExampleService.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/CodeTemplateService.cs @@ -1,15 +1,12 @@ -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.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.CodeTemplate; using NetAdmin.Domain.Extensions; -namespace NetAdmin.Application.Services.Tpl; +namespace NetAdmin.SysComponent.Application.Services.Sys; -/// -public sealed class ExampleService(BasicRepository rpo) // - : RepositoryService(rpo), IExampleService +/// +public sealed class CodeTemplateService(BasicRepository rpo) // + : RepositoryService(rpo), ICodeTemplateService { /// public async Task BulkDeleteAsync(BulkReq req) @@ -26,34 +23,34 @@ public sealed class ExampleService(BasicRepository rpo) // } /// - public Task CountAsync(QueryReq req) + public Task CountAsync(QueryReq req) { req.ThrowIfInvalid(); return QueryInternal(req).WithNoLockNoWait().CountAsync(); } /// - public async Task, int>>> CountByAsync(QueryReq req) + public async Task, int>>> CountByAsync(QueryReq req) { req.ThrowIfInvalid(); var ret = await QueryInternal(req with { Order = Orders.None }) .WithNoLockNoWait() - .GroupBy(req.GetToListExp()) + .GroupBy(req.GetToListExp()) .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()) - , x.Value)) + req.RequiredFields.ToImmutableDictionary( + y => y, y => typeof(Sys_CodeTemplate).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(CreateExampleReq req) + public async Task CreateAsync(CreateCodeTemplateReq req) { req.ThrowIfInvalid(); var ret = await Rpo.InsertAsync(req).ConfigureAwait(false); - return ret.Adapt(); + return ret.Adapt(); } /// @@ -64,33 +61,35 @@ public sealed class ExampleService(BasicRepository rpo) // } /// - public async Task EditAsync(EditExampleReq req) + public async Task EditAsync(EditCodeTemplateReq 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 QueryExampleReq { Id = req.Id }).ConfigureAwait(false) : null; + return await UpdateAsync(req).ConfigureAwait(false) > 0 + ? await GetAsync(new QueryCodeTemplateReq { Id = req.Id }).ConfigureAwait(false) + : null; #endif } /// - public Task ExportAsync(QueryReq req) + public Task ExportAsync(QueryReq req) { req.ThrowIfInvalid(); - return ExportAsync(QueryInternal, req, Ln.示例导出); + return ExportAsync(QueryInternal, req, Ln.代码模板导出); } /// - public async Task GetAsync(QueryExampleReq req) + public async Task GetAsync(QueryCodeTemplateReq req) { req.ThrowIfInvalid(); - var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false); - return ret.Adapt(); + var ret = await QueryInternal(new QueryReq { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false); + return ret.Adapt(); } /// - public async Task> PagedQueryAsync(PagedQueryReq req) + public async Task> PagedQueryAsync(PagedQueryReq req) { req.ThrowIfInvalid(); var list = await QueryInternal(req) @@ -100,18 +99,18 @@ public sealed class ExampleService(BasicRepository rpo) // .ToListAsync(req) .ConfigureAwait(false); - return new PagedQueryRsp(req.Page, req.PageSize, total, list.Adapt>()); + return new PagedQueryRsp(req.Page, req.PageSize, total, list.Adapt>()); } /// - public async Task> QueryAsync(QueryReq req) + public async Task> QueryAsync(QueryReq req) { req.ThrowIfInvalid(); var ret = await QueryInternal(req).WithNoLockNoWait().Take(req.Count).ToListAsync(req).ConfigureAwait(false); - return ret.Adapt>(); + return ret.Adapt>(); } - private ISelect QueryInternal(QueryReq req) + private ISelect QueryInternal(QueryReq req) { var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter); diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICodeTemplateService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICodeTemplateService.cs new file mode 100644 index 00000000..8232c5ae --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICodeTemplateService.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 代码模板服务 +/// +public interface ICodeTemplateService : IService, ICodeTemplateModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs index ed41d66c..c2244619 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs @@ -1,3 +1,5 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; using NetAdmin.Domain.Dto.Sys.Api; using NetAdmin.Domain.Dto.Sys.Dev; @@ -11,123 +13,52 @@ public sealed class DevService(IApiService apiService) : ServiceBase private static readonly string _clientProjectPath = Path.Combine( // Environment.CurrentDirectory, "../../frontend/admin"); - private static readonly string[] _projectDirs = Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "../")) - .Concat(Directory.GetDirectories( - Path.Combine(Environment.CurrentDirectory, "../NetAdmin"))) - .ToArray(); - private static readonly Regex _regex = new(@"\.(\w)"); private static readonly Regex _regex2 = new("([a-zA-Z]+):"); + private static readonly Regex _regex3 = new(@"`\d+"); + private static readonly Regex _regex4 = new(@"^.+?[/\\]dist[/\\]"); /// public async Task GenerateCsCodeAsync(GenerateCsCodeReq req) { req.ThrowIfInvalid(); - int index; - var typeAbbr = req.Type[(index = req.Type.LastIndexOf('.') + 1)..(index + 3)]; - // 模板层目录 - var tplHostDir = GetDir("NetAdmin.Host"); - var tplCacheDir = GetDir("NetAdmin.Cache"); - var tplDataDir = GetDir("NetAdmin.Domain"); - var tplAppDir = GetDir("NetAdmin.Application"); + // 生成 dbMaps + await GenerateDomainEntityFileAsync(req, out var project, out var prefix).ConfigureAwait(false); - // 主机层目录 - var hostControllerDir = Path.Combine(GetDir($"{req.Type}.Host"), "Controllers", typeAbbr); - - // 缓存层目录 - var cacheDir = Path.Combine(GetDir($"{req.Type}.Cache"), typeAbbr); - var cacheDependencyDir = Path.Combine(cacheDir, "Dependency"); - - // 业务逻辑层目录 - var appDir = GetDir($"{req.Type}.Application"); - var appModulesDir = Path.Combine(appDir, "Modules", typeAbbr); - var appServicesDir = Path.Combine(appDir, "Services", typeAbbr); - var appServicesDependencyDir = Path.Combine(appServicesDir, "Dependency"); - - // 数据契约层目录 - string dataDir; - try { - dataDir = GetDir($"{req.Type}.Domain"); - } - catch (InvalidOperationException) { - dataDir = tplDataDir; + // 生成 dto + await GenerateDomainQueryRspFileAsync(req, project, prefix).ConfigureAwait(false); + await GenerateDomainCreateReqFileAsync(req, project, prefix).ConfigureAwait(false); + await GenerateDomainQueryReqFileAsync(req, project, prefix).ConfigureAwait(false); + await GenerateDomainEditReqFileAsync(req, project, prefix).ConfigureAwait(false); + if (req.Interfaces.Contains(nameof(IFieldEnabled))) { + await GenerateDomainSetEnabledReqFileAsync(req, project, prefix).ConfigureAwait(false); } - var dtoDir = Path.Combine(dataDir, "Dto", typeAbbr, req.ModuleName); - var entityDir = Path.Combine(dataDir, "DbMaps", typeAbbr); + // 生成 app + await GenerateAppModuleFileAsync(req, project, prefix).ConfigureAwait(false); + await GenerateAppIServiceFileAsync(req, project, prefix).ConfigureAwait(false); + await GenerateAppServiceFileAsync(req, project, prefix).ConfigureAwait(false); - // 创建缺少的目录 - CreateDir(hostControllerDir, cacheDir, cacheDependencyDir, appDir, appModulesDir, appServicesDir, appServicesDependencyDir, dataDir, dtoDir -, entityDir); + // 生成 cache + await GenerateICacheFileAsync(req, project, prefix).ConfigureAwait(false); + await GenerateCacheFileAsync(req, project, prefix).ConfigureAwait(false); - // Controller - await WriteCodeFileAsync(req, Path.Combine(tplHostDir, "Controllers", "Tpl", "ExampleController.cs") - , Path.Combine(hostControllerDir, $"{req.ModuleName}Controller.cs"), typeAbbr) - .ConfigureAwait(false); - - // CreateReq - await WriteCodeFileAsync(req, Path.Combine(tplDataDir, "Dto", "Tpl", "Example", "CreateExampleReq.cs") - , Path.Combine(dtoDir, $"Create{req.ModuleName}Req.cs"), typeAbbr) - .ConfigureAwait(false); - - // EditReq - await WriteCodeFileAsync(req, Path.Combine(tplDataDir, "Dto", "Tpl", "Example", "EditExampleReq.cs") - , Path.Combine(dtoDir, $"Edit{req.ModuleName}Req.cs"), typeAbbr) - .ConfigureAwait(false); - - // QueryReq - await WriteCodeFileAsync(req, Path.Combine(tplDataDir, "Dto", "Tpl", "Example", "QueryExampleReq.cs") - , Path.Combine(dtoDir, $"Query{req.ModuleName}Req.cs"), typeAbbr) - .ConfigureAwait(false); - - // QueryRsp - await WriteCodeFileAsync(req, Path.Combine(tplDataDir, "Dto", "Tpl", "Example", "QueryExampleRsp.cs") - , Path.Combine(dtoDir, $"Query{req.ModuleName}Rsp.cs"), typeAbbr) - .ConfigureAwait(false); - - // ICache - await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "Dependency", "IExampleCache.cs") - , Path.Combine(cacheDependencyDir, $"I{req.ModuleName}Cache.cs"), typeAbbr) - .ConfigureAwait(false); - - // Cache - await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "ExampleCache.cs"), Path.Combine(cacheDir, $"{req.ModuleName}Cache.cs") - , typeAbbr) - .ConfigureAwait(false); - - // IModule - await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Modules", "Tpl", "IExampleModule.cs") - , Path.Combine(appModulesDir, $"I{req.ModuleName}Module.cs"), typeAbbr) - .ConfigureAwait(false); - - // IService - await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "Dependency", "IExampleService.cs") - , Path.Combine(appServicesDependencyDir, $"I{req.ModuleName}Service.cs"), typeAbbr) - .ConfigureAwait(false); - - // Service - await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "ExampleService.cs") - , Path.Combine(appServicesDir, $"{req.ModuleName}Service.cs"), typeAbbr) - .ConfigureAwait(false); - - // Entity - await WriteCodeFileAsync(req, Path.Combine(tplDataDir, "DbMaps", "Tpl", "Tpl_Example.cs") - , Path.Combine(entityDir, $"{typeAbbr}_{req.ModuleName}.cs"), typeAbbr) - .ConfigureAwait(false); + // 生成 host + await GenerateHostControllerFileAsync(req, project, prefix).ConfigureAwait(false); } /// public async Task GenerateIconCodeAsync(GenerateIconCodeReq req) { req.ThrowIfInvalid(); - var tplSvg = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue")).ConfigureAwait(false); - var tplExport = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "export.js")) + var tplSvg = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icon", "tpl", "svg.vue")).ConfigureAwait(false); + var tplExport = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "assets", "icon", "tpl", "export.js")) .ConfigureAwait(false); var vueContent = tplSvg.Replace("$svgCode$", req.SvgCode).Replace(_REPLACE_TO_EMPTY, string.Empty); - var dir = Path.Combine(_clientProjectPath, "src", "assets", "icons"); + var dir = Path.Combine(_clientProjectPath, "src", "assets", "icon"); if (!Directory.Exists(dir)) { _ = Directory.CreateDirectory(dir); } @@ -191,23 +122,956 @@ public sealed class DevService(IApiService apiService) : ServiceBase } } - private static void CreateDir(params string[] dirs) + /// + public Task>> GetDomainProjectsAsync() { - foreach (var dir in dirs.Where(x => !Directory.Exists(x))) { - _ = Directory.CreateDirectory(dir!); + return Task.FromResult(Directory.EnumerateFiles("../", "*.Domain.csproj", SearchOption.AllDirectories) + .Select(x => new Tuple(Path.GetFileName(x), Path.GetFullPath(x)))); + } + + /// + public IEnumerable GetDotnetDataTypes(GetDotnetDataTypesReq req) + { + return AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(x => x.ExportedTypes.Select(y => _regex3.Replace(y.Name, string.Empty))) + .Distinct() + .Where(x => x.StartsWith(req.StartWith, true, CultureInfo.InvariantCulture)) + .Order() + .Take(Numbers.MAX_LIMIT_QUERY_PAGE_SIZE); + } + + /// + public IEnumerable> GetEntityBaseClasses() + { + return typeof(EntityBase<>).Assembly.GetExportedTypes() + .Where(x => x.IsAbstract && x.IsClass && x.Name.EndsWith("Entity", StringComparison.InvariantCulture)) + .Select(x => new Tuple(x.Name, x.FullName)); + } + + /// + public IEnumerable> GetFieldInterfaces() + { + return typeof(IFieldEnabled).Assembly.GetExportedTypes() + .Where(x => x.IsInterface && x.Name.StartsWith("IField", StringComparison.InvariantCulture)) + .Select(x => new Tuple(x.Name, x.FullName)); + } + + private static async Task GenerateAppIServiceFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var templatePath = Path.Combine( // + _regex4.Match(Environment.ProcessPath!).Value + , "../src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICodeTemplateService.cs"); + var templateContent = await File.ReadAllTextAsync(templatePath).ConfigureAwait(false); + var appProject = project.Replace(".Domain", ".Application"); + var dir = Path.Combine(templatePath, prefix == "Sys" ? "../../../../../NetAdmin.SysComponent.Application" : $"../../../../../../{appProject}" + , "Services", prefix, "Dependency"); + _ = Directory.CreateDirectory(dir); + + if (prefix != "Sys") { + templateContent = $""" + using NetAdmin.Application.Services; + using {appProject}.Modules.{prefix}; + + + """ + templateContent; + templateContent = templateContent.Replace( // + "NetAdmin.SysComponent.Application.Services.Sys.Dependency", $"{appProject}.Services.{prefix}.Dependency"); } + + templateContent = templateContent.Replace("CodeTemplate", req.EntityName).Replace("代码模板", req.Summary); + + await WriteCsCodeAsync(Path.Combine(dir, $"I{req.EntityName}Service.cs"), templateContent).ConfigureAwait(false); } - private static string GetDir(string key) + private static async Task GenerateAppModuleFileAsync(GenerateCsCodeReq req, string project, string prefix) { - return _projectDirs.First(x => x.EndsWith(key, true, CultureInfo.InvariantCulture)); + var templatePath = Path.Combine( // + _regex4.Match(Environment.ProcessPath!).Value + , "../src/backend/NetAdmin/NetAdmin.SysComponent.Application/Modules/Sys/ICodeTemplateModule.cs"); + var templateContent = await File.ReadAllTextAsync(templatePath).ConfigureAwait(false); + var appProject = project.Replace(".Domain", ".Application"); + var dir = Path.Combine(templatePath, prefix == "Sys" ? "../../../../NetAdmin.SysComponent.Application" : $"../../../../../{appProject}" + , "Modules", prefix); + _ = Directory.CreateDirectory(dir); + if (prefix != "Sys") { + templateContent = """ + using NetAdmin.Application.Modules; + using NetAdmin.Domain.Dto.Dependency; + + """ + templateContent; + templateContent = templateContent.Replace("NetAdmin.SysComponent.Application.Modules.Sys", $"{appProject}.Modules.{prefix}") + .Replace("NetAdmin.Domain.Dto.Sys", $"{project}.Dto.{prefix}"); + } + + templateContent = templateContent.Replace("CodeTemplate", req.EntityName).Replace("代码模板", req.Summary); + + if (req.Interfaces.Any(x => x == nameof(IFieldEnabled))) { + templateContent = templateContent[..^1] + $$""" + + { + /// + /// 设置{{req.Summary}}启用状态 + /// + Task SetEnabledAsync(Set{{req.EntityName}}EnabledReq req); + } + """; + } + + await WriteCsCodeAsync(Path.Combine(dir, $"I{req.EntityName}Module.cs"), templateContent).ConfigureAwait(false); } - private static async Task WriteCodeFileAsync(GenerateCsCodeReq req, string tplFile, string writeFile, string moduleAbbr) + private static async Task GenerateAppServiceFileAsync(GenerateCsCodeReq req, string project, string prefix) { - var tplContent = await File.ReadAllTextAsync(tplFile).ConfigureAwait(false); - tplContent = tplContent.Replace("Tpl", moduleAbbr).Replace("示例", req.ModuleRemark).Replace("Example", req.ModuleName); + var templatePath = Path.Combine( // + _regex4.Match(Environment.ProcessPath!).Value + , "../src/backend/NetAdmin/NetAdmin.SysComponent.Application/Services/Sys/CodeTemplateService.cs"); + var templateContent = await File.ReadAllTextAsync(templatePath).ConfigureAwait(false); + var appProject = project.Replace(".Domain", ".Application"); + var dir = Path.Combine(templatePath, prefix == "Sys" ? "../../../../NetAdmin.SysComponent.Application" : $"../../../../../{appProject}" + , "Services", prefix); + _ = Directory.CreateDirectory(dir); - await File.WriteAllTextAsync(writeFile, tplContent).ConfigureAwait(false); + if (prefix != "Sys") { + templateContent = $""" + using NetAdmin.Application.Repositories; + using NetAdmin.Application.Services; + using NetAdmin.Domain.Dto.Dependency; + using {appProject}.Services.{prefix}.Dependency; + using {project}.DbMaps.{prefix}; + + """ + templateContent; + + templateContent = templateContent.Replace("NetAdmin.SysComponent.Application.Services.Sys", $"{appProject}.Services.{prefix}") + .Replace("NetAdmin.Domain.Dto.Sys", $"{project}.Dto.{prefix}"); + } + + templateContent = templateContent.Replace("CodeTemplate", req.EntityName).Replace("代码模板", req.Summary).Replace("Sys_", $"{prefix}_"); + + if (req.Interfaces.Contains(nameof(IFieldEnabled))) { + templateContent = templateContent[..^1] + $$""" + + /// + public Task SetEnabledAsync(Set{{req.EntityName}}EnabledReq req) + { + req.ThrowIfInvalid(); + return UpdateAsync(req, [nameof(req.Enabled)]); + } + } + """; + } + + await WriteCsCodeAsync(Path.Combine(dir, $"{req.EntityName}Service.cs"), templateContent).ConfigureAwait(false); + } + + private static async Task GenerateCacheFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var templatePath = Path.Combine( // + _regex4.Match(Environment.ProcessPath!).Value, "../src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/CodeTemplateCache.cs"); + var templateContent = await File.ReadAllTextAsync(templatePath).ConfigureAwait(false); + var cacheProject = project.Replace(".Domain", ".Cache"); + var appProject = project.Replace(".Domain", ".Application"); + var dir = Path.Combine(templatePath, prefix == "Sys" ? "../../../NetAdmin.SysComponent.Cache" : $"../../../../{cacheProject}", prefix); + _ = Directory.CreateDirectory(dir); + + if (prefix != "Sys") { + templateContent = $""" + using NetAdmin.Cache; + using {appProject}.Services.{prefix}.Dependency; + using NetAdmin.Domain.Dto.Dependency; + using {cacheProject}.{prefix}.Dependency; + + """ + templateContent; + templateContent = templateContent.Replace("NetAdmin.SysComponent.Cache.Sys", $"{cacheProject}.{prefix}") + .Replace("NetAdmin.Domain.Dto.Sys", $"{project}.Dto.{prefix}"); + } + + templateContent = templateContent.Replace("CodeTemplate", req.EntityName).Replace("代码模板", req.Summary); + + if (req.Interfaces.Contains(nameof(IFieldEnabled))) { + templateContent = templateContent[..^1] + $$""" + + /// + public Task SetEnabledAsync(Set{{req.EntityName}}EnabledReq req) + { + return Service.SetEnabledAsync(req); + } + } + """; + } + + await WriteCsCodeAsync(Path.Combine(dir, $"{req.EntityName}Cache.cs"), templateContent).ConfigureAwait(false); + } + + private static Task GenerateDomainCreateReqFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var sb = new StringBuilder(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"using {project}.DbMaps.{prefix};"); + if (!req.Interfaces.NullOrEmpty()) { + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency.Fields;"); + } + + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"namespace {project}.Dto.{prefix}.{req.EntityName};"); + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $""" + /// + /// 请求:创建{req.Summary} + /// + """); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"public record Create{req.EntityName}Req : {prefix}_{req.EntityName}"); + _ = sb.Append('{'); + if (req.Interfaces?.Contains(nameof(IFieldEnabled)) == true) { + _ = sb.AppendLine(""" + + /// + public override bool Enabled { get; init; } = true; + """); + } + + if (req.BaseClass != nameof(SimpleEntity) && req.FieldList.Single(x => x.IsPrimary).Type == "string") { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [Required] + public override string Id { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldSort)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldSummary)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + """); + } + + foreach (var field in req.FieldList) { + var condition = field.IsStruct ? "Never" : "WhenWritingNull"; + var nul = field.IsStruct && field.IsNullable ? "?" : string.Empty; + _ = sb.AppendLine(CultureInfo.InvariantCulture, $$""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.{{condition}})] + public override {{field.Type}}{{nul}} {{field.Name}} { get; init; } + """); + } + + _ = sb.Append('}'); + + var outPath = Path.Combine(Path.GetDirectoryName(req.Project)!, "Dto", prefix, req.EntityName); + _ = Directory.CreateDirectory(outPath); + return WriteCsCodeAsync(Path.Combine(outPath, $"Create{req.EntityName}Req.cs"), sb.ToString()); + } + + private static Task GenerateDomainEditReqFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var sb = new StringBuilder(); + if (!req.Interfaces.NullOrEmpty()) { + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency.Fields;"); + } + + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"namespace {project}.Dto.{prefix}.{req.EntityName};"); + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $""" + /// + /// 请求:编辑{req.Summary} + /// + """); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"public sealed record Edit{req.EntityName}Req : Create{req.EntityName}Req"); + _ = sb.Append('{'); + + if (req.BaseClass == nameof(VersionEntity) || req.BaseClass == nameof(LiteVersionEntity) || + req.Interfaces?.Contains(nameof(IFieldVersion)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } + """); + } + + _ = sb.Append('}'); + + var outPath = Path.Combine(Path.GetDirectoryName(req.Project)!, "Dto", prefix, req.EntityName); + _ = Directory.CreateDirectory(outPath); + return WriteCsCodeAsync(Path.Combine(outPath, $"Edit{req.EntityName}Req.cs"), sb.ToString()); + } + + private static Task GenerateDomainEntityFileAsync(GenerateCsCodeReq req, out string project, out string prefix) + { + project = $"{Path.GetFileNameWithoutExtension(req.Project)}"; + prefix = project == "NetAdmin.Domain" ? "Sys" : project[(project.IndexOf('.') + 1)..(project.IndexOf('.') + 4)]; + var ns = project + $".DbMaps.{prefix}"; + var className = $"{prefix}_{req.EntityName}"; + var sb = new StringBuilder(); + + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency;"); + _ = sb.AppendLine("using NetAdmin.Domain.Attributes;"); + if (!req.Interfaces.NullOrEmpty()) { + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency.Fields;"); + if (req.Interfaces.Contains(nameof(IFieldOwner))) { + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Sys;"); + } + } + + _ = sb.AppendLine(); + _ = sb.Append(CultureInfo.InvariantCulture, $"namespace {ns};"); + _ = sb.AppendLine(); + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $""" + /// + /// {req.Summary}表 + /// + """); + _ = sb.Append( // + CultureInfo.InvariantCulture, $"[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof({className}))]"); + + _ = sb.AppendLine(); + _ = sb.Append(CultureInfo.InvariantCulture, $"public record {className} : {req.BaseClass}"); + var idType = req.FieldList.Single(x => x.IsPrimary).Type; + if (!idType.Equals("long", StringComparison.OrdinalIgnoreCase) && !idType.Equals("Int64", StringComparison.OrdinalIgnoreCase)) { + _ = sb.Append(CultureInfo.InvariantCulture, $"<{idType}>"); + } + + if (!req.Interfaces.NullOrEmpty()) { + _ = sb.Append(", "); + _ = sb.Append(req.Interfaces.Join(", ")); + } + + _ = sb.AppendLine(); + _ = sb.Append('{'); + + if (req.Interfaces?.Contains(nameof(IFieldEnabled)) == true) { + _ = sb.AppendLine(""" + + /// + /// 是否启用 + /// + /// true + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual bool Enabled { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldCreatedTime)) == true) { + _ = sb.AppendLine(""" + + /// + /// 创建时间 + /// + /// 2025-07-03 17:56:44 + [Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual DateTime CreatedTime { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldModifiedTime)) == true) { + _ = sb.AppendLine(""" + + /// + /// 修改时间 + /// + /// 2025-07-03 17:56:44 + [Column(ServerTime = DateTimeKind.Local, CanInsert = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual DateTime? ModifiedTime { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldCreatedClientIp)) == true) { + _ = sb.AppendLine(""" + + /// + /// 创建者客户端IP + /// + /// 127.0.0.1 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual int? CreatedClientIp { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldModifiedClientIp)) == true) { + _ = sb.AppendLine(""" + + /// + /// 修改者客户端IP + /// + /// 127.0.0.1 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual int? ModifiedClientIp { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldCreatedClientUserAgent)) == true) { + _ = sb.AppendLine(""" + + /// + /// 创建者客户端用户代理 + /// + /// Mozilla/5.0 + [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_1022)] + [CsvIgnore] + [JsonIgnore] + public virtual string CreatedUserAgent { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldModifiedClientUserAgent)) == true) { + _ = sb.AppendLine(""" + + /// + /// 修改者客户端用户代理 + /// + /// Mozilla/5.0 + [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_1022)] + [CsvIgnore] + [JsonIgnore] + public virtual string ModifiedUserAgent { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldCreatedUser)) == true) { + _ = sb.AppendLine(""" + + /// + /// 创建者编号 + /// + /// 370942943322181 + [Column(CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual long? CreatedUserId { get; init; } + + /// + /// 创建者用户名 + /// + /// root + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual string CreatedUserName { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldModifiedUser)) == true) { + _ = sb.AppendLine(""" + + /// + /// 修改者编号 + /// + /// 370942943322181 + [Column(CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual long? ModifiedUserId { get; init; } + + /// + /// 修改者用户名 + /// + /// root + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual string ModifiedUserName { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldOwner)) == true) { + _ = sb.AppendLine(""" + + /// + /// 归属用户 + /// + [CsvIgnore] + [JsonIgnore] + [Navigate(nameof(OwnerId))] + public Sys_User Owner { get; init; } + + /// + /// 归属部门编号 + /// + /// 370942943322181 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerDeptId { get; init; } + + /// + /// 归属用户编号 + /// + /// 370942943322181 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long? OwnerId { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldSort)) == true) { + _ = sb.AppendLine(""" + + /// + /// 排序值,越大越前 + /// + /// 100 + [Column] + [CsvIgnore] + [JsonIgnore] + public virtual long Sort { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldSummary)) == true) { + _ = sb.AppendLine(""" + + /// + /// 备注 + /// + /// 备注文字 + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [CsvIgnore] + [JsonIgnore] + public virtual string Summary { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldVersion)) == true) { + _ = sb.AppendLine(""" + + /// + /// 数据版本 + /// + /// 100 + [Column(IsVersion = true, Position = -1)] + [CsvIgnore] + [JsonIgnore] + public virtual long Version { get; init; } + """); + } + + foreach (var field in req.FieldList) { + var column = new StringBuilder(); + string snowflake = null; + if (!field.DbType.NullOrEmpty()) { + _ = column.Append(",DbType = Chars." + field.DbType); + } + + if (field.IsPrimary) { + _ = column.Append(",IsIdentity = false, IsPrimary = true, Position = 1"); + if (field.DbType.NullOrEmpty()) { + snowflake = """ + + [Snowflake] + """; + } + } + + if (column.Length > 0) { + _ = column[0] = '('; + _ = column.Append(')'); + } + + var decoration = field.IsPrimary ? "override" : "virtual"; + var nul = field.IsStruct && field.IsNullable ? "?" : string.Empty; + _ = sb.AppendLine(CultureInfo.InvariantCulture, $$""" + + /// + /// {{field.Summary}} + /// + /// {{field.Example}} + [Column{{column}}] + [CsvIgnore] + [JsonIgnore]{{snowflake}} + public {{decoration}} {{field.Type}}{{nul}} {{field.Name}} { get; init; } + """); + } + + _ = sb.Append('}'); + + var outPath = Path.Combine(Path.GetDirectoryName(req.Project)!, "DbMaps", prefix); + _ = Directory.CreateDirectory(outPath); + return WriteCsCodeAsync(Path.Combine(outPath, $"{className}.cs"), sb.ToString()); + } + + private static Task GenerateDomainQueryReqFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var sb = new StringBuilder(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"using {project}.DbMaps.{prefix};"); + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency;"); + + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"namespace {project}.Dto.{prefix}.{req.EntityName};"); + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $""" + /// + /// 请求:查询{req.Summary} + /// + """); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"public sealed record Query{req.EntityName}Req : {prefix}_{req.EntityName}"); + _ = sb.Append('{'); + + if (req.BaseClass != nameof(SimpleEntity)) { + var id = req.FieldList.Single(x => x.IsPrimary); + var condition = id.IsStruct ? "Never" : "WhenWritingNull"; + _ = sb.AppendLine(CultureInfo.InvariantCulture, $$""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.{{condition}})] + public override {{id.Type}} Id { get; init; } + """); + } + + _ = sb.Append('}'); + + var outPath = Path.Combine(Path.GetDirectoryName(req.Project)!, "Dto", prefix, req.EntityName); + _ = Directory.CreateDirectory(outPath); + return WriteCsCodeAsync(Path.Combine(outPath, $"Query{req.EntityName}Req.cs"), sb.ToString()); + } + + private static Task GenerateDomainQueryRspFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var isSealed = " sealed "; + var sb = new StringBuilder(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"using {project}.DbMaps.{prefix};"); + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency;"); + if (!req.Interfaces.NullOrEmpty()) { + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency.Fields;"); + if (req.Interfaces.Contains(nameof(IFieldOwner))) { + _ = sb.AppendLine("using NetAdmin.Domain.Dto.Sys.User;"); + isSealed = " "; + } + } + + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"namespace {project}.Dto.{prefix}.{req.EntityName};"); + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $""" + /// + /// 响应:查询{req.Summary} + /// + """); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"public{isSealed}record Query{req.EntityName}Rsp : {prefix}_{req.EntityName}"); + _ = sb.Append('{'); + if (req.Interfaces?.Contains(nameof(IFieldEnabled)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + """); + } + + if (req.BaseClass != nameof(SimpleEntity)) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + """); + } + + if ((req.BaseClass != nameof(SimpleEntity) && req.BaseClass != nameof(ImmutableEntity) && req.BaseClass != nameof(LiteImmutableEntity)) || + req.Interfaces?.Contains(nameof(IFieldModifiedTime)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override DateTime? ModifiedTime { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldCreatedClientIp)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override int? CreatedClientIp { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldModifiedClientIp)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override int? ModifiedClientIp { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldCreatedClientUserAgent)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CreatedUserAgent { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldModifiedClientUserAgent)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ModifiedUserAgent { get; init; } + """); + } + + if (new[] { nameof(VersionEntity), nameof(MutableEntity), nameof(ImmutableEntity) }.Contains(req.BaseClass) || + req.Interfaces?.Contains(nameof(IFieldCreatedUser)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? CreatedUserId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CreatedUserName { get; init; } + """); + } + + if (new[] { nameof(VersionEntity), nameof(MutableEntity) }.Contains(req.BaseClass) || + req.Interfaces?.Contains(nameof(IFieldModifiedUser)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override long? ModifiedUserId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ModifiedUserName { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldOwner)) == true) { + _ = sb.AppendLine(CultureInfo.InvariantCulture, $$""" + + /// + 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; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldSort)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } + """); + } + + if (req.Interfaces?.Contains(nameof(IFieldSummary)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + """); + } + + if (req.BaseClass == nameof(VersionEntity) || req.BaseClass == nameof(LiteVersionEntity) || + req.Interfaces?.Contains(nameof(IFieldVersion)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } + """); + } + + foreach (var field in req.FieldList) { + var nul = field.IsStruct && field.IsNullable ? "?" : string.Empty; + var condition = field.IsStruct ? "Never" : "WhenWritingNull"; + _ = sb.AppendLine(CultureInfo.InvariantCulture, $$""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.{{condition}})] + public override {{field.Type}}{{nul}} {{field.Name}} { get; init; } + """); + } + + _ = sb.Append('}'); + + var outPath = Path.Combine(Path.GetDirectoryName(req.Project)!, "Dto", prefix, req.EntityName); + _ = Directory.CreateDirectory(outPath); + return WriteCsCodeAsync(Path.Combine(outPath, $"Query{req.EntityName}Rsp.cs"), sb.ToString()); + } + + private static Task GenerateDomainSetEnabledReqFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var sb = new StringBuilder(); + if (!req.Interfaces.NullOrEmpty()) { + _ = sb.AppendLine("using NetAdmin.Domain.DbMaps.Dependency.Fields;"); + } + + if (prefix != "Sys") { + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"using {project}.DbMaps.{prefix};"); + } + + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"namespace {project}.Dto.{prefix}.{req.EntityName};"); + _ = sb.AppendLine(); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $""" + /// + /// 请求:设置{req.Summary}启用状态 + /// + """); + _ = sb.AppendLine(CultureInfo.InvariantCulture, $"public sealed record Set{req.EntityName}EnabledReq : {prefix}_{req.EntityName}"); + _ = sb.Append('{'); + + _ = sb.AppendLine(CultureInfo.InvariantCulture, $$""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + """); + + if (req.BaseClass == nameof(VersionEntity) || req.BaseClass == nameof(LiteVersionEntity) || + req.Interfaces?.Contains(nameof(IFieldVersion)) == true) { + _ = sb.AppendLine(""" + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } + """); + } + + _ = sb.Append('}'); + + var outPath = Path.Combine(Path.GetDirectoryName(req.Project)!, "Dto", prefix, req.EntityName); + _ = Directory.CreateDirectory(outPath); + return WriteCsCodeAsync(Path.Combine(outPath, $"Set{req.EntityName}EnabledReq.cs"), sb.ToString()); + } + + private static async Task GenerateHostControllerFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var templatePath = Path.Combine( // + _regex4.Match(Environment.ProcessPath!).Value + , "../src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/CodeTemplateController.cs"); + var templateContent = await File.ReadAllTextAsync(templatePath).ConfigureAwait(false); + var hostProject = project.Replace(".Domain", ".Host"); + var cacheProject = project.Replace(".Domain", ".Cache"); + var appProject = project.Replace(".Domain", ".Application"); + var dir = Path.Combine( + templatePath, prefix == "Sys" ? "../../../../NetAdmin.SysComponent.Host/Controllers" : $"../../../../../{hostProject}/Controllers" + , prefix); + _ = Directory.CreateDirectory(dir); + + if (prefix != "Sys") { + templateContent = $""" + using {appProject}.Services.{prefix}.Dependency; + using NetAdmin.Domain.Dto.Dependency; + using NetAdmin.Host.Attributes; + using NetAdmin.Host.Controllers; + using {appProject}.Modules.{prefix}; + using {cacheProject}.{prefix}.Dependency; + + """ + templateContent; + templateContent = templateContent.Replace("NetAdmin.SysComponent.Host.Controllers.Sys", $"{hostProject}.Controllers.{prefix}") + .Replace("NetAdmin.Domain.Dto.Sys", $"{project}.Dto.{prefix}") + .Replace("nameof(Sys)", $"nameof({prefix})"); + } + + templateContent = templateContent.Replace("CodeTemplate", req.EntityName).Replace("代码模板", req.Summary); + if (req.Interfaces.Contains(nameof(IFieldEnabled))) { + templateContent = templateContent[..^1] + $$""" + + /// + /// 设置{{req.Summary}}启用状态 + /// + public Task SetEnabledAsync(Set{{req.EntityName}}EnabledReq req) + { + return Cache.SetEnabledAsync(req); + } + } + """; + } + + await WriteCsCodeAsync(Path.Combine(dir, $"{req.EntityName}Controller.cs"), templateContent).ConfigureAwait(false); + } + + private static async Task GenerateICacheFileAsync(GenerateCsCodeReq req, string project, string prefix) + { + var templatePath = Path.Combine( // + _regex4.Match(Environment.ProcessPath!).Value + , "../src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/ICodeTemplateCache.cs"); + var templateContent = await File.ReadAllTextAsync(templatePath).ConfigureAwait(false); + var cacheProject = project.Replace(".Domain", ".Cache"); + var appProject = project.Replace(".Domain", ".Application"); + var dir = Path.Combine(templatePath, prefix == "Sys" ? "../../../../NetAdmin.SysComponent.Cache" : $"../../../../../{cacheProject}", prefix + , "Dependency"); + _ = Directory.CreateDirectory(dir); + + if (prefix != "Sys") { + templateContent = $""" + using NetAdmin.Cache; + using {appProject}.Modules.{prefix}; + using {appProject}.Services.{prefix}.Dependency; + + + """ + templateContent; + templateContent = templateContent.Replace( // + "NetAdmin.SysComponent.Cache.Sys.Dependency", $"{cacheProject}.{prefix}.Dependency"); + } + + templateContent = templateContent.Replace("CodeTemplate", req.EntityName).Replace("代码模板", req.Summary); + + await WriteCsCodeAsync(Path.Combine(dir, $"I{req.EntityName}Cache.cs"), templateContent).ConfigureAwait(false); + } + + private static Task WriteCsCodeAsync(string path, string content) + { + content = content.Replace("\r", string.Empty); + var sb = new StringBuilder(); + var usings = new List(); + + foreach (var line in content.Split('\n')) { + if (line.StartsWith("using ", StringComparison.Ordinal)) { + usings.Add(line); + } + else { + _ = sb.AppendLine(); + _ = sb.Append(line); + } + } + + usings.Sort(); + + content = string.Join('\n', usings) + sb; + return File.WriteAllTextAsync(path, usings.Count == 0 ? content.Trim() : content); } } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/CodeTemplateCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/CodeTemplateCache.cs new file mode 100644 index 00000000..05639583 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/CodeTemplateCache.cs @@ -0,0 +1,68 @@ +using NetAdmin.Domain.Dto.Sys.CodeTemplate; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +public sealed class CodeTemplateCache(IDistributedCache cache, ICodeTemplateService service) + : DistributedCache(cache, service), IScoped, ICodeTemplateCache +{ + /// + 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(CreateCodeTemplateReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task EditAsync(EditCodeTemplateReq req) + { + return Service.EditAsync(req); + } + + /// + public Task ExportAsync(QueryReq req) + { + return Service.ExportAsync(req); + } + + /// + public Task GetAsync(QueryCodeTemplateReq 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/Dependency/ICodeTemplateCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/ICodeTemplateCache.cs new file mode 100644 index 00000000..84ce9186 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/Dependency/ICodeTemplateCache.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 代码模板缓存 +/// +public interface ICodeTemplateCache : ICache, ICodeTemplateModule; \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/DevCache.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/DevCache.cs index cf169b0b..4cfe0090 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/DevCache.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Cache/Sys/DevCache.cs @@ -23,4 +23,28 @@ public sealed class DevCache(IDistributedCache cache, IDevService service) // { return Service.GenerateJsCodeAsync(); } + + /// + public Task>> GetDomainProjectsAsync() + { + return Service.GetDomainProjectsAsync(); + } + + /// + public IEnumerable GetDotnetDataTypes(GetDotnetDataTypesReq req) + { + return Service.GetDotnetDataTypes(req); + } + + /// + public IEnumerable> GetEntityBaseClasses() + { + return Service.GetEntityBaseClasses(); + } + + /// + public IEnumerable> GetFieldInterfaces() + { + return Service.GetFieldInterfaces(); + } } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/CodeTemplateController.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/CodeTemplateController.cs new file mode 100644 index 00000000..4c1c6a15 --- /dev/null +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/CodeTemplateController.cs @@ -0,0 +1,98 @@ +using NetAdmin.Domain.Dto.Sys.CodeTemplate; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 代码模板服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +[Produces(Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_JSON)] +public sealed class CodeTemplateController(ICodeTemplateCache cache) + : ControllerBase(cache), ICodeTemplateModule +{ + /// + /// 批量删除代码模板 + /// + [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(CreateCodeTemplateReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除代码模板 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 编辑代码模板 + /// + [Transaction] + public Task EditAsync(EditCodeTemplateReq req) + { + return Cache.EditAsync(req); + } + + /// + /// 导出代码模板 + /// + [NonAction] + public Task ExportAsync(QueryReq req) + { + return Cache.ExportAsync(req); + } + + /// + /// 获取单个代码模板 + /// + public Task GetAsync(QueryCodeTemplateReq 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/DevController.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/DevController.cs index e64686ae..fb330a0e 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/DevController.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Controllers/Sys/DevController.cs @@ -32,4 +32,36 @@ public sealed class DevController(IDevCache cache) : ControllerBase + /// 获取实体项目列表 + /// + public Task>> GetDomainProjectsAsync() + { + return Cache.GetDomainProjectsAsync(); + } + + /// + /// 获取所有数据类型 + /// + public IEnumerable GetDotnetDataTypes(GetDotnetDataTypesReq req) + { + return Cache.GetDotnetDataTypes(req); + } + + /// + /// 获取实体基类列表 + /// + public IEnumerable> GetEntityBaseClasses() + { + return Cache.GetEntityBaseClasses(); + } + + /// + /// 获取字段接口列表 + /// + public IEnumerable> GetFieldInterfaces() + { + return Cache.GetFieldInterfaces(); + } } \ No newline at end of file diff --git a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Middlewares/RequestAuditMiddleware.cs b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Middlewares/RequestAuditMiddleware.cs index b25f0bb6..41569800 100644 --- a/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Middlewares/RequestAuditMiddleware.cs +++ b/src/backend/NetAdmin/NetAdmin.SysComponent.Host/Middlewares/RequestAuditMiddleware.cs @@ -28,6 +28,7 @@ public sealed class RequestAuditMiddleware( ) { #pragma warning restore SA1009 await next(context).ConfigureAwait(false); + return; } diff --git a/src/backend/UnitTests/Sys/DevTests.cs b/src/backend/UnitTests/Sys/DevTests.cs index 718184fd..0bb2a02c 100644 --- a/src/backend/UnitTests/Sys/DevTests.cs +++ b/src/backend/UnitTests/Sys/DevTests.cs @@ -35,4 +35,45 @@ public class DevTests(WebTestApplicationFactory factory, ITestOutputHel var rsp = await PostJsonAsync(typeof(DevController)); Assert.True(rsp.IsSuccessStatusCode); } + + /// + [Fact] + public async Task>> GetDomainProjectsAsync() + { + var rsp = await PostJsonAsync(typeof(DevController)); + Assert.True(rsp.IsSuccessStatusCode); + return null; + } + + /// + public IEnumerable GetDotnetDataTypes(GetDotnetDataTypesReq req) + { + #pragma warning disable xUnit1031 + var rsp = PostJsonAsync(typeof(DevController)).GetAwaiter().GetResult(); + #pragma warning restore xUnit1031 + Assert.True(rsp.IsSuccessStatusCode); + return null; + } + + /// + [Fact] + public IEnumerable> GetEntityBaseClasses() + { + #pragma warning disable xUnit1031 + var rsp = PostJsonAsync(typeof(DevController)).GetAwaiter().GetResult(); + #pragma warning restore xUnit1031 + Assert.True(rsp.IsSuccessStatusCode); + return null; + } + + /// + [Fact] + public IEnumerable> GetFieldInterfaces() + { + #pragma warning disable xUnit1031 + var rsp = PostJsonAsync(typeof(DevController)).GetAwaiter().GetResult(); + #pragma warning restore xUnit1031 + Assert.True(rsp.IsSuccessStatusCode); + return null; + } } \ No newline at end of file diff --git a/src/backend/YourSolution.AdmServer.Domain/ProjectUsings.cs b/src/backend/YourSolution.AdmServer.Domain/ProjectUsings.cs new file mode 100644 index 00000000..bdad148a --- /dev/null +++ b/src/backend/YourSolution.AdmServer.Domain/ProjectUsings.cs @@ -0,0 +1 @@ +global using CsvIgnore = CsvHelper.Configuration.Attributes.IgnoreAttribute; \ No newline at end of file diff --git a/src/backend/YourSolution.AdmServer.Host/Startup.cs b/src/backend/YourSolution.AdmServer.Host/Startup.cs index 76e6509a..37b12929 100644 --- a/src/backend/YourSolution.AdmServer.Host/Startup.cs +++ b/src/backend/YourSolution.AdmServer.Host/Startup.cs @@ -105,9 +105,13 @@ namespace YourSolution.AdmServer.Host } /// - #pragma warning disable ASA001 - public async Task Execute(CommandContext context, CommandLineArgs settings) - #pragma warning restore ASA001 + public Task ExecuteAsync(CommandContext context, CommandSettings settings) + { + return ExecuteAsync(context, (settings as CommandLineArgs)!); + } + + /// + public async Task ExecuteAsync(CommandContext context, CommandLineArgs settings) { Args = settings; var webOpt = new WebApplicationOptions // @@ -120,14 +124,6 @@ namespace YourSolution.AdmServer.Host return 0; } - /// - #pragma warning disable ASA001 - public Task Execute(CommandContext context, CommandSettings settings) - #pragma warning restore ASA001 - { - return Execute(context, (settings as CommandLineArgs)!); - } - /// public ValidationResult Validate(CommandContext context, CommandSettings settings) { diff --git a/src/backend/YourSolution.AdmServer.Infrastructure/AdmSettings.json b/src/backend/YourSolution.AdmServer.Infrastructure/AdmSettings.json index 870b73c8..a392fe68 100644 --- a/src/backend/YourSolution.AdmServer.Infrastructure/AdmSettings.json +++ b/src/backend/YourSolution.AdmServer.Infrastructure/AdmSettings.json @@ -13,10 +13,6 @@ "Group": "Adm", "Title": "管理服务", }, - { - "Group": "Tpl", - "Visible": false - }, { "Group": "Probe", "Visible": false diff --git a/src/frontend/admin/src/api/tpl/example.js b/src/frontend/admin/src/api/sys/codetemplate.js similarity index 55% rename from src/frontend/admin/src/api/tpl/example.js rename to src/frontend/admin/src/api/sys/codetemplate.js index 677adca3..26256474 100644 --- a/src/frontend/admin/src/api/tpl/example.js +++ b/src/frontend/admin/src/api/sys/codetemplate.js @@ -1,93 +1,93 @@ /** - * 示例服务 - * @module @/api/tpl/example + * 代码模板服务 + * @module @/api/sys/code.template */ import config from '@/config' import http from '@/utils/request' export default { /** - * 批量删除示例 + * 批量删除代码模板 */ bulkDelete: { - url: `${config.API_URL}/api/tpl/example/bulk.delete`, - name: `批量删除示例`, + url: `${config.API_URL}/api/sys/code.template/bulk.delete`, + name: `批量删除代码模板`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 示例计数 + * 代码模板计数 */ count: { - url: `${config.API_URL}/api/tpl/example/count`, - name: `示例计数`, + url: `${config.API_URL}/api/sys/code.template/count`, + name: `代码模板计数`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 示例分组计数 + * 代码模板分组计数 */ countBy: { - url: `${config.API_URL}/api/tpl/example/count.by`, - name: `示例分组计数`, + url: `${config.API_URL}/api/sys/code.template/count.by`, + name: `代码模板分组计数`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 创建示例 + * 创建代码模板 */ create: { - url: `${config.API_URL}/api/tpl/example/create`, - name: `创建示例`, + url: `${config.API_URL}/api/sys/code.template/create`, + name: `创建代码模板`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 删除示例 + * 删除代码模板 */ delete: { - url: `${config.API_URL}/api/tpl/example/delete`, - name: `删除示例`, + url: `${config.API_URL}/api/sys/code.template/delete`, + name: `删除代码模板`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 编辑示例 + * 编辑代码模板 */ edit: { - url: `${config.API_URL}/api/tpl/example/edit`, - name: `编辑示例`, + url: `${config.API_URL}/api/sys/code.template/edit`, + name: `编辑代码模板`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 获取单个示例 + * 获取单个代码模板 */ get: { - url: `${config.API_URL}/api/tpl/example/get`, - name: `获取单个示例`, + url: `${config.API_URL}/api/sys/code.template/get`, + name: `获取单个代码模板`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, }, /** - * 分页查询示例 + * 分页查询代码模板 */ pagedQuery: { - url: `${config.API_URL}/api/tpl/example/paged.query`, - name: `分页查询示例`, + url: `${config.API_URL}/api/sys/code.template/paged.query`, + name: `分页查询代码模板`, post: async function (data = {}, config = {}) { return await http.post(this.url, data, config) }, diff --git a/src/frontend/admin/src/api/sys/dev.js b/src/frontend/admin/src/api/sys/dev.js index 72b4d415..da807d7f 100644 --- a/src/frontend/admin/src/api/sys/dev.js +++ b/src/frontend/admin/src/api/sys/dev.js @@ -37,4 +37,48 @@ export default { return await http.post(this.url, data, config) }, }, + + /** + * 获取实体项目列表 + */ + getDomainProjects: { + url: `${config.API_URL}/api/sys/dev/get.domain.projects`, + name: `获取实体项目列表`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 获取所有数据类型 + */ + getDotnetDataTypes: { + url: `${config.API_URL}/api/sys/dev/get.dotnet.data.types`, + name: `获取所有数据类型`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 获取实体基类列表 + */ + getEntityBaseClasses: { + url: `${config.API_URL}/api/sys/dev/get.entity.base.classes`, + name: `获取实体基类列表`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + + /** + * 获取字段接口列表 + */ + getFieldInterfaces: { + url: `${config.API_URL}/api/sys/dev/get.field.interfaces`, + 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/assets/icon/index.js b/src/frontend/admin/src/assets/icon/index.js index e2c0ab30..5f36e0d5 100644 --- a/src/frontend/admin/src/assets/icon/index.js +++ b/src/frontend/admin/src/assets/icon/index.js @@ -75,4 +75,5 @@ export { default as archive } from './archive' export { default as 'device-log' } from './device-log' export { default as 'nick-name' } from './nick-name' export { default as telegram } from './telegram' -export { default as country } from './country' \ No newline at end of file +export { default as country } from './country' +export {default as template} from './template.vue' \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icon/template.vue b/src/frontend/admin/src/assets/icon/template.vue new file mode 100644 index 00000000..75f787d1 --- /dev/null +++ b/src/frontend/admin/src/assets/icon/template.vue @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/components/na-search/index.vue b/src/frontend/admin/src/components/na-search/index.vue index dc69175e..bfbcaec3 100644 --- a/src/frontend/admin/src/components/na-search/index.vue +++ b/src/frontend/admin/src/components/na-search/index.vue @@ -443,7 +443,7 @@ export default { } this.aceEditorValue = this.vkbeautify.json(this.vue.query, 2) this.selectInputKey = this.controls.find((x) => x.type === 'select-input')?.field[1][0].key - if (this.dateType === 'datetime-range') { + if (this.dateType === 'datetimerange') { this.dateShortCuts.unshift( { text: this.$t('最近一时'), diff --git a/src/frontend/admin/src/components/na-table-page/detail.vue b/src/frontend/admin/src/components/na-table-page/detail.vue new file mode 100644 index 00000000..40623135 --- /dev/null +++ b/src/frontend/admin/src/components/na-table-page/detail.vue @@ -0,0 +1,125 @@ + + + + +