using System.Globalization; using System.Security.Cryptography; using System.Text.Json; using Admin.NET.Plugin.AiDOP.Entity.DataPlatform; namespace Admin.NET.Plugin.AiDOP.DataPlatform.FileImport; public static class MdpExcelValidation { public static Dictionary MapRow( IReadOnlyDictionary raw, IReadOnlyList mappings) { var mapped = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var map in mappings.OrderBy(x => x.SortOrder)) { if (map.TargetField.Equals("tenant_id", StringComparison.OrdinalIgnoreCase)) continue; raw.TryGetValue(map.SourceField, out var val); if ((val == null || val is DBNull || string.IsNullOrWhiteSpace(Convert.ToString(val))) && !string.IsNullOrWhiteSpace(map.DefaultValue)) val = map.DefaultValue; if (map.IsRequired == 1 && (val == null || string.IsNullOrWhiteSpace(Convert.ToString(val)))) throw new InvalidOperationException($"必填列 {map.SourceField} 为空"); var text = Convert.ToString(val, CultureInfo.InvariantCulture); MdpFileImportSecurity.EnsureCell(text); mapped[map.TargetField] = val; } MdpFileImportSecurity.StripClientTenant(mapped); return mapped; } public static string BusinessKey(string? expr, IDictionary mapped) { if (string.IsNullOrWhiteSpace(expr)) throw new InvalidOperationException("实体未配置业务键"); var parts = expr.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); var vals = new List(); foreach (var p in parts) { if (!mapped.TryGetValue(p, out var v) || v == null || string.IsNullOrWhiteSpace(Convert.ToString(v))) throw new InvalidOperationException($"业务键 {p} 为空"); vals.Add(Convert.ToString(v, CultureInfo.InvariantCulture)!.Trim()); } return string.Join("|", vals); } public static string RowHash(IDictionary mapped) { var json = JsonSerializer.Serialize(mapped.OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase) .ToDictionary(x => x.Key, x => x.Value?.ToString())); var bytes = SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(json)); return Convert.ToHexString(bytes).ToLowerInvariant(); } public static bool IsPullStage(string? stageType, string? stepCode) { var t = (stageType ?? stepCode ?? string.Empty).Trim().ToUpperInvariant(); return t is "PULL" or "EXTRACT" or "INBOUND" or "SYNC_STAGING"; } }