This commit is contained in:
fuenmao
2026-08-25 20:37:17 +08:00
parent 38801533e9
commit be20a31332
22 changed files with 1090 additions and 336 deletions
@@ -11,9 +11,9 @@
namespace SimpleAdmin.Application;
/// <summary>
/// 候选人在入职任务中提交的固定人员基础信息。
/// 候选人在入职任务中提交的《入职登记表》标准员工档案信息。
/// </summary>
[SugarTable("ob_task_employee_info", TableDescription = "候选人提交的固定基础信息")]
[SugarTable("ob_task_employee_info", TableDescription = "候选人填写的入职登记表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class ObTaskEmployeeInfo : BaseEntity
{
@@ -23,45 +23,57 @@ public class ObTaskEmployeeInfo : BaseEntity
public long TaskId { get; set; }
/// <summary>
/// 员工编号。
/// 员工编号(选填/人事分配)。
/// </summary>
public string EmployeeNo { get; set; }
/// <summary>
/// 内部人员编号。
/// </summary>
public string InternalNo { get; set; }
// ==================== 1. 基本个人信息 ====================
/// <summary>
/// 员工姓名。
/// </summary>
public string EmployeeName { get; set; }
/// <summary>
/// 所属部门名称。
/// </summary>
public string DepartmentName { get; set; }
/// <summary>
/// 性别。
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 手机号码。
/// 民族。
/// </summary>
public string Phone { get; set; }
public string Nation { get; set; }
/// <summary>
/// 身份证号码。
/// 出生年月日。
/// </summary>
public string IdCardNumber { get; set; }
public string Birthday { get; set; }
/// <summary>
/// 毕业院校。
/// 户籍所在地。
/// </summary>
public string College { get; set; }
public string RegisteredResidence { get; set; }
/// <summary>
/// 身高 (cm)。
/// </summary>
public string Height { get; set; }
/// <summary>
/// 体重 (kg)。
/// </summary>
public string Weight { get; set; }
/// <summary>
/// 健康状况。
/// </summary>
public string HealthCondition { get; set; }
/// <summary>
/// 婚育情况。
/// </summary>
public string MaritalStatus { get; set; }
// ==================== 2. 学历与资质 ====================
/// <summary>
/// 最高学历。
/// </summary>
@@ -73,82 +85,125 @@ public class ObTaskEmployeeInfo : BaseEntity
public string Major { get; set; }
/// <summary>
/// 出生日期。
/// 毕业院校。
/// </summary>
public DateTime? BirthDate { get; set; }
public string GraduatedSchool { get; set; }
/// <summary>
/// 户籍所在地。
/// 职业资格。
/// </summary>
public string RegisteredResidence { get; set; }
public string VocationalQualification { get; set; }
/// <summary>
/// 民族。
/// 资格等级。
/// </summary>
public string Nation { get; set; }
public string QualificationLevel { get; set; }
/// <summary>
/// 现居住或联系地址。
/// 有何技术特长。
/// </summary>
public string ContactAddress { get; set; }
public string TechnicalSpecialty { get; set; }
// ==================== 3. 联系方式与薪酬账户 ====================
/// <summary>
/// 联系电话/手机号。
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 入职日期。
/// 电子邮箱。
/// </summary>
public DateTime? EntryDate { get; set; }
public string Email { get; set; }
/// <summary>
/// 合同开始日期。
/// 身份证号码。
/// </summary>
public DateTime? ContractStartDate { get; set; }
public string IdCardNumber { get; set; }
/// <summary>
/// 合同结束日期。
/// 暂住地址 / 现居住地址。
/// </summary>
public DateTime? ContractEndDate { get; set; }
public string CurrentAddress { get; set; }
/// <summary>
/// 试用期开始日期。
/// 房东联系方式。
/// </summary>
public DateTime? ProbationStartDate { get; set; }
/// <summary>
/// 试用期结束日期。
/// </summary>
public DateTime? ProbationEndDate { get; set; }
/// <summary>
/// 转正日期。
/// </summary>
public DateTime? RegularizationDate { get; set; }
/// <summary>
/// 社保缴纳公司。
/// </summary>
public string SocialInsuranceCompany { get; set; }
/// <summary>
/// 合同性质。
/// </summary>
public string ContractNature { get; set; }
public string LandlordContact { get; set; }
/// <summary>
/// 工资银行卡号。
/// </summary>
public string BankCardNumber { get; set; }
/// <summary>
/// 银行卡开户名。
/// </summary>
public string BankAccountName { get; set; }
/// <summary>
/// 开户银行名称。
/// </summary>
public string BankName { get; set; }
/// <summary>
/// 业务备注。
/// 银行卡开户人姓名。
/// </summary>
public string Remark { get; set; }
public string BankAccountName { get; set; }
// ==================== 4. 紧急联系人 ====================
/// <summary>
/// 紧急联系人姓名。
/// </summary>
public string EmergencyContact { get; set; }
/// <summary>
/// 紧急联系人电话。
/// </summary>
public string EmergencyPhone { get; set; }
/// <summary>
/// 紧急联系人联系地址。
/// </summary>
public string EmergencyAddress { get; set; }
// ==================== 5. 动态多条经历(JSON 存储) ====================
/// <summary>
/// 教育学习经历 JSON 列表: [ { timeRange, location, content, result } ]
/// </summary>
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string EducationHistoryJson { get; set; }
/// <summary>
/// 主要工作经历 JSON 列表: [ { timeRange, companyName, salary, position, leaveReason } ]
/// </summary>
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string WorkHistoryJson { get; set; }
/// <summary>
/// 家庭成员 JSON 列表: [ { name, relationship, age, company, phone } ]
/// </summary>
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string FamilyMembersJson { get; set; }
// ==================== 6. 入职情况与说明 ====================
/// <summary>
/// 入职部门。
/// </summary>
public string OnboardingDepartment { get; set; }
/// <summary>
/// 入职时间。
/// </summary>
public string OnboardingDate { get; set; }
/// <summary>
/// 入职岗位。
/// </summary>
public string OnboardingPosition { get; set; }
/// <summary>
/// 其他说明。
/// </summary>
public string OtherRemarks { get; set; }
/// <summary>
/// 员工补充自定义变量键值 JSON: { "VariableName": "Value" }
/// </summary>
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string CustomVariablesJson { get; set; }
}
@@ -0,0 +1,55 @@
namespace SimpleAdmin.Application;
/// <summary>
/// 全局合同变量字典定义表。
/// 包含标准入职登记表变量、人事合同变量及企业自定义变量。
/// </summary>
[SugarTable("ob_variable_definition", TableDescription = "合同变量字典定义")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class ObVariableDefinition : BaseEntity
{
/// <summary>
/// 变量全编码,如 employee.EmployeeName, hr.BaseSalary, company.CompanyName, system.TaskNo。
/// </summary>
public string VariableCode { get; set; }
/// <summary>
/// 变量中文显示名称,如“员工姓名”、“基本工资”。
/// </summary>
public string VariableName { get; set; }
/// <summary>
/// 变量作用域分类:employee(员工变量), hr(人事参数), company(公司变量), system(系统变量)。
/// </summary>
public string VariableCategory { get; set; }
/// <summary>
/// 数据类型:string, number, date, multiline。
/// </summary>
public string DataType { get; set; } = "string";
/// <summary>
/// 默认值或占位提示。
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// 是否为入职登记表内置字段(内置字段不可删,且第1步自动收集)。
/// </summary>
public bool IsBuiltIn { get; set; } = false;
/// <summary>
/// 是否必填。
/// </summary>
public bool Required { get; set; } = false;
/// <summary>
/// 排序码。
/// </summary>
public int SortCode { get; set; } = 100;
/// <summary>
/// 变量说明/备注。
/// </summary>
public string Remark { get; set; }
}
@@ -44,14 +44,25 @@ public class OnboardingAuditService : IOnboardingAuditService
throw Oops.Bah("该身份证号或手机号已存在正式员工");
}
var extraValues = await _db.Queryable<ObTaskFormValue>()
.Where(item => item.TaskId == task.Id)
.ToListAsync();
var employee = employeeInfo.Adapt<ObEmployee>();
employee.Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
employee.CompanyId = task.CompanyId;
employee.PositionId = task.PositionId;
employee.ExtraInfoJson = global::System.Text.Json.JsonSerializer.Serialize(extraValues);
employee.DepartmentName = employeeInfo.OnboardingDepartment;
employee.College = employeeInfo.GraduatedSchool;
employee.BirthDate = ParseDate(employeeInfo.Birthday);
employee.ContactAddress = employeeInfo.CurrentAddress;
employee.EntryDate = ParseDate(employeeInfo.OnboardingDate);
employee.Remark = employeeInfo.OtherRemarks;
employee.ExtraInfoJson = global::System.Text.Json.JsonSerializer.Serialize(employeeInfo);
employee.Status = CommonStatusConst.ENABLE;
employee.CreateTime = DateTime.Now;
employee.CreateUserId = UserManager.UserId;
employee.CreateUser = UserManager.Name;
employee.UpdateTime = null;
employee.UpdateUserId = null;
employee.UpdateUser = null;
employee.IsDelete = false;
// 员工档案、任务状态和审核记录必须同时成功,避免出现“已通过但没有员工档案”的中间状态。
await _db.Ado.BeginTranAsync();
@@ -124,6 +135,16 @@ public class OnboardingAuditService : IOnboardingAuditService
return task;
}
/// <summary>
/// 将登记表中的日期文本转换为正式员工档案日期。
/// </summary>
private static DateTime? ParseDate(string value)
{
return DateTime.TryParse(value, out var result)
? result.Date
: null;
}
private Task WriteAudit(ObOnboardingTask task, string action, string opinion)
{
return _db.Insertable(new ObTaskAudit
@@ -26,12 +26,8 @@ public class OnboardingContractSnapshotService : IOnboardingContractSnapshotServ
?? throw Oops.Bah("入职公司不存在");
employeeInfo ??= await _db.Queryable<ObTaskEmployeeInfo>()
.FirstAsync(item => item.TaskId == taskId);
var dynamicValues = await _db.Queryable<ObTaskFormValue>()
.Where(item => item.TaskId == taskId)
.ToListAsync();
var dynamicValueMap = dynamicValues
.GroupBy(item => item.FieldCode, StringComparer.OrdinalIgnoreCase)
.ToDictionary(group => group.Key, group => group.Last().FieldValue, StringComparer.OrdinalIgnoreCase);
// 员工补充合同变量统一从 CustomVariablesJson 读取,不再访问已移除的旧动态字段表。
var dynamicValueMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var contracts = await _db.Queryable<ObTaskContract>()
.Where(item => item.TaskId == taskId)
.ToListAsync();
@@ -110,6 +106,23 @@ public class OnboardingContractSnapshotService : IOnboardingContractSnapshotServ
var fixedValue = GetPropertyValue(employeeInfo, ResolveEmployeeField(sourceField), definition.FormatRule);
if (!string.IsNullOrWhiteSpace(fixedValue))
return fixedValue;
// 检查员工自定义补充变量 JSON
if (!string.IsNullOrWhiteSpace(employeeInfo?.CustomVariablesJson))
{
try
{
using var doc = global::System.Text.Json.JsonDocument.Parse(employeeInfo.CustomVariablesJson);
if (doc.RootElement.TryGetProperty(sourceField, out var prop)
|| doc.RootElement.TryGetProperty(definition.VariableCode, out prop))
{
var str = prop.GetString();
if (!string.IsNullOrWhiteSpace(str)) return str;
}
}
catch { }
}
return dynamicValues.TryGetValue(sourceField, out var dynamicValue)
? dynamicValue
: definition.DefaultValue;
@@ -184,8 +197,10 @@ public class OnboardingContractSnapshotService : IOnboardingContractSnapshotServ
"LEGALNAME" or "LEGAL_NAME" or "COMPANYLEGALNAME" => nameof(ObCompany.LegalName),
"UNIFIEDSOCIALCREDITCODE" or "UNIFIED_SOCIAL_CREDIT_CODE" => nameof(ObCompany.UnifiedSocialCreditCode),
"LEGALREPRESENTATIVE" or "LEGAL_REPRESENTATIVE" => nameof(ObCompany.LegalRepresentative),
"REGISTEREDADDRESS" or "REGISTERED_ADDRESS" => nameof(ObCompany.RegisteredAddress),
"CONTACTPHONE" or "CONTACT_PHONE" => nameof(ObCompany.ContactPhone),
"ADDRESS" or "COMPANYADDRESS" or "COMPANY_ADDRESS"
or "REGISTEREDADDRESS" or "REGISTERED_ADDRESS" => nameof(ObCompany.RegisteredAddress),
"PHONE" or "COMPANYPHONE" or "COMPANY_PHONE"
or "CONTACTPHONE" or "CONTACT_PHONE" => nameof(ObCompany.ContactPhone),
_ => sourceField
};
}
@@ -179,6 +179,16 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
await sourceStream.CopyToAsync(sourceBytes);
var bytes = sourceBytes.ToArray();
var variableCodes = DocxTemplateProcessor.ExtractVariableCodes(bytes);
// 严格比对变量字典库,防止手误和非法占位符
var dictList = await Context.Queryable<ObVariableDefinition>().ToListAsync();
var dictMap = dictList.ToDictionary(it => it.VariableCode, it => it, StringComparer.OrdinalIgnoreCase);
var undefinedCodes = variableCodes.Where(code => !dictMap.ContainsKey(code)).ToList();
if (undefinedCodes.Count > 0)
{
throw Oops.Bah($"DOCX 模板包含未在字典库中注册的占位符:{string.Join(",", undefinedCodes)}。请检查拼写或先在【变量字典】中添加该变量。");
}
var versionId = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
var version = input.Adapt<ObContractTemplateVersion>();
version.Id = versionId;
@@ -186,7 +196,12 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
version.FileHash = string.IsNullOrWhiteSpace(input.FileHash)
? Convert.ToHexString(global::System.Security.Cryptography.SHA256.HashData(bytes))
: input.FileHash;
var variables = variableCodes.Select((code, index) => BuildDetectedVariable(versionId, code, index)).ToList();
var variables = variableCodes.Select((code, index) =>
{
var def = dictMap.TryGetValue(code, out var d) ? d : null;
return BuildDetectedVariable(versionId, code, def, index);
}).ToList();
await Context.Ado.BeginTranAsync();
try
@@ -263,7 +278,7 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
await Context.Updateable(entity).ExecuteCommandAsync();
}
private static ObTemplateVariable BuildDetectedVariable(long versionId, string code, int index)
private static ObTemplateVariable BuildDetectedVariable(long versionId, string code, ObVariableDefinition def, int index)
{
var separatorIndex = code.IndexOf('.');
var prefix = separatorIndex > 0 ? code[..separatorIndex].ToLowerInvariant() : string.Empty;
@@ -277,21 +292,24 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
_ => ContractVariableType.Unresolved
};
var varName = def != null && !string.IsNullOrWhiteSpace(def.VariableName) ? def.VariableName : sourceField;
var dataType = def != null && !string.IsNullOrWhiteSpace(def.DataType) ? def.DataType : InferDataType(sourceField);
return new ObTemplateVariable
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TemplateVersionId = versionId,
VariableCode = code,
VariableName = sourceField,
VariableName = varName,
VariableType = variableType,
DataType = InferDataType(sourceField),
DataType = dataType,
EmployeeField = variableType is ContractVariableType.Employee or ContractVariableType.Company
? sourceField
: null,
Required = true,
Required = def?.Required ?? true,
HrEditable = variableType == ContractVariableType.Contract,
SortCode = (index + 1) * 10,
Remark = variableType == ContractVariableType.Unresolved ? "导入时未识别变量来源,请管理员确认" : null
Remark = def?.Remark
};
}
@@ -83,10 +83,8 @@ public class OnboardingTaskLifecycleService : IOnboardingTaskLifecycleService
await _db.Deleteable<ObTaskContract>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskLink>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskFormRequirement>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskMaterialRequirement>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskMaterial>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskFormValue>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskEmployeeInfo>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObTaskAudit>().Where(x => x.TaskId == task.Id).ExecuteCommandAsync();
await _db.Deleteable<ObOnboardingTask>().In(task.Id).ExecuteCommandAsync();
@@ -75,10 +75,7 @@ public class OnboardingTemplateService : IOnboardingTemplateService
.Where(item => item.OnboardingTemplateId == template.Id)
.OrderBy(item => item.SortCode)
.ToListAsync(),
FormFields = await _db.Queryable<ObOnboardingTemplateFormField>()
.Where(item => item.OnboardingTemplateId == template.Id)
.OrderBy(item => item.SortCode)
.ToListAsync(),
FormFields = new List<ObOnboardingTemplateFormField>(),
Materials = await _db.Queryable<ObOnboardingTemplateMaterial>()
.Where(item => item.OnboardingTemplateId == template.Id)
.OrderBy(item => item.SortCode)
@@ -246,49 +243,6 @@ public class OnboardingTemplateService : IOnboardingTemplateService
{
if (versions.Any(item => item.VersionStatus != ContractTemplateVersionStatus.Enabled))
throw Oops.Bah("启用入职模板前,请先启用全部合同版本");
var variables = await _db.Queryable<ObTemplateVariable>()
.Where(item => versionIds.Contains(item.TemplateVersionId))
.ToListAsync();
var validTypes = new[]
{
ContractVariableType.Employee,
ContractVariableType.Company,
ContractVariableType.Contract,
ContractVariableType.System
};
if (variables.Any(item => !validTypes.Contains(item.VariableType)))
throw Oops.Bah("合同中仍有未确认来源的变量,请先完成变量映射");
}
var fieldIds = input.FormFields.Select(item => item.FieldId).ToList();
var enabledFields = fieldIds.Count == 0
? new List<ObFormField>()
: await _db.Queryable<ObFormField>()
.Where(item => fieldIds.Contains(item.Id) && item.Status == "enable")
.ToListAsync();
if (enabledFields.Count != fieldIds.Count)
throw Oops.Bah("存在未启用或不存在的动态补充字段");
if (input.Status == "enable")
{
var variables = await _db.Queryable<ObTemplateVariable>()
.Where(item => versionIds.Contains(item.TemplateVersionId)
&& item.VariableType == ContractVariableType.Employee)
.ToListAsync();
var availableFields = new HashSet<string>(
typeof(ObTaskEmployeeInfo).GetProperties().Select(property => property.Name),
StringComparer.OrdinalIgnoreCase);
foreach (var fieldCode in enabledFields.Select(item => item.FieldCode))
availableFields.Add(fieldCode);
var missingMapping = variables.FirstOrDefault(variable =>
!availableFields.Contains(ResolveEmployeeVariableField(variable)));
if (missingMapping != null)
{
throw Oops.Bah(
$"合同员工变量“{missingMapping.VariableCode}”没有对应的固定字段或模板补充字段,请先完成字段映射");
}
}
var materialIds = input.Materials.Select(item => item.MaterialTypeId).ToList();
@@ -301,25 +255,6 @@ public class OnboardingTemplateService : IOnboardingTemplateService
}
}
private static string ResolveEmployeeVariableField(ObTemplateVariable variable)
{
var sourceField = variable.EmployeeField;
if (string.IsNullOrWhiteSpace(sourceField))
{
var separatorIndex = variable.VariableCode?.IndexOf('.') ?? -1;
sourceField = separatorIndex >= 0
? variable.VariableCode[(separatorIndex + 1)..]
: variable.VariableCode;
}
return sourceField?.ToUpperInvariant() switch
{
"FULLNAME" or "FULL_NAME" or "NAME" => nameof(ObTaskEmployeeInfo.EmployeeName),
"MOBILE" or "MOBILEPHONE" or "MOBILE_PHONE" => nameof(ObTaskEmployeeInfo.Phone),
"IDNUMBER" or "ID_NUMBER" or "IDENTITYNUMBER" => nameof(ObTaskEmployeeInfo.IdCardNumber),
_ => sourceField
};
}
private async Task InsertRelations(long templateId, OnboardingTemplateSaveInput input)
{
var positions = input.PositionIds.Select(positionId => new ObOnboardingTemplatePosition
@@ -342,20 +277,7 @@ public class OnboardingTemplateService : IOnboardingTemplateService
}).ToList();
await _db.Insertable(contracts).ExecuteCommandAsync();
if (input.FormFields.Count > 0)
{
var fields = input.FormFields.Select(item => new ObOnboardingTemplateFormField
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
OnboardingTemplateId = templateId,
FieldId = item.FieldId,
Required = item.Required,
SortCode = item.SortCode
}).ToList();
await _db.Insertable(fields).ExecuteCommandAsync();
}
if (input.Materials.Count > 0)
if (input.Materials != null && input.Materials.Count > 0)
{
var materials = input.Materials.Select(item => new ObOnboardingTemplateMaterial
{
@@ -377,9 +299,6 @@ public class OnboardingTemplateService : IOnboardingTemplateService
await _db.Deleteable<ObOnboardingTemplateContract>()
.Where(item => item.OnboardingTemplateId == templateId)
.ExecuteCommandAsync();
await _db.Deleteable<ObOnboardingTemplateFormField>()
.Where(item => item.OnboardingTemplateId == templateId)
.ExecuteCommandAsync();
await _db.Deleteable<ObOnboardingTemplateMaterial>()
.Where(item => item.OnboardingTemplateId == templateId)
.ExecuteCommandAsync();
@@ -405,9 +324,6 @@ public class OnboardingTemplateService : IOnboardingTemplateService
var contracts = await _db.Queryable<ObOnboardingTemplateContract>()
.Where(item => templateIds.Contains(item.OnboardingTemplateId))
.ToListAsync();
var fields = await _db.Queryable<ObOnboardingTemplateFormField>()
.Where(item => templateIds.Contains(item.OnboardingTemplateId))
.ToListAsync();
var materials = await _db.Queryable<ObOnboardingTemplateMaterial>()
.Where(item => templateIds.Contains(item.OnboardingTemplateId))
.ToListAsync();
@@ -432,7 +348,7 @@ public class OnboardingTemplateService : IOnboardingTemplateService
.Where(name => !string.IsNullOrWhiteSpace(name))
.ToList(),
ContractCount = contracts.Count(item => item.OnboardingTemplateId == template.Id),
FormFieldCount = fields.Count(item => item.OnboardingTemplateId == template.Id),
FormFieldCount = 0,
MaterialCount = materials.Count(item => item.OnboardingTemplateId == template.Id)
};
}).ToList();
@@ -55,6 +55,23 @@ public class OnboardingSaveMaterialInput
public long FileId { get; set; }
}
/// <summary>
/// 删除员工在当前可编辑任务中上传的一条材料。
/// </summary>
public class OnboardingDeleteMaterialInput
{
/// <summary>
/// 员工填写链接中的明文 Token。
/// </summary>
[global::System.ComponentModel.DataAnnotations.Required]
public string Token { get; set; }
/// <summary>
/// 任务材料记录 Id。
/// </summary>
public long TaskMaterialId { get; set; }
}
/// <summary>
/// 员工确认阅读合同参数。
/// </summary>
@@ -9,18 +9,27 @@ public interface IOnboardingPublicSubmissionService : ITransient
/// 保存候选人填写的动态字段值。
/// </summary>
Task SaveDynamicValues(OnboardingSaveDynamicValuesInput input);
/// <summary>
/// 关联候选人已经上传的系统文件与材料类型。
/// </summary>
Task SaveMaterial(OnboardingSaveMaterialInput input);
/// <summary>
/// 删除可编辑任务中的一条已上传材料关联。
/// </summary>
Task DeleteMaterial(OnboardingDeleteMaterialInput input);
/// <summary>
/// 记录候选人已阅读并确认指定任务合同。
/// </summary>
Task ConfirmContract(OnboardingConfirmContractInput input);
/// <summary>
/// 校验全部必填资料后提交入职任务进入审核。
/// </summary>
Task Submit(OnboardingSubmitInput input);
/// <summary>
/// 在保存文件前校验材料适用范围、扩展名、大小和数量。
/// </summary>
@@ -19,37 +19,8 @@ public class OnboardingPublicSubmissionService : IOnboardingPublicSubmissionServ
/// </summary>
public async Task SaveDynamicValues(OnboardingSaveDynamicValuesInput input)
{
var task = await GetEditableTask(input.Token);
var requirements = await GetFormRequirements(task.Id);
var fieldIds = input.Values.Select(item => item.FieldId).Distinct().ToList();
var hasInapplicableField = fieldIds.Any(id => requirements.All(item => item.FieldId != id));
if (hasInapplicableField)
throw Oops.Bah("填写字段不属于当前入职模板");
foreach (var value in input.Values)
{
var requirement = requirements.FirstOrDefault(item => item.FieldId == value.FieldId)
?? throw Oops.Bah("动态补充字段不存在");
var old = await _db.Queryable<ObTaskFormValue>()
.FirstAsync(item => item.TaskId == task.Id && item.FieldId == requirement.FieldId);
var row = new ObTaskFormValue
{
Id = old?.Id ?? global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TaskId = task.Id,
FieldId = requirement.FieldId,
FieldCode = requirement.FieldCode,
FieldName = requirement.FieldName,
FieldValue = value.FieldValue,
SubmitRound = task.SubmitCount + 1
};
if (old == null)
await _db.Insertable(row).ExecuteCommandAsync();
else
await _db.Updateable(row).ExecuteCommandAsync();
}
await _snapshotService.Build(task.Id, invalidateGeneratedPreview: true);
await GetEditableTask(input.Token);
throw Oops.Bah("新版入职登记表不再使用旧动态字段接口,请通过员工基础信息接口保存补充变量");
}
/// <summary>
@@ -96,6 +67,25 @@ public class OnboardingPublicSubmissionService : IOnboardingPublicSubmissionServ
}).ExecuteCommandAsync();
}
/// <summary>
/// 任务仍可编辑时删除一条已上传材料。
/// </summary>
public async Task DeleteMaterial(
OnboardingDeleteMaterialInput input)
{
var task = await GetEditableTask(input.Token);
var material = await _db.Queryable<ObTaskMaterial>()
.FirstAsync(item =>
item.Id == input.TaskMaterialId
&& item.TaskId == task.Id);
if (material == null)
throw Oops.Bah("上传材料不存在");
await _db.Deleteable<ObTaskMaterial>()
.In(material.Id)
.ExecuteCommandAsync();
}
/// <summary>
/// 记录候选人已经查看并确认动态生成的合同。
/// </summary>
@@ -124,24 +114,14 @@ public class OnboardingPublicSubmissionService : IOnboardingPublicSubmissionServ
var basicInfoIncomplete = info == null
|| string.IsNullOrWhiteSpace(info.EmployeeName)
|| string.IsNullOrWhiteSpace(info.Phone)
|| string.IsNullOrWhiteSpace(info.IdCardNumber);
|| string.IsNullOrWhiteSpace(info.IdCardNumber)
|| string.IsNullOrWhiteSpace(info.BankCardNumber)
|| string.IsNullOrWhiteSpace(info.BankName);
if (basicInfoIncomplete)
throw Oops.Bah("请先完整填写基本信息");
await _snapshotService.Build(task.Id, info);
var requiredFields = (await GetFormRequirements(task.Id))
.Where(item => item.Required)
.Select(item => item.FieldId)
.ToList();
var values = await _db.Queryable<ObTaskFormValue>()
.Where(item => item.TaskId == task.Id)
.ToListAsync();
var hasMissingRequiredField = requiredFields.Any(
id => values.All(item => item.FieldId != id || string.IsNullOrWhiteSpace(item.FieldValue)));
if (hasMissingRequiredField)
throw Oops.Bah("仍有必填补充信息未填写");
var requiredMaterials = (await GetMaterialRequirements(task.Id))
.Where(item => item.Required)
.Select(item => item.MaterialTypeId)
@@ -174,7 +154,7 @@ public class OnboardingPublicSubmissionService : IOnboardingPublicSubmissionServ
AuditRound = task.SubmitCount,
AuditAction = OnboardingAuditAction.Submit,
AuditOpinion = "员工提交入职资料",
SnapshotJson = global::System.Text.Json.JsonSerializer.Serialize(new { info, values, materials }),
SnapshotJson = global::System.Text.Json.JsonSerializer.Serialize(new { info, materials }),
AuditedAt = DateTime.Now
}).ExecuteCommandAsync();
}
@@ -235,14 +215,6 @@ public class OnboardingPublicSubmissionService : IOnboardingPublicSubmissionServ
throw Oops.Bah($"合同“{missing.contract.ContractName}”的必填变量“{missing.definition.VariableName}”尚未填写");
}
private Task<List<ObTaskFormRequirement>> GetFormRequirements(long taskId)
{
return _db.Queryable<ObTaskFormRequirement>()
.Where(item => item.TaskId == taskId)
.OrderBy(item => item.SortCode)
.ToListAsync();
}
private Task<List<ObTaskMaterialRequirement>> GetMaterialRequirements(long taskId)
{
return _db.Queryable<ObTaskMaterialRequirement>()
@@ -19,7 +19,7 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
}
/// <summary>
/// 通过有效 Token 获取任务创建时冻结的字段、材料和合同信息。
/// 通过有效 Token 获取任务创建时冻结的材料、合同和新版入职登记表信息。
/// </summary>
public async Task<OnboardingTaskPublicDetailOutput> Detail(OnboardingTaskPublicAccessInput input)
{
@@ -30,39 +30,49 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
link.AccessCount++;
link.LastAccessedAt = DateTime.Now;
await _db.Updateable(link).ExecuteCommandAsync();
var formRequirements = await _db.Queryable<ObTaskFormRequirement>()
.Where(item => item.TaskId == task.Id)
.OrderBy(item => item.SortCode)
.ToListAsync();
var materialRequirements = await _db.Queryable<ObTaskMaterialRequirement>()
.Where(item => item.TaskId == task.Id)
.OrderBy(item => item.SortCode)
.ToListAsync();
var contracts = await _db.Queryable<ObTaskContract>()
.Where(item => item.TaskId == task.Id)
.ToListAsync();
var templateVersionIds = contracts
.Select(item => item.TemplateVersionId)
.Distinct()
.ToList();
var contractVariables = new List<OnboardingPublicContractVariableOutput>();
if (templateVersionIds.Count > 0)
{
var employeeVariables = await _db.Queryable<ObTemplateVariable>()
.Where(item => templateVersionIds.Contains(item.TemplateVersionId)
&& item.VariableType == ContractVariableType.Employee)
.OrderBy(item => item.SortCode)
.ToListAsync();
contractVariables = employeeVariables.Select(item => new OnboardingPublicContractVariableOutput
{
VariableCode = item.VariableCode,
VariableName = item.VariableName,
VariableType = item.VariableType,
DataType = item.DataType,
DefaultValue = item.DefaultValue,
OptionsJson = item.OptionsJson,
Required = item.Required
}).ToList();
}
return new OnboardingTaskPublicDetailOutput
{
Task = task,
EmployeeInfo = await _db.Queryable<ObTaskEmployeeInfo>()
.FirstAsync(item => item.TaskId == task.Id),
Contracts = await _db.Queryable<ObTaskContract>()
.Where(item => item.TaskId == task.Id)
.ToListAsync(),
DynamicValues = await _db.Queryable<ObTaskFormValue>()
.Where(item => item.TaskId == task.Id)
.ToListAsync(),
Contracts = contracts,
DynamicValues = new List<ObTaskFormValue>(),
Materials = await _db.Queryable<ObTaskMaterial>()
.Where(item => item.TaskId == task.Id)
.ToListAsync(),
FormFields = formRequirements.Select(requirement => new OnboardingPublicFormFieldOutput
{
FieldId = requirement.FieldId,
FieldCode = requirement.FieldCode,
FieldName = requirement.FieldName,
DataType = requirement.DataType,
OptionsJson = requirement.OptionsJson,
Required = requirement.Required
}).ToList(),
FormFields = new List<OnboardingPublicFormFieldOutput>(),
MaterialRequirements = materialRequirements.Select(requirement => new OnboardingPublicMaterialOutput
{
MaterialTypeId = requirement.MaterialTypeId,
@@ -70,7 +80,8 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
AllowedExtensions = requirement.AllowedExtensions,
MaxFileCount = requirement.MaxFileCount,
Required = requirement.Required
}).ToList()
}).ToList(),
ContractVariables = contractVariables
};
}
@@ -92,15 +103,29 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
.FirstAsync(item => item.TaskId == task.Id);
var entity = input.Adapt<ObTaskEmployeeInfo>();
entity.TaskId = task.Id;
entity.IsDelete = false;
if (old == null)
{
entity.Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
entity.Status = CommonStatusConst.ENABLE;
entity.CreateTime = DateTime.Now;
entity.CreateUserId = null;
entity.CreateUser = null;
await _db.Insertable(entity).ExecuteCommandAsync();
}
else
{
entity.Id = old.Id;
entity.Status = old.Status;
entity.CreateTime = old.CreateTime;
entity.CreateUserId = old.CreateUserId;
entity.CreateUser = old.CreateUser;
entity.ExtJson = old.ExtJson;
entity.IsDelete = old.IsDelete;
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = null;
entity.UpdateUser = null;
await _db.Updateable(entity).ExecuteCommandAsync();
}
@@ -96,6 +96,47 @@ public class OnboardingPublicFormFieldOutput
public bool Required { get; set; }
}
/// <summary>
/// 员工端需要填写的合同员工变量。
/// </summary>
public class OnboardingPublicContractVariableOutput
{
/// <summary>
/// 合同变量编码。
/// </summary>
public string VariableCode { get; set; }
/// <summary>
/// 合同变量显示名称。
/// </summary>
public string VariableName { get; set; }
/// <summary>
/// 变量来源类型。
/// </summary>
public string VariableType { get; set; }
/// <summary>
/// 变量数据类型。
/// </summary>
public string DataType { get; set; }
/// <summary>
/// 变量默认值。
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// 选择型变量的可选项 JSON。
/// </summary>
public string OptionsJson { get; set; }
/// <summary>
/// 是否必填。
/// </summary>
public bool Required { get; set; }
}
/// <summary>
/// 员工端材料上传要求。
/// </summary>
@@ -166,4 +207,9 @@ public class OnboardingTaskPublicDetailOutput
/// 候选人已上传材料列表。
/// </summary>
public List<ObTaskMaterial> Materials { get; set; }
/// <summary>
/// 合同中由员工填写的扩展变量。
/// </summary>
public List<OnboardingPublicContractVariableOutput> ContractVariables { get; set; }
}
@@ -19,7 +19,7 @@ public class OnboardingTaskService : IOnboardingTaskService
}
/// <summary>
/// 校验公司、岗位和入职模板后创建任务,并冻结合同、补充字段及材料要求。
/// 校验公司、岗位和入职模板后创建任务,并冻结合同及材料要求。
/// </summary>
public async Task<OnboardingTaskCreatedOutput> Create(OnboardingTaskCreateInput input)
{
@@ -53,10 +53,6 @@ public class OnboardingTaskService : IOnboardingTaskService
if (contractConfigs.Count == 0)
throw Oops.Bah("入职模板尚未配置合同文件");
var fieldConfigs = await _db.Queryable<ObOnboardingTemplateFormField>()
.Where(item => item.OnboardingTemplateId == onboardingTemplate.Id)
.OrderBy(item => item.SortCode)
.ToListAsync();
var materialConfigs = await _db.Queryable<ObOnboardingTemplateMaterial>()
.Where(item => item.OnboardingTemplateId == onboardingTemplate.Id)
.OrderBy(item => item.SortCode)
@@ -73,14 +69,12 @@ public class OnboardingTaskService : IOnboardingTaskService
if (enabledVersionCount != versionIds.Count)
throw Oops.Bah("入职模板包含未启用的合同版本,请先调整模板配置");
var fieldIds = fieldConfigs.Select(item => item.FieldId).Distinct().ToList();
var fields = fieldIds.Count == 0
? new List<ObFormField>()
: await _db.Queryable<ObFormField>().Where(item => fieldIds.Contains(item.Id)).ToListAsync();
var materialIds = materialConfigs.Select(item => item.MaterialTypeId).Distinct().ToList();
var materialTypes = materialIds.Count == 0
? new List<ObMaterialType>()
: await _db.Queryable<ObMaterialType>().Where(item => materialIds.Contains(item.Id)).ToListAsync();
if (materialTypes.Count != materialIds.Count)
throw Oops.Bah("入职模板包含不存在的材料类型,请先调整模板配置");
var expiryConfig = await _configService.GetByConfigKey(
CateGoryConst.CONFIG_BIZ_DEFINE,
@@ -108,6 +102,8 @@ public class OnboardingTaskService : IOnboardingTaskService
Remark = input.Remark
};
ValidateInitialContractDateRanges(input.ContractVariables);
await _db.Ado.BeginTranAsync();
try
{
@@ -121,6 +117,15 @@ public class OnboardingTaskService : IOnboardingTaskService
ExpiresAt = expiresAt
}).ExecuteCommandAsync();
// 初始化空白的员工入职登记表
await _db.Insertable(new ObTaskEmployeeInfo
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TaskId = taskId,
Status = CommonStatusConst.ENABLE,
CreateTime = DateTime.Now
}).ExecuteCommandAsync();
var contracts = contractConfigs.Select(config =>
{
var template = contractTemplates.First(item => item.Id == config.ContractTemplateId);
@@ -138,27 +143,6 @@ public class OnboardingTaskService : IOnboardingTaskService
}).ToList();
await _db.Insertable(contracts).ExecuteCommandAsync();
if (fieldConfigs.Count > 0)
{
var fieldSnapshots = fieldConfigs.Select(config =>
{
var field = fields.First(item => item.Id == config.FieldId);
return new ObTaskFormRequirement
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TaskId = taskId,
FieldId = field.Id,
FieldCode = field.FieldCode,
FieldName = field.FieldName,
DataType = field.DataType,
OptionsJson = field.OptionsJson,
Required = config.Required,
SortCode = config.SortCode
};
}).ToList();
await _db.Insertable(fieldSnapshots).ExecuteCommandAsync();
}
if (materialConfigs.Count > 0)
{
var materialSnapshots = materialConfigs.Select(config =>
@@ -212,8 +196,12 @@ public class OnboardingTaskService : IOnboardingTaskService
var definitions = await _db.Queryable<ObTemplateVariable>()
.Where(item => versionIds.Contains(item.TemplateVersionId)
&& item.HrEditable
&& (item.VariableType == ContractVariableType.Contract
|| item.VariableType == ContractVariableType.Company))
&& (item.VariableType == "hr"
|| item.VariableType == "contract"
|| item.VariableType == "company"
|| item.VariableType == ContractVariableType.Contract
|| item.VariableType == ContractVariableType.Company
|| item.VariableCode.StartsWith("hr.")))
.ToListAsync();
var duplicateInput = inputs
@@ -268,4 +256,42 @@ public class OnboardingTaskService : IOnboardingTaskService
if (changedRows.Count > 0)
await _db.Updateable(changedRows).ExecuteCommandAsync();
}
/// <summary>
/// 校验人事创建任务时填写的合同日期先后关系。
/// </summary>
private static void ValidateInitialContractDateRanges(
List<OnboardingInitialContractVariableInput> inputs)
{
inputs ??= new List<OnboardingInitialContractVariableInput>();
foreach (var group in inputs.GroupBy(item => item.ContractTemplateVersionId))
{
ValidateDateRange(group, "hr.ContractStartDate", "hr.ContractEndDate", "合同");
ValidateDateRange(group, "hr.ProbationStartDate", "hr.ProbationEndDate", "试用期");
}
}
/// <summary>
/// 校验同一合同版本内一组开始、结束日期。
/// </summary>
private static void ValidateDateRange(
IEnumerable<OnboardingInitialContractVariableInput> inputs,
string startCode,
string endCode,
string rangeName)
{
var startValue = inputs.FirstOrDefault(item =>
string.Equals(item.VariableCode, startCode, StringComparison.OrdinalIgnoreCase))?.VariableValue;
var endValue = inputs.FirstOrDefault(item =>
string.Equals(item.VariableCode, endCode, StringComparison.OrdinalIgnoreCase))?.VariableValue;
if (string.IsNullOrWhiteSpace(startValue) || string.IsNullOrWhiteSpace(endValue))
return;
if (!DateTime.TryParse(startValue, out var startDate))
throw Oops.Bah($"{rangeName}开始日期格式不正确");
if (!DateTime.TryParse(endValue, out var endDate))
throw Oops.Bah($"{rangeName}结束日期格式不正确");
if (endDate.Date < startDate.Date)
throw Oops.Bah($"{rangeName}结束日期不能早于开始日期");
}
}
@@ -0,0 +1,10 @@
namespace SimpleAdmin.Application;
public interface IOnboardingVariableDefinitionService : ITransient
{
Task<SqlSugarPagedList<ObVariableDefinition>> Page(OnboardingVariableDefinitionPageInput input);
Task<List<ObVariableDefinition>> ListAll();
Task Add(OnboardingVariableDefinitionAddInput input);
Task Edit(OnboardingVariableDefinitionEditInput input);
Task Delete(BaseIdListInput input);
}
@@ -0,0 +1,33 @@
using System.ComponentModel.DataAnnotations;
namespace SimpleAdmin.Application;
public class OnboardingVariableDefinitionPageInput : BasePageInput
{
public string Keyword { get; set; }
public string VariableCategory { get; set; }
}
public class OnboardingVariableDefinitionAddInput
{
[Required(ErrorMessage = "变量编码不能为空")]
public string VariableCode { get; set; }
[Required(ErrorMessage = "变量名称不能为空")]
public string VariableName { get; set; }
[Required(ErrorMessage = "变量分类不能为空")]
public string VariableCategory { get; set; }
public string DataType { get; set; } = "string";
public string DefaultValue { get; set; }
public bool Required { get; set; }
public int SortCode { get; set; } = 100;
public string Remark { get; set; }
}
public class OnboardingVariableDefinitionEditInput : OnboardingVariableDefinitionAddInput
{
[IdNotNull(ErrorMessage = "Id不能为空")]
public long Id { get; set; }
}
@@ -0,0 +1,78 @@
namespace SimpleAdmin.Application;
public class OnboardingVariableDefinitionService : IOnboardingVariableDefinitionService
{
private readonly SqlSugarScope _db;
private static bool _initialized = false;
private static readonly object _lock = new();
public OnboardingVariableDefinitionService()
{
_db = DbContext.DB;
}
public async Task<SqlSugarPagedList<ObVariableDefinition>> Page(OnboardingVariableDefinitionPageInput input)
{
return await _db.Queryable<ObVariableDefinition>()
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), it => it.VariableCode.Contains(input.Keyword) || it.VariableName.Contains(input.Keyword))
.WhereIF(!string.IsNullOrWhiteSpace(input.VariableCategory), it => it.VariableCategory == input.VariableCategory)
.OrderBy(it => it.SortCode)
.OrderBy(it => it.Id)
.ToPagedListAsync(input.PageNum, input.PageSize);
}
public async Task<List<ObVariableDefinition>> ListAll()
{
return await _db.Queryable<ObVariableDefinition>()
.OrderBy(it => it.SortCode)
.OrderBy(it => it.Id)
.ToListAsync();
}
public async Task Add(OnboardingVariableDefinitionAddInput input)
{
var code = input.VariableCode.Trim();
var exists = await _db.Queryable<ObVariableDefinition>().AnyAsync(it => it.VariableCode == code);
if (exists)
throw Oops.Bah($"变量编码“{code}”已存在");
var entity = input.Adapt<ObVariableDefinition>();
entity.VariableCode = code;
entity.IsBuiltIn = false;
await _db.Insertable(entity).ExecuteCommandAsync();
}
public async Task Edit(OnboardingVariableDefinitionEditInput input)
{
var entity = await _db.Queryable<ObVariableDefinition>().InSingleAsync(input.Id)
?? throw Oops.Bah("变量不存在");
entity.VariableName = input.VariableName;
entity.DataType = input.DataType ?? "string";
entity.DefaultValue = input.DefaultValue;
entity.Required = input.Required;
entity.SortCode = input.SortCode;
entity.Remark = input.Remark;
if (!entity.IsBuiltIn)
{
entity.VariableCategory = input.VariableCategory;
}
await _db.Updateable(entity).ExecuteCommandAsync();
}
public async Task Delete(BaseIdListInput input)
{
if (input.Ids.Count == 0) return;
var hasBuiltIn = await _db.Queryable<ObVariableDefinition>()
.Where(it => input.Ids.Contains(it.Id) && it.IsBuiltIn)
.AnyAsync();
if (hasBuiltIn)
throw Oops.Bah("系统内置的标准入职登记表变量不能删除");
await _db.Deleteable<ObVariableDefinition>()
.Where(it => input.Ids.Contains(it.Id))
.ExecuteCommandAsync();
}
}
@@ -886,7 +886,7 @@
</member>
<member name="T:SimpleAdmin.Application.ObTaskEmployeeInfo">
<summary>
候选人在入职任务中提交的固定人员基础信息。
候选人在入职任务中提交的《入职登记表》标准员工档案信息。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.TaskId">
@@ -896,12 +896,7 @@
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EmployeeNo">
<summary>
员工编号。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.InternalNo">
<summary>
内部人员编号。
员工编号(选填/人事分配)。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EmployeeName">
@@ -909,29 +904,44 @@
员工姓名。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.DepartmentName">
<summary>
所属部门名称。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Gender">
<summary>
性别。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Phone">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Nation">
<summary>
手机号码。
民族。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.IdCardNumber">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Birthday">
<summary>
身份证号码。
出生年月日。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.College">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.RegisteredResidence">
<summary>
毕业院校。
户籍所在地。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Height">
<summary>
身高 (cm)。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Weight">
<summary>
体重 (kg)。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.HealthCondition">
<summary>
健康状况。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.MaritalStatus">
<summary>
婚育情况。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Education">
@@ -944,64 +954,49 @@
所学专业。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.BirthDate">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.GraduatedSchool">
<summary>
出生日期。
毕业院校。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.RegisteredResidence">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.VocationalQualification">
<summary>
户籍所在地。
职业资格。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Nation">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.QualificationLevel">
<summary>
民族。
资格等级。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.ContactAddress">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.TechnicalSpecialty">
<summary>
现居住或联系地址。
有何技术特长。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EntryDate">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Phone">
<summary>
入职日期。
联系电话/手机号。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.ContractStartDate">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Email">
<summary>
合同开始日期。
电子邮箱。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.ContractEndDate">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.IdCardNumber">
<summary>
合同结束日期。
身份证号码。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.ProbationStartDate">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.CurrentAddress">
<summary>
试用期开始日期。
暂住地址 / 现居住地址。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.ProbationEndDate">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.LandlordContact">
<summary>
试用期结束日期。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.RegularizationDate">
<summary>
转正日期。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.SocialInsuranceCompany">
<summary>
社保缴纳公司。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.ContractNature">
<summary>
合同性质。
房东联系方式。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.BankCardNumber">
@@ -1009,19 +1004,69 @@
工资银行卡号。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.BankAccountName">
<summary>
银行卡开户名。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.BankName">
<summary>
开户银行名称。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.Remark">
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.BankAccountName">
<summary>
业务备注。
银行卡开户人姓名。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EmergencyContact">
<summary>
紧急联系人姓名。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EmergencyPhone">
<summary>
紧急联系人电话。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EmergencyAddress">
<summary>
紧急联系人联系地址。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.EducationHistoryJson">
<summary>
教育学习经历 JSON 列表: [ { timeRange, location, content, result } ]
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.WorkHistoryJson">
<summary>
主要工作经历 JSON 列表: [ { timeRange, companyName, salary, position, leaveReason } ]
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.FamilyMembersJson">
<summary>
家庭成员 JSON 列表: [ { name, relationship, age, company, phone } ]
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.OnboardingDepartment">
<summary>
入职部门。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.OnboardingDate">
<summary>
入职时间。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.OnboardingPosition">
<summary>
入职岗位。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.OtherRemarks">
<summary>
其他说明。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObTaskEmployeeInfo.CustomVariablesJson">
<summary>
员工补充自定义变量键值 JSON: { "VariableName": "Value" }
</summary>
</member>
<member name="T:SimpleAdmin.Application.ObTaskFormRequirement">
@@ -1354,6 +1399,57 @@
业务备注。
</summary>
</member>
<member name="T:SimpleAdmin.Application.ObVariableDefinition">
<summary>
全局合同变量字典定义表。
包含标准入职登记表变量、人事合同变量及企业自定义变量。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.VariableCode">
<summary>
变量全编码,如 employee.EmployeeName, hr.BaseSalary, company.CompanyName, system.TaskNo。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.VariableName">
<summary>
变量中文显示名称,如“员工姓名”、“基本工资”。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.VariableCategory">
<summary>
变量作用域分类:employee(员工变量), hr(人事参数), company(公司变量), system(系统变量)。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.DataType">
<summary>
数据类型:string, number, date, multiline。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.DefaultValue">
<summary>
默认值或占位提示。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.IsBuiltIn">
<summary>
是否为入职登记表内置字段(内置字段不可删,且第1步自动收集)。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.Required">
<summary>
是否必填。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.SortCode">
<summary>
排序码。
</summary>
</member>
<member name="P:SimpleAdmin.Application.ObVariableDefinition.Remark">
<summary>
变量说明/备注。
</summary>
</member>
<member name="T:SimpleAdmin.Application.OnboardingTaskStatus">
<summary>
入职任务状态。
@@ -1629,6 +1725,11 @@
退回入职任务,保存审核意见并允许候选人补充资料。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingAuditService.ParseDate(System.String)">
<summary>
将登记表中的日期文本转换为正式员工档案日期。
</summary>
</member>
<member name="T:SimpleAdmin.Application.OnboardingCompanyPageInput">
<summary>
入职业务公司分页查询参数。
@@ -2926,6 +3027,21 @@
系统文件 Id。
</summary>
</member>
<member name="T:SimpleAdmin.Application.OnboardingDeleteMaterialInput">
<summary>
删除员工在当前可编辑任务中上传的一条材料。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingDeleteMaterialInput.Token">
<summary>
员工填写链接中的明文 Token。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingDeleteMaterialInput.TaskMaterialId">
<summary>
任务材料记录 Id。
</summary>
</member>
<member name="T:SimpleAdmin.Application.OnboardingConfirmContractInput">
<summary>
员工确认阅读合同参数。
@@ -2966,6 +3082,11 @@
关联候选人已经上传的系统文件与材料类型。
</summary>
</member>
<member name="M:SimpleAdmin.Application.IOnboardingPublicSubmissionService.DeleteMaterial(SimpleAdmin.Application.OnboardingDeleteMaterialInput)">
<summary>
删除可编辑任务中的一条已上传材料关联。
</summary>
</member>
<member name="M:SimpleAdmin.Application.IOnboardingPublicSubmissionService.ConfirmContract(SimpleAdmin.Application.OnboardingConfirmContractInput)">
<summary>
记录候选人已阅读并确认指定任务合同。
@@ -2996,6 +3117,11 @@
关联已上传 OSS 文件与任务材料要求。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicSubmissionService.DeleteMaterial(SimpleAdmin.Application.OnboardingDeleteMaterialInput)">
<summary>
任务仍可编辑时删除一条已上传材料。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicSubmissionService.ConfirmContract(SimpleAdmin.Application.OnboardingConfirmContractInput)">
<summary>
记录候选人已经查看并确认动态生成的合同。
@@ -3038,7 +3164,7 @@
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicTaskService.Detail(SimpleAdmin.Application.OnboardingTaskPublicAccessInput)">
<summary>
通过有效 Token 获取任务创建时冻结的字段、材料和合同信息。
通过有效 Token 获取任务创建时冻结的材料、合同和新版入职登记表信息。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicTaskService.SaveEmployeeInfo(SimpleAdmin.Application.OnboardingTaskPublicSaveInput)">
@@ -3456,6 +3582,46 @@
是否必填、必传或必签。
</summary>
</member>
<member name="T:SimpleAdmin.Application.OnboardingPublicContractVariableOutput">
<summary>
员工端需要填写的合同员工变量。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.VariableCode">
<summary>
合同变量编码。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.VariableName">
<summary>
合同变量显示名称。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.VariableType">
<summary>
变量来源类型。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.DataType">
<summary>
变量数据类型。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.DefaultValue">
<summary>
变量默认值。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.OptionsJson">
<summary>
选择型变量的可选项 JSON。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingPublicContractVariableOutput.Required">
<summary>
是否必填。
</summary>
</member>
<member name="T:SimpleAdmin.Application.OnboardingPublicMaterialOutput">
<summary>
员工端材料上传要求。
@@ -3526,6 +3692,11 @@
候选人已上传材料列表。
</summary>
</member>
<member name="P:SimpleAdmin.Application.OnboardingTaskPublicDetailOutput.ContractVariables">
<summary>
合同中由员工填写的扩展变量。
</summary>
</member>
<member name="T:SimpleAdmin.Application.IOnboardingTaskService">
<summary>
定义入职任务创建业务能力。
@@ -3543,7 +3714,7 @@
</member>
<member name="M:SimpleAdmin.Application.OnboardingTaskService.Create(SimpleAdmin.Application.OnboardingTaskCreateInput)">
<summary>
校验公司、岗位和入职模板后创建任务,并冻结合同、补充字段及材料要求。
校验公司、岗位和入职模板后创建任务,并冻结合同及材料要求。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingTaskService.ApplyInitialContractVariables(System.Collections.Generic.List{SimpleAdmin.Application.OnboardingInitialContractVariableInput},System.Collections.Generic.List{SimpleAdmin.Application.ObTaskContract})">
@@ -3551,6 +3722,16 @@
校验并保存任务创建时填写的人事合同变量。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingTaskService.ValidateInitialContractDateRanges(System.Collections.Generic.List{SimpleAdmin.Application.OnboardingInitialContractVariableInput})">
<summary>
校验人事创建任务时填写的合同日期先后关系。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingTaskService.ValidateDateRange(System.Collections.Generic.IEnumerable{SimpleAdmin.Application.OnboardingInitialContractVariableInput},System.String,System.String,System.String)">
<summary>
校验同一合同版本内一组开始、结束日期。
</summary>
</member>
<member name="T:SimpleAdmin.Application.IOrgService">
<summary>
机构服务