Files
school-developer/src/views/professional/professionalteacheracademicrelation/index.vue
guochunsi 9e3e775b0f ren
2026-01-07 18:33:03 +08:00

483 lines
15 KiB
Vue
Executable File
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"
>
<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-row>
<div class="mb15" style="width: 100%;">
<el-button
type="primary"
icon="FolderAdd"
@click="handleAdd"
v-if="permissions.professional_professionalteacheracademicrelation_add">
</el-button>
<el-button
type="warning"
plain
icon="Download"
v-if="permissions.professional_teacherbase_export"
@click="handleDownLoadWord"
:loading="exportLoading">导出信息
</el-button>
</div>
</el-row>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
v-loading="state.loading"
border
: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="graduateTime" label="毕业时间" width="180" align="center">
<template #default="scope">
{{ scope.row.graduateTime ? scope.row.graduateTime.split(' ')[0] : '-' }}
</template>
</el-table-column>
<el-table-column prop="type" label="教育类型" min-width="120" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getEducationTypeName(scope.row.type) }}
</template>
</el-table-column>
<el-table-column prop="qualificationConfigId" label="学历" min-width="120" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getQualificationName(scope.row.qualificationConfigId) }}
</template>
</el-table-column>
<el-table-column prop="degreeConfigId" label="学位" min-width="120" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getDegreeName(scope.row.degreeConfigId) }}
</template>
</el-table-column>
<!-- <el-table-column prop="createTime" label="创建时间" width="180" align="center" /> -->
<el-table-column label="学历证书附件" width="130" align="center">
<template #default="scope">
<el-button
v-if="scope.row.qualificationImg && scope.row.qualificationImg !== ''"
type="primary"
link
icon="Document"
@click="handlePreview(scope.row.qiList, 1)">查看
</el-button>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="学位证书附件" width="130" align="center">
<template #default="scope">
<el-button
v-if="scope.row.degreeImg && scope.row.degreeImg !== ''"
type="primary"
link
icon="Document"
@click="handlePreview(scope.row.deList, 2)">查看
</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
type="primary"
link
icon="edit-pen"
v-if="permissions.professional_professionalteacheracademicrelation_edit && (scope.row.state === '0' || scope.row.state === '-2')"
@click="handleEdit(scope.row)">编辑
</el-button>
<el-button
type="success"
link
icon="CircleCheck"
v-if="permissions.professional_professionalteacheracademicrelation_exam && scope.row.state === '0'"
@click="changeState(scope.row, 1)">通过
</el-button>
<el-button
type="danger"
link
icon="CircleClose"
v-if="permissions.professional_professionalteacheracademicrelation_exam && (scope.row.state === '0' || scope.row.state === '1')"
@click="changeState(scope.row, -2)">驳回
</el-button>
<el-button
type="primary"
link
icon="delete"
v-if="permissions.professional_professionalteacheracademicrelation_del"
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"
/>
<!-- 材料预览图片直接显示PDF 在组件内部 dialog 中显示 -->
<preview-file
v-for="src in imgUrl"
:key="src.title"
:authSrc="src.url"
:dialog-title="dialogTitle"
/>
<!-- 子组件 -->
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { useMessageBox } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import {
fetchList,
examObj,
delObj,
exportExcel
} from '/@/api/professional/professionaluser/professionalteacheracademicrelation'
import { getDegreeList } from '/@/api/professional/rsbase/professionalacademicdegreeconfig'
import { getQualificationList } from '/@/api/professional/rsbase/academicqualificationsconfig'
import { getAllTypeList } from '/@/api/professional/rsbase/professionalacademiceducationtypeconfig'
import { defineAsyncComponent } from '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'))
// 审核状态选项(独立定义,防止其他页面修改时被波及)
import type { StateOption } from '/@/components/AuditState/index.vue'
const auditStateOptions: StateOption[] = [
{ value: '1', label: '已通过', type: 'success', icon: 'fa-solid fa-circle-check', effect: 'dark' },
{ value: '-2', label: '已驳回', type: 'danger', icon: 'fa-solid fa-circle-xmark', effect: 'dark' },
{ value: '0', label: '待审核', type: 'warning', icon: 'fa-regular fa-clock', effect: 'light' }
]
// 使用 Pinia store
const userInfoStore = useUserInfo()
const { userInfos } = storeToRefs(userInfoStore)
// 创建权限对象
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 { 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 dialogTitle = ref('')
const imgUrl = ref<Array<{ title: string; url: string }>>([])
// 导出加载状态
const exportLoading = ref(false)
// 学位、学历和教育类型列表
const degreeList = ref<any[]>([])
const qualificationList = ref<any[]>([])
const educationTypeList = 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) => {
if (v.qualificationImg != null) {
v.qiList = [v.qualificationImg]
} else {
v.qiList = []
}
if (v.degreeImg != null) {
v.deList = [v.degreeImg]
} else {
v.deList = []
}
})
return {
data: {
records,
total: response.data.total || 0
}
}
},
queryForm: search
})
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 预览材料
const handlePreview = (list: string[], type: number) => {
imgUrl.value = []
nextTick(() => {
list.forEach(v => {
imgUrl.value.push({
title: '',
url: v
})
})
if (type === 1) {
dialogTitle.value = '学历证书附件'
} else if (type === 2) {
dialogTitle.value = '学位证书附件'
}
})
}
// 审核状态变更
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) {
// Failed to change state
}
}).catch(() => {})
} else if (val === -2) {
// 驳回
backReasonRef.value?.init(row, 'education')
}
}
// 查询
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) {
// Failed to delete
}
}).catch(() => {})
}
// 导出
const handleDownLoadWord = async () => {
exportLoading.value = true
try {
const response: any = await exportExcel(search)
const blob = new Blob([response as BlobPart])
const fileName = '学历学位信息.xls'
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
message.success('导出成功')
} catch (error) {
message.error('导出失败')
} finally {
exportLoading.value = false
}
}
// 获取学位名称
const getDegreeName = (id: string | number) => {
const item = degreeList.value.find((item: any) => item.id === id)
return item ? item.degreeName : '-'
}
// 获取学历名称
const getQualificationName = (id: string | number) => {
const item = qualificationList.value.find((item: any) => item.id === id)
return item ? item.qualificationName : '-'
}
// 获取教育类型名称
const getEducationTypeName = (id: string | number | undefined) => {
if (!id) return '-'
const item = educationTypeList.value.find((item: any) => item.id === id || String(item.id) === String(id))
return item ? item.name : '-'
}
// 加载字典数据
const loadDictData = async () => {
try {
// 并行加载所有字典数据
const [degreeRes, qualRes, eduTypeRes] = await Promise.all([
getDegreeList(),
getQualificationList(),
getAllTypeList()
])
// 加载学位列表
if (degreeRes && degreeRes.data) {
degreeList.value = degreeRes.data
}
// 加载学历列表
if (qualRes && qualRes.data) {
qualificationList.value = qualRes.data
}
// 加载教育类型列表
if (eduTypeRes && eduTypeRes.data) {
educationTypeList.value = eduTypeRes.data
}
} catch (error) {
// Failed to load dict data
}
}
// 初始化
onMounted(async () => {
await loadDictData()
getDataList()
})
</script>
<style lang="scss" scoped>
</style>