using System.Collections; using System.Data; using System.Text; using JNPF.Common.Configuration; using JNPF.Common.Core.Manager; using JNPF.Common.Core.Manager.Files; using JNPF.Common.Dtos.DataBase; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Security; using JNPF.DatabaseAccessor; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; using JNPF.Systems.Entitys.Dto.Database; using JNPF.Systems.Entitys.Model.DataBase; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.System; using JNPF.ViewEngine; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using SqlSugar; namespace JNPF.Systems; /// /// 数据管理 /// 版 本:V3.2 /// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com) /// 日 期:2021-06-01. /// [ApiDescriptionSettings(Tag = "System", Name = "DataModel", Order = 208)] [Route("api/system/[controller]")] public class DataBaseService : IDynamicApiController, ITransient { /// /// 服务基础仓储. /// public readonly ISqlSugarRepository _repository; /// /// 数据连接服务. /// private readonly IDbLinkService _dbLinkService; /// /// 视图引擎. /// private readonly IViewEngine _viewEngine; /// /// 文件服务. /// private readonly IFileManager _fileManager; /// /// 数据库管理. /// private readonly IDataBaseManager _dataBaseManager; /// /// 用户管理. /// private readonly IUserManager _userManager; /// /// 初始化一个类型的新实例. /// public DataBaseService( ISqlSugarRepository repository, IDbLinkService dbLinkService, IFileManager fileManager, IDataBaseManager dataBaseManager, IUserManager userManager, IViewEngine viewEngine) { _repository = repository; _dbLinkService = dbLinkService; _fileManager = fileManager; _dataBaseManager = dataBaseManager; _userManager = userManager; _viewEngine = viewEngine; } #region GET /// /// 表名列表. /// /// 连接Id. /// 过滤条件. /// [HttpGet("{id}/Tables")] public async Task GetList(string id, [FromQuery] PageInputBase input) { try { var link = await _dbLinkService.GetInfo(id); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var tables = _dataBaseManager.GetTableInfos(tenantLink); tables = tables.Where((x, i) => tables.FindIndex(z => z.Name == x.Name) == i).ToList();//去重 var output = tables.Adapt>(); if (!string.IsNullOrEmpty(input.keyword)) output = output.FindAll(d => d.table.ToLower().Contains(input.keyword.ToLower()) || (d.tableName.IsNotEmptyOrNull() && d.tableName.ToLower().Contains(input.keyword.ToLower()))); return PageResult.SqlSugarPageResult(new SqlSugarPagedList() { list = output.OrderBy(x => x.table).Skip((input.currentPage - 1) * input.pageSize).Take(input.pageSize).OrderBy(x => x.table).ToList(), pagination = new Pagination() { CurrentPage = input.currentPage, PageSize = input.pageSize, Total = output.Count } }); } catch (Exception ex) { return PageResult.SqlSugarPageResult(new SqlSugarPagedList() { list = new List(), pagination = new Pagination() { CurrentPage = input.currentPage, PageSize = input.pageSize, Total = 0 } }); } } /// /// 预览数据. /// /// 请求参数. /// 连接Id. /// 表名. /// [HttpGet("{linkId}/Table/{tableName}/Preview")] public async Task GetData([FromQuery] DatabaseTablePreviewQuery input, string linkId, string tableName) { var link = await _dbLinkService.GetInfo(linkId); if (string.IsNullOrEmpty(tableName)) return new PageResult(); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); StringBuilder dbSql = new StringBuilder(); dbSql.AppendFormat("SELECT * FROM {0} WHERE 1=1", tableName); if (!string.IsNullOrEmpty(input.field) && !string.IsNullOrEmpty(input.keyword)) dbSql.AppendFormat(" AND {0} like '%{1}%'", input.field, input.keyword); return await _dataBaseManager.GetDataTablePage(tenantLink, dbSql.ToString(), input.currentPage, input.pageSize); } /// /// 字段列表. /// /// 连接Id. /// 表名. /// 字段类型. /// [HttpGet("{linkId}/Tables/{tableName}/Fields")] public async Task GetFieldList(string linkId, string tableName, [FromQuery] string type) { var link = await _dbLinkService.GetInfo(linkId); if (string.IsNullOrEmpty(tableName)) return new PageResult(); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var data = _dataBaseManager.GetFieldList(tenantLink, tableName).Adapt>(); if (type.Equals("1")) { data.ForEach(item => { item.field = item.field.ReplaceRegex("^f_", string.Empty).ParseToPascalCase().ToLowerCase(); }); } return new { list = data }; } /// /// 信息. /// /// 连接Id. /// 主键值. /// [HttpGet("{linkId}/Table/{tableName}")] public async Task GetInfo(string linkId, string tableName) { var link = await _dbLinkService.GetInfo(linkId); if (string.IsNullOrEmpty(tableName)) return new PageResult(); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var output = _dataBaseManager.GetDataBaseTableInfo(tenantLink, tableName); output.hasTableData = _dataBaseManager.IsAnyData(tenantLink, tableName); return output; } /// /// 获取数据库表字段下拉框列表(弃用). /// /// 连接Id. /// 表名. /// [HttpGet("{linkId}/Tables/{tableName}/Fields/Selector")] public async Task SelectorData(string linkId, string tableName) { var link = await _dbLinkService.GetInfo(linkId); if (string.IsNullOrEmpty(tableName)) return new PageResult(); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var data = _dataBaseManager.GetDBTableList(tenantLink).FindAll(m => m.table == tableName).Adapt>(); return new { list = data }; } /// /// 导出. /// /// 连接ID. /// 表名称. /// [HttpGet("{linkId}/Table/{tableName}/Action/Export")] public async Task ActionsExport(string linkId, string tableName) { var link = await _dbLinkService.GetInfo(linkId); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var data = _dataBaseManager.GetDataBaseTableInfo(tenantLink, tableName); var jsonStr = data.ToJsonString(); return await _fileManager.Export(jsonStr, data.tableInfo.table, ExportFileType.bdb); } #endregion #region POST /// /// 删除. /// /// 连接Id. /// 表名. /// [HttpDelete("{linkId}/Table/{tableName}")] [UnitOfWork] public async Task Delete(string linkId, string tableName) { if (IsSysTable(tableName)) throw Oops.Oh(ErrorCode.D1504); var link = await _dbLinkService.GetInfo(linkId); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var data = _dataBaseManager.GetData(tenantLink, tableName); if (data.Rows.Count > 0) throw Oops.Oh(ErrorCode.D1508); if (!_dataBaseManager.Delete(tenantLink, tableName)) throw Oops.Oh(ErrorCode.D1500); } /// /// 新建. /// /// 连接Id. /// 请求参数. /// [HttpPost("{linkId}/Table")] [UnitOfWork] public async Task Create(string linkId, [FromBody] DatabaseTableInfoOutput input) { var link = await _dbLinkService.GetInfo(linkId); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); if (_dataBaseManager.IsAnyTable(tenantLink, input.tableInfo.newTable)) throw Oops.Oh(ErrorCode.D1503); if (input.tableInfo.newTable.Length >= 30) throw Oops.Oh(ErrorCode.D1514); if (input.tableFieldList.Any(x => x.field.Length >= 30)) throw Oops.Oh(ErrorCode.D1515); var tableInfo = input.tableInfo.Adapt(); tableInfo.table = input.tableInfo.newTable; var tableFieldList = input.tableFieldList.Adapt>(); if (!await _dataBaseManager.Create(tenantLink, tableInfo, tableFieldList)) throw Oops.Oh(ErrorCode.D1501); } /// /// 更新. /// /// 连接Id. /// 请求参数. /// [HttpPut("{linkId}/Table")] [UnitOfWork] public async Task Update(string linkId, [FromBody] DatabaseTableUpInput input) { var link = await _dbLinkService.GetInfo(linkId); if (input.tableInfo.newTable.Length >= 30) throw Oops.Oh(ErrorCode.D1514); if (input.tableFieldList.Any(x => x.field.Length >= 30)) throw Oops.Oh(ErrorCode.D1515); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); var oldFieldList = _dataBaseManager.GetFieldList(tenantLink, input.tableInfo.table).Adapt>(); oldFieldList = _dataBaseManager.ViewDataTypeConversion(oldFieldList, _dataBaseManager.ToDbType(tenantLink.DbType)); var oldTableInfo = _dataBaseManager.GetTableInfos(tenantLink).Find(m => m.Name == input.tableInfo.table).Adapt(); var data = _dataBaseManager.GetData(tenantLink, input.tableInfo.table); if (data.Rows.Count > 0) throw Oops.Oh(ErrorCode.D1508); var tableInfo = input.tableInfo.Adapt(); tableInfo.table = input.tableInfo.newTable; if (IsSysTable(tableInfo.table)) throw Oops.Oh(ErrorCode.D1504); var tableFieldList = input.tableFieldList.Adapt>(); if (!input.tableInfo.table.Equals(input.tableInfo.newTable) && _dataBaseManager.IsAnyTable(tenantLink, input.tableInfo.newTable)) throw Oops.Oh(ErrorCode.D1503); if (!await _dataBaseManager.Update(tenantLink, input.tableInfo.table, tableInfo, tableFieldList)) { await _dataBaseManager.Create(tenantLink, oldTableInfo, oldFieldList.Adapt>()); throw Oops.Oh(ErrorCode.D1502); } } /// /// 更新. /// /// 连接Id. /// 请求参数. /// [HttpPut("{linkId}/addFields")] [UnitOfWork] public async Task AddFields(string linkId, [FromBody] DatabaseTableUpInput input) { try { if (input.tableFieldList.Any(x => x.field.Length >= 30)) throw Oops.Oh(ErrorCode.D1515); var link = await _dbLinkService.GetInfo(linkId); var tenantLink = link ?? _dataBaseManager.GetTenantDbLink(_userManager.TenantId, _userManager.TenantDbName); _dataBaseManager.AddTableColumn(tenantLink, input.tableInfo.table, input.tableFieldList.Adapt>()); } catch (Exception ex) { throw Oops.Oh(ErrorCode.D1510); } } /// /// 导入. /// /// /// /// [HttpPost("{linkid}/Action/Import")] public async Task ActionsImport(string linkid, IFormFile file) { var fileType = Path.GetExtension(file.FileName).Replace(".", string.Empty); if (!fileType.ToLower().Equals(ExportFileType.bdb.ToString())) throw Oops.Oh(ErrorCode.D3006); var josn = _fileManager.Import(file); var data = josn.ToObject(); if (data == null || data.tableFieldList == null || data.tableInfo == null) throw Oops.Oh(ErrorCode.D3006); data.tableInfo.newTable = data.tableInfo.table; await Create(linkid, data); } /// /// 清除表数据 /// /// 数据库配置主键 /// /// [HttpPost("{linkId}/clean-data")] [AllowAnonymous] public async Task CleanTableData(string linkId, DatabaseTableDataCleanInput input) { ISqlSugarClient? sugarClient = null!; if (linkId == "0") { sugarClient = _repository.AsSugarClient(); } else { var link = await _dbLinkService.GetInfo(linkId); sugarClient = _dataBaseManager.ChangeDataBase(link); } return await sugarClient!.Deleteable().AS(input.TableName).ExecuteCommandAsync(); } /// /// 生成实体类代码 /// /// 数据库配置表主键 /// post输入参数 /// /// /// [HttpPost("{linkId}/gen-code")] public async Task GenerateCode(string linkId, DatabaseTableDataCleanInput input) { if (input.TableName.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(input.TableName)); } if (!input.TableName.Contains("_")) { throw new ArgumentException($"表【{input.TableName}】,表名之间必须包含_"); } ISqlSugarClient sugarClient = _repository.AsSugarClient(); if (linkId != "0") { var link = await _dbLinkService.GetInfo(linkId); sugarClient = _dataBaseManager.ChangeDataBase(link); } List entities = GetDbEntities(sugarClient, input.TableName == "ALL_TABLE" ? null : input.TableName); var tplContent = File.ReadAllText(Path.Combine(App.WebHostEnvironment.WebRootPath, "Template", "Entity.vue.vm")); string sResult = string.Empty; foreach (var item in entities) { sResult = _viewEngine.RunCompileFromCached(tplContent, item); var dir = Path.Combine(FileVariable.GenerateCodePath, item.nsName); Directory.CreateDirectory(dir); File.WriteAllText(Path.Combine(dir, item.clsName + ".cs"), sResult); } return sResult; //var prefix = input.TableName.Split('_')[0]; //var nsName = nsMapper.ContainsKey(prefix) ? nsMapper[prefix] : "Tnb.Entities"; //var dict = GenerateEntityConfig(sugarClient.DbFirst.Where(input.TableName)).ToClassStringList(nsName); //return dict.Count > 0 ? dict.First().Value.Replace("\r\n", "\n") : string.Empty; } #endregion #region PrivateMethod /// /// 是否系统表. /// /// /// private bool IsSysTable(string table) { string[] byoTable = { "base_appdata", "base_authorize", "base_billrule", "base_columnspurview", "base_comfields", "base_datainterface", "base_datainterfacelog", "base_dbbackup", "base_dblink", "base_dictionarydata", "base_dictionarytype", "base_group", "base_imcontent", "base_imreply", "base_message", "base_message_template", "base_messagereceive", "base_module", "base_modulebutton", "base_modulecolumn", "base_moduledataauthorize", "base_moduledataauthorizescheme", "base_moduleform", "base_organize", "base_organize_relation", "base_organizeadministrator", "base_portal", "base_position", "base_printdev", "base_province", "base_role", "base_sms_template", "base_synthirdinfo", "base_sysconfig", "base_syslog", "base_timetask", "base_timetasklog", "base_user", "base_userrelation", "base_visualdev", "base_visualdev_modeldata", "blade_visual", "blade_visual_category", "blade_visual_config", "blade_visual_db", "blade_visual_map", "crm_busines", "crm_businesproduct", "crm_clue", "crm_contract", "crm_contractinvoice", "crm_contractmoney", "crm_contractproduct", "crm_customer", "crm_customercontacts", "crm_followlog", "crm_invoice", "crm_product", "crm_receivable", "ext_bigdata", "ext_document", "ext_documentshare", "ext_emailconfig", "ext_emailreceive", "ext_emailsend", "ext_employee", "ext_order", "ext_orderentry", "ext_orderreceivable", "ext_projectgantt", "ext_schedule", "ext_tableexample", "ext_worklog", "ext_worklogshare", "flow_delegate", "flow_engine", "flow_engineform", "flow_enginevisible", "flow_task", "flow_taskcirculate", "flow_tasknode", "flow_taskoperator", "flow_taskoperatorrecord", "wechat_mpeventcontent", "wechat_mpmaterial", "wechat_mpmessage", "wechat_qydepartment", "wechat_qymessage", "wechat_qyuser", "wform_applybanquet", "wform_applydelivergoods", "wform_applydelivergoodsentry", "wform_applymeeting", "wform_archivalborrow", "wform_articleswarehous", "wform_batchpack", "wform_batchtable", "wform_conbilling", "wform_contractapproval", "wform_contractapprovalsheet", "wform_debitbill", "wform_documentapproval", "wform_documentsigning", "wform_expenseexpenditure", "wform_finishedproduct", "wform_finishedproductentry", "wform_incomerecognition", "wform_leaveapply", "wform_letterservice", "wform_materialrequisition", "wform_materialrequisitionentry", "wform_monthlyreport", "wform_officesupplies", "wform_outboundorder", "wform_outboundorderentry", "wform_outgoingapply", "wform_paydistribution", "wform_paymentapply", "wform_postbatchtab", "wform_procurementmaterial", "wform_procurementmaterialentry", "wform_purchaselist", "wform_purchaselistentry", "wform_quotationapproval", "wform_receiptprocessing", "wform_receiptsign", "wform_rewardpunishment", "wform_salesorder", "wform_salesorderentry", "wform_salessupport", "wform_staffovertime", "wform_supplementcard", "wform_travelapply", "wform_travelreimbursement", "wform_vehicleapply", "wform_violationhandling", "wform_warehousereceipt", "wform_warehousereceiptentry", "wform_workcontactsheet" }; return ((IList)byoTable).Contains(table.ToLower()); } /// /// 获取表条数. /// /// private void GetTableCount(List tableList, DbLinkEntity link) { var _sqlSugarClient = _dataBaseManager.ChangeDataBase(link); foreach (var item in tableList) { try { item.sum = _sqlSugarClient.Queryable().AS(item.table).Count(); } catch (Exception ex) { item.sum = 0; } } } /// /// 生成实体类配置 /// /// /// private IDbFirst GenerateEntityConfig(IDbFirst db) { db.IsCreateAttribute() .StringNullable() .SettingPropertyTemplate((col, tpl, type) => { string sugarColumnStr = ""; List sugarAttrs = new List(); if (col.IsPrimarykey) sugarAttrs.Add("IsPrimaryKey=true"); if (col.IsIdentity) sugarAttrs.Add("IsIdentity=true"); if (sugarAttrs.Count > 0) sugarColumnStr = $"\r\n [SugarColumn({string.Join(", ", sugarAttrs)})]"; var txt = tpl.Replace("{PropertyType}", type).Replace("{PropertyName}", col.DbColumnName).Replace("{SugarColumn}", sugarColumnStr); if (col.DbColumnName == "id") { if (type == "string") txt = txt.TrimEnd('\n', '\r') + " = SnowflakeIdHelper.NextId();\r\n"; else if (type == "long") txt = txt.TrimEnd('\n', '\r') + " = YitIdHelper.NextId();\r\n"; } else if (type == "string") txt = txt.TrimEnd('\n', '\r') + " = string.Empty;\r\n"; return txt; }) .SettingNamespaceTemplate(tpl => tpl + "using JNPF.Common.Security;\r\n"); return db; } private List GetDbEntities(ISqlSugarClient sugar, string? tbName = null) { List entities = new(); Dictionary nsMapper = new() { {"bas_", "Tnb.BasicData.Entities" }, {"prd_", "Tnb.ProductionMgr.Entities" }, {"wms_", "Tnb.WarehouseMgr.Entities" }, {"eqp_", "Tnb.EquipMgr.Entities" }, {"tool_", "Tnb.EquipMgr.Entities" }, {"qc_", "Tnb.QcMgr.Entities" }, {"per_", "Tnb.PerMgr.Entities" }, }; var allTables = sugar.DbMaintenance.GetTableInfoList().WhereIF(!string.IsNullOrEmpty(tbName), t => t.Name == tbName); foreach (var tbl in allTables) { var prefix = tbl.Name.Split('_')[0] + "_"; if (!nsMapper.ContainsKey(prefix)) continue; var entityName = string.Join("", tbl.Name.Split('_').Select(a => a.ToPascal())); //sugar.MappingTables.Add(entityName, tbl.Name); DbEntityInfo model = new() { tableName = tbl.Name, descrip = tbl.Description, clsName = entityName, nsName = nsMapper[prefix] }; foreach (var field in sugar.DbMaintenance.GetColumnInfosByTableName(tbl.Name)) { DbEntityPropInfo col = field.Adapt(); col.csType = sugar.Ado.DbBind.GetPropertyTypeName(field.DataType); col.propName = field.DbColumnName; model.columns.Add(col); } var primaryKey = model.columns.FirstOrDefault(a => a.primaryKey); if (primaryKey != null) { model.pkType = primaryKey.csType; model.pkName = primaryKey.propName; } if (model.pkName == "id") model.ignoreCols.Add(model.pkName); entities.Add(model); } return entities; } #endregion }