Merge branch 'developer' of http://code.cyweb.top/scj/zhxy/v3/cloud-ui into developer

This commit is contained in:
2026-01-15 01:15:15 +08:00
144 changed files with 17736 additions and 11469 deletions

View File

@@ -0,0 +1,57 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="回校列表" name="tab">
<tab-index ref="tabIndexRef" />
</el-tab-pane>
<el-tab-pane label="回校统计" name="static">
<static-index ref="staticIndexRef" />
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script setup lang="ts" name="backSchool">
import { ref, nextTick, defineAsyncComponent } from 'vue'
const TabIndex = defineAsyncComponent(() => import('./tabIndex.vue'))
const StaticIndex = defineAsyncComponent(() => import('./staticIndex.vue'))
const activeName = ref('tab')
const tabIndexRef = ref()
const staticIndexRef = ref()
const handleTabClick = (tab: any) => {
if (tab.paneName == 'tab') {
nextTick(() => {
tabIndexRef.value?.init()
})
} else {
nextTick(() => {
staticIndexRef.value?.init()
})
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,170 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划" @change="getTabStaticDataList" style="width: 150px;">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getTabStaticDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
ref="tableRef"
:data="tableData"
v-loading="dataListLoading"
border
stripe
show-summary
:summary-method="getSummaries"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column prop="groupId" label="招生计划" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getPlanName(scope.row.groupId) }}
</template>
</el-table-column>
<el-table-column prop="zymc" label="专业名称" align="center" show-overflow-tooltip />
<el-table-column prop="wlx" label="未联系" align="center" show-overflow-tooltip />
<el-table-column prop="yjbd" label="已经报到" align="center" show-overflow-tooltip />
<el-table-column prop="tcbd" label="推迟报到" align="center" show-overflow-tooltip />
<el-table-column prop="fqbd" label="放弃报到" align="center" show-overflow-tooltip />
<el-table-column prop="fwlx" label="无法联系" align="center" show-overflow-tooltip />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="backSchoolCheckinStaticIndex">
import { ref, reactive, onMounted } from 'vue'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getTabStaticDataList as getTabStaticDataListApi } from '/@/api/recruit/recruitstudentsignup'
// @ts-ignore
import global from '@/components/tools/commondict'
import { useTable } from '/@/hooks/table'
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
// 数据
const planList = ref<any[]>([])
const tableData = ref<any[]>([])
const dataListLoading = ref(false)
// 查询表单
const queryForm = reactive({
groupId: ''
})
// 获取计划名称
const getPlanName = (groupId: string) => {
const item = planList.value.find(item => item.id === groupId)
return item ? item.groupName : ''
}
// 表格样式
const { tableStyle } = useTable({ queryForm: queryForm, pageList: async () => ({ data: { records: [], total: 0 } }), createdIsNeed: false })
// 获取汇总数据
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总计'
} else if (index != 1) {
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: any) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: number) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
} else {
sums[index] = '--'
}
} else {
sums[index] = '--'
}
})
return sums
}
// 获取统计数据
const getTabStaticDataList = async () => {
try {
tableData.value = []
dataListLoading.value = true
const response = await getTabStaticDataListApi(queryForm)
tableData.value = response.data || []
} catch (error) {
console.error('获取统计数据失败', error)
} finally {
dataListLoading.value = false
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getTabStaticDataList()
}
// 初始化
const init = async () => {
try {
const data = await list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
getTabStaticDataList()
}
} catch (error) {
console.error('初始化失败', error)
}
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,275 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="入学年份" prop="grade">
<el-select v-model="queryForm.grade" filterable clearable placeholder="请选择入学年份">
<el-option
v-for="item in gradeList"
:key="item.year"
:label="item.year"
:value="item.year"
/>
</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="classCode">
<el-select v-model="queryForm.classCode" filterable clearable placeholder="请选择班级">
<el-option
v-for="item in classData"
:key="item.classCode"
:label="item.classNo"
:value="item.classCode"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="searchData">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button
v-if="permissions.recruit_newstucheckin_statistics_output"
type="warning"
plain
icon="Download"
:loading="exportLoading"
@click="handleExportOut"
>
导出
</el-button>
</div>
<el-table
:data="tableData"
height="650"
show-summary
:summary-method="getSummaries"
stripe
border
v-loading="tableLoading"
:header-cell-style="{ 'text-align': 'center' }"
:cell-style="{ 'text-align': 'center' }"
class="el_table_job_fair_stu"
>
<el-table-column type="index" width="50" fixed label="序号" />
<el-table-column prop="deptName" label="学院" />
<el-table-column prop="classNo" label="班级" />
<el-table-column prop="classNum" label="预计报到人数" />
<el-table-column prop="checkInOk" label="已经报到" />
<el-table-column prop="postpone" label="推迟报到" />
<el-table-column prop="abandon" label="放弃报到" />
<el-table-column prop="missing" label="无法联系" />
<el-table-column prop="contact" label="未联系" />
<el-table-column prop="checkInRate" label="报到率" />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="backSchoolCheckin-statistics">
import { ref, reactive, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { useMessage } from '/@/hooks/message'
import { getDataStatistics } from '/@/api/recruit/newstucheckin'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getDeptList } from '/@/api/basic/basicclass'
import { getClasslist } from '/@/api/stuwork/stupunlish'
import axios from 'axios'
// 使用 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 searchFormRef = ref()
// 状态
const tableData = ref<any[]>([])
const tableLoading = ref(false)
const exportLoading = ref(false)
const gradeList = ref<any[]>([])
const deptList = ref<any[]>([])
const classData = ref<any[]>([])
// 查询表单
const queryForm = reactive({
grade: '',
deptCode: '',
classCode: ''
})
// 初始化
const init = async () => {
await Promise.all([
getGradeData(),
getDeptData(),
getClassData()
])
getList()
}
// 查看所有入学年份
const getGradeData = async () => {
try {
const data = await list()
gradeList.value = data.data || []
} catch (error) {
console.error('获取入学年份失败', error)
}
}
// 查找所有二级学院
const getDeptData = async () => {
try {
const data = await getDeptList()
deptList.value = data.data || []
} catch (error) {
console.error('获取学院列表失败', error)
}
}
// 查找所有班级
const getClassData = async () => {
try {
const data = await getClasslist()
classData.value = data.data || []
} catch (error) {
console.error('获取班级列表失败', error)
}
}
// 获取数据列表
const getList = async () => {
try {
tableLoading.value = true
const response = await getDataStatistics(queryForm)
tableData.value = response.data || []
} catch (error) {
console.error('获取数据失败', error)
} finally {
tableLoading.value = false
}
}
// 查询
const searchData = () => {
getList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.grade = ''
queryForm.deptCode = ''
queryForm.classCode = ''
getList()
}
// 导出
const handleExportOut = async () => {
try {
exportLoading.value = true
const res = await axios({
method: 'post',
url: '/recruit/newstucheckin/exportDataStatistics',
data: queryForm,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
const blob = new Blob([res.data])
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)
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 合计方法
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '合计'
return
}
if (index === 1 || index === 2) {
sums[index] = ''
return
}
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: any) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: any) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
sums[index] += ''
}
})
return sums
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,159 @@
<template>
<div>
<el-dialog v-model="newStuCheckInDialog" width="40%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px" class="demo-ruleForm">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" disabled style="width: 80%" />
</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-form-item>
<el-form-item label="身份证号" prop="idNumber">
<el-input v-model="form.idNumber" disabled style="width: 80%" />
</el-form-item>
<el-form-item label="报到状态" prop="backSchoolState">
<el-select v-model="form.backSchoolState" filterable placeholder="请选择报到状态" style="width: 80%">
<el-option
v-for="item in checkInStatusData"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</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-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="backSchoolCheckin-stu-check-in">
import { ref, reactive } from 'vue'
import { useMessage } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import { putBackObj } from '/@/api/recruit/recruitstudentsignup'
// 消息提示 hooks
const message = useMessage()
// 字典
const { getTypeValue } = useDict()
// 定义 emits
const emit = defineEmits(['reload'])
// 引用
const formRef = ref()
// 状态
const newStuCheckInDialog = ref(false)
const checkInStatusData = ref<any[]>([])
const submitLoading = ref(false)
const page = ref<any>({})
// 固定数据
const genderData = [
{ label: '女', value: '2' },
{ label: '男', value: '1' }
]
// 表单数据
const form = reactive({
id: '',
name: '',
backSchoolState: '',
gender: '',
idNumber: '',
backSchoolRemark: ''
})
// 表单验证规则
const rules = reactive({
name: [
{ required: true, message: '请输入姓名', trigger: ['blur', 'change'] }
],
gender: [
{ required: true, message: '请输入性别', trigger: ['blur', 'change'] }
],
idNumber: [
{ required: true, message: '请输入身份证号', trigger: ['blur', 'change'] }
],
backSchoolState: [
{ required: true, message: '请输入报到状态', trigger: ['blur', 'change'] }
]
})
// 初始化表单
const initForm = () => {
form.id = ''
form.name = ''
form.backSchoolState = ''
form.gender = ''
form.idNumber = ''
form.backSchoolRemark = ''
}
// 初始化
const init = async (formData: any, pageData: any) => {
initForm()
page.value = pageData
submitLoading.value = false
newStuCheckInDialog.value = true
checkInStatusData.value = []
try {
const data = await getTypeValue('check_in_status')
checkInStatusData.value = data.data || []
} catch (error) {
console.error('获取字典数据失败', error)
}
Object.assign(form, formData)
}
// 报到
const checkIn = async () => {
if (!formRef.value) return
try {
await formRef.value.validate()
submitLoading.value = true
await putBackObj(form)
message.success('报到成功')
emit('reload')
newStuCheckInDialog.value = false
} catch (error: any) {
if (error !== false) {
message.error(error.msg || '报到失败')
}
} finally {
submitLoading.value = false
}
}
// 暴露方法
defineExpose({
init
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,547 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划" @change="chanMajor" style="width: 150px;">
<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="xy">
<el-select v-model="queryForm.xy" filterable clearable placeholder="请选择学院" style="width: 130px;">
<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.zydm"
:label="item.zymc + '(' + item.xz + '年制)'"
:value="item.zydm"
/>
</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="请选择缴费状态" style="width: 120px;">
<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="请选择推送状态" style="width: 120px;">
<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="请选择报到状态" style="width: 120px;">
<el-option
v-for="item in backSchoolStateList"
: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 type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
>
名单导出
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentsignup_allCX"
type="success"
plain
icon="Search"
class="ml10"
@click="updateAllFS"
>
批量查询
</el-button>
</div>
<!-- 表格 -->
<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 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="xy" label="学院" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.auditStatus == 20">
{{ getDeptName(scope.row.xy) }}
</span>
</template>
</el-table-column>
<el-table-column prop="confirmedMajor" label="录取专业" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.auditStatus == 20">
{{ getMajorName(scope.row.confirmedMajor) }}
</span>
</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>
<template #default="scope">
{{ getGender(scope.row.gender) }}
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号" 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>
</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>
<template #default="scope">
{{ getStatus(scope.row.paiedOffline) }}
</template>
</el-table-column>
<el-table-column prop="pushed" label="推送状态" align="center" show-overflow-tooltip>
<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>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 支付二维码弹窗 -->
<el-dialog v-model="dialogFormVisible" title="支付二维码" width="800px" @close="dialogFormVisible = false">
<el-table :data="tableData" border>
<el-table-column label="唯一号" prop="serialNumber" align="center" />
<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">
<el-button type="danger" icon="Search" @click="updateFS">立即查询</el-button>
</template>
</el-table-column>
</el-table>
<div style="padding-top: 20px;">
<div id="payQrcode1" style="display: inline-block;">
{{ payQrcode1Msg }}
</div>
<!-- <vue-qr :text="payQrcode1" :size="200" v-if="showPrise1" style="display: inline-block"></vue-qr> -->
<div id="payQrcode2" style="display: inline-block">
{{ payQrcode2Msg }}
</div>
<!-- <vue-qr :text="payQrcode2" :size="200" v-if="showPrise2" style="display: inline-block"></vue-qr> -->
<div id="payQrcode3" style="display: inline-block">
{{ payQrcode3Msg }}
</div>
<!-- <vue-qr :text="payQrcode3" :size="200" v-if="showPrise3" style="display: inline-block"></vue-qr> -->
</div>
<span style="color: red;padding-top: 20px;">** 此界面为查询学生缴款二维码如有收不到微信推送或手机号填错的可直接在此扫码支付支付成功后请手动点击"立即查询"按钮查询该生的缴费情况;因财政收费系统有一定的滞后性如点击"立即查询"后任显示未交费请稍后再继续查询或重新点击"立即查询"按钮 **</span>
</el-dialog>
<stu-check-in ref="stuCheckInRef" @reload="refreshChange" />
</div>
</div>
</template>
<script setup lang="ts" name="backSchoolCheckinTabIndex">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { backPush, backSchoolStuPage, batchPushAll } from '/@/api/recruit/recruitstudentsignup'
import { getDeptList } from '/@/api/basic/basicclass'
import { listPlanByCondition as planMajor } from '/@/api/recruit/recruitstudentplan'
import { updateFs, updateAllFS } from '/@/api/finance/financenormalstu'
import { getTypeValue } from '/@/api/admin/dict'
// @ts-ignore
import global from '@/components/tools/commondict.vue'
const StuCheckIn = defineAsyncComponent(() => import('./stu-check-in.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const stuCheckInRef = ref()
// 数据
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 queryForm = reactive({
groupId: '',
xy: '',
confirmedMajor: '',
search: '',
paystatus: '',
pushed: '',
backSchoolState: '',
isOut: '1',
auditStatus: '20'
})
// 弹窗状态
const dialogFormVisible = ref(false)
const tableData = ref<any[]>([])
const payQrcode1 = ref('')
const showPrise1 = ref(false)
const payQrcode1Msg = ref('')
const payQrcode2 = ref('')
const payQrcode2Msg = ref('')
const showPrise2 = ref(false)
const payQrcode3 = ref('')
const payQrcode3Msg = ref('')
const showPrise3 = ref(false)
// 获取学院名称
const getDeptName = (deptCode: string) => {
const item = deptList.value.find(item => item.deptCode === deptCode)
return item ? item.deptName : ''
}
// 获取专业名称
const getMajorName = (majorCode: string) => {
const item = planMajorList.value.find(item => item.zydm === majorCode)
return item ? item.zymc : ''
}
// 获取性别
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 ''
}
// 表格状态
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: queryForm,
pageList: async (params: any) => {
const response = await backSchoolStuPage(params)
return {
data: {
records: response.data.records,
total: response.data.total
}
}
},
createdIsNeed: false
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle, downBlobFile } = useTable(state)
// 招生计划改变
const chanMajor = async () => {
if (queryForm.groupId) {
await getMajorList(queryForm.groupId)
}
}
// 获取专业列表
const getMajorList = async (groupId: string) => {
try {
const data = await planMajor({ groupId })
planMajorList.value = data.data || []
} catch (error) {
console.error('获取专业列表失败', error)
}
}
// 初始化
const init = async () => {
try {
// 查询报到状态字典
const dictData = await getTypeValue('check_in_status')
backSchoolStateList.value = dictData.data || []
// 查询二级学院信息
const deptData = await getDeptList()
deptList.value = deptData.data || []
// 获取招生计划列表
const planData = await list()
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
await getMajorList(queryForm.groupId)
}
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 打开报到窗口
const handleCheckIn = (row: any) => {
nextTick(() => {
stuCheckInRef.value?.init(row, state.pagination.current)
})
}
// 刷新回调
const refreshChange = () => {
getDataList()
}
// 批量查询
const updateAllFS = async () => {
if (!queryForm.groupId) {
message.warning('招生计划不能为空')
return
}
try {
const plan = planList.value.find(e => e.id === queryForm.groupId)
if (!plan) return
const data = await updateAllFS({ year: plan.year, stuSource: '1' })
if (data.data.code == '200') {
message.success('正在更新所有缴费单状态,请稍后查看更新结果')
}
} catch (error: any) {
message.error(error.msg || '操作失败')
}
}
// 导出
const handleExport = async () => {
if (!queryForm.groupId) {
message.warning('招生计划不能为空')
return
}
try {
await downBlobFile(
'/recruit/recruitstudentsignup/exportBackData',
queryForm,
'招生名单导出.xls'
)
} catch (error: any) {
message.error(error.msg || '导出失败')
}
}
// 立即查询
const updateFS = async () => {
if (tableData.value.length === 0) return
try {
const serialNumber = tableData.value[0].serialNumber.substring(1, tableData.value[0].serialNumber.length)
await updateFs({ serialNumber })
message.success('已提交查询请求请等待1分钟后重新查询')
dialogFormVisible.value = false
getDataList()
} catch (error: any) {
message.error(error.msg || '查询失败')
}
}
// 显示支付二维码
const showPayCode = (row: any) => {
showPrise1.value = false
showPrise2.value = false
showPrise3.value = false
payQrcode1.value = ''
payQrcode2.value = ''
payQrcode3.value = ''
if (row.clfPayCode && row.clfPayCode != '') {
payQrcode1Msg.value = '材料费、代办费'
showPrise1.value = true
payQrcode1.value = 'https://jscz.govpay.ccb.com/online/fsjf?PyF_BillNo=' + row.clfPayCode + '&Verf_CD=blank&Admn_Rgon_Cd=320400'
} else {
payQrcode1Msg.value = ''
showPrise1.value = false
}
if (row.xfPayCode && row.xfPayCode != '') {
payQrcode2Msg.value = '学费'
showPrise2.value = true
payQrcode2.value = 'https://jscz.govpay.ccb.com/online/fsjf?PyF_BillNo=' + row.xfPayCode + '&Verf_CD=blank&Admn_Rgon_Cd=320400'
} else {
payQrcode2Msg.value = ''
showPrise2.value = false
}
if (row.zdbPayCode && row.zdbPayCode != '') {
payQrcode3Msg.value = '中德班学费'
showPrise3.value = true
payQrcode3.value = 'https://jscz.govpay.ccb.com/online/fsjf?PyF_BillNo=' + row.zdbPayCode + '&Verf_CD=blank&Admn_Rgon_Cd=320400'
} else {
payQrcode3Msg.value = ''
showPrise3.value = false
}
tableData.value = [row]
dialogFormVisible.value = true
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
queryForm.xy = ''
queryForm.confirmedMajor = ''
queryForm.search = ''
queryForm.paystatus = ''
queryForm.pushed = ''
queryForm.backSchoolState = ''
queryForm.isOut = '1'
queryForm.auditStatus = '20'
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,269 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4">
<el-form-item label="">
<el-input
v-model="queryForm.searchTotal"
style="width: 300px"
clearable
placeholder="请输入姓名/身份证号/家庭联系人"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
<el-button
v-if="permissions.recruit_newstucheckin_output"
type="warning"
plain
icon="Download"
class="ml10"
@click="handleExportOut"
:loading="exportLoading"
>
导出
</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="xy" label="学院" align="center" show-overflow-tooltip />
<el-table-column prop="classCode" label="班级" align="center" width="80" show-overflow-tooltip />
<el-table-column prop="stuNo" label="学号" align="center" show-overflow-tooltip />
<el-table-column prop="name" label="姓名" align="center" width="80" show-overflow-tooltip />
<el-table-column prop="gender" label="性别" align="center" width="60">
<template #default="scope">
<span>{{ scope.row.gender === '1' ? '男' : scope.row.gender === '2' ? '女' : '' }}</span>
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号" align="center" show-overflow-tooltip />
<el-table-column prop="checkInStatus" label="报到状态" align="center" show-overflow-tooltip>
<template #default="scope">
<el-tag v-if="scope.row.checkInStatus">
{{ getCheckInStatusLabel(scope.row.checkInStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="isDormApply" label="住宿申请" align="center" width="100">
<template #default="scope">
<el-tag v-if="scope.row.isDormApply == '1'" type="success">通过</el-tag>
<el-tag v-else-if="scope.row.isDormApply == '0'" type="info">未通过</el-tag>
</template>
</el-table-column>
<el-table-column prop="isRoom" label="是否住宿" align="center" width="100">
<template #default="scope">
<span>{{ scope.row.isRoom === '1' ? '是' : scope.row.isRoom === '0' ? '否' : '' }}</span>
</template>
</el-table-column>
<el-table-column prop="roomNo" label="宿舍号" align="center" width="80" show-overflow-tooltip />
<el-table-column prop="bedNo" label="床位号" align="center" width="80" show-overflow-tooltip />
<el-table-column prop="degreeOfEducation" label="文化程度" align="center" show-overflow-tooltip />
<el-table-column prop="residenceDetail" label="居住地址" align="center" show-overflow-tooltip />
<el-table-column prop="parentName" label="家庭联系人" 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="remarks" label="备注" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="100" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_newstucheckin_edit"
type="primary"
link
icon="CircleCheck"
@click="handleCheckIn(scope.row)"
>
报到
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 报到弹窗组件 -->
<stu-check-in ref="stuCheckInRef" @reload="refreshChange"></stu-check-in>
</div>
</div>
</template>
<script setup lang="ts" name="newstucheckin">
import { ref, reactive, computed, onMounted, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { fetchList } from '/@/api/recruit/newstucheckin'
import { getTypeValue } from '/@/api/admin/dict'
import request from '/@/utils/request'
const StuCheckIn = defineAsyncComponent(() => import('./stu-check-in.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const stuCheckInRef = ref()
// 导出加载状态
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
searchTotal: ''
})
// 报到状态字典数据
const checkInStatusData = ref<any[]>([])
// 表格状态
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: queryForm,
pageList: async (params: any) => {
const response = await fetchList({
...params,
searchTotal: queryForm.searchTotal
})
return {
data: {
records: response.data.records,
total: response.data.total
}
}
}
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 获取报到状态标签
const getCheckInStatusLabel = (value: string) => {
const item = checkInStatusData.value.find(item => item.value === value)
return item ? item.label : value
}
// 重置查询
const resetQuery = () => {
queryForm.searchTotal = ''
getDataList()
}
// 刷新回调
const refreshChange = () => {
getDataList()
}
// 打开报到窗口
const handleCheckIn = (row: any) => {
if (stuCheckInRef.value) {
stuCheckInRef.value.init(row, {
currentPage: state.pagination?.current || 1,
pageSize: state.pagination?.size || 10,
total: state.pagination?.total || 0
})
}
}
// 导出
const handleExportOut = async () => {
exportLoading.value = true
try {
const res = await request({
method: 'post',
url: '/recruit/newstucheckin/exportData',
data: {
...queryForm,
current: state.pagination?.current || 1,
size: state.pagination?.size || 10
},
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
const blob = new Blob([res.data])
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: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 查询报到状态字典
const getCheckInStatusData = async () => {
try {
const data = await getTypeValue('check_in_status')
checkInStatusData.value = data.data || []
} catch (error) {
console.error('获取报到状态字典失败', error)
}
}
onMounted(() => {
getCheckInStatusData()
getDataList()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,275 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="入学年份" prop="grade">
<el-select v-model="queryForm.grade" filterable clearable placeholder="请选择入学年份">
<el-option
v-for="item in gradeList"
:key="item.year"
:label="item.year"
:value="item.year"
/>
</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="classCode">
<el-select v-model="queryForm.classCode" filterable clearable placeholder="请选择班级">
<el-option
v-for="item in classData"
:key="item.classCode"
:label="item.classNo"
:value="item.classCode"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="searchData">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button
v-if="permissions.recruit_newstucheckin_statistics_output"
type="warning"
plain
icon="Download"
:loading="exportLoading"
@click="handleExportOut"
>
导出
</el-button>
</div>
<el-table
:data="tableData"
height="650"
show-summary
:summary-method="getSummaries"
stripe
border
v-loading="tableLoading"
:header-cell-style="{ 'text-align': 'center' }"
:cell-style="{ 'text-align': 'center' }"
class="el_table_job_fair_stu"
>
<el-table-column type="index" width="50" fixed label="序号" />
<el-table-column prop="deptName" label="学院" />
<el-table-column prop="classNo" label="班级" />
<el-table-column prop="classNum" label="预计报到人数" />
<el-table-column prop="checkInOk" label="已经报到" />
<el-table-column prop="postpone" label="推迟报到" />
<el-table-column prop="abandon" label="放弃报到" />
<el-table-column prop="missing" label="无法联系" />
<el-table-column prop="contact" label="未联系" />
<el-table-column prop="checkInRate" label="报到率" />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="newstucheckin-statistics">
import { ref, reactive, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { useMessage } from '/@/hooks/message'
import { getDataStatistics } from '/@/api/recruit/newstucheckin'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getDeptList } from '/@/api/basic/basicclass'
import { getClasslist } from '/@/api/stuwork/stupunlish'
import axios from 'axios'
// 使用 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 searchFormRef = ref()
// 状态
const tableData = ref<any[]>([])
const tableLoading = ref(false)
const exportLoading = ref(false)
const gradeList = ref<any[]>([])
const deptList = ref<any[]>([])
const classData = ref<any[]>([])
// 查询表单
const queryForm = reactive({
grade: '',
deptCode: '',
classCode: ''
})
// 初始化
const init = async () => {
await Promise.all([
getGradeData(),
getDeptData(),
getClassData()
])
getList()
}
// 查看所有入学年份
const getGradeData = async () => {
try {
const data = await list()
gradeList.value = data.data || []
} catch (error) {
console.error('获取入学年份失败', error)
}
}
// 查找所有二级学院
const getDeptData = async () => {
try {
const data = await getDeptList()
deptList.value = data.data || []
} catch (error) {
console.error('获取学院列表失败', error)
}
}
// 查找所有班级
const getClassData = async () => {
try {
const data = await getClasslist()
classData.value = data.data || []
} catch (error) {
console.error('获取班级列表失败', error)
}
}
// 获取数据列表
const getList = async () => {
try {
tableLoading.value = true
const response = await getDataStatistics(queryForm)
tableData.value = response.data || []
} catch (error) {
console.error('获取数据失败', error)
} finally {
tableLoading.value = false
}
}
// 查询
const searchData = () => {
getList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.grade = ''
queryForm.deptCode = ''
queryForm.classCode = ''
getList()
}
// 导出
const handleExportOut = async () => {
try {
exportLoading.value = true
const res = await axios({
method: 'post',
url: '/recruit/newstucheckin/exportDataStatistics',
data: queryForm,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
const blob = new Blob([res.data])
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)
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 合计方法
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '合计'
return
}
if (index === 1 || index === 2) {
sums[index] = ''
return
}
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: any) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: any) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
sums[index] += ''
}
})
return sums
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,298 @@
<template>
<div>
<el-dialog v-model="newStuCheckInDialog" width="40%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px"
class="demo-ruleForm">
<el-form-item label="姓名" prop="realName">
<el-input v-model="form.name" style=" width: 80%"></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-select v-model="form.gender" placeholder="请选择性别" style=" width: 80%">
<el-option
v-for="item in genderData"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idNumber" style=" width: 80%"></el-input>
</el-form-item>
<el-form-item label="报到状态" prop="checkInStatus">
<el-select v-model="form.checkInStatus" filterable placeholder="请选择报到状态" style=" width: 80% ">
<el-option
v-for="item in checkInStatusData"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="是否住宿" prop="isRoom" v-if="isRoomTab">
<el-select v-model="form.isRoom" filterable placeholder="是否住宿" style=" width: 80% ">
<el-option
v-for="item in yesOrNoData"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="宿舍号" prop="roomNo" v-if="isRoomTab && form.isRoom=='1'">
<el-select
v-model="form.roomNo"
filterable
remote
placeholder="请选择宿舍号"
:remote-method="remoteMethod"
@change="handleRoomNoChange"
:loading="loading"
style=" width: 80% "
>
<el-option
v-for="item in roomNoList"
:key="item.id"
:label="item.roomNo"
:value="item.roomNo">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="床号" prop="bedNo" v-if="isRoomTab && form.isRoom=='1'">
<el-select v-model="form.bedNo" filterable placeholder="请选择床号" style=" width: 80% " :key="bedNoKey">
<el-option
v-for="item in bedNoData"
:key="item.bedNo"
:label="item.bedNo"
:value="item.bedNo"
:disabled="isRoomDisable(item.notBedNo)">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="form.remarks" :rows="2" style=" width: 80%"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="checkIn" v-loading="submitLoading">确定</el-button>
<el-button @click="newStuCheckInDialog = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import { useMessage } from '/@/hooks/message'
import { getDataByRoomNo } from "/@/api/stuwork/dormroom"
import { fearchRoomStuNum } from "/@/api/stuwork/dormroomstudent"
import { getDictByType } from "/@/api/contract/contract"
import { putObj } from '@/api/recruit/newstucheckin'
// Emits
const emit = defineEmits<{
(e: 'reload', page: any): void
}>()
// 消息提示
const message = useMessage()
// 表单引用
const formRef = ref()
// 响应式数据
const page = ref<any>({})
const newStuCheckInDialog = ref(false)
const bedNoData = ref<any[]>([])
const roomNoList = ref<any[]>([])
const checkInStatusData = ref<any[]>([])
const loading = ref(false)
const isRoomTab = ref(false)
const bedNoKey = ref(0) // 用于强制更新床号选择器
const yesOrNoData = [
{ label: '否', value: '0' },
{ label: '是', value: '1' }
]
const genderData = [
{ label: '女', value: '2' },
{ label: '男', value: '1' }
]
const submitLoading = ref(false)
const form = reactive({
name: "",
checkInStatus: "",
gender: "",
idNumber: "",
isRoom: "",
roomNo: "",
bedNo: "",
remarks: "",
residenceDetail: "",
parentName: "",
parentTelOne: "",
parentTelTwo: ""
})
const rules = {
name: [
{ required: true, message: '请输入姓名', trigger: ["blur", "change"] }
],
gender: [
{ required: true, message: '请输入性别', trigger: ["blur", "change"] }
],
idNumber: [
{ required: true, message: '请输入身份证号', trigger: ["blur", "change"] }
],
checkInStatus: [
{ required: true, message: '请输入报到状态', trigger: ["blur", "change"] }
],
isRoom: [
{ required: true, message: '请选择是否住宿', trigger: ["blur", "change"] }
],
roomNo: [
{ required: true, message: '请选择宿舍号', trigger: ["blur", "change"] }
],
bedNo: [
{ required: true, message: '请选择床位号', trigger: ["blur", "change"] }
],
}
// 监听报到状态变化
watch(() => form.checkInStatus, (newVal) => {
if (newVal === '1') {
isRoomTab.value = true
} else {
isRoomTab.value = false
}
})
// 监听宿舍号变化
watch(() => form.roomNo, (newVal) => {
console.log(newVal)
if (newVal) {
fearchRoomStuNums(newVal)
}
})
// 监听是否住宿变化
watch(() => form.isRoom, (newVal) => {
if (newVal === '0') {
form.roomNo = ''
form.bedNo = ''
}
})
// 初始化表单
const initForm = () => {
form.name = ""
form.checkInStatus = ""
form.gender = ""
form.idNumber = ""
form.isRoom = ""
form.roomNo = ""
form.bedNo = ""
form.remarks = ""
form.residenceDetail = ""
form.parentName = ""
form.parentTelOne = ""
form.parentTelTwo = ""
}
// 初始化方法
const init = (formData: any, pageData: any) => {
initForm()
page.value = pageData
submitLoading.value = false
newStuCheckInDialog.value = true
Object.assign(form, formData)
if (formData.roomNo) {
remoteMethod(formData.roomNo)
fearchRoomStuNums(formData.bedNo)
}
getDictByType('check_in_status').then(data => {
checkInStatusData.value = data.data
})
console.log("OKKK")
}
// 报到提交
const checkIn = () => {
submitLoading.value = true
formRef.value?.validate((valid: boolean) => {
if (valid) {
putObj(form).then(() => {
message.success('报到成功')
emit('reload', page.value)
newStuCheckInDialog.value = false
submitLoading.value = false
}).catch(() => {
submitLoading.value = false
})
} else {
submitLoading.value = false
return false
}
})
}
// 实时检索宿舍号
const remoteMethod = (query: string) => {
if (query != '' && query.length >= 3) {
const data = { 'roomNo': query }
loading.value = true
getDataByRoomNo(data).then(data => {
roomNoList.value = data.data
console.log("this.roomNoList")
console.log(roomNoList.value)
loading.value = false
}).catch(() => {
loading.value = false
})
}
}
// 查询此房间为几人间
const fearchRoomStuNums = (roomNo: string) => {
const data = { "roomNo": roomNo }
fearchRoomStuNum(data).then(data => {
bedNoData.value = data.data
})
}
// 判断床位是否禁用
const isRoomDisable = (notBedNo: any) => {
if (undefined != notBedNo && "" != notBedNo) {
return true
} else {
return false
}
}
// 宿舍号变化时清空床号
const handleRoomNoChange = () => {
form.bedNo = ''
bedNoKey.value++ // 强制更新床号选择器
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,295 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
v-model="visible"
append-to-body
>
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit" label-width="140px">
<el-form-item label="模拟学生" prop="serialNumber">
<el-select
v-model="dataForm.serialNumber"
@change="changeStu"
filterable
remote
clearable
reserve-keyword
:disabled="!!dataForm.id" placeholder="请选择唯一号" size="small" style="width: 100%"
:remote-method="remoteTeacherByQuery"
>
<el-option
v-for="item in serialNumberList"
:key="item.serialNumber"
:label="item.name+'('+item.serialNumber+')'"
:value="item.serialNumber">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="来源" prop="isOut">
<el-select v-model="dataForm.isOut" filterable disabled placeholder="请选择来源" size="small" style="width: 100%" >
<el-option
v-for="item in isOutList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业1" prop="wishMajorOne">
<el-select v-model="dataForm.wishMajorOne" filterable placeholder="请选择拟报专业1" size="small" style="width: 100%">
<el-option
v-for="item in planMajorList"
:key="item.zydm"
:label="item.zymc+' | '+item.xz+'年 | '+item.zydm"
:value="item.zydm"
:disabled="isDisable(item.zydm)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业2" prop="wishMajorTwo">
<el-select v-model="dataForm.wishMajorTwo" filterable placeholder="请选择拟报专业2" size="small" style="width: 100%">
<el-option
v-for="item in planMajorList"
:key="item.zydm"
:label="item.zymc+' | '+item.xz+'年 | '+item.zydm"
:value="item.zydm"
:disabled="isDisable(item.zydm)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业3" prop="wishMajorThree">
<el-select v-model="dataForm.wishMajorThree" filterable placeholder="请选择拟报专业3" size="small" style="width: 100%">
<el-option
v-for="item in planMajorList"
:key="item.zydm"
:label="item.zymc+' | '+item.xz+'年 | '+item.zydm"
:value="item.zydm"
:disabled="isDisable(item.zydm)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="录取专业" prop="confirmedMajor">
<el-select v-model="dataForm.confirmedMajor" filterable placeholder="请选择录取专业" size="small" style="width: 100%">
<el-option
v-for="item in planMajorEduList"
:key="item.zydm"
:label="item.zymc+' | '+item.xz+'年 | '+item.zydm"
:value="item.zydm">
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { addMNObj, getMNObj, putMNObj } from '@/api/recruit/recruitImitateAdjustBatch'
import { getList } from "@/api/recruit/recruitstudentsignup"
import { listPlanByCondition as planMajor, listByEdu } from "@/api/recruit/recruitstudentplan"
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const disabled = ref(false)
const serialNumberList = ref<any[]>([])
const planMajorEduList = ref<any[]>([])
const planMajorList = ref<any[]>([])
const isOutList = [
{ label: "学校", value: "0" },
{ label: "市平台", value: "1" }
]
const dataForm = reactive({
id: "",
serialNumber: "",
groupId: "",
batchNo: "",
wishMajorOne: '',
wishMajorTwo: '',
wishMajorThree: '',
confirmedMajor: '',
isOut: '',
degreeOfEducation: "",
name: "",
gender: "",
idNumber: "",
oldConfirmedMajor: ""
})
const dataRule = {
serialNumber: [
{ required: true, message: '模拟学生不能为空', trigger: 'blur' },
],
confirmedMajor: [
{ required: true, message: '录取专业不能为空', trigger: 'blur' },
],
}
/**
* 判断拟报专业是否已经占用,占用不可选
*/
const isDisable = (zydm: string) => {
if (zydm == dataForm.wishMajorOne
|| zydm == dataForm.wishMajorTwo
|| zydm == dataForm.wishMajorThree
) {
return true
} else {
return false
}
}
// 初始化数据
const initData = () => {
planMajorList.value = []
serialNumberList.value = []
planMajor({ groupId: dataForm.groupId }).then((data: any) => {
planMajorList.value = data.data
})
}
// 远程搜索学生
const remoteTeacherByQuery = (query: string) => {
serialNumberList.value = []
if (query !== '') {
setTimeout(() => {
getList({ groupId: dataForm.groupId, name: query }).then((response: any) => {
serialNumberList.value = response.data
})
}, 200)
}
}
// 学生选择变化
const changeStu = () => {
planMajorEduList.value = []
dataForm.wishMajorOne = ''
dataForm.wishMajorTwo = ''
dataForm.wishMajorThree = ''
dataForm.degreeOfEducation = ""
dataForm.oldConfirmedMajor = ""
dataForm.name = ""
dataForm.idNumber = ""
dataForm.confirmedMajor = ""
dataForm.gender = ""
dataForm.isOut = ""
serialNumberList.value.forEach(e => {
if (e.serialNumber == dataForm.serialNumber) {
dataForm.wishMajorOne = e.wishMajorOne
dataForm.wishMajorTwo = e.wishMajorTwo
dataForm.wishMajorThree = e.wishMajorThree
dataForm.degreeOfEducation = e.degreeOfEducation
dataForm.name = e.name
dataForm.idNumber = e.idNumber
dataForm.gender = e.gender
dataForm.isOut = e.isOut
dataForm.confirmedMajor = e.confirmedMajor
dataForm.oldConfirmedMajor = e.confirmedMajor
getMajorListByEdu()
}
})
}
// 根据学历获取专业列表
const getMajorListByEdu = () => {
planMajorEduList.value = []
listByEdu({ groupId: dataForm.groupId, degreeOfEducation: dataForm.degreeOfEducation }).then((res: any) => {
planMajorEduList.value = res.data
})
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
if (dataForm.oldConfirmedMajor == dataForm.confirmedMajor) {
ElNotification.error({
title: '错误',
message: '模拟调整的专业不能和原录取专业相同,请检查'
})
return
}
canSubmit.value = false
if (dataForm.id) {
putMNObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addMNObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null, groupId: string, batchNo: string) => {
dataForm.id = id || ""
dataForm.batchNo = batchNo
dataForm.groupId = groupId
visible.value = true
canSubmit.value = true
planMajorEduList.value = []
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
getMNObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
getMajorListByEdu()
})
} else {
disabled.value = true
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,139 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
width="600px"
v-model="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit" label-width="120px">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable :disabled="!!dataForm.id" placeholder="请选择招生计划">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="批次名称" prop="batchName">
<el-input v-model="dataForm.batchName" placeholder="批次名称"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { addObj, getObj, putObj } from '/@/api/recruit/recruitImitateAdjustBatch'
import { list } from '/@/api/recruit/recruitstudentplangroup'
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const disabled = ref(false)
const planList = ref<any[]>([])
const dataForm = reactive({
id: "",
batchName: "",
groupId: "",
})
const dataRule = {
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'blur' },
],
batchName: [
{ required: true, message: '批次名称不能为空', trigger: 'blur' },
{ min: 1, max: 20, message: '批次名称长度不大于20个字符', trigger: 'blur' }
],
}
// 初始化数据
const initData = () => {
list().then((data: any) => {
planList.value = data.data
if (!dataForm.id) {
dataForm.groupId = planList.value[0].id
}
})
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
})
} else {
disabled.value = true
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,267 @@
<!--
- 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="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="batchName">
<el-input v-model="queryForm.batchName" clearable placeholder="批次名称" />
</el-form-item>
<el-form-item label="批次代码" prop="batchCode">
<el-input v-model="queryForm.batchCode" clearable placeholder="批次代码" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitImitateAdjustBatch_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle"
>
</el-button>
</div>
<!-- 表格 -->
<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="batchName" label="批次名称" align="center" show-overflow-tooltip />
<el-table-column prop="batchCode" label="批次代码" align="center" show-overflow-tooltip />
<el-table-column prop="peopleNumber" label="人数" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="300" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitImitateAdjustBatch_show"
type="primary"
link
icon="Document"
@click="showTable(scope.row.batchCode, scope.row.groupId)"
>
模拟列表
</el-button>
<el-button
v-if="permissions.recruit_recruitImitateAdjustBatch_show"
type="warning"
link
icon="Download"
@click="handleExport(scope.row.batchCode, scope.row.groupId)"
>
导出模拟结果
</el-button>
<el-button
v-if="permissions.recruit_recruitImitateAdjustBatch_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
修改
</el-button>
<el-button
v-if="permissions.recruit_recruitImitateAdjustBatch_del"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form ref="addOrUpdateRef" @refreshDataList="getDataList" />
<mn-table ref="mnTableRef" @refreshDataList="getDataList" />
</div>
</div>
</template>
<script setup lang="ts" name="recruitImitateAdjustBatch">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { delObj, fetchList } from '/@/api/recruit/recruitImitateAdjustBatch'
const TableForm = defineAsyncComponent(() => import('./detaiform.vue'))
const MnTable = defineAsyncComponent(() => import('./mnTable.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
const mnTableRef = ref()
// 弹窗状态
const addOrUpdateVisible = ref(false)
const mnTableVisible = ref(false)
// 数据
const planList = ref<any[]>([])
// 查询表单
const queryForm = reactive({
groupId: '',
batchName: '',
batchCode: ''
})
// 表格状态
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, downBlobFile } = useTable(state)
// 初始化
const init = async () => {
try {
const data = await list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
} catch (error) {
// 初始化失败
}
}
// 新增 / 修改
const addOrUpdateHandle = (payload?: string | MouseEvent) => {
// 新增按钮未传参时会传入 MouseEvent这里统一转换为 id 或 null
const id = typeof payload === 'string' ? payload : null
nextTick(() => {
addOrUpdateRef.value?.init(id)
})
}
// 显示模拟列表
const showTable = (batchNo: string, groupId: string) => {
nextTick(() => {
mnTableRef.value?.init(batchNo, groupId)
})
}
// 导出模拟结果
const handleExport = async (code: string, gid: string) => {
try {
await downBlobFile(
'/recruit/recruitImitateAdjustBatch/exportExcel',
{ batchNo: code, groupId: gid },
'招生模拟统计.xls'
)
} catch (error: any) {
message.error(error.msg || '导出失败')
}
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
queryForm.batchName = ''
queryForm.batchCode = ''
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,246 @@
<template>
<el-dialog
title="模拟列表"
:close-on-click-modal="false"
v-model="visible"
width="80%"
>
<el-form :inline="true">
<el-form-item>
<el-button v-if="permissions.recruit_recruitImitateAdjustBatch_add" :icon="Plus" size="small" type="primary" @click="addOrUpdateHandle()">新增</el-button>
</el-form-item>
</el-form>
<div class="avue-crud">
<el-table
:data="dataList"
border
stripe
v-loading="dataListLoading">
<el-table-column
prop="serialNumber"
header-align="center"
align="center"
label="唯一号">
</el-table-column>
<el-table-column
prop="name"
header-align="center"
align="center"
label="姓名">
</el-table-column>
<el-table-column
prop="gender"
header-align="center"
align="center"
label="性别">
<template #default="scope">
<span v-if="scope.row.gender==1"></span>
<span v-if="scope.row.gender==2"></span>
</template>
</el-table-column>
<el-table-column
prop="degreeOfEducation"
header-align="center"
align="center"
label="学历">
<template #default="scope">
{{global.getLabelValueByPropes(eduList,scope.row.degreeOfEducation,{'key':'value','value':'label'})}}
</template>
</el-table-column>
<el-table-column
prop="wishMajorOne"
header-align="center"
width="100px"
align="center"
label="拟报专业1">
<template #default="scope">
{{global.getLabelValueByPropes2(planMajorList,scope.row.wishMajorOne,{'key':'zydm','value':'zymc'})}}
</template>
</el-table-column>
<el-table-column
prop="wishMajorTwo"
header-align="center"
align="center"
width="100px"
label="拟报专业2">
<template #default="scope">
{{global.getLabelValueByPropes2(planMajorList,scope.row.wishMajorTwo,{'key':'zydm','value':'zymc'})}}
</template>
</el-table-column>
<el-table-column
prop="wishMajorThree"
header-align="center"
align="center"
width="100px"
label="拟报专业3">
<template #default="scope">
{{global.getLabelValueByPropes2(planMajorList,scope.row.wishMajorThree,{'key':'zydm','value':'zymc'})}}
</template>
</el-table-column>
<el-table-column
prop="oldConfirmedMajor"
header-align="center"
align="center"
label="原录取专业">
<template #default="scope">
{{global.getLabelValueByPropes2(planMajorList,scope.row.oldConfirmedMajor,{'key':'zydm','value':'zymc'})}}
</template>
</el-table-column>
<el-table-column
prop="confirmedMajor"
header-align="center"
align="center"
label="模拟录取专业">
<template #default="scope">
{{global.getLabelValueByPropes2(planMajorList,scope.row.confirmedMajor,{'key':'zydm','value':'zymc'})}}
</template>
</el-table-column>
<el-table-column
prop="isOut"
header-align="center"
align="center"
width="120"
label="来源">
<template #default="scope">
<span v-if="scope.row.isOut==0">学校</span>
<span v-if="scope.row.isOut==1">市平台</span>
</template>
</el-table-column>
<el-table-column
header-align="center"
align="center"
label="操作">
<template #default="scope">
<el-button v-if="permissions.recruit_recruitImitateAdjustBatch_edit" type="text" size="small" :icon="Edit" @click="addOrUpdateHandle(scope.row.id)">修改</el-button>
<el-button v-if="permissions.recruit_recruitImitateAdjustBatch_del" type="text" size="small" :icon="Delete" @click="deleteHandle(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<add-m-n-stu v-if="addMnStuVisible" ref="addMnStuRef" @refreshDataList="getDataList"></add-m-n-stu>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { Plus, Edit, Delete } from '@element-plus/icons-vue'
import { getMNStuList, delMNObj } from '@/api/recruit/recruitImitateAdjustBatch'
import { listPlanByCondition as planMajor } from "@/api/recruit/recruitstudentplan"
import { getTypeValue } from "@/api/admin/dict"
// @ts-ignore
import global from '@/components/tools/commondict'
const AddMNStu = defineAsyncComponent(() => import('./addMNStu.vue'))
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 使用 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 addMnStuRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const dataListLoading = ref(false)
const addMnStuVisible = ref(false)
const dataForm = reactive({
batchNo: "",
groupId: ""
})
const dataList = ref<any[]>([])
const eduList = ref<any[]>([])
const planMajorList = ref<any[]>([])
// 初始化方法
const init = (batchNo: string, groupId: string) => {
dataForm.batchNo = batchNo
dataForm.groupId = groupId
visible.value = true
canSubmit.value = true
initData()
}
// 新增 / 修改
const addOrUpdateHandle = (id?: string) => {
addMnStuVisible.value = true
nextTick(() => {
addMnStuRef.value?.init(id || null, dataForm.groupId, dataForm.batchNo)
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delMNObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 获取数据列表
const getDataList = () => {
dataList.value = []
dataListLoading.value = true
emit('refreshDataList')
getMNStuList(dataForm).then((response: any) => {
dataList.value = response.data
dataListLoading.value = false
}).catch(() => {
dataListLoading.value = false
})
}
// 初始化数据
const initData = () => {
eduList.value = []
getTypeValue('finance_student_source').then((res: any) => {
eduList.value = res.data
})
planMajorList.value = []
planMajor({ groupId: dataForm.groupId }).then((data: any) => {
planMajorList.value = data.data
getDataList()
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.avue-crud {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,129 @@
<!--
- 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>
<el-dialog v-model="dialogVisible" title="保存审核人员" width="600px" append-to-body @close="handleClose">
<el-form :model="{ belongTeacherNos }" label-width="100px">
<el-form-item label="选择教师:">
<el-select
v-model="belongTeacherNos"
filterable
remote
clearable
reserve-keyword
placeholder="请选择或输入教师姓名"
:remote-method="remoteTeacherByQuery"
style="width: 100%"
>
<el-option
v-for="item in teacherList"
:key="item.teacherNo"
:label="item.realName"
:value="item.realName"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="AddExamPeopleForm">
import { ref, watch } from 'vue'
import { queryTeacherBaseByNoByAssets } from '/@/api/professional/professionaluser/teacherbase'
// Props
const props = defineProps<{
visible: boolean
timeRange: string[]
}>()
// Emits
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void
(e: 'save', data: { teacherNo: string; startTime: string; endTime: string }): void
}>()
// 弹窗显示状态
const dialogVisible = ref(false)
const belongTeacherNos = ref('')
const teacherList = ref<any[]>([])
// 监听 visible 变化
watch(() => props.visible, (newVal) => {
dialogVisible.value = newVal
if (newVal) {
belongTeacherNos.value = ''
teacherList.value = []
}
})
// 监听 dialogVisible 变化,同步到父组件
watch(dialogVisible, (newVal) => {
emit('update:visible', newVal)
})
// 检索教师
const remoteTeacherByQuery = (query: string) => {
teacherList.value = []
if (query !== '') {
setTimeout(() => {
queryTeacherBaseByNoByAssets(query).then(response => {
teacherList.value = response.data
})
}, 200)
}
}
// 关闭窗口
const handleClose = () => {
belongTeacherNos.value = ''
dialogVisible.value = false
}
// 保存
const handleSave = () => {
if (props.timeRange.length === 0) {
emit('save', {
teacherNo: belongTeacherNos.value,
startTime: '',
endTime: ''
})
return
}
emit('save', {
teacherNo: belongTeacherNos.value,
startTime: props.timeRange[0],
endTime: props.timeRange[1]
})
handleClose()
}
</script>
<style lang="scss" scoped>
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
</style>

View File

@@ -0,0 +1,239 @@
<!--
- 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>
<el-dialog
title="招生审核人员管理"
:close-on-click-modal="false"
v-model="visible"
width="800"
:append-to-body="true"
destroy-on-close
>
<div class="dialog-content">
<!-- 时间选择器和操作按钮 -->
<el-form :inline="true" :model="queryForm">
<el-form-item label="审核时间范围:" label-width="110px">
<el-time-picker
is-range
v-model="form.time1"
format="HH:mm:ss"
value-format="HH:mm:ss"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
placeholder="选择时间范围"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15" v-if="permissions.recruit_recruitexampeople_add">
<el-button
type="primary"
icon="FolderAdd"
@click="handleAdd"
>
</el-button>
</div>
<!-- 表格 -->
<div class="table-wrapper">
<el-table
ref="tableRef"
:data="state.dataList || []"
v-loading="state.loading"
border
stripe
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
empty-text="暂无数据"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="工号" align="center" prop="teacherNo" show-overflow-tooltip>
</el-table-column>
<el-table-column label="姓名" align="center" prop="teacherName" show-overflow-tooltip>
</el-table-column>
<el-table-column label="操作" width="120" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitexampeople_del"
type="primary"
link
icon="Delete"
@click="handleDel(scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination-wrapper">
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
</div>
</div>
<!-- 保存审核人员弹窗 -->
<add-form
v-model:visible="setTeachNoFormVisible"
:time-range="form.time1"
@save="handleSave"
/>
</el-dialog>
</template>
<script setup lang="ts" name="recruitexampeople">
import { ref, reactive, computed, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { addObj, delObj, fetchList } from '/@/api/recruit/recruitexampeople'
const AddForm = defineAsyncComponent(() => import('./add-form.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
// 弹窗状态
const visible = ref(false)
const setTeachNoFormVisible = ref(false)
// 表单数据
const form = reactive({
time1: [] as string[]
})
// 查询表单
const queryForm = reactive<Record<string, any>>({})
// 表格状态
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 || 0
}
}
},
createdIsNeed: false, // 弹窗组件,不在挂载时自动加载数据
dataList: [], // 确保 dataList 初始化为空数组
loading: false, // 确保 loading 初始化为 false
onLoaded: async (state: any) => {
// 如果有数据,设置时间范围
if (state.dataList && state.dataList.length > 0) {
form.time1 = [state.dataList[0].startTime, state.dataList[0].endTime]
}
}
})
// 使用 table hook
// 注意useTable 会直接修改传入的 state 对象,所以不需要从返回值中获取 state
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 初始化
const init = () => {
visible.value = true
form.time1 = []
// 等待弹窗显示后再加载数据
nextTick(() => {
getDataList()
})
}
// 新增
const handleAdd = () => {
setTeachNoFormVisible.value = true
}
// 保存审核人员
const handleSave = async (data: { teacherNo: string; startTime: string; endTime: string }) => {
if (form.time1.length === 0) {
message.error('审核时间不能为空')
return
}
try {
await addObj({
teacherNo: data.teacherNo,
startTime: data.startTime,
endTime: data.endTime
})
message.success('添加成功')
getDataList()
} catch (error: any) {
message.error(error.msg || '添加失败')
}
}
// 删除
const handleDel = async (row: any) => {
try {
await messageBox.confirm(`是否确认删除ID为${row.id}的记录?`)
await delObj(row.id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
getDataList()
}
// 暴露方法
defineExpose({
init
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,318 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
v-model="visible"
width="600px"
destroy-on-close
>
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit"
label-width="120px">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="专业代码" prop="zydm">
<el-input v-model="dataForm.zydm" placeholder="专业代码"></el-input>
</el-form-item>
<el-form-item label="专业名称" prop="zymc">
<el-input v-model="dataForm.zymc" placeholder="专业名称"></el-input>
</el-form-item>
<el-form-item label="专业规范名称" prop="zygfmc">
<el-input v-model="dataForm.zygfmc" placeholder="专业规范名称"></el-input>
</el-form-item>
<el-form-item label="所属学院" prop="deptCode">
<el-select v-model="dataForm.deptCode" filterable placeholder="请选择">
<el-option
v-for="item in deptList"
:key="item.deptCode"
:label="item.deptName"
:value="item.deptCode">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="学制" prop="xz">
<el-select v-model="dataForm.xz" filterable placeholder="请选择学制">
<el-option
v-for="item in majorYears"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="层次" prop="cc">
<el-select v-model="dataForm.cc" filterable placeholder="请选择层次">
<el-option
v-for="item in ccList"
:key="item.label"
:label="item.label"
:value="item.label">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="中德班" prop="isZd">
<el-radio-group v-model="dataForm.isZd">
<el-radio v-for="item in yes_no_type" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="订单班" prop="isOrder">
<el-radio-group v-model="dataForm.isOrder">
<el-radio v-for="item in yes_no_type" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="联院班" prop="isUnion">
<el-radio-group v-model="dataForm.isUnion">
<el-radio v-for="item in yes_no_type" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="正式专业代码" prop="offcialZydm">
<el-select v-model="dataForm.offcialZydm" filterable placeholder="请选择正式专业代码">
<el-option
v-for="item in offcialZydmList"
:key="item.majorCode"
:label="item.majorCodeAndName"
:value="item.majorCode">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="市平台代码" prop="cityPlanId">
<el-select v-model="dataForm.cityPlanId" filterable placeholder="请选择市平台代码">
<el-option
v-for="item in cityPlanIdList"
:key="item.id"
:label="item.schoolMajorName+' | '+item.educational"
:value="item.id"
:disabled="isCityDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number :min="0" :max="999" v-model="dataForm.sort" placeholder="排序"
style="width: 100%"></el-input-number>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input type="textarea" :rows="3" placeholder="请输入备注信息" v-model="dataForm.remarks"
style="width: 100%;margin-top: 10px"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { addObj, getObj, putObj } from '/@/api/recruit/recruitstudentplan'
import { getDeptList } from '/@/api/basic/basicclass'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getMajorNameList } from '/@/api/basic/major'
import { getDicts } from '/@/api/admin/dict'
import { useDict } from '/@/hooks/dict'
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 字典数据
const { yes_no_type } = useDict('yes_no_type')
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const cityPlanIdList = ref<any[]>([])
const offcialZydmList = ref<any[]>([])
const planList = ref<any[]>([])
const deptList = ref<any[]>([])
const ccList = ref<any[]>([])
const majorYears = ref<any[]>([])
const dataForm = reactive({
id: "",
groupId: "",
zydm: "",
zymc: "",
zygfmc: "",
deptCode: "",
xz: "",
cc: "",
isZd: "0",
isOrder: "0",
remarks: "",
offcialZydm: "",
isUnion: "0",
tuitionFee: 0,
cityPlanId: null as string | null,
cityPlanIds: [] as string[],
cityPlanName: "",
cityPlanYear: "",
sort: 0
})
const dataRule = {
zydm: [
{ required: true, message: '专业代码不能为空', trigger: 'blur' },
{ min: 1, max: 6, message: '专业代码长度不大于6个字符', trigger: 'blur' }
],
tuitionFee: [
{ required: true, message: '学费不能为空', trigger: 'blur' }
],
zymc: [
{ required: true, message: '专业名称不能为空', trigger: 'blur' },
{ min: 1, max: 200, message: '专业名称长度不大于200个字符', trigger: 'blur' }
],
zygfmc: [
{ required: true, message: '专业规范名称不能为空', trigger: 'blur' },
{ min: 1, max: 200, message: '专业规范名称长度不大于200个字符', trigger: 'blur' }
],
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'blur' }
],
xz: [
{ required: true, message: '学制不能为空', trigger: 'blur' }
],
deptCode: [
{ required: true, message: '学院不能为空', trigger: 'blur' }
],
cc: [
{ required: true, message: '层次不能为空', trigger: 'blur' }
],
isOrder: [
{ required: true, message: '订单班不能为空', trigger: 'blur' }
],
isZd: [
{ required: true, message: '订单班不能为空', trigger: 'blur' }
],
isUnion: [
{ required: true, message: '联院班不能为空', trigger: 'blur' }
],
remarks: [
{ min: 1, max: 100, message: '备注长度不大于100个字符', trigger: 'blur' }
],
}
/**
* 判断市平台招生专业是否占用,占用不可选
*/
const isCityDisable = (id: string) => {
if (!dataForm.cityPlanIds || !Array.isArray(dataForm.cityPlanIds)) {
return false
}
return dataForm.cityPlanIds.some(e => e == id)
}
// 初始化数据
const initData = () => {
// 查询二级学院信息
getDeptList().then((data: any) => {
deptList.value = data.data
})
list().then((data: any) => {
planList.value = data.data
if (!dataForm.id) {
dataForm.groupId = planList.value[0]?.id || ""
}
})
getMajorNameList().then((data: any) => {
offcialZydmList.value = data.data
})
// 获取数据字典
getDicts('basic_major_years').then((res: any) => {
majorYears.value = res.data || []
})
getDicts('basic_major_level').then((res: any) => {
ccList.value = res.data || []
})
}
// 表单提交
const dataFormSubmit = () => {
if (dataForm.cityPlanId != null) {
cityPlanIdList.value.forEach(e => {
if (e.id == dataForm.cityPlanId) {
dataForm.cityPlanName = e.schoolMajorName
dataForm.cityPlanYear = e.educational
}
})
}
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
// 获取市平台对应年份下的招生计划
// getCityPlan({ id: dataForm.id }).then((data: any) => {
// cityPlanIdList.value = data.data
// })
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,339 @@
<!--
- 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="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="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="zydm">
<el-input v-model="queryForm.zydm" placeholder="专业序号" />
</el-form-item>
<el-form-item label="专业名称" prop="zymc">
<el-input v-model="queryForm.zymc" placeholder="专业名称" />
</el-form-item>
<el-form-item label="学制" prop="xz">
<el-input v-model="queryForm.xz" placeholder="学制" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitplanmajor_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle"
>
</el-button>
</div>
<!-- 表格 -->
<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="groupId" label="招生计划名称" align="center" min-width="140" show-overflow-tooltip>
<template #default="scope">
{{ getPlanName(scope.row.groupId) }}
</template>
</el-table-column>
<el-table-column prop="zydm" label="专业序号" align="center" show-overflow-tooltip />
<el-table-column prop="zymc" label="专业名称" align="center" show-overflow-tooltip />
<!-- <el-table-column prop="zygfmc" label="专业规范名称" align="center" show-overflow-tooltip /> -->
<el-table-column prop="deptCode" label="学院" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getDeptName(scope.row.deptCode) }}
</template>
</el-table-column>
<el-table-column prop="xz" label="学制" align="center" width="80" show-overflow-tooltip />
<el-table-column prop="cc" label="层次" align="center" show-overflow-tooltip />
<el-table-column prop="isOrder" label="订单班" align="center" width="80" show-overflow-tooltip>
<template #default="scope">
{{ getYesNoLabel(scope.row.isOrder) }}
</template>
</el-table-column>
<el-table-column prop="isZd" label="中德班" align="center" width="80" show-overflow-tooltip>
<template #default="scope">
{{ getYesNoLabel(scope.row.isZd) }}
</template>
</el-table-column>
<el-table-column prop="isUnion" label="联院班" align="center" width="80" show-overflow-tooltip>
<template #default="scope">
{{ getYesNoLabel(scope.row.isUnion) }}
</template>
</el-table-column>
<el-table-column prop="sm" label="色盲不可录" align="center" width="120">
<template #default="scope">
<el-switch
v-model="scope.row.sm"
active-text=""
inactive-text=""
active-value="1"
inactive-value="0"
@change="changeSm(scope.row)"
/>
</template>
</el-table-column>
<el-table-column prop="offcialZydm" label="正式专业代码" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getMajorCodeName(scope.row.offcialZydm) }}
</template>
</el-table-column>
<!-- <el-table-column prop="cityPlanId" label="市平台招生计划" align="center" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.cityPlanName != undefined ? (scope.row.cityPlanName + '|' + scope.row.cityPlanYear) : '' }}
</template>
</el-table-column> -->
<!-- <el-table-column prop="sort" label="排序" align="center" show-overflow-tooltip /> -->
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitplanmajor_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
修改
</el-button>
<el-button
v-if="permissions.recruit_recruitplanmajor_del"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form ref="addOrUpdateRef" @refreshDataList="getDataList" />
</div>
</div>
</template>
<script setup lang="ts" name="recruitplanmajor">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { fetchList, putObj, delObj } from '/@/api/recruit/recruitstudentplan'
import { getDeptList } from '/@/api/basic/basicclass'
import { getMajorNameList } from '/@/api/basic/major'
const TableForm = defineAsyncComponent(() => import('./detaiform.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
// 字典数据
const { yes_no_type } = useDict('yes_no_type')
// 数据
const planList = ref<any[]>([])
const deptList = ref<any[]>([])
const offcialZydmList = ref<any[]>([])
// 查询表单
const queryForm = reactive({
groupId: '',
deptCode: '',
zydm: '',
zymc: '',
xz: ''
})
// 获取计划名称
const getPlanName = (groupId: string) => {
const item = planList.value.find(item => item.id === groupId)
return item ? item.groupName : ''
}
// 获取学院名称
const getDeptName = (deptCode: string) => {
const item = deptList.value.find(item => item.deptCode === deptCode)
return item ? item.deptName : ''
}
// 获取是/否标签
const getYesNoLabel = (value: string) => {
const item = yes_no_type.value.find((item: any) => item.value === value)
return item ? item.label : ''
}
// 获取专业代码名称
const getMajorCodeName = (majorCode: string) => {
const item = offcialZydmList.value.find(item => item.majorCode === majorCode)
return item ? item.majorCodeAndName : ''
}
// 表格状态
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 deptData = await getDeptList()
deptList.value = deptData.data || []
// 获取招生计划列表
const planData = await list()
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
// 获取专业名称列表
const majorData = await getMajorNameList()
offcialZydmList.value = majorData.data || []
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 修改开关
const changeSm = async (row: any) => {
try {
await putObj(row)
message.success('修改成功')
} catch (error: any) {
message.error(error.msg || '修改失败')
}
}
// 新增 / 修改
const addOrUpdateHandle = (id?: string) => {
nextTick(() => {
addOrUpdateRef.value?.init(id || null)
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
queryForm.deptCode = ''
queryForm.zydm = ''
queryForm.zymc = ''
queryForm.xz = ''
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,272 @@
<template>
<el-dialog
title="招生计划专业调整"
append-to-body
width="90%"
:close-on-click-modal="false"
v-model="visible">
<el-form :model="dataForm" ref="dataFormRef" label-width="140px">
<el-form-item label="招生计划名称" prop="groupName">
<el-input v-model="dataForm.groupName" placeholder="招生计划名称" disabled></el-input>
</el-form-item>
</el-form>
<el-tabs v-model="activiName" @tab-click="handleChange">
<el-tab-pane v-for="item in deptList"
:key="item.deptCode"
:label="item.deptName"
:name="item.deptCode">
<div style="margin-top: 20px;">
<el-table
:data="dataList"
border
stripe
v-loading="dataListLoading">
<el-table-column
prop="zymc"
header-align="center"
align="center"
label="专业"
>
<template #default="scope">
<span>{{ scope.row.zymc+' || '+scope.row.zydm+' || '+scope.row.xz+' 年制'}}</span>
</template>
</el-table-column>
<el-table-column
prop="planStudentNum"
header-align="center"
align="center"
label="计划总数"
width="180px"
>
<template #default="scope">
<el-input-number style="width: 80%" v-model="scope.row.planStudentNum" :min="0" :max="999" @change="updateMajor(scope.row)" width="100px"></el-input-number>
</template>
</el-table-column>
<el-table-column
prop="needStudentNum"
header-align="center"
align="center"
label="控制数"
width="180px"
>
<template #default="scope">
<el-input-number style="width: 80%" v-model="scope.row.needStudentNum" :min="0" :max="999"
@change="updateMajor(scope.row)"></el-input-number>
</template>
</el-table-column>
<el-table-column
prop="needStudentOverNum"
header-align="center"
align="center"
label="预留"
width="180px"
>
<template #default="scope">
<el-input-number style="width: 80%" v-model="scope.row.needStudentOverNum" :min="0" :max="999"
@change="updateMajor(scope.row)"></el-input-number>
</template>
</el-table-column>
<el-table-column
prop="scoreLine"
header-align="center"
align="center"
label="录取线"
width="180px"
>
<template #default="scope">
<el-input-number style="width: 80%" v-model="scope.row.scoreLine" :min="0" :max="999"
@change="updateMajor(scope.row)"></el-input-number>
</template>
</el-table-column>
<el-table-column
prop="degreeOfEducation"
header-align="center"
align="center"
label="生源">
<template #default="scope">
<el-select v-model="scope.row.degreeOfEducation" placeholder="请选择生源" style=" width: 100%;text-align:center" multiple
@change="updateMajor(scope.row)">
<el-option
v-for="item in degreeOfEducationList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { ElNotification } from 'element-plus'
import { listPlanByCondition as list, delObj ,putObj} from '/@/api/recruit/recruitstudentplan'
import { fetchSecondTree } from '/@/api/basic/basicdept'
import { getDicts } from "/@/api/admin/dict"
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const activiName = ref("11")
const dataList = ref<any[]>([])
const deptList = ref<any[]>([])
const degreeOfEducationList = ref<any[]>([])
const dataListLoading = ref(false)
const dataForm = reactive({
groupId: "",
groupName: "",
deptCode: "11",
})
// 初始化数据
const initData = () => {
degreeOfEducationList.value = []
// 获取数据字典
getDicts("finance_student_source").then((res: any) => {
degreeOfEducationList.value = res.data || []
}).catch((error: any) => {
message.error('获取字典数据失败:' + (error.msg || '未知错误'))
degreeOfEducationList.value = []
})
}
// 获取部门列表
const getDepartment = () => {
fetchSecondTree().then((res: any) => {
deptList.value = res.data || []
}).catch((error: any) => {
message.error('获取部门列表失败:' + (error.msg || '未知错误'))
deptList.value = []
})
}
// 更新专业
const updateMajor = (row: any) => {
if (!row || !row.planId) {
message.error('缺少必要的参数planId')
return
}
if (row.degreeOfEducation && Array.isArray(row.degreeOfEducation) && row.degreeOfEducation.length != 0) {
row.degreeOfEducations = row.degreeOfEducation.join(",")
} else {
row.degreeOfEducations = ""
}
putObj({
id: row.planId,
planStudentNum: row.planStudentNum || 0,
planStudentBoyNum: row.planStudentBoyNum || 0,
planStudentGirlNum: row.planStudentGirlNum || 0,
needStudentNum: row.needStudentNum || 0,
needStudentOverNum: row.needStudentOverNum || 0,
scoreLine: row.scoreLine || 0,
scoreMinLine: row.scoreMinLine || 0,
degreeOfEducations: row.degreeOfEducations || ""
}).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
}).catch((error: any) => {
message.error('修改失败:' + (error.msg || '未知错误'))
})
}
// 标签切换
const handleChange = (tab: any) => {
dataForm.deptCode = tab.name
getDataList()
}
// 获取数据列表
const getDataList = () => {
if (!dataForm.groupId) {
dataListLoading.value = false
return
}
dataList.value = []
dataListLoading.value = true
if (dataForm.deptCode == '') {
dataForm.deptCode = "11"
}
list({ groupId: dataForm.groupId, deptCode: dataForm.deptCode }).then((response: any) => {
dataList.value = response.data || []
dataList.value.forEach((e: any) => {
if (e.degreeOfEducation && typeof e.degreeOfEducation === 'string') {
e.degreeOfEducation = e.degreeOfEducation.split(",")
}
})
dataListLoading.value = false
}).catch((error: any) => {
message.error('获取数据失败:' + (error.msg || '未知错误'))
dataListLoading.value = false
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 初始化方法
const init = (row: any) => {
if (!row) {
message.error('初始化参数错误')
return
}
if (!row.id || !row.groupName) {
message.error('缺少必要的参数id 或 groupName')
return
}
try {
visible.value = true
dataForm.deptCode = "11"
dataForm.groupName = row.groupName || ''
dataForm.groupId = row.id || ''
initData()
getDepartment()
getDataList()
} catch (error: any) {
message.error('初始化失败:' + (error.message || '未知错误'))
visible.value = false
}
}
// 暴露方法给父组件
defineExpose({
init,
deleteHandle
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,431 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
v-model="visible"
width="600px"
>
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit" label-width="120px">
<el-form-item label="招生计划名称" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划" :disabled="!!dataForm.id">
<el-option
v-for="item in planListLocal"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="dataForm.name" placeholder="姓名"></el-input>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="dataForm.phone" placeholder="电话"></el-input>
</el-form-item>
<el-form-item label="身份证" prop="idCard">
<el-input v-model="dataForm.idCard" placeholder="身份证"></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-select v-model="dataForm.gender">
<el-option
v-for="item in sexyList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="准考证" prop="admission">
<el-input v-model="dataForm.admission" placeholder="准考证"></el-input>
</el-form-item>
<el-form-item label="中考成绩" prop="achievement">
<el-input-number v-model="dataForm.achievement" :min="0" :max="700" placeholder="中考成绩"></el-input-number>
</el-form-item>
<el-form-item label="对接人" prop="djUser" v-if="permissions.recruit_recruitprestudent_dj_sure">
<el-select v-model="dataForm.djUser" filterable clearable placeholder="">
<el-option
v-for="item in contactNameList"
:key="item.teacherNo"
:label="item.realName+'-'+item.deptCode"
:value="item.teacherNo">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="学校" prop="schoolId">
<el-select v-model="dataForm.schoolId" filterable placeholder="请选择学校">
<el-option
v-for="item in schoolList"
:key="item.id"
:label="item.schoolName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业1" prop="planMajorOne">
<el-select v-model="dataForm.planMajorOne" filterable placeholder="请选择拟报专业1">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业2" prop="planMajorTwo">
<el-select v-model="dataForm.planMajorTwo" filterable clearable placeholder="请选择拟报专业2">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业3" prop="planMajorThree">
<el-select v-model="dataForm.planMajorThree" filterable clearable placeholder="请选择拟报专业3">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业4" prop="planMajorFour">
<el-select v-model="dataForm.planMajorFour" filterable clearable placeholder="请选择拟报专业4">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业5" prop="planMajorFive">
<el-select v-model="dataForm.planMajorFive" filterable clearable placeholder="请选择拟报专业5">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业6" prop="planMajorSix">
<el-select v-model="dataForm.planMajorSix" filterable clearable placeholder="请选择拟报专业6">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业7" prop="planMajorSeven">
<el-select v-model="dataForm.planMajorSeven" filterable clearable placeholder="请选择拟报专业7">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业8" prop="planMajorEight">
<el-select v-model="dataForm.planMajorEight" filterable clearable placeholder="请选择拟报专业8">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业9" prop="planMajorNine">
<el-select v-model="dataForm.planMajorNine" filterable clearable placeholder="请选择拟报专业9">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业10" prop="planMajorTen">
<el-select v-model="dataForm.planMajorTen" filterable clearable placeholder="请选择拟报专业10">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业11" prop="planMajorEleven">
<el-select v-model="dataForm.planMajorEleven" filterable clearable placeholder="请选择拟报专业11">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="拟报专业12" prop="planMajorTwelve">
<el-select v-model="dataForm.planMajorTwelve" filterable clearable placeholder="请选择拟报专业12">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc"
:value="item.id"
:disabled="isDisable(item.id)"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { ElNotification } from 'element-plus'
import { getObj, addObjStu, putObj } from '/@/api/recruit/recruitprestudent'
import { queryTeacherBaseByNoByAssets } from '/@/api/professional/professionaluser/teacherbase'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getDicts } from '/@/api/admin/dict'
// Props
const props = defineProps<{
planList?: any[]
planMajorList?: any[]
schoolList?: any[]
}>()
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 使用 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 dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const contactNameList = ref<any[]>([])
const planListLocal = ref<any[]>([])
const sexyList = ref<any[]>([])
const dataForm = reactive({
id: "",
groupId: "",
name: "",
gender: "",
phone: "",
idCard: "",
schoolId: "",
planMajorOne: "",
planMajorTwo: "",
planMajorThree: "",
planMajorFour: "",
planMajorFive: "",
planMajorSix: "",
planMajorSeven: "",
planMajorEight: "",
planMajorNine: "",
planMajorTen: "",
planMajorEleven: "",
planMajorTwelve: "",
admission: "",
achievement: null as number | null,
contactsNo: "",
djUser: null as string | null,
djTime: null as string | null,
djName: null as string | null,
djDept: null as string | null,
isDj: "0",
year: ""
})
const dataRule = {
planMajorOne: [
{ required: true, message: '拟报专业1不能为空', trigger: 'blur' }
],
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'blur' }
],
name: [
{ required: true, message: '姓名不能为空', trigger: 'blur' },
{ min: 1, max: 20, message: "姓名长度最多20位", trigger: "blur" }
],
phone: [
{ required: true, message: '电话不能为空', trigger: 'blur' },
{ min: 11, max: 11, message: "电话号码长度为11位", trigger: "blur" }
],
gender: [
{ required: true, message: '性别不能为空', trigger: 'blur' }
],
schoolId: [
{ required: true, message: '学校不能为空', trigger: 'blur' }
],
}
/**
* 判断拟报专业是否已经占用,占用不可选
*/
const isDisable = (id: string) => {
if (id == dataForm.planMajorOne
|| id == dataForm.planMajorTwo
|| id == dataForm.planMajorThree
|| id == dataForm.planMajorFour
|| id == dataForm.planMajorFive
|| id == dataForm.planMajorSix
|| id == dataForm.planMajorSeven
|| id == dataForm.planMajorEight
|| id == dataForm.planMajorNine
|| id == dataForm.planMajorTen
|| id == dataForm.planMajorEleven
|| id == dataForm.planMajorTwelve
) {
return true
} else {
return false
}
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
dataForm.djUser = null
dataForm.djTime = null
dataForm.djName = null
dataForm.djDept = null
dataForm.isDj = "0"
addObjStu(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
// 初始化 planListLocal优先使用 props如果没有则使用空数组
planListLocal.value = props.planList ? [...props.planList] : []
nextTick(() => {
dataFormRef.value?.resetFields()
// 获取性别字典
getDicts('sexy').then((res: any) => {
sexyList.value = res.data || []
})
// 这里如果需要教师列表,可以改用新的教师接口;当前项目中常用的是 queryTeacherBaseByNoByAssets
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
if (dataForm.year) {
dataForm.year = String(dataForm.year)
}
})
} else {
list().then((data: any) => {
planListLocal.value = data.data
if (planListLocal.value.length > 0) {
dataForm.groupId = planListLocal.value[0].id
}
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,394 @@
<!--
- 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="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="请选择招生计划" @change="changeG">
<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="isDj">
<el-select v-model="queryForm.isDj" filterable clearable placeholder="请选择是否对接">
<el-option
v-for="item in isDjList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="对接人" prop="djUser">
<el-input v-model="queryForm.djName" type="text" placeholder="请输入对接人" />
</el-form-item>
<el-form-item label="姓名/身份证/电话" prop="name">
<el-input v-model="queryForm.name" clearable placeholder="请填写学生姓名/身份证/电话" />
</el-form-item>
<el-form-item label="学校" prop="schoolId">
<el-select v-model="queryForm.schoolId" filterable clearable placeholder="请选择学校">
<el-option
v-for="item in schoolList"
:key="item.id"
:label="item.schoolName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="拟报专业" prop="planMajorOne">
<el-select v-model="queryForm.planMajorOne" filterable clearable placeholder="请选择拟报专业">
<el-option
v-for="item in planMajorList"
:key="item.id"
:label="item.zymc + ' || ' + item.zydm"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitprestudent_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle(null)"
>
新增
</el-button>
<el-button
type="warning"
plain
icon="Download"
class="ml10"
:loading="exportLoading"
@click="dataExportHandle"
>
导出
</el-button>
</div>
<!-- 表格 -->
<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 label="操作" width="200" align="center" fixed="left">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitprestudent_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
调整
</el-button>
<el-button
v-if="permissions.recruit_recruitprestudent_dj && scope.row.isDj == '0'"
type="success"
link
icon="CircleCheck"
@click="sureDJ(scope.row.id)"
>
确认对接
</el-button>
<el-button
v-if="permissions.recruit_recruitprestudent_del"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
<el-table-column prop="djName" label="对接人" width="150" align="center">
<template #default="scope">
{{ scope.row.djName }} <br />
<span style="color: #0e90d2">{{ scope.row.djTime }}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="学生姓名" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="phone" label="电话" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="achievement" label="中考分数" width="90" align="center" show-overflow-tooltip />
<el-table-column prop="admission" label="准考证号" width="120" align="left" show-overflow-tooltip />
<el-table-column prop="planMajorOne" label="拟报专业1" align="left" show-overflow-tooltip>
<template #default="scope">
{{ getMajorName(scope.row.planMajorOne) }}
</template>
</el-table-column>
<el-table-column prop="schoolId" label="学校" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getSchoolName(scope.row.schoolId) }}
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form
ref="addOrUpdateRef"
@refreshDataList="getDataList"
:planList="planList"
:planMajorList="planMajorList"
:schoolList="schoolList"
/>
</div>
</div>
</template>
<script setup lang="ts" name="recruitprestudent">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useDict } from '/@/hooks/dict'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { delObj, fetchList, sureDJ } from '/@/api/recruit/recruitprestudent'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { listcz } from '/@/api/recruit/recruitstudentplan'
import { list as schoolListApi } from '/@/api/recruit/recruitstudentschool'
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept'
const TableForm = defineAsyncComponent(() => import('./enrolplantemplate-form.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
// 弹窗状态
const exportLoading = ref(false)
// 字典数据
const { yes_no_type: isDjList } = useDict('yes_no_type')
// 数据
const planList = ref<any[]>([])
const deptList = ref<any[]>([])
const schoolList = ref<any[]>([])
const planMajorList = ref<any[]>([])
// 查询表单
const queryForm = reactive({
groupId: '',
deptCode: '',
isDj: '',
djName: '',
name: '',
schoolId: '',
planMajorOne: ''
})
// 获取专业名称
const getMajorName = (majorId: string) => {
const item = planMajorList.value.find(item => item.id === majorId)
return item ? item.zymc : ''
}
// 获取学校名称
const getSchoolName = (schoolId: string) => {
const item = schoolList.value.find(item => item.id === schoolId)
return item ? item.schoolName : ''
}
// 表格状态
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, downBlobFile } = useTable(state)
// 初始化
const init = async () => {
try {
// 获取部门列表
const deptData = await getDeptListByLevelTwo()
deptList.value = deptData.data || []
// 获取招生计划列表
const planData = await list()
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
await getMajor(queryForm.groupId)
// 获取学校列表
const schoolData = await schoolListApi({ groupId: queryForm.groupId })
schoolList.value = schoolData.data || []
}
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 招生计划改变
const changeG = async () => {
if (queryForm.groupId) {
await getMajor(queryForm.groupId)
const schoolData = await schoolListApi({ groupId: queryForm.groupId })
schoolList.value = schoolData.data || []
}
}
// 获取专业列表
const getMajor = async (groupId: string) => {
try {
const data = await listcz({ groupId })
planMajorList.value = data.data || []
getDataList()
} catch (error) {
console.error('获取专业列表失败', error)
}
}
// 新增 / 修改
const addOrUpdateHandle = (id?: string | null) => {
nextTick(() => {
addOrUpdateRef.value?.init(id ?? null)
})
}
// 确认对接
const sureDJ = async (id: string) => {
try {
await messageBox.confirm('是否确认已对接?请谨慎操作')
await sureDJ({ id, isDj: '1' })
message.success('确认成功')
getDataList()
} catch {
// 用户取消
}
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
queryForm.deptCode = ''
queryForm.isDj = ''
queryForm.djName = ''
queryForm.name = ''
queryForm.schoolId = ''
queryForm.planMajorOne = ''
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
// 导出
const dataExportHandle = async () => {
try {
exportLoading.value = true
await downBlobFile(
'/recruit/recruitprestudent/export',
queryForm,
'预登记导出.xls'
)
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,145 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划" @change="handleFilter">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleFilter">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button type="warning" plain icon="Download" :loading="exportLoading" @click="dataExportHandle">导出</el-button>
</div>
<el-table
:data="state.dataList"
border
stripe
v-loading="state.loading"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column prop="zymc" header-align="center" align="center" label="专业" />
<el-table-column prop="number" header-align="center" align="center" label="人数" />
<el-table-column prop="rate" header-align="center" align="center" label="占比" />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="recruitprestudent-static">
import { ref, reactive, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { fetchListStatic } from '/@/api/recruit/recruitprestudent'
import { list } from '/@/api/recruit/recruitstudentplangroup'
// @ts-ignore
import global from '/@/components/tools/commondict.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
})
// 消息提示 hooks
const message = useMessage()
// 引用
const searchFormRef = ref()
// 状态
const planList = ref<any[]>([])
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
groupId: ''
})
// 表格状态
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: queryForm,
pageList: async (params: any) => {
const response = await fetchListStatic(params)
return {
data: {
records: response.data || [],
total: response.data?.length || 0
}
}
},
createdIsNeed: false
})
// 使用 table hook
const { getDataList, tableStyle, downBlobFile } = useTable(state)
// 初始化
const init = async () => {
try {
const data = await list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
getDataList()
}
} catch (error) {
console.error('初始化失败', error)
}
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
// 导出
const dataExportHandle = async () => {
try {
exportLoading.value = true
await downBlobFile(
'/recruit/recruitprestudent/staticExport',
queryForm,
'预登记统计.xls'
)
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
onMounted(() => {
init()
})
</script>

View File

@@ -0,0 +1,147 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
v-model="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit" label-width="140px">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable :disabled="!!dataForm.id" placeholder="请选择招生计划" size="small" style="width: 100%">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="学校名称" prop="schoolName">
<el-input v-model="dataForm.schoolName" placeholder="学校名称"></el-input>
</el-form-item>
<el-form-item label="学校代码" prop="schoolCode">
<el-input v-model="dataForm.schoolCode" placeholder="学校代码"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { addObj, getObj, putObj } from '@/api/recruit/recruitschoolcode'
import { list } from "@/api/recruit/recruitstudentplangroup"
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const planList = ref<any[]>([])
const dataForm = reactive({
id: "",
groupId: "",
schoolName: "",
schoolCode: "",
area: ""
})
const dataRule = {
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'blur' },
],
schoolName: [
{ required: true, message: '学校名称不能为空', trigger: 'blur' },
{ min: 1, max: 20, message: '学校名称长度不大于20个字符', trigger: 'blur' }
],
schoolCode: [
{ required: true, message: '学校代码不能为空', trigger: 'blur' },
{ min: 4, max: 4, message: '学校代码长度为4个字符', trigger: 'blur' }
],
}
// 初始化数据
const initData = () => {
list().then((data: any) => {
planList.value = data.data
if (!dataForm.id) {
dataForm.groupId = planList.value[0]?.id || ""
}
})
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
if (dataForm.area) {
dataForm.area = String(dataForm.area)
}
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,372 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4" 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="schoolName">
<el-input v-model="queryForm.schoolName" clearable placeholder="学校名称" />
</el-form-item>
<el-form-item label="学校代码" prop="schoolCode">
<el-input v-model="queryForm.schoolCode" clearable placeholder="学校代码" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitschoolcode_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle"
>
新增
</el-button>
<el-button
v-if="permissions.recruit_recruitschoolcode_add"
type="primary"
plain
icon="UploadFilled"
class="ml10"
@click="handleExportIn"
>
导入
</el-button>
</div>
<!-- 表格 -->
<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="groupId" label="招生计划名称" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getPlanName(scope.row.groupId) }}
</template>
</el-table-column>
<el-table-column prop="schoolCode" label="学校代码" align="center" show-overflow-tooltip />
<el-table-column prop="schoolName" label="学校名称" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitschoolcode_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
修改
</el-button>
<el-button
v-if="permissions.recruit_recruitschoolcode_del"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form v-if="addOrUpdateVisible" ref="addOrUpdateRef" @refreshDataList="getDataList" />
<!-- 导入弹窗 -->
<el-dialog v-model="dialogViewVisible" title="导入学校代码" append-to-body>
<el-form :model="exportForm" inline>
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="exportForm.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>
<el-upload
class="upload-container"
ref="uploadFormRef"
action="doUpload"
:limit="1"
:file-list="fileList"
:before-upload="beforeUpload"
>
<template #trigger>
<el-button type="primary">选取文件</el-button>
</template>
<a href="schoolCode.xlsx" rel="external nofollow" download="常州中学代码模版">
<el-button type="success" class="ml10">下载模板</el-button>
</a>
<template #tip>
<div class="el-upload__tip">只能上传excel文件且不超过5MB</div>
<div class="el-upload-list__item-name">{{ fileName }}</div>
</template>
</el-upload>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogViewVisible = false; impoerLoadinBtn = false">取消</el-button>
<el-button type="primary" @click="submitUpload" :loading="impoerLoadinBtn">导入</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts" name="recruitschoolcode">
import { ref, reactive, computed, onMounted, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { delObj, fetchList } from '/@/api/recruit/recruitschoolcode'
import request from '/@/utils/request'
const TableForm = defineAsyncComponent(() => import('./detaiform.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
const uploadFormRef = ref()
// 弹窗状态
const addOrUpdateVisible = ref(false)
const dialogViewVisible = ref(false)
const impoerLoadinBtn = ref(false)
// 数据
const planList = ref<any[]>([])
const fileList = ref<any[]>([])
const fileName = ref('')
const files = ref<File | null>(null)
// 查询表单
const queryForm = reactive({
groupId: '',
schoolName: '',
schoolCode: ''
})
// 导出表单
const exportForm = reactive({
groupId: ''
})
// 获取计划名称
const getPlanName = (groupId: string) => {
const item = planList.value.find(item => item.id === groupId)
return item ? item.groupName : ''
}
// 表格状态
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 list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 上传验证
const beforeUpload = (file: File) => {
const fileLast = file.name.split('.')
const extension = fileLast[fileLast.length - 1] === 'xls'
const extension2 = fileLast[fileLast.length - 1] === 'xlsx'
const isLt2M = file.size / 1024 / 1024 < 5
if (!extension && !extension2) {
message.warning('上传模板只能是 xls、xlsx格式!')
return false
}
if (!isLt2M) {
message.warning('上传模板大小不能超过 5MB!')
return false
}
fileName.value = file.name
files.value = file
return false // 返回false不会自动上传
}
// 提交上传
const submitUpload = async () => {
if (fileName.value === '') {
message.warning('请选择要上传的文件!')
return
}
if (exportForm.groupId === '') {
message.warning('请选择招生计划!')
return
}
impoerLoadinBtn.value = true
try {
const fileFormData = new FormData()
fileFormData.append('file', files.value!, fileName.value)
const res = await request({
method: 'post',
url: `/recruit/recruitschoolcode/exportSchoolCode?groupId=${exportForm.groupId}`,
data: fileFormData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
if (res.data === 'fail') {
message.error('请上传正确的学校代码模板')
return
}
if (res.data && res.data === 0) {
message.error(res.data.msg)
} else if (res.data && res.data === 10) {
message.error(res.data.msg)
} else {
message.success('操作成功')
dialogViewVisible.value = false
state.pagination!.current = 1
getDataList()
}
} catch (error: any) {
message.error(error.msg || '导入失败')
} finally {
impoerLoadinBtn.value = false
}
}
// 导入
const handleExportIn = () => {
fileName.value = ''
exportForm.groupId = ''
dialogViewVisible.value = true
}
// 新增 / 修改
const addOrUpdateHandle = (id?: string) => {
addOrUpdateVisible.value = true
nextTick(() => {
addOrUpdateRef.value?.init(id)
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,321 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4">
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
<el-form-item v-if="permissions.recruit_recruitstudentplan_add">
<el-button type="primary" icon="FolderAdd" class="ml10" @click="handleAdd">新增</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="zydm" label="专业代码" align="center" show-overflow-tooltip />
<el-table-column prop="xy" label="系部" align="center" show-overflow-tooltip />
<el-table-column prop="needStudentNum" label="拟招人数(不限男女)和拟招男女生数互斥" align="center" show-overflow-tooltip />
<el-table-column prop="needStudentBoyNum" label="拟招男生数" align="center" show-overflow-tooltip />
<el-table-column prop="needStudentGirlNum" label="拟招女生数" align="center" show-overflow-tooltip />
<el-table-column prop="needStudentOverNum" label="拟招过载人数(不限男女) 和拟招过载男女生数互斥" align="center" show-overflow-tooltip />
<el-table-column prop="needStudentOverBoyNum" label="拟招过载男生数" align="center" show-overflow-tooltip />
<el-table-column prop="needStudentOverGirlNum" label="拟招过载女生数" align="center" show-overflow-tooltip />
<el-table-column prop="scoreLine" label="录取分数线" align="center" show-overflow-tooltip />
<el-table-column prop="scoreMinLine" label="最低录取分数线" align="center" show-overflow-tooltip />
<el-table-column prop="planStudentNum" label="计划招生人数(不限男女)" align="center" show-overflow-tooltip />
<el-table-column prop="planStudentBoyNum" label="计划招生男生数" align="center" show-overflow-tooltip />
<el-table-column prop="planStudentGirlNum" label="计划招生女生数" align="center" show-overflow-tooltip />
<el-table-column prop="degreeOfEducation" label="生源" align="center" show-overflow-tooltip />
<el-table-column prop="scoreFeeConf" label="捐资助学费配置" align="center" show-overflow-tooltip />
<el-table-column prop="tuition" label="学费配置,和生源对应" align="center" show-overflow-tooltip />
<el-table-column prop="remarks" label="备注信息" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentplan_edit"
type="primary"
link
icon="EditPen"
@click="handleEdit(scope.row)"
>
编辑
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentplan_del"
type="danger"
link
icon="Delete"
@click="handleDel(scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 新增/编辑弹窗 -->
<el-dialog
v-model="dialogVisible"
:title="form.id ? '编辑' : '新增'"
width="600px"
:close-on-click-modal="false"
destroy-on-close
>
<el-form
ref="formRef"
:model="form"
:rules="formRules"
label-width="180px"
>
<el-form-item label="专业代码" prop="zydm">
<el-input v-model="form.zydm" placeholder="请输入专业代码" clearable />
</el-form-item>
<el-form-item label="系部" prop="xy">
<el-input v-model="form.xy" placeholder="请输入系部" clearable />
</el-form-item>
<el-form-item label="拟招人数(不限男女)" prop="needStudentNum">
<el-input-number v-model="form.needStudentNum" :min="0" placeholder="请输入拟招人数" style="width: 100%" />
</el-form-item>
<el-form-item label="拟招男生数" prop="needStudentBoyNum">
<el-input-number v-model="form.needStudentBoyNum" :min="0" placeholder="请输入拟招男生数" style="width: 100%" />
</el-form-item>
<el-form-item label="拟招女生数" prop="needStudentGirlNum">
<el-input-number v-model="form.needStudentGirlNum" :min="0" placeholder="请输入拟招女生数" style="width: 100%" />
</el-form-item>
<el-form-item label="拟招过载人数(不限男女)" prop="needStudentOverNum">
<el-input-number v-model="form.needStudentOverNum" :min="0" placeholder="请输入拟招过载人数" style="width: 100%" />
</el-form-item>
<el-form-item label="拟招过载男生数" prop="needStudentOverBoyNum">
<el-input-number v-model="form.needStudentOverBoyNum" :min="0" placeholder="请输入拟招过载男生数" style="width: 100%" />
</el-form-item>
<el-form-item label="拟招过载女生数" prop="needStudentOverGirlNum">
<el-input-number v-model="form.needStudentOverGirlNum" :min="0" placeholder="请输入拟招过载女生数" style="width: 100%" />
</el-form-item>
<el-form-item label="录取分数线" prop="scoreLine">
<el-input-number v-model="form.scoreLine" :min="0" placeholder="请输入录取分数线" style="width: 100%" />
</el-form-item>
<el-form-item label="最低录取分数线" prop="scoreMinLine">
<el-input-number v-model="form.scoreMinLine" :min="0" placeholder="请输入最低录取分数线" style="width: 100%" />
</el-form-item>
<el-form-item label="计划招生人数(不限男女)" prop="planStudentNum">
<el-input-number v-model="form.planStudentNum" :min="0" placeholder="请输入计划招生人数" style="width: 100%" />
</el-form-item>
<el-form-item label="计划招生男生数" prop="planStudentBoyNum">
<el-input-number v-model="form.planStudentBoyNum" :min="0" placeholder="请输入计划招生男生数" style="width: 100%" />
</el-form-item>
<el-form-item label="计划招生女生数" prop="planStudentGirlNum">
<el-input-number v-model="form.planStudentGirlNum" :min="0" placeholder="请输入计划招生女生数" style="width: 100%" />
</el-form-item>
<el-form-item label="生源" prop="degreeOfEducation">
<el-input v-model="form.degreeOfEducation" placeholder="请输入生源" clearable />
</el-form-item>
<el-form-item label="捐资助学费配置" prop="scoreFeeConf">
<el-input v-model="form.scoreFeeConf" placeholder="请输入捐资助学费配置" clearable />
</el-form-item>
<el-form-item label="学费配置,和生源对应" prop="tuition">
<el-input v-model="form.tuition" placeholder="请输入学费配置" clearable />
</el-form-item>
<el-form-item label="备注信息" prop="remarks">
<el-input v-model="form.remarks" type="textarea" :rows="3" placeholder="请输入备注信息" clearable />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentplan">
import { ref, reactive, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { addObj, delObj, fetchList, putObj } from '/@/api/recruit/recruitstudentplan'
// 使用 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 tableRef = ref()
const formRef = ref()
// 弹窗状态
const dialogVisible = ref(false)
const submitLoading = ref(false)
// 查询表单
const queryForm = reactive({})
// 表单数据
const form = reactive({
id: '',
zydm: '',
xy: '',
needStudentNum: undefined,
needStudentBoyNum: undefined,
needStudentGirlNum: undefined,
needStudentOverNum: undefined,
needStudentOverBoyNum: undefined,
needStudentOverGirlNum: undefined,
scoreLine: undefined,
scoreMinLine: undefined,
planStudentNum: undefined,
planStudentBoyNum: undefined,
planStudentGirlNum: undefined,
degreeOfEducation: '',
scoreFeeConf: '',
tuition: '',
remarks: ''
})
// 表单验证规则
const formRules = {}
// 表格状态
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
}
}
}
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 重置查询
const resetQuery = () => {
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
getDataList()
}
// 新增
const handleAdd = () => {
Object.keys(form).forEach(key => {
if (key === 'id') {
form[key] = ''
} else if (typeof form[key] === 'number') {
form[key] = undefined
} else {
form[key] = ''
}
})
dialogVisible.value = true
}
// 编辑
const handleEdit = async (row: any) => {
Object.keys(form).forEach(key => {
form[key] = row[key]
})
dialogVisible.value = true
}
// 删除
const handleDel = async (row: any) => {
try {
await messageBox.confirm(`是否确认删除ID为${row.id}的记录?`)
await delObj(row.id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid: boolean) => {
if (valid) {
submitLoading.value = true
try {
if (form.id) {
await putObj(form)
message.success('修改成功')
} else {
await addObj(form)
message.success('添加成功')
}
dialogVisible.value = false
getDataList()
} catch (error: any) {
message.error(error.msg || '操作失败')
} finally {
submitLoading.value = false
}
}
})
}
onMounted(() => {
getDataList()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,158 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
width="600px"
v-model="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit"
label-width="120px">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划" :disabled="!!dataForm.id">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="地区" prop="regionId">
<el-select v-model="dataForm.regionId" filterable placeholder="请选择地区">
<el-option
v-for="item in regionList"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="分数线" prop="fullScore">
<el-input-number v-model="dataForm.fullScore" :min="0" :max="999"></el-input-number>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { addObj, getObj, putObj } from '/@/api/recruit/recruitstudentplancorrectscoreconfig'
import { areaList } from '/@/api/recruit/recruitstudentschool'
import { list } from '/@/api/recruit/recruitstudentplangroup'
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const regionList = ref<any[]>([])
const planList = ref<any[]>([])
const dataForm = reactive({
id: "",
groupId: "",
regionId: "",
fullScore: null as number | null,
regionName: ""
})
const dataRule = {
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'blur' }
],
regionId: [
{ required: true, message: '地区不能为空', trigger: 'blur' }
],
fullScore: [
{ required: true, message: '分数线不能为空', trigger: 'blur' }
],
}
// 初始化数据
const initData = () => {
list().then((data: any) => {
planList.value = data.data
})
areaList({ type: "0", parentId: "11" }).then((data: any) => {
regionList.value = data.data
})
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
regionList.value.forEach(e => {
if (e.code == dataForm.regionId) {
dataForm.regionName = e.name
}
})
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
nextTick(() => {
initData()
dataFormRef.value?.resetFields()
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,210 @@
<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>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitstudentplancorrectscoreconfig_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle"
>
</el-button>
</div>
<!-- 表格 -->
<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="groupId" label="招生计划名称" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getPlanName(scope.row.groupId) }}
</template>
</el-table-column>
<el-table-column prop="regionName" label="地区" align="center" show-overflow-tooltip />
<el-table-column prop="fullScore" label="分数线" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentplancorrectscoreconfig_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
修改
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentplancorrectscoreconfig_del"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form ref="addOrUpdateRef" @refreshDataList="getDataList" />
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentplancorrectscoreconfig">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { fetchList, delObj } from '/@/api/recruit/recruitstudentplancorrectscoreconfig'
const TableForm = defineAsyncComponent(() => import('./detaiform.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
// 弹窗状态
const addOrUpdateVisible = ref(false)
// 数据
const planList = ref<any[]>([])
// 查询表单
const queryForm = reactive({
groupId: ''
})
// 获取计划名称
const getPlanName = (groupId: string) => {
const item = planList.value.find(item => item.id === groupId)
return item ? item.groupName : ''
}
// 表格状态
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 list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 新增 / 修改
const addOrUpdateHandle = (payload?: string | MouseEvent) => {
// 新增按钮未传参时会传入 MouseEvent这里统一转换为 id 或 null
const id = typeof payload === 'string' ? payload : null
nextTick(() => {
addOrUpdateRef.value?.init(id)
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,251 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4">
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
<el-form-item v-if="permissions.recruit_recruitstudentplandegreeofeducation_add">
<el-button type="primary" icon="FolderAdd" class="ml10" @click="handleAdd">新增</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="planId" label="计划明细ID" align="center" show-overflow-tooltip />
<el-table-column prop="degreeOfEducation" label="生源" align="center" show-overflow-tooltip />
<el-table-column prop="remarks" label="备注信息" align="center" show-overflow-tooltip />
<el-table-column prop="createBy" label="创建者" align="center" show-overflow-tooltip />
<el-table-column prop="createDate" label="创建时间" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentplandegreeofeducation_edit"
type="primary"
link
icon="EditPen"
@click="handleEdit(scope.row)"
>
编辑
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentplandegreeofeducation_del"
type="danger"
link
icon="Delete"
@click="handleDel(scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 新增/编辑弹窗 -->
<el-dialog
v-model="dialogVisible"
:title="form.id ? '编辑' : '新增'"
width="600px"
:close-on-click-modal="false"
destroy-on-close
>
<el-form
ref="formRef"
:model="form"
:rules="formRules"
label-width="120px"
>
<el-form-item label="计划明细ID" prop="planId">
<el-input v-model="form.planId" placeholder="请输入计划明细ID" clearable />
</el-form-item>
<el-form-item label="生源" prop="degreeOfEducation">
<el-input v-model="form.degreeOfEducation" placeholder="请输入生源" clearable />
</el-form-item>
<el-form-item label="备注信息" prop="remarks">
<el-input v-model="form.remarks" type="textarea" :rows="3" placeholder="请输入备注信息" clearable />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentplandegreeofeducation">
import { ref, reactive, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { addObj, delObj, fetchList, putObj } from '/@/api/recruit/recruitstudentplandegreeofeducation'
// 使用 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 tableRef = ref()
const formRef = ref()
// 弹窗状态
const dialogVisible = ref(false)
const submitLoading = ref(false)
// 查询表单
const queryForm = reactive({})
// 表单数据
const form = reactive({
id: '',
planId: '',
degreeOfEducation: '',
remarks: ''
})
// 表单验证规则
const formRules = {}
// 表格状态
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
}
}
}
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 重置查询
const resetQuery = () => {
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
getDataList()
}
// 新增
const handleAdd = () => {
Object.keys(form).forEach(key => {
if (key === 'id') {
form[key] = ''
} else {
form[key] = ''
}
})
dialogVisible.value = true
}
// 编辑
const handleEdit = async (row: any) => {
Object.keys(form).forEach(key => {
form[key] = row[key]
})
dialogVisible.value = true
}
// 删除
const handleDel = async (row: any) => {
try {
await messageBox.confirm(`是否确认删除ID为${row.id}的记录?`)
await delObj(row.id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid: boolean) => {
if (valid) {
submitLoading.value = true
try {
if (form.id) {
await putObj(form)
message.success('修改成功')
} else {
await addObj(form)
message.success('添加成功')
}
dialogVisible.value = false
getDataList()
} catch (error: any) {
message.error(error.msg || '操作失败')
} finally {
submitLoading.value = false
}
}
})
}
onMounted(() => {
getDataList()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,281 @@
<template>
<el-dialog
:title="dataForm.id ? '编辑' : '新增'"
:close-on-click-modal="false"
width="600"
v-model="visible">
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit" label-width="120px">
<el-form-item label="年份" prop="year">
<el-date-picker
v-model="dataForm.year"
type="year"
format="YYYY"
value-format="YYYY"
placeholder="请选择年份"
></el-date-picker>
</el-form-item>
<el-form-item label="招生计划名称" prop="groupName">
<el-input v-model="dataForm.groupName" placeholder="招生计划名称"></el-input>
</el-form-item>
<el-form-item label="报名开始时间" prop="startDate">
<el-date-picker
v-model="dataForm.startDate"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
:disabled-date="startDateDisabledDate"
type="datetime"
placeholder="请选择报名开始时间"
></el-date-picker>
</el-form-item>
<el-form-item label="报名截止时间" prop="endDate">
<el-date-picker
v-model="dataForm.endDate"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
:disabled-date="endDateDisabledDate"
type="datetime"
placeholder="请选择报名截止时间"
></el-date-picker>
</el-form-item>
<el-form-item label="维护开始时间" prop="maintenanceStartDate">
<el-date-picker
v-model="dataForm.maintenanceStartDate"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
:disabled-date="maintenanceStartDateDisabledDate"
type="datetime"
placeholder="请选择维护开始时间"
></el-date-picker>
</el-form-item>
<el-form-item label="维护结束时间" prop="maintenanceEndDate">
<el-date-picker
v-model="dataForm.maintenanceEndDate"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
:disabled-date="maintenanceEndDateDisabledDate"
type="datetime"
placeholder="请选择维护结束时间"
></el-date-picker>
</el-form-item>
<el-form-item label="初中生报名" prop="czSignStart">
<el-select v-model="dataForm.czSignStart" placeholder="请选择初中生报名">
<el-option
v-for="item in yesNoList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="高中生报名" prop="gzSignStart">
<el-select v-model="dataForm.gzSignStart" placeholder="请选择高中生报名">
<el-option
v-for="item in yesNoList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="技职校报名" prop="jzxSignStart">
<el-select v-model="dataForm.jzxSignStart" placeholder="请选择技职校报名">
<el-option
v-for="item in yesNoList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { useDict } from '/@/hooks/dict'
import { addObj, getObj, putObj } from '@/api/recruit/recruitstudentplangroup'
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 字典数据
const { yes_no_type: yesNoList } = useDict('yes_no_type')
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const dataForm = reactive({
id: "",
year: "",
groupName: "",
startDate: "",
endDate: "",
maintenanceStartDate: "",
maintenanceEndDate: "",
feeAgency: 0,
czSignStart: "",
gzSignStart: "",
jzxSignStart: ""
})
const dataRule = {
year: [
{ required: true, message: '年份不能为空', trigger: 'blur' }
],
groupName: [
{ required: true, message: '招生计划名称不能为空', trigger: 'blur' },
{ min: 0, max: 30, message: '长度在 0 到 30 个字符', trigger: 'blur' }
],
startDate: [
{ required: true, message: '报名开始时间不能为空', trigger: 'blur' }
],
endDate: [
{ required: true, message: '报名截止时间不能为空', trigger: 'blur' }
],
maintenanceStartDate: [
{ required: true, message: '维护开始时间不能为空', trigger: 'blur' }
],
maintenanceEndDate: [
{ required: true, message: '维护截止时间不能为空', trigger: 'blur' }
],
feeAgency: [
{ required: true, message: '代办费不能为空', trigger: 'blur' }
],
czSignStart: [
{ required: true, message: '初中生不能为空', trigger: 'blur' }
],
gzSignStart: [
{ required: true, message: '高中生不能为空', trigger: 'blur' }
],
jzxSignStart: [
{ required: true, message: '技职校不能为空', trigger: 'blur' }
],
}
// 日期选择器的禁用日期函数
const startDateDisabledDate = (time: Date) => {
if (dataForm.endDate) {
return new Date(dataForm.endDate).getTime() < time.getTime()
}
return false
}
const endDateDisabledDate = (time: Date) => {
if (dataForm.startDate) {
return new Date(dataForm.startDate).getTime() > time.getTime()
}
return false
}
const maintenanceStartDateDisabledDate = (time: Date) => {
if (dataForm.maintenanceEndDate) {
return new Date(dataForm.maintenanceEndDate).getTime() < time.getTime()
}
return false
}
const maintenanceEndDateDisabledDate = (time: Date) => {
if (dataForm.maintenanceStartDate) {
return new Date(dataForm.maintenanceStartDate).getTime() > time.getTime()
}
return false
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id?: string | null) => {
// 重置表单数据
dataForm.id = ""
dataForm.year = ""
dataForm.groupName = ""
dataForm.startDate = ""
dataForm.endDate = ""
dataForm.maintenanceStartDate = ""
dataForm.maintenanceEndDate = ""
dataForm.feeAgency = 0
dataForm.czSignStart = ""
dataForm.gzSignStart = ""
dataForm.jzxSignStart = ""
visible.value = true
canSubmit.value = true
nextTick(() => {
dataFormRef.value?.resetFields()
// 只有当 id 是有效的字符串时才加载数据
if (id && typeof id === 'string' && id.trim() !== '') {
dataForm.id = id
getObj(id).then((response: any) => {
Object.assign(dataForm, response.data)
if (dataForm.year) {
dataForm.year = String(dataForm.year)
}
}).catch(() => {
// 错误处理
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,387 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline ref="searchFormRef">
<el-form-item label="招生计划名称" prop="groupName">
<el-input v-model="queryForm.groupName" placeholder="招生计划名称" />
</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>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitstudentplangroup_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle"
>
</el-button>
<el-button
v-if="permissions.recruit_recruitexampeople_add"
type="primary"
plain
icon="UserFilled"
class="ml10"
@click="editExam"
>
审核人员
</el-button>
</div>
<!-- 表格 -->
<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="groupName" label="招生计划名称" align="center" show-overflow-tooltip />
<el-table-column prop="startDate" label="报名时间段" align="center" show-overflow-tooltip>
<template #default="scope">
<div class="date-cell">
<el-icon class="date-icon"><Calendar /></el-icon>
<span class="date-text">{{ dateFormat(scope.row.startDate, 'YYYY-mm-dd') + ' 至 ' + dateFormat(scope.row.endDate, 'YYYY-mm-dd') }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="maintenanceStartDate" label="维护时间段" align="center" show-overflow-tooltip>
<template #default="scope">
<div class="date-cell">
<el-icon class="date-icon"><Calendar /></el-icon>
<span class="date-text">{{ dateFormat(scope.row.maintenanceStartDate, 'YYYY-mm-dd') + ' 至 ' + dateFormat(scope.row.maintenanceEndDate, 'YYYY-mm-dd') }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="czSignStart" label="开启初中生报名" align="center" width="140">
<template #default="scope">
<el-switch
v-model="scope.row.czSignStart"
active-text=""
inactive-text=""
active-value="1"
inactive-value="0"
@change="changeSm(scope.row)"
/>
</template>
</el-table-column>
<el-table-column prop="gzSignStart" label="开启高中生报名" align="center" width="140">
<template #default="scope">
<el-switch
v-model="scope.row.gzSignStart"
active-text=""
inactive-text=""
active-value="1"
inactive-value="0"
@change="changeSm(scope.row)"
/>
</template>
</el-table-column>
<el-table-column prop="jzxSignStart" label="开启技职校报名" align="center" width="140">
<template #default="scope">
<el-switch
v-model="scope.row.jzxSignStart"
active-text=""
inactive-text=""
active-value="1"
inactive-value="0"
@change="changeSm(scope.row)"
/>
</template>
</el-table-column>
<el-table-column prop="isPreStart" label="开启预登记" align="center" width="130">
<template #default="scope">
<el-switch
v-model="scope.row.isPreStart"
active-text=""
inactive-text=""
active-value="1"
inactive-value="0"
@change="changeSm(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="240" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentplangroup_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
调整
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentplangroup_edit"
type="primary"
link
icon="Switch"
@click="majorHandle(scope.row)"
>
专业调整
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentplangroup_del"
type="primary"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form v-if="addOrUpdateVisible" ref="addOrUpdateRef" @refreshDataList="getDataList" />
<major-group-by-dept-form ref="majorGroupByDeptRef" />
<exam-people-index v-if="exitExamVisible" ref="examPeopleIndexRef" />
</div>
<!-- 预登记二维码弹窗 -->
<el-dialog v-model="dialogFormVisible" title="预登记二维码" width="10%" height="50%" @close="dialogFormVisible=false">
<!-- <vue-qr :text="payQrcode" :size="200"></vue-qr>-->
</el-dialog>
</div>
</template>
<script setup lang="ts" name="recruitstudentplangroup">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { delObj, fetchList, putObj } from '/@/api/recruit/recruitstudentplangroup'
import { formatDate } from '/@/utils/formatTime'
import { Calendar } from '@element-plus/icons-vue'
// import vueQr from 'vue-qr'
const TableForm = defineAsyncComponent(() => import('./enrolplantemplate-form.vue'))
const MajorGroupByDeptForm = defineAsyncComponent(() => import('@/views/recruit/recruitplanmajor/majorGroupByDept.vue'))
const ExamPeopleIndex = defineAsyncComponent(() => import('@/views/recruit/recruitexampeople/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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
const majorGroupByDeptRef = ref()
const examPeopleIndexRef = ref()
// 弹窗状态
const addOrUpdateVisible = ref(false)
const exitExamVisible = ref(false)
const dialogFormVisible = ref(false)
// 数据
const payQrcode = ref('')
// 查询表单
const queryForm = reactive({
groupName: ''
})
// 日期格式化
const dateFormat = (date: string | null | undefined, format: string) => {
if (!date) return '-'
try {
return formatDate(new Date(date), format)
} catch (error) {
return date
}
}
// 表格状态
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
}
}
}
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 初始化(如果需要初始化逻辑可以在这里添加)
const init = async () => {
// 初始化逻辑
}
// 显示二维码
const showQrCode = (row: any) => {
payQrcode.value = '123'
dialogFormVisible.value = true
}
// 修改开关
const changeSm = async (row: any) => {
try {
await putObj(row)
message.success('修改成功')
} catch (error: any) {
message.error(error.msg || '修改失败')
}
}
// 新增 / 修改
const addOrUpdateHandle = (id?: string) => {
addOrUpdateVisible.value = true
nextTick(() => {
addOrUpdateRef.value?.init(id)
})
}
// 编辑审核人员
const editExam = () => {
exitExamVisible.value = true
// 如果组件已经加载,立即初始化
if (examPeopleIndexRef.value && typeof examPeopleIndexRef.value.init === 'function') {
nextTick(() => {
try {
examPeopleIndexRef.value.init()
} catch (error: any) {
message.error('初始化审核人员弹窗失败:' + (error.message || '未知错误'))
exitExamVisible.value = false
}
})
}
// 否则等待 watch 监听器处理
}
// 监听组件引用变化,当组件加载完成后自动初始化
watch(examPeopleIndexRef, (newVal) => {
if (newVal && exitExamVisible.value) {
nextTick(() => {
if (newVal && typeof newVal.init === 'function') {
try {
newVal.init()
} catch (error: any) {
message.error('初始化审核人员弹窗失败:' + (error.message || '未知错误'))
exitExamVisible.value = false
}
}
})
}
}, { immediate: true })
// 专业调整
const majorHandle = (row: any) => {
if (!row || !row.id) {
message.warning('请选择有效的招生计划')
return
}
nextTick(() => {
majorGroupByDeptRef.value?.init(row)
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupName = ''
getDataList()
}
onMounted(() => {
init()
getDataList()
})
</script>
<style lang="scss" scoped>
/* 时间段图标和文字垂直对齐 */
.date-cell {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
}
.date-icon {
flex-shrink: 0;
color: #909399;
font-size: 14px;
line-height: 1;
display: inline-flex;
align-items: center;
}
.date-text {
line-height: 1.5;
display: inline-block;
vertical-align: middle;
}
/* 开启报名开关文字颜色 */
</style>

View File

@@ -0,0 +1,177 @@
<template>
<el-dialog
:title="!dataForm.id ? '新增' : '修改'"
:close-on-click-modal="false"
v-model="visible"
width="600px"
destroy-on-close
>
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit" label-width="120px">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable :disabled="!!dataForm.id" placeholder="请选择招生计划">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="学校名称" prop="schoolName">
<el-input v-model="dataForm.schoolName" placeholder="学校名称"></el-input>
</el-form-item>
<el-form-item label="对接学院" prop="xy">
<el-select v-model="dataForm.xy" filterable clearable placeholder="请选择对接学院">
<el-option
v-for="item in deptList"
:key="item.deptCode"
:label="item.deptName"
:value="item.deptCode">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="地区" prop="area">
<el-select v-model="dataForm.area" filterable placeholder="请选择地区">
<el-option
v-for="item in areaListData"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit" v-if="canSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { addObj, areaList, getObj, putObj } from '/@/api/recruit/recruitstudentschool'
import { getDeptList } from '/@/api/basic/basicclass'
import { list } from '/@/api/recruit/recruitstudentplangroup'
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const planList = ref<any[]>([])
const areaListData = ref<any[]>([])
const deptList = ref<any[]>([])
const dataForm = reactive({
id: "",
groupId: "",
area: "",
xy: "",
schoolName: ""
})
const dataRule = {
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'blur' },
],
schoolName: [
{ required: true, message: '学校名称不能为空', trigger: 'blur' },
{ min: 1, max: 20, message: '学校名称长度不大于20个字符', trigger: 'blur' }
],
area: [
{ required: true, message: '地区不能为空', trigger: 'blur' },
],
}
// 初始化数据
const initData = () => {
// 查询二级学院信息
getDeptList().then((data: any) => {
deptList.value = data.data
deptList.value.push({ deptCode: "190", deptName: "招生就业处" })
})
list().then((data: any) => {
planList.value = data.data
if (!dataForm.id) {
dataForm.groupId = planList.value[0]?.id || ""
}
})
// 获取所有省
areaList({ type: "0", parentId: 112 }).then((res: any) => {
areaListData.value = res.data
})
}
// 表单提交
const dataFormSubmit = () => {
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
putObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '修改成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
} else {
addObj(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '添加成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
if (dataForm.area) {
dataForm.area = String(dataForm.area)
}
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,257 @@
<!--
- 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="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="schoolName">
<el-input v-model="queryForm.schoolName" clearable placeholder="学校名称" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruit_recruitstudentplangroup_add"
type="primary"
icon="FolderAdd"
@click="addOrUpdateHandle"
>
</el-button>
</div>
<!-- 表格 -->
<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="schoolName" label="学校名称" align="center" show-overflow-tooltip />
<el-table-column prop="xy" label="对接学院" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getDeptName(scope.row.xy) }}
</template>
</el-table-column>
<el-table-column prop="area" label="所在区" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getAreaName(scope.row.area) }}
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentschool_edit"
type="primary"
link
icon="EditPen"
@click="addOrUpdateHandle(scope.row.id)"
>
修改
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentschool_del"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 弹窗, 新增 / 修改 -->
<table-form ref="addOrUpdateRef" @refreshDataList="getDataList" />
<major-group-by-dept-form v-if="majorGroupByDeptVisible" ref="majorGroupByDeptRef" />
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentschool">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { delObj, fetchList, areaList } from '/@/api/recruit/recruitstudentschool'
import { getDeptList } from '/@/api/basic/basicclass'
const TableForm = defineAsyncComponent(() => import('./detaiform.vue'))
const MajorGroupByDeptForm = defineAsyncComponent(() => import('/@/views/recruit/recruitplanmajor/majorGroupByDept.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const addOrUpdateRef = ref()
const majorGroupByDeptRef = ref()
// 弹窗状态
const majorGroupByDeptVisible = ref(false)
// 数据
const planList = ref<any[]>([])
const deptList = ref<any[]>([])
const provinceList = ref<any[]>([])
// 查询表单
const queryForm = reactive({
groupId: '',
schoolName: ''
})
// 获取学院名称
const getDeptName = (deptCode: string) => {
const item = deptList.value.find(item => item.deptCode === deptCode)
return item ? item.deptName : ''
}
// 获取地区名称
const getAreaName = (areaCode: string) => {
const item = provinceList.value.find(item => item.code === areaCode)
return item ? item.name : ''
}
// 表格状态
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 deptData = await getDeptList()
deptList.value = deptData.data || []
deptList.value.push({ deptCode: '190', deptName: '招生就业处' })
// 获取所有省
const areaData = await areaList({ type: '0', parentId: 112 })
provinceList.value = areaData.data || []
// 获取招生计划列表
const planData = await list()
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 新增 / 修改
const addOrUpdateHandle = (payload?: any) => {
// 兼容新增按钮未传参时自动传入的 MouseEvent
const id = payload && typeof payload === 'object' ? null : payload
nextTick(() => {
addOrUpdateRef.value?.init(id)
})
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delObj(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,86 @@
<template>
<el-dialog title="录取通知书" v-model="visible" width="80%" height="50%" @close="handleClose">
<div style="height: 60vh">
<iframe id="iframeid" :src="pdfPath" ref="iframeRef" frameborder="0" style="width:100%;height:100%;"></iframe>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose"> </el-button>
<el-button @click="handleConfirm" v-if="props.permissions.sureLQTZ && canConfirm" type="primary">确认已发放</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { toWord, sureLQTZ } from '/@/api/recruit/recruitstudentsignup'
export default {
name: 'AdmissionNoticeDialog',
props: {
permissions: {
type: Object,
default: () => ({})
}
},
emits: ['refresh'],
setup(props, { emit }) {
const visible = ref(false)
const pdfPath = ref('')
const currentId = ref('')
const canConfirm = ref(false)
const init = async (row) => {
currentId.value = row.id
pdfPath.value = ''
canConfirm.value = row.isBackTz == '0'
try {
const res = await toWord(row)
pdfPath.value = "/recruit/file/previewPdf?filePath=" + encodeURIComponent(res.data)
visible.value = true
} catch (error) {
ElMessage.error('加载录取通知书失败')
}
}
const handleConfirm = () => {
ElMessageBox.confirm('是否确认已打印并发放本通知书?请谨慎操作', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return sureLQTZ({ id: currentId.value })
}).then(() => {
ElMessage.success('保存成功')
visible.value = false
emit('refresh')
}).catch(() => {
// 用户取消操作
})
}
const handleClose = () => {
visible.value = false
}
return {
visible,
pdfPath,
canConfirm,
init,
handleConfirm,
handleClose
}
}
}
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<el-dialog title="延迟缴费" v-model="visible" width="300px" height="50%" @close="handleClose">
<el-date-picker
v-model="delayPayTime"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
filterable
clearable
type="datetime"
style="width: 100%"
></el-date-picker>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose"> </el-button>
<el-button @click="handleSave" type="primary">保存</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { updateInfo } from '/@/api/recruit/recruitstudentsignup'
export default {
name: 'DelayPayTimeDialog',
emits: ['refresh'],
setup(props, { emit }) {
const visible = ref(false)
const delayPayTime = ref('')
const currentId = ref('')
const init = (row) => {
delayPayTime.value = ''
currentId.value = row.id
if (row.delayPaymentTime) {
delayPayTime.value = row.delayPaymentTime
}
visible.value = true
}
const handleSave = () => {
ElMessageBox.confirm('是否确认进度延迟收费操作?请谨慎操作', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return updateInfo({ delayPaymentTime: delayPayTime.value, id: currentId.value })
}).then(() => {
visible.value = false
ElMessage.success('延迟收费修改成功')
emit('refresh')
}).catch(() => {
// 用户取消操作
})
}
const handleClose = () => {
visible.value = false
}
return {
visible,
delayPayTime,
init,
handleSave,
handleClose
}
}
}
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,131 @@
<template>
<el-dialog title="支付二维码" v-model="visible" width="800px" height="80%" @close="handleClose">
<el-table :data="tableData" border>
<el-table-column label="唯一号" prop="serialNumber" align="center"></el-table-column>
<el-table-column label="姓名" prop="name" align="center"></el-table-column>
<el-table-column label="家长手机号" prop="parentTelOne" align="center"></el-table-column>
<el-table-column label="操作" prop="" align="center">
<template #default>
<el-button @click="handleUpdateFS" icon="el-icon-search" type="danger" size="small">立即查询</el-button>
</template>
</el-table-column>
</el-table>
<div style="padding-top: 20px;">
<div id="payQrcode1" style="display: inline-block;">
{{ payQrcode1Msg }}
</div>
<vue-qr :text="payQrcode1" :size="200" v-if="showPrise1" style="display: inline-block"></vue-qr>
<div id="payQrcode2" style="display: inline-block">
{{ payQrcode2Msg }}
</div>
<vue-qr :text="payQrcode2" :size="200" v-if="showPrise2" style="display: inline-block"></vue-qr>
<div id="payQrcode3" style="display: inline-block">
{{ payQrcode3Msg }}
</div>
<vue-qr :text="payQrcode3" :size="200" v-if="showPrise3" style="display: inline-block"></vue-qr>
</div>
<span style="color: red;padding-top: 20px;">** 此界面为查询学生缴款二维码如有收不到微信推送或手机号填错的可直接在此扫码支付支付成功后请手动点击"立即查询"按钮查询该生的缴费情况;因财政收费系统有一定的滞后性如点击"立即查询"后任显示未交费请稍后再继续查询或重新点击"立即查询"按钮 **</span>
</el-dialog>
</template>
<script>
import { ref } from 'vue'
import { ElNotification } from 'element-plus'
import { updateFs } from '/@/api/finance/financenormalstu'
export default {
name: 'PayQrcodeDialog',
emits: ['refresh'],
setup(props, { emit }) {
const visible = ref(false)
const tableData = ref([])
const payQrcode1 = ref('')
const showPrise1 = ref(false)
const payQrcode1Msg = ref('')
const payQrcode2 = ref('')
const payQrcode2Msg = ref('')
const showPrise2 = ref(false)
const payQrcode3 = ref('')
const payQrcode3Msg = ref('')
const showPrise3 = ref(false)
const init = (row) => {
showPrise1.value = false
showPrise2.value = false
showPrise3.value = false
// 置空
payQrcode1.value = ''
payQrcode2.value = ''
payQrcode3.value = ''
if (row.clfPayCode == '' || row.clfPayCode == undefined) {
payQrcode1Msg.value = ''
showPrise1.value = false
} else {
payQrcode1Msg.value = '材料费、代办费'
showPrise1.value = true
payQrcode1.value = 'https://jscz.govpay.ccb.com/online/fsjf?PyF_BillNo=' + row.clfPayCode + '&Verf_CD=blank&Admn_Rgon_Cd=320400'
}
if (row.xfPayCode == '' || row.xfPayCode == undefined) {
payQrcode2Msg.value = ''
showPrise2.value = false
} else {
payQrcode2Msg.value = '学费'
showPrise2.value = true
payQrcode2.value = 'https://jscz.govpay.ccb.com/online/fsjf?PyF_BillNo=' + row.xfPayCode + '&Verf_CD=blank&Admn_Rgon_Cd=320400'
}
if (row.zdbPayCode == '' || row.zdbPayCode == undefined) {
payQrcode3Msg.value = ''
showPrise3.value = false
} else {
payQrcode3Msg.value = '中德班学费'
showPrise3.value = true
payQrcode3.value = 'https://jscz.govpay.ccb.com/online/fsjf?PyF_BillNo=' + row.zdbPayCode + '&Verf_CD=blank&Admn_Rgon_Cd=320400'
}
tableData.value = []
tableData.value.push(row)
visible.value = true
}
const handleUpdateFS = () => {
if (tableData.value.length === 0) return
updateFs({ "serialNumber": tableData.value[0].serialNumber.substring(1, tableData.value[0].serialNumber.length) }).then(() => {
ElNotification.success('已提交查询请求请等待1分钟后重新查询')
visible.value = false
emit('refresh')
})
}
const handleClose = () => {
visible.value = false
}
return {
visible,
tableData,
payQrcode1,
showPrise1,
payQrcode1Msg,
payQrcode2,
showPrise2,
payQrcode2Msg,
payQrcode3,
showPrise3,
payQrcode3Msg,
init,
handleUpdateFS,
handleClose
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,31 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="初中生" name="tab">
<AreaStaticByCZ ref="tabIndexRef" />
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-areaStatic">
import { ref, defineAsyncComponent, nextTick } from 'vue'
const AreaStaticByCZ = defineAsyncComponent(() => import('./areaStaticByCZ.vue'))
// 状态
const activeName = ref('tab')
const tabIndexRef = ref()
// Tab 切换
const handleTabClick = (tab: any) => {
if (tab.paneName === 'tab') {
nextTick(() => {
tabIndexRef.value?.init()
})
}
}
</script>

View File

@@ -0,0 +1,169 @@
<template>
<div class="mod-config">
<basic-container>
<el-form :inline="true" :model="dataForm" @keyup.enter="handleFilter" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划" size="small">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" size="small"
@click="handleFilter">查询
</el-button>
<el-button icon="Delete" type="default" plain size="small"
@click="resetForm">清空
</el-button>
</el-form-item>
</el-form>
<el-form>
<el-form-item>
<el-button icon="Download" type="warning" size="small" @click="dataExportHandle">导出</el-button>
</el-form-item>
</el-form>
<div class="avue-crud">
<el-table :data="dataList" border stripe v-loading="dataListLoading"
:summary-method="getSummaries" show-summary
>
<el-table-column align="center" header-align="center" prop="provinceName" label="省市" />
<el-table-column align="center" header-align="center" prop="peopleNum" label="人数" />
<el-table-column align="center" header-align="center" prop="peopleRate" label="占比" />
</el-table>
<chart ref="typeEchartBarRef" style="width:100%;margin-top:80px" :options="chartOption" theme="macarons"></chart>
</div>
</basic-container>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import axios from 'axios'
import { getAreaStatic } from "@/api/recruit/recruitstudentsignup"
import { list } from "@/api/recruit/recruitstudentplangroup"
// 响应式数据
const dataForm = reactive({
groupId: "",
degreeOfEducation: ""
})
const dataList = ref<any[]>([])
const planList = ref<any[]>([])
const dataListLoading = ref(false)
const chartOption = ref<any>({})
const searchFormRef = ref()
const typeEchartBarRef = ref()
// 初始化
const init = () => {
list().then((data: any) => {
planList.value = data.data
if (planList.value.length > 0) {
dataForm.groupId = planList.value[0].id
}
getDataList()
})
}
// 获取数据列表
const getDataList = () => {
dataList.value = []
dataForm.degreeOfEducation = '1'
dataListLoading.value = true
getAreaStatic(dataForm).then((response: any) => {
dataList.value = response.data
chartOption.value = response.data.option
dataListLoading.value = false
}).catch(() => {
dataListLoading.value = false
})
}
// 导出Excel
const exportExcel = (form: any, url: string) => {
return axios({
method: 'post',
url: url,
data: form,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
}
// 导出表格
const dataExportHandle = () => {
exportExcel(dataForm, '/recruit/recruitstudentsignup/getAreaStaticExport').then((res: any) => {
const blob = new Blob([res.data])
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)
}).catch(() => {
// 错误处理
})
}
// 表格汇总
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总计'
} else if (index !== 0) {
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: number) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: number) => {
const numValue = Number(curr)
if (!isNaN(numValue)) {
return prev + numValue
} else {
return prev
}
}, 0)
} else {
sums[index] = '--'
}
} else {
sums[index] = '--'
}
})
return sums
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置表单
const resetForm = () => {
searchFormRef.value?.resetFields()
}
// 组件挂载时初始化
onMounted(() => {
init()
})
</script>
<style scoped>
.avue-crud {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,177 @@
<template>
<div class="mod-config">
<basic-container>
<el-form :inline="true" :model="dataForm" @keyup.enter="handleFilter" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划" size="small">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" size="small"
@click="handleFilter">查询
</el-button>
<el-button icon="Delete" type="default" plain size="small"
@click="resetForm">清空
</el-button>
</el-form-item>
</el-form>
<div class="avue-crud">
<el-table :data="dataList" border stripe :span-method="objectSpanMethod" v-loading="dataListLoading"
:summary-method="getSummaries" show-summary :row-style="changeRowColor"
>
<el-table-column align="center" header-align="center" prop="deptName" label="部门" />
<el-table-column align="center" header-align="center" prop="contantName" label="联系人" />
<el-table-column align="center" header-align="center" prop="peopleNum" label="招生人数" />
<el-table-column align="center" header-align="center" prop="czNum" label="初中生" />
<el-table-column align="center" header-align="center" prop="gzNum" label="高中生" />
<el-table-column align="center" header-align="center" prop="jzxNum" label="技职校" />
<el-table-column align="center" header-align="center" prop="allNum" label="高中+技职校" />
</el-table>
</div>
</basic-container>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { getContantByUserStatic } from "@/api/recruit/recruitstudentsignup"
import { list } from "@/api/recruit/recruitstudentplangroup"
// 响应式数据
const dataForm = reactive({
groupId: ""
})
const dataList = ref<any[]>([])
const planList = ref<any[]>([])
const indexArray = ref<number[]>([])
const dataListLoading = ref(false)
const searchFormRef = ref()
// 初始化
const init = () => {
list().then((data: any) => {
planList.value = data.data
if (planList.value.length > 0) {
dataForm.groupId = planList.value[0].id
}
getDataList()
})
}
// 获取数据列表
const getDataList = () => {
dataList.value = []
indexArray.value = []
dataListLoading.value = true
getContantByUserStatic(dataForm).then((response: any) => {
dataList.value = response.data
let count = 0
for (let rowIndex = 0; rowIndex < dataList.value.length; ) {
indexArray.value.push(rowIndex)
count = getRows(rowIndex, dataList.value[rowIndex].deptName)
rowIndex += count
}
dataListLoading.value = false
}).catch(() => {
dataListLoading.value = false
})
}
// 改变行颜色
const changeRowColor = ({ row }: any) => {
if (row.contantName === "小记") {
return {
color: "red"
}
}
}
// 表格汇总
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总计'
} else if (index !== 0 && index !== 1) {
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: number) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: number) => {
const numValue = Number(curr)
if (!isNaN(numValue)) {
return prev + numValue
} else {
return prev
}
}, 0) / 2
} else {
sums[index] = '--'
}
} else {
sums[index] = '--'
}
})
return sums
}
// 合并单元格
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
if (columnIndex === 0) {
let rowCount = 0
if (indexArray.value.includes(rowIndex)) {
rowCount = getRows(rowIndex, row.deptName)
return {
rowspan: rowCount,
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
// 获取行数
const getRows = (rowIndex: number, name: string) => {
let count = 0
for (let i = rowIndex; i < dataList.value.length; i++) {
if (dataList.value[i].deptName === name) {
count++
} else {
break
}
}
return count
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置表单
const resetForm = () => {
searchFormRef.value?.resetFields()
}
// 组件挂载时初始化
onMounted(() => {
init()
})
</script>
<style scoped>
.avue-crud {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,162 @@
<template>
<div class="mod-config">
<basic-container>
<el-form :inline="true" :model="dataForm" @keyup.enter="handleFilter" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划" size="small">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" size="small"
@click="handleFilter">查询
</el-button>
<el-button icon="Delete" type="default" plain size="small"
@click="resetForm">清空
</el-button>
</el-form-item>
</el-form>
<el-form>
<el-form-item>
<el-button icon="Download" type="warning" size="small" @click="dataExportHandle">导出</el-button>
</el-form-item>
</el-form>
<div class="avue-crud">
<el-table :data="dataList" border stripe v-loading="dataListLoading"
:summary-method="getSummaries" show-summary
>
<el-table-column align="center" header-align="center" prop="deptName" label="部门" />
<el-table-column align="center" header-align="center" prop="allNum" label="合计" />
<el-table-column align="center" header-align="center" prop="schoolNum" label="学校推荐" />
<el-table-column align="center" header-align="center" prop="contantNum" label="联系人" />
</el-table>
</div>
</basic-container>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import axios from 'axios'
import { getContantByDeptStatic } from "@/api/recruit/recruitstudentsignup"
import { list } from "@/api/recruit/recruitstudentplangroup"
// 响应式数据
const dataForm = reactive({
groupId: ""
})
const dataList = ref<any[]>([])
const planList = ref<any[]>([])
const dataListLoading = ref(false)
const searchFormRef = ref()
// 初始化
const init = () => {
list().then((data: any) => {
planList.value = data.data
if (planList.value.length > 0) {
dataForm.groupId = planList.value[0].id
}
getDataList()
})
}
// 获取数据列表
const getDataList = () => {
dataList.value = []
dataListLoading.value = true
getContantByDeptStatic(dataForm).then((response: any) => {
dataList.value = response.data
dataListLoading.value = false
}).catch(() => {
dataListLoading.value = false
})
}
// 导出Excel
const exportExcel = (form: any, url: string) => {
return axios({
method: 'post',
url: url,
data: form,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
}
// 导出表格
const dataExportHandle = () => {
exportExcel(dataForm, '/recruit/recruitstudentsignup/getContantByDeptStaticExport').then((res: any) => {
const blob = new Blob([res.data])
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)
}).catch(() => {
// 错误处理
})
}
// 表格汇总
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总计'
} else if (index !== 0) {
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: number) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: number) => {
const numValue = Number(curr)
if (!isNaN(numValue)) {
return prev + numValue
} else {
return prev
}
}, 0)
} else {
sums[index] = '--'
}
} else {
sums[index] = '--'
}
})
return sums
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置表单
const resetForm = () => {
searchFormRef.value?.resetFields()
}
// 组件挂载时初始化
onMounted(() => {
init()
})
</script>
<style scoped>
.avue-crud {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,214 @@
<template>
<div class="mod-config">
<basic-container>
<el-form :inline="true" :model="dataForm" @keyup.enter="handleFilter" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable placeholder="请选择招生计划" size="small">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" size="small"
@click="handleFilter">查询
</el-button>
<el-button icon="Delete" type="default" plain size="small"
@click="resetForm">清空
</el-button>
</el-form-item>
</el-form>
<el-form>
<el-form-item>
<el-button icon="Download" type="warning" size="small" @click="dataExportHandle">导出</el-button>
</el-form-item>
</el-form>
<div class="avue-crud">
<el-table :data="dataList" border stripe :span-method="objectSpanMethod" v-loading="dataListLoading"
:summary-method="getSummaries" show-summary :row-style="changeRowColor"
>
<el-table-column align="center" header-align="center" prop="deptName" label="部门" />
<el-table-column align="center" header-align="center" prop="contantName" label="联系人" />
<el-table-column align="center" header-align="center" prop="peopleNum" label="招生人数" />
<el-table-column align="center" header-align="center" prop="czNum" label="初中生" />
<el-table-column align="center" header-align="center" prop="gzNum" label="高中生" />
<el-table-column align="center" header-align="center" prop="jzxNum" label="技职校" />
<el-table-column align="center" header-align="center" prop="allNum" label="高中+技职校" />
</el-table>
</div>
</basic-container>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import axios from 'axios'
import { getContantByUserStatic } from "@/api/recruit/recruitstudentsignup"
import { list } from "@/api/recruit/recruitstudentplangroup"
// 响应式数据
const dataForm = reactive({
groupId: ""
})
const dataList = ref<any[]>([])
const planList = ref<any[]>([])
const indexArray = ref<number[]>([])
const dataListLoading = ref(false)
const searchFormRef = ref()
// 初始化
const init = () => {
list().then((data: any) => {
planList.value = data.data
if (planList.value.length > 0) {
dataForm.groupId = planList.value[0].id
}
getDataList()
})
}
// 获取数据列表
const getDataList = () => {
dataList.value = []
indexArray.value = []
dataListLoading.value = true
getContantByUserStatic(dataForm).then((response: any) => {
dataList.value = response.data
let count = 0
for (let rowIndex = 0; rowIndex < dataList.value.length; ) {
indexArray.value.push(rowIndex)
count = getRows(rowIndex, dataList.value[rowIndex].deptName)
rowIndex += count
}
dataListLoading.value = false
}).catch(() => {
dataListLoading.value = false
})
}
// 导出Excel
const exportExcel = (form: any, url: string) => {
return axios({
method: 'post',
url: url,
data: form,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
}
// 导出表格
const dataExportHandle = () => {
exportExcel(dataForm, '/recruit/recruitstudentsignup/getContantByUserStaticExport').then((res: any) => {
const blob = new Blob([res.data])
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)
}).catch(() => {
// 错误处理
})
}
// 改变行颜色
const changeRowColor = ({ row }: any) => {
if (row.contantName === "小记") {
return {
color: "red"
}
}
}
// 表格汇总
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总计'
} else if (index !== 0 && index !== 1) {
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: number) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: number) => {
const numValue = Number(curr)
if (!isNaN(numValue)) {
return prev + numValue
} else {
return prev
}
}, 0) / 2
} else {
sums[index] = '--'
}
} else {
sums[index] = '--'
}
})
return sums
}
// 合并单元格
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
if (columnIndex === 0) {
let rowCount = 0
if (indexArray.value.includes(rowIndex)) {
rowCount = getRows(rowIndex, row.deptName)
return {
rowspan: rowCount,
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
// 获取行数
const getRows = (rowIndex: number, name: string) => {
let count = 0
for (let i = rowIndex; i < dataList.value.length; i++) {
if (dataList.value[i].deptName === name) {
count++
} else {
break
}
}
return count
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置表单
const resetForm = () => {
searchFormRef.value?.resetFields()
}
// 组件挂载时初始化
onMounted(() => {
init()
})
</script>
<style scoped>
.avue-crud {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,40 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="按联系人统计" name="tab">
<ContanctByUserStatic ref="tabIndexRef" />
</el-tab-pane>
<el-tab-pane label="按部门统计" name="static">
<ContanctByDeptStatic ref="staticIndexRef" />
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-contanctStatic">
import { ref, defineAsyncComponent, nextTick } from 'vue'
const ContanctByUserStatic = defineAsyncComponent(() => import('./contanctByUserStatic.vue'))
const ContanctByDeptStatic = defineAsyncComponent(() => import('./contanctByDeptStatic.vue'))
// 状态
const activeName = ref('tab')
const tabIndexRef = ref()
const staticIndexRef = ref()
// Tab 切换
const handleTabClick = (tab: any) => {
if (tab.paneName === 'tab') {
nextTick(() => {
tabIndexRef.value?.init()
})
} else {
nextTick(() => {
staticIndexRef.value?.init()
})
}
}
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
<template>
<el-dialog
title="请设置住宿范围"
append-to-body
:close-on-click-modal="false"
v-model="visible"
width="90%">
<div style="height: 100%;width:100%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px"
class="demo-ruleForm">
<el-form-item label="住宿半径(米)" prop="raidus">
<el-input-number v-model="form.raidus" :min="0" style="width: 100%"></el-input-number>
</el-form-item>
</el-form>
<div id="container"></div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="dataFormSubmit">确定</el-button>
<el-button @click="visible = false">取消</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch, nextTick } from 'vue'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { BMPGL } from "@/api/recruit/recruitstudentsignup"
import { putItemObj } from "@/api/admin/dict"
import { getTypeValue } from "@/api/admin/dict"
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表单引用
const formRef = ref()
// 响应式数据
const ak = "V0ooaf2RZyEGOkD8UzZB3gvw7pCb0Kx7" // 百度的地图密钥
const visible = ref(false)
const canSubmit = ref(false)
const circleShow = ref(false)
const circle = ref<any>(null)
// 地址信息
const address = ref(null)
const center = reactive({ lng: 0, lat: 0 })
const dictId = ref("")
const circleArr = ref<any[]>([])
const form = reactive({
raidus: 0,
})
const rules = {
raidus: [
{ required: true, message: '住宿半径不能为空', trigger: ["blur", "change"] }
],
}
// 监听半径变化
watch(() => form.raidus, (newVal) => {
if (newVal != '' && newVal != undefined && circle.value) {
circle.value.setRadius(newVal) // 设置圆形覆盖物的半径
}
})
// 初始化
const init = () => {
visible.value = true
canSubmit.value = true
circleShow.value = true
nextTick(() => {
getTypeValue("dorm_jw").then((data: any) => {
const arr = data.data
arr.forEach((e: any) => {
if (e.label == 'bj') {
form.raidus = e.value
dictId.value = e.id
} else if (e.label == 'lng') {
center.lng = e.value
} else if (e.label == 'lat') {
center.lat = e.value
}
})
BMPGL(ak).then((BMapGL: any) => {
// 创建地图实例
const map = new BMapGL.Map("container")
// 创建点坐标
const point = new BMapGL.Point(center.lng, center.lat)
// 初始化地图,设置中心点坐标和地图级别
map.centerAndZoom(point, 13)
// 开启鼠标滚轮缩放
map.enableScrollWheelZoom(true)
// 绘制圆
circle.value = new BMapGL.Circle(new BMapGL.Point(center.lng, center.lat), form.raidus, {
strokeColor: 'blue',
strokeWeight: 2,
strokeOpacity: 0.5,
enableEditing: false
})
map.addOverlay(circle.value)
})
})
})
}
// 表单提交
const dataFormSubmit = async () => {
try {
await messageBox.confirm('是否确认保存住宿半径')
formRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
putItemObj({ id: dictId.value, value: form.raidus }).then(() => {
message.success('修改成功')
visible.value = false
canSubmit.value = true
}).catch(() => {
canSubmit.value = true
})
}
})
} catch {
// 用户取消
}
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
#container {
overflow: hidden;
width: 100%;
height: 700px;
margin: 0;
font-family: "微软雅黑";
}
ul li {
list-style: none;
}
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<div class="mod-config">
<basic-container>
<el-form :inline="true" :model="dataForm" @keyup.enter="getDataList" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable clearable placeholder="请选择招生计划" size="small"
style="width: 150px;">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="warning"
icon="Download"
size="small"
@click="handleExport">汇总导出</el-button>
</el-form-item>
</el-form>
<el-table
:data="dataList"
border
stripe
show-summary
v-loading="dataListLoading">
<el-table-column
prop="xy"
header-align="center"
align="center"
width="120"
label="学院">
<template #default="scope">
<span>{{
global.getLabelValueByPropes(deptList, scope.row.xy, {
'key': 'deptCode',
'value': 'deptName'
})
}}</span>
</template>
</el-table-column>
<el-table-column
prop="total"
header-align="center"
align="center"
label="申请人数(范围外)">
</el-table-column>
<el-table-column
prop="man"
header-align="center"
align="center"
label="男生数">
</el-table-column>
<el-table-column
prop="woman"
header-align="center"
align="center"
label="女生数">
</el-table-column>
</el-table>
</basic-container>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch, onMounted } from 'vue'
import axios from 'axios'
import { getDeptList } from "@/api/basic/basicclass"
import { dormApplyAnalysis } from "@/api/recruit/recruitstudentsignup"
import { list } from '@/api/recruit/recruitstudentplangroup'
// @ts-ignore
import global from '@/components/tools/commondict'
// 响应式数据
const deptList = ref<any[]>([])
const dataList = ref<any[]>([])
const planList = ref<any[]>([])
const dataListLoading = ref(false)
const searchFormRef = ref()
const dataForm = reactive({
groupId: ''
})
// 监听 groupId 变化
watch(() => dataForm.groupId, (val) => {
if (val) {
getTableList(val)
}
})
// 初始化部门列表
const initDept = () => {
getDeptList().then((data: any) => {
deptList.value = data.data
})
}
// 导出Excel
const exportExcel = (form: any, url: string) => {
return axios({
method: 'post',
url: url,
data: form,
responseType: 'blob',
headers: {
'Content-Type': 'application/json'
}
})
}
// 导出处理
const handleExport = () => {
exportExcel(dataForm, '/recruit/recruitstudentsignup/dormApplyAnalysisExport').then((res: any) => {
const blob = new Blob([res.data])
const elink = document.createElement('a')
elink.download = "新生住宿申请汇总.xls"
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
}).catch(() => {
// 错误处理
})
}
// 初始化招生计划
const initPlanGroup = () => {
list().then((data: any) => {
planList.value = data.data
if (planList.value.length > 0) {
dataForm.groupId = planList.value[0].id
}
})
}
// 获取表格数据
const getTableList = (groupId: string) => {
dataListLoading.value = true
dormApplyAnalysis({ "groupId": groupId }).then((response: any) => {
dataList.value = response.data
dataListLoading.value = false
}).catch(() => {
dataListLoading.value = false
})
}
// 获取数据列表
const getDataList = () => {
if (dataForm.groupId) {
getTableList(dataForm.groupId)
}
}
// 组件挂载时初始化
onMounted(() => {
initDept()
initPlanGroup()
})
</script>
<style scoped>
.mod-config {
padding: 20px;
}
</style>

View File

@@ -0,0 +1,127 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<header style="font-size: 40px; text-align: center; margin-bottom: 20px;">
历年常州地区初中生分数段人数统计(本省本市初中生源)
</header>
<div class="mb15">
<el-button type="warning" plain icon="Download" :loading="exportLoading" @click="dataExportHandle">导出</el-button>
</div>
<el-table
:data="dataList"
border
stripe
v-loading="dataListLoading"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column prop="socre" header-align="center" align="center" label="分数段" />
<el-table-column
v-for="(item, index) in headList"
:key="index"
:prop="item.year"
:label="item.year"
header-align="center"
>
<el-table-column
:prop="item.propOne"
header-align="center"
align="center"
label="人数"
/>
<el-table-column
:prop="item.propTwo"
header-align="center"
align="center"
label="占比"
/>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-inSchoolSocreStatic">
import { ref, reactive, onMounted } from 'vue'
import { useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { inSchoolSocreStatic } from '/@/api/recruit/recruitstudentsignup'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept'
// 消息提示 hooks
const message = useMessage()
// 状态
const headList = ref<any[]>([])
const deptCodes = ref<any[]>([])
const planList = ref<any[]>([])
const dataList = ref<any[]>([])
const dataListLoading = ref(false)
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
groupId: ''
})
// 使用 table hook 获取样式
const { tableStyle, downBlobFile } = useTable()
// 初始化
const init = async () => {
try {
const [deptResponse, planData] = await Promise.all([
getDeptListByLevelTwo(),
list()
])
deptCodes.value = deptResponse.data || []
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
getDataList()
}
} catch (error) {
console.error('初始化失败', error)
}
}
// 获取数据列表
const getDataList = async () => {
try {
dataListLoading.value = true
dataList.value = []
const response = await inSchoolSocreStatic(queryForm)
if (response.data && response.data.length > 0) {
response.data.forEach((e: any) => {
dataList.value.push(e.map)
})
headList.value = response.data[0].list || []
}
} catch (error) {
console.error('获取数据失败', error)
} finally {
dataListLoading.value = false
}
}
// 导出
const dataExportHandle = async () => {
try {
exportLoading.value = true
await downBlobFile('/recruit/recruitstudentsignup/inSchoolSocreStaticExport', queryForm, '历年常州地区初中生分数段统计.xls')
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
onMounted(() => {
init()
})
</script>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
<template>
<el-dialog v-model="visible" width="60%" :title="`面试审核(${row.name})`">
<el-row>
<el-radio v-model="status" label="1">通过</el-radio>
<el-radio v-model="status" label="-1">未通过</el-radio>
</el-row>
<el-row v-if="status == '-1'">
<br />
<el-input type="textarea" v-model="reason" placeholder="请输入未通过的原因"></el-input>
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="confirm"><span>确认</span></el-button>
<el-button @click="visible = false">取消</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useMessage } from '/@/hooks/message'
// @ts-ignore
import global from "@/components/tools/commondict"
import { interview } from "@/api/recruit/recruitstudentsignup"
// 消息提示 hooks
const message = useMessage()
// Emits
const emit = defineEmits<{
(e: 'refresh'): void
}>()
// 响应式数据
const visible = ref(false)
const row = reactive<any>({})
const status = ref('1')
const reason = ref('')
// 初始化
const init = (rowData: any) => {
visible.value = true
Object.assign(row, rowData)
status.value = rowData.interview || '1'
reason.value = rowData.interviewReason || ''
}
// 确认
const confirm = () => {
if (!status.value || (status.value == '-1' && !reason.value)) {
message.warning('请选择通过还是未通过,未通过请输入原因')
return
} else {
interview({ "id": row.id, "interview": status.value, "interviewReason": reason.value }).then(() => {
message.success('操作成功')
visible.value = false
emit('refresh')
}).catch(() => {
message.error('操作失败')
})
}
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,189 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable 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="xz">
<el-select v-model="queryForm.xz" filterable placeholder="请选择学制" clearable>
<el-option
v-for="item in majorYears"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="是否联院" prop="isUnion">
<el-select v-model="queryForm.isUnion" filterable placeholder="请选择是否联院" clearable>
<el-option key="0" label="否" value="0" />
<el-option key="1" label="是" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleFilter">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button type="warning" plain icon="Download" :loading="exportLoading" @click="dataExportHandle">导出</el-button>
</div>
<el-table
:data="dataList"
border
stripe
:row-style="changeRowColor"
v-loading="dataListLoading"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column prop="indexNum" header-align="center" align="center" label="序号">
<template #default="scope">
{{ scope.row.indexNum }}
</template>
</el-table-column>
<el-table-column prop="deptCode" header-align="center" align="center" label="系部">
<template #default="scope">
{{ getDeptType(scope.row.deptCode) }}
</template>
</el-table-column>
<el-table-column prop="zymc" header-align="center" align="center" label="所报专业" />
<el-table-column prop="maxScore" header-align="center" align="center" label="最高分" />
<el-table-column prop="minScore" header-align="center" align="center" label="最低分" />
<el-table-column prop="avgScore" header-align="center" align="center" label="平均分" />
<el-table-column prop="majorPeopleNum" header-align="center" align="center" label="专业人数" />
<el-table-column prop="avgScoreDB" header-align="center" align="center" label="均分对比" />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-juniorlneStatic">
import { ref, reactive, onMounted } from 'vue'
import { useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import { juniorlneStatic } from '/@/api/recruit/recruitstudentsignup'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept'
// 消息提示 hooks
const message = useMessage()
// 字典
const { getTypeValue } = useDict()
// 引用
const searchFormRef = ref()
// 状态
const deptCodes = ref<any[]>([])
const planList = ref<any[]>([])
const dataList = ref<any[]>([])
const majorYears = ref<any[]>([])
const dataListLoading = ref(false)
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
groupId: '',
xz: '',
isUnion: ''
})
// 使用 table hook 获取样式
const { tableStyle, downBlobFile } = useTable()
// 初始化
const init = async () => {
try {
const [deptResponse, majorYearsRes, planData] = await Promise.all([
getDeptListByLevelTwo(),
getTypeValue('basic_major_years'),
list()
])
deptCodes.value = deptResponse.data || []
majorYears.value = majorYearsRes.data || []
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
getDataList()
}
} catch (error) {
console.error('初始化失败', error)
}
}
// 获取数据列表
const getDataList = async () => {
try {
dataListLoading.value = true
dataList.value = []
const response = await juniorlneStatic(queryForm)
dataList.value = response.data || []
} catch (error) {
console.error('获取数据失败', error)
} finally {
dataListLoading.value = false
}
}
// 导出
const dataExportHandle = async () => {
try {
exportLoading.value = true
await downBlobFile('/recruit/recruitstudentsignup/juniorlneStaticExport', queryForm, '初中分数统计.xls')
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 改变行颜色
const changeRowColor = ({ row }: { row: any }) => {
if (row.zymc === '合计') {
return {
color: 'red'
}
}
}
// 获取系部名称
const getDeptType = (type: string) => {
const dept = deptCodes.value.find((item: any) => item.deptCode === type)
return dept ? dept.deptName : ''
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
queryForm.xz = ''
queryForm.isUnion = ''
getDataList()
}
onMounted(() => {
init()
})
</script>

View File

@@ -0,0 +1,510 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable clearable placeholder="请选择招生计划" style="width: 150px;">
<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="xy">
<el-select v-model="queryForm.xy" filterable clearable placeholder="请选择学院" style="width: 130px;">
<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.zydm"
:label="item.zymc + '(' + item.xz + '年制)'"
:value="item.zydm"
/>
</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="isOutFw">
<el-select v-model="queryForm.isOutFw" filterable clearable placeholder="请选择住宿范围" style="width: 100px;">
<el-option
v-for="item in isOutFwList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="是否发送短信" prop="isSend">
<el-select v-model="queryForm.isSend" filterable clearable placeholder="请选择是否发送短信" style="width: 100px;">
<el-option
v-for="item in isSendList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-select v-model="queryForm.gender" filterable clearable placeholder="请选择性别" style="width: 120px;">
<el-option
v-for="item in genderList"
: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 type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="mb15">
<el-button
v-if="permissions.recruitStuDorm"
type="primary"
icon="Setting"
@click="setDormFW"
>
住宿范围
</el-button>
<el-button
v-if="permissions.recruitStuDorm"
type="danger"
plain
icon="Location"
class="ml10"
@click="yjOut"
>
一键判断住宿范围
</el-button>
<el-button
v-if="permissions.recruitStuDormMess"
type="danger"
plain
icon="Message"
class="ml10"
@click="yjSend"
>
批量发送短信
</el-button>
<el-button
type="warning"
plain
icon="Download"
class="ml10"
@click="handleExport"
>
名单导出
</el-button>
</div>
<!-- 表格 -->
<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="serialNumber" label="唯一号" width="100" align="center" show-overflow-tooltip />
<el-table-column prop="name" label="姓名" width="100" align="center" show-overflow-tooltip />
<el-table-column prop="gender" label="性别" width="80" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getGender(scope.row.gender) }}
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号" width="180" align="center" show-overflow-tooltip />
<el-table-column prop="xy" label="学院" width="120" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getDeptName(scope.row.xy) }}
</template>
</el-table-column>
<el-table-column prop="homeAddressDetail" label="家庭地址" align="center" show-overflow-tooltip />
<el-table-column prop="isOutFw" label="范围" width="100" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.isOutFw == 0">待确认</span>
<span v-if="scope.row.isOutFw == 1">范围内</span>
<span v-if="scope.row.isOutFw == 2">范围外</span>
</template>
</el-table-column>
<el-table-column prop="isSd" label="手动设置" width="100" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.isSd == 0">未设置</span>
<span v-if="scope.row.isSd == 1">已设置</span>
</template>
</el-table-column>
<el-table-column prop="isSend" label="发送短信" width="100" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.isSend == 0">未发送</span>
<span v-if="scope.row.isSend == 1">已发送</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruitStuDormSd && scope.row.isOutFw != '1'"
type="success"
link
icon="CircleCheck"
@click="setFw(scope.row, 1)"
>
设为范围内
</el-button>
<el-button
v-if="permissions.recruitStuDormSd && scope.row.isOutFw != '2'"
type="warning"
link
icon="Close"
@click="setFw(scope.row, 2)"
>
设为范围外
</el-button>
<el-button
type="primary"
link
icon="Location"
@click="baiduMap(scope.row)"
>
家庭地址
</el-button>
<el-button
v-if="permissions.recruitStuDormDel"
type="danger"
link
icon="Delete"
@click="deleteHandle(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 支付二维码弹窗 -->
<el-dialog v-model="dialogFormVisible" title="支付二维码" width="800px" @close="dialogFormVisible = false">
<el-table :data="tableData" border>
<el-table-column label="唯一号" prop="serialNumber" align="center" />
<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">
<el-button type="danger" icon="Search" @click="updateFS">立即查询</el-button>
</template>
</el-table-column>
</el-table>
<div style="padding-top: 20px;">
<div id="payQrcode1" style="display: inline-block;">
{{ payQrcode1Msg }}
</div>
<!-- <vue-qr :text="payQrcode1" :size="200" v-if="showPrise1" style="display: inline-block"></vue-qr> -->
<div id="payQrcode2" style="display: inline-block">
{{ payQrcode2Msg }}
</div>
<!-- <vue-qr :text="payQrcode2" :size="200" v-if="showPrise2" style="display: inline-block"></vue-qr> -->
<div id="payQrcode3" style="display: inline-block">
{{ payQrcode3Msg }}
</div>
<!-- <vue-qr :text="payQrcode3" :size="200" v-if="showPrise3" style="display: inline-block"></vue-qr> -->
</div>
<span style="color: red;padding-top: 20px;">** 此界面为查询学生缴款二维码如有收不到微信推送或手机号填错的可直接在此扫码支付支付成功后请手动点击"立即查询"按钮查询该生的缴费情况;因财政收费系统有一定的滞后性如点击"立即查询"后任显示未交费请稍后再继续查询或重新点击"立即查询"按钮 **</span>
</el-dialog>
<dorm-f-w v-if="dormFWRefVisible" ref="dormFWRef" />
<show-map v-if="baiduMapVisible" ref="baiduMapRef" />
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignupList">
import { ref, reactive, computed, onMounted, nextTick, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { fetchListStuDorm, yjOut, setFw, delFw, yjSend } from '/@/api/recruit/recruitstudentsignup'
import { getDeptList } from '/@/api/basic/basicclass'
// @ts-ignore
import global from '@/components/tools/commondict'
const DormFW = defineAsyncComponent(() => import('./dormFW.vue'))
const ShowMap = defineAsyncComponent(() => import('./showMap.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
})
// 消息提示 hooks
const message = useMessage()
const messageBox = useMessageBox()
// 表格引用
const tableRef = ref()
const searchFormRef = ref()
const dormFWRef = ref()
const baiduMapRef = ref()
// 数据
const planList = ref<any[]>([])
const planMajorList = ref<any[]>([])
const deptList = ref<any[]>([])
const genderList = ref([{ label: '男', value: '1' }, { label: '女', value: '2' }])
const isOutFwList = ref([{ label: '待确认', value: '0' }, { label: '范围内', value: '1' }, { label: '范围外', value: '2' }])
const isSendList = ref([{ label: '未发送', value: 0 }, { label: '已发送', value: 1 }])
// 查询表单
const queryForm = reactive({
groupId: '',
xy: '',
confirmedMajor: '',
search: '',
isOutFw: '',
isSend: null,
gender: ''
})
// 弹窗状态
const dialogFormVisible = ref(false)
const dormFWRefVisible = ref(false)
const baiduMapVisible = ref(false)
const tableData = ref<any[]>([])
const payQrcode1 = ref('')
const showPrise1 = ref(false)
const payQrcode1Msg = ref('')
const payQrcode2 = ref('')
const payQrcode2Msg = ref('')
const showPrise2 = ref(false)
const payQrcode3 = ref('')
const payQrcode3Msg = ref('')
const showPrise3 = ref(false)
// 获取学院名称
const getDeptName = (deptCode: string) => {
const item = deptList.value.find(item => item.deptCode === deptCode)
return item ? item.deptName : ''
}
// 获取性别
const getGender = (gender: string) => {
if (gender == '2') {
return '女'
}
if (gender == '1') {
return '男'
}
return ''
}
// 表格状态
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: queryForm,
pageList: async (params: any) => {
const response = await fetchListStuDorm(params)
return {
data: {
records: response.data.records,
total: response.data.total
}
}
},
createdIsNeed: false
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle, downBlobFile } = useTable(state)
// 初始化
const init = async () => {
try {
// 查询二级学院信息
const deptData = await getDeptList()
deptList.value = deptData.data || []
// 获取招生计划列表
const planData = await list()
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
} catch (error) {
console.error('初始化失败', error)
}
}
// 设置住宿范围
const setFw = async (row: any, type: number) => {
const title = type == 1 ? '范围内' : '范围外'
try {
await messageBox.confirm(`是否确认设置${title}?请谨慎操作`)
await setFw({ id: row.id, isOutFw: type })
message.success('操作成功')
getDataList()
} catch {
// 用户取消
}
}
// 设置住宿范围窗口
const setDormFW = () => {
dormFWRefVisible.value = true
nextTick(() => {
dormFWRef.value?.init()
})
}
// 一键判断住宿范围
const yjOut = async () => {
if (!queryForm.groupId) {
message.warning('招生计划不能为空')
return
}
try {
await messageBox.confirm('是否确认一键判断是否超出住宿范围?请谨慎操作')
await yjOut({ groupId: queryForm.groupId })
message.success('操作成功')
getDataList()
} catch {
// 用户取消
}
}
// 批量发送短信
const yjSend = async () => {
if (!queryForm.groupId) {
message.warning('招生计划不能为空')
return
}
try {
await messageBox.confirm('是否确认批量发送短信通知?请谨慎操作')
await yjSend({ groupId: queryForm.groupId })
message.success('操作成功')
getDataList()
} catch {
// 用户取消
}
}
// 百度地图
const baiduMap = (row: any) => {
baiduMapVisible.value = true
nextTick(() => {
baiduMapRef.value?.init(row)
})
}
// 导出
const handleExport = async () => {
if (!queryForm.groupId) {
message.warning('招生计划不能为空')
return
}
try {
await downBlobFile(
'/recruit/recruitstudentsignup/stuDormExport',
queryForm,
'新生住宿名单导出.xls'
)
} catch (error: any) {
message.error(error.msg || '导出失败')
}
}
// 立即查询
const updateFS = async () => {
// 这个方法需要根据实际API调整
message.info('功能待实现')
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.groupId = ''
queryForm.xy = ''
queryForm.confirmedMajor = ''
queryForm.search = ''
queryForm.isOutFw = ''
queryForm.isSend = null
queryForm.gender = ''
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
// 删除
const deleteHandle = async (id: string) => {
try {
await messageBox.confirm('是否确认删除本条数据?请谨慎操作')
await delFw(id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,387 @@
<template>
<el-dialog
:title="title"
:close-on-click-modal="false"
v-model="visible"
append-to-body
width="90%">
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit"
label-width="170px" size="small">
<el-row>
<el-col :span="24">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable :disabled="!!dataForm.id"
placeholder="请选择招生计划" size="small" style="width: 100%">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="姓名" prop="name">
<el-input type="text" v-model="dataForm.name" :disabled="type != 1"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="身份证号" prop="idNumber">
<el-input type="text" v-model="dataForm.idNumber" :disabled="type != 2"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="成绩折算分" prop="correctedScore">
<el-input-number v-model="dataForm.correctedScore" controls-position="right" :min="0" :max="999" :step-strictly="true" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="原录取专业" prop="confirmedMajor">
<el-select v-model="dataForm.confirmedMajor" filterable clearable placeholder="" size="small" style="width: 100%" :disabled="type != 1" @change="changeM(dataForm.confirmedMajor)">
<el-option
v-for="item in planMajorList"
:key="item.zydm"
:label="item.zymc"
:value="item.zydm">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="新录取专业" prop="newConfirmedMajor">
<el-select v-model="dataForm.newConfirmedMajor" filterable placeholder="" size="small" style="width: 100%" @change="changeCM(dataForm.newConfirmedMajor)">
<el-option
v-for="item in planMajorList"
:key="item.zydm"
:label="item.zymc+' || '+item.xyNum"
:value="item.zydm">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="学费" prop="feeTuition">
<el-input-number v-model="dataForm.feeTuition" controls-position="right" :min="0" :max="999999" :step-strictly="true" style="width:100%;" :disabled="type == 2"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="代办费" prop="feeAgency">
<el-input-number v-model="dataForm.feeAgency" controls-position="right" :min="0" :max="999999" :step-strictly="true" style="width:100%;" :disabled="type == 2"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="总费用" prop="allMoney">
<span style="color: red">{{ dataForm.feeTuition + dataForm.feeAgency }}</span>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="审核备注" prop="auditRemarks">
<el-input type="textarea" v-model="dataForm.auditRemarks" placeholder="审核备注" :rows="2"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="success" @click="dataFormSubmit" v-if="canSubmit">确认修改</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { ElNotification } from 'element-plus'
import { useMessageBox } from '/@/hooks/message'
import { getObj, changeMajor } from '@/api/recruit/recruitstudentsignup'
import { list } from "@/api/recruit/recruitstudentplangroup"
import { listByEdu } from "@/api/recruit/recruitstudentplan"
import { getDictByType } from "@/api/contract/contract"
import { list as scoreList } from "@/api/recruit/recruitstudentplancorrectscoreconfig"
// 消息提示 hooks
const messageBox = useMessageBox()
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const visible = ref(false)
const canSubmit = ref(false)
const title = ref("")
const type = ref<number | null>(null)
const planList = ref<any[]>([])
const planMajorList = ref<any[]>([])
const agencyFeeList = ref<any[]>([])
const tuitionFeeList = ref<any[]>([])
const schoolCodeList = ref<any[]>([])
const dataForm = reactive({
id: "",
groupId: "",
name: "",
oldName: "",
gender: "",
nationality: "",
degreeOfEducation: "",
isLeagueMember: "",
schoolOfGraduation: "",
isAccommodation: "",
examRegistrationNumbers: "",
isMinimumLivingSecurity: "",
score: "",
postcode: "",
residenceType: "",
correctedScore: null as number | null,
placeScore: "",
schoolFrom: "",
idNumber: "",
residenceProvince: "",
residenceCity: "",
residenceArea: "",
residenceDetail: "",
homeAddressProvince: "",
homeAddressCity: "",
homeAddressArea: "",
homeAddressDetail: "",
parentName: "",
parentTelOne: "",
parentTelTwo: "",
selfTel: "",
wishMajorOne: "",
wishMajorTwo: "",
wishMajorThree: "",
confirmedMajor: "",
sevenMajor: "",
sixMajor: "",
fiveMajor: "",
fourMajor: "",
threeMajor: "",
twoMajor: "",
feeContribute: 0,
scorePhoto: "",
graPic: "",
yyPic: "",
housePic: "",
sbPic: "",
contactName: "",
oldSerialNumber: "",
colorDiscrimination: "",
nutrition: "",
height: "",
weight: "",
pastMedicalHistory: "",
eyesightLeft: "",
eyesightRight: "",
correctEyesightLeft: "",
correctEyesightRight: "",
remarks: "",
auditRemarks: "",
serialNumber: "",
auditStatus: "",
schoolCode: "",
newConfirmedMajor: "",
householdPic: "",
feeTuition: 0,
feeAgency: 0
})
const dataRule = {
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'change' }
],
name: [
{ required: true, message: '姓名不能为空', trigger: 'change' }
],
idNumber: [
{ required: true, message: '身份证不能为空', trigger: 'change' }
],
correctedScore: [
{ required: true, message: '成绩折算分不能为空', trigger: 'change' }
],
confirmedMajor: [
{ required: true, message: '原录取专业不能为空', trigger: 'change' }
],
newConfirmedMajor: [
{ required: true, message: '新录取专业不能为空', trigger: 'change' }
]
}
// 初始化数据
const initData = () => {
list().then((data: any) => {
planList.value = data.data
})
}
// 改变新专业
const changeCM = (id: string) => {
if (id) {
let flag = false
planMajorList.value.forEach((e: any) => {
if (dataForm.newConfirmedMajor == e.zydm && e.isZd == "1" && String(dataForm.degreeOfEducation) == "1") {
flag = true
}
})
if (String(dataForm.degreeOfEducation) == "1") {
dataForm.feeTuition = 0
tuitionFeeList.value.forEach((e: any) => {
if (e.label == "0" && flag) {
dataForm.feeTuition = e.value
}
})
}
}
}
// 改变原专业
const changeM = (id: string) => {
if (id) {
dataForm.confirmedMajor = id
// 是初中生并且是中德班
let flag = false
planMajorList.value.forEach((e: any) => {
if (dataForm.confirmedMajor == e.zydm && e.isZd == "1" && String(dataForm.degreeOfEducation) == "1") {
flag = true
}
})
if (String(dataForm.degreeOfEducation) == "1") {
dataForm.feeTuition = 0
tuitionFeeList.value.forEach((e: any) => {
if (e.label == "0" && flag) {
dataForm.feeTuition = e.value
}
})
}
}
}
// 表单提交
const dataFormSubmit = async () => {
const titleText = "确认调整录取专业么?"
if (dataForm.confirmedMajor == dataForm.newConfirmedMajor) {
ElNotification.error({
title: '错误',
message: '新专业不能和原专业相同'
})
return
}
try {
await messageBox.confirm(titleText)
dataFormRef.value?.validate((valid: boolean) => {
if (valid) {
canSubmit.value = false
if (dataForm.id) {
changeMajor(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '操作成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
}
})
} catch {
// 用户取消
}
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
// 获取数据字典代办费
getDictByType("agency_fee").then((res: any) => {
agencyFeeList.value = res.data
// 获取数据字典学费
getDictByType("tuition_fee").then((res: any) => {
tuitionFeeList.value = res.data
getObj(dataForm.id).then((response: any) => {
Object.assign(dataForm, response.data)
title.value = dataForm.serialNumber
// 获取文化程度对应的专业
planMajorList.value = []
agencyFeeList.value.forEach((e: any) => {
if (String(dataForm.degreeOfEducation) == String(e.label)) {
dataForm.feeAgency = e.value
}
})
tuitionFeeList.value.forEach((e: any) => {
if (String(dataForm.degreeOfEducation) == String(e.label) && (String(dataForm.degreeOfEducation) != "1")) {
dataForm.feeTuition = e.value
}
})
listByEdu({ groupId: dataForm.groupId, degreeOfEducation: dataForm.degreeOfEducation }).then((e: any) => {
planMajorList.value = e.data
})
// 获取招生计划下的学校和分数线
scoreList({ groupId: dataForm.groupId }).then((data: any) => {
schoolCodeList.value = data.data
})
if ("1" == dataForm.degreeOfEducation) {
title.value = "C" + title.value
} else if ("2" == dataForm.degreeOfEducation) {
title.value = "G" + title.value
} else if ("3" == dataForm.degreeOfEducation) {
title.value = "J" + title.value
}
if ("-20" == dataForm.auditStatus) {
title.value = "未录取 " + title.value
} else if ("0" == dataForm.auditStatus) {
title.value = "待审核 " + title.value
} else if ("20" == dataForm.auditStatus) {
title.value = "已录取 " + title.value
}
})
})
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,389 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<header style="font-size: 40px; text-align: center; margin-bottom: 20px;">
招生地区分布统计(本省本市普通招生自主招生)
</header>
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="是否联院" prop="isUnion">
<el-select v-model="queryForm.isUnion" filterable placeholder="请选择是否联院">
<el-option
v-for="item in isUnionList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleFilter">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button type="warning" plain icon="Download" :loading="exportLoading" @click="dataExportHandle">导出</el-button>
</div>
<el-table
:data="dataList"
border
stripe
:span-method="objectSpanMethod"
v-loading="dataListLoading"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column
prop="year"
header-align="center"
align="center"
label="年份">
</el-table-column>
<el-table-column
prop="type"
header-align="center"
align="center"
label="类别">
</el-table-column>
<el-table-column
prop="peopleNum"
header-align="center"
align="center"
label="招生总数">
</el-table-column>
<el-table-column
prop="peopleRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="天宁区">
<el-table-column
prop="tnNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="tnRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="新北区">
<el-table-column
prop="xbNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="xbRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="武进区">
<el-table-column
prop="wjNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="wjRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="钟楼区">
<el-table-column
prop="zlNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="zlRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="金坛">
<el-table-column
prop="jtNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="jtRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="溧阳">
<el-table-column
prop="lyNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="lyRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="武进区(含 戚墅堰)">
<el-table-column
prop="wjjNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="wjjRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="经开区">
<el-table-column
prop="jkqNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="jkqRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="市辖区">
<el-table-column
prop="cityNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="cityRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="本省外市">
<el-table-column
prop="bswNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="bswRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
<el-table-column
prop=""
header-align="center"
align="center"
label="外省">
<el-table-column
prop="wsNum"
header-align="center"
align="center"
label="人数">
</el-table-column>
<el-table-column
prop="wsRate"
header-align="center"
align="center"
label="占比">
</el-table-column>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-schoolAreaStatic">
import { ref, reactive, onMounted } from 'vue'
import { useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { schoolAreaStatic } from '/@/api/recruit/recruitstudentsignup'
// 消息提示 hooks
const message = useMessage()
// 引用
const searchFormRef = ref()
// 状态
const isUnionList = [
{ value: '0', label: '否' },
{ value: '1', label: '是' }
]
const dataList = ref<any[]>([])
const indexArray = ref<number[]>([])
const dataListLoading = ref(false)
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
isUnion: '0'
})
// 使用 table hook 获取样式
const { tableStyle, downBlobFile } = useTable()
// 初始化
const init = () => {
queryForm.isUnion = '0'
getDataList()
}
// 获取行数
const getRows = (rowIndex: number, name: string) => {
let count = 0
for (let i = rowIndex; i < dataList.value.length; i++) {
if (dataList.value[i].year === name) {
count++
} else {
break
}
}
return count
}
// 合并单元格方法
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
if (columnIndex === 0) {
if (indexArray.value.includes(rowIndex)) {
const rowCount = getRows(rowIndex, row.year)
return {
rowspan: rowCount,
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
// 获取数据列表
const getDataList = async () => {
try {
dataListLoading.value = true
dataList.value = []
indexArray.value = []
const response = await schoolAreaStatic(queryForm)
dataList.value = response.data || []
// 计算合并单元格的索引
let count = 0
for (let rowIndex = 0; rowIndex < dataList.value.length; ) {
indexArray.value.push(rowIndex)
count = getRows(rowIndex, dataList.value[rowIndex].year)
rowIndex += count
}
} catch (error) {
console.error('获取数据失败', error)
} finally {
dataListLoading.value = false
}
}
// 导出
const dataExportHandle = async () => {
try {
exportLoading.value = true
await downBlobFile(
'/recruit/recruitstudentsignup/schoolAreaStaticExport',
queryForm,
'招生地区分布统计(本省本市、普通招生、自主招生).xls'
)
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
queryForm.isUnion = '0'
getDataList()
}
onMounted(() => {
init()
})
</script>

View File

@@ -0,0 +1,175 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form :model="queryForm" inline class="mb-4" ref="searchFormRef">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="queryForm.groupId" filterable 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>
<el-button type="primary" icon="Search" @click="handleFilter">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button type="warning" plain icon="Download" :loading="exportLoading" @click="dataExportHandle">导出</el-button>
</div>
<el-table
:data="dataList"
border
stripe
v-loading="dataListLoading"
:summary-method="getSummaries"
show-summary
:row-style="changeRowColor"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column align="center" header-align="center" prop="schoolName" label="学校名称" />
<el-table-column align="center" header-align="center" prop="peopleNum" label="人数" />
<el-table-column align="center" header-align="center" prop="peopleRate" label="占比" />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-schoolStatic">
import { ref, reactive, onMounted } from 'vue'
import { useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { getSchoolStatic } from '/@/api/recruit/recruitstudentsignup'
import { list } from '/@/api/recruit/recruitstudentplangroup'
// 消息提示 hooks
const message = useMessage()
// 引用
const searchFormRef = ref()
// 状态
const dataList = ref<any[]>([])
const planList = ref<any[]>([])
const indexArray = ref<any[]>([])
const dataListLoading = ref(false)
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
groupId: ''
})
// 使用 table hook 获取样式
const { tableStyle, downBlobFile } = useTable()
// 初始化
const init = async () => {
try {
const data = await list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
getDataList()
}
} catch (error) {
console.error('初始化失败', error)
}
}
// 获取数据列表
const getDataList = async () => {
try {
dataListLoading.value = true
dataList.value = []
indexArray.value = []
const response = await getSchoolStatic(queryForm)
dataList.value = response.data || []
} catch (error) {
console.error('获取数据失败', error)
} finally {
dataListLoading.value = false
}
}
// 导出
const dataExportHandle = async () => {
try {
exportLoading.value = true
await downBlobFile('/recruit/recruitstudentsignup/getSchoolStaticExport', queryForm, '按学校导出.xls')
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 改变行颜色
const changeRowColor = ({ row }: { row: any }) => {
const specialSchools = [
'智能装备学院',
'智能制造学院',
'信息服务学院',
'交通运输学院',
'医药康养学院',
'招生就业处'
]
if (specialSchools.includes(row.schoolName)) {
return {
color: 'red'
}
}
}
// 合计方法
const getSummaries = (param: any) => {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总计'
} else if (index === 1) {
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: any) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: any) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0) / 2
} else {
sums[index] = '--'
}
} else {
sums[index] = '--'
}
})
return sums
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>

View File

@@ -0,0 +1,117 @@
<template>
<el-dialog
title="家庭地址地图选点"
append-to-body
:close-on-click-modal="false"
v-model="visible"
width="90%">
<div style="height: 100%;width:100%">
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px"
class="demo-ruleForm">
<el-form-item label="家庭地址" prop="homeAddressDetail">
<el-input v-model="form.homeAddressDetail" style="width: 100%"></el-input>
</el-form-item>
</el-form>
<div id="container2"></div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import { BMPGL } from "@/api/recruit/recruitstudentsignup"
import { getTypeValue } from "@/api/admin/dict"
// 表单引用
const formRef = ref()
// 响应式数据
const ak = "V0ooaf2RZyEGOkD8UzZB3gvw7pCb0Kx7" // 百度的地图密钥
const visible = ref(false)
const canSubmit = ref(false)
const circleShow = ref(false)
const circle = ref<any>(null)
// 地址信息
const address = ref(null)
const center = reactive({ lng: 0, lat: 0 })
const dictId = ref("")
const circleArr = ref<any[]>([])
const form = reactive({
id: "",
homeAddressDetail: "",
raidus: 0
})
const rules = {
homeAddressDetail: [
{ required: true, message: '家庭地址不能为空', trigger: ["blur", "change"] }
],
}
// 初始化
const init = (row: any) => {
visible.value = true
canSubmit.value = true
circleShow.value = true
form.id = row.id
form.homeAddressDetail = row.homeAddressDetail
nextTick(() => {
getTypeValue("dorm_jw").then((data: any) => {
const arr = data.data
arr.forEach((e: any) => {
if (e.label == 'bj') {
form.raidus = e.value
dictId.value = e.id
} else if (e.label == 'lng') {
center.lng = e.value
} else if (e.label == 'lat') {
center.lat = e.value
}
})
BMPGL(ak).then((BMapGL: any) => {
// 创建地图实例
const map = new BMapGL.Map("container2")
// 创建点坐标
const point = new BMapGL.Point(center.lng, center.lat)
// 初始化地图,设置中心点坐标和地图级别
map.centerAndZoom(point, 13)
// 开启鼠标滚轮缩放
map.enableScrollWheelZoom(true)
// 创建地址解析器实例
const myGeo = new BMapGL.Geocoder()
myGeo.getPoint(form.homeAddressDetail, function (point: any) {
if (point) {
map.centerAndZoom(point, 16)
map.addOverlay(new BMapGL.Marker(point, { title: form.homeAddressDetail }))
} else {
alert('您选择的地址没有解析到结果!')
}
}, '北京市')
})
})
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
#container2 {
overflow: hidden;
width: 100%;
height: 700px;
margin: 0;
font-family: "微软雅黑";
}
ul li {
list-style: none;
}
</style>

View File

@@ -0,0 +1,176 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form :model="queryForm" inline class="mb-4" 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>
<el-button type="primary" icon="Search" @click="handleFilter">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb15">
<el-button type="warning" plain icon="Download" :loading="exportLoading" @click="handleExport">导出</el-button>
</div>
<el-table
:data="state.dataList"
border
stripe
height="700px"
v-loading="state.loading"
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column width="150" prop="deptCode" header-align="center" align="center" label="学院">
<template #default="scope">
{{ global.getLabelValueByPropes(deptList, scope.row.deptCode, { key: 'deptCode', value: 'deptName' }) }}
</template>
</el-table-column>
<el-table-column width="150" prop="zydm" header-align="center" align="center" label="专业代码" />
<el-table-column prop="zymc" header-align="center" align="center" label="专业名称" />
<el-table-column width="80" prop="scoreLine" header-align="center" align="center" label="分数线" />
<el-table-column width="80" prop="planNum" header-align="center" align="center" label="计划总数" />
<el-table-column width="80" prop="recruitmentNum" header-align="center" align="center" label="拟招人数" />
<el-table-column width="80" prop="hasNum" header-align="center" align="center" label="已招人数" />
<el-table-column width="80" prop="boyNum" header-align="center" align="center" label="已招(男)" />
<el-table-column width="80" prop="girlNum" header-align="center" align="center" label="已招(女)" />
<el-table-column width="80" prop="cityFrom" header-align="center" align="center" label="市平台" />
<el-table-column width="80" prop="schoolFrom" header-align="center" align="center" label="校平台" />
<el-table-column width="80" prop="xyNum" header-align="center" align="center" label="剩余人数" />
</el-table>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignup-static">
import { ref, reactive, onMounted } from 'vue'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage } from '/@/hooks/message'
import { useDict } from '/@/hooks/dict'
import { list } from '/@/api/recruit/recruitstudentplangroup'
import { fetchListByStatic, listPlanByCondition as planMajor } from '/@/api/recruit/recruitstudentplan'
import { getDeptList } from '/@/api/basic/basicclass'
// @ts-ignore
import global from '/@/components/tools/commondict.vue'
// 消息提示 hooks
const message = useMessage()
// 字典
const { getTypeValue } = useDict()
// 引用
const searchFormRef = ref()
// 状态
const planList = ref<any[]>([])
const eduList = ref<any[]>([])
const planMajorList = ref<any[]>([])
const deptList = ref<any[]>([])
const exportLoading = ref(false)
// 查询表单
const queryForm = reactive({
groupId: '',
auditStatus: 20
})
// 表格状态
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: queryForm,
pageList: async (params: any) => {
const response = await fetchListByStatic(params)
return {
data: {
records: response.data || [],
total: response.data?.length || 0
}
}
},
createdIsNeed: false
})
// 使用 table hook
const { getDataList, tableStyle, downBlobFile } = useTable(state)
// 初始化
const init = async () => {
try {
// 查询二级学院信息
const deptData = await getDeptList()
deptList.value = deptData.data || []
deptList.value.push({ deptCode: '小计(高中/职技校)', deptName: '小计(高中/职技校)' })
deptList.value.push({ deptCode: '小计(初中)', deptName: '小计(初中)' })
deptList.value.push({ deptCode: '小计(初中_联院大专)', deptName: '小计(初中_联院大专)' })
deptList.value.push({ deptCode: '合计', deptName: '合计' })
// 获取招生计划列表
const planData = await list()
planList.value = planData.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
getDataList()
chanMajor()
}
// 获取字典数据
const eduRes = await getTypeValue('education_type')
eduList.value = eduRes.data || []
} catch (error) {
console.error('初始化失败', error)
}
}
// 导出
const handleExport = async () => {
try {
exportLoading.value = true
await downBlobFile('/recruit/recruitstudentsignup/exportExcel', queryForm, '招生统计.xls')
} catch (error: any) {
message.error(error.msg || '导出失败')
} finally {
exportLoading.value = false
}
}
// 切换专业
const chanMajor = async () => {
try {
planMajorList.value = []
if (queryForm.groupId) {
const data = await planMajor({ groupId: queryForm.groupId })
planMajorList.value = data.data || []
}
} catch (error) {
console.error('获取专业列表失败', error)
}
}
// 查询
const handleFilter = () => {
getDataList()
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>

View File

@@ -0,0 +1,31 @@
<template>
<div class="mod-config">
<basic-container>
<el-tabs v-model="activeName">
<el-tab-pane label="申请列表" name="first">
<List></List>
</el-tab-pane>
<el-tab-pane label="申请汇总" name="second">
<DormAnalysis></DormAnalysis>
</el-tab-pane>
</el-tabs>
</basic-container>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { defineAsyncComponent } from 'vue'
const List = defineAsyncComponent(() => import('./list.vue'))
const DormAnalysis = defineAsyncComponent(() => import('./dorm_analysis.vue'))
// 响应式数据
const activeName = ref('first')
</script>
<style scoped>
.mod-config {
padding: 20px;
}
</style>

View File

@@ -0,0 +1,647 @@
<template>
<el-dialog
:title="title"
:close-on-click-modal="false"
v-model="visible"
append-to-body
width="90%">
<el-form :model="dataForm" :rules="dataRule" ref="dataFormRef" @keyup.enter="dataFormSubmit"
label-width="170px" size="small">
<el-row>
<el-col :span="24">
<el-form-item label="招生计划" prop="groupId">
<el-select v-model="dataForm.groupId" filterable :disabled="!!dataForm.id"
placeholder="请选择招生计划" size="small" style="width: 100%">
<el-option
v-for="item in planList"
:key="item.id"
:label="item.groupName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="姓名" prop="name">
<el-input type="text" v-model="dataForm.name" :disabled="type != 1"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="联系人" prop="contactName">
<el-select v-model="dataForm.contactName" filterable clearable placeholder="" size="small" style="width: 100%" :disabled="!(permissions.recruit_recruitprestudent_dj_sure || dataForm.auditStatus != '20')">
<el-option
v-for="item in contactNameList"
:key="item.teacherNo"
:label="item.realName+'-'+item.deptCode"
:value="item.teacherNo">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="成绩单" prop="scorePhoto">
<el-upload
action="/recruit/file/uploadAttachment"
list-type="picture-card"
name="file"
:headers="headers"
:limit="1"
:data="uploadData"
:file-list="fileList"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="removeHandler"
:http-request="httpRequest"
:on-success="uploadSuccess">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="毕业证" prop="graPic">
<el-upload
action="/recruit/file/uploadAttachment"
list-type="picture-card"
name="file"
:headers="headers"
:limit="1"
:data="uploadData"
:file-list="graPicList"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="remove2Handler"
:http-request="httpRequest"
:on-success="upload2Success">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="在常营业执照" prop="yyPic">
<el-upload
action="/recruit/file/uploadAttachment"
list-type="picture-card"
name="file"
:headers="headers"
:limit="1"
:data="uploadData"
:file-list="yyPicList"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="remove3Handler"
:http-request="httpRequest"
:on-success="upload3Success">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="在常租赁合同/房产证明" prop="housePic">
<el-upload
action="/recruit/file/uploadAttachment"
list-type="picture-card"
name="file"
:headers="headers"
:limit="5"
:data="uploadData"
:file-list="houseList"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="remove4Handler"
:http-request="httpRequest"
:on-success="upload4Success">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="在常就业社保证明" prop="sbPic">
<el-upload
action="/recruit/file/uploadAttachment"
list-type="picture-card"
name="file"
:headers="headers"
:limit="1"
:data="uploadData"
:file-list="sbPicList"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="remove5Handler"
:http-request="httpRequest"
:on-success="upload5Success">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="户口本" prop="householdPic">
<el-upload
action="/recruit/file/uploadAttachment"
list-type="picture-card"
name="file"
:headers="headers"
:limit="5"
:data="uploadData"
:file-list="hkPicList"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-remove="remove6Handler"
:http-request="httpRequest"
:on-success="upload6Success">
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="材料审核意见" prop="zlshRemark">
<el-input v-model="dataForm.zlshRemark" placeholder="请输入审核意见" type="textarea" :rows="2" style="width: 80%;text-align:center;margin-top: 10px"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit('1')" v-if="canSubmit">保存</el-button>
<el-button type="success" @click="dataFormSubmit('2')" v-if="canSubmit">通过</el-button>
<el-button type="danger" @click="dataFormSubmit('3')" v-if="canSubmit">驳回</el-button>
</div>
</template>
<el-dialog title="图片预览" v-model="dialogUploadVisible" append-to-body>
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick, computed, onMounted } from 'vue'
import { Plus } from '@element-plus/icons-vue'
import { ElNotification } from 'element-plus'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { Session } from '/@/utils/storage'
import axios from 'axios'
import { getObj, updateInfo } from '@/api/recruit/recruitstudentsignup'
import { list } from "@/api/recruit/recruitstudentplangroup"
import { queryAllTeacher } from "@/api/professional/teacherbase"
// 使用 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 headers = computed(() => {
return {
"Authorization": 'Bearer ' + Session.getToken()
}
})
// Emits
const emit = defineEmits<{
(e: 'refreshDataList'): void
}>()
// 表单引用
const dataFormRef = ref()
// 响应式数据
const uploadData = reactive({})
const visible = ref(false)
const canSubmit = ref(false)
const title = ref("")
const contactNameflag = ref(false)
const type = ref<number | null>(null)
const contactNameList = ref<any[]>([])
const planList = ref<any[]>([])
const form = reactive({
attachment: '',
graPic: "",
yyPic: "",
housePic: "",
sbPic: "",
hkPic: ""
})
const fileList = ref<any[]>([])
const graPicList = ref<any[]>([])
const yyPicList = ref<any[]>([])
const houseList = ref<any[]>([])
const sbPicList = ref<any[]>([])
const hkPicList = ref<any[]>([])
const fileReader = ref<FileReader | null>(null)
const dialogImageUrl = ref("")
const dialogUploadVisible = ref(false)
const dataForm = reactive({
id: "",
zlshRemark: "",
groupId: "",
name: "",
oldName: "",
gender: "",
nationality: "",
degreeOfEducation: "",
isLeagueMember: "",
schoolOfGraduation: "",
isAccommodation: "",
examRegistrationNumbers: "",
isMinimumLivingSecurity: "",
score: "",
postcode: "",
residenceType: "",
correctedScore: "",
placeScore: "",
schoolFrom: "",
idNumber: "",
residenceProvince: "",
residenceCity: "",
residenceArea: "",
residenceDetail: "",
homeAddressProvince: "",
homeAddressCity: "",
homeAddressArea: "",
homeAddressDetail: "",
parentName: "",
parentTelOne: "",
parentTelTwo: "",
selfTel: "",
wishMajorOne: "",
wishMajorTwo: "",
wishMajorThree: "",
confirmedMajor: "",
sevenMajor: "",
sixMajor: "",
fiveMajor: "",
fourMajor: "",
threeMajor: "",
twoMajor: "",
feeContribute: 0,
scorePhoto: "",
graPic: "",
yyPic: "",
housePic: "",
sbPic: "",
contactName: "",
oldSerialNumber: "",
colorDiscrimination: "",
nutrition: "",
height: "",
weight: "",
pastMedicalHistory: "",
eyesightLeft: "",
eyesightRight: "",
correctEyesightLeft: "",
correctEyesightRight: "",
remarks: "",
auditRemarks: "",
serialNumber: "",
auditStatus: "",
schoolCode: "",
newConfirmedMajor: "",
householdPic: "",
zlsh: ""
})
const dataRule = {
groupId: [
{ required: true, message: '招生计划不能为空', trigger: 'change' }
],
name: [
{ required: true, message: '姓名不能为空', trigger: 'change' }
],
idNumber: [
{ required: true, message: '身份证不能为空', trigger: 'change' }
],
correctedScore: [
{ required: true, message: '成绩折算分不能为空', trigger: 'change' }
],
confirmedMajor: [
{ required: true, message: '原录取专业不能为空', trigger: 'change' }
],
newConfirmedMajor: [
{ required: true, message: '新录取专业不能为空', trigger: 'change' }
]
}
// 初始化 FileReader
onMounted(() => {
if (!window.FileReader) {
console.error('Your browser does not support FileReader API!')
} else {
fileReader.value = new FileReader()
}
})
// 上传前验证
const beforeUpload = (file: File) => {
const isLt5M = file.size < 10 * 1024 * 1024
if (!isLt5M) {
ElNotification.error({
title: '错误',
message: '文件大小不能超过10M'
})
return false
}
return true
}
// 图片预览
const handlePictureCardPreview = (file: any) => {
dialogImageUrl.value = file.url
dialogUploadVisible.value = true
}
// 移除文件处理
const removeHandler = (file: any) => {
const index = fileList.value.findIndex((item: any) => item.url === file.url)
if (index > -1) {
fileList.value.splice(index, 1)
}
form.attachment = ""
dataForm.scorePhoto = ""
}
const remove2Handler = (file: any) => {
const index = graPicList.value.findIndex((item: any) => item.url === file.url)
if (index > -1) {
graPicList.value.splice(index, 1)
}
form.graPic = ""
dataForm.graPic = ""
}
const remove3Handler = (file: any) => {
const index = yyPicList.value.findIndex((item: any) => item.url === file.url)
if (index > -1) {
yyPicList.value.splice(index, 1)
}
form.yyPic = ""
dataForm.yyPic = ""
}
const remove4Handler = (file: any) => {
const arr: any[] = []
const strArr: string[] = []
houseList.value.forEach((e: any) => {
if (e.url != file.url) {
arr.push(e)
strArr.push(e.url)
}
})
houseList.value = arr
dataForm.housePic = strArr.join(",")
}
const remove5Handler = (file: any) => {
const index = sbPicList.value.findIndex((item: any) => item.url === file.url)
if (index > -1) {
sbPicList.value.splice(index, 1)
}
form.sbPic = ""
dataForm.sbPic = ""
}
const remove6Handler = (file: any) => {
const arr: any[] = []
const strArr: string[] = []
hkPicList.value.forEach((e: any) => {
if (e.url != file.url) {
arr.push(e)
strArr.push(e.url)
}
})
hkPicList.value = arr
dataForm.householdPic = strArr.join(",")
}
// 自定义上传请求
const httpRequest = (options: any) => {
const file = options.file
if (file && fileReader.value) {
fileReader.value.readAsDataURL(file)
fileReader.value.onload = () => {
const base64Str = fileReader.value?.result as string
const config = {
url: '/recruit/file/uploadAttachment',
method: 'post',
data: {
base64Str: base64Str.split(',')[1]
},
timeout: 10000,
onUploadProgress: function (progressEvent: any) {
progressEvent.percent = progressEvent.loaded / progressEvent.total * 100
options.onProgress(progressEvent, file)
},
}
axios(config)
.then((res: any) => {
options.onSuccess(res, file)
})
.catch((err: any) => {
options.onError(err)
})
}
}
}
// 上传成功回调
const uploadSuccess = (res: any, file: any) => {
form.attachment = res.data.fileUrl
if (fileList.value.length > 0) {
fileList.value[0] = { url: form.attachment, name: "" }
} else {
fileList.value.push({ url: form.attachment, name: "" })
}
dataForm.scorePhoto = form.attachment
}
const upload2Success = (res: any, file: any) => {
form.graPic = res.data.fileUrl
if (graPicList.value.length > 0) {
graPicList.value[0] = { url: form.graPic, name: "" }
} else {
graPicList.value.push({ url: form.graPic, name: "" })
}
dataForm.graPic = form.graPic
}
const upload3Success = (res: any, file: any) => {
form.yyPic = res.data.fileUrl
if (yyPicList.value.length > 0) {
yyPicList.value[0] = { url: form.yyPic, name: "" }
} else {
yyPicList.value.push({ url: form.yyPic, name: "" })
}
dataForm.yyPic = form.yyPic
}
const upload4Success = (res: any, file: any) => {
form.housePic = res.data.fileUrl
houseList.value.push({ url: form.housePic })
const arr: string[] = []
houseList.value.forEach((e: any) => {
arr.push(e.url)
})
dataForm.housePic = arr.join(",")
}
const upload5Success = (res: any, file: any) => {
form.sbPic = res.data.fileUrl
if (sbPicList.value.length > 0) {
sbPicList.value[0] = { url: form.sbPic, name: "" }
} else {
sbPicList.value.push({ url: form.sbPic, name: "" })
}
dataForm.sbPic = form.sbPic
}
const upload6Success = (res: any, file: any) => {
form.hkPic = res.data.fileUrl
hkPicList.value.push({ url: form.hkPic })
const arr: string[] = []
hkPicList.value.forEach((e: any) => {
arr.push(e.url)
})
dataForm.householdPic = arr.join(",")
}
// 初始化数据
const initData = () => {
list().then((data: any) => {
planList.value = data.data
})
// 联系人(教职工)
queryAllTeacher().then((res: any) => {
contactNameList.value = res.data
})
}
// 表单提交
const dataFormSubmit = (submitType: string) => {
if (dataForm.zlshRemark == '' && submitType == '3') {
ElNotification.error({
title: '错误',
message: '请填写驳回理由'
})
return
}
dataForm.zlsh = submitType
canSubmit.value = false
updateInfo(dataForm).then(() => {
ElNotification.success({
title: '成功',
message: '操作成功'
})
visible.value = false
emit('refreshDataList')
}).catch(() => {
canSubmit.value = true
})
}
// 初始化方法
const init = (id: string | null) => {
dataForm.id = id || ""
visible.value = true
canSubmit.value = true
initData()
nextTick(() => {
dataFormRef.value?.resetFields()
if (dataForm.id) {
getObj(dataForm.id).then((response: any) => {
fileList.value = []
graPicList.value = []
yyPicList.value = []
houseList.value = []
sbPicList.value = []
hkPicList.value = []
Object.assign(dataForm, response.data)
title.value = dataForm.serialNumber
if (dataForm.scorePhoto != '') {
fileList.value.push({ url: dataForm.scorePhoto, name: "" })
}
if (dataForm.graPic != '') {
graPicList.value.push({ url: dataForm.graPic, name: "" })
}
if (dataForm.yyPic != '') {
yyPicList.value.push({ url: dataForm.yyPic, name: "" })
}
if (dataForm.housePic != '') {
const arr = dataForm.housePic.split(",")
arr.forEach((e: string) => {
houseList.value.push({ url: e })
})
}
if (dataForm.sbPic != '') {
sbPicList.value.push({ url: dataForm.sbPic, name: "" })
}
if (dataForm.householdPic != '') {
const arr2 = dataForm.householdPic.split(",")
arr2.forEach((e: string) => {
hkPicList.value.push({ url: e })
})
}
if ("1" == String(dataForm.degreeOfEducation)) {
title.value = "C" + title.value
} else if ("2" == String(dataForm.degreeOfEducation)) {
title.value = "G" + title.value
} else if ("3" == String(dataForm.degreeOfEducation)) {
title.value = "J" + title.value
}
contactNameflag.value = false
if ("-20" == String(dataForm.auditStatus)) {
title.value = "未录取 " + title.value
} else if ("0" == String(dataForm.auditStatus)) {
title.value = "待审核 " + title.value
} else if ("20" == String(dataForm.auditStatus)) {
title.value = "已录取 " + title.value
contactNameflag.value = true
}
})
}
})
}
// 暴露方法给父组件
defineExpose({
init
})
</script>
<style scoped>
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,308 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4" 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 type="primary" plain 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="异动类型" align="center" show-overflow-tooltip>
<template #default="scope">
{{ getTypeLabel(scope.row.type) }}
</template>
</el-table-column>
<el-table-column prop="name" label="姓名[唯一号]" align="center" show-overflow-tooltip />
<el-table-column prop="majorChangeInfo" label="专业变更情况" align="center" show-overflow-tooltip />
<el-table-column label="学费变更情况" align="center">
<el-table-column prop="dbName" label="费用类型" align="center" show-overflow-tooltip />
<el-table-column prop="dbOldValue" label="原费用" align="center" show-overflow-tooltip />
<el-table-column prop="dbNewValue" label="新费用" align="center" show-overflow-tooltip />
<el-table-column prop="dbType" label="变更类型" align="center" show-overflow-tooltip />
<el-table-column prop="dbChangeValue" label="变更金额" align="center" show-overflow-tooltip />
</el-table-column>
<el-table-column label="分数变更情况" align="center">
<el-table-column prop="scoreName" label="分数类型" align="center" show-overflow-tooltip />
<el-table-column prop="scoreOldValue" label="原分值" align="center" show-overflow-tooltip />
<el-table-column prop="scoreNewValue" label="新分值" align="center" show-overflow-tooltip />
</el-table-column>
<el-table-column prop="createBy" label="异动发起人" align="center" show-overflow-tooltip />
<el-table-column prop="createDate" label="异动时间" align="center" show-overflow-tooltip />
<el-table-column prop="remarks" label="备注信息" align="center" show-overflow-tooltip />
<el-table-column prop="isMajorChange" label="异动审核" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.isMajorChange == '0'" style="color: green">{{ getMajor(scope.row.isMajorChange) }}</span>
<span v-if="scope.row.isMajorChange != '0'" style="color: red">{{ getMajor(scope.row.isMajorChange) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentsignupturnover_edit && 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="异动审核">
<el-form :model="exarmForm" ref="exarmFormRef" label-width="80px" :rules="dataRule">
<el-form-item label="审核结果" prop="isMajorChange">
<el-select v-model="exarmForm.isMajorChange" filterable clearable placeholder="请选择审核结果" style="width: 100%">
<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, defineAsyncComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { fetchList, putObj } from '/@/api/recruit/recruitstudentsignupturnover'
import { list } from '/@/api/recruit/recruitstudentplangroup'
// 使用 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 tableRef = ref()
const searchFormRef = ref()
const exarmFormRef = ref()
// 弹窗状态
const majorChangeVisible = ref(false)
// 数据
const planList = ref<any[]>([])
const typeList = ref([{ label: '专业变更', value: '1' }, { label: '退学', value: '2' }])
const isMajorChangeList = ref([{ label: '通过', value: '3' }, { label: '驳回', value: '2' }])
const majorChangeList = ref([{ label: '通过', value: '3' }, { label: '驳回', value: '2' }, { label: '待审核', value: '1' }])
// 查询表单
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(item => item.value === type)
return item ? item.label : ''
}
// 获取审核状态
const getMajor = (type: string) => {
if (type == '1') {
return '待审核'
} else if (type == '2') {
return '驳回'
} else if (type == '3') {
return '已通过'
}
return ''
}
// 表格状态
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 list()
planList.value = data.data || []
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
} catch (error) {
console.error('初始化失败', 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: any) {
message.error(error.msg || '审核失败')
}
}
// 重置查询
const resetQuery = () => {
searchFormRef.value?.resetFields()
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
if (planList.value.length > 0) {
queryForm.groupId = planList.value[0].id
}
getDataList()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,160 @@
<!--
- 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="execution">
<basic-container>
<avue-crud ref="crud"
:page="page"
:data="tableData"
:table-loading="tableLoading"
:option="tableOption"
@on-load="getList"
@search-change="handleFilter"
@refresh-change="refreshChange"
@row-update="handleUpdate"
@row-save="handleSave"
@row-del="rowDel">
</avue-crud>
</basic-container>
</div>
</template>
<script>
import {addObj, delObj, fetchList, putObj} from '@/api/recruit/recruitstudentsignupturnover'
import {tableOption} from '@/const/crud/recruit/recruitstudentsignupturnover'
import {mapGetters} from 'vuex'
export default {
name: 'recruitstudentsignupturnover',
data() {
return {
tableData: [],
page: {
total: 0, // 总页数
currentPage: 1, // 当前页数
pageSize: 10 // 每页显示多少条
},
tableLoading: false,
tableOption: tableOption,
params:{}
}
},
created() {
},
mounted: function() { },
computed: {
...mapGetters(['permissions'])
},
methods: {
getList(page) {
this.tableLoading = true
fetchList(Object.assign({
current: page.currentPage,
size: page.pageSize
}, this.params)).then(response => {
this.tableData = response.data.records
this.page.total = response.data.total
this.tableLoading = false
})
},
/**
* @title 打开新增窗口
* @detail 调用crud的handleadd方法即可
*
**/
handleAdd: function() {
this.$refs.crud.rowAdd()
},
handleEdit(row, index) {
this.$refs.crud.rowEdit(row, index)
},
handleDel(row, index) {
this.$refs.crud.rowDel(row, index)
},
rowDel: function(row, index) {
var _this = this
this.$confirm('是否确认删除ID为' + row.id, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(function() {
return delObj(row.id)
}).then(data => {
_this.tableData.splice(index, 1)
_this.$message({
showClose: true,
message: '删除成功',
type: 'success'
})
this.getList(this.page)
}).catch(function(err) { })
},
/**
* @title 数据更新
* @param row 为当前的数据
* @param index 为当前更新数据的行数
* @param done 为表单关闭函数
*
**/
handleUpdate: function(row, index, done) {
putObj(row).then(data => {
this.tableData.splice(index, 1, Object.assign({}, row))
this.$message({
showClose: true,
message: '修改成功',
type: 'success'
})
done()
this.getList(this.page)
})
},
/**
* @title 数据添加
* @param row 为当前的数据
* @param done 为表单关闭函数
*
**/
handleSave: function(row, done) {
addObj(row).then(data => {
this.tableData.push(Object.assign({}, row))
this.$message({
showClose: true,
message: '添加成功',
type: 'success'
})
done()
this.getList(this.page)
})
},
/**
* 刷新回调
*/
refreshChange() {
this.getList(this.page)
},
handleFilter(param){
this.params = param;
this.page.currentPage = 1;
this.getList(this.page);
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,288 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<!-- 搜索表单 -->
<el-form :model="queryForm" inline class="mb-4">
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
<el-button type="primary" plain icon="Refresh" class="ml10" @click="resetQuery">重置</el-button>
</el-form-item>
<el-form-item v-if="permissions.recruit_recruitstudentsignupturnovermoneychange_add">
<el-button type="primary" icon="FolderAdd" class="ml10" @click="handleAdd">新增</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="turnOverId" label="异动ID" align="center" show-overflow-tooltip />
<el-table-column prop="type" label="退补类型 1学费 2代办费 3捐资费" align="center" show-overflow-tooltip />
<el-table-column prop="oldFee" label="原费用" align="center" show-overflow-tooltip />
<el-table-column prop="newFee" label="变更后费用" align="center" show-overflow-tooltip />
<el-table-column prop="fee" label="变更费用" align="center" show-overflow-tooltip />
<el-table-column prop="incOrDec" label="补还是退 1补 2退" align="center" show-overflow-tooltip />
<el-table-column prop="pushed" label="是否推送,预留字段,单项推送则需要该字段" align="center" show-overflow-tooltip />
<el-table-column prop="pushFailReason" label="推送失败原因" align="center" show-overflow-tooltip />
<el-table-column prop="createBy" label="创建者" align="center" show-overflow-tooltip />
<el-table-column prop="createDate" label="创建时间" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="scope">
<el-button
v-if="permissions.recruit_recruitstudentsignupturnovermoneychange_edit"
type="primary"
link
icon="EditPen"
@click="handleEdit(scope.row)"
>
编辑
</el-button>
<el-button
v-if="permissions.recruit_recruitstudentsignupturnovermoneychange_del"
type="danger"
link
icon="Delete"
@click="handleDel(scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-bind="state.pagination"
@current-change="currentChangeHandle"
@size-change="sizeChangeHandle"
/>
<!-- 新增/编辑弹窗 -->
<el-dialog
v-model="dialogVisible"
:title="form.id ? '编辑' : '新增'"
width="600px"
:close-on-click-modal="false"
destroy-on-close
>
<el-form
ref="formRef"
:model="form"
:rules="formRules"
label-width="200px"
>
<el-form-item label="异动ID" prop="turnOverId">
<el-input v-model="form.turnOverId" placeholder="请输入异动ID" clearable />
</el-form-item>
<el-form-item label="退补类型" prop="type">
<el-select v-model="form.type" placeholder="请选择退补类型" clearable style="width: 100%">
<el-option label="学费" value="1" />
<el-option label="代办费" value="2" />
<el-option label="捐资费" value="3" />
</el-select>
</el-form-item>
<el-form-item label="原费用" prop="oldFee">
<el-input-number v-model="form.oldFee" :min="0" :precision="2" placeholder="请输入原费用" style="width: 100%" />
</el-form-item>
<el-form-item label="变更后费用" prop="newFee">
<el-input-number v-model="form.newFee" :min="0" :precision="2" placeholder="请输入变更后费用" style="width: 100%" />
</el-form-item>
<el-form-item label="变更费用" prop="fee">
<el-input-number v-model="form.fee" :precision="2" placeholder="请输入变更费用" style="width: 100%" />
</el-form-item>
<el-form-item label="补还是退" prop="incOrDec">
<el-select v-model="form.incOrDec" placeholder="请选择补还是退" clearable style="width: 100%">
<el-option label="补" value="1" />
<el-option label="退" value="2" />
</el-select>
</el-form-item>
<el-form-item label="是否推送" prop="pushed">
<el-select v-model="form.pushed" placeholder="请选择是否推送" clearable style="width: 100%">
<el-option label="是" value="1" />
<el-option label="否" value="0" />
</el-select>
</el-form-item>
<el-form-item label="推送失败原因" prop="pushFailReason">
<el-input v-model="form.pushFailReason" type="textarea" :rows="3" placeholder="请输入推送失败原因" clearable />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts" name="recruitstudentsignupturnovermoneychange">
import { ref, reactive, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useUserInfo } from '/@/stores/userInfo'
import { BasicTableProps, useTable } from '/@/hooks/table'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { addObj, delObj, fetchList, putObj } from '/@/api/recruit/recruitstudentsignupturnovermoneychange'
// 使用 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 tableRef = ref()
const formRef = ref()
// 弹窗状态
const dialogVisible = ref(false)
const submitLoading = ref(false)
// 查询表单
const queryForm = reactive({})
// 表单数据
const form = reactive({
id: '',
turnOverId: '',
type: '',
oldFee: undefined,
newFee: undefined,
fee: undefined,
incOrDec: '',
pushed: '',
pushFailReason: ''
})
// 表单验证规则
const formRules = {}
// 表格状态
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
}
}
}
})
// 使用 table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state)
// 重置查询
const resetQuery = () => {
Object.keys(queryForm).forEach(key => {
queryForm[key] = ''
})
getDataList()
}
// 新增
const handleAdd = () => {
Object.keys(form).forEach(key => {
if (key === 'id') {
form[key] = ''
} else if (typeof form[key] === 'number') {
form[key] = undefined
} else {
form[key] = ''
}
})
dialogVisible.value = true
}
// 编辑
const handleEdit = async (row: any) => {
Object.keys(form).forEach(key => {
form[key] = row[key]
})
dialogVisible.value = true
}
// 删除
const handleDel = async (row: any) => {
try {
await messageBox.confirm(`是否确认删除ID为${row.id}的记录?`)
await delObj(row.id)
message.success('删除成功')
getDataList()
} catch {
// 用户取消
}
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid: boolean) => {
if (valid) {
submitLoading.value = true
try {
if (form.id) {
await putObj(form)
message.success('修改成功')
} else {
await addObj(form)
message.success('添加成功')
}
dialogVisible.value = false
getDataList()
} catch (error: any) {
message.error(error.msg || '操作失败')
} finally {
submitLoading.value = false
}
}
})
}
onMounted(() => {
getDataList()
})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,30 @@
<!--
- 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="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<iframe style="width:100%;height:700px;" src="https://zhxy.czjsy.com/2023zzzc.pdf"></iframe>
</div>
</div>
</template>
<script setup lang="ts" name="zizhu">
</script>
<style scoped lang="scss">
</style>