using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Loader; using System.Text; using System.Threading.Tasks; using Infrastructure; using Infrastructure.Extensions; using Infrastructure.Helpers; using Infrastructure.Utilities; using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.Options; using OpenAuth.App.Interface; using OpenAuth.App.Request; using OpenAuth.App.Response; using OpenAuth.Repository; using OpenAuth.Repository.Core; using OpenAuth.Repository.Domain; using OpenAuth.Repository.Interface; namespace OpenAuth.App { public class BuilderTableApp : BaseStringApp { private BuilderTableColumnApp _builderTableColumnApp; private CategoryApp _categoryApp; private DbExtension _dbExtension; private string _webProject = null; private string _apiNameSpace = null; private string _startName = ""; private IOptions _appConfiguration; public BuilderTableApp(IUnitWork unitWork, IRepository repository, RevelanceManagerApp app, IAuth auth, DbExtension dbExtension, BuilderTableColumnApp builderTableColumnApp, IOptions appConfiguration, CategoryApp categoryApp) : base(unitWork, repository, auth) { _dbExtension = dbExtension; _builderTableColumnApp = builderTableColumnApp; _appConfiguration = appConfiguration; _categoryApp = categoryApp; } private string StratName { get { if (_startName == "") { _startName = WebProject.Substring(0, _webProject.IndexOf('.')); } return _startName; } } private string WebProject { get { if (_webProject != null) return _webProject; _webProject = ProjectPath.GetLastIndexOfDirectoryName(".WebApi") ?? ProjectPath.GetLastIndexOfDirectoryName("Api") ?? ProjectPath.GetLastIndexOfDirectoryName(".Mvc"); if (_webProject == null) { throw new Exception("未获取到以.WebApi结尾的项目名称,无法创建页面"); } return _webProject; } } /// /// 加载列表 /// public async Task> Load(QueryBuilderTableListReq request) { var loginContext = _auth.GetCurrentUser(); if (loginContext == null) { throw new CommonException("登录已过期", Define.INVALID_TOKEN); } var result = new TableResp(); var objs = UnitWork.Find(null); if (!string.IsNullOrEmpty(request.key)) { objs = objs.Where(u => u.Id.Contains(request.key)); } result.data = objs.OrderBy(u => u.Id) .Skip((request.page - 1) * request.limit) .Take(request.limit).ToList(); result.count = objs.Count(); return result; } public string Add(AddOrUpdateBuilderTableReq req) { if (string.IsNullOrEmpty(req.TableName)) { throw new Exception("英文表名不能为空"); } if (string.IsNullOrEmpty(req.ModuleName)) { throw new Exception("模块名称不能为空"); } if (string.IsNullOrEmpty(req.Namespace)) { throw new Exception("命名空间不能为空"); } var columns = _dbExtension.GetDbTableStructure(req.TableName); if (!columns.Any()) { throw new Exception($"未能找到{req.TableName}表结构定义"); } var obj = req.MapTo(); if (string.IsNullOrEmpty(obj.ClassName)) obj.ClassName = obj.TableName; if (string.IsNullOrEmpty(obj.ModuleCode)) obj.ModuleCode = obj.TableName; //todo:补充或调整自己需要的字段 obj.CreateTime = DateTime.Now; var user = _auth.GetCurrentUser().User; obj.CreateUserId = user.Id; obj.CreateUserName = user.Name; UnitWork.Add(obj); foreach (var column in columns) { var builderColumn = new BuilderTableColumn { ColumnName = column.ColumnName, Comment = column.Comment, ColumnType = column.ColumnType, EntityType = column.EntityType, EntityName = column.ColumnName, IsKey = column.IsKey == 1, IsRequired = column.IsNull != 1, IsEdit = true, IsInsert = true, IsList = true, MaxLength = column.MaxLength, TableName = obj.TableName, TableId = obj.Id, CreateUserId = user.Id, CreateUserName = user.Name, CreateTime = DateTime.Now }; UnitWork.Add(builderColumn); } UnitWork.Save(); return obj.Id; } public void Update(AddOrUpdateBuilderTableReq obj) { var user = _auth.GetCurrentUser().User; UnitWork.Update(u => u.Id == obj.Id, u => new BuilderTable { TableName = obj.TableName, Comment = obj.Comment, DetailTableName = obj.DetailTableName, DetailComment = obj.DetailComment, ClassName = obj.ClassName, Namespace = obj.Namespace, ModuleCode = obj.ModuleCode, ModuleName = obj.ModuleName, Folder = obj.Folder, Options = obj.Options, TypeId = obj.TypeId, TypeName = obj.TypeName, UpdateTime = DateTime.Now, UpdateUserId = user.Id, UpdateUserName = user.Name //todo:补充或调整自己需要的字段 }); } /// /// 删除头和字段明细 /// /// public void DelTableAndcolumns(string[] ids) { UnitWork.ExecuteWithTransaction(() => { UnitWork.Delete(u => ids.Contains(u.Id)); UnitWork.Delete(u => ids.Contains(u.TableId)); UnitWork.Save(); }); } /// /// 生成实体Model /// /// public void CreateEntity(CreateEntityReq req) { var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id); var tableColumns = _builderTableColumnApp.Find(req.Id); if (sysTableInfo == null || tableColumns == null || tableColumns.Count == 0) throw new Exception("未能找到正确的模版信息"); CheckExistsModule(sysTableInfo.ClassName); CreateEntityModel(tableColumns, sysTableInfo); } /// /// 创建业务逻辑层 /// /// public void CreateBusiness(CreateBusiReq req) { var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id); var tableColumns = _builderTableColumnApp.Find(req.Id); if (sysTableInfo == null || tableColumns == null || tableColumns.Count == 0) throw new Exception("未能找到正确的模版信息"); //生成应用层 GenerateApp(sysTableInfo,tableColumns); //生成应用层的请求参数 GenerateAppReq(sysTableInfo, tableColumns); //生成WebApI接口 GenerateWebApi(sysTableInfo, tableColumns); } /// /// 创建应用层 /// /// /// private void GenerateApp(BuilderTable sysTableInfo, List sysColumns) { string appRootPath = ProjectPath.GetProjectDirectoryInfo() .GetDirectories().FirstOrDefault(x => x.Name.ToLower().EndsWith(".app"))?.FullName; if (string.IsNullOrEmpty(appRootPath)) { throw new Exception("未找到openauth.app类库,请确认是否存在"); } CheckExistsModule(sysTableInfo.ModuleCode); string domainContent = FileHelper.ReadFile(@"Template\\BuildApp.html"); domainContent = domainContent .Replace("{TableName}", sysTableInfo.TableName) .Replace("{ModuleCode}", sysTableInfo.ModuleCode) .Replace("{ModuleName}", sysTableInfo.ModuleName) .Replace("{ClassName}", sysTableInfo.ClassName) .Replace("{StartName}", StratName); var primarykey = sysColumns.FirstOrDefault(u => u.IsKey); if (primarykey == null) { throw new Exception($"未能找到表{sysTableInfo.TableName}的主键字段"); } if (primarykey.ColumnType == "decimal" || primarykey.ColumnType == "numberic") //是否为数字 { if(primarykey.IsIncrement) //是否自增 { domainContent = domainContent.Replace("{BaseAppName}", "BaseIntAutoGenApp"); } else //普通的雪花算法生成id { domainContent = domainContent.Replace("{BaseAppName}", "BaseLongApp"); } } else { domainContent = domainContent.Replace("{BaseAppName}", "BaseStringApp"); } FileHelper.WriteFile($"{appRootPath}\\{sysTableInfo.ModuleCode}", $"{sysTableInfo.ModuleCode}.cs", domainContent); } /// /// 生成APP层的请求参数 /// /// /// private void GenerateAppReq(BuilderTable sysTableInfo, List tableColumns) { string appRootPath = ProjectPath.GetProjectDirectoryInfo() .GetDirectories().FirstOrDefault(x => x.Name.ToLower().EndsWith(".app"))?.FullName; if (string.IsNullOrEmpty(appRootPath)) { throw new Exception("未找到openauth.app类库,请确认是否存在"); } string domainContent; domainContent = FileHelper.ReadFile(@"Template\\BuildQueryReq.html") .Replace("{TableName}", sysTableInfo.TableName) .Replace("{ModuleCode}", sysTableInfo.ModuleCode) .Replace("{ModuleName}", sysTableInfo.ModuleName) .Replace("{ClassName}", sysTableInfo.ClassName) .Replace("{StartName}", StratName); FileHelper.WriteFile(Path.Combine(appRootPath, $"{sysTableInfo.ModuleCode}\\Request"), $"Query{sysTableInfo.ClassName}ListReq.cs", domainContent); domainContent = FileHelper.ReadFile(@"Template\\BuildUpdateReq.html"); StringBuilder attributeBuilder = new StringBuilder(); var sysColumn = tableColumns.OrderByDescending(c => c.Sort).ToList(); foreach (BuilderTableColumn column in sysColumn) { attributeBuilder.Append("/// "); attributeBuilder.Append("\r\n"); attributeBuilder.Append(" ///" + column.Comment + ""); attributeBuilder.Append("\r\n"); attributeBuilder.Append(" /// "); attributeBuilder.Append("\r\n"); string entityType = column.EntityType; if (!column.IsRequired && column.EntityType != "string") { entityType = entityType + "?"; } attributeBuilder.Append(" public " + entityType + " " + column.EntityName + " { get; set; }"); attributeBuilder.Append("\r\n\r\n "); } domainContent = domainContent.Replace("{ClassName}", sysTableInfo.ClassName) .Replace("{AttributeList}", attributeBuilder.ToString()); var tableAttr = new StringBuilder(); tableAttr.Append("/// "); tableAttr.Append("\r\n"); tableAttr.Append(" ///" + sysTableInfo.Comment + ""); tableAttr.Append("\r\n"); tableAttr.Append(" /// "); tableAttr.Append("\r\n"); domainContent = domainContent.Replace("{AttributeManager}", tableAttr.ToString()); FileHelper.WriteFile(Path.Combine(appRootPath, $"{sysTableInfo.ModuleCode}\\Request"), $"AddOrUpdate{sysTableInfo.ClassName}Req.cs", domainContent); } /// /// 创建WebAPI接口 /// /// /// private void GenerateWebApi(BuilderTable sysTableInfo, List sysColumns) { string domainContent; string apiPath = ProjectPath.GetProjectDirectoryInfo() .GetDirectories().FirstOrDefault(x => x.Name.ToLower().EndsWith(".webapi"))?.FullName; if (string.IsNullOrEmpty(apiPath)) { throw new Exception("未找到webapi类库,请确认是存在weiapi类库命名以.webapi结尾"); } var controllerName = sysTableInfo.ClassName + "sController"; CheckExistsModule(controllerName); //单元测试下无效,因为没有执行webapi项目 var controllerPath = apiPath + $"\\Controllers\\"; domainContent = FileHelper.ReadFile(@"Template\\BuildControllerApi.html") .Replace("{TableName}", sysTableInfo.TableName) .Replace("{ModuleCode}", sysTableInfo.ModuleCode) .Replace("{ModuleName}", sysTableInfo.ModuleName) .Replace("{ClassName}", sysTableInfo.ClassName) .Replace("{StartName}", StratName); var primarykey = sysColumns.FirstOrDefault(u => u.IsKey); if (primarykey == null) { throw new Exception($"未能找到表{sysTableInfo.TableName}的主键字段"); } if (primarykey.ColumnType == "decimal" || primarykey.ColumnType == "numberic") //是否为数字 { if(primarykey.IsIncrement) //是否自增 { domainContent = domainContent.Replace("{KeyTypeName}", "int"); } else //普通的雪花算法生成id { domainContent = domainContent.Replace("{KeyTypeName}", "long"); } } else { domainContent = domainContent.Replace("{KeyTypeName}", "string"); } FileHelper.WriteFile(controllerPath, controllerName + ".cs", domainContent); } /// /// 创建实体 /// /// /// private void CreateEntityModel(List sysColumns, BuilderTable tableInfo) { string template = "BuildEntity.html"; string domainContent = FileHelper.ReadFile("Template\\" + template); StringBuilder attributeBuilder = new StringBuilder(); StringBuilder constructionBuilder = new StringBuilder(); //生成构造函数初始化值 sysColumns = sysColumns.OrderByDescending(c => c.Sort).ToList(); foreach (BuilderTableColumn column in sysColumns) { if (column.IsKey) continue; attributeBuilder.Append("/// "); attributeBuilder.Append("\r\n"); attributeBuilder.Append(" ///" + column.Comment + ""); attributeBuilder.Append("\r\n"); attributeBuilder.Append(" /// "); attributeBuilder.Append("\r\n"); attributeBuilder.Append(" [Description(\""+ column.Comment +"\")]"); attributeBuilder.Append("\r\n"); string entityType = column.EntityType; if (!column.IsRequired && column.EntityType != "string") { entityType = entityType + "?"; } attributeBuilder.Append(" public " + entityType + " " + column.EntityName + " { get; set; }"); attributeBuilder.Append("\r\n\r\n "); constructionBuilder.Append(" this." + column.EntityName + "=" + (GetDefault(column.EntityType)??"\"\"") + ";\r\n"); } //获取的是本地开发代码所在目录,不是发布后的目录 string mapPath = ProjectPath.GetProjectDirectoryInfo()?.FullName; //new DirectoryInfo(("~/").MapPath()).Parent.FullName; if (string.IsNullOrEmpty(mapPath)) { throw new Exception("未找到生成的目录!"); } var primarykey = sysColumns.FirstOrDefault(u => u.IsKey); if (primarykey == null) { throw new Exception($"未能找到表{tableInfo.TableName}的主键字段"); } if (primarykey.ColumnType == "decimal" || primarykey.ColumnType == "numberic") //是否为数字 { if(primarykey.IsIncrement) //是否自增 { domainContent = domainContent.Replace("{BaseEntityName}", "IntAutoGenEntity"); } else //普通的雪花算法生成id { domainContent = domainContent.Replace("{BaseEntityName}", "LongEntity"); } } else { domainContent = domainContent.Replace("{BaseEntityName}", "StringEntity"); } domainContent = domainContent.Replace("{ClassName}", tableInfo.ClassName) .Replace("{AttributeList}", attributeBuilder.ToString()) .Replace("{Construction}", constructionBuilder.ToString()); var tableAttr = new StringBuilder(); tableAttr.Append("/// "); tableAttr.Append("\r\n"); tableAttr.Append(" ///" + tableInfo.Comment + ""); tableAttr.Append("\r\n"); tableAttr.Append(" /// "); tableAttr.Append("\r\n"); tableAttr.Append(" [Table(\"" + tableInfo.TableName + "\")]"); domainContent = domainContent.Replace("{AttributeManager}", tableAttr.ToString()); FileHelper.WriteFile( mapPath + $"\\OpenAuth.Repository\\Domain\\", tableInfo.ClassName + ".cs", domainContent); string openAuthDBContextPath = mapPath + "\\OpenAuth.Repository\\OpenAuthDBContext.cs"; FileHelper.RegxAddContentByParenthesis(openAuthDBContextPath, "public virtual DbSet<" + tableInfo.ClassName + "> " + tableInfo.TableName + "s { get; set; }"); } Dictionary PrimitiveTypes = new Dictionary() { {"int", typeof(int)} ,{"long", typeof(long)} ,{"string", typeof(string)} ,{"bool", typeof(bool)} ,{"byte", typeof(byte)} ,{"char", typeof(char)} ,{"decimal", typeof(decimal)} ,{"double", typeof(double)} ,{"DateTime", typeof(DateTime)} }; string? GetDefault(string type) { Type t = PrimitiveTypes[type]; if (t == null) { return null; } if (t.IsValueType) { if (type == "DateTime") { return "DateTime.Now"; } return Activator.CreateInstance(t).ToString(); } return null; } /// /// 校验模块是否已经存在 /// /// /// /// public void CheckExistsModule(string moduleCode) { //如果是第一次创建model,此处反射获取到的是已经缓存过的文件,必须重新运行项目否则新增的文件无法做判断文件是否创建,需要重新做反射实际文件,待修改... var compilationLibrary = DependencyContext .Default .CompileLibraries .Where(x => !x.Serviceable && x.Type == "project"); foreach (var compilation in compilationLibrary) { var types = AssemblyLoadContext.Default .LoadFromAssemblyName(new AssemblyName(compilation.Name)) .GetTypes().Where(x => x.GetTypeInfo().BaseType != null && x.BaseType == typeof(StringEntity)); foreach (var entity in types) { if (entity.Name == moduleCode ) throw new Exception($"实际表名【{moduleCode}】已创建实体,不能创建实体"); if (entity.Name != moduleCode) { var tableAttr = entity.GetCustomAttribute(); if (tableAttr != null && tableAttr.Name == moduleCode) { throw new Exception( $"实际表名【{moduleCode}】已被创建建实体,不能创建"); } } } } } /// /// 创建vue界面 /// /// /// public void CreateVue(CreateVueReq req) { if (string.IsNullOrEmpty(req.VueProjRootPath)) { throw new Exception("请提供vue项目的根目录,如:C:\\OpenAuth.Pro\\Client"); } var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id); var tableColumns = _builderTableColumnApp.Find(req.Id); if (sysTableInfo == null || tableColumns == null || tableColumns.Count == 0) throw new Exception("未能找到正确的模版信息"); var domainContent = FileHelper.ReadFile(@"Template\\BuildVue.html"); StringBuilder dialogStrBuilder = new StringBuilder(); //编辑对话框 StringBuilder tempBuilder = new StringBuilder(); //临时类的默认值属性 var syscolums = tableColumns.OrderByDescending(c => c.Sort).ToList(); string[] eidtTye = new string[] { "select", "selectList", "checkbox" }; if (syscolums.Exists(x => eidtTye.Contains(x.EditType) && string.IsNullOrEmpty(x.DataSource))) { throw new Exception($"编辑类型为[{string.Join(',', eidtTye)}]时必须选择数据源"); } foreach (BuilderTableColumn column in syscolums) { if (!column.IsEdit) continue; tempBuilder.Append($" {column.ColumnName.ToCamelCase()}: "); dialogStrBuilder.Append($" =0\">\r\n"); if (column.EditType == "switch") { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"false, //{column.Comment} \r\n"); } else if (column.EditType == "date") { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"'', //{column.Comment} \r\n"); } else if (column.EditType == "datetime") { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"'', //{column.Comment} \r\n"); } else if (column.EditType == "decimal") //小数 { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"0, //{column.Comment} \r\n"); } else if (column.EditType =="number") //整数 { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"0, //{column.Comment} \r\n"); } else if (column.EditType =="textarea") { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"'', //{column.Comment} \r\n"); } else if (column.EditType =="select") { var categories = _categoryApp.LoadByTypeId(column.DataSource); if (categories.IsNullOrEmpty()) { throw new Exception($"未能找到{column.DataSource}对应的值,请在分类管理里面添加"); } dialogStrBuilder.Append($" \r\n"); foreach (var category in categories) { dialogStrBuilder.Append($" \r\n"); } dialogStrBuilder.Append(" \r\n"); tempBuilder.Append($"'', //{column.Comment} \r\n"); } else if (column.EditType =="checkbox") { var categories = _categoryApp.LoadByTypeId(column.DataSource); if (categories.IsNullOrEmpty()) { throw new Exception($"未能找到{column.DataSource}对应的值,请在分类管理里面添加"); } dialogStrBuilder.Append($" \r\n"); foreach (var category in categories) { dialogStrBuilder.Append($" \r\n"); } dialogStrBuilder.Append(" \r\n"); tempBuilder.Append($"[], //{column.Comment} \r\n"); } else { dialogStrBuilder.Append($" \r\n"); tempBuilder.Append($"'', //{column.Comment} \r\n"); } dialogStrBuilder.Append(" \r\n"); dialogStrBuilder.Append("\r\n"); } tempBuilder.Append(" nothing:'' //代码生成时的占位符,看不顺眼可以删除 \r\n"); domainContent = domainContent.Replace("{ClassName}", sysTableInfo.ClassName) .Replace("{TableName}", sysTableInfo.ClassName.ToCamelCase()) .Replace("{Temp}", tempBuilder.ToString()) .Replace("{DialogFormItem}", dialogStrBuilder.ToString()); FileHelper.WriteFile(Path.Combine(req.VueProjRootPath, $"src/views/{sysTableInfo.ClassName.ToLower()}s/"), $"index.vue", domainContent); } /// /// 创建vue接口 /// /// /// public void CreateVueApi(CreateVueReq req) { if (string.IsNullOrEmpty(req.VueProjRootPath)) { throw new Exception("请提供vue项目的根目录,如:C:\\OpenAuth.Pro\\Client"); } var sysTableInfo = Repository.FirstOrDefault(u => u.Id == req.Id); var tableColumns = _builderTableColumnApp.Find(req.Id); if (sysTableInfo == null || tableColumns == null || tableColumns.Count == 0) throw new Exception("未能找到正确的模版信息"); var domainContent = FileHelper.ReadFile(@"Template\\BuildVueApi.html"); domainContent = domainContent.Replace("{TableName}", sysTableInfo.ClassName.ToCamelCase()); FileHelper.WriteFile(Path.Combine(req.VueProjRootPath, $"src/api/"),$"{sysTableInfo.ClassName.ToCamelCase()}s.js", domainContent); } } }