修复相关bug
This commit is contained in:
+68
@@ -0,0 +1,68 @@
|
||||
namespace SimpleAdmin.Application;
|
||||
|
||||
/// <summary>
|
||||
/// 生成并读取入职登记表内置员工字段的任务级必填快照。
|
||||
/// </summary>
|
||||
internal static class OnboardingEmployeeFieldRequirementSnapshot
|
||||
{
|
||||
private const string EmployeeVariablePrefix = "employee.";
|
||||
|
||||
/// <summary>
|
||||
/// 根据当前内置员工变量配置创建一份任务快照。
|
||||
/// </summary>
|
||||
public static async Task<List<ObTaskFormRequirement>> BuildFromCurrentDefinitions(
|
||||
SqlSugarScope db,
|
||||
long taskId)
|
||||
{
|
||||
var definitions = await db.Queryable<ObVariableDefinition>()
|
||||
.Where(item => item.IsBuiltIn
|
||||
&& item.VariableCategory == ContractVariableType.Employee)
|
||||
.OrderBy(item => item.SortCode)
|
||||
.OrderBy(item => item.Id)
|
||||
.ToListAsync();
|
||||
|
||||
return definitions.Select(definition => new ObTaskFormRequirement
|
||||
{
|
||||
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
|
||||
TaskId = taskId,
|
||||
FieldId = definition.Id,
|
||||
FieldCode = definition.VariableCode,
|
||||
FieldName = definition.VariableName,
|
||||
DataType = definition.DataType,
|
||||
Required = definition.Required,
|
||||
SortCode = definition.SortCode
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取任务冻结配置;历史任务没有员工字段快照时使用当前配置兼容。
|
||||
/// </summary>
|
||||
public static async Task<List<ObTaskFormRequirement>> GetForTask(
|
||||
SqlSugarScope db,
|
||||
long taskId)
|
||||
{
|
||||
var snapshots = await db.Queryable<ObTaskFormRequirement>()
|
||||
.Where(item => item.TaskId == taskId)
|
||||
.OrderBy(item => item.SortCode)
|
||||
.ToListAsync();
|
||||
if (snapshots.Any(IsEmployeeField))
|
||||
return snapshots;
|
||||
|
||||
var compatibilitySnapshots = await BuildFromCurrentDefinitions(db, taskId);
|
||||
if (snapshots.Count == 0)
|
||||
return compatibilitySnapshots;
|
||||
|
||||
snapshots.AddRange(compatibilitySnapshots);
|
||||
return snapshots.OrderBy(item => item.SortCode).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断快照是否对应入职登记表内置员工字段。
|
||||
/// </summary>
|
||||
public static bool IsEmployeeField(ObTaskFormRequirement requirement)
|
||||
{
|
||||
return requirement?.FieldCode?.StartsWith(
|
||||
EmployeeVariablePrefix,
|
||||
StringComparison.OrdinalIgnoreCase) == true;
|
||||
}
|
||||
}
|
||||
+54
-10
@@ -16,9 +16,11 @@ internal static class OnboardingEmployeeInfoValidator
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 规范化文本,并校验固定登记表字段的格式。
|
||||
/// 规范化文本,并按照任务冻结配置校验固定登记表必填项及字段格式。
|
||||
/// </summary>
|
||||
public static void ValidateAndNormalize(ObTaskEmployeeInfo input)
|
||||
public static void ValidateAndNormalize(
|
||||
ObTaskEmployeeInfo input,
|
||||
IReadOnlyCollection<ObTaskFormRequirement> fieldRequirements = null)
|
||||
{
|
||||
input.EmployeeName = input.EmployeeName?.Trim();
|
||||
input.Phone = input.Phone?.Trim();
|
||||
@@ -26,20 +28,27 @@ internal static class OnboardingEmployeeInfoValidator
|
||||
input.IdCardNumber = input.IdCardNumber?.Trim().ToUpperInvariant();
|
||||
input.BankCardNumber = global::System.Text.RegularExpressions.Regex.Replace(
|
||||
input.BankCardNumber ?? string.Empty,
|
||||
"[\\s-]",
|
||||
@"[\s-]",
|
||||
string.Empty);
|
||||
input.BankName = input.BankName?.Trim();
|
||||
input.BankAccountName = input.EmployeeName;
|
||||
|
||||
ValidateRequiredFields(input, fieldRequirements);
|
||||
|
||||
// 电子签约实名认证始终依赖以下三项,不能通过后台配置关闭。
|
||||
if (string.IsNullOrWhiteSpace(input.EmployeeName) || input.EmployeeName.Length > 100)
|
||||
throw Oops.Bah("员工姓名不能为空且不能超过 100 个字符");
|
||||
|
||||
if (input.Gender != "男" && input.Gender != "女")
|
||||
if (!string.IsNullOrWhiteSpace(input.Gender)
|
||||
&& input.Gender != "男"
|
||||
&& input.Gender != "女")
|
||||
{
|
||||
throw Oops.Bah("请选择正确的性别");
|
||||
}
|
||||
|
||||
if (!global::System.Text.RegularExpressions.Regex.IsMatch(
|
||||
input.Phone ?? string.Empty,
|
||||
"^1[3-9]\\d{9}$"))
|
||||
@"^1[3-9]\d{9}$"))
|
||||
{
|
||||
throw Oops.Bah("请输入正确的 11 位手机号码");
|
||||
}
|
||||
@@ -51,10 +60,11 @@ internal static class OnboardingEmployeeInfoValidator
|
||||
ValidateOptionalEmail(input.Email);
|
||||
ValidateOptionalNumber(input.Height, "身高", 100M, 250M, "厘米");
|
||||
ValidateOptionalNumber(input.Weight, "体重", 30M, 300M, "公斤");
|
||||
ValidateBankCard(input.BankCardNumber);
|
||||
if (!string.IsNullOrWhiteSpace(input.BankCardNumber))
|
||||
ValidateBankCard(input.BankCardNumber);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.BankName) || input.BankName.Length > 100)
|
||||
throw Oops.Bah("开户银行名称不能为空且不能超过 100 个字符");
|
||||
if (!string.IsNullOrWhiteSpace(input.BankName) && input.BankName.Length > 100)
|
||||
throw Oops.Bah("开户银行名称不能超过 100 个字符");
|
||||
|
||||
ValidateOptionalContactPhone(input.EmergencyPhone);
|
||||
ValidateEducationHistory(input.EducationHistoryJson);
|
||||
@@ -63,6 +73,40 @@ internal static class OnboardingEmployeeInfoValidator
|
||||
ValidateJson(input.CustomVariablesJson, global::System.Text.Json.JsonValueKind.Object, "员工补充变量");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按任务快照校验后台配置为必填的内置员工字段。
|
||||
/// </summary>
|
||||
private static void ValidateRequiredFields(
|
||||
ObTaskEmployeeInfo input,
|
||||
IReadOnlyCollection<ObTaskFormRequirement> fieldRequirements)
|
||||
{
|
||||
if (fieldRequirements == null || fieldRequirements.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var requirement in fieldRequirements.Where(item =>
|
||||
item.Required
|
||||
&& OnboardingEmployeeFieldRequirementSnapshot.IsEmployeeField(item)))
|
||||
{
|
||||
var separatorIndex = requirement.FieldCode.LastIndexOf('.');
|
||||
var propertyName = separatorIndex >= 0
|
||||
? requirement.FieldCode[(separatorIndex + 1)..]
|
||||
: requirement.FieldCode;
|
||||
var property = typeof(ObTaskEmployeeInfo).GetProperty(
|
||||
propertyName,
|
||||
global::System.Reflection.BindingFlags.Instance
|
||||
| global::System.Reflection.BindingFlags.Public
|
||||
| global::System.Reflection.BindingFlags.IgnoreCase);
|
||||
if (property == null)
|
||||
{
|
||||
throw Oops.Bah(
|
||||
$"内置员工变量“{requirement.FieldCode}”没有对应的入职登记表字段,请联系管理员");
|
||||
}
|
||||
|
||||
var value = property.GetValue(input)?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
throw Oops.Bah($"请填写入职登记表“{requirement.FieldName}”");
|
||||
}
|
||||
}
|
||||
private static bool TryValidateIdCard(
|
||||
string idCardNumber,
|
||||
out DateTime birthday,
|
||||
@@ -106,7 +150,7 @@ internal static class OnboardingEmployeeInfoValidator
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ValidateBirthday(string birthdayText, DateTime idCardBirthday)
|
||||
private static void ValidateBirthday(string birthdayText, DateTime? idCardBirthday)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(birthdayText))
|
||||
return;
|
||||
@@ -120,7 +164,7 @@ internal static class OnboardingEmployeeInfoValidator
|
||||
if (!birthdayIsValid || birthday.Date > DateTime.Today)
|
||||
throw Oops.Bah("请输入正确的出生日期");
|
||||
|
||||
if (birthday.Date != idCardBirthday.Date)
|
||||
if (idCardBirthday.HasValue && birthday.Date != idCardBirthday.Value.Date)
|
||||
throw Oops.Bah("出生日期与身份证号码不一致");
|
||||
}
|
||||
|
||||
|
||||
+16
-2
@@ -40,6 +40,8 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
|
||||
.Where(item => item.TaskId == task.Id)
|
||||
.OrderBy(item => item.SortCode)
|
||||
.ToListAsync();
|
||||
var formRequirements =
|
||||
await OnboardingEmployeeFieldRequirementSnapshot.GetForTask(_db, task.Id);
|
||||
|
||||
var contracts = await _db.Queryable<ObTaskContract>()
|
||||
.Where(item => item.TaskId == task.Id)
|
||||
@@ -106,7 +108,17 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
|
||||
Contracts = contracts,
|
||||
DynamicValues = new List<ObTaskFormValue>(),
|
||||
Materials = materialOutputs,
|
||||
FormFields = new List<OnboardingPublicFormFieldOutput>(),
|
||||
FormFields = formRequirements
|
||||
.Where(OnboardingEmployeeFieldRequirementSnapshot.IsEmployeeField)
|
||||
.Select(requirement => new OnboardingPublicFormFieldOutput
|
||||
{
|
||||
FieldId = requirement.FieldId,
|
||||
FieldCode = requirement.FieldCode,
|
||||
FieldName = requirement.FieldName,
|
||||
DataType = requirement.DataType,
|
||||
OptionsJson = requirement.OptionsJson,
|
||||
Required = requirement.Required
|
||||
}).ToList(),
|
||||
MaterialRequirements = materialRequirements.Select(requirement => new OnboardingPublicMaterialOutput
|
||||
{
|
||||
MaterialTypeId = requirement.MaterialTypeId,
|
||||
@@ -134,7 +146,9 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
|
||||
throw Oops.Bah("当前任务不可编辑");
|
||||
}
|
||||
|
||||
OnboardingEmployeeInfoValidator.ValidateAndNormalize(input);
|
||||
var formRequirements =
|
||||
await OnboardingEmployeeFieldRequirementSnapshot.GetForTask(_db, task.Id);
|
||||
OnboardingEmployeeInfoValidator.ValidateAndNormalize(input, formRequirements);
|
||||
await _identityValidationService.EnsureNoDuplicate(
|
||||
task.Id,
|
||||
input.EmployeeName,
|
||||
|
||||
Reference in New Issue
Block a user