新增员工确认信息实名认证相关信息板块
This commit is contained in:
@@ -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 }) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user