|
@@ -106,7 +106,7 @@
|
|
|
>修改</el-button
|
|
>修改</el-button
|
|
|
>
|
|
>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
- <el-col :span="1.5">
|
|
|
|
|
|
|
+ <!-- <el-col :span="1.5">
|
|
|
<el-button
|
|
<el-button
|
|
|
type="danger"
|
|
type="danger"
|
|
|
plain
|
|
plain
|
|
@@ -116,7 +116,7 @@
|
|
|
v-hasPermi="['dormViolation:dormViolation:remove']"
|
|
v-hasPermi="['dormViolation:dormViolation:remove']"
|
|
|
>删除</el-button
|
|
>删除</el-button
|
|
|
>
|
|
>
|
|
|
- </el-col>
|
|
|
|
|
|
|
+ </el-col> -->
|
|
|
<el-col :span="1.5">
|
|
<el-col :span="1.5">
|
|
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['dormViolation:dormViolation:export']">导出</el-button>
|
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['dormViolation:dormViolation:export']">导出</el-button>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -126,47 +126,47 @@
|
|
|
|
|
|
|
|
<el-table v-loading="loading" border :data="dormViolationList" @selection-change="handleSelectionChange">
|
|
<el-table v-loading="loading" border :data="dormViolationList" @selection-change="handleSelectionChange">
|
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
|
- <el-table-column label="违纪记录ID" align="center" prop="id" v-if="true" />
|
|
|
|
|
- <el-table-column label="学生ID" align="center" prop="studentId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="违纪记录ID" align="center" prop="id" v-if="true" />
|
|
|
|
|
+ <el-table-column label="学生ID" align="center" prop="studentId" /> -->
|
|
|
<el-table-column label="学生姓名" align="center" prop="studentName" />
|
|
<el-table-column label="学生姓名" align="center" prop="studentName" />
|
|
|
<el-table-column label="学号" align="center" prop="studentNo" />
|
|
<el-table-column label="学号" align="center" prop="studentNo" />
|
|
|
- <el-table-column label="学院ID" align="center" prop="collegeId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="学院ID" align="center" prop="collegeId" /> -->
|
|
|
<el-table-column label="学院名称" align="center" prop="collegeName" />
|
|
<el-table-column label="学院名称" align="center" prop="collegeName" />
|
|
|
- <el-table-column label="专业ID" align="center" prop="majorId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="专业ID" align="center" prop="majorId" /> -->
|
|
|
<el-table-column label="专业名称" align="center" prop="majorName" />
|
|
<el-table-column label="专业名称" align="center" prop="majorName" />
|
|
|
- <el-table-column label="班级ID" align="center" prop="classId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="班级ID" align="center" prop="classId" /> -->
|
|
|
<el-table-column label="班级名称" align="center" prop="className" />
|
|
<el-table-column label="班级名称" align="center" prop="className" />
|
|
|
- <el-table-column label="校区ID" align="center" prop="campusId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="校区ID" align="center" prop="campusId" /> -->
|
|
|
<el-table-column label="校区名称" align="center" prop="campusName" />
|
|
<el-table-column label="校区名称" align="center" prop="campusName" />
|
|
|
- <el-table-column label="宿舍区域ID" align="center" prop="areaId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="宿舍区域ID" align="center" prop="areaId" /> -->
|
|
|
<el-table-column label="宿舍区域名称" align="center" prop="areaName" />
|
|
<el-table-column label="宿舍区域名称" align="center" prop="areaName" />
|
|
|
- <el-table-column label="宿舍楼ID" align="center" prop="buildingId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="宿舍楼ID" align="center" prop="buildingId" /> -->
|
|
|
<el-table-column label="宿舍楼名称" align="center" prop="buildingName" />
|
|
<el-table-column label="宿舍楼名称" align="center" prop="buildingName" />
|
|
|
- <el-table-column label="宿舍房间ID" align="center" prop="roomId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="宿舍房间ID" align="center" prop="roomId" /> -->
|
|
|
<el-table-column label="房间名称" align="center" prop="roomName" />
|
|
<el-table-column label="房间名称" align="center" prop="roomName" />
|
|
|
- <el-table-column label="床位ID" align="center" prop="bedId" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="床位ID" align="center" prop="bedId" /> -->
|
|
|
<el-table-column label="床位名称" align="center" prop="bedName" />
|
|
<el-table-column label="床位名称" align="center" prop="bedName" />
|
|
|
<el-table-column label="违纪类型" align="center" prop="violationType">
|
|
<el-table-column label="违纪类型" align="center" prop="violationType">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<dict-tag :options="dorm_violation_type" :value="scope.row.violationType" />
|
|
<dict-tag :options="dorm_violation_type" :value="scope.row.violationType" />
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column label="违纪等级:1轻微 2一般 3严重 4特别严重" align="center" prop="violationLevel">
|
|
|
|
|
|
|
+ <el-table-column label="违纪等级" align="center" prop="violationLevel">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<dict-tag :options="dorm_violation_level" :value="scope.row.violationLevel" />
|
|
<dict-tag :options="dorm_violation_level" :value="scope.row.violationLevel" />
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
<el-table-column label="违纪发生时间" align="center" prop="violationTime" width="180">
|
|
<el-table-column label="违纪发生时间" align="center" prop="violationTime" width="180">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
- <span>{{ parseTime(scope.row.violationTime, '{y}-{m}-{d}') }}</span>
|
|
|
|
|
|
|
+ <span>{{ parseTime(scope.row.violationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
<el-table-column label="违纪行为描述" align="center" prop="violationDescription" />
|
|
<el-table-column label="违纪行为描述" align="center" prop="violationDescription" />
|
|
|
- <el-table-column label="涉及其他学生id" align="center" prop="involvedStudents" />
|
|
|
|
|
- <el-table-column label="附件OSS ID列表" align="center" prop="attachmentOssIds" />
|
|
|
|
|
- <el-table-column label="删除标志" align="center" prop="deleted" />
|
|
|
|
|
|
|
+ <!-- <el-table-column label="涉及其他学生id" align="center" prop="involvedStudents" /> -->
|
|
|
|
|
+ <!-- <el-table-column label="附件OSS ID列表" align="center" prop="attachmentOssIds" /> -->
|
|
|
|
|
+ <!-- <el-table-column label="删除标志" align="center" prop="deleted" /> -->
|
|
|
<el-table-column label="备注" align="center" prop="remark" />
|
|
<el-table-column label="备注" align="center" prop="remark" />
|
|
|
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
|
|
|
|
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="120">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
<el-tooltip content="修改" placement="top">
|
|
<el-tooltip content="修改" placement="top">
|
|
|
<el-button
|
|
<el-button
|
|
@@ -180,7 +180,7 @@
|
|
|
<el-tooltip content="删除" placement="top">
|
|
<el-tooltip content="删除" placement="top">
|
|
|
<el-button
|
|
<el-button
|
|
|
link
|
|
link
|
|
|
- type="primary"
|
|
|
|
|
|
|
+ type="danger"
|
|
|
icon="Delete"
|
|
icon="Delete"
|
|
|
@click="handleDelete(scope.row)"
|
|
@click="handleDelete(scope.row)"
|
|
|
v-hasPermi="['dormViolation:dormViolation:remove']"
|
|
v-hasPermi="['dormViolation:dormViolation:remove']"
|
|
@@ -377,13 +377,89 @@
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <el-form-item label="涉及其他学生" prop="involvedStudents">
|
|
|
|
|
- <el-input v-model="form.involvedStudents" placeholder="请输入涉及其他学生ID" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
+ <!-- 涉及其他学生 - 单独一行 -->
|
|
|
|
|
+ <el-form-item label="涉及其他学生" prop="involvedStudents">
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="form.involvedStudents"
|
|
|
|
|
+ placeholder="请选择涉及的其他学生"
|
|
|
|
|
+ filterable
|
|
|
|
|
+ remote
|
|
|
|
|
+ :remote-method="remoteSearchInvolvedStudents"
|
|
|
|
|
+ :loading="involvedStudentLoading"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ multiple
|
|
|
|
|
+ collapse-tags
|
|
|
|
|
+ collapse-tags-tooltip
|
|
|
|
|
+ style="width: 100%"
|
|
|
|
|
+ @visible-change="handleInvolvedStudentSelectVisibleChange"
|
|
|
|
|
+ @change="handleInvolvedStudentsChange"
|
|
|
|
|
+ popper-class="involved-student-select-dropdown"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-option
|
|
|
|
|
+ v-for="student in involvedStudentOptions.filter((s) => s.id !== form.studentId)"
|
|
|
|
|
+ :key="student.id"
|
|
|
|
|
+ :label="`${student.name} (${student.studentNo})`"
|
|
|
|
|
+ :value="student.id"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="student-option">
|
|
|
|
|
+ <div class="student-main">
|
|
|
|
|
+ <span class="student-name">{{ student.name }}</span>
|
|
|
|
|
+ <span class="student-no">{{ student.studentNo }}</span>
|
|
|
|
|
+ <span class="student-gender">{{ student.gender === '0' ? '男' : '女' }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="student-info" v-if="student.collegeName || student.majorName || student.className">
|
|
|
|
|
+ <span v-if="student.collegeName && student.collegeName.trim()" class="info-item">{{ student.collegeName }}</span>
|
|
|
|
|
+ <span v-if="student.majorName && student.majorName.trim()" class="info-item">{{ student.majorName }}</span>
|
|
|
|
|
+ <span v-if="student.className && student.className.trim()" class="info-item">{{ student.className }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ <div class="form-tip">
|
|
|
|
|
+ <el-icon><InfoFilled /></el-icon>
|
|
|
|
|
+ <span>支持多选,可搜索学号或姓名,最多选择10名学生</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 涉及其他学生信息展示表格 -->
|
|
|
|
|
+ <div v-if="selectedInvolvedStudents.length > 0" class="involved-students-table-container">
|
|
|
|
|
+ <div class="table-header">
|
|
|
|
|
+ <span class="table-title">已选择的涉及学生信息</span>
|
|
|
|
|
+ <span class="table-count">(共 {{ selectedInvolvedStudents.length }} 人)</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-table :data="selectedInvolvedStudents" size="small" border stripe class="involved-students-table" max-height="300">
|
|
|
|
|
+ <el-table-column label="序号" type="index" width="50" align="center" />
|
|
|
|
|
+ <el-table-column label="姓名" prop="name" width="120" align="center" />
|
|
|
|
|
+ <el-table-column label="学号" prop="studentNo" width="120" align="center" />
|
|
|
|
|
+ <el-table-column label="性别" prop="gender" width="60" align="center">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-tag :type="scope.row.gender === '0' ? 'primary' : 'danger'" size="small">
|
|
|
|
|
+ {{ scope.row.gender === '0' ? '男' : '女' }}
|
|
|
|
|
+ </el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="学院" prop="collegeName" min-width="120" align="center" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column label="专业" prop="majorName" min-width="120" align="center" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column label="班级" prop="className" min-width="120" align="center" show-overflow-tooltip />
|
|
|
|
|
+ <!-- <el-table-column label="宿舍信息" min-width="150" align="center" show-overflow-tooltip>
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <div v-if="scope.row.dormInfo" class="dorm-info">
|
|
|
|
|
+ <div>{{ scope.row.dormInfo.campusName }}</div>
|
|
|
|
|
+ <div>{{ scope.row.dormInfo.buildingName }} - {{ scope.row.dormInfo.roomName }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span v-else class="no-dorm">暂无宿舍信息</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column> -->
|
|
|
|
|
+ <el-table-column label="操作" width="80" align="center" fixed="right">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-button type="danger" size="small" link @click="removeInvolvedStudent(scope.row.id)"> 移除 </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
<!-- 完整宽度的字段 -->
|
|
<!-- 完整宽度的字段 -->
|
|
|
<el-form-item label="违纪行为描述" prop="violationDescription">
|
|
<el-form-item label="违纪行为描述" prop="violationDescription">
|
|
|
<el-input v-model="form.violationDescription" type="textarea" placeholder="请输入违纪行为描述" :rows="3" />
|
|
<el-input v-model="form.violationDescription" type="textarea" placeholder="请输入违纪行为描述" :rows="3" />
|
|
@@ -483,7 +559,7 @@ import { ref, reactive, toRefs, onMounted, getCurrentInstance, ComponentInternal
|
|
|
import ElMessage from 'element-plus/es/components/message/index';
|
|
import ElMessage from 'element-plus/es/components/message/index';
|
|
|
import ElMessageBox from 'element-plus/es/components/message-box/index';
|
|
import ElMessageBox from 'element-plus/es/components/message-box/index';
|
|
|
import ElLoading from 'element-plus/es/components/loading/index';
|
|
import ElLoading from 'element-plus/es/components/loading/index';
|
|
|
-import { UploadFilled, Document, Loading, Download, Delete } from '@element-plus/icons-vue';
|
|
|
|
|
|
|
+import { UploadFilled, Document, Loading, Download, Delete, InfoFilled } from '@element-plus/icons-vue';
|
|
|
import { getToken } from '@/utils/auth';
|
|
import { getToken } from '@/utils/auth';
|
|
|
import ImagePreview from '@/components/ImagePreview/index.vue';
|
|
import ImagePreview from '@/components/ImagePreview/index.vue';
|
|
|
import request from '@/utils/request';
|
|
import request from '@/utils/request';
|
|
@@ -494,6 +570,7 @@ import {
|
|
|
addDormViolation,
|
|
addDormViolation,
|
|
|
updateDormViolation,
|
|
updateDormViolation,
|
|
|
getStudentOptions,
|
|
getStudentOptions,
|
|
|
|
|
+ getStudentById,
|
|
|
getCampusOptions,
|
|
getCampusOptions,
|
|
|
getAreaOptions,
|
|
getAreaOptions,
|
|
|
getBuildingOptions,
|
|
getBuildingOptions,
|
|
@@ -530,6 +607,76 @@ const studentOptions = ref<StudentOptionVO[]>([]);
|
|
|
const studentLoading = ref(false);
|
|
const studentLoading = ref(false);
|
|
|
const studentSelectVisible = ref(false);
|
|
const studentSelectVisible = ref(false);
|
|
|
|
|
|
|
|
|
|
+// 涉及其他学生选择器相关状态
|
|
|
|
|
+const involvedStudentOptions = ref<StudentOptionVO[]>([]);
|
|
|
|
|
+const involvedStudentLoading = ref(false);
|
|
|
|
|
+const involvedStudentSelectVisible = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+// 存储已选择的涉及学生完整信息
|
|
|
|
|
+const selectedInvolvedStudentsMap = ref<Map<string | number, StudentOptionVO>>(new Map());
|
|
|
|
|
+
|
|
|
|
|
+// 计算属性:获取已选择的涉及学生详细信息
|
|
|
|
|
+const selectedInvolvedStudents = computed(() => {
|
|
|
|
|
+ if (!form.value.involvedStudents || !Array.isArray(form.value.involvedStudents)) {
|
|
|
|
|
+ return [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log('计算涉及学生信息 - 当前ID列表:', form.value.involvedStudents);
|
|
|
|
|
+ console.log('当前Map大小:', selectedInvolvedStudentsMap.value.size);
|
|
|
|
|
+ console.log('当前涉及学生选项数量:', involvedStudentOptions.value.length);
|
|
|
|
|
+
|
|
|
|
|
+ const result = form.value.involvedStudents
|
|
|
|
|
+ .map((id) => {
|
|
|
|
|
+ console.log(`处理学生ID: ${id}`);
|
|
|
|
|
+
|
|
|
|
|
+ // 优先从已保存的完整信息中获取(包括预加载的占位符)
|
|
|
|
|
+ const savedStudent = selectedInvolvedStudentsMap.value.get(id);
|
|
|
|
|
+ if (savedStudent) {
|
|
|
|
|
+ console.log(`从Map中找到学生: ${savedStudent.name}`);
|
|
|
|
|
+ return savedStudent;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从涉及学生选项中查找详细信息
|
|
|
|
|
+ const student = involvedStudentOptions.value.find((s) => s.id === id);
|
|
|
|
|
+ if (student) {
|
|
|
|
|
+ console.log(`从涉及学生选项中找到: ${student.name}`);
|
|
|
|
|
+ // 保存到Map中,避免后续丢失
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(id, student);
|
|
|
|
|
+ return student;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果涉及学生选项中没有,从主学生选项中查找
|
|
|
|
|
+ const mainStudent = studentOptions.value.find((s) => s.id === id);
|
|
|
|
|
+ if (mainStudent) {
|
|
|
|
|
+ console.log(`从主学生选项中找到: ${mainStudent.name}`);
|
|
|
|
|
+ // 保存到Map中,避免后续丢失
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(id, mainStudent);
|
|
|
|
|
+ return mainStudent;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`未找到学生 ${id} 的详细信息,创建临时占位符`);
|
|
|
|
|
+ // 如果都没有找到,创建一个临时的占位符信息
|
|
|
|
|
+ const tempPlaceholder = {
|
|
|
|
|
+ id: id,
|
|
|
|
|
+ name: `学生${id.toString().slice(-4)}`, // 使用ID后4位作为显示名称
|
|
|
|
|
+ studentNo: id.toString(),
|
|
|
|
|
+ gender: '',
|
|
|
|
|
+ collegeName: '信息加载中...',
|
|
|
|
|
+ majorName: '信息加载中...',
|
|
|
|
|
+ className: '信息加载中...',
|
|
|
|
|
+ dormInfo: null
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 将临时占位符也保存到Map中,避免重复创建
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(id, tempPlaceholder);
|
|
|
|
|
+ return tempPlaceholder;
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter((student) => student); // 过滤掉无效数据
|
|
|
|
|
+
|
|
|
|
|
+ console.log('最终涉及学生列表:', result);
|
|
|
|
|
+ return result;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
// 宿舍级联选择器相关状态
|
|
// 宿舍级联选择器相关状态
|
|
|
const campusOptions = ref<CampusOptionVO[]>([]);
|
|
const campusOptions = ref<CampusOptionVO[]>([]);
|
|
|
const areaOptions = ref<AreaOptionVO[]>([]);
|
|
const areaOptions = ref<AreaOptionVO[]>([]);
|
|
@@ -538,6 +685,25 @@ const roomOptions = ref<RoomOptionVO[]>([]);
|
|
|
const bedOptions = ref<BedOptionVO[]>([]);
|
|
const bedOptions = ref<BedOptionVO[]>([]);
|
|
|
const dormLoading = ref(false);
|
|
const dormLoading = ref(false);
|
|
|
|
|
|
|
|
|
|
+// 缓存机制,避免重复请求
|
|
|
|
|
+const dormCache = ref<Map<string, any[]>>(new Map());
|
|
|
|
|
+const cacheExpireTime = 5 * 60 * 1000; // 5分钟缓存过期
|
|
|
|
|
+const cacheTimestamps = ref<Map<string, number>>(new Map());
|
|
|
|
|
+
|
|
|
|
|
+// 缓存工具函数
|
|
|
|
|
+const getCachedData = (key: string) => {
|
|
|
|
|
+ const timestamp = cacheTimestamps.value.get(key);
|
|
|
|
|
+ if (timestamp && Date.now() - timestamp < cacheExpireTime) {
|
|
|
|
|
+ return dormCache.value.get(key);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const setCachedData = (key: string, data: any[]) => {
|
|
|
|
|
+ dormCache.value.set(key, data);
|
|
|
|
|
+ cacheTimestamps.value.set(key, Date.now());
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 附件上传相关状态
|
|
// 附件上传相关状态
|
|
|
const attachmentList = ref<any[]>([]);
|
|
const attachmentList = ref<any[]>([]);
|
|
|
|
|
|
|
@@ -574,7 +740,7 @@ const initFormData: DormViolationForm = {
|
|
|
violationLevel: undefined,
|
|
violationLevel: undefined,
|
|
|
violationTime: undefined,
|
|
violationTime: undefined,
|
|
|
violationDescription: undefined,
|
|
violationDescription: undefined,
|
|
|
- involvedStudents: undefined,
|
|
|
|
|
|
|
+ involvedStudents: [] as (string | number)[], // 初始化为空数组
|
|
|
attachmentOssIds: undefined,
|
|
attachmentOssIds: undefined,
|
|
|
deleted: undefined,
|
|
deleted: undefined,
|
|
|
remark: undefined
|
|
remark: undefined
|
|
@@ -624,7 +790,19 @@ const data = reactive<PageData<DormViolationForm, DormViolationQuery>>({
|
|
|
violationType: [{ required: true, message: '违纪类型不能为空', trigger: 'change' }],
|
|
violationType: [{ required: true, message: '违纪类型不能为空', trigger: 'change' }],
|
|
|
violationLevel: [{ required: true, message: '违纪等级:1轻微 2一般 3严重 4特别严重不能为空', trigger: 'change' }],
|
|
violationLevel: [{ required: true, message: '违纪等级:1轻微 2一般 3严重 4特别严重不能为空', trigger: 'change' }],
|
|
|
violationTime: [{ required: true, message: '违纪发生时间不能为空', trigger: 'blur' }],
|
|
violationTime: [{ required: true, message: '违纪发生时间不能为空', trigger: 'blur' }],
|
|
|
- violationDescription: [{ required: true, message: '违纪行为描述不能为空', trigger: 'blur' }]
|
|
|
|
|
|
|
+ violationDescription: [{ required: true, message: '违纪行为描述不能为空', trigger: 'blur' }],
|
|
|
|
|
+ involvedStudents: [
|
|
|
|
|
+ {
|
|
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
|
|
+ if (Array.isArray(value) && value.length > 10) {
|
|
|
|
|
+ callback(new Error('最多只能选择10名学生'));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ callback();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ trigger: 'change'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -676,6 +854,9 @@ const reset = () => {
|
|
|
|
|
|
|
|
// 清空附件列表
|
|
// 清空附件列表
|
|
|
attachmentList.value = [];
|
|
attachmentList.value = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 清空已选择的涉及学生信息Map
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.clear();
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/** 搜索按钮操作 */
|
|
/** 搜索按钮操作 */
|
|
@@ -706,19 +887,67 @@ const handleAdd = () => {
|
|
|
|
|
|
|
|
/** 修改按钮操作 */
|
|
/** 修改按钮操作 */
|
|
|
const handleUpdate = async (row?: DormViolationVO) => {
|
|
const handleUpdate = async (row?: DormViolationVO) => {
|
|
|
- reset();
|
|
|
|
|
- const _id = row?.id || ids.value[0];
|
|
|
|
|
- const res = await getDormViolation(_id);
|
|
|
|
|
- Object.assign(form.value, res.data);
|
|
|
|
|
|
|
+ // 先显示弹窗,提升用户体验
|
|
|
|
|
+ dialog.visible = true;
|
|
|
|
|
+ dialog.title = '修改宿舍违纪记录';
|
|
|
|
|
|
|
|
- // 根据已有数据级联加载宿舍选项
|
|
|
|
|
- await loadCascadeOptionsForUpdate(form.value);
|
|
|
|
|
|
|
+ // 显示加载状态
|
|
|
|
|
+ const loadingInstance = ElLoading.service({
|
|
|
|
|
+ target: '.el-dialog__body',
|
|
|
|
|
+ text: '正在加载数据...',
|
|
|
|
|
+ background: 'rgba(255, 255, 255, 0.8)'
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- // 处理附件数据
|
|
|
|
|
- await handleAttachmentData();
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ reset();
|
|
|
|
|
+ const _id = row?.id || ids.value[0];
|
|
|
|
|
|
|
|
- dialog.visible = true;
|
|
|
|
|
- dialog.title = '修改宿舍违纪记录';
|
|
|
|
|
|
|
+ // 并行执行数据加载,提升性能
|
|
|
|
|
+ const [violationRes, campusRes] = await Promise.all([
|
|
|
|
|
+ getDormViolation(_id),
|
|
|
|
|
+ getCampusOptions() // 预加载校区选项
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ Object.assign(form.value, violationRes.data);
|
|
|
|
|
+ campusOptions.value = campusRes.rows || [];
|
|
|
|
|
+
|
|
|
|
|
+ console.log('编辑违纪记录,使用原始数据:', violationRes.data);
|
|
|
|
|
+
|
|
|
|
|
+ // 处理涉及其他学生数据 - 将逗号分隔的字符串转换为数组
|
|
|
|
|
+ if (form.value.involvedStudents && typeof form.value.involvedStudents === 'string') {
|
|
|
|
|
+ form.value.involvedStudents = form.value.involvedStudents
|
|
|
|
|
+ .split(',')
|
|
|
|
|
+ .map((id) => id.trim())
|
|
|
|
|
+ .filter((id) => id) as (string | number)[];
|
|
|
|
|
+
|
|
|
|
|
+ console.log('编辑时的涉及学生ID列表:', form.value.involvedStudents);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 并行执行其他数据加载任务
|
|
|
|
|
+ const loadTasks = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有涉及学生,异步加载学生信息
|
|
|
|
|
+ if (form.value.involvedStudents && form.value.involvedStudents.length > 0) {
|
|
|
|
|
+ loadTasks.push(
|
|
|
|
|
+ Promise.all([loadInvolvedStudentsInfo(form.value.involvedStudents), loadInvolvedStudentsForSelect(form.value.involvedStudents)])
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 异步加载宿舍级联选项
|
|
|
|
|
+ loadTasks.push(loadCascadeOptionsForUpdate(form.value));
|
|
|
|
|
+
|
|
|
|
|
+ // 异步处理附件数据
|
|
|
|
|
+ loadTasks.push(handleAttachmentData());
|
|
|
|
|
+
|
|
|
|
|
+ // 等待所有异步任务完成
|
|
|
|
|
+ await Promise.all(loadTasks);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载编辑数据失败:', error);
|
|
|
|
|
+ ElMessage.error('加载数据失败,请重试');
|
|
|
|
|
+ dialog.visible = false;
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loadingInstance.close();
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/** 提交按钮 */
|
|
/** 提交按钮 */
|
|
@@ -733,6 +962,11 @@ const submitForm = () => {
|
|
|
// 将附件ID添加到表单数据中,处理成逗号分隔的字符串
|
|
// 将附件ID添加到表单数据中,处理成逗号分隔的字符串
|
|
|
form.value.attachmentOssIds = attachmentOssIds.join(',');
|
|
form.value.attachmentOssIds = attachmentOssIds.join(',');
|
|
|
|
|
|
|
|
|
|
+ // 处理涉及其他学生数据 - 将数组转换为逗号分隔的字符串
|
|
|
|
|
+ if (Array.isArray(form.value.involvedStudents)) {
|
|
|
|
|
+ form.value.involvedStudents = form.value.involvedStudents.join(',');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (form.value.id) {
|
|
if (form.value.id) {
|
|
|
await updateDormViolation(form.value).finally(() => (buttonLoading.value = false));
|
|
await updateDormViolation(form.value).finally(() => (buttonLoading.value = false));
|
|
|
} else {
|
|
} else {
|
|
@@ -776,7 +1010,8 @@ const remoteSearchStudents = async (query: string) => {
|
|
|
};
|
|
};
|
|
|
const res = await getStudentOptions(params);
|
|
const res = await getStudentOptions(params);
|
|
|
console.log('学生搜索响应:', res);
|
|
console.log('学生搜索响应:', res);
|
|
|
- studentOptions.value = res.rows || [];
|
|
|
|
|
|
|
+ // 修复:正确处理API返回的数据结构
|
|
|
|
|
+ studentOptions.value = res.data?.rows || res.rows || [];
|
|
|
|
|
|
|
|
// 调试:检查第一个学生的数据
|
|
// 调试:检查第一个学生的数据
|
|
|
if (studentOptions.value.length > 0) {
|
|
if (studentOptions.value.length > 0) {
|
|
@@ -818,7 +1053,8 @@ const loadInitialStudents = async () => {
|
|
|
};
|
|
};
|
|
|
const res = await getStudentOptions(params);
|
|
const res = await getStudentOptions(params);
|
|
|
console.log('初始学生数据响应:', res);
|
|
console.log('初始学生数据响应:', res);
|
|
|
- studentOptions.value = res.rows || [];
|
|
|
|
|
|
|
+ // 修复:正确处理API返回的数据结构
|
|
|
|
|
+ studentOptions.value = res.data?.rows || res.rows || [];
|
|
|
|
|
|
|
|
// 调试:检查第一个学生的数据
|
|
// 调试:检查第一个学生的数据
|
|
|
if (studentOptions.value.length > 0) {
|
|
if (studentOptions.value.length > 0) {
|
|
@@ -839,6 +1075,171 @@ const loadInitialStudents = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+/** 远程搜索涉及其他学生 */
|
|
|
|
|
+const remoteSearchInvolvedStudents = async (query: string) => {
|
|
|
|
|
+ involvedStudentLoading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const params: StudentOptionQuery = {
|
|
|
|
|
+ keyword: query.trim(),
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 20
|
|
|
|
|
+ };
|
|
|
|
|
+ const res = await getStudentOptions(params);
|
|
|
|
|
+ console.log('涉及学生搜索响应:', res);
|
|
|
|
|
+ // 修复:正确处理API返回的数据结构
|
|
|
|
|
+ involvedStudentOptions.value = res.data?.rows || res.rows || [];
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('搜索涉及学生失败:', error);
|
|
|
|
|
+ involvedStudentOptions.value = [];
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ involvedStudentLoading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 涉及其他学生选择器可见性变化处理 */
|
|
|
|
|
+const handleInvolvedStudentSelectVisibleChange = async (visible: boolean) => {
|
|
|
|
|
+ involvedStudentSelectVisible.value = visible;
|
|
|
|
|
+
|
|
|
|
|
+ // 当下拉框打开且没有数据时,加载初始数据
|
|
|
|
|
+ if (visible && involvedStudentOptions.value.length === 0) {
|
|
|
|
|
+ await loadInitialInvolvedStudents();
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 加载初始涉及其他学生数据 */
|
|
|
|
|
+const loadInitialInvolvedStudents = async () => {
|
|
|
|
|
+ involvedStudentLoading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const params: StudentOptionQuery = {
|
|
|
|
|
+ keyword: '', // 空关键词获取初始数据
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 20
|
|
|
|
|
+ };
|
|
|
|
|
+ const res = await getStudentOptions(params);
|
|
|
|
|
+ console.log('初始涉及学生数据响应:', res);
|
|
|
|
|
+ // 修复:正确处理API返回的数据结构
|
|
|
|
|
+ involvedStudentOptions.value = res.data?.rows || res.rows || [];
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载初始涉及学生数据失败:', error);
|
|
|
|
|
+ involvedStudentOptions.value = [];
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ involvedStudentLoading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 预加载涉及学生的完整信息 */
|
|
|
|
|
+const loadInvolvedStudentsInfo = async (studentIds: (string | number)[]) => {
|
|
|
|
|
+ // 批量获取学生信息,减少接口调用次数
|
|
|
|
|
+ try {
|
|
|
|
|
+ const studentPromises = studentIds.map(async (studentId) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const studentRes = await getStudentById(studentId);
|
|
|
|
|
+ const studentInfo = studentRes.data;
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(studentId, studentInfo);
|
|
|
|
|
+ console.log(`预加载学生 ${studentId} 信息:`, studentInfo);
|
|
|
|
|
+ return { studentId, success: true, data: studentInfo };
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(`预加载学生 ${studentId} 信息失败:`, error);
|
|
|
|
|
+ // 创建临时占位符
|
|
|
|
|
+ const tempPlaceholder = {
|
|
|
|
|
+ id: studentId,
|
|
|
|
|
+ name: `学生${studentId.toString().slice(-4)}`,
|
|
|
|
|
+ studentNo: studentId.toString(),
|
|
|
|
|
+ gender: '',
|
|
|
|
|
+ collegeName: '信息加载失败',
|
|
|
|
|
+ majorName: '信息加载失败',
|
|
|
|
|
+ className: '信息加载失败',
|
|
|
|
|
+ dormInfo: null
|
|
|
|
|
+ };
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(studentId, tempPlaceholder);
|
|
|
|
|
+ return { studentId, success: false, data: tempPlaceholder };
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 并行执行所有学生信息获取
|
|
|
|
|
+ await Promise.all(studentPromises);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('批量加载涉及学生信息失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 为选择框加载涉及学生信息 */
|
|
|
|
|
+const loadInvolvedStudentsForSelect = async (studentIds: (string | number)[]) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 获取涉及学生的完整信息
|
|
|
|
|
+ const studentsInfo: StudentOptionVO[] = [];
|
|
|
|
|
+
|
|
|
|
|
+ for (const studentId of studentIds) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const studentRes = await getStudentById(studentId);
|
|
|
|
|
+ const studentInfo = studentRes.data;
|
|
|
|
|
+ studentsInfo.push(studentInfo);
|
|
|
|
|
+ console.log(`为选择框加载学生 ${studentId} 信息:`, studentInfo);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(`为选择框加载学生 ${studentId} 信息失败:`, error);
|
|
|
|
|
+ // 创建临时占位符
|
|
|
|
|
+ const tempPlaceholder = {
|
|
|
|
|
+ id: studentId,
|
|
|
|
|
+ name: `学生${studentId.toString().slice(-4)}`,
|
|
|
|
|
+ studentNo: studentId.toString(),
|
|
|
|
|
+ gender: '',
|
|
|
|
|
+ collegeName: '信息加载失败',
|
|
|
|
|
+ majorName: '信息加载失败',
|
|
|
|
|
+ className: '信息加载失败',
|
|
|
|
|
+ dormInfo: null
|
|
|
|
|
+ };
|
|
|
|
|
+ studentsInfo.push(tempPlaceholder);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 将学生信息添加到涉及学生选项中,确保选择框能正确显示
|
|
|
|
|
+ involvedStudentOptions.value = [...studentsInfo];
|
|
|
|
|
+ console.log('涉及学生选择框选项已更新:', involvedStudentOptions.value);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('为选择框加载涉及学生信息失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 涉及其他学生选择变化处理 */
|
|
|
|
|
+const handleInvolvedStudentsChange = (selectedIds: (string | number)[]) => {
|
|
|
|
|
+ // 确保不会选择主学生
|
|
|
|
|
+ if (form.value.studentId && selectedIds.includes(form.value.studentId)) {
|
|
|
|
|
+ ElMessage.warning('不能选择主学生作为涉及其他学生');
|
|
|
|
|
+ // 移除主学生ID
|
|
|
|
|
+ form.value.involvedStudents = selectedIds.filter((id) => id !== form.value.studentId) as (string | number)[];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 直接更新选择的学生列表
|
|
|
|
|
+ form.value.involvedStudents = selectedIds as (string | number)[];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 确保新选择的学生信息被保存
|
|
|
|
|
+ selectedIds.forEach((id) => {
|
|
|
|
|
+ if (!selectedInvolvedStudentsMap.value.has(id)) {
|
|
|
|
|
+ // 从当前选项中查找并保存学生信息
|
|
|
|
|
+ const student = involvedStudentOptions.value.find((s) => s.id === id);
|
|
|
|
|
+ if (student) {
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(id, student);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 从主学生选项中查找
|
|
|
|
|
+ const mainStudent = studentOptions.value.find((s) => s.id === id);
|
|
|
|
|
+ if (mainStudent) {
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.set(id, mainStudent);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 移除涉及学生 */
|
|
|
|
|
+const removeInvolvedStudent = (studentId: string | number) => {
|
|
|
|
|
+ if (Array.isArray(form.value.involvedStudents)) {
|
|
|
|
|
+ form.value.involvedStudents = form.value.involvedStudents.filter((id) => id !== studentId) as (string | number)[];
|
|
|
|
|
+ // 从Map中也移除该学生信息
|
|
|
|
|
+ selectedInvolvedStudentsMap.value.delete(studentId);
|
|
|
|
|
+ ElMessage.success('已移除该学生');
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
/** 学生选择处理 */
|
|
/** 学生选择处理 */
|
|
|
const handleStudentChange = async (studentId: string | number) => {
|
|
const handleStudentChange = async (studentId: string | number) => {
|
|
|
if (!studentId) {
|
|
if (!studentId) {
|
|
@@ -868,6 +1269,11 @@ const handleStudentChange = async (studentId: string | number) => {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 如果主学生ID在涉及其他学生列表中,则移除
|
|
|
|
|
+ if (Array.isArray(form.value.involvedStudents)) {
|
|
|
|
|
+ form.value.involvedStudents = form.value.involvedStudents.filter((id) => id !== studentId) as (string | number)[];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const selectedStudent = studentOptions.value.find((student) => student.id === studentId);
|
|
const selectedStudent = studentOptions.value.find((student) => student.id === studentId);
|
|
|
if (selectedStudent) {
|
|
if (selectedStudent) {
|
|
|
// 填充学生基本信息
|
|
// 填充学生基本信息
|
|
@@ -989,9 +1395,19 @@ const handleCampusChange = async (campusId: string | number) => {
|
|
|
/** 加载宿舍区选项 */
|
|
/** 加载宿舍区选项 */
|
|
|
const loadAreaOptions = async (campusId: string | number) => {
|
|
const loadAreaOptions = async (campusId: string | number) => {
|
|
|
try {
|
|
try {
|
|
|
|
|
+ const cacheKey = `area_${campusId}`;
|
|
|
|
|
+ const cachedData = getCachedData(cacheKey);
|
|
|
|
|
+
|
|
|
|
|
+ if (cachedData) {
|
|
|
|
|
+ areaOptions.value = cachedData;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
dormLoading.value = true;
|
|
dormLoading.value = true;
|
|
|
const res = await getAreaOptions(campusId);
|
|
const res = await getAreaOptions(campusId);
|
|
|
- areaOptions.value = res.rows || [];
|
|
|
|
|
|
|
+ const data = res.rows || [];
|
|
|
|
|
+ areaOptions.value = data;
|
|
|
|
|
+ setCachedData(cacheKey, data);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('加载宿舍区选项失败:', error);
|
|
console.error('加载宿舍区选项失败:', error);
|
|
|
areaOptions.value = [];
|
|
areaOptions.value = [];
|
|
@@ -1141,25 +1557,33 @@ const handleBedChange = (bedId: string | number) => {
|
|
|
/** 修改时级联加载宿舍选项数据 */
|
|
/** 修改时级联加载宿舍选项数据 */
|
|
|
const loadCascadeOptionsForUpdate = async (formData: DormViolationForm) => {
|
|
const loadCascadeOptionsForUpdate = async (formData: DormViolationForm) => {
|
|
|
try {
|
|
try {
|
|
|
|
|
+ // 并行加载所有需要的宿舍选项,提升性能
|
|
|
|
|
+ const loadTasks = [];
|
|
|
|
|
+
|
|
|
// 如果有校区ID,加载宿舍区选项
|
|
// 如果有校区ID,加载宿舍区选项
|
|
|
if (formData.campusId) {
|
|
if (formData.campusId) {
|
|
|
- await loadAreaOptions(formData.campusId);
|
|
|
|
|
|
|
+ loadTasks.push(loadAreaOptions(formData.campusId));
|
|
|
|
|
|
|
|
// 如果有宿舍区ID,加载宿舍楼选项
|
|
// 如果有宿舍区ID,加载宿舍楼选项
|
|
|
if (formData.areaId) {
|
|
if (formData.areaId) {
|
|
|
- await loadBuildingOptions(formData.areaId);
|
|
|
|
|
|
|
+ loadTasks.push(loadBuildingOptions(formData.areaId));
|
|
|
|
|
|
|
|
// 如果有宿舍楼ID,加载房间选项
|
|
// 如果有宿舍楼ID,加载房间选项
|
|
|
if (formData.buildingId) {
|
|
if (formData.buildingId) {
|
|
|
- await loadRoomOptions(formData.buildingId);
|
|
|
|
|
|
|
+ loadTasks.push(loadRoomOptions(formData.buildingId));
|
|
|
|
|
|
|
|
// 如果有房间ID,加载床位选项
|
|
// 如果有房间ID,加载床位选项
|
|
|
if (formData.roomId) {
|
|
if (formData.roomId) {
|
|
|
- await loadBedOptions(formData.roomId);
|
|
|
|
|
|
|
+ loadTasks.push(loadBedOptions(formData.roomId));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 并行执行所有加载任务
|
|
|
|
|
+ if (loadTasks.length > 0) {
|
|
|
|
|
+ await Promise.all(loadTasks);
|
|
|
|
|
+ }
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('修改时级联加载宿舍选项失败:', error);
|
|
console.error('修改时级联加载宿舍选项失败:', error);
|
|
|
}
|
|
}
|
|
@@ -1364,56 +1788,63 @@ const handleDownloadAttachment = async (file: any) => {
|
|
|
// 处理附件数据
|
|
// 处理附件数据
|
|
|
const handleAttachmentData = async () => {
|
|
const handleAttachmentData = async () => {
|
|
|
try {
|
|
try {
|
|
|
- // 如果有附件ID,则获取附件信息
|
|
|
|
|
- if (form.value.attachmentOssIds && form.value.attachmentOssIds.toString().trim()) {
|
|
|
|
|
- console.log('开始处理附件数据:', form.value.attachmentOssIds);
|
|
|
|
|
|
|
+ // 如果没有附件ID,直接返回,避免不必要的请求
|
|
|
|
|
+ if (!form.value.attachmentOssIds || !form.value.attachmentOssIds.toString().trim()) {
|
|
|
|
|
+ console.log('没有附件数据,清空附件列表');
|
|
|
|
|
+ attachmentList.value = [];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 将逗号分隔的字符串转换为数组
|
|
|
|
|
- const ossIdsArray = form.value.attachmentOssIds
|
|
|
|
|
- .toString()
|
|
|
|
|
- .split(',')
|
|
|
|
|
- .map((id) => id.trim())
|
|
|
|
|
- .filter((id) => id);
|
|
|
|
|
|
|
+ console.log('开始处理附件数据:', form.value.attachmentOssIds);
|
|
|
|
|
|
|
|
- // 调用接口获取附件信息
|
|
|
|
|
- const response = await request({
|
|
|
|
|
- url: `/resource/oss/listByIds/${ossIdsArray.join(',')}`,
|
|
|
|
|
- method: 'get'
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ // 将逗号分隔的字符串转换为数组
|
|
|
|
|
+ const ossIdsArray = form.value.attachmentOssIds
|
|
|
|
|
+ .toString()
|
|
|
|
|
+ .split(',')
|
|
|
|
|
+ .map((id) => id.trim())
|
|
|
|
|
+ .filter((id) => id);
|
|
|
|
|
|
|
|
- if (response.code === 200 && response.data) {
|
|
|
|
|
- console.log('获取到的附件信息:', response.data);
|
|
|
|
|
-
|
|
|
|
|
- // 将附件信息转换为上传组件需要的格式
|
|
|
|
|
- const attachmentFiles = response.data.map((item: any, index: number) => ({
|
|
|
|
|
- uid: `existing_${index}_${Date.now()}`,
|
|
|
|
|
- name: item.originalName || `附件${index + 1}`,
|
|
|
|
|
- url: item.url,
|
|
|
|
|
- ossId: item.ossId,
|
|
|
|
|
- status: 'success', // 标记为已上传成功
|
|
|
|
|
- response: {
|
|
|
|
|
- code: 200,
|
|
|
|
|
- data: {
|
|
|
|
|
- url: item.url,
|
|
|
|
|
- ossId: item.ossId
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 如果附件ID数组为空,直接返回
|
|
|
|
|
+ if (ossIdsArray.length === 0) {
|
|
|
|
|
+ attachmentList.value = [];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 调用接口获取附件信息
|
|
|
|
|
+ const response = await request({
|
|
|
|
|
+ url: `/resource/oss/listByIds/${ossIdsArray.join(',')}`,
|
|
|
|
|
+ method: 'get'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (response.code === 200 && response.data) {
|
|
|
|
|
+ console.log('获取到的附件信息:', response.data);
|
|
|
|
|
+
|
|
|
|
|
+ // 将附件信息转换为上传组件需要的格式
|
|
|
|
|
+ const attachmentFiles = response.data.map((item: any, index: number) => ({
|
|
|
|
|
+ uid: `existing_${index}_${Date.now()}`,
|
|
|
|
|
+ name: item.originalName || `附件${index + 1}`,
|
|
|
|
|
+ url: item.url,
|
|
|
|
|
+ ossId: item.ossId,
|
|
|
|
|
+ status: 'success', // 标记为已上传成功
|
|
|
|
|
+ response: {
|
|
|
|
|
+ code: 200,
|
|
|
|
|
+ data: {
|
|
|
|
|
+ url: item.url,
|
|
|
|
|
+ ossId: item.ossId
|
|
|
}
|
|
}
|
|
|
- }));
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ }));
|
|
|
|
|
|
|
|
- // 设置附件列表
|
|
|
|
|
- attachmentList.value = attachmentFiles;
|
|
|
|
|
- console.log('设置附件列表成功:', attachmentList.value);
|
|
|
|
|
- } else {
|
|
|
|
|
- console.warn('获取附件信息失败:', response.msg);
|
|
|
|
|
- attachmentList.value = [];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 设置附件列表
|
|
|
|
|
+ attachmentList.value = attachmentFiles;
|
|
|
|
|
+ console.log('设置附件列表成功:', attachmentList.value);
|
|
|
} else {
|
|
} else {
|
|
|
- console.log('没有附件数据,清空附件列表');
|
|
|
|
|
|
|
+ console.warn('获取附件信息失败:', response.msg);
|
|
|
attachmentList.value = [];
|
|
attachmentList.value = [];
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('处理附件数据失败:', error);
|
|
console.error('处理附件数据失败:', error);
|
|
|
- ElMessage.error('获取附件信息失败,请稍后重试');
|
|
|
|
|
|
|
+ // 不显示错误提示,避免影响用户体验
|
|
|
attachmentList.value = [];
|
|
attachmentList.value = [];
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
@@ -1483,6 +1914,27 @@ onMounted(() => {
|
|
|
padding: 4px 12px !important;
|
|
padding: 4px 12px !important;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+:global(.involved-student-select-dropdown .el-select-dropdown__item) {
|
|
|
|
|
+ height: auto !important;
|
|
|
|
|
+ min-height: 32px !important;
|
|
|
|
|
+ padding: 4px 12px !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 表单提示样式 */
|
|
|
|
|
+.form-tip {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ margin-top: 4px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.form-tip .el-icon {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* 附件上传容器样式 */
|
|
/* 附件上传容器样式 */
|
|
|
.attachment-upload-container {
|
|
.attachment-upload-container {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
@@ -1692,4 +2144,74 @@ onMounted(() => {
|
|
|
cursor: not-allowed;
|
|
cursor: not-allowed;
|
|
|
background: #f5f5f5;
|
|
background: #f5f5f5;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+/* 涉及其他学生表格样式 */
|
|
|
|
|
+.involved-students-table-container {
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ background: #fafafa;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.table-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ padding: 8px 12px;
|
|
|
|
|
+ background: #f5f7fa;
|
|
|
|
|
+ border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.table-title {
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.table-count {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.involved-students-table {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.involved-students-table :deep(.el-table__header) {
|
|
|
|
|
+ background: #f5f7fa;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.involved-students-table :deep(.el-table__header th) {
|
|
|
|
|
+ background: #f5f7fa;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.involved-students-table :deep(.el-table__body td) {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ padding: 6px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dorm-info {
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ line-height: 1.3;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dorm-info div:first-child {
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dorm-info div:last-child {
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ margin-top: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.no-dorm {
|
|
|
|
|
+ color: #c0c4cc;
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ font-style: italic;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|