Files
school-developer/src/views/professional/teacherbase/index.vue
zhoutianchi 204c163cc1 人事优化
2026-01-12 16:57:17 +08:00

2940 lines
111 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<search-form
v-show="showSearch"
:model="search"
ref="searchFormRef"
@keyup-enter="handleFilter(search)"
>
<template #default="{ visible }">
<!-- 直接展示的常用筛选条件 -->
<template v-if="visible">
<el-form-item label="姓名" prop="realName">
<el-input
v-model="search.realName"
clearable
placeholder="请输入姓名"
/>
</el-form-item>
<el-form-item label="工号" prop="teacherNo">
<el-input
v-model="search.teacherNo"
clearable
placeholder="请输入工号"
/>
</el-form-item>
<el-form-item label="部门" prop="deptCode">
<el-select
v-model="search.deptCode"
filterable
reserve-keyword
clearable
@change="chooseSecDept"
placeholder="请选择部门"
>
<el-option
v-for="item in secDeptList"
:key="item.deptCode"
:label="item.deptName"
:value="item.deptCode">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="子部门" prop="secDeptCode">
<el-select
v-model="search.secDeptCode"
filterable
reserve-keyword
clearable
placeholder="请选择子部门"
>
<el-option
v-for="item in newSecChildDeptCodeList"
:key="item.deptCode"
:label="item.deptName"
:value="item.deptCode">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="是否退休" prop="tied">
<el-select
v-model="search.tied"
filterable
reserve-keyword
clearable
placeholder="请选择"
>
<el-option
v-for="item in YES_OR_NO"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</template>
<!-- 折叠的高级筛选条件 -->
<template v-if="!visible">
<el-form-item label="退休年份" prop="retireDate">
<el-date-picker
v-model="search.retireDate"
type="year"
format="YYYY"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
placeholder="请选择退休年份"
/>
</el-form-item>
<el-form-item label="职称等级" prop="pfTitleId">
<el-select
v-model="search.pfTitleId"
filterable
reserve-keyword
clearable
placeholder="请选择职称等级"
>
<el-option
v-for="item in baseInfoAbout.proTitleList"
:key="item.id"
:label="item.professionalTitle"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="职务等级" prop="stationDutyLevelId">
<el-select
v-model="search.stationDutyLevelId"
filterable
reserve-keyword
clearable
placeholder="请选择职务等级"
>
<el-option
v-for="item in baseInfoAbout.stationDutyLevelList"
:key="item.id"
:label="item.stationDutyLevelName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="政治面貌" prop="politicsStatus">
<el-select
v-model="search.politicsStatus"
filterable
reserve-keyword
clearable
placeholder="请选择政治面貌"
>
<el-option
v-for="item in searchPoliticsStatusList"
:key="item.id"
:label="item.politicsStatus"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="授课类型" prop="teacherCate">
<el-select
v-model="search.teacherCate"
filterable
reserve-keyword
clearable
placeholder="请选择授课类型"
>
<el-option
v-for="item in searchTeacherCateList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="允许进出" prop="inoutFlag">
<el-select
v-model="search.inoutFlag"
filterable
reserve-keyword
clearable
placeholder="请选择"
>
<el-option
v-for="item in inoutFlagOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</template>
</template>
<!-- 操作按钮始终在最后 -->
<template #actions>
<el-form-item>
<el-button type="primary" @click="handleFilter(search)" icon="Search">查询</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</template>
</search-form>
<!-- 操作按钮 -->
<el-row>
<div class="mb15" style="width: 100%; display: flex; justify-content: space-between; align-items: center;">
<div>
<!-- 主要操作新增 -->
<el-button
type="primary"
icon="FolderAdd"
@click="handleAdd"
v-if="permissions.professional_teacherbase_add">
</el-button>
<!-- 查询操作使用 primary plain 样式统一协调 -->
<!-- <el-button
type="primary"
plain
icon="User"
class="ml10"
v-if="permissions.professional_teacherbase_status_lock"
@click="handelQuickSeach(4)">双师
</el-button> -->
<!-- 设置操作使用默认样式中性灰色 -->
<el-button
icon="Lock"
class="ml10"
v-if="permissions.professional_teacherbase_status_lock"
@click="dialogVisible.statusDialogFormVisible=true">状态锁定
</el-button>
<!-- 导出操作使用 warning plain 样式橙色边框表示数据导出 -->
<el-button
type="warning"
plain
icon="Download"
class="ml10"
v-if="permissions.professional_teacherbase_export"
@click="handleDownLoadWord('')"
:loading="exportLoading">导出WORD
</el-button>
<el-button
type="warning"
plain
icon="Download"
class="ml10"
v-if="permissions.professional_teacherbase_export"
@click="handleExportDialog"
:loading="exportLoading">自定义导出
</el-button>
<!-- 导入操作使用 primary plain 样式蓝色边框保持项目默认样式 -->
<el-button
type="primary"
plain
icon="UploadFilled"
class="ml10"
v-if="permissions.professional_teacherinfo_import"
@click="handleImportDialog"
:loading="exportLoading">导入信息
</el-button>
</div>
<!-- 列显示控制 - 使用自动提取靠右显示 -->
<TableColumnControl
ref="tableColumnControlRef"
:table-ref="tableRef"
v-model="visibleTableColumns"
storage-key="teacherbase-table-columns"
trigger-type="default"
trigger-link
>
</TableColumnControl>
</div>
</el-row>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
v-loading="state.loading"
border
>
<!-- 调试检查 tableRef -->
<!-- tableRef 会在组件挂载后自动赋值 -->
<!-- <TableColumn type="index" label="序号" width="60" align="center" /> -->
<TableColumnProvider :is-column-visible="isColumnVisible">
<TableColumn prop="tied" label="是否退休" width="100" align="center">
<template #default="scope">
<StatusTag
:value="scope.row.tied"
:options="YES_OR_NO"
/>
</template>
</TableColumn>
<TableColumn label="姓名/工号" min-width="150" align="center" fixed>
<template #default="scope">
<TeacherNameNo :name="scope.row.realName" :no="scope.row.teacherNo" />
</template>
</TableColumn>
<TableColumn prop="sex" label="性别" width="80" align="center">
<template #default="scope">
<GenderTag :sex="scope.row.sex" />
</template>
</TableColumn>
<TableColumn prop="deptName" label="部门" width="150" align="center" show-overflow-tooltip />
<TableColumn prop="dgreeName" label="学历学位" width="120" align="center" show-overflow-tooltip />
<TableColumn prop="titleName" label="职称等级" width="120" align="center" show-overflow-tooltip />
<TableColumn prop="stationLevelName" label="岗位级别" width="120" align="center" show-overflow-tooltip />
<TableColumn prop="workLevelName" label="职业资格等级" width="120" align="center" show-overflow-tooltip />
<TableColumn prop="teacherCer" label="教师上岗证" width="120" align="center" show-overflow-tooltip />
<TableColumn prop="midCer" label="中等教师资格证" width="150" align="center" show-overflow-tooltip />
<TableColumn prop="highCer" label="高校教师资格证" width="150" align="center" show-overflow-tooltip />
<TableColumn prop="employmentNature" label="用工性质" width="120" align="center" show-overflow-tooltip />
<TableColumn prop="telPhone" label="手机" width="120" align="center" />
<TableColumn prop="homeAddress" label="家庭住址" width="200" align="center" show-overflow-tooltip />
<TableColumn prop="teacherCate" label="授课类型" width="120" align="center" show-overflow-tooltip />
<TableColumn label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: center; flex-wrap: nowrap; white-space: nowrap;">
<el-button
v-if="permissions.professional_teacherbase_edit"
type="primary"
link
icon="Document"
@click="handleEdit(scope.row, scope.$index)">查看
</el-button>
<ActionDropdown
:items="getActionMenuItems(scope.row)"
@command="(command) => handleMoreCommand(command, scope.row, scope.$index)"
/>
</div>
</template>
</TableColumn>
</TableColumnProvider>
</el-table>
<!-- 分页 -->
<pagination
:current="state.pagination?.current"
:size="state.pagination?.size"
:total="state.pagination?.total"
@currentChange="currentChangeHandle"
@sizeChange="sizeChangeHandle"
/>
</div>
<!--1 职工基础信息-->
<el-dialog v-model="dialogFromVisible" width="90%" :title="nowUserInfo.userName" class="employee-info-dialog">
<el-dialog v-model="preImgDialog" title="职称材料" append-to-body>
<div class="contentA">
<viewer :images="preImgUrl">
<auth-img v-for="src in preImgUrl" :authSrc="src.url" :key="src.title" style="width:200px;height:200px;"></auth-img>
</viewer>
</div>
</el-dialog>
<el-tabs v-model="activeName" type="border-card" tab-position="left">
<el-tab-pane label="基本信息" name="first">
<div class="base-info-form">
<el-form ref="baseForm" :model="form" label-width="120px" :rules="mergedRules">
<!-- 子标签页 -->
<el-tabs v-model="subActiveName" type="card" class="sub-tabs">
<!-- 基本信息子标签 -->
<el-tab-pane label="基本信息" name="subBaseInfo">
<!-- 照片区域和基本信息分组 -->
<div class="base-info-layout">
<!-- 左侧照片区域 -->
<div v-if="isAdd==false && imageUrl" class="photo-section">
<div class="photo-wrapper">
<img :src="imageUrl" class="avatar-photo" alt="照片">
</div>
</div>
<!-- 右侧基本信息分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><User /></el-icon>
<span>基本信息</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="姓名" prop="baseInfo.realName">
<el-input
type="text"
v-model="form.baseInfo.realName"
:disabled="isAdd==false"
placeholder="请输入姓名"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="工号" prop="baseInfo.teacherNo">
<el-input
v-model="form.baseInfo.teacherNo"
:disabled="isAdd==false"
placeholder="请输入工号"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="性别" prop="baseInfo.sex">
<el-select clearable disabled v-model="form.baseInfo.sex" placeholder="请选择性别">
<el-option
v-for="item in sexyList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="身份证" prop="baseInfo.idCard">
<el-input
v-model="form.baseInfo.idCard"
:disabled="isAdd==false && auditAll==false"
placeholder="请输入身份证号"
maxlength="18"
@input="handleIdCardInput"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="出生年月" prop="baseInfo.birthday">
<el-input disabled v-model="form.baseInfo.birthday" placeholder="自动计算" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年龄" prop="baseInfo.age">
<el-input disabled v-model="form.baseInfo.age" placeholder="自动计算" />
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<!-- 联系方式分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><Phone /></el-icon>
<span>联系方式</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="手机" prop="baseInfo.telPhone">
<el-input
v-model="form.baseInfo.telPhone"
type="number"
placeholder="请输入手机号"
maxlength="11"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="手机2" prop="baseInfo.telPhoneTwo">
<el-input
v-model="form.baseInfo.telPhoneTwo"
type="number"
placeholder="请输入备用手机号"
maxlength="11"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="宅电">
<el-input
v-model="form.baseInfo.homePhone"
type="number"
placeholder="请输入宅电"
maxlength="20"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 个人资料分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><Document /></el-icon>
<span>个人资料</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="民族" prop="baseInfo.national">
<el-select clearable v-model="form.baseInfo.national" placeholder="请选择民族" style="width: 100%">
<el-option
v-for="item in nationalList"
:key="item.nationCode"
:label="item.nationName"
:value="item.nationCode">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="宗教信仰" prop="baseInfo.religiousBelief">
<el-select clearable v-model="form.baseInfo.religiousBelief" placeholder="请选择宗教信仰" style="width: 100%">
<el-option
v-for="item in religiousBeliefDic"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="健康状况">
<el-select clearable v-model="form.baseInfo.health" placeholder="请选择健康状况" style="width: 100%">
<el-option
v-for="item in healthList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="籍贯" prop="baseInfo.nativePlace">
<el-input v-model="form.baseInfo.nativePlace" placeholder="请输入籍贯" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="出生地">
<el-input
v-model="form.baseInfo.birthPlace"
type="textarea"
:rows="2"
placeholder="请输入出生地"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="特长">
<el-input
v-model="form.baseInfo.speciality"
type="textarea"
:rows="2"
placeholder="请输入特长"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 银行信息分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><CreditCard /></el-icon>
<span>银行信息</span>
</div>
<el-row :gutter="16">
<el-col :span="6" v-if="auditAll=='1'">
<el-form-item label="银行卡号" prop="baseInfo.bankNo" :rules="{required: true, message: '请输入银行卡号', trigger: 'blur'}">
<el-input
v-model="form.baseInfo.bankNo"
type="number"
placeholder="请输入银行卡号"
maxlength="30"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="开户行" prop="baseInfo.bankOpen">
<el-input v-model="form.baseInfo.bankOpen" placeholder="请输入开户行" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="家庭住址" prop="baseInfo.homeAddress">
<el-input
v-model="form.baseInfo.homeAddress"
type="textarea"
:rows="2"
placeholder="请输入家庭住址"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 工作信息分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><Briefcase /></el-icon>
<span>工作信息</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="允许进出">
<el-select v-model="form.baseInfo.inoutFlag" :disabled="auditAll!='1'" placeholder="请选择" style="width: 100%">
<el-option
v-for="item in YES_OR_NO"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="授课类型">
<el-select v-model="form.baseInfo.teacherCate" :disabled="auditAll!='1'" placeholder="请选择授课类型" style="width: 100%">
<el-option
v-for="item in teacherCateList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16" v-if="auditAll=='1'">
<el-col :span="24">
<el-form-item label="进出情况备注">
<el-input
v-model="form.baseInfo.inoutRemarks"
type="textarea"
:rows="3"
placeholder="请输入进出情况备注"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</el-tab-pane>
<!-- 岗位信息子标签 -->
<el-tab-pane label="岗位信息" name="subStation">
<!-- 岗位信息分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><Briefcase /></el-icon>
<span>岗位信息</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="岗位类别" prop="professionalStationRelation.stationTypeId">
<el-select clearable v-model="form.professionalStationRelation.stationTypeId" placeholder="请选择岗位类别" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.stationTypeList"
:key="item.id"
:label="item.typeName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="职务级别" prop="professionalStationRelation.stationDutyLevelId">
<el-select clearable v-model="form.professionalStationRelation.stationDutyLevelId" placeholder="请选择职务级别" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.stationDutyLevelList"
:key="item.id"
:label="item.stationDutyLevelName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="岗位级别" prop="professionalStationRelation.stationLevel">
<el-select clearable v-model="form.professionalStationRelation.stationLevel" placeholder="请选择岗位级别" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.stationLevelList"
:key="item.id"
:label="item.levelName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="在职情况" prop="professionalStationRelation.atStation">
<el-select clearable v-model="form.professionalStationRelation.atStation" placeholder="请选择在职情况" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.atStationList"
:key="item.id"
:label="item.atStationName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="任现职级时间" prop="professionalStationRelation.stationDate">
<el-date-picker
type="date"
v-model="form.professionalStationRelation.stationDate"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
placeholder="请选择时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<!-- 新增时可编辑 编辑时不可编辑 -->
<el-form-item label="部门" prop="professionalStationRelation.deptCodeList">
<el-cascader
:disabled="!isAdd"
v-model="form.professionalStationRelation.deptCodeList"
:options="deptTreeList"
filterable
placeholder="请选择部门"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职务">
<el-input
v-model="form.professionalStationRelation.dutyDesc"
type="textarea"
:rows="2"
placeholder="请输入职务"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 工作时间分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><Clock /></el-icon>
<span>工作时间</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="参加工作时间">
<el-date-picker
type="date"
v-model="form.professionalStationRelation.workDate"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
placeholder="请选择时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="退休时间">
<el-date-picker
type="date"
readonly
v-model="form.professionalStationRelation.retireDate"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
placeholder="自动计算"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6" v-if="isShow">
<el-form-item label="职位类别">
<el-select clearable v-model="form.professionalStationRelation.teacherClassify" placeholder="请选择职位类别" style="width: 100%">
<el-option
v-for="item in teacherClassifyData"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="任现职务时间">
<el-date-picker
type="date"
v-model="form.professionalStationRelation.dutyDate"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
placeholder="请选择时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="进校时间" prop="professionalStationRelation.entrySchoolDate">
<el-date-picker
type="date"
v-model="form.professionalStationRelation.entrySchoolDate"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
placeholder="请选择时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6" v-if="isShow">
<el-form-item label="进编时间" prop="entryDutyDate">
<el-date-picker
type="date"
v-model="form.professionalStationRelation.entryDutyDate"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
placeholder="请选择时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 其他信息分组 -->
<div class="form-section">
<div class="section-title">
<el-icon><Setting /></el-icon>
<span>其他信息</span>
</div>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="用工性质" prop="professionalStationRelation.employmentNature">
<el-select clearable v-model="form.professionalStationRelation.employmentNature" placeholder="请选择用工性质" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.employmentNatureList"
:key="item.id"
:label="item.employmentNatureName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="教师类型">
<el-select clearable v-model="form.professionalStationRelation.teacherType" placeholder="请选择教师类型" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.teacherTypeList"
:key="item.id"
:label="item.typeName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="党支部">
<el-select clearable v-model="form.professionalStationRelation.branchId" disabled placeholder="请选择党支部" style="width: 100%">
<el-option
v-for="item in baseInfoAbout.partBranchList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="备注">
<el-input
v-model="form.baseInfo.remarks"
type="textarea"
:rows="2"
placeholder="请输入备注"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
</el-tab-pane>
<el-tab-pane label="政治面貌" name="politicsPane">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Flag /></el-icon>
<span>政治面貌信息</span>
</div>
<el-button v-if="permissions.politics_edit" type="primary" size="default" @click="handleAddPolitics">
<el-icon><Plus /></el-icon>
<span>新增</span>
</el-button>
</div>
<el-table :data="dataPolitics" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="politicsStatus" label="政治面貌" min-width="120" align="center">
<template #default="scope">
{{ getNameById(searchPoliticsStatusList, scope.row.politicsStatusId || scope.row.politicsStatus, 'politicsStatus') }}
</template>
</el-table-column>
<el-table-column prop="joinTime" label="加入时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.joinTime ? new Date(scope.row.joinTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="correctionTime" label="转正时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.correctionTime ? new Date(scope.row.correctionTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="更新时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.createTime ? new Date(scope.row.createTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center" v-if="permissions.politics_edit">
<template #default="scope">
<el-button type="primary" link @click="handleEditPolitics(scope.row, scope.$index)">
<el-icon><EditPen /></el-icon>
<span>编辑</span>
</el-button>
<el-button type="primary" link @click="handleDeletePolitics(scope.row, scope.$index)">
<el-icon><Delete /></el-icon>
<span>删除</span>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="社会关系" name="third">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Connection /></el-icon>
<span>社会关系信息</span>
</div>
<el-button v-if="permissions.professionalsocial_add" type="primary" size="default" @click="handleAddRelation">
<el-icon><Plus /></el-icon>
<span>新增</span>
</el-button>
</div>
<el-table :data="relationData" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="title" label="称谓" min-width="100" align="center" />
<el-table-column prop="realName" label="姓名" min-width="100" align="center" />
<el-table-column prop="birthday" label="出生年月" min-width="120" align="center">
<template #default="scope">
{{ scope.row.birthday ? new Date(scope.row.birthday).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="politicsStatus" label="政治面貌" min-width="120" align="center">
<template #default="scope">
{{ getNameById(searchPoliticsStatusList, scope.row.politicsStatusId || scope.row.politicsStatus, 'politicsStatus') }}
</template>
</el-table-column>
<el-table-column prop="workStation" label="工作单位及职务" min-width="200" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" v-if="permissions.professionalsocial_edit">
<template #default="scope">
<el-button type="primary" link @click="handleEditRelation(scope.row, scope.$index)">
<el-icon><EditPen /></el-icon>
<span>编辑</span>
</el-button>
<el-button type="primary" link @click="handleDeleteRelation(scope.row, scope.$index)">
<el-icon><Delete /></el-icon>
<span>删除</span>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="学历" name="second">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><School /></el-icon>
<span>学历信息</span>
</div>
</div>
<el-table :data="dataEducation" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="graduateTime" label="毕业时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.graduateTime ? new Date(scope.row.graduateTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="qualificationConfigId" label="学历" min-width="100" align="center">
<template #default="scope">
{{ getNameById(baseInfoAbout.academicQualificationList, scope.row.qualificationConfigId, 'qualificationName') }}
</template>
</el-table-column>
<el-table-column prop="degreeConfigId" label="学位" min-width="100" align="center">
<template #default="scope">
{{ getNameById(baseInfoAbout.degreeList, scope.row.degreeConfigId, 'degreeName') }}
</template>
</el-table-column>
<el-table-column prop="graduateSchool" label="毕业学校" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="major" label="所学专业" min-width="150" align="center" show-overflow-tooltip />
<el-table-column prop="certificateNumber" label="证书编码" min-width="120" align="center" />
<el-table-column label="学历证书" min-width="150" align="center">
<template #default="scope">
<el-button
v-if="scope.row.qiList && scope.row.qiList.length > 0"
type="primary"
link
size="small"
icon="Document"
@click="handlePreviewFiles(scope.row.qiList)"
>查看</el-button>
<span v-else class="text-placeholder">-</span>
</template>
</el-table-column>
<el-table-column label="学位证书" min-width="150" align="center">
<template #default="scope">
<el-button
v-if="scope.row.deList && scope.row.deList.length > 0"
type="primary"
link
size="small"
icon="Document"
@click="handlePreviewFiles(scope.row.deList)"
>查看</el-button>
<span v-else class="text-placeholder">-</span>
</template>
</el-table-column>
<!-- <el-table-column prop="createTime" label="更新时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.createTime ? new Date(scope.row.createTime).toLocaleDateString() : '-' }}
</template>
</el-table-column> -->
</el-table>
</div>
</el-tab-pane>
<!--职称表单-->
<el-tab-pane label="职称" name="fourth">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Medal /></el-icon>
<span>职称信息</span>
</div>
</div>
<el-table :data="proData" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="professionalTitleConfigId" label="职称等级" min-width="120" align="center">
<template #default="scope">
{{ getNameById(baseInfoAbout.proTitleList, scope.row.professionalTitleConfigId, 'professionalTitle') }}
</template>
</el-table-column>
<el-table-column prop="majorStation" label="专业技术职务" min-width="150" align="center">
<template #default="scope">
{{ getNameById(baseInfoAbout.majorStationList, scope.row.majorStation, 'majorStationName') }}
</template>
</el-table-column>
<el-table-column prop="certificateTime" label="取证时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.certificateTime ? new Date(scope.row.certificateTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="inOfficeDate" label="职称任职时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.inOfficeDate ? new Date(scope.row.inOfficeDate).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="certificateNumber" label="证书编号" min-width="120" align="center" />
<el-table-column label="证明材料" min-width="120" align="center">
<template #default="scope">
<el-button
v-if="scope.row.srcList && scope.row.srcList.length > 0"
type="primary"
link
size="small"
icon="Document"
@click="handlePreviewFiles(scope.row.srcList)"
>查看</el-button>
<span v-else class="text-placeholder">-</span>
</template>
</el-table-column>
<!-- <el-table-column prop="createTime" label="更新时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.createTime ? new Date(scope.row.createTime).toLocaleDateString() : '-' }}
</template>
</el-table-column> -->
</el-table>
</div>
</el-tab-pane>
<!--职业资格表单-->
<el-tab-pane label="职业资格" name="five">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Medal /></el-icon>
<span>职业资格信息</span>
</div>
</div>
<el-table :data="workData" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="worker" label="职业工种" min-width="120" align="center">
<template #default="scope">
{{ getNameById(baseInfoAbout.workTypeList, scope.row.worker, 'workName') }}
</template>
</el-table-column>
<el-table-column prop="qualificationConfigId" label="等级" min-width="100" align="center">
<template #default="scope">
{{ getNameById(baseInfoAbout.qualificationList, scope.row.qualificationConfigId, 'levelName') }}
</template>
</el-table-column>
<el-table-column prop="certificateTime" label="取证时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.certificateTime ? new Date(scope.row.certificateTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="certificateNumber" label="证书编号" min-width="120" align="center" />
<el-table-column label="证明材料" min-width="120" align="center">
<template #default="scope">
<el-button
v-if="scope.row.srcList && scope.row.srcList.length > 0"
type="primary"
link
size="small"
icon="Document"
@click="handlePreviewFiles(scope.row.srcList)"
>查看</el-button>
<span v-else class="text-placeholder">-</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="更新时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.createTime ? new Date(scope.row.createTime).toLocaleDateString() : '-' }}
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<!--教师证表单-->
<el-tab-pane label="教师证" name="six">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Files /></el-icon>
<span>教师证信息</span>
</div>
</div>
<el-table :data="zgzData" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="certificateConfId" label="证书名称" min-width="200" align="center">
<template #default="scope">
{{ getNameById(certificateList, scope.row.certificateConfId, 'cretificateName') }}
</template>
</el-table-column>
<el-table-column prop="certificateNumber" label="证书编号" min-width="150" align="center" />
<el-table-column label="证明材料" min-width="120" align="center">
<template #default="scope">
<el-button
v-if="scope.row.srcList && scope.row.srcList.length > 0"
type="primary"
link
size="small"
icon="Document"
@click="handlePreviewFiles(scope.row.srcList)"
>查看</el-button>
<span v-else class="text-placeholder">-</span>
</template>
</el-table-column>
<!-- <el-table-column prop="createTime" label="更新时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.createTime ? new Date(scope.row.createTime).toLocaleDateString() : '-' }}
</template>
</el-table-column> -->
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="岗位变更" name="stationChange">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Switch /></el-icon>
<span>岗位变更信息</span>
</div>
</div>
<el-table :data="stationChange" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="oldDeptName" label="原部门名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="newDeptName" label="现部门名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="changeDate" label="调令日期" min-width="120" align="center">
<template #default="scope">
{{ scope.row.changeDate ? new Date(scope.row.changeDate).toLocaleDateString() : '' }}
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="党员调动" name="partyChange">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Flag /></el-icon>
<span>党员调动信息</span>
</div>
</div>
<el-table :data="partyChange" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="oldBranchName" label="原支部名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="branchName" label="现支部名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="partyFee" label="党费" min-width="100" align="center">
<template #default="scope">
{{ scope.row.partyFee ? scope.row.partyFee.toFixed(2) : '' }}
</template>
</el-table-column>
<el-table-column prop="changeTime" label="变动时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.changeTime ? new Date(scope.row.changeTime).toLocaleDateString() : '' }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="remarks" label="备注" min-width="150" align="center" show-overflow-tooltip />
</el-table>
</div>
</el-tab-pane>
<!--综合表彰-->
<el-tab-pane label="综合表彰" name="teacherHonor">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Medal /></el-icon>
<span>综合表彰信息</span>
</div>
</div>
<el-table :data="honorVOList" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="honor" label="荣誉" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="honorCompany" label="表彰单位" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="year" label="年份" min-width="100" align="center" />
<el-table-column label="证明材料" width="150" align="center">
<template #default="scope">
<el-button
v-if="scope.row.attachment"
type="primary"
link
size="small"
icon="Document"
@click="handlePreviewFiles([{ url: scope.row.attachment, title: '' }])"
>查看</el-button>
<span v-else class="text-placeholder">-</span>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="教师论文" name="nine">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Document /></el-icon>
<span>教师论文信息</span>
</div>
</div>
<el-table :data="paperVOList" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="author" label="作者" min-width="100" align="center" />
<el-table-column prop="secondAuthor" label="第二作者" min-width="100" align="center" />
<el-table-column prop="title" label="论文名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="paperTypeName" label="论文类型" min-width="120" align="center" />
<el-table-column prop="nameOfPublication" label="发表刊物名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="dateOfPublication" label="发表时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.dateOfPublication ? new Date(scope.row.dateOfPublication).toLocaleDateString() : '' }}
</template>
</el-table-column>
<el-table-column prop="publicationsCompetentUnit" label="刊物主办单位" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="publicationsManageUnit" label="刊物主管单位" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="awardingUnit" label="颁奖单位" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="rewardLevel" label="获奖等级" min-width="100" align="center" />
<el-table-column prop="rewardTime" label="获奖时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.rewardTime ? new Date(scope.row.rewardTime).toLocaleDateString() : '' }}
</template>
</el-table-column>
<el-table-column prop="remarks" label="备注" min-width="120" align="center" show-overflow-tooltip />
<el-table-column label="证明材料" width="150" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="openShowEvidence(scope.row)">证明材料</el-button>
<ShowEvidence ref="evidenceDialogRef" :row="edviceForm"></ShowEvidence>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="教材列表" name="ten">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Document /></el-icon>
<span>教材列表信息</span>
</div>
</div>
<el-table :data="materialVOList" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="materialName" label="教材名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="materialTypeName" label="教材类别" min-width="120" align="center" />
<el-table-column prop="editor" label="主编" min-width="100" align="center" />
<el-table-column prop="secondEditor" label="副主编" min-width="100" align="center" />
<el-table-column prop="joinEditor" label="参编" min-width="100" align="center" />
<el-table-column prop="words" label="编写字数(千字)" min-width="120" align="center" />
<el-table-column prop="publishCompany" label="出版单位" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="publishTime" label="出版时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.publishTime ? new Date(scope.row.publishTime).toLocaleDateString() : '' }}
</template>
</el-table-column>
<el-table-column prop="remarks" label="备注" min-width="120" align="center" show-overflow-tooltip />
<el-table-column label="证明材料" width="150" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="openShowEvidence(scope.row)">证明材料</el-button>
<ShowEvidence ref="evidenceDialogRef" :row="edviceForm"></ShowEvidence>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="课题列表" name="eleven">
<div class="table-section">
<div class="table-header">
<div class="table-title">
<el-icon><Document /></el-icon>
<span>课题列表信息</span>
</div>
</div>
<el-table :data="topicListVOList" border stripe class="data-table">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="deptName" label="课题所属部门" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="topicName" label="课题名称" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="topicLeader" label="课题负责人" min-width="120" align="center" />
<el-table-column prop="topicJoiner" label="课题参与人" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="topicSourceName" label="课题来源" min-width="120" align="center" />
<el-table-column prop="topicLevelName" label="级别" min-width="100" align="center" />
<el-table-column prop="finishTime" label="结题时间" min-width="120" align="center">
<template #default="scope">
{{ scope.row.finishTime ? new Date(scope.row.finishTime).toLocaleDateString() : '' }}
</template>
</el-table-column>
<el-table-column prop="awardingUnit" label="颁奖单位" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="awardingLevel" label="获奖等级" min-width="100" align="center" />
<el-table-column prop="remarks" label="备注" min-width="120" align="center" show-overflow-tooltip />
<el-table-column label="证明材料" width="150" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="openShowEvidence(scope.row)">证明材料</el-button>
<ShowEvidence ref="evidenceDialogRef" :row="edviceForm"></ShowEvidence>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
<template #footer>
<div class="dialog-footer">
<el-button
v-if="activeName === 'first'"
type="primary"
@click="saveSubmit"
:disabled="!canSave"
:loading="!canSave">基本信息保存</el-button>
<el-button @click="dialogFromVisible=false"> </el-button>
</div>
</template>
</el-dialog>
<!-- 政治面貌编辑对话框 -->
<PoliticsDialog
v-model="politicsDialogVisible"
:form-data="politicsForm"
:politics-status-list="searchPoliticsStatusList"
@submit="handlePoliticsSubmit"
/>
<!-- 社会关系编辑对话框 -->
<RelationDialog
v-model="relationDialogVisible"
:form-data="relationForm"
:politics-status-list="searchPoliticsStatusList"
@submit="handleRelationSubmit"
/>
<!-- 锁定状态管理对话框 -->
<StatusLockDialog
v-model="dialogVisible.statusDialogFormVisible"
:form-data="statusForm"
:can-edit="permissions.professional_teacherbase_edit"
@submit="handleStatusLockSubmit"
/>
<MultiDialog ref="multiDialogRef" @getList="getDataList" :page="state.pagination" :nowRow="nowRow"></MultiDialog>
<ImportTeacherInfo ref="importTeacherInfoRef"></ImportTeacherInfo>
<ExportTeacherInfoDialog ref="exportTeacherInfoDialogRef" :search="params"></ExportTeacherInfoDialog>
<!-- 证书预览 -->
<preview-file
v-for="src in certificateImgUrl"
:key="src.title || src.url"
:authSrc="src.url"
dialog-title="证书预览"
/>
</div>
</template>
<script setup lang="ts">
// Vue 3 Composition API
import { ref, reactive, computed, watch, onMounted, nextTick, defineAsyncComponent, unref, type Ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { useMessage, useMessageBox } from '/@/hooks/message'
import axios from 'axios'
// 导入图标
import { User, Phone, Document, CreditCard, Briefcase, Flag, Plus, Delete, Connection, School, Medal, Files, Clock, Setting, Switch, CircleCheck, CircleClose, Refresh, Download } from '@element-plus/icons-vue'
// 导入api统一使用 /@/ 路径别名)
import {
fetchList,
getObj,
addObj,
putObj,
addInformation,
getAllInfoAboutList,
updateInout,
exportTeacherInfo as exportTeacherInfoApi
} from '/@/api/professional/professionaluser/teacherbase'
import {getDictsByTypes} from '/@/api/admin/dict'
import {getNationalList} from '/@/api/basic/basicnation'
import {addPoliticssStatus, dePoObj} from '/@/api/professional/professionaluser/professionalpoliticsstatus'
import {addSocialObj, delSocialObj as delSocialObjApi} from '/@/api/professional/professionaluser/professionalsocial'
import {getPoliticsStatusList} from '/@/api/basic/basicpoliticsstatusbase'
import {getTeacherCertificateList} from '/@/api/professional/rsbase/professionalteachercertificateconf'
import {
treeForCascader,
getDeptByCode,
getDeptListByLevelTwo,
getDeptListByParent
} from '/@/api/basic/basicdept'
import {updateStatus} from '/@/api/professional/professionalstatuslock'
import {resetPassWord} from "/@/api/professional/professionaluser/teacherbase"
// 组件配置已不再需要(已从 avue-crud 迁移到 el-table
import global from '/@/components/tools/commondict.vue'
import authImg from "/@/components/tools/auth-img.vue"
// 导入工具
import { Session } from '/@/utils/storage'
// 导入 composables已移除改为通过 TableColumnControl 组件暴露)
// 导入组件(使用 defineAsyncComponent 异步加载,优化性能)
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
const GenderTag = defineAsyncComponent(() => import('/@/components/GenderTag/index.vue'))
const StatusTag = defineAsyncComponent(() => import('/@/components/StatusTag/index.vue'))
const ShowEvidence = defineAsyncComponent(() => import("../common/showEvidence.vue"));
const ExportTeacherInfoDialog = defineAsyncComponent(() => import('./export-teacher-info.vue'));
const ImportTeacherInfo = defineAsyncComponent(() => import('./import-teacherInfo.vue'));
const MultiDialog = defineAsyncComponent(() => import("./multiDialog.vue"));
const PoliticsDialog = defineAsyncComponent(() => import('./politics-dialog.vue'));
const RelationDialog = defineAsyncComponent(() => import('./relation-dialog.vue'));
const StatusLockDialog = defineAsyncComponent(() => import('./status-lock-dialog.vue'));
const ActionDropdown = defineAsyncComponent(() => import('/@/components/tools/action-dropdown.vue'));
const TableColumnControl = defineAsyncComponent(() => import('/@/components/TableColumnControl/index.vue'));
const TableColumn = defineAsyncComponent(() => import('/@/components/TableColumn/index.vue'));
const TableColumnProvider = defineAsyncComponent(() => import('/@/components/TableColumn/Provider.vue'));
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'));
// Pagination 组件已在模板中使用,无需导入(全局组件)
// 导入工具
import {validateNull} from "/@/utils/validate";
import { BasicTableProps, useTable } from '/@/hooks/table';
// 使用 Pinia store
const userInfoStore = useUserInfo()
const { userInfos } = storeToRefs(userInfoStore)
// 创建权限对象,将 authBtnList 转换为 permissions 对象格式
const permissions = computed(() => {
const perms: Record<string, boolean> = {}
userInfos.value.authBtnList.forEach((perm: string) => {
perms[perm] = true
})
return perms
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 响应式数据
const canSave = ref(true)
const nowRow = ref<any>({})
const edviceForm = ref<any>({})
const dialogFromVisible = ref(false)
const searchFormRef = ref()
const showSearch = ref(true)
// 搜索表单数据
const search = reactive({
deptCode: '',
secDeptCode: '',
tied: '',
realName: '',
teacherNo: '',
retireDate: '',
pfTitleId: '',
stationDutyLevelId: '',
politicsStatus: '',
teacherCate: '',
inoutFlag: ''
})
// 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: search, // 将 search 作为 queryForm
createdIsNeed: false, // 不在 onMounted 时自动加载,等 init 完成后再加载
pageList: async (queryParams: any) => {
// 合并额外参数(如 flag、tied
params.value.tied = search.tied
const requestParams = {
...queryParams,
...params.value
}
const response = await fetchList(requestParams)
// 处理数据转换
let records = response.data.record.records
records = convertDictData(records)
// 处理 auditAll
if (response.data.auditAll == '0') {
auditAll.value = false
} else {
auditAll.value = true
}
// 返回 useTable 期望的数据结构:{ data: { records: [...], total: ... } }
return {
...response,
data: {
records: records, // 转换后的数据列表
total: response.data.record.total // 总数
}
}
},
onLoaded: (state: any) => {
// onLoaded 回调,可以在这里进行额外的数据处理
// 数据已经在 pageList 中处理过了
}
})
// 使用 useTable hook
const { getDataList, sizeChangeHandle, currentChangeHandle } = useTable(state)
// 各种option配置这些是静态配置直接使用导入的值
// 响应式数据
const form = reactive<{
baseInfo: any,
professionalStationRelation: any
}>({
baseInfo: {},
professionalStationRelation: {}
})
const healthList = ref([])
const YES_OR_NO = global.YES_OR_NO
const teacherCateList = ref([])
const baseInfoAbout = reactive({
stationTypeList: [],
atStationList: [],
teacherTypeList: [],
partBranchList: [],
employmentNatureList: [],
stationLevelList: [],
stationDutyLevelList: [],
workTypeList: [],
proTitleList: [],
majorStationList: [],
qualificationList: [], // 职业资格等级列表
academicQualificationList: [], // 学历列表
degreeList: []
})
const activeName = ref('')
const subActiveName = ref('subBaseInfo') // 子标签页当前激活的标签
const dialogImageUrl = ref('')
const nationalList = ref([])
const imgList = ref([])
const deptTreeList = ref([])
const relationData = ref([])
const dataEducation = ref([])
const workData = ref([])
const honorVOList = ref([])
const paperVOList = ref([])
const materialVOList = ref([])
const topicListVOList = ref([])
const partyChange = ref([])
const stationChange = ref([])
const proData = ref([])
const zgzData = ref([])
const nowImage = ref("")
const dataPolitics = ref([])
// 表格引用
const tableRef = ref()
// TableColumnControl 组件引用
const tableColumnControlRef = ref()
// 从 TableColumnControl 获取 isColumnVisible 和 visibleTableColumns
const isColumnVisible = (propOrLabel: string) => {
if (tableColumnControlRef.value?.isColumnVisible) {
return tableColumnControlRef.value.isColumnVisible(propOrLabel)
}
// 默认显示所有列(在 TableColumnControl 初始化之前)
return true
}
const visibleTableColumns = ref<string[]>([])
// 静态配置数据
const sexyList = [
{
label: '男',
value: '1'
},
{
label: '女',
value: '0'
}
]
const teacherClassifyData = ref([])
const stationFormValidate = {
stationTypeId: [
{required: true, message: '请选择类别', trigger: 'blur'},
],
stationDutyLevelId: [
{required: true, message: '请选择职务级别', trigger: 'blur'},
],
stationLevel: [
{required: true, message: '请选择岗位级别', trigger: 'blur'},
],
stationDate: [
{required: true, message: '请选择任现岗位职级时间', trigger: 'blur'},
],
atStation: [
{required: true, message: '请选择在职情况', trigger: 'blur'},
],
employmentNature: [
{required: true, message: '请选择用工性质', trigger: 'blur'},
],
entrySchoolDate: [
{required: true, message: '请选进校时间', trigger: 'blur'},
],
deptCodeList: [
{required: true, message: '请选择部门', trigger: 'change'},
{
validator: (rule: any, value: any, callback: any) => {
if (!value || !Array.isArray(value) || value.length === 0) {
callback(new Error('请选择部门'))
} else {
callback()
}
},
trigger: 'change'
}
]
}
const rules = {
realName: [
{required: true, message: '请输入姓名', trigger: 'blur'},
],
telPhone: [
{required: true, message: '请输入正确的电话号码', trigger: 'blur'},
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur'}
],
idCard: [
{required: true, message: '请输入正确身份证', trigger: 'blur'},
{min: 15, max: 18, message: '长度在 15 到 18 个字符', trigger: 'blur'},
{pattern: /^(\d{15}|\d{17}[\dXx])$/, message: '身份证号格式不正确15位或18位18位最后一位可以是X', trigger: 'blur'}
],
telPhoneTwo: [
{required: false, pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur'}
],
bankNo: [
{required: true, message: '请输入银行卡号', trigger: 'blur'},
{pattern: /^\d{16,30}$/, message: '银行卡号格式不正确16-30位数字', trigger: 'blur'},
{min: 16, max: 30, message: '银行卡号长度为 16 到 30 位', trigger: 'blur'}
],
bankOpen: [
{required: true, message: '请输入开户行', trigger: 'blur'}
],
teacherNo: [
{required: true, message: '请输入工号', trigger: 'blur'},
],
national: [
{required: true, message: '请选择民族', trigger: 'change'},
],
religiousBelief:[
{required: true, message: '请选择宗教信仰', trigger: 'change'},
],
homeAddress: [
{required: true, message: '请输入家庭地址', trigger: 'blur'},
],
nativePlace: [
{required: true, message: '请输入籍贯', trigger: 'blur'},
]
}
// 响应式数据
const nowUserInfo = reactive({
userName: '',
teacherNo: '',
uploadUrl: ''
})
const dialogVisible = reactive({
statusDialogFormVisible: false
})
const params = ref<any>({})
const statusForm = reactive({
title: false,
job: true,
teacherTitle: true,
acade: true,
remix: true,
work: true
})
const isAdd = ref(true)
const dialogForListVisible = ref(false)
const dialogForListImageUrl = ref('')
const auditAll = ref(false)
const preImgDialog = ref(false)
const preImgUrl = ref([])
const imageUrl = ref('')
const certificateImgUrl = ref<Array<{ title: string; url: string }>>([]) // 证书预览URL列表
const certificateList = ref<any[]>([]) // 教师资格证列表
const secDeptList = ref([])
const newSecChildDeptCodeList = ref([])
// 搜索条件字典数据
const searchPoliticsStatusList = ref([])
const searchTeacherCateList = ref([])
const inoutFlagOptions = ref([])
const exportLoading = ref(false)
const isShow = ref(false)
const religiousBeliefDic = ref([])
// 模板引用
const baseForm = ref()
const evidenceDialogRef = ref()
const importTeacherInfoRef = ref()
const exportTeacherInfoDialogRef = ref()
const multiDialogRef = ref()
// 合并表单验证规则
const mergedRules = computed(() => {
// 将 baseInfo 的规则加上 baseInfo 前缀
const baseInfoRules: Record<string, any> = {}
Object.keys(rules).forEach(key => {
// 在编辑模式下,某些字段被禁用(如 realName, teacherNo不需要验证
// 根据 isAdd 状态动态调整验证规则
if (isAdd.value) {
// 新增模式:使用原始规则
baseInfoRules[`baseInfo.${key}`] = rules[key]
} else {
// 编辑模式:对于被禁用的字段,移除必填验证
if (key === 'realName' || key === 'teacherNo') {
// 这些字段在编辑模式下被禁用,移除必填验证
const rule = rules[key]
if (Array.isArray(rule)) {
baseInfoRules[`baseInfo.${key}`] = rule.filter((r: any) => !r.required)
} else {
baseInfoRules[`baseInfo.${key}`] = rule
}
} else {
baseInfoRules[`baseInfo.${key}`] = rules[key]
}
}
})
// 岗位信息规则:始终包含所有岗位信息规则,以便在保存时能够验证
const stationRules: Record<string, any> = {}
Object.keys(stationFormValidate).forEach(key => {
stationRules[`professionalStationRelation.${key}`] = stationFormValidate[key]
})
return {
// baseInfo 的规则(加上 baseInfo 前缀)
...baseInfoRules,
// professionalStationRelation 的规则(始终包含)
...stationRules
}
})
// 生命周期
onMounted(async () => {
// 先初始化基础数据
await init()
// 加载搜索条件字典数据
await loadSearchDictData()
// 初始化完成后加载表格数据
getDataList()
})
// 加载搜索条件字典数据
const loadSearchDictData = async () => {
try {
// 加载政治面貌列表
const politicsRes: any = await getPoliticsStatusList()
if (politicsRes && politicsRes.data) {
searchPoliticsStatusList.value = politicsRes.data
}
} catch (error) {
console.error('加载搜索字典数据失败:', error)
}
}
// 暴露方法给模板使用(如果需要)
// watch 监听器
watch(activeName, (val, oldVal) => {
//监听切换状态-计划单
// 从其他标签页切换到非"first"标签页时检查基础信息
// 避免在初始化时触发检查oldVal 为空字符串表示初始化)
// 同时需要确保对话框已打开dialogFromVisible 为 true
if (val != "first" && oldVal && oldVal !== '' && dialogFromVisible.value) {
setTimeout(() => {
if (!form.baseInfo.id || form.baseInfo.id == '') {
message.info("请先完善基础信息")
activeName.value = "first"
}
}, 500)
}
})
watch(() => form.professionalStationRelation.employmentNature, (newVal) => {
if (newVal == '7b89e20d84ded4afe5bd97d9b42c5705'){
isShow.value = true
}else {
isShow.value = false
}
})
// 方法定义
const openShowEvidence = (row: any) => {
edviceForm.value = row
nextTick(() => {
evidenceDialogRef.value?.init()
})
}
const exportTeacherInfo = () => {
const obj = {}
exportTeacherInfoApi(obj).then((res: any) => {
import('/@/excel/Export2Excel.js').then(({ export_json_to_excel }) => {
const tHeader = ['工号', '岗位级别', '姓名', '性别', '学历', '学位', '政治面貌', '出生年月', '参加工作时间',
'专业技术职务', '职称任职时间', '进校时间', '进校年份', '校龄', '职业工种', '等级', '高校职业资格证', '中等教师资格证', '教师上岗证', '家庭住址', '宅电', '手机', '身份证号码'];
const filterVal = ['teacherNo', 'levelName', 'realName', 'sex', 'dgreeName', 'dgreeNameA', 'politicsStatus', 'birthday', 'workDate',
'titleName', 'inOfficeDate', 'entrySchoolDate', 'entryYear', 'schoolYears', 'quaLevelWorkName', 'quaLevelName', 'highCer', 'midCer', 'teacherCer', 'homeAddress', 'homePhone', 'telPhone', 'idCard']
const list = res.data.data
const data = formatJson(filterVal, list);
export_json_to_excel(tHeader, data, '人员信息');
})
})
}
const formatJson = (filterVal: string[], jsonData: any[]) => {
return jsonData.map(v => filterVal.map(j => v[j]))
}
// 获取二级部门树
const fetchSecondTree = () => {
getDeptListByLevelTwo().then(res => {
secDeptList.value = res.data
})
}
const chooseSecDept = () => {
search.secDeptCode = ''
newSecChildDeptCodeList.value = []
getDeptListByParent(search.deptCode).then(res => {
let obj: any = {}
obj.deptName = "--全部子部门--"
obj.deptCode = "-2"
newSecChildDeptCodeList.value.push(obj)
let objA: any = {}
objA.deptName = "--只查父级部门--"
objA.deptCode = "-1"
newSecChildDeptCodeList.value.push(objA)
for (let i in res.data) {
newSecChildDeptCodeList.value.push(res.data[i])
}
})
}
const handleAvatarSuccess = (res: any, file: any) => {
imageUrl.value = URL.createObjectURL(file.raw);
}
// 通用预览函数(用于证书、证明材料等)
const handlePreviewFiles = (list: Array<{ title?: string; url: string }>) => {
certificateImgUrl.value = []
nextTick(() => {
list.forEach(v => {
certificateImgUrl.value.push({
title: v.title || '',
url: v.url
})
})
})
}
const handleStatusLockSubmit = (formData: any) => {
const data = {"statusMap": formData};
updateStatus(data).then((response: any) => {
message.success("修改成功")
// 更新本地状态
Object.assign(statusForm, formData)
}).catch(() => {
// 错误处理
})
}
const handleWaitExam = (row: any, val: any) => {
nowRow.value = row
nextTick(() => {
multiDialogRef.value?.init(val)
})
}
// 获取操作菜单项配置
const getActionMenuItems = (row: any) => {
return [
{
command: 'export',
label: '导出信息',
icon: Download,
visible: () => permissions.value.professional_teacherbase_export
},
{
command: 'personnel-transfer',
label: '人员调动',
icon: Switch,
visible: () => permissions.value.professional_teacherbase_status_lock
},
{
command: 'party-transfer',
label: '党员调动',
icon: Switch,
visible: () => permissions.value.professional_teacherbase_status_lock
},
{
command: 'allow-inout',
label: '允许进出',
icon: CircleCheck,
visible: () => permissions.value.professional_teacherbase_inout && row.inoutFlag == '0'
},
{
command: 'forbid-inout',
label: '禁止进出',
icon: CircleClose,
visible: () => permissions.value.professional_teacherbase_inout && row.inoutFlag == '1'
},
{
command: 'reset-password',
label: '重置密码',
icon: Refresh,
visible: () => permissions.value.professional_teacherbase_resetpw
}
]
}
// 处理更多操作下拉菜单命令
const handleMoreCommand = (command: string, row: any, index: number) => {
switch (command) {
case 'export':
handleDownLoadWord(row.teacherNo)
break
case 'personnel-transfer':
handleWaitExam(row, 5)
break
case 'party-transfer':
handleWaitExam(row, 6)
break
case 'allow-inout':
updateInoutFlag(row, 1)
break
case 'forbid-inout':
updateInoutFlag(row, 0)
break
case 'reset-password':
resetPassword(row)
break
}
}
// 分页处理方法已由 useTable 提供,无需手动实现
// tableRef 已在上面定义(用于 useTableColumns
const exportExcel = (form: any, url: string) => {
return axios({
method: 'post',
url: url,
data: form,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
}
/**
* 基本信息保存
*/
const saveSubmit = () => {
canSave.value = false
if (activeName.value == "first") {
// 构建基本信息需要验证的字段列表(始终包含所有基本信息字段)
const baseInfoFields = Object.keys(rules).map(key => `baseInfo.${key}`)
// 构建岗位信息需要验证的字段列表(始终包含所有岗位信息字段)
const stationFields = Object.keys(stationFormValidate).map(key => `professionalStationRelation.${key}`)
// 根据当前子标签页决定先验证哪个
const currentFields = subActiveName.value === 'subBaseInfo'
? baseInfoFields
: stationFields
const otherFields = subActiveName.value === 'subBaseInfo'
? stationFields
: baseInfoFields
// 先验证当前子标签页的字段
baseForm.value?.validateField(currentFields, (isCurrentValid: boolean, currentInvalidFields: any) => {
if (!isCurrentValid) {
// 当前子标签页验证失败,提示用户
console.log('当前子标签页验证失败的字段:', currentInvalidFields);
if (subActiveName.value === 'subBaseInfo') {
message.info("请完善基本信息");
} else {
message.info("请完善岗位信息");
}
setTimeout(() => {
canSave.value = true
}, 1000)
return
}
// 当前子标签页验证通过,继续验证另一个子标签页
baseForm.value?.validateField(otherFields, (isOtherValid: boolean, otherInvalidFields: any) => {
if (!isOtherValid) {
// 另一个子标签页验证失败,跳转到那个子标签页
console.log('另一个子标签页验证失败的字段:', otherInvalidFields);
if (subActiveName.value === 'subBaseInfo') {
subActiveName.value = 'subStation'
message.info("基本信息已完善,请完善岗位信息");
} else {
subActiveName.value = 'subBaseInfo'
message.info("岗位信息已完善,请完善基本信息");
}
setTimeout(() => {
canSave.value = true
}, 1000)
return
}
// 两个子标签页都验证通过,处理数据并执行保存
// 将 deptCodeList 数组的最后一项赋值给 form.baseInfo.deptCode
if (form.professionalStationRelation.deptCodeList &&
Array.isArray(form.professionalStationRelation.deptCodeList) &&
form.professionalStationRelation.deptCodeList.length > 0) {
form.baseInfo.deptCode = form.professionalStationRelation.deptCodeList[form.professionalStationRelation.deptCodeList.length - 1]
}
addInformation(form).then((response: any) => {
const data = response.data;
message.success('保存成功')
form.baseInfo.id = data.baseId;
form.professionalStationRelation.id = data.relationId;
getDataList()
}).catch((err: any) => {
// 处理业务错误
message.error(err.msg)
});
setTimeout(() => {
canSave.value = true
}, 1000)
})
})
}
}
// getNodeData 方法已移除,如需要请重新实现
// 政治面貌相关
const politicsDialogVisible = ref(false)
const politicsForm = ref<any>({})
const politicsEditIndex = ref(-1)
// 通用函数根据ID从列表中获取名称
const getNameById = (
list: any[] | Ref<any[]>,
id: string | number | undefined,
nameField: string
): string => {
if (!id) return '-'
const listData = unref(list)
if (!Array.isArray(listData)) return '-'
const item = listData.find((item: any) => item.id === id || item.id === String(id))
return item?.[nameField] || '-'
}
// 政治面貌新增
const handleAddPolitics = () => {
politicsForm.value = {}
politicsEditIndex.value = -1
politicsDialogVisible.value = true
}
// 政治面貌编辑
const handleEditPolitics = (row: any, index: number) => {
politicsForm.value = { ...row }
politicsEditIndex.value = index
politicsDialogVisible.value = true
}
// 政治面貌删除
const handleDeletePolitics = (row: any, index: number) => {
messageBox.confirm('确认删除该条记录?').then(() => {
dePoObj(row.id).then(() => {
dataPolitics.value.splice(index, 1)
message.success("删除成功");
}).catch((err: any) => {
// 处理业务错误
message.error(err.msg)
})
}).catch(() => {})
}
// 政治面貌保存
const handlePoliticsSubmit = (data: any) => {
if (!form.baseInfo.id || form.baseInfo.id == '') {
message.info("请完善基础信息");
activeName.value = 'first';
politicsDialogVisible.value = false
return
}
const submitData = { ...data };
submitData.teacherNo = form.baseInfo.teacherNo;
addPoliticssStatus(submitData).then((response: any) => {
message.success("保存成功");
politicsDialogVisible.value = false
// 刷新数据
getObj(form.baseInfo.id).then((res: any) => {
const baseInfo = res.data;
if (!baseInfo) return;
dataPolitics.value = baseInfo.poList;
})
}).catch((err: any) => {
// 处理业务错误
if (err && err.msg) {
message.error(err.msg)
}
});
}
// 社会关系相关
const relationDialogVisible = ref(false)
const relationForm = ref<any>({})
const relationEditIndex = ref(-1)
const handleAddRelation = () => {
relationForm.value = {}
relationEditIndex.value = -1
relationDialogVisible.value = true
}
const handleEditRelation = (row: any, index: number) => {
relationForm.value = { ...row }
relationEditIndex.value = index
relationDialogVisible.value = true
}
const handleDeleteRelation = (row: any, index: number) => {
messageBox.confirm('确认删除该条记录?').then(() => {
delSocialObjApi(row.id).then(() => {
relationData.value.splice(index, 1)
message.success("删除成功");
}).catch((err: any) => {
// 处理业务错误
message.error(err.msg)
})
}).catch(() => {})
}
const handleRelationSubmit = (data: any) => {
if (!form.baseInfo.id || form.baseInfo.id == '') {
message.info("请完善基础信息");
activeName.value = 'first';
relationDialogVisible.value = false
return
}
const submitData = { ...data };
submitData.teacherNo = form.baseInfo.teacherNo;
addSocialObj(submitData).then((response: any) => {
message.success("保存成功");
relationDialogVisible.value = false
// 刷新数据
getObj(form.baseInfo.id).then((res: any) => {
const baseInfo = res.data;
if (!baseInfo) return;
relationData.value = baseInfo.socialList;
})
}).catch((err: any) => {
// 处理业务错误
message.error(err.msg)
})
}
const init = async () => {
// 获取一级部门
fetchSecondTree()
await Promise.all([
// 批量获取字典数据 religious_belief宗教信仰 health健康状况 teacher_cate授课类型 teacher_classify职位类别 yes_no_type是否类型
getDictsByTypes(['religious_belief', 'heath', 'teacher_cate', 'teacher_classify', 'yes_no_type']).then((response: any) => {
religiousBeliefDic.value = response.data.religious_belief;
healthList.value = response.data.heath;
teacherCateList.value = response.data.teacher_cate;
teacherClassifyData.value = response.data.teacher_classify || [];
inoutFlagOptions.value = response.data.yes_no_type || [];
}),
// 民族
getNationalList().then((response: any) => {
nationalList.value = response.data;
}),
// 岗位类型部门树
treeForCascader().then((response: any) => {
deptTreeList.value = response.data;
}),
// 锁定状态列表
// getAllList().then((response: any) => {
// Object.assign(statusForm, response.data)
// }),
getAllInfoAboutList().then((response: any) => {
const map = response.data
baseInfoAbout.stationTypeList = map['stationTypeList']
baseInfoAbout.atStationList = map['atStationList']
baseInfoAbout.teacherTypeList = map['teacherTypeList']
baseInfoAbout.employmentNatureList = map['employmentNatureList']
// 职称等级列表
baseInfoAbout.stationLevelList = map['stationLevelList']
// 职务等级列表
baseInfoAbout.stationDutyLevelList = map['stationDutyLevelList']
baseInfoAbout.workTypeList = map['workTypeList']
baseInfoAbout.proTitleList = map['proTitleList']
baseInfoAbout.majorStationList = map['majorStationList']
// 职业资格等级列表
baseInfoAbout.qualificationList = map['qualificationList'] || []
// 学历列表
baseInfoAbout.academicQualificationList = map['academicQuaList'] || []
// 学位列表
baseInfoAbout.degreeList = map['academicDegreeList'] || []
baseInfoAbout.partBranchList = map['partBranchList']
Object.assign(statusForm, map['allStatusList'])
}),
// 加载教师资格证列表
getTeacherCertificateList().then((response: any) => {
if (response && response.data) {
certificateList.value = response.data
}
})
])
}
// 字典数据转换函数
const convertDictData = (records: any[]) => {
if (!records || records.length === 0) {
return records
}
return records.map((record: any) => {
const newRecord = { ...record }
// 转换职称等级 (pfTitleId -> professionalTitle)
if (newRecord.pfTitleId && baseInfoAbout.proTitleList && baseInfoAbout.proTitleList.length > 0) {
const titleItem = baseInfoAbout.proTitleList.find((item: any) => item.id === newRecord.pfTitleId || item.id === String(newRecord.pfTitleId))
if (titleItem && titleItem.professionalTitle) {
newRecord.professionalTitle = titleItem.professionalTitle
}
}
// 转换职业资格等级 (workId -> levelName, workName)
if (newRecord.workId && baseInfoAbout.qualificationList && baseInfoAbout.qualificationList.length > 0) {
const qualItem = baseInfoAbout.qualificationList.find((item: any) => item.id === newRecord.workId || item.id === String(newRecord.workId))
if (qualItem) {
if (qualItem.levelName) {
newRecord.levelName = qualItem.levelName
}
if (qualItem.workName) {
newRecord.workName = qualItem.workName
}
}
}
// 转换用工性质 (employmentNature -> employmentNatureName)
if (newRecord.employmentNature && baseInfoAbout.employmentNatureList && baseInfoAbout.employmentNatureList.length > 0) {
const empItem = baseInfoAbout.employmentNatureList.find((item: any) => item.id === newRecord.employmentNature || item.id === String(newRecord.employmentNature))
if (empItem && empItem.employmentNatureName) {
newRecord.employmentNatureName = empItem.employmentNatureName
}
}
return newRecord
})
}
// getList 方法已由 useTable 的 getDataList 替代,无需手动实现
/**
* @title 打开新增窗口
* @detail 调用crud的handleadd方法即可
**/
const handleAdd = () => {
nowImage.value = ''
isAdd.value = true
activeName.value = "first";
form.professionalStationRelation = {};
form.baseInfo = {};
dataPolitics.value = [];
dataEducation.value = [];
relationData.value = [];
proData.value = [];
workData.value = [];
dialogFromVisible.value = true;
// 清除表单验证提示
nextTick(() => {
baseForm.value?.clearValidate()
})
}
const handleEdit = (row: any, index: any) => {
isAdd.value = false
nowUserInfo.uploadUrl = '/professional/file/upload?teacherNo=' + row.teacherNo;
nowUserInfo.userName = row.realName;
nowUserInfo.teacherNo = row.teacherNo;
activeName.value = "first";
dialogForListImageUrl.value = ''
imageUrl.value = ''
//查询基础信息
getObj(row.id).then((response: any) => {
const baseInfo = response.data;
if (!baseInfo || !baseInfo.teacherBase) {
console.error('[teacherbase] 获取教师详情失败,返回数据异常:', response);
message.error('获取教师详情失败,请稍后重试');
return;
}
form.baseInfo.teacherPhoto = "";
nowImage.value = baseInfo.teacherBase.teacherPhoto;
imgList.value = [];
form.baseInfo = baseInfo.teacherBase;
dialogForListImageUrl.value = "/professional/minio/show?fileName=base-teach_photo/" + baseInfo.teacherBase.teacherNo + "/" + baseInfo.teacherBase.teacherNo + ".jpg"
imageUrl.value = dialogForListImageUrl.value
dataPolitics.value = baseInfo.poList;
//资格证
zgzData.value = baseInfo.certList;
zgzData.value.forEach((v: any) => {
v.srcList = []
if (v.evidenceA != null) {
const obj: any = {}
obj.url = v.evidenceA
obj.title = ""
v.srcList.push(obj)
}
if (v.evidenceB != null) {
const obj: any = {}
obj.url = v.evidenceB
obj.title = ""
v.srcList.push(obj)
}
})
//学历
dataEducation.value = baseInfo.acadeList
dataEducation.value.forEach((v: any) => {
v.qiList = []
v.deList = []
if (v.qualificationImg != null) {
const obj: any = {}
obj.url = v.qualificationImg
obj.title = ""
v.qiList.push(obj)
}
if (v.degreeImg != null) {
const obj: any = {}
obj.url = v.degreeImg
obj.title = ""
v.deList.push(obj)
}
})
//社会关系
relationData.value = baseInfo.socialList;
//职称
proData.value = baseInfo.titleList
proData.value.forEach((v: any) => {
v.srcList = []
if (v.evidence != null) {
const obj: any = {}
obj.url = v.evidence
obj.title = ""
v.srcList.push(obj)
}
})
//职业
workData.value = baseInfo.quaList
workData.value.forEach((v: any) => {
v.srcList = []
if (v.evidenceA != null) {
const obj: any = {}
obj.url = v.evidenceA
obj.title = ""
v.srcList.push(obj)
}
if (v.evidenceB != null) {
const obj: any = {}
obj.url = v.evidenceB
obj.title = ""
v.srcList.push(obj)
}
if (v.evidenceC != null) {
const obj: any = {}
obj.url = v.evidenceC
obj.title = ""
v.srcList.push(obj)
}
})
//综合表彰
honorVOList.value = baseInfo.honorVOList
//教师论文
paperVOList.value = baseInfo.paperVOList
//教材管理
materialVOList.value = baseInfo.materialVOList
//课题列表
topicListVOList.value = baseInfo.topicListVOList
stationChange.value = baseInfo.stationChangeList
partyChange.value = baseInfo.partyChangeList
if (baseInfo.professionalStationRelation != null) {
form.professionalStationRelation = baseInfo.professionalStationRelation;
} else {
form.professionalStationRelation = {};
}
if (row.deptCode != null && row.deptCode != '') {
getDeptByCode(row.deptCode).then((response: any) => {
const dept = response.data
if (dept) {
form.professionalStationRelation.deptCodeList = [];
form.professionalStationRelation.deptCodeList[0] = dept.parentCode
form.professionalStationRelation.deptCodeList[1] = dept.deptCode
}
dialogFromVisible.value = true
// 清除表单验证提示
nextTick(() => {
baseForm.value?.clearValidate()
})
})
} else {
dialogFromVisible.value = true
// 清除表单验证提示
nextTick(() => {
baseForm.value?.clearValidate()
})
}
});
}
/**
* @title 数据更新
* @param row 为当前的数据
* @param index 为当前更新数据的行数
* @param done 为表单关闭函数
**/
const handleUpdate = (row: any, index: any, done: any) => {
putObj(row).then((data: any) => {
message.success('修改成功')
done()
getDataList()
}).catch((err: any) => {
// 处理业务错误
message.error(err.msg)
})
}
/**
* @title 数据添加
* @param row 为当前的数据
* @param done 为表单关闭函数
**/
const handleSave = (row: any, done: any) => {
addObj(row).then((data: any) => {
message.success('添加成功')
done()
getDataList()
}).catch((err: any) => {
// 处理业务错误
message.error(err.msg)
})
}
//重置密码
const resetPassword = (row: any) => {
messageBox.confirm('是否确定重置密码?').then(() => {
resetPassWord(row).then((data: any) => {
const pw = data.data.data
if (!validateNull(pw)) {
messageBox.info('重置后密码为:' + pw)
} else {
messageBox.info('系统繁忙,请重试')
}
})
}).catch(() => {
});
}
/**
* 刷新回调
*/
const refreshChange = () => {
getDataList()
}
// 重置查询条件
const resetQuery = () => {
searchFormRef.value?.formRef?.resetFields()
search.deptCode = ''
search.secDeptCode = ''
search.tied = ''
search.realName = ''
search.teacherNo = ''
search.retireDate = ''
search.pfTitleId = ''
search.stationDutyLevelId = ''
search.politicsStatus = ''
search.teacherCate = ''
search.inoutFlag = ''
handleFilter(search)
}
const handleFilter = (param: any) => {
params.value = { ...param };
params.value.deptCode = search.deptCode
params.value.secDeptCode = search.secDeptCode
params.value.tied = search.tied
params.value.realName = search.realName
params.value.teacherNo = search.teacherNo
params.value.retireDate = search.retireDate
params.value.pfTitleId = search.pfTitleId
params.value.stationDutyLevelId = search.stationDutyLevelId
params.value.politicsStatus = search.politicsStatus
params.value.teacherCate = search.teacherCate
params.value.inoutFlag = search.inoutFlag
// 重置到第一页并刷新数据
if (state.pagination) {
state.pagination.current = 1
}
getDataList();
}
//照片上传
const handleRemove = (file: any, fileList: any) => {
form.baseInfo.teacherPhoto = "";
}
const handlePictureCardPreview = (file: any) => {
dialogImageUrl.value = file.url;
dialogFromVisible.value = true;
}
const handleRemoveForList = (file: any, fileList: any) => {
console.log(file, fileList);
}
const handlePictureCardPreviewForList = (file: any) => {
dialogForListImageUrl.value = file.url;
dialogForListVisible.value = true;
}
const beforeAvatarUpload = (file: any) => {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
message.error('上传头像图片大小不能超过 1MB!');
}
return isJPG && isLt2M;
}
// 更新进出状态
const updateInoutFlag = (row: any, val: any) => {
const updateParams = {"teacherNo": row.teacherNo, "inoutFlag": val}
messageBox.confirm('确认操作?').then(() => {
updateInout(updateParams).then((res: any) => {
message.success("修改成功")
getDataList()
})
}).catch(() => {
});
}
const handleDownLoadWord = (teacherNo: string) => {
const formData: any = {}
let docName = "";
if(teacherNo){
formData.teacherNo=teacherNo
docName="人事信息.doc"
}else{
if(search.deptCode==''&&search.secDeptCode==''){
message.warning("请选择部门信息")
return
}
formData.deptCode=search.deptCode
formData.secDeptCode=search.secDeptCode
docName="人事信息.zip"
}
exportLoading.value=true
downLoadFile(formData, '/professional/file/exportTeacherBaseInfo').then((res: any) => {
const blob = new Blob([res.data]);
const elink = document.createElement('a');
elink.download =docName;
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
exportLoading.value=false
})
}
const downLoadFile = (form: any, url: string) => {
return axios({
method: 'post',
url: url,
data: form,
responseType: 'blob',
headers: {
'Content-Type': 'application/json',
"Authorization": 'Bearer ' + Session.getToken()
}
})
}
const handleExportDialog = () => {
exportTeacherInfoDialogRef.value?.init()
}
const handleImportDialog = () => {
importTeacherInfoRef.value?.init()
}
// 身份证号输入限制只允许数字和X/x最大长度18
const handleIdCardInput = (value: string) => {
// 只保留数字和X/x
const filtered = value.replace(/[^\dXx]/g, '')
if (filtered !== value) {
form.baseInfo.idCard = filtered
}
}
</script>
<style lang="scss" scoped>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px !important;
display: block;
}
// 基础信息表单样式优化
.base-info-form {
background: #ffffff;
// 基本信息布局(照片+表单)
.base-info-layout {
display: flex;
gap: 18px;
align-items: center;
margin-bottom: 16px;
// 照片区域
.photo-section {
flex-shrink: 0;
.photo-wrapper {
width: 120px;
height: 160px;
border-radius: 8px;
overflow: hidden;
border: 1px solid #e4e7ed;
background: #fafafa;
.avatar-photo {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
}
// 表单区域
.form-section {
flex: 1;
min-width: 0; // 防止 flex 子元素溢出
}
}
// 照片区域(独立显示,当没有表单时)
.photo-section {
display: flex;
justify-content: center;
.photo-wrapper {
width: 120px;
height: 160px;
border-radius: 8px;
overflow: hidden;
border: 1px solid #e4e7ed;
background: #fafafa;
.avatar-photo {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
}
// 子标签页样式优化 - 只优化外层容器,不修改组件内部样式
.sub-tabs {
margin-top: 0;
margin-bottom: 0;
:deep(.el-tab-pane) {
padding: 0;
}
}
// 表单分组样式优化 - 保持当前间距,添加背景
.form-section {
margin-bottom: 16px;
padding: 20px;
background: #fafbfc;
border-radius: 8px;
border: 1px solid #ebeef5;
&:last-child {
margin-bottom: 0;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
padding-bottom: 10px;
border-bottom: 1px solid #e4e7ed;
font-size: 15px;
font-weight: 600;
.el-icon {
margin-right: 8px;
font-size: 16px;
color: var(--el-color-primary);
}
}
// 确保表单项之间有合适的间距(通过外层容器控制)
.el-row {
margin-bottom: 0;
+ .el-row {
margin-top: 18px;
}
}
}
}
// 表格模块样式优化
.table-section {
// padding: 24px;
background: #ffffff;
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
padding-bottom: 14px;
border-bottom: 1px solid #ebeef5;
.table-title {
display: flex;
align-items: center;
font-size: 15px;
font-weight: 600;
color: #303133;
.el-icon {
margin-right: 8px;
font-size: 16px;
color: var(--el-color-primary);
}
}
.el-button {
display: flex;
align-items: center;
gap: 6px;
}
}
.data-table {
// 操作按钮样式
:deep(.el-button--text) {
padding: 4px 8px;
display: inline-flex;
align-items: center;
gap: 4px;
.el-icon {
font-size: 14px;
}
}
}
// 图片列表样式
.image-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
.cert-image {
width: 80px;
height: 50px;
border-radius: 4px;
border: 1px solid #e4e7ed;
object-fit: cover;
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: scale(1.1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
}
}
// 占位符文本
.text-placeholder {
color: #c0c4cc;
font-size: 14px;
}
}
// 弹窗内容区域样式优化 - 只优化外层容器,不修改组件内部样式
.employee-info-dialog {
// 只优化弹窗外层,不修改内部组件样式
}
// 响应式优化
@media (max-width: 1200px) {
.base-info-form {
padding: 20px;
.form-section {
padding: 16px;
margin-bottom: 24px;
.section-title {
font-size: 15px;
margin-bottom: 16px;
}
}
}
}
</style>