namespace SimpleAdmin.Application; /// /// 统一校验任务合同变量,确保最终提交的数据可以安全用于合同生成。 /// public class OnboardingContractVariableValidationService : IOnboardingContractVariableValidationService { private readonly SqlSugarScope _db; public OnboardingContractVariableValidationService() { _db = DbContext.DB; } /// public async Task Validate(long taskId) { var contracts = await _db.Queryable() .Where(item => item.TaskId == taskId) .ToListAsync(); if (contracts.Count == 0) return; var contractIds = contracts .Select(item => item.Id) .ToList(); var templateVersionIds = contracts .Select(item => item.TemplateVersionId) .Distinct() .ToList(); var variables = await _db.Queryable() .Where(item => contractIds.Contains(item.TaskContractId)) .ToListAsync(); var definitions = await _db.Queryable() .Where(item => templateVersionIds.Contains(item.TemplateVersionId)) .ToListAsync(); foreach (var contract in contracts) { var contractDefinitions = definitions .Where(item => item.TemplateVersionId == contract.TemplateVersionId) .OrderBy(item => item.SortCode); foreach (var definition in contractDefinitions) { var variable = variables.FirstOrDefault(item => item.TaskContractId == contract.Id && item.VariableCode == definition.VariableCode); var value = variable?.VariableValue?.Trim(); if (definition.Required && string.IsNullOrWhiteSpace(value)) { throw Oops.Bah( $"合同“{contract.ContractName}”的必填变量“{definition.VariableName}”尚未填写"); } if (string.IsNullOrWhiteSpace(value) || definition.VariableType != ContractVariableType.Employee) { continue; } ValidateDataType(contract.ContractName, definition, value); ValidateOptions(contract.ContractName, definition, value); } } } private static void ValidateDataType( string contractName, ObTemplateVariable definition, string value) { var dataType = definition.DataType?.Trim().ToLowerInvariant() ?? "string"; switch (dataType) { case "string": return; case "number": var numberIsValid = decimal.TryParse( value, global::System.Globalization.NumberStyles.Number, global::System.Globalization.CultureInfo.InvariantCulture, out _); if (!numberIsValid) { throw Oops.Bah( $"合同“{contractName}”的变量“{definition.VariableName}”必须填写数字"); } return; case "date": var dateIsValid = DateTime.TryParseExact( value, "yyyy-MM-dd", global::System.Globalization.CultureInfo.InvariantCulture, global::System.Globalization.DateTimeStyles.None, out _); if (!dateIsValid) { throw Oops.Bah( $"合同“{contractName}”的变量“{definition.VariableName}”必须填写正确日期"); } return; default: throw Oops.Bah( $"合同“{contractName}”的变量“{definition.VariableName}”数据类型配置不正确"); } } private static void ValidateOptions( string contractName, ObTemplateVariable definition, string value) { if (string.IsNullOrWhiteSpace(definition.OptionsJson)) return; var options = ParseOptions(contractName, definition); if (options.Contains(value)) return; throw Oops.Bah( $"合同“{contractName}”的变量“{definition.VariableName}”必须从配置选项中选择"); } private static HashSet ParseOptions( string contractName, ObTemplateVariable definition) { try { using var document = global::System.Text.Json.JsonDocument.Parse( definition.OptionsJson); if (document.RootElement.ValueKind != global::System.Text.Json.JsonValueKind.Array) throw new global::System.Text.Json.JsonException(); var options = document.RootElement .EnumerateArray() .Select(GetOptionValue) .Where(item => !string.IsNullOrWhiteSpace(item)) .ToHashSet(StringComparer.Ordinal); if (options.Count == 0) throw new global::System.Text.Json.JsonException(); return options; } catch (global::System.Text.Json.JsonException) { throw Oops.Bah( $"合同“{contractName}”的变量“{definition.VariableName}”可选项配置不正确"); } } private static string GetOptionValue( global::System.Text.Json.JsonElement option) { if (option.ValueKind == global::System.Text.Json.JsonValueKind.String) return option.GetString()?.Trim(); if (option.ValueKind == global::System.Text.Json.JsonValueKind.Object) { if (option.TryGetProperty("value", out var value)) return GetJsonText(value); if (option.TryGetProperty("label", out var label)) return GetJsonText(label); } return GetJsonText(option); } private static string GetJsonText( global::System.Text.Json.JsonElement value) { return value.ValueKind switch { global::System.Text.Json.JsonValueKind.String => value.GetString()?.Trim(), global::System.Text.Json.JsonValueKind.Number => value.ToString(), global::System.Text.Json.JsonValueKind.True => bool.TrueString, global::System.Text.Json.JsonValueKind.False => bool.FalseString, _ => null }; } }