前端第一版
This commit is contained in:
@@ -0,0 +1,371 @@
|
||||
<template>
|
||||
<div class="table-box">
|
||||
<ProTable
|
||||
ref="proTable"
|
||||
title="正式员工档案"
|
||||
:columns="columns"
|
||||
:request-api="onboardingTaskApi.employeePage"
|
||||
>
|
||||
<template #operation="scope">
|
||||
<el-button link type="primary" icon="UserFilled" @click="showDetail(scope.row)">
|
||||
查看完整档案
|
||||
</el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
|
||||
<!-- 员工完整档案抽屉 -->
|
||||
<el-drawer
|
||||
v-model="detailVisible"
|
||||
:title="`员工档案详情 · ${detail?.employee?.employeeName || ''}`"
|
||||
size="820px"
|
||||
destroy-on-close
|
||||
>
|
||||
<div v-if="detail?.employee" class="employee-drawer-content">
|
||||
<!-- 头部个人简要信息 -->
|
||||
<div class="employee-header-card">
|
||||
<el-avatar :size="64" class="employee-avatar">
|
||||
{{ detail.employee.employeeName ? detail.employee.employeeName.substring(0, 1) : '员' }}
|
||||
</el-avatar>
|
||||
<div class="employee-header-info">
|
||||
<div class="employee-name-row">
|
||||
<span class="employee-name">{{ detail.employee.employeeName }}</span>
|
||||
<el-tag size="small" :type="detail.employee.gender === '女' ? 'danger' : 'primary'" effect="plain">
|
||||
{{ detail.employee.gender || '未知' }}
|
||||
</el-tag>
|
||||
<el-tag size="small" type="success">正式员工</el-tag>
|
||||
</div>
|
||||
<div class="employee-meta-row">
|
||||
<span>员工编号:{{ detail.employee.employeeNo || '-' }}</span>
|
||||
<span>联系电话:{{ detail.employee.phone }}</span>
|
||||
<span>入职日期:{{ detail.employee.entryDate || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="activeTab" class="employee-tabs">
|
||||
<!-- 1. 基本人事档案 -->
|
||||
<el-tab-pane label="基本人事档案" name="basic">
|
||||
<el-card shadow="never" class="section-card">
|
||||
<template #header>
|
||||
<div class="card-header-title">身份与联系信息</div>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="姓名">{{ detail.employee.employeeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">{{ detail.employee.gender || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ detail.employee.phone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="身份证号码">{{ detail.employee.idCardNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出生日期">{{ detail.employee.birthDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="民族">{{ detail.employee.nation || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="户口所在地" :span="2">
|
||||
{{ detail.employee.registeredResidence || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="现居通讯地址" :span="2">
|
||||
{{ detail.employee.contactAddress || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="section-card mt-4">
|
||||
<template #header>
|
||||
<div class="card-header-title">学历与就职信息</div>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="毕业院校">{{ detail.employee.college || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最高学历">{{ detail.employee.education || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所学专业">{{ detail.employee.major || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="部门名称">{{ detail.employee.departmentName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同社保单位">{{ detail.employee.socialInsuranceCompany || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同性质">{{ detail.employee.contractNature || '全职劳动合同' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同开始日期">{{ detail.employee.contractStartDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同终止日期">{{ detail.employee.contractEndDate || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="section-card mt-4">
|
||||
<template #header>
|
||||
<div class="card-header-title">工资卡账户信息</div>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="银行卡号">{{ detail.employee.bankCardNumber || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开户人姓名">{{ detail.employee.bankAccountName || detail.employee.employeeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="工资卡开户行" :span="2">{{ detail.employee.bankName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 2. 归档合同与协议 -->
|
||||
<el-tab-pane label="归档合同协议" name="contracts">
|
||||
<el-empty v-if="!detail.contracts?.length" description="暂无已归档的劳动合同" />
|
||||
<div v-else class="contracts-list">
|
||||
<div v-for="contract in detail.contracts" :key="contract.id" class="contract-box">
|
||||
<div class="contract-info-left">
|
||||
<div class="contract-title font-bold">{{ contract.contractName }}</div>
|
||||
<div class="contract-meta-text text-secondary">
|
||||
<span>状态:{{ contract.contractStatus }}</span>
|
||||
<span v-if="contract.offlineSignedAt">· 线下签署于:{{ formatTime(contract.offlineSignedAt) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contract-action-right">
|
||||
<el-button
|
||||
v-if="contract.generatedDocxFileId"
|
||||
type="primary"
|
||||
plain
|
||||
size="small"
|
||||
icon="Download"
|
||||
@click="download(contract.generatedDocxFileId)"
|
||||
>
|
||||
下载合同 DOCX
|
||||
</el-button>
|
||||
<el-tag v-else type="info">尚未生成电子文件</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 3. 入职流转与审核日志 -->
|
||||
<el-tab-pane label="入职流转时间轴" name="audits">
|
||||
<el-empty v-if="!detail.audits?.length" description="暂无流转记录" />
|
||||
<div v-else class="timeline-box">
|
||||
<el-timeline>
|
||||
<el-timeline-item
|
||||
v-for="item in detail.audits"
|
||||
:key="item.id"
|
||||
type="primary"
|
||||
:timestamp="formatTime(item.auditedAt)"
|
||||
placement="top"
|
||||
>
|
||||
<div class="audit-card">
|
||||
<div class="audit-action-name font-bold">
|
||||
{{ auditActionText(item.auditAction) }}
|
||||
<span v-if="item.createUser" class="audit-operator">(操作人:{{ item.createUser }})</span>
|
||||
</div>
|
||||
<div v-if="item.auditOpinion" class="audit-opinion">
|
||||
审核意见:{{ item.auditOpinion }}
|
||||
</div>
|
||||
</div>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="detailVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="onboardingEmployee">
|
||||
import { ref } from "vue";
|
||||
import { UserFilled, Download } from "@element-plus/icons-vue";
|
||||
import {
|
||||
onboardingTaskApi,
|
||||
type OnboardingEmployee
|
||||
} from "@/api/modules/biz/onboarding";
|
||||
import type { ColumnProps } from "@/components/ProTable/interface";
|
||||
|
||||
const detailVisible = ref(false);
|
||||
const activeTab = ref("basic");
|
||||
const detail = ref<any>();
|
||||
|
||||
const columns: ColumnProps<OnboardingEmployee>[] = [
|
||||
{
|
||||
prop: "employeeNo",
|
||||
label: "员工编号",
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
prop: "employeeName",
|
||||
label: "姓名",
|
||||
minWidth: 140,
|
||||
search: { el: "input" }
|
||||
},
|
||||
{
|
||||
prop: "gender",
|
||||
label: "性别",
|
||||
minWidth: 80,
|
||||
align: "center"
|
||||
},
|
||||
{
|
||||
prop: "phone",
|
||||
label: "手机号码",
|
||||
minWidth: 160,
|
||||
search: { el: "input" }
|
||||
},
|
||||
{
|
||||
prop: "entryDate",
|
||||
label: "入职日期",
|
||||
minWidth: 140
|
||||
},
|
||||
{
|
||||
prop: "createTime",
|
||||
label: "建档时间",
|
||||
minWidth: 180,
|
||||
render: scope => formatTime(scope.row.createTime)
|
||||
},
|
||||
{
|
||||
prop: "operation",
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 160
|
||||
}
|
||||
];
|
||||
|
||||
const auditActionText = (action: string) => {
|
||||
const map: Record<string, string> = {
|
||||
submit: "候选人提交入职资料",
|
||||
approve: "人事复核通过并转正建档",
|
||||
reject: "人事退回补充资料",
|
||||
archive: "任务归档",
|
||||
revoke: "任务撤销"
|
||||
};
|
||||
return map[action] || action;
|
||||
};
|
||||
|
||||
const formatTime = (timeStr?: string) => {
|
||||
if (!timeStr) return "-";
|
||||
return timeStr.replace("T", " ").substring(0, 19);
|
||||
};
|
||||
|
||||
async function showDetail(row: OnboardingEmployee) {
|
||||
const { data } = await onboardingTaskApi.employeeDetail({
|
||||
id: row.id
|
||||
});
|
||||
|
||||
detail.value = data;
|
||||
activeTab.value = "basic";
|
||||
detailVisible.value = true;
|
||||
}
|
||||
|
||||
function download(fileId: number) {
|
||||
window.open(`/api/sys/dev/file/download?id=${fileId}`, "_blank");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.table-search) {
|
||||
margin-bottom: 12px !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.table-main) {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.employee-drawer-content {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.employee-header-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.employee-avatar {
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.employee-header-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.employee-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.employee-name {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.employee-meta-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.section-card {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.card-header-title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.text-secondary {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* 合同列表 */
|
||||
.contracts-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.contract-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.contract-meta-text {
|
||||
font-size: 13px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* 时间轴 */
|
||||
.timeline-box {
|
||||
padding: 16px 8px;
|
||||
}
|
||||
|
||||
.audit-card {
|
||||
background: #f8fafc;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.audit-operator {
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.audit-opinion {
|
||||
font-size: 13px;
|
||||
color: #dc2626;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user