using MiaoYu.Repository.Admin.Entities.LowCode; using MiaoYu.Repository.ChatAI.Admin.Entities; using CoreIDatabaseTableService = MiaoYu.Core.CodeGenerator.Services.IDatabaseTableService; using CoreICodeGenerationService = MiaoYu.Core.CodeGenerator.Services.ICodeGenerationService; using CoreDataSourceManager = MiaoYu.Core.CodeGenerator.Core.DataSourceManager; using CoreITableMetaConfigService = MiaoYu.Core.CodeGenerator.Services.ITableMetaConfigService; using CoreITableSchemaCache = MiaoYu.Core.CodeGenerator.Services.ITableSchemaCache; using CoreEntityNamingStrategy = MiaoYu.Core.CodeGenerator.Abstractions.EntityNamingStrategy; using CorePathResolver = MiaoYu.Core.CodeGenerator.Core.PathResolver; namespace MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl; /// /// 服务 Low_Code_TableService /// public class LowCodeTableService : ApplicationService> { private readonly IRepository _lowCodeTableInfoRepository; private readonly LowCodeTableInfoService _lowCodeTableInfoService; private readonly CoreIDatabaseTableService _databaseTableService; private readonly CoreICodeGenerationService _codeGenerationService; private readonly CoreDataSourceManager _dataSourceManager; private readonly CoreITableMetaConfigService _tableMetaConfigService; private readonly CoreITableSchemaCache _tableSchemaCache; private readonly CorePathResolver _pathResolver; public LowCodeTableService( IRepository defaultRepository, LowCodeTableInfoService lowCodeTableInfoService, IRepository lowCodeTableInfoRepository, CoreIDatabaseTableService databaseTableService, CoreICodeGenerationService codeGenerationService, CoreDataSourceManager dataSourceManager, CoreITableMetaConfigService tableMetaConfigService, CoreITableSchemaCache tableSchemaCache, CorePathResolver pathResolver) : base(defaultRepository) { _lowCodeTableInfoService = lowCodeTableInfoService; _lowCodeTableInfoRepository = lowCodeTableInfoRepository; _databaseTableService = databaseTableService; _codeGenerationService = codeGenerationService; _dataSourceManager = dataSourceManager; _tableMetaConfigService = tableMetaConfigService; _tableSchemaCache = tableSchemaCache; _pathResolver = pathResolver; } /// /// 获取列表数据(从 Core 层查询表结构并合并配置) /// /// /// public async Task FindListAsync(PagingSearchInput pagingSearchInput) { // ✅ 从 Core 层获取所有表信息(已包含配置合并) var allTables = _databaseTableService.GetAllTables(); // 应用筛选条件 var filteredTables = allTables.AsEnumerable(); // ✅ 数据库筛选条件(重要:支持多数据源筛选) if (!string.IsNullOrWhiteSpace(pagingSearchInput.Search.DataBase)) { filteredTables = filteredTables.Where(t => t.DataBase == pagingSearchInput.Search.DataBase); } if (!string.IsNullOrWhiteSpace(pagingSearchInput.Search.TableName)) { filteredTables = filteredTables.Where(t => t.TableName != null && t.TableName.Contains(pagingSearchInput.Search.TableName)); } if (!string.IsNullOrWhiteSpace(pagingSearchInput.Search.EntityName)) { filteredTables = filteredTables.Where(t => t.EntityName != null && t.EntityName.Contains(pagingSearchInput.Search.EntityName)); } if (!string.IsNullOrWhiteSpace(pagingSearchInput.Search.DisplayName)) { filteredTables = filteredTables.Where(t => t.DisplayName != null && t.DisplayName.Contains(pagingSearchInput.Search.DisplayName)); } // 排序和分页 var pagedTablesList = filteredTables .Skip((pagingSearchInput.Page - 1) * pagingSearchInput.Size) .Take(pagingSearchInput.Size) .ToList(); // 异步获取 ID 并构建结果 var pagedTables = new List>(); foreach (var t in pagedTablesList) { var id = await GetOrCreateTableId(t.TableName, t.DataBase); pagedTables.Add(new Dictionary { ["id"] = id, ["tableName"] = t.TableName, ["displayName"] = t.DisplayName, ["entityName"] = t.EntityName, ["remark"] = t.Remark, ["lastModificationTime"] = DateTime.Now.ToString("yyyy-MM-dd"), ["creationTime"] = DateTime.Now.ToString("yyyy-MM-dd"), ["dataBase"] = t.DataBase }); } return new PagingView(pagingSearchInput.Page, pagingSearchInput.Size) { Total = filteredTables.Count(), DataSource = pagedTables, PageCount = (filteredTables.Count() + pagingSearchInput.Size - 1) / pagingSearchInput.Size }; } /// /// 获取或创建表的 ID(用于兼容性) /// private async Task GetOrCreateTableId(string? tableName, string? dataBase) { if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(dataBase)) return Guid.NewGuid(); var existingTable = await _defaultRepository.FindAsync(t => t.TableName == tableName && t.DataBase == dataBase); return existingTable?.Id ?? Guid.NewGuid(); } /// /// 根据id数组删除 /// /// /// public async Task DeleteListAsync(List ids) { // 查询要删除的表信息,用于删除配置文件 var tablesToDelete = await _defaultRepository.Select.Where(w => ids.Contains(w.Id)).ToListAsync(); _databaseTableService.ClearAllTablesByCache(); //删除子表 await _lowCodeTableInfoRepository.DeleteAsync(w => ids.Contains(w.Low_Code_TableId)); //删除主表 await _defaultRepository.DeleteByIdsAsync(ids); // 删除对应的配置文件 foreach (var table in tablesToDelete) { if (!string.IsNullOrEmpty(table.DataBase) && !string.IsNullOrEmpty(table.TableName)) { try { await _tableMetaConfigService.DeleteConfigAsync(table.DataBase, table.TableName); } catch (Exception) { // 配置文件可能不存在,忽略异常 } } } } /// /// 同步表(支持多数据源) /// public async Task SynchronizationAsync() { // 刷新表结构缓存(从数据库重新加载表结构) _tableSchemaCache.RefreshCache(); var allTables = _databaseTableService.GetAllTableInfos(); var oldAllTables = await _defaultRepository.ToListAllAsync(); var insertList = new List(); var updateList = new List(); var ids = new List(); foreach (var item in allTables) { // 修复:同时匹配表名和数据库标识,避免多数据源同名表冲突 var table = oldAllTables.Find(w => w.TableName == item.Name && w.DataBase == item.DataBase); var id = Guid.NewGuid(); // 获取数据源提供者 var provider = _dataSourceManager.GetProvider(item.DataBase ?? "Admin"); if (table == null) { var lowCodeTable = new LowCodeTable { Id = id, DisplayName = item.Comment, TableName = item.Name, DataBase = item.DataBase, Schema = item.Schema, // 根据命名策略生成实体名 EntityName = provider?.Config.NamingStrategy == CoreEntityNamingStrategy.KeepOriginal ? item.Name : ConvertToPascalCase(item.Name) }; insertList.Add(lowCodeTable); } else { id = table.Id; table.DataBase = item.DataBase; table.Schema = item.Schema; table.EntityName = provider?.Config.NamingStrategy == CoreEntityNamingStrategy.KeepOriginal ? item.Name : ConvertToPascalCase(item.Name); updateList.Add(table); } ids.Add(id); } if (insertList.Count > 0) { await _defaultRepository.InsertRangeAsync(insertList); } if (updateList.Count > 0) { await _defaultRepository.UpdateRangeAsync(updateList); } // 同步列信息 foreach (var item in ids) { await _lowCodeTableInfoService.SynchronizationColumnByTableIdAsync(item, true); } // 注意:这里不需要清除缓存,因为缓存在开始时已经刷新过了 // 清除缓存会导致下次查询重新加载,没有必要 } /// /// 将下划线命名转换为 PascalCase /// private static string ConvertToPascalCase(string input) { if (string.IsNullOrEmpty(input)) return input; var words = input.Split(new[] { '_', '-' }, StringSplitOptions.RemoveEmptyEntries); var result = new System.Text.StringBuilder(); foreach (var word in words) { if (word.Length > 0) { result.Append(char.ToUpper(word[0])); if (word.Length > 1) { result.Append(word.Substring(1).ToLower()); } } } return result.ToString(); } /// /// 变更数据 /// /// /// public async Task ChangeAsync(List lowCodeTables) { _databaseTableService.ClearAllTablesByCache(); var oldLowCodeTables = await _defaultRepository.ToListAsync(w => lowCodeTables.Select(w => w.Id).Contains(w.Id)); var updateList = new List(); foreach (var item in lowCodeTables) { var lowCodeTable = oldLowCodeTables.Find(w => w.Id == item.Id); lowCodeTable.DisplayName = item.DisplayName; lowCodeTable.EntityName = item.EntityName; lowCodeTable.Remark = item.Remark; updateList.Add(lowCodeTable); } await _defaultRepository.UpdateRangeAsync(updateList); } /// /// 查询表单数据 /// /// /// public async Task> FindFormAsync(Guid id) { var res = new Dictionary(); var form = (await _defaultRepository.FindByIdAsync(id)).NullSafe(); FillPathByLowCodeTable(form); res[nameof(id)] = id == Guid.Empty ? "" : id; res[nameof(form)] = form; res["menu"] = $"views/apps/{form.TableName}s/Index.vue"; res["router"] = $"/apps/{form.TableName.ToLower()}s"; return res; } /// /// 根据 lowCodeTable 填充路径(支持多数据源) /// private void FillPathByLowCodeTable(LowCodeTable lowCodeTable) { var provider = _dataSourceManager.GetProvider(lowCodeTable.DataBase ?? "Admin"); if (provider == null) { return; } if (string.IsNullOrEmpty(lowCodeTable.ModelPath)) lowCodeTable.ModelPath = _pathResolver.ResolvePath(provider.Config.ModelPathTemplate, provider.Config, lowCodeTable.TableName!); if (string.IsNullOrEmpty(lowCodeTable.ServicePath)) lowCodeTable.ServicePath = _pathResolver.ResolvePath(provider.Config.ServicePathTemplate, provider.Config, lowCodeTable.TableName!); if (string.IsNullOrEmpty(lowCodeTable.ControllerPath)) lowCodeTable.ControllerPath = _pathResolver.ResolvePath(provider.Config.ControllerPathTemplate, provider.Config, lowCodeTable.TableName!); if (string.IsNullOrEmpty(lowCodeTable.ClientIndexPath)) lowCodeTable.ClientIndexPath = _pathResolver.ResolvePath(provider.Config.ClientIndexPathTemplate, provider.Config, lowCodeTable.TableName!); if (string.IsNullOrEmpty(lowCodeTable.ClientInfoPath)) lowCodeTable.ClientInfoPath = _pathResolver.ResolvePath(provider.Config.ClientInfoPathTemplate, provider.Config, lowCodeTable.TableName!); if (string.IsNullOrEmpty(lowCodeTable.ClientServicePath)) lowCodeTable.ClientServicePath = _pathResolver.ResolvePath(provider.Config.ClientServicePathTemplate, provider.Config, lowCodeTable.TableName!); } /// /// 保存数据 /// /// /// [Transactional] public virtual async Task SaveFormAsync(LowCodeTable form) { await _defaultRepository.InsertOrUpdateAsync(form); } }