Files
school-developer/src/views/professional/professionalqualificationrelation/index.vue
zhoutianchi 37e709cf7e 1
2026-02-06 14:24:42 +08:00

448 lines
14 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="page-cards">
<div class="page-wrapper">
<!-- 筛选卡片 -->
<el-card v-show="showSearch" class="search-card" shadow="never">
<search-form
:model="search"
ref="searchFormRef"
@keyup-enter="handleFilter"
>
<template #default="{ visible }">
<template v-if="visible">
<el-form-item label="审核状态" prop="state">
<el-select
v-model="search.state"
clearable
placeholder="请选择审核状态"
>
<el-option
v-for="item in professionalState"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</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="realName">
<el-input
v-model="search.realName"
clearable
placeholder="请输入姓名"
/>
</el-form-item>
</template>
</template>
<template #actions>
<el-form-item>
<el-button type="primary" @click="handleFilter" icon="Search">查询</el-button>
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
</el-form-item>
</template>
</search-form>
</el-card>
<!-- 列表内容卡片 -->
<el-card class="content-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Medal /></el-icon>
职业资格信息
</span>
<div class="header-actions">
<div class="action-group">
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_add')"
type="primary"
icon="FolderAdd"
@click="handleAdd"
>新增</el-button>
<el-button
v-if="hasAuth('professional_teacherbase_export')"
type="warning"
plain
icon="Download"
@click="handleDownLoadWord"
:loading="exportLoading"
>导出信息</el-button>
<el-button
v-auth="'professional_teacherinfo_import'"
type="primary"
plain
icon="UploadFilled"
:loading="exportLoading"
@click="handleImportDialog"
>导入信息</el-button>
</div>
<div class="header-right">
<RightToolbar
v-model:showSearch="showSearch"
@queryTable="getDataList"
/>
</div>
</div>
</div>
</template>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
row-key="id"
v-loading="state.loading"
border
stripe
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="state" label="审核状态" width="120" align="center">
<template #default="scope">
<AuditState :state="scope.row.state" :options="auditStateOptions" />
</template>
</el-table-column>
<el-table-column label="姓名/工号" min-width="150" align="center">
<template #default="scope">
<TeacherNameNo :name="scope.row.realName" :no="scope.row.teacherNo" />
</template>
</el-table-column>
<el-table-column prop="qualificationConfigId" label="资格等级" min-width="150" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getQualificationLevelName(scope.row.qualificationConfigId) }}
</template>
</el-table-column>
<el-table-column prop="worker" label="工种" min-width="150" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getWorkTypeName(scope.row.worker) }}
</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间" width="180" align="center" />
<el-table-column label="证明材料" width="120" align="center">
<template #default="scope">
<el-button
v-if="scope.row.evidenceA && scope.row.evidenceA !== ''"
type="primary"
link
icon="Document"
@click="handlePreview(scope.row.srcList)">查看
</el-button>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="backReason" label="驳回理由" min-width="150" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="280" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_edit') && (scope.row.state === '0' || scope.row.state === '-2')"
type="primary"
link
icon="edit-pen"
@click="handleEdit(scope.row)">修改
</el-button>
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_exam') && scope.row.canExam"
type="success"
link
icon="CircleCheck"
@click="changeState(scope.row, 1)">通过
</el-button>
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_exam') && scope.row.canDeptExam"
type="success"
link
icon="CircleCheck"
@click="changeState(scope.row, 1)">部门通过
</el-button>
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_exam') && scope.row.canBack"
type="danger"
link
icon="CircleClose"
@click="changeState(scope.row, -2)">驳回
</el-button>
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_exam') && scope.row.canDeptBack"
type="danger"
link
icon="CircleClose"
@click="changeState(scope.row, -2)">部门驳回
</el-button>
<el-button
v-if="hasAuth('professional_professionalqualificationrelation_del')"
type="danger"
link
icon="delete"
style="margin-left: 12px"
@click="handleDel(scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
</el-card>
</div>
<!-- 材料预览图片直接显示PDF 在组件内部 dialog 中显示 -->
<preview-file
v-for="src in imgUrl"
:key="src.title"
:authSrc="src.url"
dialog-title="职业资格材料"
/>
<!-- 子组件 -->
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter" />
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, nextTick } from 'vue'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useAuth } from '/@/hooks/auth'
import { useMessage } from '/@/hooks/message'
import { useMessageBox } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import {
fetchList,
examObj,
delObj} from '/@/api/professional/professionaluser/professionalqualificationrelation'
import { getLevelList } from '/@/api/professional/rsbase/professionalqualificationconfig'
import { getWorkTypeList } from '/@/api/professional/rsbase/professionalworktype'
import { makeExportTeacherInfoByTypeTask } from '/@/api/professional/professionalfile';
import { PROFESSIONAL_AUDIT_STATE_OPTIONS } from '/@/config/global'
import { defineAsyncComponent } from 'vue'
import { Medal } from '@element-plus/icons-vue'
const RightToolbar = defineAsyncComponent(() => import('/@/components/RightToolbar/index.vue'))
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/index.vue'))
const DataForm = defineAsyncComponent(() => import('./form.vue'))
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
// 审核状态选项
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
// 无权限即无节点
const { hasAuth } = useAuth()
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 字典数据
const { professional_state: professionalState } = useDict('professional_state')
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const dataFormRef = ref()
const backReasonRef = ref()
const showSearch = ref(true)
// 搜索表单数据
const search = reactive({
state: '',
teacherNo: '',
realName: ''
})
// 材料预览
const imgUrl = ref<Array<{ title: string; url: string }>>([])
// 导出/导入加载状态
const exportLoading = ref(false)
const importTeacherOtherInfoRef = ref()
// 资格等级和工种列表
const qualificationLevelList = ref<any[]>([])
const workTypeList = ref<any[]>([])
// 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
pageList: async (params: any) => {
const response = await fetchList(params)
const records = response.data.records || []
// 处理证明材料列表
records.forEach((v: any) => {
v.srcList = []
if (v.evidenceA != null) {
v.srcList.push(v.evidenceA)
}
})
return {
data: {
records,
total: response.data.total || 0
}
}
},
queryForm: search
})
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 预览材料
// 预览材料
const handlePreview = (list: string[]) => {
imgUrl.value = []
nextTick(() => {
list.forEach(v => {
imgUrl.value.push({
title: '',
url: v
})
})
})
}
// 审核状态变更
const changeState = (row: any, val: number) => {
if (val === 1) {
// 通过
const str = '通过'
messageBox.confirm(`是否确认${str}${row.realName}的申请`).then(async () => {
try {
await examObj({
id: row.id,
state: val
})
message.success('操作成功')
getDataList()
} catch (error: any) {
// 处理业务错误
message.error(error.msg)
}
}).catch(() => {})
} else if (val === -2) {
// 驳回
backReasonRef.value?.init(row, 'qua')
}
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置查询
const resetQuery = () => {
Object.assign(search, {
state: '',
teacherNo: '',
realName: ''
})
getDataList()
}
// 打开新增窗口
const handleAdd = () => {
dataFormRef.value?.openDialog()
}
// 打开编辑窗口
const handleEdit = (row: any) => {
dataFormRef.value?.openDialog(row)
}
// 删除
const handleDel = (row: any) => {
messageBox.confirm('是否确认删除该条记录').then(async () => {
try {
await delObj(row.id)
message.success('删除成功')
// 如果当前页只剩一条数据,且不是第一页,则跳转到上一页
if (state.pagination && state.dataList && state.dataList.length === 1 && state.pagination.current && state.pagination.current > 1) {
state.pagination.current = state.pagination.current - 1
}
getDataList()
} catch (error: any) {
// 处理业务错误
}
}).catch(() => {})
}
// 导出
const handleDownLoadWord = async () => {
exportLoading.value = true;
let params = Object.assign(search, { type: 'P20003' });
makeExportTeacherInfoByTypeTask(params).then((res: any) => {
message.success('后台下载进行中,请稍后查看任务列表');
});
setTimeout(() => {
exportLoading.value = false;
}, 3000); // 5分钟后自动关闭
};
// 获取资格等级名称
const getQualificationLevelName = (id: string | number) => {
const item = qualificationLevelList.value.find((item: any) => item.id === id)
return item ? item.levelName : '-'
}
// 获取工种名称
const getWorkTypeName = (id: string | number) => {
const item = workTypeList.value.find((item: any) => item.id === id)
return item ? item.workName : '-'
}
// 打开导入弹窗
const handleImportDialog = () => {
importTeacherOtherInfoRef.value?.init('quaRelation')
}
// 加载字典数据
const loadDictData = async () => {
try {
// 加载资格等级列表
const levelRes = await getLevelList()
if (levelRes && levelRes.data) {
qualificationLevelList.value = levelRes.data
}
// 加载工种列表
const workRes = await getWorkTypeList()
if (workRes && workRes.data) {
workTypeList.value = workRes.data
}
} catch (error) {
// Failed to load dict data
}
}
// 初始化:仅加载下拉字典,表格数据由 useTablecreatedIsNeed 默认 true自动请求
onMounted(async () => {
await loadDictData()
})
</script>
<style lang="scss" scoped>
@import '/@/assets/styles/page-cards.scss';
</style>