11
This commit is contained in:
@@ -3,6 +3,7 @@ import type { ReqId, ResPage } from "@/api/interface";
|
|||||||
|
|
||||||
const taskHttp = moduleRequest("/biz/onboarding/task/");
|
const taskHttp = moduleRequest("/biz/onboarding/task/");
|
||||||
const auditHttp = moduleRequest("/biz/onboarding/audit/");
|
const auditHttp = moduleRequest("/biz/onboarding/audit/");
|
||||||
|
const fileHttp = moduleRequest("/sys/dev/file/");
|
||||||
|
|
||||||
export interface OnboardingTask {
|
export interface OnboardingTask {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -178,6 +179,15 @@ export const onboardingTaskApi = {
|
|||||||
return taskHttp.get("detail", params);
|
return taskHttp.get("detail", params);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 使用后台登录令牌读取文件流,供入职材料下载和图片预览使用。 */
|
||||||
|
downloadFile(fileId: number) {
|
||||||
|
return fileHttp.get<any>(
|
||||||
|
"download",
|
||||||
|
{ id: fileId },
|
||||||
|
{ responseType: "blob", loading: false, cancel: false }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
create(params: Record<string, unknown>) {
|
create(params: Record<string, unknown>) {
|
||||||
return taskHttp.post("create", params);
|
return taskHttp.post("create", params);
|
||||||
},
|
},
|
||||||
@@ -543,4 +553,4 @@ export const onboardingPublicApi = {
|
|||||||
deleteMaterial(params: { token: string; taskMaterialId: number }) {
|
deleteMaterial(params: { token: string; taskMaterialId: number }) {
|
||||||
return publicHttp.post("delete-material", params);
|
return publicHttp.post("delete-material", params);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -121,84 +121,147 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 发起任务弹窗 -->
|
<!-- 发起任务弹窗 -->
|
||||||
<el-dialog v-model="createVisible" title="发起入职任务" width="760px" destroy-on-close>
|
<el-dialog
|
||||||
<el-form :model="form" label-width="90px">
|
v-model="createVisible"
|
||||||
<el-form-item label="所属公司" required>
|
title="发起入职任务"
|
||||||
<el-select
|
width="1050px"
|
||||||
v-model="form.companyId"
|
top="4vh"
|
||||||
filterable
|
destroy-on-close
|
||||||
placeholder="请选择公司主体"
|
append-to-body
|
||||||
class="full-width"
|
class="create-task-dialog"
|
||||||
@change="onCompanyChange"
|
>
|
||||||
>
|
<div class="create-task-dialog-body">
|
||||||
<el-option v-for="item in companies" :key="item.id" :label="item.companyName" :value="item.id" />
|
<el-form :model="form" label-position="top">
|
||||||
</el-select>
|
<!-- 1. 基础岗位选择板块 -->
|
||||||
</el-form-item>
|
<div class="form-card-section">
|
||||||
|
<div class="section-title">
|
||||||
|
<span class="title-text">入职基础信息</span>
|
||||||
|
<span class="title-tip">请选择新员工入职的公司主体、岗位及适用的入职模板</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-form-item label="入职岗位" required>
|
<el-row :gutter="20">
|
||||||
<el-select
|
<el-col :xs="24" :sm="8">
|
||||||
v-model="form.positionId"
|
<el-form-item label="所属公司" required>
|
||||||
filterable
|
<el-select
|
||||||
placeholder="请选择岗位"
|
v-model="form.companyId"
|
||||||
class="full-width"
|
filterable
|
||||||
:disabled="!form.companyId"
|
placeholder="请选择公司主体"
|
||||||
@change="onPositionChange"
|
class="full-width"
|
||||||
>
|
@change="onCompanyChange"
|
||||||
<el-option v-for="item in positions" :key="item.id" :label="item.positionName" :value="item.id" />
|
>
|
||||||
</el-select>
|
<el-option v-for="item in companies" :key="item.id" :label="item.companyName" :value="item.id" />
|
||||||
</el-form-item>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-form-item label="入职模板" required>
|
<el-col :xs="24" :sm="8">
|
||||||
<el-select
|
<el-form-item label="入职岗位" required>
|
||||||
v-model="form.onboardingTemplateId"
|
<el-select
|
||||||
filterable
|
v-model="form.positionId"
|
||||||
placeholder="请选择入职模板"
|
filterable
|
||||||
class="full-width"
|
placeholder="请选择岗位"
|
||||||
:disabled="!form.positionId"
|
class="full-width"
|
||||||
@change="onOnboardingTemplateChange"
|
:disabled="!form.companyId"
|
||||||
>
|
@change="onPositionChange"
|
||||||
<el-option v-for="item in onboardingTemplates" :key="item.id" :label="item.templateName" :value="item.id" />
|
>
|
||||||
</el-select>
|
<el-option v-for="item in positions" :key="item.id" :label="item.positionName" :value="item.id" />
|
||||||
</el-form-item>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<template v-if="form.contractVariables.length">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-divider content-position="left">合同人事参数</el-divider>
|
<el-form-item label="入职模板" required>
|
||||||
<el-alert
|
<el-select
|
||||||
title="以下内容会在候选人查看合同时自动替换到 DOCX 中,请在发送链接前确认。"
|
v-model="form.onboardingTemplateId"
|
||||||
type="warning"
|
filterable
|
||||||
:closable="false"
|
placeholder="请选择入职模板"
|
||||||
class="contract-variable-tip"
|
class="full-width"
|
||||||
/>
|
:disabled="!form.positionId"
|
||||||
<el-form-item
|
@change="onOnboardingTemplateChange"
|
||||||
v-for="item in form.contractVariables"
|
>
|
||||||
:key="`${item.contractTemplateVersionId}-${item.variableCode}`"
|
<el-option v-for="item in onboardingTemplates" :key="item.id" :label="item.templateName" :value="item.id" />
|
||||||
:label="item.variableName"
|
</el-select>
|
||||||
:required="item.required"
|
</el-form-item>
|
||||||
>
|
</el-col>
|
||||||
<el-date-picker
|
</el-row>
|
||||||
v-if="item.dataType === 'date'"
|
</div>
|
||||||
v-model="item.variableValue"
|
|
||||||
type="date"
|
<!-- 2. 合同人事参数卡片 -->
|
||||||
value-format="YYYY-MM-DD"
|
<div v-if="form.contractVariables.length" class="form-card-section">
|
||||||
placeholder="请选择日期"
|
<div class="section-title">
|
||||||
class="full-width"
|
<span class="title-text">合同人事参数预设</span>
|
||||||
|
<span class="title-tip">以下参数将自动替换进 DOCX 合同中,请在向员工发送链接前核对填写</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-alert
|
||||||
|
title="提示:此处填写的内容将作为合同正式条款,如薪资、合同起止日期、试用期等,请谨慎填写。"
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
style="margin-bottom: 16px;"
|
||||||
/>
|
/>
|
||||||
<el-input
|
|
||||||
v-else
|
|
||||||
v-model="item.variableValue"
|
|
||||||
:placeholder="`${item.contractName} · ${item.variableCode}`"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-form-item label="人事备注">
|
<el-row :gutter="20">
|
||||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="填写该候选人入职的相关备注(选填)" />
|
<el-col
|
||||||
</el-form-item>
|
v-for="item in form.contractVariables"
|
||||||
</el-form>
|
:key="`${item.contractTemplateVersionId}-${item.variableCode}`"
|
||||||
|
:xs="24"
|
||||||
|
:sm="12"
|
||||||
|
>
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<div class="var-label-row">
|
||||||
|
<span v-if="item.required" class="required-star">*</span>
|
||||||
|
<span class="var-name">{{ item.variableName }}</span>
|
||||||
|
<el-tag size="small" type="info" effect="plain" class="contract-source-tag">
|
||||||
|
{{ item.contractName }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-date-picker
|
||||||
|
v-if="item.dataType === 'date'"
|
||||||
|
v-model="item.variableValue"
|
||||||
|
type="date"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
placeholder="选择日期"
|
||||||
|
class="var-input-field"
|
||||||
|
/>
|
||||||
|
<el-input-number
|
||||||
|
v-else-if="item.dataType === 'number' || item.dataType === 'decimal'"
|
||||||
|
v-model="item.variableValue"
|
||||||
|
controls-position="right"
|
||||||
|
class="var-input-field"
|
||||||
|
placeholder="输入金额或数值"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-else
|
||||||
|
v-model="item.variableValue"
|
||||||
|
:placeholder="`请输入${item.variableName}`"
|
||||||
|
class="var-input-field"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. 其他备注 -->
|
||||||
|
<div class="form-card-section">
|
||||||
|
<div class="section-title">
|
||||||
|
<span class="title-text">补充备注</span>
|
||||||
|
<span class="title-tip">填写该候选人入职的相关流转备注(仅人事可见,选填)</span>
|
||||||
|
</div>
|
||||||
|
<el-form-item label="">
|
||||||
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入人事备注说明(选填)" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="createVisible = false">取消</el-button>
|
<el-button @click="createVisible = false">取消</el-button>
|
||||||
<el-button type="primary" :loading="creating" @click="createTask">立即创建</el-button>
|
<el-button type="primary" :loading="creating" @click="createTask">立即发起入职</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
@@ -242,23 +305,32 @@
|
|||||||
<el-drawer
|
<el-drawer
|
||||||
v-model="detailVisible"
|
v-model="detailVisible"
|
||||||
:title="`入职任务详情 · ${detail?.task?.taskNo || ''}`"
|
:title="`入职任务详情 · ${detail?.task?.taskNo || ''}`"
|
||||||
size="860px"
|
size="1180px"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
@closed="clearMaterialPreviews"
|
||||||
>
|
>
|
||||||
<div v-if="detail" class="drawer-content">
|
<div v-if="detail" class="drawer-content">
|
||||||
<!-- 头部状态栏 -->
|
<!-- 头部状态栏 (100% 满宽卡片) -->
|
||||||
<div class="drawer-status-bar">
|
<div class="drawer-status-banner">
|
||||||
<div class="status-left">
|
<div class="banner-left">
|
||||||
<span class="task-no-large">{{ detail.task.taskNo }}</span>
|
<div class="banner-title-row">
|
||||||
<el-tag :type="statusType(detail.task.taskStatus)" size="large" effect="dark">
|
<span class="task-no-large">{{ detail.task.taskNo }}</span>
|
||||||
{{ statusText(detail.task.taskStatus) }}
|
<el-tag :type="statusType(detail.task.taskStatus)" size="large" effect="dark">
|
||||||
</el-tag>
|
{{ statusText(detail.task.taskStatus) }}
|
||||||
<span v-if="detail.task.submitCount > 0" class="submit-count-badge">
|
</el-tag>
|
||||||
第 {{ detail.task.submitCount }} 次提交
|
<span v-if="detail.task.submitCount > 0" class="submit-count-badge">
|
||||||
</span>
|
第 {{ detail.task.submitCount }} 次提交
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="banner-meta-row">
|
||||||
|
<span>所属公司:<strong>{{ detail.task.companyName || '-' }}</strong></span>
|
||||||
|
<span>入职岗位:<strong>{{ detail.task.positionName || '-' }}</strong></span>
|
||||||
|
<span>入职模板:<strong>{{ detail.task.onboardingTemplateName || '-' }}</strong></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-right">
|
<div class="banner-right">
|
||||||
<span class="created-time">发起于:{{ formatTime(detail.task.createTime) }}</span>
|
<div class="meta-item">发起时间:{{ formatTime(detail.task.createTime) }}</div>
|
||||||
|
<div v-if="detail.task.linkExpireAt" class="meta-item">链接有效期至:{{ formatTime(detail.task.linkExpireAt) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -275,51 +347,156 @@
|
|||||||
<!-- Tab 切换 -->
|
<!-- Tab 切换 -->
|
||||||
<el-tabs v-model="activeDetailTab" class="detail-tabs">
|
<el-tabs v-model="activeDetailTab" class="detail-tabs">
|
||||||
<!-- 1. 候选人档案与动态信息 -->
|
<!-- 1. 候选人档案与动态信息 -->
|
||||||
<el-tab-pane label="候选人信息" name="profile">
|
<el-tab-pane label="候选人档案 (入职登记表)" name="profile">
|
||||||
<el-card shadow="never" class="mb-4 border-card">
|
<div v-if="!detail.employeeInfo || !detail.employeeInfo.employeeName" class="empty-profile-box">
|
||||||
<template #header>
|
<el-empty description="候选人尚未填写或提交《入职登记表》" :image-size="100" />
|
||||||
<div class="card-header-flex">
|
</div>
|
||||||
<span class="font-bold">基本个人档案</span>
|
|
||||||
<el-tag size="small" type="info">固定信息</el-tag>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-descriptions v-if="detail.employeeInfo" :column="2" border>
|
|
||||||
<el-descriptions-item label="姓名">
|
|
||||||
<span class="font-bold text-primary">{{ detail.employeeInfo.employeeName }}</span>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="性别">{{ detail.employeeInfo.gender || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="手机号码">{{ detail.employeeInfo.phone }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="身份证号码">{{ detail.employeeInfo.idCardNumber }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="毕业院校">{{ detail.employeeInfo.college || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="学历 / 专业">
|
|
||||||
{{ detail.employeeInfo.education || '-' }} / {{ detail.employeeInfo.major || '-' }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="现居地址" :span="2">
|
|
||||||
{{ detail.employeeInfo.contactAddress || '-' }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
<el-empty v-else description="候选人尚未提交基础档案" :image-size="80" />
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- 动态填写字段 -->
|
<div v-else class="profile-details-wrapper">
|
||||||
<el-card shadow="never" class="border-card">
|
<!-- 1. 基本个人档案 -->
|
||||||
<template #header>
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
<div class="card-header-flex">
|
<template #header>
|
||||||
<span class="font-bold">岗位补充登记信息</span>
|
<div class="card-header-flex">
|
||||||
<el-tag size="small" type="info">动态字段</el-tag>
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><UserFilled /></el-icon> 基本个人信息</span>
|
||||||
</div>
|
<el-tag size="small" type="primary">档案标准项</el-tag>
|
||||||
</template>
|
</div>
|
||||||
<el-descriptions v-if="detail.formValues && detail.formValues.length" :column="2" border>
|
</template>
|
||||||
<el-descriptions-item
|
<el-descriptions :column="3" border size="default">
|
||||||
v-for="item in detail.formValues"
|
<el-descriptions-item label="真实姓名">
|
||||||
:key="item.id"
|
<strong class="text-primary font-bold">{{ detail.employeeInfo.employeeName }}</strong>
|
||||||
:label="item.fieldName || item.fieldCode"
|
</el-descriptions-item>
|
||||||
>
|
<el-descriptions-item label="性别">{{ detail.employeeInfo.gender || '-' }}</el-descriptions-item>
|
||||||
{{ item.fieldValue || '-' }}
|
<el-descriptions-item label="民族">{{ detail.employeeInfo.nation || '-' }}</el-descriptions-item>
|
||||||
</el-descriptions-item>
|
<el-descriptions-item label="出生年月日">{{ detail.employeeInfo.birthday || '-' }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
<el-descriptions-item label="户籍所在地" :span="2">{{ detail.employeeInfo.registeredResidence || '-' }}</el-descriptions-item>
|
||||||
<el-empty v-else description="暂无岗位补充字段或未填写" :image-size="80" />
|
<el-descriptions-item label="身高 / 体重">
|
||||||
</el-card>
|
{{ detail.employeeInfo.height ? detail.employeeInfo.height + ' cm' : '-' }} /
|
||||||
|
{{ detail.employeeInfo.weight ? detail.employeeInfo.weight + ' kg' : '-' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="健康状况">{{ detail.employeeInfo.healthCondition || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="婚育情况">{{ detail.employeeInfo.maritalStatus || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="身份证号码" :span="3">
|
||||||
|
<code class="code-font font-bold">{{ detail.employeeInfo.idCardNumber || '-' }}</code>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 2. 学历与职业资质 -->
|
||||||
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><School /></el-icon> 学历与职业资格</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions :column="3" border size="default">
|
||||||
|
<el-descriptions-item label="最高学历">{{ detail.employeeInfo.education || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="所学专业">{{ detail.employeeInfo.major || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="毕业院校">{{ detail.employeeInfo.graduatedSchool || detail.employeeInfo.college || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="职业资格/职称">{{ detail.employeeInfo.vocationalQualification || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="资格等级">{{ detail.employeeInfo.qualificationLevel || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="特长技能">{{ detail.employeeInfo.technicalSpecialty || '-' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 3. 联系方式与银行卡 -->
|
||||||
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><Phone /></el-icon> 联系方式与工资银行卡</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions :column="3" border size="default">
|
||||||
|
<el-descriptions-item label="联系电话">{{ detail.employeeInfo.phone || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="电子邮箱" :span="2">{{ detail.employeeInfo.email || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="现居住详细地址" :span="2">{{ detail.employeeInfo.currentAddress || detail.employeeInfo.contactAddress || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="房东联系方式">{{ detail.employeeInfo.landlordContact || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="工资银行卡号" :span="2">
|
||||||
|
<code class="code-font font-bold">{{ detail.employeeInfo.bankCardNumber || '-' }}</code>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="开户银行全称">{{ detail.employeeInfo.bankName || '-' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 4. 紧急联系人 -->
|
||||||
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><FirstAidKit /></el-icon> 紧急联系人</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions :column="3" border size="default">
|
||||||
|
<el-descriptions-item label="紧急联系人姓名">{{ detail.employeeInfo.emergencyContact || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="联系电话">{{ detail.employeeInfo.emergencyPhone || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="联系地址">{{ detail.employeeInfo.emergencyAddress || '-' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 5. 教育学习经历 -->
|
||||||
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><Reading /></el-icon> 教育学习经历</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table :data="detailEducationList" border stripe empty-text="未填写教育学习经历">
|
||||||
|
<el-table-column prop="timeRange" label="起止时间" min-width="160" />
|
||||||
|
<el-table-column prop="location" label="学校 / 机构" min-width="200" />
|
||||||
|
<el-table-column prop="content" label="所学专业 / 学习内容" min-width="200" />
|
||||||
|
<el-table-column prop="result" label="学习结果 / 获得学位" min-width="180" />
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 6. 主要工作经历 -->
|
||||||
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><Briefcase /></el-icon> 主要工作经历</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table :data="detailWorkList" border stripe empty-text="未填写工作经历(应届生无记录)">
|
||||||
|
<el-table-column prop="timeRange" label="起止时间" min-width="160" />
|
||||||
|
<el-table-column prop="companyName" label="工作单位" min-width="220" />
|
||||||
|
<el-table-column prop="position" label="担任职务" width="140" />
|
||||||
|
<el-table-column prop="salary" label="薪资待遇" width="120" />
|
||||||
|
<el-table-column prop="leaveReason" label="离职原因" min-width="180" />
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 7. 家庭成员 -->
|
||||||
|
<el-card shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text"><el-icon class="mr-1"><HomeFilled /></el-icon> 家庭成员</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table :data="detailFamilyList" border stripe empty-text="未填写家庭成员">
|
||||||
|
<el-table-column prop="name" label="姓名" width="120" />
|
||||||
|
<el-table-column prop="relationship" label="与本人关系" width="120" />
|
||||||
|
<el-table-column prop="age" label="年龄" width="90" align="center" />
|
||||||
|
<el-table-column prop="company" label="工作单位及职务" min-width="240" />
|
||||||
|
<el-table-column prop="phone" label="联系电话" width="150" />
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 8. 合同专有自定义补充项 (如果有) -->
|
||||||
|
<el-card v-if="detailCustomVars.length" shadow="never" class="mb-3 border-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header-flex">
|
||||||
|
<span class="font-bold card-title-text">合同专属补充信息</span>
|
||||||
|
<el-tag size="small" type="warning">合同专有项</el-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions :column="2" border size="default">
|
||||||
|
<el-descriptions-item
|
||||||
|
v-for="item in detailCustomVars"
|
||||||
|
:key="item.key"
|
||||||
|
:label="item.key"
|
||||||
|
>
|
||||||
|
{{ item.value || '-' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!-- 2. 证件与材料复核画廊 -->
|
<!-- 2. 证件与材料复核画廊 -->
|
||||||
@@ -337,19 +514,16 @@
|
|||||||
>
|
>
|
||||||
<div class="material-img-wrapper">
|
<div class="material-img-wrapper">
|
||||||
<el-image
|
<el-image
|
||||||
|
v-if="isImageMaterial(item) && materialPreviewUrls[item.fileId]"
|
||||||
class="material-thumb"
|
class="material-thumb"
|
||||||
:src="fileDownloadUrl(item.fileId)"
|
:src="materialPreviewUrls[item.fileId]"
|
||||||
:preview-src-list="[fileDownloadUrl(item.fileId)]"
|
|
||||||
fit="cover"
|
fit="cover"
|
||||||
preview-teleported
|
@click="previewImage(item.fileId)"
|
||||||
>
|
/>
|
||||||
<template #error>
|
<div v-else class="material-thumb-placeholder">
|
||||||
<div class="material-thumb-placeholder">
|
<el-icon :size="32"><Document /></el-icon>
|
||||||
<el-icon :size="32"><Document /></el-icon>
|
<span>{{ materialPreviewText(item) }}</span>
|
||||||
<span>文档文件</span>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-image>
|
|
||||||
<div class="material-overlay-status">
|
<div class="material-overlay-status">
|
||||||
<el-tag
|
<el-tag
|
||||||
:type="item.reviewStatus === 'passed' ? 'success' : item.reviewStatus === 'need_supplement' ? 'danger' : 'warning'"
|
:type="item.reviewStatus === 'passed' ? 'success' : item.reviewStatus === 'need_supplement' ? 'danger' : 'warning'"
|
||||||
@@ -367,7 +541,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="material-actions-flex">
|
<div class="material-actions-flex">
|
||||||
<el-button link type="primary" size="small" icon="Download" @click="download(item.fileId)">
|
<el-button
|
||||||
|
v-if="isImageMaterial(item)"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon="View"
|
||||||
|
:disabled="!materialPreviewUrls[item.fileId]"
|
||||||
|
@click="previewImage(item.fileId)"
|
||||||
|
>
|
||||||
|
图片预览
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="primary" size="small" icon="Download" @click="download(item.fileId, item.fileName)">
|
||||||
原件下载
|
原件下载
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
@@ -519,6 +704,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
||||||
|
<el-image-viewer
|
||||||
|
v-if="imageViewerVisible"
|
||||||
|
:url-list="imageViewerUrls"
|
||||||
|
hide-on-click-modal
|
||||||
|
@close="closeImageViewer"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 合同参数弹窗 -->
|
<!-- 合同参数弹窗 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="contractVariablesVisible"
|
v-model="contractVariablesVisible"
|
||||||
@@ -586,7 +778,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="onboardingTask">
|
<script setup lang="ts" name="onboardingTask">
|
||||||
import { ref, reactive, onMounted } from "vue";
|
import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import {
|
import {
|
||||||
DocumentAdd,
|
DocumentAdd,
|
||||||
@@ -632,6 +824,53 @@ const createdTaskInfo = ref<any>(null);
|
|||||||
const detailVisible = ref(false);
|
const detailVisible = ref(false);
|
||||||
const activeDetailTab = ref("profile");
|
const activeDetailTab = ref("profile");
|
||||||
const detail = ref<any>();
|
const detail = ref<any>();
|
||||||
|
const materialPreviewUrls = reactive<Record<number, string>>({});
|
||||||
|
const materialPreviewLoading = reactive<Record<number, boolean>>({});
|
||||||
|
const materialPreviewFailed = reactive<Record<number, boolean>>({});
|
||||||
|
const imageViewerVisible = ref(false);
|
||||||
|
const imageViewerUrls = ref<string[]>([]);
|
||||||
|
|
||||||
|
const imageMimeTypes: Record<string, string> = {
|
||||||
|
bmp: "image/bmp",
|
||||||
|
gif: "image/gif",
|
||||||
|
jpeg: "image/jpeg",
|
||||||
|
jpg: "image/jpeg",
|
||||||
|
png: "image/png",
|
||||||
|
webp: "image/webp"
|
||||||
|
};
|
||||||
|
|
||||||
|
const detailEducationList = computed(() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(detail.value?.employeeInfo?.educationHistoryJson || "[]");
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const detailWorkList = computed(() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(detail.value?.employeeInfo?.workHistoryJson || "[]");
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const detailFamilyList = computed(() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(detail.value?.employeeInfo?.familyMembersJson || "[]");
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const detailCustomVars = computed(() => {
|
||||||
|
try {
|
||||||
|
const obj = JSON.parse(detail.value?.employeeInfo?.customVariablesJson || "{}");
|
||||||
|
return Object.entries(obj).map(([k, v]) => ({ key: k, value: String(v) }));
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const contractVariablesVisible = ref(false);
|
const contractVariablesVisible = ref(false);
|
||||||
const contractVariableTask = ref<OnboardingTask>();
|
const contractVariableTask = ref<OnboardingTask>();
|
||||||
@@ -781,9 +1020,96 @@ const formatTime = (timeStr?: string) => {
|
|||||||
return timeStr.replace("T", " ").substring(0, 19);
|
return timeStr.replace("T", " ").substring(0, 19);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileDownloadUrl = (fileId: number) => {
|
function materialFileSuffix(item: any) {
|
||||||
return `/api/sys/dev/file/download?id=${fileId}`;
|
const suffix = String(item?.fileSuffix || "")
|
||||||
};
|
.trim()
|
||||||
|
.replace(/^\./, "")
|
||||||
|
.toLowerCase();
|
||||||
|
if (suffix) return suffix;
|
||||||
|
|
||||||
|
const fileName = String(item?.fileName || "");
|
||||||
|
const dotIndex = fileName.lastIndexOf(".");
|
||||||
|
return dotIndex >= 0 ? fileName.substring(dotIndex + 1).toLowerCase() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isImageMaterial(item: any) {
|
||||||
|
return Boolean(imageMimeTypes[materialFileSuffix(item)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function materialPreviewText(item: any) {
|
||||||
|
if (!isImageMaterial(item)) return "非图片文件";
|
||||||
|
if (materialPreviewLoading[item.fileId]) return "图片加载中";
|
||||||
|
if (materialPreviewFailed[item.fileId]) return "图片预览加载失败";
|
||||||
|
return "图片待加载";
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeImageViewer() {
|
||||||
|
imageViewerVisible.value = false;
|
||||||
|
imageViewerUrls.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearMaterialPreviews() {
|
||||||
|
Object.values(materialPreviewUrls).forEach(url => URL.revokeObjectURL(url));
|
||||||
|
Object.keys(materialPreviewUrls).forEach(key => delete materialPreviewUrls[Number(key)]);
|
||||||
|
Object.keys(materialPreviewLoading).forEach(key => delete materialPreviewLoading[Number(key)]);
|
||||||
|
Object.keys(materialPreviewFailed).forEach(key => delete materialPreviewFailed[Number(key)]);
|
||||||
|
closeImageViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function previewImage(fileId: number) {
|
||||||
|
const previewUrl = materialPreviewUrls[fileId];
|
||||||
|
if (!previewUrl) {
|
||||||
|
ElMessage.warning("图片正在加载或暂时无法预览");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageViewerUrls.value = [previewUrl];
|
||||||
|
imageViewerVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadMaterialPreviews(materials: any[]) {
|
||||||
|
clearMaterialPreviews();
|
||||||
|
const imageMaterials = (materials || []).filter(isImageMaterial);
|
||||||
|
|
||||||
|
await Promise.all(imageMaterials.map(async item => {
|
||||||
|
materialPreviewLoading[item.fileId] = true;
|
||||||
|
materialPreviewFailed[item.fileId] = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response: any = await onboardingTaskApi.downloadFile(item.fileId);
|
||||||
|
const sourceBlob = response?.data;
|
||||||
|
if (!(sourceBlob instanceof Blob)) {
|
||||||
|
throw new Error("服务器未返回有效的图片文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
const mimeType = imageMimeTypes[materialFileSuffix(item)];
|
||||||
|
const imageBlob = sourceBlob.type.startsWith("image/")
|
||||||
|
? sourceBlob
|
||||||
|
: new Blob([sourceBlob], { type: mimeType });
|
||||||
|
materialPreviewUrls[item.fileId] = URL.createObjectURL(imageBlob);
|
||||||
|
} catch {
|
||||||
|
materialPreviewFailed[item.fileId] = true;
|
||||||
|
} finally {
|
||||||
|
materialPreviewLoading[item.fileId] = false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveDownloadFileName(response: any, fallbackFileName?: string) {
|
||||||
|
const disposition = String(response?.headers?.["content-disposition"] || "");
|
||||||
|
const encodedName = disposition.match(/filename\*=UTF-8\'\'([^;]+)/i)?.[1]
|
||||||
|
|| disposition.match(/filename="?([^";]+)"?/i)?.[1];
|
||||||
|
|
||||||
|
if (encodedName) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(encodedName.replace(/\+/g, "%20"));
|
||||||
|
} catch {
|
||||||
|
return encodedName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackFileName || "入职材料";
|
||||||
|
}
|
||||||
|
|
||||||
// 列表查询并统计
|
// 列表查询并统计
|
||||||
async function getTableData(params: any) {
|
async function getTableData(params: any) {
|
||||||
@@ -922,10 +1248,11 @@ function copyInviteMessage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function showDetail(row: OnboardingTask) {
|
async function showDetail(row: OnboardingTask) {
|
||||||
const { data } = await onboardingTaskApi.detail({ id: row.id });
|
const { data }: any = await onboardingTaskApi.detail({ id: row.id });
|
||||||
detail.value = data;
|
detail.value = data;
|
||||||
activeDetailTab.value = "profile";
|
activeDetailTab.value = "profile";
|
||||||
detailVisible.value = true;
|
detailVisible.value = true;
|
||||||
|
void loadMaterialPreviews(data?.materials || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openContractVariables(row: OnboardingTask) {
|
async function openContractVariables(row: OnboardingTask) {
|
||||||
@@ -988,10 +1315,29 @@ async function generate(taskContractId: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function download(fileId: number) {
|
async function download(fileId: number, fallbackFileName?: string) {
|
||||||
window.open(fileDownloadUrl(fileId), "_blank");
|
try {
|
||||||
|
const response: any = await onboardingTaskApi.downloadFile(fileId);
|
||||||
|
const blob = response?.data;
|
||||||
|
if (!(blob instanceof Blob)) {
|
||||||
|
throw new Error("服务器未返回有效的文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectUrl = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = objectUrl;
|
||||||
|
link.download = resolveDownloadFileName(response, fallbackFileName);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
link.remove();
|
||||||
|
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 0);
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.msg || error?.message || "文件下载失败");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(clearMaterialPreviews);
|
||||||
|
|
||||||
async function reviewMaterial(taskMaterialId: number, reviewStatus: string) {
|
async function reviewMaterial(taskMaterialId: number, reviewStatus: string) {
|
||||||
let reviewRemark = "";
|
let reviewRemark = "";
|
||||||
if (reviewStatus === "need_supplement") {
|
if (reviewStatus === "need_supplement") {
|
||||||
@@ -1257,6 +1603,52 @@ onMounted(loadCompanies);
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.material-img-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #e2e8f0;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-thumb {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-thumb-placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
gap: 8px;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-overlay-status {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-info-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-actions-flex,
|
||||||
|
.review-btn-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.border-pass {
|
.border-pass {
|
||||||
border-color: #10b981;
|
border-color: #10b981;
|
||||||
background: #f0fdf4;
|
background: #f0fdf4;
|
||||||
@@ -1347,4 +1739,150 @@ onMounted(loadCompanies);
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
/* 发起任务大弹窗样式 */
|
||||||
|
.create-task-dialog-body {
|
||||||
|
max-height: 74vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card-section {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #0f172a;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.var-label-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contract-source-tag {
|
||||||
|
font-weight: normal;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required-star {
|
||||||
|
color: #f56c6c;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.var-input-field {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.var-input-field.el-date-editor) {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.var-input-field.el-input-number) {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.var-input-field.el-input-number .el-input__inner) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 详情抽屉顶部横幅与档案卡片样式 */
|
||||||
|
.drawer-status-banner {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-no-large {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-count-badge {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #2563eb;
|
||||||
|
background: #eff6ff;
|
||||||
|
border: 1px solid #bfdbfe;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-meta-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #64748b;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: flex-end;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1e293b;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-1 {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-font {
|
||||||
|
font-family: Consolas, Monaco, monospace;
|
||||||
|
background: #eff6ff;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
+382
-110
@@ -5,10 +5,10 @@
|
|||||||
<div class="brand-content">
|
<div class="brand-content">
|
||||||
<div class="brand-badge">
|
<div class="brand-badge">
|
||||||
<el-icon><Promotion /></el-icon>
|
<el-icon><Promotion /></el-icon>
|
||||||
<span>OnboardX 智能入职系统</span>
|
<span>OnboardX 智能入职服务</span>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="brand-title">欢迎加入我们</h1>
|
<h1 class="brand-title">欢迎加入新团队</h1>
|
||||||
<p class="brand-subtitle">请按照指引完成入职登记表填写、证件材料上传与合同查阅确认</p>
|
<p class="brand-subtitle">请按照 4 步指引完成入职登记表、证件上传与合同查阅确认</p>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -38,15 +38,15 @@
|
|||||||
<div class="wizard-card">
|
<div class="wizard-card">
|
||||||
<div v-if="!canEdit" class="readonly-banner">
|
<div v-if="!canEdit" class="readonly-banner">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="当前为只读查阅模式(资料已提交审核)"
|
title="当前为查阅模式(入职资料已提交审核)"
|
||||||
type="info"
|
type="info"
|
||||||
show-icon
|
show-icon
|
||||||
:closable="false"
|
:closable="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 步骤导航条 -->
|
<!-- 步骤导航条:PC端展示完整步骤,移动端展示紧凑自适应导航 -->
|
||||||
<div class="steps-wrapper">
|
<div class="steps-wrapper desktop-only">
|
||||||
<el-steps :active="currentStep" finish-status="success" align-center>
|
<el-steps :active="currentStep" finish-status="success" align-center>
|
||||||
<el-step title="入职登记表" icon="User" />
|
<el-step title="入职登记表" icon="User" />
|
||||||
<el-step title="合同补充项" icon="Document" />
|
<el-step title="合同补充项" icon="Document" />
|
||||||
@@ -55,18 +55,40 @@
|
|||||||
</el-steps>
|
</el-steps>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mobile-steps-wrapper mobile-only">
|
||||||
|
<div class="mobile-steps-track">
|
||||||
|
<div
|
||||||
|
v-for="(stepName, index) in ['1. 登记表', '2. 补充项', '3. 证件材料', '4. 合同确认']"
|
||||||
|
:key="index"
|
||||||
|
class="mobile-step-item"
|
||||||
|
:class="{
|
||||||
|
'is-active': currentStep === index,
|
||||||
|
'is-finished': currentStep > index,
|
||||||
|
'is-pending': currentStep < index
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="step-indicator-bar" />
|
||||||
|
<span class="step-label">{{ stepName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mobile-current-indicator">
|
||||||
|
当前进行:<span class="highlight-step">第 {{ currentStep + 1 }}/4 步 · {{ ['入职登记表填写', '合同专有补充项', '证件材料上传', '合同查阅与确认'][currentStep] }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 步骤 1: 入职登记表 -->
|
<!-- 步骤 1: 入职登记表 -->
|
||||||
<div v-show="currentStep === 0" class="step-content">
|
<div v-show="currentStep === 0" class="step-content">
|
||||||
<div class="registration-header">
|
<div class="registration-header">
|
||||||
<h2 class="reg-title">入 职 登 记 表</h2>
|
<h2 class="reg-title">入 职 登 记 表</h2>
|
||||||
<p class="reg-subtitle">请准确填写您的真实个人档案、学习经历与家庭信息</p>
|
<p class="reg-subtitle">请准确填写您的真实个人档案、学习经历与家庭信息(带 * 为必填项)</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form ref="regFormRef" :model="form" :rules="regRules" label-position="top" class="reg-form">
|
<el-form ref="regFormRef" :model="form" :rules="regRules" label-position="top" class="reg-form">
|
||||||
<!-- 1. 基本信息板块 -->
|
<!-- 1. 基本信息板块 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-title">
|
<div class="card-section-title">
|
||||||
<el-icon><UserFilled /></el-icon> 基本个人信息
|
<div class="title-icon-box"><el-icon><UserFilled /></el-icon></div>
|
||||||
|
<span>基本个人信息</span>
|
||||||
</div>
|
</div>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
@@ -99,12 +121,12 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="4">
|
<el-col :xs="12" :sm="4">
|
||||||
<el-form-item label="身高(cm)" prop="height">
|
<el-form-item label="身高 (cm)" prop="height">
|
||||||
<el-input v-model="form.height" placeholder="如 175" :disabled="!canEdit" />
|
<el-input v-model="form.height" placeholder="如 175" :disabled="!canEdit" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="4">
|
<el-col :xs="12" :sm="4">
|
||||||
<el-form-item label="体重(kg)" prop="weight">
|
<el-form-item label="体重 (kg)" prop="weight">
|
||||||
<el-input v-model="form.weight" placeholder="如 65" :disabled="!canEdit" />
|
<el-input v-model="form.weight" placeholder="如 65" :disabled="!canEdit" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -135,7 +157,8 @@
|
|||||||
<!-- 2. 学历与资质 -->
|
<!-- 2. 学历与资质 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-title">
|
<div class="card-section-title">
|
||||||
<el-icon><School /></el-icon> 学历与职业资格
|
<div class="title-icon-box"><el-icon><School /></el-icon></div>
|
||||||
|
<span>学历与职业资格</span>
|
||||||
</div>
|
</div>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :xs="12" :sm="8">
|
<el-col :xs="12" :sm="8">
|
||||||
@@ -151,7 +174,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="8">
|
<el-col :xs="12" :sm="8">
|
||||||
<el-form-item label="所学专业" prop="major">
|
<el-form-item label="所学专业" prop="major">
|
||||||
<el-input v-model="form.major" placeholder="请输入专业" :disabled="!canEdit" clearable />
|
<el-input v-model="form.major" placeholder="请输入专业全称" :disabled="!canEdit" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
@@ -160,49 +183,50 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :xs="12" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-form-item label="职业资格" prop="vocationalQualification">
|
<el-form-item label="职业资格/职称" prop="vocationalQualification">
|
||||||
<el-input v-model="form.vocationalQualification" placeholder="如 软考高级 / 注册会计师" :disabled="!canEdit" />
|
<el-input v-model="form.vocationalQualification" placeholder="如 注册会计师/无" :disabled="!canEdit" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="8">
|
<el-col :xs="12" :sm="8">
|
||||||
<el-form-item label="资格等级" prop="qualificationLevel">
|
<el-form-item label="资格等级" prop="qualificationLevel">
|
||||||
<el-input v-model="form.qualificationLevel" placeholder="如 高级 / 中级" :disabled="!canEdit" />
|
<el-input v-model="form.qualificationLevel" placeholder="如 高级/中级/无" :disabled="!canEdit" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="12" :sm="8">
|
||||||
<el-form-item label="有何技术特长" prop="technicalSpecialty">
|
<el-form-item label="特长技能" prop="technicalSpecialty">
|
||||||
<el-input v-model="form.technicalSpecialty" placeholder="专业特长说明" :disabled="!canEdit" />
|
<el-input v-model="form.technicalSpecialty" placeholder="如 驾驶/英语六级" :disabled="!canEdit" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 3. 联系方式与薪酬账户 -->
|
<!-- 3. 联系方式与银行卡 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-title">
|
<div class="card-section-title">
|
||||||
<el-icon><Phone /></el-icon> 通讯地址与薪酬账户
|
<div class="title-icon-box"><el-icon><Phone /></el-icon></div>
|
||||||
|
<span>联系方式与工资银行卡</span>
|
||||||
</div>
|
</div>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-form-item label="联系电话" prop="phone">
|
<el-form-item label="联系电话" prop="phone">
|
||||||
<el-input v-model="form.phone" placeholder="11位手机号码" :disabled="!canEdit" maxlength="11" clearable />
|
<el-input v-model="form.phone" placeholder="手机号码" :disabled="!canEdit" maxlength="11" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-form-item label="电子邮箱" prop="email">
|
<el-form-item label="电子邮箱" prop="email">
|
||||||
<el-input v-model="form.email" placeholder="个人常用电子邮箱" :disabled="!canEdit" clearable />
|
<el-input v-model="form.email" placeholder="常用电子邮箱" :disabled="!canEdit" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-form-item label="暂住 / 现居住地址" prop="currentAddress">
|
<el-form-item label="现居住地址" prop="currentAddress">
|
||||||
<el-input v-model="form.currentAddress" placeholder="现详细居住地址" :disabled="!canEdit" clearable />
|
<el-input v-model="form.currentAddress" placeholder="目前常住的详细地址" :disabled="!canEdit" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-form-item label="房东联系方式" prop="landlordContact">
|
<el-form-item label="房东联系方式" prop="landlordContact">
|
||||||
<el-input v-model="form.landlordContact" placeholder="租房房东姓名及电话(选填)" :disabled="!canEdit" />
|
<el-input v-model="form.landlordContact" placeholder="租房房东姓名及电话 (选填)" :disabled="!canEdit" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
@@ -221,7 +245,8 @@
|
|||||||
<!-- 4. 紧急联系人 -->
|
<!-- 4. 紧急联系人 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-title">
|
<div class="card-section-title">
|
||||||
<el-icon><FirstAidKit /></el-icon> 紧急联系人
|
<div class="title-icon-box"><el-icon><FirstAidKit /></el-icon></div>
|
||||||
|
<span>紧急联系人</span>
|
||||||
</div>
|
</div>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :xs="24" :sm="8">
|
<el-col :xs="24" :sm="8">
|
||||||
@@ -245,26 +270,40 @@
|
|||||||
<!-- 5. 教育学习经历动态列表 -->
|
<!-- 5. 教育学习经历动态列表 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-header">
|
<div class="card-section-header">
|
||||||
<div class="card-section-title"><el-icon><Reading /></el-icon> 教育学习经历</div>
|
<div class="card-section-title">
|
||||||
<el-button v-if="canEdit" size="small" type="primary" plain icon="Plus" @click="addEducation">添加经历</el-button>
|
<div class="title-icon-box"><el-icon><Reading /></el-icon></div>
|
||||||
|
<span>教育学习经历</span>
|
||||||
|
</div>
|
||||||
|
<el-button v-if="canEdit" size="small" type="primary" plain icon="Plus" @click="addEducation">
|
||||||
|
添加经历
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!educationHistory.length" class="empty-hint">暂未添加学习经历</div>
|
<div v-if="!educationHistory.length" class="empty-hint">暂未添加学习经历,可点击右上角添加</div>
|
||||||
<div v-for="(item, idx) in educationHistory" :key="idx" class="dynamic-row-box">
|
<div v-for="(item, idx) in educationHistory" :key="idx" class="dynamic-row-box">
|
||||||
|
<div class="row-badge-header">
|
||||||
|
<span class="row-badge">学习经历 #{{ idx + 1 }}</span>
|
||||||
|
<el-button v-if="canEdit" link type="danger" icon="Delete" @click="educationHistory.splice(idx, 1)">删除本条</el-button>
|
||||||
|
</div>
|
||||||
<el-row :gutter="12">
|
<el-row :gutter="12">
|
||||||
<el-col :xs="24" :sm="6">
|
<el-col :xs="24" :sm="6">
|
||||||
<el-input v-model="item.timeRange" placeholder="时间 (如 2018.09-2022.06)" :disabled="!canEdit" />
|
<el-form-item label="时间范围">
|
||||||
|
<el-input v-model="item.timeRange" placeholder="如 2018.09-2022.06" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="6">
|
<el-col :xs="24" :sm="6">
|
||||||
<el-input v-model="item.location" placeholder="学校 / 地点" :disabled="!canEdit" />
|
<el-form-item label="学校/机构">
|
||||||
|
<el-input v-model="item.location" placeholder="毕业学校全称" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="6">
|
<el-col :xs="24" :sm="6">
|
||||||
<el-input v-model="item.content" placeholder="学习专业 / 内容" :disabled="!canEdit" />
|
<el-form-item label="专业/学习内容">
|
||||||
|
<el-input v-model="item.content" placeholder="所学专业" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="20" :sm="5">
|
<el-col :xs="24" :sm="6">
|
||||||
<el-input v-model="item.result" placeholder="学习结果 (如 毕业/获学士学位)" :disabled="!canEdit" />
|
<el-form-item label="结果/学位">
|
||||||
</el-col>
|
<el-input v-model="item.result" placeholder="如 毕业/获学士学位" :disabled="!canEdit" />
|
||||||
<el-col :xs="4" :sm="1" class="delete-btn-col">
|
</el-form-item>
|
||||||
<el-button v-if="canEdit" link type="danger" icon="Delete" @click="educationHistory.splice(idx, 1)" />
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
@@ -273,29 +312,45 @@
|
|||||||
<!-- 6. 工作经历动态列表 -->
|
<!-- 6. 工作经历动态列表 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-header">
|
<div class="card-section-header">
|
||||||
<div class="card-section-title"><el-icon><Briefcase /></el-icon> 主要工作经历</div>
|
<div class="card-section-title">
|
||||||
<el-button v-if="canEdit" size="small" type="primary" plain icon="Plus" @click="addWork">添加经历</el-button>
|
<div class="title-icon-box"><el-icon><Briefcase /></el-icon></div>
|
||||||
|
<span>主要工作经历</span>
|
||||||
|
</div>
|
||||||
|
<el-button v-if="canEdit" size="small" type="primary" plain icon="Plus" @click="addWork">
|
||||||
|
添加经历
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!workHistory.length" class="empty-hint">暂未添加工作经历(应届生可留空)</div>
|
<div v-if="!workHistory.length" class="empty-hint">暂未添加工作经历(应届生可留空)</div>
|
||||||
<div v-for="(item, idx) in workHistory" :key="idx" class="dynamic-row-box">
|
<div v-for="(item, idx) in workHistory" :key="idx" class="dynamic-row-box">
|
||||||
|
<div class="row-badge-header">
|
||||||
|
<span class="row-badge">工作经历 #{{ idx + 1 }}</span>
|
||||||
|
<el-button v-if="canEdit" link type="danger" icon="Delete" @click="workHistory.splice(idx, 1)">删除本条</el-button>
|
||||||
|
</div>
|
||||||
<el-row :gutter="12">
|
<el-row :gutter="12">
|
||||||
<el-col :xs="24" :sm="5">
|
<el-col :xs="24" :sm="5">
|
||||||
<el-input v-model="item.timeRange" placeholder="时间 (如 2022.07-2024.05)" :disabled="!canEdit" />
|
<el-form-item label="起止时间">
|
||||||
|
<el-input v-model="item.timeRange" placeholder="如 2022.07-2024.05" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="6">
|
<el-col :xs="24" :sm="6">
|
||||||
<el-input v-model="item.companyName" placeholder="工作单位名称" :disabled="!canEdit" />
|
<el-form-item label="工作单位名称">
|
||||||
|
<el-input v-model="item.companyName" placeholder="公司全称" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="4">
|
<el-col :xs="12" :sm="4">
|
||||||
<el-input v-model="item.salary" placeholder="工资待遇" :disabled="!canEdit" />
|
<el-form-item label="担任职务">
|
||||||
|
<el-input v-model="item.position" placeholder="职位名称" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="4">
|
<el-col :xs="12" :sm="4">
|
||||||
<el-input v-model="item.position" placeholder="担任职务" :disabled="!canEdit" />
|
<el-form-item label="薪资待遇">
|
||||||
|
<el-input v-model="item.salary" placeholder="薪资 (选填)" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="20" :sm="4">
|
<el-col :xs="24" :sm="5">
|
||||||
<el-input v-model="item.leaveReason" placeholder="离职原因" :disabled="!canEdit" />
|
<el-form-item label="离职原因">
|
||||||
</el-col>
|
<el-input v-model="item.leaveReason" placeholder="简述离职原因" :disabled="!canEdit" />
|
||||||
<el-col :xs="4" :sm="1" class="delete-btn-col">
|
</el-form-item>
|
||||||
<el-button v-if="canEdit" link type="danger" icon="Delete" @click="workHistory.splice(idx, 1)" />
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
@@ -304,29 +359,45 @@
|
|||||||
<!-- 7. 家庭成员动态列表 -->
|
<!-- 7. 家庭成员动态列表 -->
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="card-section-header">
|
<div class="card-section-header">
|
||||||
<div class="card-section-title"><el-icon><HomeFilled /></el-icon> 家庭成员</div>
|
<div class="card-section-title">
|
||||||
<el-button v-if="canEdit" size="small" type="primary" plain icon="Plus" @click="addFamily">添加成员</el-button>
|
<div class="title-icon-box"><el-icon><HomeFilled /></el-icon></div>
|
||||||
|
<span>家庭成员</span>
|
||||||
|
</div>
|
||||||
|
<el-button v-if="canEdit" size="small" type="primary" plain icon="Plus" @click="addFamily">
|
||||||
|
添加成员
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!familyMembers.length" class="empty-hint">暂未添加家庭成员信息</div>
|
<div v-if="!familyMembers.length" class="empty-hint">暂未添加家庭成员信息</div>
|
||||||
<div v-for="(item, idx) in familyMembers" :key="idx" class="dynamic-row-box">
|
<div v-for="(item, idx) in familyMembers" :key="idx" class="dynamic-row-box">
|
||||||
|
<div class="row-badge-header">
|
||||||
|
<span class="row-badge">家庭成员 #{{ idx + 1 }}</span>
|
||||||
|
<el-button v-if="canEdit" link type="danger" icon="Delete" @click="familyMembers.splice(idx, 1)">删除本条</el-button>
|
||||||
|
</div>
|
||||||
<el-row :gutter="12">
|
<el-row :gutter="12">
|
||||||
<el-col :xs="12" :sm="4">
|
<el-col :xs="12" :sm="4">
|
||||||
<el-input v-model="item.name" placeholder="姓名" :disabled="!canEdit" />
|
<el-form-item label="姓名">
|
||||||
|
<el-input v-model="item.name" placeholder="成员姓名" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="4">
|
<el-col :xs="12" :sm="4">
|
||||||
<el-input v-model="item.relationship" placeholder="与本人关系" :disabled="!canEdit" />
|
<el-form-item label="关系">
|
||||||
|
<el-input v-model="item.relationship" placeholder="如 父母/配偶" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="12" :sm="3">
|
<el-col :xs="12" :sm="3">
|
||||||
<el-input v-model="item.age" placeholder="年龄" :disabled="!canEdit" />
|
<el-form-item label="年龄">
|
||||||
|
<el-input v-model="item.age" placeholder="年龄" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="7">
|
<el-col :xs="24" :sm="8">
|
||||||
<el-input v-model="item.company" placeholder="工作单位" :disabled="!canEdit" />
|
<el-form-item label="工作单位">
|
||||||
|
<el-input v-model="item.company" placeholder="工作单位及职务" :disabled="!canEdit" />
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="20" :sm="5">
|
<el-col :xs="24" :sm="5">
|
||||||
<el-input v-model="item.phone" placeholder="联系电话" :disabled="!canEdit" />
|
<el-form-item label="联系电话">
|
||||||
</el-col>
|
<el-input v-model="item.phone" placeholder="手机号" :disabled="!canEdit" />
|
||||||
<el-col :xs="4" :sm="1" class="delete-btn-col">
|
</el-form-item>
|
||||||
<el-button v-if="canEdit" link type="danger" icon="Delete" @click="familyMembers.splice(idx, 1)" />
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
@@ -392,7 +463,7 @@
|
|||||||
<el-tag v-if="mat.required" size="small" type="danger" effect="plain">必传</el-tag>
|
<el-tag v-if="mat.required" size="small" type="danger" effect="plain">必传</el-tag>
|
||||||
<el-tag v-else size="small" type="info" effect="plain">选传</el-tag>
|
<el-tag v-else size="small" type="info" effect="plain">选传</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<span class="mat-limit">最多 {{ mat.maxFileCount }} 份,格式:{{ mat.allowedExtensions }}</span>
|
<span class="mat-limit">最多 {{ mat.maxFileCount }} 份 · 格式:{{ mat.allowedExtensions }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="uploaded-files-list">
|
<div class="uploaded-files-list">
|
||||||
@@ -401,7 +472,7 @@
|
|||||||
:key="f.id"
|
:key="f.id"
|
||||||
class="file-badge"
|
class="file-badge"
|
||||||
>
|
>
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon color="#2563eb"><Document /></el-icon>
|
||||||
<span class="file-name">{{ f.fileName || f.materialName }}</span>
|
<span class="file-name">{{ f.fileName || f.materialName }}</span>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canEdit"
|
v-if="canEdit"
|
||||||
@@ -446,13 +517,14 @@
|
|||||||
>
|
>
|
||||||
<div class="contract-card-top">
|
<div class="contract-card-top">
|
||||||
<div class="contract-meta">
|
<div class="contract-meta">
|
||||||
|
<el-icon color="#2563eb" size="20"><Tickets /></el-icon>
|
||||||
<span class="contract-title font-bold">{{ c.contractName }}</span>
|
<span class="contract-title font-bold">{{ c.contractName }}</span>
|
||||||
<el-tag size="small" :type="c.contractStatus === 'confirmed' ? 'success' : 'warning'">
|
<el-tag size="small" :type="c.contractStatus === 'confirmed' ? 'success' : 'warning'">
|
||||||
{{ c.contractStatus === 'confirmed' ? '已阅并同意' : '待查阅确认' }}
|
{{ c.contractStatus === 'confirmed' ? '已阅并同意' : '待查阅确认' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="contract-desc">
|
<div class="contract-desc">
|
||||||
请点击下方按钮下载/查阅带您专属信息的合同全文。
|
请点击下方按钮下载/查阅带您专属信息的合同全文,仔细核对您的基本信息与薪资条款。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -469,6 +541,7 @@
|
|||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-if="canEdit"
|
v-if="canEdit"
|
||||||
v-model="c.isAgreed"
|
v-model="c.isAgreed"
|
||||||
|
class="agree-checkbox"
|
||||||
:label="`我已完整阅读并同意《${c.contractName}》全部条款`"
|
:label="`我已完整阅读并同意《${c.contractName}》全部条款`"
|
||||||
/>
|
/>
|
||||||
<span v-else class="confirmed-text">✓ 候选人已确认同意</span>
|
<span v-else class="confirmed-text">✓ 候选人已确认同意</span>
|
||||||
@@ -479,10 +552,11 @@
|
|||||||
|
|
||||||
<!-- 底部向导操作栏 -->
|
<!-- 底部向导操作栏 -->
|
||||||
<div class="wizard-footer">
|
<div class="wizard-footer">
|
||||||
<el-button v-if="currentStep > 0" @click="currentStep--">上一步</el-button>
|
<el-button v-if="currentStep > 0" size="large" @click="currentStep--">上一步</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="currentStep < 3"
|
v-if="currentStep < 3"
|
||||||
type="primary"
|
type="primary"
|
||||||
|
size="large"
|
||||||
@click="nextStep"
|
@click="nextStep"
|
||||||
>
|
>
|
||||||
下一步
|
下一步
|
||||||
@@ -490,6 +564,7 @@
|
|||||||
<el-button
|
<el-button
|
||||||
v-if="currentStep === 3 && canEdit"
|
v-if="currentStep === 3 && canEdit"
|
||||||
type="success"
|
type="success"
|
||||||
|
size="large"
|
||||||
icon="Check"
|
icon="Check"
|
||||||
:loading="submitting"
|
:loading="submitting"
|
||||||
@click="submitAll"
|
@click="submitAll"
|
||||||
@@ -724,6 +799,7 @@ async function nextStep() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentStep.value++;
|
currentStep.value++;
|
||||||
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMaterialUploadUrl(materialTypeId: number) {
|
function getMaterialUploadUrl(materialTypeId: number) {
|
||||||
@@ -800,186 +876,248 @@ onMounted(load);
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.fill-page {
|
.fill-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f8fafc;
|
background: #f1f5f9;
|
||||||
padding-bottom: 40px;
|
padding-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-header {
|
.brand-header {
|
||||||
background: linear-gradient(135deg, #1e40af, #3b82f6);
|
background: linear-gradient(135deg, #1e3a8a 0%, #2563eb 50%, #38bdf8 100%);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 36px 20px;
|
padding: 40px 20px 48px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-badge {
|
.brand-badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
background: rgba(255, 255, 255, 0.2);
|
background: rgba(255, 255, 255, 0.18);
|
||||||
padding: 4px 12px;
|
backdrop-filter: blur(8px);
|
||||||
|
padding: 5px 14px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-title {
|
.brand-title {
|
||||||
margin: 0 0 8px 0;
|
margin: 0 0 8px 0;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
font-weight: 700;
|
font-weight: 800;
|
||||||
|
letter-spacing: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-subtitle {
|
.brand-subtitle {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
opacity: 0.9;
|
opacity: 0.92;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-container {
|
.main-container {
|
||||||
max-width: 1000px;
|
max-width: 980px;
|
||||||
margin: -24px auto 0;
|
margin: -28px auto 0;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-banner {
|
.status-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 12px 18px;
|
padding: 14px 20px;
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-no {
|
.task-no {
|
||||||
font-weight: bold;
|
font-weight: 700;
|
||||||
margin-right: 10px;
|
color: #1e293b;
|
||||||
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expire-time {
|
.expire-time {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-card {
|
.wizard-card {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 10px;
|
border-radius: 12px;
|
||||||
padding: 24px;
|
padding: 26px 24px;
|
||||||
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
|
box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.steps-wrapper {
|
.steps-wrapper {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
padding: 0 20px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.registration-header {
|
.registration-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 2px solid #e2e8f0;
|
border-bottom: 2px solid #f1f5f9;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reg-title {
|
.reg-title {
|
||||||
letter-spacing: 4px;
|
letter-spacing: 4px;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
color: #1e293b;
|
font-weight: 800;
|
||||||
|
color: #0f172a;
|
||||||
margin: 0 0 6px 0;
|
margin: 0 0 6px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reg-subtitle {
|
.reg-subtitle {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 卡片分区样式 */
|
||||||
.card-section {
|
.card-section {
|
||||||
background: #f8fafc;
|
background: #ffffff;
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
|
border-left: 3px solid #3b82f6;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px 20px;
|
padding: 18px 20px;
|
||||||
margin-bottom: 18px;
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-section-title {
|
.card-section-title {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #0f172a;
|
color: #0f172a;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-icon-box {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background: #eff6ff;
|
||||||
|
color: #2563eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.card-section-header {
|
.card-section-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynamic-row-box {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 14px 16px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.dynamic-row-box {
|
|
||||||
background: #fff;
|
.row-badge-header {
|
||||||
border: 1px solid #cbd5e1;
|
display: flex;
|
||||||
border-radius: 6px;
|
justify-content: space-between;
|
||||||
padding: 10px 12px;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.delete-btn-col {
|
|
||||||
display: flex;
|
.row-badge {
|
||||||
align-items: center;
|
font-size: 12px;
|
||||||
justify-content: center;
|
font-weight: 700;
|
||||||
|
color: #2563eb;
|
||||||
|
background: #eff6ff;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-hint {
|
.empty-hint {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
padding: 8px 0;
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-width {
|
.full-width {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-header {
|
.section-header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
margin: 0 0 6px 0;
|
margin: 0 0 6px 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #0f172a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-desc {
|
.section-desc {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
}
|
}
|
||||||
.all-covered-card {
|
|
||||||
padding: 40px 0;
|
|
||||||
}
|
|
||||||
.materials-grid {
|
.materials-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-item-card {
|
.material-item-card {
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-card-header {
|
.mat-card-header {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-title-box {
|
.mat-title-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-name {
|
.mat-name {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
color: #1e293b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-limit {
|
.mat-limit {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-badge {
|
.file-badge {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 8px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #cbd5e1;
|
border: 1px solid #cbd5e1;
|
||||||
padding: 6px 10px;
|
padding: 8px 12px;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-name {
|
.file-name {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contract-sign-card {
|
.contract-sign-card {
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -987,20 +1125,25 @@ onMounted(load);
|
|||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contract-meta {
|
.contract-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contract-title {
|
.contract-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
color: #0f172a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contract-desc {
|
.contract-desc {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contract-card-bottom {
|
.contract-card-bottom {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1008,14 +1151,143 @@ onMounted(load);
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
border-top: 1px dashed #cbd5e1;
|
border-top: 1px dashed #cbd5e1;
|
||||||
padding-top: 12px;
|
padding-top: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.agree-checkbox {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmed-text {
|
||||||
|
color: #16a34a;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部操作栏吸底优化 */
|
||||||
.wizard-footer {
|
.wizard-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 12px;
|
gap: 14px;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
border-top: 1px solid #e2e8f0;
|
border-top: 1px solid #e2e8f0;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
padding-bottom: max(10px, env(safe-area-inset-bottom));
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-banner {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-only {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-only {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-steps-wrapper {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-steps-track {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-step-item {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-indicator-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #e2e8f0;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-step-item.is-active .step-indicator-bar {
|
||||||
|
background: #2563eb;
|
||||||
|
height: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-step-item.is-finished .step-indicator-bar {
|
||||||
|
background: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #64748b;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-step-item.is-active .step-label {
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-step-item.is-finished .step-label {
|
||||||
|
color: #16a34a;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-current-indicator {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #475569;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px dashed #e2e8f0;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight-step {
|
||||||
|
color: #2563eb;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.desktop-only {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.mobile-only {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
.brand-header {
|
||||||
|
padding: 28px 16px 36px;
|
||||||
|
}
|
||||||
|
.brand-title {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
.main-container {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
.wizard-card {
|
||||||
|
padding: 18px 14px;
|
||||||
|
}
|
||||||
|
.status-banner {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.contract-card-bottom {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user