276 lines
8.7 KiB
Vue
276 lines
8.7 KiB
Vue
|
|
<template>
|
|||
|
|
<!-- 模板部分保持不变 -->
|
|||
|
|
<div class="class-popup">
|
|||
|
|
<popup
|
|||
|
|
ref="popupRef"
|
|||
|
|
:title="popupTitle"
|
|||
|
|
:async="true"
|
|||
|
|
width="800px"
|
|||
|
|
:clickModalClose="true"
|
|||
|
|
@confirm="handleConfirm"
|
|||
|
|
@close="handleClose"
|
|||
|
|
>
|
|||
|
|
<el-card class="!border-none" shadow="never">
|
|||
|
|
<el-form ref="formRef" :model="queryParams" :inline="true">
|
|||
|
|
<el-form-item label="班级代码" prop="classCode">
|
|||
|
|
<el-input v-model="queryParams.classCode" class="w-[200px]" />
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="班级名称" prop="className">
|
|||
|
|
<el-input v-model="queryParams.className" class="w-[200px]" />
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="入学年份" prop="enrollmentYear">
|
|||
|
|
<el-input v-model="queryParams.enrollmentYear" class="w-[200px]" />
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="所属学院" prop="collegeId">
|
|||
|
|
<el-select
|
|||
|
|
v-model="queryParams.collegeId"
|
|||
|
|
class="w-[200px]"
|
|||
|
|
clearable
|
|||
|
|
@change="handleCollegeChange"
|
|||
|
|
>
|
|||
|
|
<el-option
|
|||
|
|
v-for="college in collegeList"
|
|||
|
|
:key="college.id"
|
|||
|
|
:value="college.id"
|
|||
|
|
:label="college.collegeName"
|
|||
|
|
/>
|
|||
|
|
</el-select>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item>
|
|||
|
|
<el-button type="primary" @click="getClassLists">查询</el-button>
|
|||
|
|
<el-button @click="resetQuery">重置</el-button>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
</el-card>
|
|||
|
|
|
|||
|
|
<el-table
|
|||
|
|
ref="tableRef"
|
|||
|
|
:data="pager.lists"
|
|||
|
|
size="small"
|
|||
|
|
v-loading="pager.loading"
|
|||
|
|
@selection-change="handleSelectionChange"
|
|||
|
|
>
|
|||
|
|
<el-table-column type="selection" width="55" />
|
|||
|
|
<el-table-column prop="classCode" label="班级代码" min-width="120" />
|
|||
|
|
<el-table-column prop="className" label="班级名称" min-width="150" />
|
|||
|
|
<el-table-column prop="collegeName" label="所属学院" min-width="150" />
|
|||
|
|
<el-table-column prop="majorName" label="所属专业" min-width="150" />
|
|||
|
|
<el-table-column
|
|||
|
|
prop="studentCount"
|
|||
|
|
label="学生人数"
|
|||
|
|
min-width="100"
|
|||
|
|
:formatter="(row: { studentCount: any; maxStudentCount: any }) => `${row.studentCount}/${row.maxStudentCount}`"
|
|||
|
|
:cell-style="({ row }: { row: { studentCount: any; maxStudentCount: any } }) => {
|
|||
|
|
// 判断:当人数相等时,字体变红
|
|||
|
|
return row.studentCount === row.maxStudentCount
|
|||
|
|
? { color: 'red' }
|
|||
|
|
: {}
|
|||
|
|
}"
|
|||
|
|
/>
|
|||
|
|
</el-table>
|
|||
|
|
|
|||
|
|
<div class="flex justify-end mt-4">
|
|||
|
|
<pagination v-model="pager" @change="getClassLists" />
|
|||
|
|
</div>
|
|||
|
|
</popup>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script lang="ts" setup name="ClassPopup">
|
|||
|
|
import type { PropType } from 'vue'
|
|||
|
|
import { nextTick, reactive, ref, shallowRef, watch } from 'vue'
|
|||
|
|
|
|||
|
|
import { classLists } from '@/api/class'
|
|||
|
|
import { collegeLists } from '@/api/college'
|
|||
|
|
import Popup from '@/components/popup/index.vue'
|
|||
|
|
import { usePaging } from '@/hooks/usePaging'
|
|||
|
|
import feedback from '@/utils/feedback'
|
|||
|
|
|
|||
|
|
// 外部传入的已选择班级ID
|
|||
|
|
const props = defineProps({
|
|||
|
|
selectedIds: {
|
|||
|
|
type: Array as PropType<number[]>,
|
|||
|
|
default: () => []
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 向父组件传递事件
|
|||
|
|
const emit = defineEmits(['success', 'close'])
|
|||
|
|
|
|||
|
|
// 弹窗相关
|
|||
|
|
const popupRef = shallowRef<InstanceType<typeof Popup>>()
|
|||
|
|
const popupTitle = ref('选择班级') // 统一弹窗标题
|
|||
|
|
|
|||
|
|
// 表格引用
|
|||
|
|
const tableRef = shallowRef<any>(null)
|
|||
|
|
|
|||
|
|
// 查询参数
|
|||
|
|
const queryParams = reactive({
|
|||
|
|
classCode: '',
|
|||
|
|
className: '',
|
|||
|
|
collegeId: '',
|
|||
|
|
enrollmentYear: '',
|
|||
|
|
maxStudentCount: '',
|
|||
|
|
majorId: ''
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 学院列表
|
|||
|
|
const collegeList = ref<any[]>([])
|
|||
|
|
|
|||
|
|
// 存储与父组件交互的选中班级ID(外部数据)
|
|||
|
|
const allSelectedId = ref<number[]>([])
|
|||
|
|
// 存储组件内部使用的选中班级ID(内部状态)
|
|||
|
|
const allSelectedIds = ref<number[]>([])
|
|||
|
|
|
|||
|
|
// 分页配置
|
|||
|
|
const { pager, getLists: getClassLists } = usePaging({
|
|||
|
|
fetchFun: classLists,
|
|||
|
|
params: queryParams
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 加载学院列表
|
|||
|
|
const fetchColleges = async () => {
|
|||
|
|
try {
|
|||
|
|
const res = await collegeLists()
|
|||
|
|
collegeList.value = res.lists
|
|||
|
|
} catch (err) {
|
|||
|
|
feedback.msgError('获取学院列表失败')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 学院变更时重新加载专业
|
|||
|
|
const handleCollegeChange = async () => {
|
|||
|
|
getClassLists()
|
|||
|
|
// 实际项目中可能需要加载对应学院的专业
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理选择变化 - 只修改内部状态
|
|||
|
|
const handleSelectionChange = (rows: any[]) => {
|
|||
|
|
const currentPageSelectedIds = rows.map((row) => row.id)
|
|||
|
|
const currentPageIds = pager.lists.map((row) => row.id)
|
|||
|
|
// 移除当前页中取消选中的ID
|
|||
|
|
currentPageIds.forEach((id) => {
|
|||
|
|
if (!currentPageSelectedIds.includes(id)) {
|
|||
|
|
const index = allSelectedIds.value.indexOf(id)
|
|||
|
|
if (index > -1) {
|
|||
|
|
allSelectedIds.value.splice(index, 1)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
// 添加当前页中新选中的ID
|
|||
|
|
currentPageSelectedIds.forEach((id) => {
|
|||
|
|
if (!allSelectedIds.value.includes(id)) {
|
|||
|
|
allSelectedIds.value.push(id)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重置查询
|
|||
|
|
const resetQuery = () => {
|
|||
|
|
Object.keys(queryParams).forEach((key) => {
|
|||
|
|
queryParams[key as keyof typeof queryParams] = ''
|
|||
|
|
})
|
|||
|
|
getClassLists()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开弹窗时初始化选中状态
|
|||
|
|
const initSelection = async () => {
|
|||
|
|
await nextTick()
|
|||
|
|
if (!tableRef.value || !pager.lists || pager.lists.length === 0) {
|
|||
|
|
console.warn('表格数据未加载完成')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
try {
|
|||
|
|
// 先清空所有选中状态
|
|||
|
|
tableRef.value.clearSelection()
|
|||
|
|
// 遍历当前页数据,设置选中状态(使用外部状态)
|
|||
|
|
pager.lists.forEach((row: any) => {
|
|||
|
|
if (allSelectedId.value.includes(row.id)) {
|
|||
|
|
nextTick(() => {
|
|||
|
|
tableRef.value?.toggleRowSelection(row, true)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('初始化选中状态失败:', error)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 确认选择 - 同步内部状态到外部数据并传递给父组件
|
|||
|
|
const handleConfirm = async () => {
|
|||
|
|
if (allSelectedIds.value.length === 0) {
|
|||
|
|
return feedback.msgWarning('请选择班级')
|
|||
|
|
}
|
|||
|
|
// 同步内部状态到外部数据
|
|||
|
|
allSelectedId.value = [...allSelectedIds.value]
|
|||
|
|
emit('success', allSelectedId.value)
|
|||
|
|
popupRef.value?.close()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 关闭弹窗 - 不保存修改,保持原有外部数据
|
|||
|
|
const handleClose = () => {
|
|||
|
|
// 关闭时恢复内部状态与外部数据一致
|
|||
|
|
allSelectedIds.value = [...allSelectedId.value]
|
|||
|
|
emit('close')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开弹窗方法 - 从父组件传入值同步到内部状态
|
|||
|
|
const open = async () => {
|
|||
|
|
// 同步父组件传入的值到外部数据
|
|||
|
|
allSelectedId.value = [...props.selectedIds]
|
|||
|
|
// 同步外部数据到内部状态
|
|||
|
|
allSelectedIds.value = [...allSelectedId.value]
|
|||
|
|
try {
|
|||
|
|
await getClassLists()
|
|||
|
|
popupRef.value?.open()
|
|||
|
|
await nextTick()
|
|||
|
|
setTimeout(() => {
|
|||
|
|
initSelection()
|
|||
|
|
}, 100)
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('打开弹窗失败:', error)
|
|||
|
|
}
|
|||
|
|
fetchColleges()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 监听外部选中ID变化
|
|||
|
|
watch(
|
|||
|
|
() => props.selectedIds,
|
|||
|
|
(val) => {
|
|||
|
|
if (!popupRef.value?.visible) {
|
|||
|
|
allSelectedId.value = [...val]
|
|||
|
|
allSelectedIds.value = [...allSelectedId.value]
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
{ deep: true }
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 监听表格数据变化,数据加载完成后自动设置选中状态
|
|||
|
|
watch(
|
|||
|
|
() => pager.lists,
|
|||
|
|
(newLists) => {
|
|||
|
|
if (newLists && newLists.length > 0 && popupRef.value?.visible) {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
initSelection()
|
|||
|
|
}, 100)
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
{ deep: true }
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 监听页码变化
|
|||
|
|
watch(
|
|||
|
|
() => pager.page,
|
|||
|
|
() => {
|
|||
|
|
if (popupRef.value?.visible) {
|
|||
|
|
allSelectedId.value = [...allSelectedIds.value]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 暴露open方法供父组件调用
|
|||
|
|
defineExpose({
|
|||
|
|
open
|
|||
|
|
})
|
|||
|
|
</script>
|