新增员工确认信息实名认证相关信息板块

This commit is contained in:
fuenmao
2026-09-11 11:31:16 +08:00
parent 446e83eed1
commit cdf2b0776a
2 changed files with 275 additions and 4 deletions
+7 -1
View File
@@ -977,7 +977,13 @@ export const onboardingPublicApi = {
confirmContract(params: { token: string; taskContractId: number }) {
return publicHttp.post("confirm-contract", params);
},
submit(params: { token: string }) {
submit(params: {
token: string;
identityInformationConfirmed: boolean;
confirmedEmployeeName: string;
confirmedIdCardNumber: string;
confirmedPhone: string;
}) {
return publicHttp.post("submit", params);
},
prepareContract(params: { token: string; taskContractId: number }) {
+268 -3
View File
@@ -635,6 +635,53 @@
<!-- 步骤 4: 合同查阅与签署 -->
<div v-show="currentStep === 3" class="step-content">
<div v-if="canEdit" id="identity-confirmation-card" class="identity-confirmation-card">
<div class="identity-confirmation-heading">
<div>
<h3 class="identity-confirmation-title">实名认证信息二次确认</h3>
<p class="identity-confirmation-desc">
以下三项将直接用于电子签约实名认证,请按身份证及本人实名手机号逐项核对。
</p>
</div>
<el-tag type="warning" effect="plain">必须全部确认</el-tag>
</div>
<el-alert
title="任意一项填写错误都可能导致实名认证失败,并需要退回后重新发起流程。"
type="warning"
show-icon
:closable="false"
/>
<div class="identity-confirmation-list">
<div v-for="field in identityFields" :key="field.key" class="identity-confirmation-item">
<div class="identity-field-row">
<span class="identity-field-label">{{ field.label }}</span>
<span class="identity-field-value">{{ identityDisplayValue(field.key) }}</span>
</div>
<el-checkbox
:model-value="isIdentityFieldConfirmed(field.key)"
class="identity-confirmation-checkbox"
@change="setIdentityFieldConfirmation(field.key, $event)"
>
{{ field.confirmText }}
</el-checkbox>
</div>
</div>
<div class="identity-confirmation-footer">
<span
class="identity-confirmation-progress"
:class="{ 'is-complete': isIdentityConfirmationComplete }"
>
已确认 {{ confirmedIdentityFieldCount }}/{{ identityFields.length }} 项
</span>
<el-button type="primary" plain @click="returnToIdentityInformation">
返回第一步修改实名信息
</el-button>
</div>
</div>
<div class="section-header">
<h3 class="section-title">入职签署材料查阅与确认</h3>
<p class="section-desc">系统已为您代入真实登记信息生成专属签署材料,请认真查阅条款并勾选确认</p>
@@ -742,7 +789,7 @@
</template>
<script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from "vue";
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox, FormInstance, FormRules } from "element-plus";
import {
@@ -819,6 +866,85 @@ const form = reactive<any>({
otherRemarks: ""
});
type IdentityField = "employeeName" | "idCardNumber" | "phone";
const identityFields: Array<{
key: IdentityField;
label: string;
confirmText: string;
}> = [
{ key: "employeeName", label: "真实姓名", confirmText: "我已核对姓名,与本人身份证一致" },
{ key: "idCardNumber", label: "身份证号码", confirmText: "我已核对身份证号码完整且无误" },
{ key: "phone", label: "手机号码", confirmText: "我已核对手机号,可用于本人实名认证" }
];
const identityConfirmations = reactive<Record<IdentityField, boolean>>({
employeeName: false,
idCardNumber: false,
phone: false
});
const identityConfirmedValues = reactive<Record<IdentityField, string>>({
employeeName: "",
idCardNumber: "",
phone: ""
});
function normalizeIdentityValue(field: IdentityField, value: unknown) {
const normalized = String(value ?? "").trim();
return field === "idCardNumber" ? normalized.toUpperCase() : normalized;
}
function identityDisplayValue(field: IdentityField) {
return normalizeIdentityValue(field, form[field]) || "未填写";
}
function isIdentityFieldConfirmed(field: IdentityField) {
return identityConfirmations[field]
&& identityConfirmedValues[field] === normalizeIdentityValue(field, form[field]);
}
function setIdentityFieldConfirmation(field: IdentityField, value: unknown) {
const checked = Boolean(value);
identityConfirmations[field] = checked;
identityConfirmedValues[field] = checked
? normalizeIdentityValue(field, form[field])
: "";
}
function resetIdentityConfirmations() {
identityFields.forEach(({ key }) => {
identityConfirmations[key] = false;
identityConfirmedValues[key] = "";
});
}
const confirmedIdentityFieldCount = computed(() =>
identityFields.filter(({ key }) => isIdentityFieldConfirmed(key)).length
);
const isIdentityConfirmationComplete = computed(() =>
confirmedIdentityFieldCount.value === identityFields.length
);
function returnToIdentityInformation() {
resetIdentityConfirmations();
currentStep.value = 0;
window.scrollTo({ top: 0, behavior: "smooth" });
nextTick(() => regFormRef.value?.scrollToField("employeeName"));
}
watch(
() => identityFields.map(({ key }) => normalizeIdentityValue(key, form[key])),
values => {
identityFields.forEach(({ key }, index) => {
if (identityConfirmations[key] && identityConfirmedValues[key] !== values[index]) {
identityConfirmations[key] = false;
identityConfirmedValues[key] = "";
}
});
},
{ flush: "sync" }
);
// 多条动态经历
const educationHistory = ref<{ timeRange: string; location: string; content: string; result: string }[]>([]);
const workHistory = ref<{ timeRange: string; companyName: string; salary: string; position: string; leaveReason: string }[]>([]);
@@ -1583,6 +1709,15 @@ function previewAndDownloadContract(c: any) {
}
async function submitAll() {
if (!isIdentityConfirmationComplete.value) {
const missingLabels = identityFields
.filter(({ key }) => !isIdentityFieldConfirmed(key))
.map(item => item.label);
ElMessage.warning(`请逐项核对并确认实名认证信息:${missingLabels.join("、")}`);
locateValidationTarget("identity-confirmation-card");
return;
}
const unprepared = contracts.value.filter(c => !isContractPrepared(c.id));
if (unprepared.length) {
ElMessage.warning(`请先等待签署材料准备完成:${unprepared.map(c => c.contractName).join("、")}`);
@@ -1605,7 +1740,7 @@ async function submitAll() {
}
const confirmed = await isMessageBoxConfirmed(
ElMessageBox.confirm("确认提交全部入职资料与签署材料确认?提交后将进入人事复核建档流程。", "最终提交确认", {
ElMessageBox.confirm("请再次确认姓名、身份证号码和手机号码均准确无误。提交后将进入人事复核建档流程,您不能再自行修改。", "最终提交确认", {
type: "success",
confirmButtonText: "确认提交",
cancelButtonText: "再检查一下"
@@ -1621,7 +1756,13 @@ async function submitAll() {
for (const c of contracts.value) {
await onboardingPublicApi.confirmContract({ token: token.value, taskContractId: c.id });
}
await onboardingPublicApi.submit({ token: token.value });
await onboardingPublicApi.submit({
token: token.value,
identityInformationConfirmed: true,
confirmedEmployeeName: identityConfirmedValues.employeeName,
confirmedIdCardNumber: identityConfirmedValues.idCardNumber,
confirmedPhone: identityConfirmedValues.phone
});
ElMessage.success("入职资料已成功提交!请等待人事审核。");
await load();
} finally {
@@ -1972,6 +2113,112 @@ onBeforeUnmount(() => {
line-height: 1.5;
}
.identity-confirmation-card {
margin-bottom: 26px;
padding: 18px;
border: 1px solid #f59e0b;
border-radius: 10px;
background: #fffbeb;
box-sizing: border-box;
}
.identity-confirmation-heading {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 14px;
margin-bottom: 14px;
}
.identity-confirmation-title {
margin: 0 0 6px;
color: #92400e;
font-size: 17px;
font-weight: 700;
}
.identity-confirmation-desc {
margin: 0;
color: #78350f;
font-size: 13px;
line-height: 1.6;
}
.identity-confirmation-list {
display: grid;
gap: 10px;
margin-top: 14px;
}
.identity-confirmation-item {
min-width: 0;
padding: 13px 14px;
border: 1px solid #fde68a;
border-radius: 8px;
background: #fff;
}
.identity-field-row {
display: flex;
align-items: baseline;
gap: 14px;
margin-bottom: 9px;
min-width: 0;
}
.identity-field-label {
flex: 0 0 86px;
color: #64748b;
font-size: 13px;
}
.identity-field-value {
min-width: 0;
color: #0f172a;
font-size: 16px;
font-weight: 700;
letter-spacing: 0.02em;
overflow-wrap: anywhere;
}
.identity-confirmation-checkbox {
max-width: 100%;
height: auto;
margin-right: 0;
white-space: normal;
}
.identity-confirmation-checkbox :deep(.el-checkbox__input) {
flex: 0 0 auto;
margin-top: 3px;
}
.identity-confirmation-checkbox :deep(.el-checkbox__label) {
min-width: 0;
padding-left: 8px;
white-space: normal;
overflow-wrap: anywhere;
line-height: 1.5;
}
.identity-confirmation-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 14px;
}
.identity-confirmation-progress {
color: #b45309;
font-size: 13px;
font-weight: 600;
}
.identity-confirmation-progress.is-complete {
color: #15803d;
}
.contract-sign-card {
border: 1px solid #e2e8f0;
border-radius: 8px;
@@ -2197,6 +2444,24 @@ onBeforeUnmount(() => {
width: 100%;
justify-content: flex-end;
}
.identity-confirmation-card {
padding: 14px;
}
.identity-confirmation-heading,
.identity-confirmation-footer {
flex-direction: column;
align-items: stretch;
}
.identity-field-row {
flex-direction: column;
gap: 4px;
}
.identity-field-label {
flex-basis: auto;
}
.identity-confirmation-footer > .el-button {
width: 100%;
}
.contract-card-bottom {
flex-direction: column;
align-items: stretch;