namespace Admin.NET.Plugin.AiDOP.DataPlatform; [ApiDescriptionSettings(Order = 321, Description = "数据中台同步日志")] [Route("api/DataPlatform")] [NonUnify] public class MdpSyncLogService : IDynamicApiController, ITransient { private readonly ISqlSugarClient _db; private readonly UserManager _user; public MdpSyncLogService(ISqlSugarClient db, UserManager user) { _db = db; _user = user; } [DisplayName("同步日志列表")] [HttpGet("sync-logs")] public async Task GetList( [FromQuery] string? taskCode, [FromQuery] long? entityId, [FromQuery] string? entityCode, [FromQuery] string? sourceCode, [FromQuery] string? status, [FromQuery] string? triggerType, [FromQuery] DateTime? startTime, [FromQuery] DateTime? endTime, [FromQuery] int page = 1, [FromQuery] int pageSize = 20) { await EnsureMenuAsync(); page = page < 1 ? 1 : page; pageSize = Math.Clamp(pageSize, 1, 100); var offset = (page - 1) * pageSize; var where = new List(); var pars = new List { new("@limit", pageSize), new("@offset", offset) }; if (!_user.SuperAdmin && !_user.SysAdmin) { where.Add("tenant_id=@tenantId"); pars.Add(new SugarParameter("@tenantId", _user.TenantId)); } if (entityId is > 0) { where.Add("entity_id=@entityId"); pars.Add(new SugarParameter("@entityId", entityId.Value)); } if (!string.IsNullOrWhiteSpace(entityCode)) { where.Add("entity_name=@entityCode"); pars.Add(new SugarParameter("@entityCode", entityCode.Trim())); } if (!string.IsNullOrWhiteSpace(sourceCode)) { where.Add("source_code=@sourceCode"); pars.Add(new SugarParameter("@sourceCode", sourceCode.Trim())); } if (!string.IsNullOrWhiteSpace(taskCode)) { where.Add("sync_batch_id LIKE @taskCode"); pars.Add(new SugarParameter("@taskCode", "%" + taskCode.Trim() + "%")); } if (!string.IsNullOrWhiteSpace(status)) { where.Add("status=@status"); pars.Add(new SugarParameter("@status", status.Trim())); } if (!string.IsNullOrWhiteSpace(triggerType)) { where.Add("trigger_type=@triggerType"); pars.Add(new SugarParameter("@triggerType", triggerType.Trim())); } if (startTime.HasValue) { where.Add("sync_start>=@startTime"); pars.Add(new SugarParameter("@startTime", startTime.Value)); } if (endTime.HasValue) { where.Add("sync_start<=@endTime"); pars.Add(new SugarParameter("@endTime", endTime.Value)); } var whereSql = where.Count == 0 ? "1=1" : string.Join(" AND ", where); var countPars = pars.Where(p => p.ParameterName is not ("@limit" or "@offset")).ToList(); var total = await _db.Ado.GetIntAsync($"SELECT COUNT(*) FROM mdp_sync_log WHERE {whereSql}", countPars); var list = await _db.Ado.SqlQueryAsync( $""" SELECT id, entity_id AS entityId, source_code AS sourceCode, entity_name AS entityName, sync_batch_id AS batchId, sync_type AS syncType, trigger_type AS triggerType, sync_start AS syncStart, sync_end AS syncEnd, duration_ms AS durationMs, rows_read AS rowsRead, COALESCE(rows_written, rows_insert, 0) AS rowsWritten, rows_error AS rowsError, status, COALESCE(error_message, error_msg) AS errorMessage FROM mdp_sync_log WHERE {whereSql} ORDER BY id DESC LIMIT @limit OFFSET @offset """, pars); return new { total, page, pageSize, list }; } [DisplayName("同步日志详情")] [HttpGet("sync-logs/{id:long}")] public async Task Get(long id) { await EnsureMenuAsync(); var rows = await _db.Ado.SqlQueryAsync( """ SELECT id, tenant_id AS tenantId, entity_id AS entityId, source_code AS sourceCode, entity_name AS entityName, sync_batch_id AS batchId, sync_type AS syncType, trigger_type AS triggerType, sync_start AS syncStart, sync_end AS syncEnd, duration_ms AS durationMs, rows_read AS rowsRead, COALESCE(rows_written, rows_insert, 0) AS rowsWritten, rows_error AS rowsError, status, COALESCE(error_message, error_msg) AS errorMessage FROM mdp_sync_log WHERE id=@id AND (@admin=1 OR tenant_id=@tenantId) """, new SugarParameter("@id", id), new SugarParameter("@tenantId", _user.TenantId), new SugarParameter("@admin", _user.SuperAdmin || _user.SysAdmin ? 1 : 0)); return rows.FirstOrDefault() ?? throw Oops.Oh("同步日志不存在"); } private async Task EnsureMenuAsync() { if (_user.SuperAdmin || _user.SysAdmin) return; var roleIds = await _db.Queryable().Where(x => x.UserId == _user.UserId).Select(x => x.RoleId).ToListAsync(); var allowed = roleIds.Count > 0 && await _db.Queryable() .Where(x => roleIds.Contains(x.RoleId) && x.MenuId == MdpDbSyncRules.SyncLogMenuId) .AnyAsync(); if (!allowed) throw Oops.Oh("没有同步日志权限"); } }