using Microsoft.Extensions.Configuration; using SqlSugar; using System.Text.Json; using YY.Admin.Core; using YY.Admin.Core.Entity; using YY.Admin.Services.Service.Category.Dto; using YY.Admin.Services.Service.Jeecg; namespace YY.Admin.Services.Service.Category; public class JeecgCategorySyncService : IJeecgCategorySyncService, ISingletonDependency { private readonly ISqlSugarClient _dbContext; private readonly IConfiguration _configuration; private readonly IJeecgBackendGateway _jeecgGateway; public JeecgCategorySyncService( ISqlSugarClient dbContext, IConfiguration configuration, IJeecgBackendGateway jeecgGateway) { _dbContext = dbContext; _configuration = configuration; _jeecgGateway = jeecgGateway; } public async Task> PageAsync(PageJeecgCategoryItemInput input) { var name = input.Name; var code = input.Code; var pid = input.Pid; var query = _dbContext.Queryable().ClearFilter() .WhereIF(!string.IsNullOrWhiteSpace(name), x => x.Name != null && x.Name.Contains(name!)) .WhereIF(!string.IsNullOrWhiteSpace(code), x => x.Code != null && x.Code.Contains(code!)) .WhereIF(!string.IsNullOrWhiteSpace(pid), x => x.Pid == pid); query = query.OrderBy(x => SqlFunc.IsNull(x.Code, "")) .OrderBy(x => SqlFunc.IsNull(x.Name, "")) .OrderBy(x => SqlFunc.Desc(x.UpdateTime)); RefAsync total = 0; var list = await query.ToPageListAsync(input.Page, input.PageSize, total); var items = list.Select(x => new JeecgCategoryItemOutput { Id = x.Id, Pid = x.Pid, Name = x.Name, Code = x.Code, HasChild = x.HasChild, CreateTime = x.CreateTime, UpdateTime = x.UpdateTime }).ToList(); return new SqlSugarPagedList { Page = input.Page, PageSize = input.PageSize, Total = total, TotalPages = input.PageSize > 0 ? (int)Math.Ceiling(total / (double)input.PageSize) : 0, HasNextPage = input.PageSize > 0 && input.Page < (int)Math.Ceiling(total / (double)input.PageSize), HasPrevPage = input.Page > 1, Items = items }; } public async Task SyncFromJeecgAsync() { var baseUrl = _configuration.GetValue("JeecgIntegration:BaseUrl")?.TrimEnd('/'); if (string.IsNullOrWhiteSpace(baseUrl)) { return 0; } var queue = new Queue(); var visited = new HashSet(StringComparer.OrdinalIgnoreCase); queue.Enqueue("0"); visited.Add("0"); var synced = 0; while (queue.Count > 0) { var pid = queue.Dequeue(); var requestUrl = $"{baseUrl}/sys/category/anon/childList?pid={Uri.EscapeDataString(pid)}"; var json = await _jeecgGateway.ExecuteGetStringAsync(requestUrl); if (string.IsNullOrWhiteSpace(json)) { continue; } using var doc = JsonDocument.Parse(json); var root = doc.RootElement; if (!(root.TryGetProperty("success", out var successEl) && successEl.GetBoolean())) { continue; } if (!root.TryGetProperty("result", out var listEl) || listEl.ValueKind != JsonValueKind.Array) { continue; } foreach (var row in listEl.EnumerateArray()) { var id = GetString(row, "id"); if (string.IsNullOrWhiteSpace(id)) { continue; } var existing = await _dbContext.Queryable() .ClearFilter() .Where(x => x.Id == id) .FirstAsync(); if (existing == null) { existing = new JeecgSysCategoryItem { Id = id }; } existing.Pid = GetString(row, "pid"); existing.Name = GetString(row, "name"); existing.Code = GetString(row, "code"); existing.HasChild = GetString(row, "hasChild"); existing.CreateBy = GetString(row, "createBy"); existing.CreateTime = GetDateTime(row, "createTime"); existing.UpdateBy = GetString(row, "updateBy"); existing.UpdateTime = GetDateTime(row, "updateTime"); var existsCount = await _dbContext.Queryable() .ClearFilter() .Where(x => x.Id == existing.Id) .CountAsync(); if (existsCount > 0) { await _dbContext.Updateable(existing).ExecuteCommandAsync(); } else { await _dbContext.Insertable(existing).ExecuteCommandAsync(); } synced++; if (existing.HasChild == "1" && !visited.Contains(existing.Id)) { queue.Enqueue(existing.Id); visited.Add(existing.Id); } } } return synced; } public async Task> LoadTreeAsync() { return await BuildLocalTreeAsync(); } private async Task> BuildLocalTreeAsync() { var allItems = await _dbContext.Queryable() .ClearFilter() .ToListAsync(); if (allItems == null || allItems.Count == 0) { return []; } var nodeMap = allItems .Where(x => !string.IsNullOrWhiteSpace(x.Id)) .ToDictionary( x => x.Id, x => new JeecgCategoryTreeNodeDto { Id = x.Id, Pid = x.Pid, Name = x.Name, Code = x.Code }, StringComparer.OrdinalIgnoreCase); var roots = new List(); foreach (var node in nodeMap.Values) { if (string.IsNullOrWhiteSpace(node.Pid) || node.Pid == "0" || !nodeMap.TryGetValue(node.Pid, out var parent)) { roots.Add(node); continue; } parent.Children.Add(node); } SortTreeNodes(roots); return roots; } private static void SortTreeNodes(List nodes) { nodes.Sort((a, b) => { var codeCompare = string.Compare(a.Code, b.Code, StringComparison.OrdinalIgnoreCase); return codeCompare != 0 ? codeCompare : string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase); }); foreach (var node in nodes) { if (node.Children.Count > 0) { SortTreeNodes(node.Children); } } } private static string? GetString(JsonElement row, string propertyName) { if (!row.TryGetProperty(propertyName, out var el)) { return null; } if (el.ValueKind == JsonValueKind.String) { return el.GetString(); } return el.ToString(); } private static DateTime? GetDateTime(JsonElement row, string propertyName) { if (!row.TryGetProperty(propertyName, out var el)) { return null; } if (el.ValueKind == JsonValueKind.String && DateTime.TryParse(el.GetString(), out var dt)) { return dt; } return null; } }