提交代码

This commit is contained in:
zlwu committed 2025-08-14 20:11:57 +08:00
1 parent 3468e1c88a
commit bd5d4e57fc
7 files changed
+214 -5

No files matched your search

@@ -257,4 +257,17 @@ public class XgDormBedStudentController extends BaseController {
@RequestParam(required = false) Long classId) { @RequestParam(required = false) Long classId) {
return toAjax(xgDormBedStudentService.classTeacherRecallSelectedBeds(bedIds, classId)); return toAjax(xgDormBedStudentService.classTeacherRecallSelectedBeds(bedIds, classId));
} }
/**
* 班主任批量退宿
*/
@SaCheckPermission("dormBedStudent:dormBedStudent:edit")
@Log(title = "班主任批量退宿", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/classTeacherStayawaySelectedBeds")
public R<Void> classTeacherStayawaySelectedBeds(@RequestBody List<Long> bedIds,
@RequestParam(required = false) Long classId) {
return toAjax(xgDormBedStudentService.classTeacherStayawaySelectedBeds(bedIds, classId));
}
} }
@@ -183,4 +183,13 @@ public interface IXgDormBedStudentService {
* @return 是否收回成功 * @return 是否收回成功
*/ */
Boolean classTeacherRecallSelectedBeds(List<Long> bedIds, Long classId); Boolean classTeacherRecallSelectedBeds(List<Long> bedIds, Long classId);
/**
* 班主任批量退宿
*
* @param bedIds 床位ID列表
* @param classId 班级ID
* @return 是否退宿成功
*/
Boolean classTeacherStayawaySelectedBeds(List<Long> bedIds, Long classId);
} }
@@ -1806,4 +1806,71 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
throw new RuntimeException("收回选中床位失败:" + e.getMessage()); throw new RuntimeException("收回选中床位失败:" + e.getMessage());
} }
} }
/**
* 班主任退宿床位
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean classTeacherStayawaySelectedBeds(List<Long> bedIds, Long classId) {
if (bedIds == null || bedIds.isEmpty()) {
throw new IllegalArgumentException("床位ID列表不能为空");
}
try {
Long targetClassId = classId != null ? classId : getCurrentUserClassId();
Date now = new Date();
Long loginUserId = LoginHelper.getUserId();
log.info("班主任退宿选中床位,床位IDs: {},classId:{}", bedIds, targetClassId);
// 1. 更新 xg_student_msg 表:根据 ext_field1 = 床位id,deleted = 0,student_status = 1
// 的数据
// 将 dormitory_building、dormitory_room、ext_field1 置空
if (!bedIds.isEmpty()) {
LambdaUpdateWrapper<XgStudentMsg> updateStudentWrapper = Wrappers.lambdaUpdate();
updateStudentWrapper
.in(XgStudentMsg::getExtField1,
bedIds.stream().map(String::valueOf).collect(java.util.stream.Collectors.toList()))
.eq(XgStudentMsg::getDeleted, 0L)
.eq(XgStudentMsg::getStudentStatus, "1")
.set(XgStudentMsg::getDormitoryBuilding, null)
.set(XgStudentMsg::getDormitoryRoom, null)
.set(XgStudentMsg::getExtField1, null)
.set(XgStudentMsg::getUpdateTime, now)
.set(XgStudentMsg::getUpdateBy, loginUserId);
int studentUpdateCount = xgStudentMsgMapper.update(null, updateStudentWrapper);
log.info("更新学生信息表记录数: {}", studentUpdateCount);
}
// 2. 更新 xg_dorm_bed_student 表:根据 bed_id = 床位id,deleted = 0,status = 0
// 将 status = 1 , checkout_time = 当前时间
LambdaUpdateWrapper<XgDormBedStudent> updateBedStudentWrapper = Wrappers.lambdaUpdate();
updateBedStudentWrapper.in(XgDormBedStudent::getBedId, bedIds)
.eq(XgDormBedStudent::getDeleted, "0")
.eq(XgDormBedStudent::getStatus, "0")
.set(XgDormBedStudent::getStatus, "1")
// .set(XgDormBedStudent::getAssignTime, null)
.set(XgDormBedStudent::getCheckoutTime, now)
.set(XgDormBedStudent::getUpdateTime, now)
.set(XgDormBedStudent::getUpdateBy, loginUserId);
int bedStudentUpdateCount = baseMapper.update(null, updateBedStudentWrapper);
log.info("更新床位学生分配表记录数: {}", bedStudentUpdateCount);
// 根据id跟床位id更新床位状态为空闲
LambdaUpdateWrapper<XgDormBed> updateBedWrapper = Wrappers.lambdaUpdate();
updateBedWrapper.in(XgDormBed::getId, bedIds)
.eq(XgDormBed::getDeleted, "0")
.set(XgDormBed::getBedStatus, "0");
xgDormBedMapper.update(null, updateBedWrapper);
return true;
} catch (Exception e) {
log.error("班主任退宿选中床位失败", e);
throw new RuntimeException("退宿选中床位失败:" + e.getMessage());
}
}
} }
@@ -201,3 +201,17 @@ export const classTeacherRecallSelectedBeds = (bedIds: number[], classId?: strin
params: { classId } params: { classId }
}); });
}; };
/**
* 班主任退宿选中床位
* @param bedIds 床位ID数组
* @param classId 班级ID,可为空
*/
export const classTeacherStayawaySelectedBeds = (bedIds: number[], classId?: string | number) => {
return request({
url: '/dormBedStudent/dormBedStudent/classTeacherStayawaySelectedBeds',
method: 'post',
data: bedIds,
params: { classId }
});
};
+39 -1
View File
@@ -99,6 +99,7 @@
<!-- <el-button type="success" icon="UserFilled" size="small" @click="handleRandomAllocation">随机分配</el-button> <!-- <el-button type="success" icon="UserFilled" size="small" @click="handleRandomAllocation">随机分配</el-button>
<el-button type="info" icon="Sort" size="small" @click="handleStudentNoAllocation">按学号分配</el-button> --> <el-button type="info" icon="Sort" size="small" @click="handleStudentNoAllocation">按学号分配</el-button> -->
<el-button type="warning" icon="RefreshLeft" size="small" @click="handleRecallBeds">收回选中床位</el-button> <el-button type="warning" icon="RefreshLeft" size="small" @click="handleRecallBeds">收回选中床位</el-button>
<el-button type="danger" icon="House" size="small" @click="handleStayawayBeds">退宿选中床位</el-button>
</el-col> </el-col>
<el-col :span="12" style="text-align: right"> <el-col :span="12" style="text-align: right">
<el-button <el-button
@@ -304,7 +305,8 @@ import {
getClassTeacherUnallocatedStudents, getClassTeacherUnallocatedStudents,
classTeacherRandomAllocation, classTeacherRandomAllocation,
classTeacherStudentNoAllocation, classTeacherStudentNoAllocation,
classTeacherRecallSelectedBeds classTeacherRecallSelectedBeds,
classTeacherStayawaySelectedBeds
} from '@/api/xg/xgss/dormBedStudent/dormBedStudent'; } from '@/api/xg/xgss/dormBedStudent/dormBedStudent';
// 导入API方法 // 导入API方法
import { listDormRoomByClassId } from '@/api/xg/xgss/dormRoom/index'; import { listDormRoomByClassId } from '@/api/xg/xgss/dormRoom/index';
@@ -748,6 +750,42 @@ const handleRecallBeds = async () => {
} }
}; };
/** 退宿床位 */
const handleStayawayBeds = async () => {
if (!selectedBuilding.value) {
ElMessage.warning('请先选择宿舍楼');
return;
}
// 获取选中的床位ID数组
const selectedBedIds = selectedRows.value
.filter((row) => row.isBed && row.studentId) // 只退宿已分配的床位
.map((bed) => bed.id);
if (selectedBedIds.length === 0) {
ElMessage.warning('请先勾选要退宿的床位!');
return;
}
try {
const confirmMessage = `确认退宿选中的 ${selectedBedIds.length} 个床位吗?\n\n退宿后,这些床位上学生的床位信息将被清空,同时该床位归还学校。`;
await ElMessageBox.confirm(confirmMessage, '确认退宿选中床位', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
await classTeacherStayawaySelectedBeds(selectedBedIds, activeClassId.value);
ElMessage.success('退宿选中床位成功');
handleAllocationSuccess();
} catch (error: any) {
if (error !== 'cancel') {
ElMessage.error('退宿床位失败');
}
}
};
/** 分配成功回调 */ /** 分配成功回调 */
const handleAllocationSuccess = () => { const handleAllocationSuccess = () => {
// 清除缓存,确保数据刷新 // 清除缓存,确保数据刷新
+36 -2
View File
@@ -134,6 +134,7 @@
<el-col :span="12"> <el-col :span="12">
<el-button type="primary" icon="check" size="small" @click="handleAddRoom">分配给班级</el-button> <el-button type="primary" icon="check" size="small" @click="handleAddRoom">分配给班级</el-button>
<el-button type="warning" icon="RefreshLeft" size="small" @click="handleBatchRecall">批量收回宿舍</el-button> <el-button type="warning" icon="RefreshLeft" size="small" @click="handleBatchRecall">批量收回宿舍</el-button>
<el-button type="danger" icon="UserFilled" size="small" @click="handleBatchStayaway">批量退宿床位</el-button>
</el-col> </el-col>
<el-col :span="12" style="text-align: right"> <el-col :span="12" style="text-align: right">
<el-button <el-button
@@ -358,7 +359,7 @@
<script setup name="DormRoomTreeManagement" lang="ts"> <script setup name="DormRoomTreeManagement" lang="ts">
import { ref, computed, reactive, onMounted, nextTick, watch, getCurrentInstance } from 'vue'; import { ref, computed, reactive, onMounted, nextTick, watch, getCurrentInstance } from 'vue';
import { InfoFilled, House, Avatar } from '@element-plus/icons-vue'; import { InfoFilled, House, Avatar, UserFilled } from '@element-plus/icons-vue';
import type { DormBuildingTreeVO } from '@/api/xg/xgss/dormBedStudent/dormBedStudent/types'; import type { DormBuildingTreeVO } from '@/api/xg/xgss/dormBedStudent/dormBedStudent/types';
import type { DormTreeNode, BedInfo } from '@/api/xg/xgss/xsssfjgl/types'; import type { DormTreeNode, BedInfo } from '@/api/xg/xgss/xsssfjgl/types';
import type { DormRoomVO } from '@/api/xg/xgss/dormRoom/types'; import type { DormRoomVO } from '@/api/xg/xgss/dormRoom/types';
@@ -375,7 +376,7 @@ import ElMessageBox from 'element-plus/es/components/message-box/index';
import RoomDialog from './components/RoomDialog.vue'; import RoomDialog from './components/RoomDialog.vue';
import BedDialog from './components/BedDialog.vue'; import BedDialog from './components/BedDialog.vue';
import ClassAllocationDialog from './components/ClassAllocationDialog.vue'; import ClassAllocationDialog from './components/ClassAllocationDialog.vue';
import { batchRecallDormBeds, batchRecallClassAllocation } from '@/api/xg/xgss/dormBedStudent/dormBedStudent'; import { batchRecallDormBeds, batchRecallClassAllocation, classTeacherStayawaySelectedBeds } from '@/api/xg/xgss/dormBedStudent/dormBedStudent';
// const { proxy } = getCurrentInstance(); // const { proxy } = getCurrentInstance();
@@ -712,6 +713,39 @@ const handleBatchRecall = async () => {
} }
}; };
/** 批量退宿床位 */
const handleBatchStayaway = async () => {
if (!selectedBuilding.value) {
ElMessage.warning('请先选择宿舍楼');
return;
}
const selectedBeds = selectedRows.value.filter((row) => row.isBed).map((row) => row.id);
if (selectedBeds.length === 0) {
ElMessage.warning('请先选择要退宿的床位');
return;
}
try {
const content = `确认退宿选中的 ${selectedBeds.length} 个床位吗?\n\n重要提示:退宿后,这些床位上学生的床位信息将被清空,同时该床位归还学校。`;
await ElMessageBox.confirm(content, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
} catch {
return;
}
try {
await classTeacherStayawaySelectedBeds(selectedBeds);
ElMessage.success('批量退宿成功');
// 刷新数据
selectableRowsCache.value = [];
loadRoomData();
} catch (e) {
ElMessage.error('批量退宿失败');
console.error(e);
}
};
/** 全部展开 */ /** 全部展开 */
const expandAll = async () => { const expandAll = async () => {
if (expandAllLoading.value || selectionLoading.value || !roomList.value?.length) return; if (expandAllLoading.value || selectionLoading.value || !roomList.value?.length) return;
+36 -2
View File
@@ -134,6 +134,7 @@
<el-col :span="12"> <el-col :span="12">
<el-button type="primary" icon="check" size="small" @click="handleAddRoom">分配给二级学院</el-button> <el-button type="primary" icon="check" size="small" @click="handleAddRoom">分配给二级学院</el-button>
<el-button type="warning" icon="RefreshLeft" size="small" @click="handleBatchRecall">批量收回宿舍</el-button> <el-button type="warning" icon="RefreshLeft" size="small" @click="handleBatchRecall">批量收回宿舍</el-button>
<el-button type="danger" icon="UserFilled" size="small" @click="handleBatchStayaway">批量退宿床位</el-button>
</el-col> </el-col>
<el-col :span="12" style="text-align: right"> <el-col :span="12" style="text-align: right">
<el-button <el-button
@@ -356,7 +357,7 @@
<script setup name="DormRoomTreeManagement" lang="ts"> <script setup name="DormRoomTreeManagement" lang="ts">
import { ref, computed, reactive, onMounted, nextTick, watch, getCurrentInstance } from 'vue'; import { ref, computed, reactive, onMounted, nextTick, watch, getCurrentInstance } from 'vue';
import { InfoFilled, House, Avatar } from '@element-plus/icons-vue'; import { InfoFilled, House, Avatar, UserFilled } from '@element-plus/icons-vue';
import type { DormTreeNode, BedInfo } from '@/api/xg/xgss/xsssfjgl/types'; import type { DormTreeNode, BedInfo } from '@/api/xg/xgss/xsssfjgl/types';
import type { DormRoomVO } from '@/api/xg/xgss/dormRoom/types'; import type { DormRoomVO } from '@/api/xg/xgss/dormRoom/types';
import type { DormBedDetailVO } from '@/api/xg/xgss/dormBed/types'; import type { DormBedDetailVO } from '@/api/xg/xgss/dormBed/types';
@@ -372,7 +373,7 @@ import ElMessageBox from 'element-plus/es/components/message-box/index';
import RoomDialog from './components/RoomDialog.vue'; import RoomDialog from './components/RoomDialog.vue';
import BedDialog from './components/BedDialog.vue'; import BedDialog from './components/BedDialog.vue';
import CollegeAllocationDialog from './components/CollegeAllocationDialog.vue'; import CollegeAllocationDialog from './components/CollegeAllocationDialog.vue';
import { batchRecallDormBeds } from '@/api/xg/xgss/dormBedStudent/dormBedStudent'; import { batchRecallDormBeds, classTeacherStayawaySelectedBeds } from '@/api/xg/xgss/dormBedStudent/dormBedStudent';
// const { proxy } = getCurrentInstance(); // const { proxy } = getCurrentInstance();
@@ -713,6 +714,39 @@ const handleBatchRecall = async () => {
} }
}; };
/** 批量退宿床位 */
const handleBatchStayaway = async () => {
if (!selectedBuilding.value) {
ElMessage.warning('请先选择宿舍楼');
return;
}
const selectedBeds = selectedRows.value.filter((row) => row.isBed).map((row) => row.id);
if (selectedBeds.length === 0) {
ElMessage.warning('请先选择要退宿的床位');
return;
}
try {
const content = `确认退宿选中的 ${selectedBeds.length} 个床位吗?\n\n重要提示:退宿后,这些床位上学生的床位信息将被清空,同时该床位归还学校。`;
await ElMessageBox.confirm(content, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
} catch {
return;
}
try {
await classTeacherStayawaySelectedBeds(selectedBeds);
ElMessage.success('批量退宿成功');
// 刷新数据
selectableRowsCache.value = [];
loadRoomData();
} catch (e) {
ElMessage.error('批量退宿失败');
console.error(e);
}
};
/** 全部展开 */ /** 全部展开 */
const expandAll = async () => { const expandAll = async () => {
if (expandAllLoading.value || selectionLoading.value || !roomList.value?.length) return; if (expandAllLoading.value || selectionLoading.value || !roomList.value?.length) return;