Files
school-developer/src/views/recruit/recruitstudentsignupturnover/index.vue
guochunsi 5dd173d8d3 a
2026-01-23 18:00:43 +08:00

441 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="唯一号/姓名/身份证号" prop="search">
<el-input v-model="queryForm.search" clearable placeholder="唯一号/姓名/身份证号/学校名称" />
</el-form-item>
<el-form-item label="异动审核" prop="isMajorChange">
<el-select v-model="queryForm.isMajorChange" filterable clearable placeholder="请选择异动审核">
<el-option
v-for="item in majorChangeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="state.dataList"
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="type" label="异动类型" width="100" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getTypeLabel(scope.row.type) }}
</template>
</el-table-column>
<el-table-column prop="name" label="姓名[唯一号]" min-width="160" align="center" show-overflow-tooltip />
<el-table-column prop="majorChangeInfo" label="专业变更情况" min-width="180" align="center" show-overflow-tooltip>
<template #default="scope">
<DetailPopover
v-if="scope.row.newMajorInfo || scope.row.oldMajorInfo"
title="专业变更详情"
:title-icon="InfoFilled"
:width="320"
:items="(() => {
const items = []
if (scope.row.oldMajorInfo) {
items.push({ label: '旧专业', content: scope.row.oldMajorInfo })
}
if (scope.row.newMajorInfo) {
items.push({ label: '新专业', content: scope.row.newMajorInfo, contentClass: 'new-major' })
}
return items
})()">
<template #reference>
<span class="major-change-link">
{{ scope.row.newMajorInfo || '查看详情' }}
<el-icon class="title-icon"><InfoFilled /></el-icon>
</span>
</template>
</DetailPopover>
<span v-else class="empty-text">-</span>
</template>
</el-table-column>
<el-table-column label="代办费变更情况" min-width="130" align="center" show-overflow-tooltip>
<template #default="scope">
<span class="new-fee">{{ scope.row.newAgencyFee }}</span> / <span class="old-fee">{{ scope.row.oldAgencyFee }}</span>
</template>
</el-table-column>
<el-table-column label="学费变更情况" min-width="140" align="center" show-overflow-tooltip>
<template #default="scope">
<span class="new-fee">{{ scope.row.newFeeTuition }}</span> / <span class="old-fee">{{ scope.row.oldFeeTuition }}</span>
</template>
</el-table-column>
<el-table-column label="分数变更情况" min-width="130" align="center">
<template #default="scope">
<span class="new-fee">{{ scope.row.newCorrectedScore }}</span> / <span class="old-fee">{{ scope.row.oldCorrectedScore }}</span>
</template>
</el-table-column>
<el-table-column prop="createBy" label="异动发起人" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="createTime" label="异动时间" min-width="180" align="center" show-overflow-tooltip />
<el-table-column prop="isMajorChange" label="异动审核" min-width="110" align="center" show-overflow-tooltip>
<template #default="scope">
<template v-if="getStatusConfig(auditStateOptions, scope.row.isMajorChange)">
<!-- 有备注信息时使用 popover 包裹 ClickableTag -->
<DetailPopover
v-if="scope.row.remarks"
title="异动审核详情"
:width="300"
:items="[
{
label: '审核状态',
layout: 'horizontal',
content: getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.label
},
{
label: '备注信息',
content: scope.row.remarks,
contentClass: 'reason-content'
}
]">
<template #reference>
<ClickableTag
width="80"
:type="getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.type || 'info'"
:left-icon="getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.icon">
{{ getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.label }}
</ClickableTag>
</template>
<template #content-0>
<ClickableTag
:type="getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.type || 'info'"
:left-icon="getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.icon"
:right-icon="null">
{{ getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.label }}
</ClickableTag>
</template>
<template #content-1>
<div class="reason-content">
<el-icon class="reason-icon"><Warning /></el-icon>
<span>{{ scope.row.remarks }}</span>
</div>
</template>
</DetailPopover>
<!-- 没有备注信息时直接显示 ClickableTag -->
<ClickableTag
v-else
width="80"
:type="getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.type || 'info'"
:left-icon="getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.icon"
:right-icon="null">
{{ getStatusConfig(auditStateOptions, scope.row.isMajorChange)?.label }}
</ClickableTag>
</template>
<!-- 无状态 -->
<span v-else class="empty-text">-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center" fixed="right">
<template #default="scope">
<el-button
v-auth="'recruit_recruitstudentsignupturnover_edit'"
v-if="scope.row.isMajorChange == '1'"
type="primary"
link
icon="EditPen"
@click="majorchange(scope.row.id, scope.row.groupId)"
>
审核
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 异动审核弹窗 -->
<el-dialog v-model="majorChangeVisible" title="异动审核" width="600px">
<el-form :model="exarmForm" ref="exarmFormRef" label-width="100px" :rules="dataRule">
<el-form-item label="审核结果" prop="isMajorChange">
<el-select v-model="exarmForm.isMajorChange" filterable clearable placeholder="请选择审核结果">
<el-option
v-for="item in isMajorChangeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="审核意见" prop="remarks">
<el-input
type="textarea"
placeholder="请输入审核意见"
:autosize="{ minRows: 2, maxRows: 4 }"
style="width: 100%"
v-model="exarmForm.remarks"
maxlength="20"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="update">保存</el-button>
<el-button @click="cancelPlace">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignupturnover">
import { ref, reactive, computed, onMounted } from 'vue'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { fetchList, putObj } from '/@/api/recruit/recruitstudentsignupturnover'
import { getList } from '/@/api/recruit/recruitstudentplangroup'
import ClickableTag from '/@/components/ClickableTag/index.vue'
import DetailPopover from '/@/components/DetailPopover/index.vue'
import { Warning, InfoFilled } from '@element-plus/icons-vue'
import { TURNOVER_AUDIT_STATUS_LIST, getStatusConfig } from '/@/config/global'
import { getDicts } from '/@/api/admin/dict'
// 消息提示 hooks
const message = useMessage()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const exarmFormRef = ref()
// 弹窗状态
const majorChangeVisible = ref(false)
// 数据
const planList = ref<any[]>([])
// 使用字典 recruit_change_type
const typeList = ref<any[]>([])
// 审核状态选项配置(用于 ClickableTag 组件和检索条件)
const auditStateOptions = ref<any[]>(TURNOVER_AUDIT_STATUS_LIST)
// 从 auditStateOptions 派生检索条件列表(只包含 label 和 value
const majorChangeList = computed(() => {
return auditStateOptions.value.map(item => ({
label: item.label,
value: item.value
}))
})
// 审核弹窗中的选项(只包含通过和驳回)
const isMajorChangeList = computed(() => {
return auditStateOptions.value
.filter(item => item.value !== '1')
.map(item => ({
label: item.label,
value: item.value
}))
})
// 查询表单
const queryForm = reactive({
groupId: '',
search: '',
isMajorChange: ''
})
// 审核表单
const exarmForm = reactive({
id: '',
isMajorChange: '',
examRemark: '',
groupId: '',
remarks: ''
})
// 表单验证规则
const dataRule = {
isMajorChange: [
{ required: true, message: '请选择审核结果', trigger: 'change' }
]
}
// 获取异动类型标签
const getTypeLabel = (type: string) => {
const item = typeList.value.find((it: any) => String(it.value) === String(type))
return item ? item.label : ''
}
// 表格状态
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: queryForm,
pageList: async (params: any) => {
const response = await fetchList(params)
return {
data: {
records: response.data.records,
total: response.data.total
}
}
},
createdIsNeed: false
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 初始化
const init = async () => {
try {
const data = await getList()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
const typeData = await getDicts('recruit_change_type')
typeList.value = typeData.data || []
getDataList()
} catch (error) {
// eslint-disable-next-line no-console
console.log('初始化失败', error)
}
}
// 打开审核弹窗
const majorchange = (id: string, groupId: string) => {
exarmForm.id = id
exarmForm.groupId = groupId
exarmForm.isMajorChange = ''
exarmForm.remarks = ''
majorChangeVisible.value = true
}
// 取消审核
const cancelPlace = () => {
majorChangeVisible.value = false
}
// 保存审核
const update = async () => {
try {
const valid = await exarmFormRef.value?.validate().catch(() => {})
if (!valid) return
await putObj(exarmForm)
message.success('审核成功')
majorChangeVisible.value = false
getDataList()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
queryForm.search = ''
queryForm.isMajorChange = ''
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
.new-fee {
color: var(--el-color-primary);
font-weight: 600;
font-size: 14px;
}
.old-fee {
text-decoration: line-through;
color: #606266;
font-size: 13px;
margin-left: 4px;
}
.empty-text {
color: #909399;
}
// 备注内容样式(用于 DetailPopover 的插槽内容)
.reason-content {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 12px;
background-color: #fef0f0;
border-radius: 4px;
border-left: 3px solid #f56c6c;
.reason-icon {
color: #f56c6c;
font-size: 16px;
flex-shrink: 0;
margin-top: 1px;
}
span {
color: #f56c6c;
line-height: 1.6;
word-break: break-all;
flex: 1;
}
}
// 专业变更链接样式
.major-change-link {
display: inline-flex;
align-items: center;
gap: 4px;
color: var(--el-color-primary);
text-decoration: underline;
cursor: pointer;
font-weight: 500;
&:hover {
color: var(--el-color-primary-light-3);
}
.title-icon {
color: var(--el-color-primary);
}
}
// 新专业样式(用于 DetailPopover 的内容类)
.new-major {
color: var(--el-color-primary);
font-weight: 500;
}
</style>