using Microsoft.Extensions.Configuration; using SqlSugar; using System.Text.Json; using YY.Admin.Core.Session; using YY.Admin.Services.Service.Jeecg; namespace YY.Admin.Services.Service.Tenant { public class SysTenantSyncService : ISysTenantSyncService, ISingletonDependency { private readonly ISqlSugarClient _dbContext; private readonly IConfiguration _configuration; private readonly ISysCacheService _sysCacheService; private readonly IJeecgBackendGateway _jeecgGateway; public SysTenantSyncService( ISqlSugarClient dbContext, IConfiguration configuration, ISysCacheService sysCacheService, IJeecgBackendGateway jeecgGateway) { _dbContext = dbContext; _configuration = configuration; _sysCacheService = sysCacheService; _jeecgGateway = jeecgGateway; } public async Task> PageAsync(PageTenantInput input) { var status = input.Status; var statusValue = status.GetValueOrDefault(); var query = _dbContext.Queryable().ClearFilter() .WhereIF(!string.IsNullOrWhiteSpace(input.Name), t => t.Title!.Contains(input.Name!)) .WhereIF(status.HasValue, t => t.Status == statusValue) .OrderBy(t => t.Id); RefAsync total = 0; var list = await query.ToPageListAsync(input.Page, input.PageSize, total); var items = list.Select(t => new TenantOutput { Id = t.Id, Title = t.Title, Logo = t.Logo, Status = t.Status, CreateTime = t.CreateTime, UpdateTime = t.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 userId = AppSession.CurrentUser?.Id; if (!userId.HasValue || userId.Value <= 0) return 0; var tokenKey = $"jeecg:token:{userId.Value}"; var token = _sysCacheService.Get(tokenKey); if (string.IsNullOrWhiteSpace(token)) return 0; var baseUrl = _configuration.GetValue("JeecgIntegration:BaseUrl")?.TrimEnd('/'); if (string.IsNullOrWhiteSpace(baseUrl)) return 0; var tenantListPath = _configuration.GetValue("JeecgIntegration:TenantListPath") ?? "/sys/tenant/list"; var requestUrl = $"{baseUrl}{tenantListPath}?pageNo=1&pageSize=200"; var headers = new Dictionary { ["X-Access-Token"] = token }; var json = await _jeecgGateway.ExecuteGetStringAsync(requestUrl, headers); if (string.IsNullOrWhiteSpace(json)) return 0; using var doc = JsonDocument.Parse(json); var root = doc.RootElement; if (!(root.TryGetProperty("success", out var successEl) && successEl.GetBoolean())) return 0; if (!root.TryGetProperty("result", out var resultEl) || resultEl.ValueKind != JsonValueKind.Object) return 0; if (!resultEl.TryGetProperty("records", out var recordsEl) || recordsEl.ValueKind != JsonValueKind.Array) return 0; var templateTenant = await _dbContext.Queryable().ClearFilter().OrderBy(t => t.Id).FirstAsync(); if (templateTenant == null) return 0; var synced = 0; foreach (var tenantEl in recordsEl.EnumerateArray()) { if (!tenantEl.TryGetProperty("id", out var idEl) || !idEl.TryGetInt64(out var tenantId) || tenantId <= 0) continue; var name = tenantEl.TryGetProperty("name", out var nameEl) ? nameEl.GetString() : null; var logo = tenantEl.TryGetProperty("companyLogo", out var logoEl) ? logoEl.GetString() : null; var status = ResolveTenantStatus(tenantEl); var exists = await _dbContext.Queryable().ClearFilter().Where(t => t.Id == tenantId).AnyAsync(); if (exists) { await _dbContext.Updateable() .SetColumns(t => t.Title == (string.IsNullOrWhiteSpace(name) ? t.Title : name)) .SetColumns(t => t.Logo == logo) .SetColumns(t => t.Status == status) .SetColumns(t => t.UpdateTime == DateTime.Now) .Where(t => t.Id == tenantId) .ExecuteCommandAsync(); } else { var entity = new SysTenant { Id = tenantId, UserId = templateTenant.UserId, OrgId = templateTenant.OrgId, TenantType = templateTenant.TenantType, DbType = templateTenant.DbType, Connection = templateTenant.Connection, ConfigId = templateTenant.ConfigId, SlaveConnections = templateTenant.SlaveConnections, EnableReg = templateTenant.EnableReg, RegWayId = templateTenant.RegWayId, Logo = logo, Title = string.IsNullOrWhiteSpace(name) ? $"租户{tenantId}" : name, ViceTitle = templateTenant.ViceTitle, ViceDesc = templateTenant.ViceDesc, Watermark = templateTenant.Watermark, Copyright = templateTenant.Copyright, Icp = templateTenant.Icp, IcpUrl = templateTenant.IcpUrl, OrderNo = templateTenant.OrderNo, Remark = templateTenant.Remark, Status = status, CreateTime = DateTime.Now, UpdateTime = DateTime.Now }; await _dbContext.Insertable(entity).ExecuteCommandAsync(); } synced++; } return synced; } /// /// 安全解析Jeecg租户状态,避免null或字符串导致异常 /// private static StatusEnum ResolveTenantStatus(JsonElement tenantEl) { if (!tenantEl.TryGetProperty("status", out var statusEl)) { return StatusEnum.Disable; } if (statusEl.ValueKind == JsonValueKind.Number && statusEl.TryGetInt32(out var numStatus)) { return numStatus == 1 ? StatusEnum.Enable : StatusEnum.Disable; } if (statusEl.ValueKind == JsonValueKind.String && int.TryParse(statusEl.GetString(), out var strStatus)) { return strStatus == 1 ? StatusEnum.Enable : StatusEnum.Disable; } return StatusEnum.Disable; } } }