From 3842e2a765db5bb51d89bd316e9797c689ed8c3a Mon Sep 17 00:00:00 2001 From: coolcalf <28551@qq.com> Date: Sat, 17 Aug 2024 15:07:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E8=83=BD=201.=E6=A8=A1=E6=9D=BF=E9=87=8D?= =?UTF-8?q?=E5=91=BD=E5=90=8D=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=9B=202.=E5=A2=9E=E5=8A=A0=20SysCodeGen?= =?UTF-8?q?Template=20=E6=A8=A1=E6=9D=BF=E5=AE=9A=E4=B9=89=E8=A1=A8?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E7=B3=BB=E7=BB=9F=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=A7=8D=E5=AD=90=E6=95=B0=E6=8D=AE=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entity/SysCodeGenTemplate.cs | 52 ++ .../CodeGenTypeEnum.cs} | 18 +- .../SeedData/SysCodeGenTemplate.cs | 31 ++ .../CodeGen/SysCodeGenConfigService.cs | 7 +- .../Service/CodeGen/SysCodeGenService.cs | 255 ++++------ Admin.NET/Admin.NET.Core/Util/BaseInput.cs | 71 +++ Admin.NET/Admin.NET.Core/Util/BaseOutput.cs | 64 +++ .../{Input.cs.vm => service_InputDto.cs.vm} | 0 .../{Output.cs.vm => service_OutputDto.cs.vm} | 0 .../{Service.cs.vm => service_Service.cs.vm} | 38 +- .../template/{Manage.js.vm => web_api.ts.vm} | 0 ...log.vue.vm => web_views_editDialog.vue.vm} | 354 +++++++------ .../{index.vue.vm => web_views_index.vue.vm} | 19 +- .../template/web_views_listDialog.vue.vm | 465 ++++++++++++++++++ 14 files changed, 989 insertions(+), 385 deletions(-) create mode 100644 Admin.NET/Admin.NET.Core/Entity/SysCodeGenTemplate.cs rename Admin.NET/Admin.NET.Core/{Util/BaseIdInput.cs => Enum/CodeGenTypeEnum.cs} (72%) create mode 100644 Admin.NET/Admin.NET.Core/SeedData/SysCodeGenTemplate.cs create mode 100644 Admin.NET/Admin.NET.Core/Util/BaseInput.cs create mode 100644 Admin.NET/Admin.NET.Core/Util/BaseOutput.cs rename Admin.NET/Admin.NET.Web.Entry/wwwroot/template/{Input.cs.vm => service_InputDto.cs.vm} (100%) rename Admin.NET/Admin.NET.Web.Entry/wwwroot/template/{Output.cs.vm => service_OutputDto.cs.vm} (100%) rename Admin.NET/Admin.NET.Web.Entry/wwwroot/template/{Service.cs.vm => service_Service.cs.vm} (88%) rename Admin.NET/Admin.NET.Web.Entry/wwwroot/template/{Manage.js.vm => web_api.ts.vm} (100%) rename Admin.NET/Admin.NET.Web.Entry/wwwroot/template/{editDialog.vue.vm => web_views_editDialog.vue.vm} (54%) rename Admin.NET/Admin.NET.Web.Entry/wwwroot/template/{index.vue.vm => web_views_index.vue.vm} (97%) create mode 100644 Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_listDialog.vue.vm diff --git a/Admin.NET/Admin.NET.Core/Entity/SysCodeGenTemplate.cs b/Admin.NET/Admin.NET.Core/Entity/SysCodeGenTemplate.cs new file mode 100644 index 00000000..e3137261 --- /dev/null +++ b/Admin.NET/Admin.NET.Core/Entity/SysCodeGenTemplate.cs @@ -0,0 +1,52 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Core; + +/// +/// 代码生成模板配置 +/// +[SugarTable(null, "代码生成模板配置")] +[SysTable] +public partial class SysCodeGenTemplate : EntityBase +{ + /// + /// 模板文件名 + /// + [SugarColumn(ColumnDescription = "模板文件名", Length = 128)] + [Required, MaxLength(128)] + public string Name { get; set; } + + /// + /// 是否是内置模板(Y-是,N-否) + /// + [SugarColumn(ColumnDescription = "是否是内置模板")] + public CodeGenTypeEnum Type { get; set; } + + /// + /// 是否是内置模板(Y-是,N-否) + /// + [SugarColumn(ColumnDescription = "是否是内置模板")] + public YesNoEnum SysFlag { get; set; } + + /// + /// 输出位置 + /// + [SugarColumn(ColumnDescription = "输出位置", Length = 256)] + public string OutputFile { get; set; } + + /// + /// 描述 + /// + [SugarColumn(ColumnDescription = "描述", Length = 200)] + public string Describe { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int OrderNo { get; set; } = 100; +} \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Util/BaseIdInput.cs b/Admin.NET/Admin.NET.Core/Enum/CodeGenTypeEnum.cs similarity index 72% rename from Admin.NET/Admin.NET.Core/Util/BaseIdInput.cs rename to Admin.NET/Admin.NET.Core/Enum/CodeGenTypeEnum.cs index bdc86b25..c7afc4f0 100644 --- a/Admin.NET/Admin.NET.Core/Util/BaseIdInput.cs +++ b/Admin.NET/Admin.NET.Core/Enum/CodeGenTypeEnum.cs @@ -7,14 +7,20 @@ namespace Admin.NET.Core; /// -/// 主键Id输入参数 +/// 代码生成类型枚举 /// -public class BaseIdInput +[Description("代码生成类型枚举")] +public enum CodeGenTypeEnum { /// - /// 主键Id + /// 前端 /// - [Required(ErrorMessage = "Id不能为空")] - [DataValidation(ValidationTypes.Numeric)] - public virtual long Id { get; set; } + [Description("前端")] + Frontend = 1, + + /// + /// 后端 + /// + [Description("后端")] + Backend = 2, } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/SeedData/SysCodeGenTemplate.cs b/Admin.NET/Admin.NET.Core/SeedData/SysCodeGenTemplate.cs new file mode 100644 index 00000000..1adc98aa --- /dev/null +++ b/Admin.NET/Admin.NET.Core/SeedData/SysCodeGenTemplate.cs @@ -0,0 +1,31 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Core; + +/// +/// 系统配置表种子数据 +/// +public class SysCodeGenTemplateSeedData : ISqlSugarEntitySeedData +{ + /// + /// 种子数据 + /// + /// + public IEnumerable HasData() + { + return new[] + { + new SysCodeGenTemplate{ Id=36036980201001, SysFlag=YesNoEnum.Y, Type=CodeGenTypeEnum.Frontend, Name="web_api.ts.vm", OutputFile="api/main/{TableNameLower}.ts", Describe ="(WEB)接口"}, + new SysCodeGenTemplate{ Id=36036980201002, SysFlag=YesNoEnum.Y, Type=CodeGenTypeEnum.Frontend, Name="web_views_index.vue.vm", OutputFile="views/main/{TableNameLower}/index.vue", Describe ="(WEB)列表页面"}, + new SysCodeGenTemplate{ Id=36036980201003, SysFlag=YesNoEnum.Y, Type=CodeGenTypeEnum.Frontend, Name="web_views_editDialog.vue.vm", OutputFile="views/main/{TableNameLower}/component/editDialog.vue", Describe ="(WEB)编辑对话框"}, + + new SysCodeGenTemplate{ Id=36036980202001, SysFlag=YesNoEnum.Y, Type=CodeGenTypeEnum.Backend, Name="service_Service.cs.vm", OutputFile="Service/{TableName}/{TableName}Service.cs", Describe ="(服务端)业务"}, + new SysCodeGenTemplate{ Id=36036980202002, SysFlag=YesNoEnum.Y, Type=CodeGenTypeEnum.Backend, Name="service_InputDto.cs.vm", OutputFile="Service/{TableName}/Dto/{TableName}Input.cs", Describe ="(服务端)输入参数"}, + new SysCodeGenTemplate{ Id=36036980202003, SysFlag=YesNoEnum.Y, Type=CodeGenTypeEnum.Backend, Name="service_OutputDto.cs.vm", OutputFile="Service/{TableName}/Dto/{TableName}Output.cs", Describe ="(服务端)输出参数"}, + }; + } +} \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs index 560651a9..ec9f1cf3 100644 --- a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs +++ b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs @@ -4,6 +4,8 @@ // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! +using Elastic.Clients.Elasticsearch.MachineLearning; + namespace Admin.NET.Core.Service; /// @@ -89,6 +91,9 @@ public class SysCodeGenConfigService : IDynamicApiController, ITransient var orderNo = 100; foreach (var tableColumn in tableColumnOutputList) { + if (_db.Queryable().Any(u => u.ColumnName == tableColumn.ColumnName && u.CodeGenId == codeGenerate.Id)) + continue; + var codeGenConfig = new SysCodeGenConfig(); var YesOrNo = YesNoEnum.Y.ToString(); @@ -132,7 +137,7 @@ public class SysCodeGenConfigService : IDynamicApiController, ITransient orderNo += 10; // 每个配置排序间隔10 } // 多库代码生成---这里要切回主库 - var provider = _db.AsTenant().GetConnectionScope(SqlSugarConst.MainConfigId); + var provider = _db.AsTenant().GetConnectionScope(SqlSugarConst.MainConfigId); provider.Insertable(codeGenConfigs).ExecuteCommand(); } diff --git a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs index a1917485..b2837ca0 100644 --- a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs +++ b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs @@ -15,17 +15,19 @@ namespace Admin.NET.Core.Service; public class SysCodeGenService : IDynamicApiController, ITransient { private readonly ISqlSugarClient _db; - + private readonly SqlSugarRepository _codeGetTemplateRep; private readonly SysCodeGenConfigService _codeGenConfigService; private readonly IViewEngine _viewEngine; private readonly CodeGenOptions _codeGenOptions; public SysCodeGenService(ISqlSugarClient db, + SqlSugarRepository codeGetTemplateRep, SysCodeGenConfigService codeGenConfigService, IViewEngine viewEngine, IOptions codeGenOptions) { _db = db; + this._codeGetTemplateRep = codeGetTemplateRep; _codeGenConfigService = codeGenConfigService; _viewEngine = viewEngine; _codeGenOptions = codeGenOptions.Value; @@ -40,8 +42,8 @@ public class SysCodeGenService : IDynamicApiController, ITransient public async Task> Page(PageCodeGenInput input) { return await _db.Queryable() - .WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableName.Contains(input.TableName.Trim())) - .WhereIF(!string.IsNullOrWhiteSpace(input.BusName), u => u.BusName.Contains(input.BusName.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableName!.Contains(input.TableName.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.BusName), u => u.BusName!.Contains(input.BusName.Trim())) .OrderBy(u => u.Id, OrderByType.Desc) .ToPagedListAsync(input.Page, input.PageSize); } @@ -82,8 +84,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient var codeGen = input.Adapt(); await _db.Updateable(codeGen).ExecuteCommandAsync(); - // 更新配置表 - await _codeGenConfigService.DeleteCodeGenConfig(codeGen.Id); + // 更新配置表 _codeGenConfigService.AddList(GetColumnList(input.Adapt()), codeGen); } @@ -149,7 +150,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient var tableOutputList = new List(); foreach (var item in entityInfos) { - var table = dbTableInfos.FirstOrDefault(u => u.Name.ToLower() == (config.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(item.DbTableName) : item.DbTableName).ToLower()); + var table = dbTableInfos.FirstOrDefault(u => u.Name.ToLower() == (config!.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(item.DbTableName) : item.DbTableName).ToLower()); if (table == null) continue; tableOutputList.Add(new TableOutput { @@ -233,7 +234,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient if (propertyInfo != null) { columnOutput.PropertyName = propertyInfo.Name; - columnOutput.ColumnComment = propertyInfo.GetCustomAttribute().ColumnDescription; + columnOutput.ColumnComment = propertyInfo.GetCustomAttribute()!.ColumnDescription; } else { @@ -258,7 +259,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { - var assemblyName = assembly.GetName().Name; + var assemblyName = assembly.GetName().Name!; if (_codeGenOptions.EntityAssemblyNames.Contains(assemblyName) || _codeGenOptions.EntityAssemblyNames.Any(name => assemblyName.Contains(name))) { Assembly asm = Assembly.Load(assemblyName); @@ -313,26 +314,18 @@ public class SysCodeGenService : IDynamicApiController, ITransient } /// - /// 代码生成到本地 🔖 + /// 执行代码生成 🔖 /// /// - [DisplayName("代码生成到本地")] + [DisplayName("执行代码生成")] public async Task RunLocal(SysCodeGen input) { if (string.IsNullOrEmpty(input.GenerateType)) input.GenerateType = "200"; - // 先删除该表已生成的菜单列表 - List targetPathList; - var zipPath = Path.Combine(App.WebHostEnvironment.WebRootPath, "CodeGen", input.TableName); - if (input.GenerateType.StartsWith('1')) - { - targetPathList = GetZipPathList(input); - if (Directory.Exists(zipPath)) - Directory.Delete(zipPath, true); - } - else - targetPathList = GetTargetPathList(input); + string outputPath = Path.Combine(App.WebHostEnvironment.WebRootPath, "CodeGen", input.TableName!); + if (Directory.Exists(outputPath)) + Directory.Delete(outputPath, true); var tableFieldList = await _codeGenConfigService.GetList(new CodeGenConfig() { CodeGenId = input.Id }); // 字段集合 var queryWhetherList = tableFieldList.Where(u => u.QueryWhether == YesNoEnum.Y.ToString()).ToList(); // 前端查询集合 @@ -341,28 +334,29 @@ public class SysCodeGenService : IDynamicApiController, ITransient var data = new CustomViewEngine(_db) { - ConfigId = input.ConfigId, - AuthorName = input.AuthorName, - BusName = input.BusName, - NameSpace = input.NameSpace, - ClassName = input.TableName, - PagePath = input.PagePath, - ProjectLastName = input.NameSpace.Split('.').Last(), + ConfigId = input.ConfigId!, + AuthorName = input.AuthorName!, + BusName = input.BusName!, + NameSpace = input.NameSpace!, + ClassName = input.TableName!, + PagePath = input.PagePath!, + ProjectLastName = input.NameSpace!.Split('.').Last(), QueryWhetherList = queryWhetherList, TableField = tableFieldList, IsJoinTable = joinTableList.Count > 0, IsUpload = joinTableList.Where(u => u.EffectType == "Upload").Any(), - PrintType = input.PrintType, - PrintName = input.PrintName, + PrintType = input.PrintType!, + PrintName = input.PrintName!, IsApiService = input.IsApiService }; - // 模板目录 - var templatePathList = GetTemplatePathList(input); + + // 模板 + var templateList = GetTemplateList(input); var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "template"); - for (var i = 0; i < templatePathList.Count; i++) + for (var i = 0; i < templateList.Count; i++) { - var templateFilePath = Path.Combine(templatePath, templatePathList[i]); + var templateFilePath = Path.Combine(templatePath, templateList[i].Name); if (!File.Exists(templateFilePath)) continue; var tContent = File.ReadAllText(templateFilePath); var tResult = await _viewEngine.RunCompileFromCachedAsync(tContent, data, builderAction: builder => @@ -372,23 +366,43 @@ public class SysCodeGenService : IDynamicApiController, ITransient builder.AddUsing("System.Collections.Generic"); builder.AddUsing("System.Linq"); }); - var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; + + string targetFile = templateList[i].OutputFile + .Replace("{TableName}", input.TableName) + .Replace("{TableNameLower}", input.TableName!.ToLower()); + + string tmpPath; + if (!input.GenerateType.StartsWith('1')) + { + if (templateList[i].Type == CodeGenTypeEnum.Frontend) + tmpPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent!.Parent!.FullName, _codeGenOptions.FrontRootPath, "src"); + else + tmpPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent!.FullName, input.NameSpace); + } + else + { + tmpPath = templateList[i].Type == CodeGenTypeEnum.Frontend ? Path.Combine(outputPath, _codeGenOptions.FrontRootPath, "src") : Path.Combine(outputPath, input!.NameSpace!); + } + targetFile = Path.Combine( tmpPath, targetFile); + + var dirPath = new DirectoryInfo(targetFile).Parent!.FullName; if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath); - File.WriteAllText(targetPathList[i], tResult, Encoding.UTF8); + File.WriteAllText(targetFile, tResult, Encoding.UTF8); } if (input.GenerateMenu) - await AddMenu(input.TableName, input.BusName, input.MenuPid ?? 0, input.MenuIcon, input.PagePath, tableFieldList); + await AddMenu(input.TableName!, input.BusName!, input.MenuPid ?? 0, input.MenuIcon!, input.PagePath!, tableFieldList); + // 非ZIP压缩返回空 if (!input.GenerateType.StartsWith('1')) return null; else { - string downloadPath = zipPath + ".zip"; + string downloadPath = outputPath + ".zip"; // 判断是否存在同名称文件 if (File.Exists(downloadPath)) File.Delete(downloadPath); - ZipFile.CreateFromDirectory(zipPath, downloadPath); + ZipFile.CreateFromDirectory(outputPath, downloadPath); return new { url = $"{App.HttpContext.Request.Scheme}://{App.HttpContext.Request.Host.Value}/CodeGen/{input.TableName}.zip" }; } } @@ -407,30 +421,30 @@ public class SysCodeGenService : IDynamicApiController, ITransient var data = new CustomViewEngine(_db) { - ConfigId = input.ConfigId, - AuthorName = input.AuthorName, - BusName = input.BusName, - NameSpace = input.NameSpace, - ClassName = input.TableName, - PagePath = input.PagePath, - ProjectLastName = input.NameSpace.Split('.').Last(), + ConfigId = input.ConfigId!, + AuthorName = input.AuthorName!, + BusName = input.BusName!, + NameSpace = input.NameSpace!, + ClassName = input.TableName!, + PagePath = input.PagePath!, + ProjectLastName = input.NameSpace!.Split('.').Last(), QueryWhetherList = queryWhetherList, TableField = tableFieldList, IsJoinTable = joinTableList.Count > 0, IsUpload = joinTableList.Where(u => u.EffectType == "Upload").Any(), - PrintType = input.PrintType, - PrintName = input.PrintName, + PrintType = input.PrintType!, + PrintName = input.PrintName!, IsApiService = input.IsApiService }; // 获取模板文件并替换 - var templatePathList = GetTemplatePathList(); + var templateFileList = GetTemplateFileList(); var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "template"); var result = new Dictionary(); - for (var i = 0; i < templatePathList.Count; i++) + for (var i = 0; i < templateFileList.Count; i++) { - var templateFilePath = Path.Combine(templatePath, templatePathList[i]); + var templateFilePath = Path.Combine(templatePath, templateFileList[i]); if (!File.Exists(templateFilePath)) continue; var tContent = File.ReadAllText(templateFilePath); var tResult = await _viewEngine.RunCompileFromCachedAsync(tContent, data, builderAction: builder => @@ -440,7 +454,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient builder.AddUsing("System.Collections.Generic"); builder.AddUsing("System.Linq"); }); - result.Add(templatePathList[i]?.TrimEnd(".vm"), tResult); + result.Add(templateFileList[i]?.TrimEnd(".vm")!, tResult); } return result; @@ -685,136 +699,47 @@ public class SysCodeGenService : IDynamicApiController, ITransient } /// - /// 获取模板文件路径集合 + /// 获取模板文件集合 /// /// - private static List GetTemplatePathList(SysCodeGen input) + private List GetTemplateList(SysCodeGen input) { - if (input.GenerateType.Substring(1, 1).Contains('1')) + //TODO: 只获取选中的模板 + if (input.GenerateType!.Substring(1, 1).Contains('1')) { - return new() { "index.vue.vm", "editDialog.vue.vm", "manage.js.vm" }; + return _codeGetTemplateRep.AsQueryable() + .Where(u => u.Type == CodeGenTypeEnum.Frontend) + .ToList(); } else if (input.GenerateType.Substring(1, 1).Contains('2')) { - return new() { "Service.cs.vm", "Input.cs.vm", "Output.cs.vm", "Dto.cs.vm" }; + return _codeGetTemplateRep.AsQueryable() + .Where(u => u.Type == CodeGenTypeEnum.Backend) + .ToList(); } else { - return new() { "Service.cs.vm", "Input.cs.vm", "Output.cs.vm", "Dto.cs.vm", "index.vue.vm", "editDialog.vue.vm", "manage.js.vm" }; + return _codeGetTemplateRep.AsQueryable() + .ToList(); } } /// - /// 获取模板文件路径集合 + /// 获取模板文件集合 /// /// - private static List GetTemplatePathList() => new() { "Service.cs.vm", "Input.cs.vm", "Output.cs.vm", "Dto.cs.vm", "index.vue.vm", "editDialog.vue.vm", "manage.js.vm" }; - - /// - /// 设置生成文件路径 - /// - /// - /// - private List GetTargetPathList(SysCodeGen input) + private static List GetTemplateFileList() { - //var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, _codeGenOptions.BackendApplicationNamespace, "Service", input.TableName); - var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, input.NameSpace, "Service", input.TableName); - var servicePath = Path.Combine(backendPath, input.TableName + "Service.cs"); - var inputPath = Path.Combine(backendPath, "Dto", input.TableName + "Input.cs"); - var outputPath = Path.Combine(backendPath, "Dto", input.TableName + "Output.cs"); - var viewPath = Path.Combine(backendPath, "Dto", input.TableName + "Dto.cs"); - var frontendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName, _codeGenOptions.FrontRootPath, "src", "views", input.PagePath); - var indexPath = Path.Combine(frontendPath, input.TableName[..1].ToLower() + input.TableName[1..], "index.vue");// - var formModalPath = Path.Combine(frontendPath, input.TableName[..1].ToLower() + input.TableName[1..], "component", "editDialog.vue"); - var apiJsPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName, _codeGenOptions.FrontRootPath, "src", "api", input.PagePath, input.TableName[..1].ToLower() + input.TableName[1..] + ".ts"); + return new List() + { + "web_views_index.vue.vm", + "web_views_listDialog.vue.vm", + "web_views_editDialog.vue.vm", + "web_api.ts.vm", - if (input.GenerateType.Substring(1, 1).Contains('1')) - { - // 生成到本项目(前端) - return new List() - { - indexPath, - formModalPath, - apiJsPath - }; - } - else if (input.GenerateType.Substring(1, 1).Contains('2')) - { - // 生成到本项目(后端) - return new List() - { - servicePath, - inputPath, - outputPath, - viewPath, - }; - } - else - { - // 前后端同时生成到本项目 - return new List() - { - servicePath, - inputPath, - outputPath, - viewPath, - indexPath, - formModalPath, - apiJsPath - }; - } - } - - /// - /// 设置生成文件路径 - /// - /// - /// - private List GetZipPathList(SysCodeGen input) - { - var zipPath = Path.Combine(App.WebHostEnvironment.WebRootPath, "CodeGen", input.TableName); - - //var backendPath = Path.Combine(zipPath, _codeGenOptions.BackendApplicationNamespace, "Service", input.TableName); - var backendPath = Path.Combine(zipPath, input.NameSpace, "Service", input.TableName); - var servicePath = Path.Combine(backendPath, input.TableName + "Service.cs"); - var inputPath = Path.Combine(backendPath, "Dto", input.TableName + "Input.cs"); - var outputPath = Path.Combine(backendPath, "Dto", input.TableName + "Output.cs"); - var viewPath = Path.Combine(backendPath, "Dto", input.TableName + "Dto.cs"); - var frontendPath = Path.Combine(zipPath, _codeGenOptions.FrontRootPath, "src", "views", input.PagePath); - var indexPath = Path.Combine(frontendPath, input.TableName[..1].ToLower() + input.TableName[1..], "index.vue"); - var formModalPath = Path.Combine(frontendPath, input.TableName[..1].ToLower() + input.TableName[1..], "component", "editDialog.vue"); - var apiJsPath = Path.Combine(zipPath, _codeGenOptions.FrontRootPath, "src", "api", input.PagePath, input.TableName[..1].ToLower() + input.TableName[1..] + ".ts"); - if (input.GenerateType.StartsWith("11")) - { - return new List() - { - indexPath, - formModalPath, - apiJsPath - }; - } - else if (input.GenerateType.StartsWith("12")) - { - return new List() - { - servicePath, - inputPath, - outputPath, - viewPath - }; - } - else - { - return new List() - { - servicePath, - inputPath, - outputPath, - viewPath, - indexPath, - formModalPath, - apiJsPath - }; - } + "service_Service.cs.vm", + "service_InputDto.cs.vm", + "service_OutputDto.cs.vm", + }; } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Util/BaseInput.cs b/Admin.NET/Admin.NET.Core/Util/BaseInput.cs new file mode 100644 index 00000000..df81c995 --- /dev/null +++ b/Admin.NET/Admin.NET.Core/Util/BaseInput.cs @@ -0,0 +1,71 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Core; + +/// +/// 主键Id输入参数 +/// +public class BaseIdInput +{ + /// + /// 主键Id + /// + [Required(ErrorMessage = "Id不能为空")] + [DataValidation(ValidationTypes.Numeric)] + public virtual long Id { get; set; } +} + +/// +/// Code +/// +public class CodeInput +{ + /// + /// Code + /// + /// + [Required(ErrorMessage = "Code不能为空"), MinLength(10, ErrorMessage = "Code错误")] + public string Code { get; set; } +} + +/// +/// OpenId +/// +public class OpenIdInputDto //: WechatUserLogin +{ + /// + /// OpenId + /// + /// + [Required(ErrorMessage = "微信标识不能为空"), MinLength(10, ErrorMessage = "微信标识长错误")] + public string OpenId { get; set; } +} + +/// +/// Url +/// +public class UrlInput //: SignatureInput +{ + /// + /// Url + /// + public string Url { get; set; } +} + +/// +/// Phone +/// +public class PhoneInput +{ + /// + /// 手机号码 + /// + /// 13980134216 + [Required(ErrorMessage = "手机号码不能为空")] + [DataValidation(ValidationTypes.PhoneNumber, ErrorMessage = "手机号码不正确")] + public string Phone { get; set; } +} \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Util/BaseOutput.cs b/Admin.NET/Admin.NET.Core/Util/BaseOutput.cs new file mode 100644 index 00000000..204c9251 --- /dev/null +++ b/Admin.NET/Admin.NET.Core/Util/BaseOutput.cs @@ -0,0 +1,64 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Core; + +/// +/// BaseOutput +/// +public class BaseOutput +{ + /// + /// 创建时间 + /// + public virtual DateTime CreateTime { get; set; } + + /// + /// 更新时间 + /// + public virtual DateTime UpdateTime { get; set; } + + ///// + ///// 创建者Id + ///// + //public virtual long CreateUserId { get; set; } + + ///// + ///// 创建者部门Id + ///// + //public virtual long CreateOrgId { get; set; } + + /// + /// 创建者名称 + /// + public virtual string CreateUserName { get; set; } + + ///// + ///// 修改者Id + ///// + //public virtual long UpdateUserId { get; set; } + + /// + /// 修改者名称 + /// + public virtual string UpdateUserName { get; set; } +} + +/// +/// 标签值输出 +/// +public class LabelValueOutput +{ + /// + /// Label + /// + public string Label { get; set; } + + /// + /// Value + /// + public string Value { get; set; } +} \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Input.cs.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_InputDto.cs.vm similarity index 100% rename from Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Input.cs.vm rename to Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_InputDto.cs.vm diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Output.cs.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_OutputDto.cs.vm similarity index 100% rename from Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Output.cs.vm rename to Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_OutputDto.cs.vm diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Service.cs.vm similarity index 88% rename from Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm rename to Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Service.cs.vm index de3affe8..1f5b30e1 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Service.cs.vm @@ -21,7 +21,7 @@ namespace @Model.NameSpace; /// /// @(@Model.BusName)服务 /// -[ApiDescriptionSettings(@(@Model.ProjectLastName)Const.GroupName, Order = 100)] +[ApiDescriptionSettings(@(@Model.ProjectLastName)Const.GroupName, Name = "@(@Model.LowerClassName)", Order = 100)] public class @(@Model.ClassName)Service : IDynamicApiController, ITransient { private readonly SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep; @@ -34,9 +34,8 @@ public class @(@Model.ClassName)Service : IDynamicApiController, ITransient /// 分页查询@(@Model.BusName) /// /// - /// - [HttpPost] - [ApiDescriptionSettings(Name = "Page")] + /// + [ApiDescriptionSettings(Name = "page", Description = "分页查询", Order = 1000), HttpPost] [DisplayName("分页查询@(@Model.BusName)")] public async Task> Page(Page@(@Model.ClassName)Input input) { @@ -117,8 +116,7 @@ if (@column.QueryWhether == "Y"){ /// /// /// - [HttpPost] - [ApiDescriptionSettings(Name = "Add")] + [ApiDescriptionSettings(Name = "add", Description = "增加@(@Model.BusName)", Order = 990), HttpPost] [DisplayName("增加@(@Model.BusName)")] public async Task Add(Add@(@Model.ClassName)Input input) { @@ -132,8 +130,7 @@ if (@column.QueryWhether == "Y"){ /// /// /// - [HttpPost] - [ApiDescriptionSettings(Name = "Delete")] + [ApiDescriptionSettings(Name = "delete", Description = "删除(@Model.BusName)", Order = 980), HttpPost] [DisplayName("删除@(@Model.BusName)")] public async Task Delete(Delete@(@Model.ClassName)Input input) { @@ -151,8 +148,7 @@ if (@column.ColumnKey == "True"){ /// /// /// - [HttpPost] - [ApiDescriptionSettings(Name = "Update")] + [ApiDescriptionSettings(Name = "update", Description = "更新@(@Model.BusName)", Order = 970), HttpPost] [DisplayName("更新@(@Model.BusName)")] public async Task Update(Update@(@Model.ClassName)Input input) { @@ -165,8 +161,7 @@ if (@column.ColumnKey == "True"){ /// /// /// - [HttpGet] - [ApiDescriptionSettings(Name = "Detail")] + [ApiDescriptionSettings(Name = "detail", Description = "获取@(@Model.BusName)", Order = 960), HttpGet] [DisplayName("获取@(@Model.BusName)")] public async Task<@(@Model.ClassName)> Detail([FromQuery] QueryById@(@Model.ClassName)Input input) { @@ -182,8 +177,7 @@ if (@column.ColumnKey == "True"){ /// /// /// - [HttpGet] - [ApiDescriptionSettings(Name = "List")] + [ApiDescriptionSettings(Name = "list", Description = "获取@(@Model.BusName)列表", Order = 950), HttpGet] [DisplayName("获取@(@Model.BusName)列表")] public async Task> List([FromQuery] Page@(@Model.ClassName)Input input) { @@ -196,15 +190,15 @@ if(@column.EffectType == "fk" && (@column.WhetherAddUpdate == "Y" || column.Quer @:/// 获取@(@column.ColumnComment)列表 @:/// @:/// - @:[ApiDescriptionSettings(Name = "@(@column.FkEntityName)@(@column.PropertyName)Dropdown"), HttpGet] + @:[ApiDescriptionSettings(Name = "@(@column.FkEntityName)@(@column.PropertyName)Dropdown", Description = "获取@(@column.ColumnComment)列表"), HttpGet] @:[DisplayName("获取@(@column.ColumnComment)列表")] - @:public async Task @(@column.FkEntityName)@(@column.PropertyName)Dropdown() + @:public async Task> @(@column.FkEntityName)@(@column.PropertyName)Dropdown() @:{ @:return await _@(@Model.LowerClassName)Rep.Context.Queryable<@(@column.FkEntityName)>() - @:.Select(u => new + @:.Select(u => new LabelValueOutput @:{ @:Label = u.@(@column.FkColumnName), - @:Value = u.@(@column.FkLinkColumnName) + @:Value = u.@(@column.FkLinkColumnName).ToString() @:} @:).ToListAsync(); @:} @@ -218,7 +212,7 @@ if(@column.EffectType == "Upload"){ @:/// @:/// @:/// - @:[ApiDescriptionSettings(Name = "Upload@(@column.PropertyName)"), HttpPost] + @:[ApiDescriptionSettings(Name = "Upload@(@column.PropertyName)", Description = "上传@(@column.ColumnComment)", HttpPost] @:[DisplayName("上传@(@column.ColumnComment)")] @:public async Task Upload@(@column.PropertyName)([Required] IFormFile file) @:{ @@ -228,11 +222,10 @@ if(@column.EffectType == "Upload"){ } } - @foreach (var column in Model.TableField){ if(@column.EffectType == "ApiTreeSelect" && !definedObjects.ContainsKey("@(@column.FkEntityName)Tree")){ - @{definedObjects.Add("@(@column.FkEntityName)Tree", 1);} - @:[HttpGet("@(@column.FkEntityName)Tree")] + @{definedObjects.Add("@(@column.FkEntityName)Tree", 1);} + @:[ApiDescriptionSettings(Name = ""@(@column.FkEntityName)Tree"", Description = "获取@(@column.ColumnComment)列表", HttpGet] @:[DisplayName("获取@(@column.FkEntityName)Tree")] @:public async Task @(@column.FkEntityName)Tree() @:{ @@ -240,5 +233,4 @@ if(@column.EffectType == "ApiTreeSelect" && !definedObjects.ContainsKey("@(@colu @:} } } - } diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Manage.js.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_api.ts.vm similarity index 100% rename from Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Manage.js.vm rename to Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_api.ts.vm diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/editDialog.vue.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_editDialog.vue.vm similarity index 54% rename from Admin.NET/Admin.NET.Web.Entry/wwwroot/template/editDialog.vue.vm rename to Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_editDialog.vue.vm index 5308fa53..2d36b5cd 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/editDialog.vue.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_editDialog.vue.vm @@ -6,7 +6,7 @@ @@ -23,12 +23,9 @@ @: @: @: - @: - @: - - @: + @: + - @: }else if(@column.EffectType == "ApiTreeSelect"){ @: @@ -46,71 +43,53 @@ ({{ data.children.length }}) - @: - @: }else if(@column.EffectType == "Input"){ @: @: @: - @: - @: }else if(@column.EffectType == "InputNumber"){ @: @: @: - @: - @: }else if(@column.EffectType == "InputTextArea"){ @: @: @: - @: - @: }else if(@column.EffectType == "Select"){ @: @: @: @: - @: - @: - @: }else if(@column.EffectType == "ConstSelector"){ @: @: @: @:{{ item.name }} - @: - @: - @: }else if(@column.EffectType == "Switch"){ @: @: @: - @: - @: }else if(@column.EffectType == "DatePicker"){ @: @: @: - @: - @: }else if(@column.EffectType == "Upload"){ @: @@ -125,25 +104,18 @@ @:@@click="state.ruleForm.@(@column.LowerPropertyName)=''" @:style="width: 100%; height: 100%; object-fit: contain"/> @: - @: - @: - @: }else if(@column.EffectType == "EnumSelector"){ @: @: @: @: - @: - @: - @: }else{ - } } } @@ -159,205 +131,215 @@ + + - - - @{ string LowerFirstLetter(string text) { diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/index.vue.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_index.vue.vm similarity index 97% rename from Admin.NET/Admin.NET.Web.Entry/wwwroot/template/index.vue.vm rename to Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_index.vue.vm index 8750a9fc..26aac671 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/index.vue.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_index.vue.vm @@ -228,7 +228,7 @@ import ModifyRecord from '/@@/components/table/modifyRecord.vue'; @:import { page@(@Model.ClassName), delete@(@Model.ClassName) } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; foreach (var column in Model.QueryWhetherList){ if(@column.EffectType == "fk"){ - @:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; +@:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; } } } @@ -266,7 +266,11 @@ const changeAdvanceQueryUI = () => { }; // 表格参数配置 -const options = useVxeTable<@(@Model.ClassName)>( +@if (@Model.IsApiService) { +@:const options = useVxeTable<@(@Model.ClassName)>( +} else { +@:const options = useVxeTable( +} { id: '@(@Model.ClassName)', name: '@(@Model.BusName)', @@ -401,7 +405,11 @@ const handleDelete = (row: any) => { }; // 表格事件 -const gridEvents: VxeGridListeners<@(@Model.ClassName)> = { +@if (@Model.IsApiService) { +@:const gridEvents: VxeGridListeners<@(@Model.ClassName)> = { +} else { +@:const gridEvents: VxeGridListeners = { +} // 只对 pager-config 配置时有效,分页发生改变时会触发该事件 async pageChange({ pageSize }) { state.localPageParam.pageSize = pageSize; @@ -418,8 +426,11 @@ const gridEvents: VxeGridListeners<@(@Model.ClassName)> = { @if(@column.EffectType == "fk") { @:const @LowerFirstLetter(@column.FkEntityName)@(@column.PropertyName)DropdownList = ref([]); @:const get@(@column.FkEntityName)@(@column.PropertyName)DropdownList = async () => { - //@:let list = await get@(@column.FkEntityName)@(@column.PropertyName)Dropdown(); + @if (@Model.IsApiService) { @:let list = await getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)@(@column.FkEntityName)@(@column.PropertyName)DropdownGet(); + } else { + @:let list = await get@(@column.FkEntityName)@(@column.PropertyName)Dropdown(); + } @:@LowerFirstLetter(@column.FkEntityName)@(@column.PropertyName)DropdownList.value = list.data.result ?? []; @:}; @:get@(@column.FkEntityName)@(@column.PropertyName)DropdownList(); diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_listDialog.vue.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_listDialog.vue.vm new file mode 100644 index 00000000..1e8acf74 --- /dev/null +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/template/web_views_listDialog.vue.vm @@ -0,0 +1,465 @@ +@{ + string LowerFirstLetter(string text) + { + return text.ToString()[..1].ToLower() + text[1..]; // 首字母小写 + } + var pkField = Model.TableField.Where(c => c.ColumnKey == "True").FirstOrDefault(); + string pkFieldName = null; + if(pkField != null && !string.IsNullOrEmpty(pkField.PropertyName)) + { + pkFieldName = LowerFirstLetter(pkField.PropertyName); + } + Dictionary definedObjects = new Dictionary(); + bool haveLikeCdt = false; + foreach (var column in Model.TableField){ + if (column.QueryWhether == "Y" && column.QueryType == "like"){ + haveLikeCdt = true; + } + } +} + + + + +