diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBedStudentController.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBedStudentController.java index d36ae8e8..579cb845 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBedStudentController.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBedStudentController.java @@ -270,4 +270,55 @@ public class XgDormBedStudentController extends BaseController { return toAjax(xgDormBedStudentService.classTeacherStayawaySelectedBeds(bedIds, classId)); } + /** + * 班主任床位互换 + * 将两个有学生的床位进行互换 + */ + @SaCheckPermission("dormBedStudent:dormBedStudent:edit") + @Log(title = "班主任床位互换", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/classTeacherExchangeBeds") + public R classTeacherExchangeBeds(@RequestParam Long sourceBedId, + @RequestParam Long targetBedId, + @RequestParam(required = false) Long classId) { + return toAjax(xgDormBedStudentService.classTeacherExchangeBeds(sourceBedId, targetBedId, classId)); + } + + /** + * 班主任床位移动 + * 将学生从当前床位移动到指定的空闲床位 + */ + @SaCheckPermission("dormBedStudent:dormBedStudent:edit") + @Log(title = "班主任床位移动", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/classTeacherMoveBed") + public R classTeacherMoveBed(@RequestParam Long sourceBedId, + @RequestParam Long targetBedId, + @RequestParam(required = false) Long classId) { + return toAjax(xgDormBedStudentService.classTeacherMoveBed(sourceBedId, targetBedId, classId)); + } + + /** + * 获取班级所有已入住宿舍的学生床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + * 和学生信息(学生姓名、学号、性别) + */ + @SaCheckPermission("dormBedStudent:dormBedStudent:list") + @GetMapping("/getClassOccupiedBedDetails") + public R> getClassOccupiedBedDetails(@RequestParam(required = false) Long classId) { + List occupiedBedDetails = xgDormBedStudentService.getClassOccupiedBedDetails(classId); + return R.ok(occupiedBedDetails); + } + + /** + * 获取班级所有未安排学生的床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + */ + @SaCheckPermission("dormBedStudent:dormBedStudent:list") + @GetMapping("/getClassUnoccupiedBedDetails") + public R> getClassUnoccupiedBedDetails(@RequestParam(required = false) Long classId) { + List unoccupiedBedDetails = xgDormBedStudentService.getClassUnoccupiedBedDetails(classId); + return R.ok(unoccupiedBedDetails); + } + } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBedStudentService.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBedStudentService.java index 679fdf14..2ff74eba 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBedStudentService.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBedStudentService.java @@ -192,4 +192,45 @@ public interface IXgDormBedStudentService { * @return 是否退宿成功 */ Boolean classTeacherStayawaySelectedBeds(List bedIds, Long classId); + + /** + * 班主任床位互换 + * 将两个有学生的床位进行互换 + * + * @param sourceBedId 源床位ID + * @param targetBedId 目标床位ID + * @param classId 班级ID + * @return 是否互换成功 + */ + Boolean classTeacherExchangeBeds(Long sourceBedId, Long targetBedId, Long classId); + + /** + * 班主任床位移动 + * 将学生从当前床位移动到指定的空闲床位 + * + * @param sourceBedId 源床位ID + * @param targetBedId 目标床位ID + * @param classId 班级ID + * @return 是否移动成功 + */ + Boolean classTeacherMoveBed(Long sourceBedId, Long targetBedId, Long classId); + + /** + * 获取班级所有已入住宿舍的学生床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + * 和学生信息(学生姓名、学号、性别) + * + * @param classId 班级ID,可为空 + * @return 已入住床位详情列表 + */ + List getClassOccupiedBedDetails(Long classId); + + /** + * 获取班级所有未安排学生的床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + * + * @param classId 班级ID,可为空 + * @return 未安排学生的床位详情列表 + */ + List getClassUnoccupiedBedDetails(Long classId); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java index d43faa6e..a73b22bc 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java @@ -1873,4 +1873,323 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService { } } + /** + * 班主任床位互换 + * 将两个有学生的床位进行互换 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean classTeacherExchangeBeds(Long sourceBedId, Long targetBedId, Long classId) { + try { + log.info("班主任床位互换开始,源床位ID: {}, 目标床位ID: {}, 班级ID: {}", sourceBedId, targetBedId, classId); + + // 1. 校验参数 + if (sourceBedId == null || targetBedId == null) { + throw new RuntimeException("床位ID不能为空"); + } + if (sourceBedId.equals(targetBedId)) { + throw new RuntimeException("不能选择相同的床位进行互换"); + } + + // 2. 获取源床位和目标床位的分配信息 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.in(XgDormBedStudent::getBedId, sourceBedId, targetBedId) + .eq(XgDormBedStudent::getDeleted, "0"); + List bedStudents = baseMapper.selectList(queryWrapper); + + if (bedStudents.size() != 2) { + throw new RuntimeException("互换床位必须都已分配学生"); + } + + // 3. 找到对应的分配记录 + XgDormBedStudent sourceBedStudent = bedStudents.stream() + .filter(bs -> bs.getBedId().equals(sourceBedId)) + .findFirst() + .orElseThrow(() -> new RuntimeException("未找到源床位的分配记录")); + + XgDormBedStudent targetBedStudent = bedStudents.stream() + .filter(bs -> bs.getBedId().equals(targetBedId)) + .findFirst() + .orElseThrow(() -> new RuntimeException("未找到目标床位的分配记录")); + + // 4. 验证班级权限(如果指定了班级ID) + if (classId != null) { + if (!classId.equals(sourceBedStudent.getClassId()) && !classId.equals(targetBedStudent.getClassId())) { + throw new RuntimeException("没有权限操作这些床位"); + } + } + + // 5. 执行互换:交换两个记录的床位ID + Long tempStudentId = sourceBedStudent.getStudentId(); + Long tempClassId = sourceBedStudent.getClassId(); + + // 更新源床位分配记录 + sourceBedStudent.setStudentId(targetBedStudent.getStudentId()); + sourceBedStudent.setClassId(targetBedStudent.getClassId()); + sourceBedStudent.setUpdateTime(new Date()); + sourceBedStudent.setUpdateBy(LoginHelper.getUserId()); + + // 更新目标床位分配记录 + targetBedStudent.setStudentId(tempStudentId); + targetBedStudent.setClassId(tempClassId); + targetBedStudent.setUpdateTime(new Date()); + targetBedStudent.setUpdateBy(LoginHelper.getUserId()); + + // 6. 更新数据库 + baseMapper.updateById(sourceBedStudent); + baseMapper.updateById(targetBedStudent); + + log.info("班主任床位互换成功"); + return true; + + } catch (Exception e) { + log.error("班主任床位互换失败", e); + throw new RuntimeException("床位互换失败:" + e.getMessage()); + } + } + + /** + * 班主任床位移动 + * 将学生从当前床位移动到指定的空闲床位 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean classTeacherMoveBed(Long sourceBedId, Long targetBedId, Long classId) { + try { + log.info("班主任床位移动开始,源床位ID: {}, 目标床位ID: {}, 班级ID: {}", sourceBedId, targetBedId, classId); + + // 1. 校验参数 + if (sourceBedId == null || targetBedId == null) { + throw new RuntimeException("床位ID不能为空"); + } + if (sourceBedId.equals(targetBedId)) { + throw new RuntimeException("不能选择相同的床位进行移动"); + } + + // 2. 检查源床位是否有学生分配 + LambdaQueryWrapper sourceQueryWrapper = Wrappers.lambdaQuery(); + sourceQueryWrapper.eq(XgDormBedStudent::getBedId, sourceBedId) + .eq(XgDormBedStudent::getDeleted, "0"); + XgDormBedStudent sourceBedStudent = baseMapper.selectOne(sourceQueryWrapper); + + if (sourceBedStudent == null) { + throw new RuntimeException("源床位未分配学生"); + } + + // 3. 验证班级权限(如果指定了班级ID) + if (classId != null && !classId.equals(sourceBedStudent.getClassId())) { + throw new RuntimeException("没有权限操作此床位"); + } + + // 4. 检查目标床位是否空闲 + LambdaQueryWrapper targetQueryWrapper = Wrappers.lambdaQuery(); + targetQueryWrapper.eq(XgDormBedStudent::getBedId, targetBedId) + .eq(XgDormBedStudent::getDeleted, "0"); + XgDormBedStudent targetBedStudent = baseMapper.selectOne(targetQueryWrapper); + + if (targetBedStudent != null) { + throw new RuntimeException("目标床位已被占用"); + } + + // 5. 检查目标床位是否存在且可用 + XgDormBed targetBed = xgDormBedMapper.selectById(targetBedId); + if (targetBed == null || !"0".equals(targetBed.getDeleted())) { + throw new RuntimeException("目标床位不存在"); + } + if (!"0".equals(targetBed.getBedStatus())) { + throw new RuntimeException("目标床位不可用(维修中或其他状态)"); + } + + // 6. 创建目标床位的新分配记录 + XgDormBedStudent newBedStudent = new XgDormBedStudent(); + newBedStudent.setBedId(targetBedId); + newBedStudent.setStudentId(sourceBedStudent.getStudentId()); + newBedStudent.setClassId(sourceBedStudent.getClassId()); + newBedStudent.setCollegeId(sourceBedStudent.getCollegeId()); + newBedStudent.setCreateTime(new Date()); + newBedStudent.setCreateBy(LoginHelper.getUserId()); + newBedStudent.setDeleted("0"); + + // 7. 插入新记录 + baseMapper.insert(newBedStudent); + + // 8. 删除源床位的分配记录 + sourceBedStudent.setDeleted("1"); + sourceBedStudent.setUpdateTime(new Date()); + sourceBedStudent.setUpdateBy(LoginHelper.getUserId()); + baseMapper.updateById(sourceBedStudent); + + log.info("班主任床位移动成功"); + return true; + + } catch (Exception e) { + log.error("班主任床位移动失败", e); + throw new RuntimeException("床位移动失败:" + e.getMessage()); + } + } + + /** + * 获取班级所有已入住宿舍的学生床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + * 和学生信息(学生姓名、学号、性别) + */ + @Override + public List getClassOccupiedBedDetails(Long classId) { + try { + log.info("开始获取班级已入住床位详情,班级ID: {}", classId); + + // 查询已分配学生的床位信息 + List> bedDetails = baseMapper.selectMaps( + Wrappers.lambdaQuery(XgDormBedStudent.class) + .select(XgDormBedStudent::getBedId, XgDormBedStudent::getStudentId, + XgDormBedStudent::getClassId, XgDormBedStudent::getCollegeId) + .eq(XgDormBedStudent::getClassId, classId) + .isNotNull(XgDormBedStudent::getStudentId) + .eq(XgDormBedStudent::getStatus, "0") + .eq(XgDormBedStudent::getDeleted, "0")); + + List result = new ArrayList<>(); + + for (Map bedStudent : bedDetails) { + Long bedId = (Long) bedStudent.get("bed_id"); + Long studentId = (Long) bedStudent.get("student_id"); + + // 查询床位详细信息 + XgDormBed bed = xgDormBedMapper.selectById(bedId); + if (bed == null) + continue; + + XgDormRoom room = xgDormRoomMapper.selectById(bed.getRoomId()); + if (room == null) + continue; + + XgDormBuilding building = xgDormBuildingMapper.selectById(room.getBuildingId()); + if (building == null) + continue; + + XgDormArea area = xgDormAreaMapper.selectById(building.getAreaId()); + if (area == null) + continue; + + XgDormCampus campus = xgDormCampusMapper.selectById(area.getCampusId()); + if (campus == null) + continue; + + // 查询学生信息 + XgStudentMsg student = xgStudentMsgMapper.selectById(studentId); + if (student == null) + continue; + + // 组装结果数据 + Map detailInfo = new LinkedHashMap<>(); + + // 床位信息 + detailInfo.put("bedId", bedId); + detailInfo.put("campusName", campus.getCampusName()); + detailInfo.put("areaName", area.getAreaName()); + detailInfo.put("buildingName", building.getBuildingName()); + detailInfo.put("roomName", room.getRoomName()); + detailInfo.put("bedName", bed.getBedName()); + detailInfo.put("bedType", bed.getBedType()); + + // 床位性别类型(基于楼栋类型) + String bedGenderType = building.getBuildingType(); // 1男生楼 2女生楼 3混合楼 + detailInfo.put("bedGenderType", bedGenderType); + + // 学生信息 + detailInfo.put("studentId", studentId); + detailInfo.put("studentName", student.getName()); + detailInfo.put("studentNo", student.getStudentNo()); + detailInfo.put("gender", student.getGender()); + + result.add(detailInfo); + } + + log.info("获取班级已入住床位详情成功,共{}条记录", result.size()); + return result; + + } catch (Exception e) { + log.error("获取班级已入住床位详情失败", e); + return Collections.emptyList(); + } + } + + /** + * 获取班级所有未安排学生的床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + */ + @Override + public List getClassUnoccupiedBedDetails(Long classId) { + try { + log.info("开始获取班级未分配学生床位详情,班级ID: {}", classId); + + // 查询分配给班级但未分配学生的床位信息 + List> bedDetails = baseMapper.selectMaps( + Wrappers.lambdaQuery(XgDormBedStudent.class) + .select(XgDormBedStudent::getBedId, XgDormBedStudent::getClassId, + XgDormBedStudent::getCollegeId) + .eq(XgDormBedStudent::getClassId, classId) + .isNull(XgDormBedStudent::getStudentId) + .eq(XgDormBedStudent::getStatus, "0") + .eq(XgDormBedStudent::getDeleted, "0")); + + List result = new ArrayList<>(); + + for (Map bedStudent : bedDetails) { + Long bedId = (Long) bedStudent.get("bed_id"); + + // 查询床位详细信息 + XgDormBed bed = xgDormBedMapper.selectById(bedId); + if (bed == null) + continue; + + // 确保床位可用 + if (!"1".equals(bed.getBedStatus()) || !"0".equals(bed.getDeleted())) { + continue; + } + + XgDormRoom room = xgDormRoomMapper.selectById(bed.getRoomId()); + if (room == null) + continue; + + XgDormBuilding building = xgDormBuildingMapper.selectById(room.getBuildingId()); + if (building == null) + continue; + + XgDormArea area = xgDormAreaMapper.selectById(building.getAreaId()); + if (area == null) + continue; + + XgDormCampus campus = xgDormCampusMapper.selectById(area.getCampusId()); + if (campus == null) + continue; + + // 组装结果数据 + Map detailInfo = new LinkedHashMap<>(); + + // 床位信息 + detailInfo.put("bedId", bedId); + detailInfo.put("campusName", campus.getCampusName()); + detailInfo.put("areaName", area.getAreaName()); + detailInfo.put("buildingName", building.getBuildingName()); + detailInfo.put("roomName", room.getRoomName()); + detailInfo.put("bedName", bed.getBedName()); + detailInfo.put("bedType", bed.getBedType()); + + // 床位性别类型(基于楼栋类型) + String bedGenderType = building.getBuildingType(); // 1男生楼 2女生楼 3混合楼 + detailInfo.put("bedGenderType", bedGenderType); + + result.add(detailInfo); + } + + log.info("获取班级未分配学生床位详情成功,共{}条记录", result.size()); + return result; + + } catch (Exception e) { + log.error("获取班级未分配学生床位详情失败", e); + return Collections.emptyList(); + } + } + } diff --git a/web/src/api/xg/xgss/dormBedStudent/dormBedStudent/index.ts b/web/src/api/xg/xgss/dormBedStudent/dormBedStudent/index.ts index 0604f9ea..4606bc9e 100644 --- a/web/src/api/xg/xgss/dormBedStudent/dormBedStudent/index.ts +++ b/web/src/api/xg/xgss/dormBedStudent/dormBedStudent/index.ts @@ -215,3 +215,60 @@ export const classTeacherStayawaySelectedBeds = (bedIds: number[], classId?: str params: { classId } }); }; + +/** + * 班主任床位互换 + * 将两个有学生的床位进行互换 + * @param sourceBedId 源床位ID + * @param targetBedId 目标床位ID + * @param classId 班级ID,可为空 + */ +export const classTeacherExchangeBeds = (sourceBedId: number, targetBedId: number, classId?: string | number) => { + return request({ + url: '/dormBedStudent/dormBedStudent/classTeacherExchangeBeds', + method: 'post', + params: { sourceBedId, targetBedId, classId } + }); +}; + +/** + * 班主任床位移动 + * 将学生从当前床位移动到指定的空闲床位 + * @param sourceBedId 源床位ID + * @param targetBedId 目标床位ID + * @param classId 班级ID,可为空 + */ +export const classTeacherMoveBed = (sourceBedId: number, targetBedId: number, classId?: string | number) => { + return request({ + url: '/dormBedStudent/dormBedStudent/classTeacherMoveBed', + method: 'post', + params: { sourceBedId, targetBedId, classId } + }); +}; + +/** + * 获取班级所有已入住宿舍的学生床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + * 和学生信息(学生姓名、学号、性别) + * @param classId 班级ID,可为空 + */ +export const getClassOccupiedBedDetails = (classId?: string | number) => { + return request({ + url: '/dormBedStudent/dormBedStudent/getClassOccupiedBedDetails', + method: 'get', + params: { classId } + }); +}; + +/** + * 获取班级所有未安排学生的床位信息 + * 包含床位信息(校区名称、宿舍区名称、楼栋名称、房间名称、床位名称) + * @param classId 班级ID,可为空 + */ +export const getClassUnoccupiedBedDetails = (classId?: string | number) => { + return request({ + url: '/dormBedStudent/dormBedStudent/getClassUnoccupiedBedDetails', + method: 'get', + params: { classId } + }); +}; diff --git a/web/src/views/xg/xgss/bzrfp/bzrfp.vue b/web/src/views/xg/xgss/bzrfp/bzrfp.vue index e4cf827c..813343ba 100644 --- a/web/src/views/xg/xgss/bzrfp/bzrfp.vue +++ b/web/src/views/xg/xgss/bzrfp/bzrfp.vue @@ -100,6 +100,7 @@ 按学号分配 --> 收回选中床位 退宿选中床位 + 调宿 + + + @@ -325,6 +337,7 @@ import ElMessageBox from 'element-plus/es/components/message-box/index'; // 引入子组件 import SelectiveAllocationDialog from './components/SelectiveAllocationDialog.vue'; +import BedTransferDialog from './components/BedTransferDialog.vue'; // 组件状态 const dormTreeRef = ref(); @@ -411,6 +424,14 @@ const selectiveAllocationDialog = reactive({ buildingInfo: undefined as DormBuildingTreeVO | undefined }); +// 调宿对话框 +const bedTransferDialog = reactive({ + visible: false, + title: '调宿管理', + selectedBed: undefined as any | undefined, + buildingInfo: undefined as DormBuildingTreeVO | undefined +}); + // 表格最大高度计算 const tableMaxHeight = computed(() => { // 根据不同屏幕尺寸动态调整预留空间 @@ -814,6 +835,31 @@ const handleStayawayBeds = async () => { } }; +/** 调宿管理 */ +const handleBedTransfer = () => { + if (!selectedBuilding.value) { + ElMessage.warning('请先选择宿舍楼'); + return; + } + + // 获取选中的已分配床位 + const selectedAllocatedBeds = selectedRows.value.filter((row) => row.isBed && row.studentId); + + if (selectedAllocatedBeds.length === 0) { + ElMessage.warning('请先勾选要调宿的床位(必须是已分配学生的床位)!'); + return; + } + + if (selectedAllocatedBeds.length > 1) { + ElMessage.warning('调宿操作一次只能选择一个床位!'); + return; + } + + bedTransferDialog.selectedBed = selectedAllocatedBeds[0]; + bedTransferDialog.buildingInfo = selectedBuilding.value; + bedTransferDialog.visible = true; +}; + /** 分配成功回调 */ const handleAllocationSuccess = () => { // 清除缓存,确保数据刷新 diff --git a/web/src/views/xg/xgss/bzrfp/components/BedTransferDialog.vue b/web/src/views/xg/xgss/bzrfp/components/BedTransferDialog.vue new file mode 100644 index 00000000..db1144ba --- /dev/null +++ b/web/src/views/xg/xgss/bzrfp/components/BedTransferDialog.vue @@ -0,0 +1,702 @@ + + + + +