This commit is contained in:
zhoutianchi
2026-01-14 10:52:06 +08:00
parent 8c1f4ec05e
commit d0c8ea0223
140 changed files with 16969 additions and 11469 deletions

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.data.records,
total: response.data.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.data || []
} catch (error) {
console.error('获取入学年份失败', error)
}
}
// 查找所有二级学院
const getDeptData = async () => {
try {
const data = await getDeptList()
deptList.value = data.data.data || []
} catch (error) {
console.error('获取学院列表失败', error)
}
}
// 查找所有班级
const getClassData = async () => {
try {
const data = await getClasslist()
classData.value = data.data.data || []
} catch (error) {
console.error('获取班级列表失败', error)
}
}
// 获取数据列表
const getList = async () => {
try {
tableLoading.value = true
const response = await getDataStatistics(queryForm)
tableData.value = response.data.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,280 @@
<template>
<div>
<el-dialog :visible.sync="newStuCheckInDialog" width="40%">
<el-form :model="form" :rules="rules" ref="form" 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 placeholder="请选择房间号" :remote-method="remoteMethod" style=" width: 80% ">-->
<el-select
v-model="form.roomNo"
filterable
remote
placeholder="请选择宿舍号"
:remote-method="remoteMethod"
@change="change"
: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% ">
<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('form')" v-loading="submitLoading">确定</el-button>
<el-button @click="newStuCheckInDialog = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import {getDataByRoomNo} from "/@/api/stuwork/dormroom";
import {fearchRoomStuNum} from "/@/api/stuwork/dormroomstudent";
import {getDictByType} from "/@/api/contract/contract";
import {putObj} from '@/api/recruit/newstucheckin'
export default {
name: "stu-check-in",
data() {
return {
page:{},
newStuCheckInDialog:false,
bedNoData:[],
roomNoList:[],
checkInStatusData:[],
loading:false,
isRoomTab:false,
yesOrNoData:[{label:'否', value:'0'},{label:'是', value:'1'}],
genderData:[{label:'女', value:'2'},{label:'男', value:'1'}],
submitLoading:false,
form:{
name:"",
checkInStatus:"",
gender:"",
idNumber:"",
isRoom:"",
roomNo:"",
bedNo:"",
remarks:"",
residenceDetail:"",
parentName:"",
parentTelOne:"",
parentTelTwo:""
},
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':{
handler(newVal){
if(newVal==='1'){
this.isRoomTab = true
}else {
this.isRoomTab = false
}
},
},
'form.roomNo':{
handler(newVal){
console.log(newVal)
if (newVal){
this.fearchRoomStuNums(newVal)
}
}
},
'form.isRoom':{
handler(newVal){
if (newVal === '0'){
this.form.roomNo = ''
this.form.bedNo = ''
}
}
}
},
methods:{
initForm(){
this.form.name = ""
this.form.checkInStatus = ""
this.form.gender = ""
this.form.idNumber = ""
this.form.isRoom = ""
this.form.roomNo = ""
this.form.bedNo = ""
this.form.remarks = ""
this.form.residenceDetail="";
this.form.parentName="";
this.form.parentTelOne="";
this.form.parentTelTwo="";
},
init(formData,page){
this.initForm();
this.page = page
this.submitLoading = false
this.newStuCheckInDialog = true
Object.assign(this.form,formData)
if(formData.roomNo){
this.remoteMethod(formData.roomNo);
this.fearchRoomStuNums(formData.bedNo);
}
getDictByType('check_in_status').then(data=>{
this.checkInStatusData = data.data.data
})
console.log("OKKK")
},
checkIn(form) {
let _that = this
_that.submitLoading = true;
_that.$refs[form].validate((valid) => {
if (valid) {
// console.log("form",this.form)
// _that.formLoading = true
putObj(this.form).then(data => {
this.$message({
showClose: true,
message: '报到成功',
type: 'success'
})
_that.$emit("reload",this.page);
_that.newStuCheckInDialog = false
_that.submitLoading = false
})
// _that.formLoading = false
}else {
return false
}
})
},
//实时检索宿舍号
remoteMethod(query) {
if (query != '' && query.length>=3) {
let data = {'roomNo':query}
this.loading = true
let _this = this
getDataByRoomNo(data).then(data=>{
_this.roomNoList = data.data.data;
console.log("this.roomNoList")
console.log(_this.roomNoList)
_this.loading = false
})
}
},
//查询此房间为几人间
fearchRoomStuNums(roomNo){
var data = {"roomNo":roomNo}
fearchRoomStuNum(data).then(data =>{
this.bedNoData = data.data.data;
})
},
isRoomDisable(notBedNo){
if(undefined != notBedNo && "" != notBedNo){
return true
}else {
return false
}
},
change(){
this.form.bedNo='';
this.$forceUpdate()
}
}
}
</script>
<style scoped>
</style>