HuanMengAdmin/admin-server/MiaoYu.Api.Admin/ApplicationServices/DevelopmentTools/LowCode/Impl/LowCodeTableService.cs
2025-11-08 04:30:38 +08:00

351 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>
/// 服务 Low_Code_TableService
/// </summary>
public class LowCodeTableService : ApplicationService<IRepository<LowCodeTable>>
{
private readonly IRepository<LowCodeTableInfo> _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<LowCodeTable> defaultRepository,
LowCodeTableInfoService lowCodeTableInfoService,
IRepository<LowCodeTableInfo> 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;
}
/// <summary>
/// 获取列表数据(从 Core 层查询表结构并合并配置)
/// </summary>
/// <param name="pagingSearchInput"></param>
/// <returns></returns>
public async Task<PagingView> FindListAsync(PagingSearchInput<LowCodeTable> 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<Dictionary<string, object?>>();
foreach (var t in pagedTablesList)
{
var id = await GetOrCreateTableId(t.TableName, t.DataBase);
pagedTables.Add(new Dictionary<string, object?>
{
["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
};
}
/// <summary>
/// 获取或创建表的 ID用于兼容性
/// </summary>
private async Task<Guid> 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();
}
/// <summary>
/// 根据id数组删除
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task DeleteListAsync(List<Guid> 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)
{
// 配置文件可能不存在,忽略异常
}
}
}
}
/// <summary>
/// 同步表(支持多数据源)
/// </summary>
public async Task SynchronizationAsync()
{
// 刷新表结构缓存(从数据库重新加载表结构)
_tableSchemaCache.RefreshCache();
var allTables = _databaseTableService.GetAllTableInfos();
var oldAllTables = await _defaultRepository.ToListAllAsync();
var insertList = new List<LowCodeTable>();
var updateList = new List<LowCodeTable>();
var ids = new List<Guid>();
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);
}
// 注意:这里不需要清除缓存,因为缓存在开始时已经刷新过了
// 清除缓存会导致下次查询重新加载,没有必要
}
/// <summary>
/// 将下划线命名转换为 PascalCase
/// </summary>
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();
}
/// <summary>
/// 变更数据
/// </summary>
/// <param name="lowCodeTables"></param>
/// <returns></returns>
public async Task ChangeAsync(List<LowCodeTable> lowCodeTables)
{
_databaseTableService.ClearAllTablesByCache();
var oldLowCodeTables =
await _defaultRepository.ToListAsync(w => lowCodeTables.Select(w => w.Id).Contains(w.Id));
var updateList = new List<LowCodeTable>();
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);
}
/// <summary>
/// 查询表单数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<Dictionary<string, object>> FindFormAsync(Guid id)
{
var res = new Dictionary<string, object>();
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;
}
/// <summary>
/// 根据 lowCodeTable 填充路径(支持多数据源)
/// </summary>
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!);
}
/// <summary>
/// 保存数据
/// </summary>
/// <param name="form"></param>
/// <returns></returns>
[Transactional]
public virtual async Task SaveFormAsync(LowCodeTable form)
{
await _defaultRepository.InsertOrUpdateAsync(form);
}
}