zhaosheng

This commit is contained in:
guochunsi
2026-01-26 18:19:57 +08:00
parent 741af78a0e
commit c5eea52c46
48 changed files with 656 additions and 488 deletions

View File

@@ -1,28 +1,23 @@
<template>
<div>
<el-dialog v-model="newStuCheckInDialog" width="40%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px" class="demo-ruleForm">
<el-dialog v-model="newStuCheckInDialog" width="600">
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px" class="demo-ruleForm">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" disabled style="width: 80%" />
<el-input v-model="form.name" disabled/>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-select v-model="form.gender" placeholder="请选择性别" disabled style="width: 80%">
<el-option
v-for="item in genderData"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-radio-group v-model="form.gender">
<el-radio v-for="item in genderData" :key="item.value" :label="item.value" :disabled="true">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="身份证号" prop="idNumber">
<el-input v-model="form.idNumber" disabled style="width: 80%" />
<el-input v-model="form.idNumber" disabled/>
</el-form-item>
<el-form-item label="报到状态" prop="backSchoolState">
<el-select v-model="form.backSchoolState" filterable placeholder="请选择报到状态" style="width: 80%">
<el-select v-model="form.backSchoolState" filterable placeholder="请选择报到状态">
<el-option
v-for="item in checkInStatusData"
:key="item.value"
@@ -33,13 +28,14 @@
</el-form-item>
<el-form-item label="回校备注" prop="backSchoolRemark">
<el-input v-model="form.backSchoolRemark" :rows="2" style="width: 80%" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="checkIn" :loading="submitLoading">确定</el-button>
<el-button @click="newStuCheckInDialog = false">取消</el-button>
<el-input v-model="form.backSchoolRemark" :rows="2" type="textarea"/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="newStuCheckInDialog = false">取消</el-button>
<el-button type="primary" @click="checkIn" :loading="submitLoading">确定</el-button>
</template>
</el-dialog>
</div>
</template>
@@ -51,12 +47,12 @@ import { useDict } from '/@/hooks/dict'
import { putBackObj } from '/@/api/recruit/recruitstudentsignup'
import { getDicts } from '/@/api/admin/dict'
// 性别字典
const { sexy:genderData } = useDict('sexy')
// 消息提示 hooks
const message = useMessage()
// 字典
const { getTypeValue } = useDict()
// 定义 emits
const emit = defineEmits(['reload'])
@@ -69,12 +65,6 @@ const checkInStatusData = ref<any[]>([])
const submitLoading = ref(false)
const page = ref<any>({})
// 固定数据
const genderData = [
{ label: '女', value: '2' },
{ label: '男', value: '1' }
]
// 表单数据
const form = reactive({
id: '',
@@ -140,10 +130,6 @@ const checkIn = async () => {
message.success('报到成功')
emit('reload')
newStuCheckInDialog.value = false
} catch (error: any) {
if (error !== false) {
message.error(error.msg || '报到失败')
}
} finally {
submitLoading.value = false
}

View File

@@ -1,94 +1,88 @@
<!--
- Copyright (c) 2018-2025, cyweb All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- Neither the name of the pig4cloud.com developer nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-->
<template>
<div class="tab-index-container">
<!-- 搜索表单 -->
<div class="search-form-wrapper">
<el-form :model="queryForm" inline ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划" @change="chanMajor">
<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="deptCode">
<el-select v-model="queryForm.deptCode" filterable clearable placeholder="请选择学院">
<el-option
v-for="item in deptList"
:key="item.deptCode"
:label="item.deptName"
:value="item.deptCode"
/>
</el-select>
</el-form-item>
<el-form-item label="录取专业" prop="confirmedMajor">
<el-select v-model="queryForm.confirmedMajor" filterable clearable placeholder="请选择录取专业">
<el-option
v-for="item in planMajorList"
:key="item.majorCode"
:label="item.majorName + '(' + item.learnYear + '年制)'"
:value="item.majorCode"
/>
</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="paystatus">
<el-select v-model="queryForm.paystatus" filterable clearable placeholder="请选择缴费状态">
<el-option
v-for="item in paystatusList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="推送状态" prop="pushed">
<el-select v-model="queryForm.pushed" filterable clearable placeholder="请选择推送状态">
<el-option
v-for="item in pushedList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="报到状态" prop="backSchoolState">
<el-select v-model="queryForm.backSchoolState" filterable clearable placeholder="请选择报到状态">
<el-option
v-for="item in backSchoolStateList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<search-form
v-show="showSearch"
:model="queryForm"
ref="searchFormRef"
@keyup-enter="getDataList"
>
<template #default="{ visible }">
<template v-if="visible">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划" @change="chanMajor">
<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="deptCode">
<el-select v-model="queryForm.deptCode" filterable clearable placeholder="请选择学院">
<el-option
v-for="item in deptList"
:key="item.deptCode"
:label="item.deptName"
:value="item.deptCode"
/>
</el-select>
</el-form-item>
<el-form-item label="录取专业" prop="confirmedMajor">
<el-select v-model="queryForm.confirmedMajor" filterable clearable placeholder="请选择录取专业">
<el-option
v-for="item in planMajorList"
:key="item.majorCode"
:label="item.majorName + '(' + item.learnYear + '年制)'"
:value="item.majorCode"
/>
</el-select>
</el-form-item>
<el-form-item label="唯一号/姓名/身份证号/学校名称" prop="search">
<el-input v-model="queryForm.search" clearable placeholder="唯一号/姓名/身份证号/学校名称" />
</el-form-item>
</template>
<template v-else>
<el-form-item label="缴费状态" prop="paystatus">
<el-select v-model="queryForm.paystatus" filterable clearable placeholder="请选择缴费状态">
<el-option
v-for="item in paystatusList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="推送状态" prop="pushed">
<el-select v-model="queryForm.pushed" filterable clearable placeholder="请选择推送状态">
<el-option
v-for="item in pushedList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="报到状态" prop="backSchoolState">
<el-select v-model="queryForm.backSchoolState" filterable clearable placeholder="请选择报到状态">
<el-option
v-for="item in backSchoolStateList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template>
</template>
<template #actions>
<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>
</div>
</template>
</search-form>
<!-- 操作按钮 -->
<div class="action-buttons-wrapper mb15">
@@ -101,7 +95,7 @@
名单导出
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentsignup_allCX"
v-auth="'recruit_recruitstudentsignup_allCX'"
type="primary"
plain
icon="Search"
@@ -110,6 +104,12 @@
>
批量查询
</el-button>
<right-toolbar
@queryTable="getDataList"
class="ml10"
style="float: right; "
v-model:showSearch="showSearch"
></right-toolbar>
</div>
<!-- 表格 -->
@@ -125,28 +125,6 @@
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="操作" width="200" align="center" fixed="left">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentsignup_show && scope.row.pushed == '1' && scope.row.paiedOffline != '10' && (scope.row.clfPayCode != undefined && scope.row.clfPayCode != '')"
type="primary"
link
icon="QrCode"
@click="showPayCode(scope.row)"
>
支付二维码
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentsignup_back"
type="success"
link
icon="CircleCheck"
@click="handleCheckIn(scope.row)"
>
报到
</el-button>
</template>
</el-table-column>
<el-table-column prop="serialNumber" label="唯一号" align="center" show-overflow-tooltip />
<el-table-column prop="deptCode" label="学院" align="center" show-overflow-tooltip>
<template #default="scope">
@@ -163,29 +141,113 @@
</template>
</el-table-column>
<el-table-column prop="name" label="姓名" align="center" show-overflow-tooltip />
<el-table-column prop="gender" label="性别" align="center" show-overflow-tooltip>
<el-table-column prop="gender" label="性别" width="80" align="center" show-overflow-tooltip>
<template #default="scope">
<GenderTag :sex="scope.row.gender" />
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号" align="center" show-overflow-tooltip />
<el-table-column prop="idNumber" label="身份证号" width="190" align="center" show-overflow-tooltip />
<el-table-column prop="parentTelOne" label="家长电话1" align="center" show-overflow-tooltip />
<el-table-column prop="parentTelTwo" label="家长电话2" align="center" show-overflow-tooltip />
<el-table-column prop="backSchoolState" label="报到状态" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getBackSchoolStateLabel(scope.row.backSchoolState) }}
<template v-if="getBackSchoolStateConfig(scope.row.backSchoolState)">
<!-- 有备注信息时使用 popover 包裹 ClickableTag -->
<DetailPopover
v-if="scope.row.backSchoolRemark"
title="报到详情"
:width="300"
:items="[
{
label: '报到状态',
layout: 'horizontal',
content: getBackSchoolStateConfig(scope.row.backSchoolState)?.label
},
{
label: '备注信息',
content: scope.row.backSchoolRemark,
contentClass: 'reason-content'
}
]">
<template #reference>
<ClickableTag
:type="getBackSchoolStateConfig(scope.row.backSchoolState)?.type || 'info'"
:left-icon="getBackSchoolStateConfig(scope.row.backSchoolState)?.icon"
>
{{ getBackSchoolStateConfig(scope.row.backSchoolState)?.label }}
</ClickableTag>
</template>
<template #content-0>
<ClickableTag
:type="getBackSchoolStateConfig(scope.row.backSchoolState)?.type || 'info'"
:left-icon="getBackSchoolStateConfig(scope.row.backSchoolState)?.icon"
:right-icon="null"
>
{{ getBackSchoolStateConfig(scope.row.backSchoolState)?.label }}
</ClickableTag>
</template>
<template #content-1>
<div class="reason-content">
<el-icon class="reason-icon"><Warning /></el-icon>
<span>{{ scope.row.backSchoolRemark }}</span>
</div>
</template>
</DetailPopover>
<!-- 无备注时直接显示 ClickableTag -->
<ClickableTag
v-else
:type="getBackSchoolStateConfig(scope.row.backSchoolState)?.type || 'info'"
:left-icon="getBackSchoolStateConfig(scope.row.backSchoolState)?.icon"
:right-icon="null"
>
{{ getBackSchoolStateConfig(scope.row.backSchoolState)?.label }}
</ClickableTag>
</template>
<span v-else class="empty-text">-</span>
</template>
</el-table-column>
<el-table-column prop="backSchoolRemark" label="报到备注" align="center" show-overflow-tooltip />
<el-table-column prop="paiedOffline" label="缴费状态" align="center" show-overflow-tooltip>
<el-table-column prop="paiedOffline" label="缴费状态" width="110" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getStatus(scope.row.paiedOffline) }}
<el-tag
v-if="getStatusConfig(paystatusList, scope.row.paiedOffline)"
:type="getStatusConfig(paystatusList, scope.row.paiedOffline)?.type"
>
{{ getStatusConfig(paystatusList, scope.row.paiedOffline)?.label }}
</el-tag>
<span v-else class="empty-text">{{ getStatusConfig(paystatusList, scope.row.paiedOffline)?.label || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="pushed" label="推送状态" width="110" align="center" show-overflow-tooltip>
<template #default="scope">
<el-tag
:type="getStatusConfig(pushedList, scope.row.pushed)?.type"
>
{{ getStatusConfig(pushedList, scope.row.pushed)?.label }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="pushed" label="推送状态" align="center" show-overflow-tooltip>
<el-table-column label="操作" width="200" align="center" fixed="right">
<template #default="scope">
<span v-if="scope.row.pushed == 0" style="color: red">{{ getPushed(scope.row.pushed) }}</span>
<span v-if="scope.row.pushed == 1" style="color: green">{{ getPushed(scope.row.pushed) }}</span>
<el-button
v-auth="'recruit_recruitstudentsignup_show'"
v-if="scope.row.pushed == '1' && scope.row.paiedOffline != '10' && (scope.row.clfPayCode != undefined && scope.row.clfPayCode != '')"
type="primary"
link
:icon="Tickets"
@click="showPayCode(scope.row)"
>
支付二维码
</el-button>
<el-button
v-auth="'recruit_recruitstudentsignup_back'"
type="primary"
link
icon="EditPen"
@click="handleCheckIn(scope.row)"
>
报到
</el-button>
</template>
</el-table-column>
</el-table>
@@ -207,7 +269,7 @@
<el-table-column label="姓名" prop="name" align="center" />
<el-table-column label="家长手机号" prop="parentTelOne" align="center" />
<el-table-column label="操作" align="center">
<template #default="scope">
<template #default>
<el-button type="danger" icon="Search" @click="updateFS">立即查询</el-button>
</template>
</el-table-column>
@@ -236,33 +298,23 @@
</template>
<script setup lang="ts" name="backSchoolCheckinTabIndex">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent, defineExpose } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { ref, reactive, onMounted, nextTick, defineAsyncComponent, defineExpose } from 'vue'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { getList } from '/@/api/recruit/recruitstudentplangroup'
import { backPush, backSchoolStuPage, batchPushAll } from '/@/api/recruit/recruitstudentsignup'
import { backSchoolStuPage } from '/@/api/recruit/recruitstudentsignup'
import { getDeptList } from '/@/api/basic/basicclass'
import { listPlanByCondition as planMajor } from '/@/api/recruit/recruitstudentplan'
import { updateFs, updateAllFS as updateAllFSApi } from '/@/api/finance/financenormalstu'
import { getDicts } from '/@/api/admin/dict'
import { PAY_STATUS_LIST,PUSHED_STATUS_LIST,getStatusConfig, getCheckInStatusConfig } from '/@/config/global'
import { CircleCheck, CircleClose, DocumentChecked, Warning, Clock, Tickets } from '@element-plus/icons-vue'
const StuCheckIn = defineAsyncComponent(() => import('./stu-check-in.vue'))
const GenderTag = defineAsyncComponent(() => import('/@/components/GenderTag/index.vue'))
// 使用 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
})
const SearchForm = defineAsyncComponent(() => import('/@/components/SearchForm/index.vue'))
const ClickableTag = defineAsyncComponent(() => import('/@/components/ClickableTag/index.vue'))
const DetailPopover = defineAsyncComponent(() => import('/@/components/DetailPopover/index.vue'))
// 消息提示 hooks
const message = useMessage()
@@ -272,13 +324,16 @@ const tableRef = ref()
const searchFormRef = ref()
const stuCheckInRef = ref()
// 搜索表单显示状态
const showSearch = ref(true)
// 数据
const planList = ref<any[]>([])
const planMajorList = ref<any[]>([])
const deptList = ref<any[]>([])
const backSchoolStateList = ref<any[]>([])
const paystatusList = ref([{ label: '已缴费', value: '10' }, { label: '未缴费', value: '0' }, { label: '部分缴费', value: '5' }])
const pushedList = ref([{ label: '未推送', value: '0' }, { label: '已推送', value: '1' }])
const paystatusList = PAY_STATUS_LIST
const pushedList = PUSHED_STATUS_LIST
// 查询表单
const queryForm = reactive({
@@ -318,43 +373,15 @@ const getMajorName = (majorCode: string) => {
return item ? item.majorName : ''
}
// 获取性别
const getGender = (gender: string) => {
if (gender == '2') {
return '女'
}
if (gender == '1') {
return '男'
}
return ''
}
// 获取报到状态标签
const getBackSchoolStateLabel = (value: string) => {
const item = backSchoolStateList.value.find(item => item.value === value)
return item ? item.label : ''
}
// 获取缴费状态
const getStatus = (type: string) => {
if (type == '0') {
return '未缴费'
} else if (type == '5') {
return '部分缴费'
} else if (type == '10') {
return '已缴费'
}
return ''
}
// 获取推送状态
const getPushed = (type: string) => {
if (type == '0') {
return '未推送'
} else if (type == '1') {
return '已推送'
}
return ''
// 获取报到状态配置(用于 ClickableTag
const getBackSchoolStateConfig = (value: string) => {
return getCheckInStatusConfig(backSchoolStateList.value, value, {
CircleCheck,
CircleClose,
DocumentChecked,
Warning,
Clock
})
}
// 表格状态
@@ -388,6 +415,7 @@ const getMajorList = async (groupId: string) => {
const data = await planMajor({ groupId })
planMajorList.value = data.data || []
} catch (error) {
// eslint-disable-next-line no-console
console.error('获取专业列表失败', error)
}
}
@@ -413,6 +441,7 @@ const init = async () => {
getDataList()
} catch (error) {
// eslint-disable-next-line no-console
console.error('初始化失败', error)
}
}
@@ -420,7 +449,7 @@ const init = async () => {
// 打开报到窗口
const handleCheckIn = (row: any) => {
nextTick(() => {
stuCheckInRef.value?.init(row, state.pagination.current)
stuCheckInRef.value?.init(row, state.pagination?.current || 1)
})
}
@@ -445,7 +474,7 @@ const updateAllFS = async () => {
message.success('正在更新所有缴费单状态,请稍后查看更新结果')
}
} catch (error: any) {
message.error(error.msg || '操作失败')
// console.log(error)
}
}
@@ -559,9 +588,6 @@ onMounted(() => {
overflow: hidden;
}
.search-form-wrapper {
flex-shrink: 0;
}
.action-buttons-wrapper {
flex-shrink: 0;
@@ -583,4 +609,33 @@ onMounted(() => {
flex-shrink: 0;
padding-top: 15px;
}
.empty-text {
color: #909399;
}
.reason-content {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 8px 12px;
background-color: #fef0f0;
border-radius: 4px;
border-left: 3px solid #f56c6c;
.reason-icon {
color: #f56c6c;
font-size: 16px;
flex-shrink: 0;
margin-top: 2px;
}
span {
color: #f56c6c;
font-size: 13px;
line-height: 1.6;
word-break: break-all;
flex: 1;
}
}
</style>