SYN/admin/src/views/organization/assign/class.vue

276 lines
8.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- 模板部分保持不变 -->
<div class="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>