Prechádzať zdrojové kódy

提交宿舍区去除的业务修改

zlwu 1 rok pred
rodič
commit
2a38245ae2
24 zmenil súbory, kde vykonal 1136 pridanie a 554 odobranie
  1. 2 2
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBedStudentController.java
  2. 23 1
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingController.java
  3. 52 5
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingTreeController.java
  4. 1 1
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/XgDormHygieneCheck.java
  5. 1 1
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/XgDormHygieneStudentScore.java
  6. 2 1
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgDormBuildingBo.java
  7. 104 0
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/DormBuildingTreeSimplifiedVo.java
  8. 103 0
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormBuildingSimplifiedVo.java
  9. 183 0
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormHygieneCheckSimplifiedVo.java
  10. 1 1
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBedStudentService.java
  11. 20 0
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingService.java
  12. 19 0
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingTreeService.java
  13. 59 4
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java
  14. 71 46
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingServiceImpl.java
  15. 39 0
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingTreeServiceImpl.java
  16. 2 2
      backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java
  17. 80 1
      docs/开发文档/API/宿舍卫生检查管理API.md
  18. 135 41
      docs/开发文档/API/宿舍楼树形结构API.md
  19. 2 2
      docs/设计文档/database/hzdyjs_xg0820.sql
  20. 60 125
      web/src/views/xg/xgss/dormHygieneCheck/dormHygieneCheck/DormHygieneCheckDialog.vue
  21. 6 6
      web/src/views/xg/xgss/dormHygieneCheck/dormHygieneCheck/index.vue
  22. 48 271
      web/src/views/xg/xgss/sslxx/dormBuilding/index.vue
  23. 121 43
      web/src/views/xg/xgss/xsssfjgl/index.vue
  24. 2 1
      web/src/views/xg/xgss/xsssgly/index.vue

+ 2 - 2
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBedStudentController.java

@@ -157,7 +157,7 @@ public class XgDormBedStudentController extends BaseController {
 
     /**
      * 获取当前用户二级学院的宿舍楼树形结构
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      */
     @SaCheckPermission("dormBedStudent:dormBedStudent:list")
     @GetMapping("/currentUserCollegeDormTree")
@@ -168,7 +168,7 @@ public class XgDormBedStudentController extends BaseController {
 
     /**
      * 获取班主任管理的班级宿舍楼树形结构
-     * 只显示班主任管理班级分配到的宿舍楼
+     * 校区-宿舍楼二级结构,只显示班主任管理班级分配到的宿舍楼
      */
     @SaCheckPermission("dormBedStudent:dormBedStudent:list")
     @GetMapping("/getClassTeacherDormTree")

+ 23 - 1
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingController.java

@@ -18,6 +18,7 @@ import org.dromara.common.core.validate.EditGroup;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
 import org.dromara.xg.domain.vo.XgDormBuildingVo;
+import org.dromara.xg.domain.vo.XgDormBuildingSimplifiedVo;
 import org.dromara.xg.domain.bo.XgDormBuildingBo;
 import org.dromara.xg.domain.vo.BuildingTreeSelectVo;
 import org.dromara.xg.service.IXgDormBuildingService;
@@ -104,7 +105,7 @@ public class XgDormBuildingController extends BaseController {
 
     /**
      * 获取宿舍楼树形结构数据
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      */
     @SaCheckPermission("sslxx:dormBuilding:list")
     @GetMapping("/buildingTree")
@@ -112,4 +113,25 @@ public class XgDormBuildingController extends BaseController {
         List<BuildingTreeSelectVo> treeData = xgDormBuildingService.getBuildingTreeData();
         return R.ok(treeData);
     }
+
+    /**
+     * 查询宿舍楼信息简化列表
+     * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
+     */
+    @SaCheckPermission("sslxx:dormBuilding:list")
+    @GetMapping("/simplifiedList")
+    public TableDataInfo<XgDormBuildingSimplifiedVo> getSimplifiedList(XgDormBuildingBo bo, PageQuery pageQuery) {
+        return xgDormBuildingService.querySimplifiedPageList(bo, pageQuery);
+    }
+
+    /**
+     * 查询宿舍楼信息简化列表(不分页)
+     * 用于下拉选择等场景
+     */
+    @SaCheckPermission("sslxx:dormBuilding:list")
+    @GetMapping("/simplifiedListAll")
+    public R<List<XgDormBuildingSimplifiedVo>> getSimplifiedListAll(XgDormBuildingBo bo) {
+        List<XgDormBuildingSimplifiedVo> list = xgDormBuildingService.querySimplifiedList(bo);
+        return R.ok(list);
+    }
 }

+ 52 - 5
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingTreeController.java

@@ -9,6 +9,7 @@ import org.springframework.validation.annotation.Validated;
 import org.dromara.common.web.core.BaseController;
 import org.dromara.common.core.domain.R;
 import org.dromara.xg.domain.vo.DormBuildingTreeVo;
+import org.dromara.xg.domain.vo.DormBuildingTreeSimplifiedVo;
 import org.dromara.xg.domain.bo.DormBuildingTreeBo;
 import org.dromara.xg.service.IXgDormBuildingTreeService;
 
@@ -28,24 +29,70 @@ public class XgDormBuildingTreeController extends BaseController {
 
     /**
      * 获取宿舍楼树形结构数据
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      */
     @SaCheckPermission("xgss:dormBuildingTree:list")
     @GetMapping("/list")
-    public R<List<DormBuildingTreeVo>> getDormBuildingTree(DormBuildingTreeBo bo) {
-        List<DormBuildingTreeVo> treeData = xgDormBuildingTreeService.getDormBuildingTree(bo);
+    public R<List<DormBuildingTreeSimplifiedVo>> getDormBuildingTree(DormBuildingTreeBo bo) {
+        List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getSimplifiedDormBuildingTree(bo);
         return R.ok(treeData);
     }
 
     /**
      * 获取所有宿舍楼树形结构数据(不考虑权限)
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      */
     @SaCheckPermission("xgss:dormBuildingTree:list")
     @GetMapping("/listAll")
-    public R<List<DormBuildingTreeVo>> getAllDormBuildingTree(DormBuildingTreeBo bo) {
+    public R<List<DormBuildingTreeSimplifiedVo>> getAllDormBuildingTree(DormBuildingTreeBo bo) {
+        List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getAllSimplifiedDormBuildingTree(bo);
+        return R.ok(treeData);
+    }
+
+    /**
+     * 获取宿舍楼树形结构完整数据(包含宿舍区层级)
+     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 注意:此接口仅用于特殊需求,一般情况请使用/list接口
+     */
+    @SaCheckPermission("xgss:dormBuildingTree:list")
+    @GetMapping("/fullList")
+    public R<List<DormBuildingTreeVo>> getFullDormBuildingTree(DormBuildingTreeBo bo) {
+        List<DormBuildingTreeVo> treeData = xgDormBuildingTreeService.getDormBuildingTree(bo);
+        return R.ok(treeData);
+    }
+
+    /**
+     * 获取所有宿舍楼树形结构完整数据(不考虑权限,包含宿舍区层级)
+     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 注意:此接口仅用于特殊需求,一般情况请使用/listAll接口
+     */
+    @SaCheckPermission("xgss:dormBuildingTree:list")
+    @GetMapping("/fullListAll")
+    public R<List<DormBuildingTreeVo>> getAllFullDormBuildingTree(DormBuildingTreeBo bo) {
         List<DormBuildingTreeVo> treeData = xgDormBuildingTreeService.getAllDormBuildingTree(bo);
         return R.ok(treeData);
     }
 
+    /**
+     * 获取宿舍楼树形结构简化数据
+     * 校区-宿舍楼二级结构,隐藏宿舍区层级,校区不可选,只有宿舍楼可以选择
+     */
+    @SaCheckPermission("xgss:dormBuildingTree:list")
+    @GetMapping("/simplifiedList")
+    public R<List<DormBuildingTreeSimplifiedVo>> getSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
+        List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getSimplifiedDormBuildingTree(bo);
+        return R.ok(treeData);
+    }
+
+    /**
+     * 获取所有宿舍楼树形结构简化数据(不考虑权限)
+     * 校区-宿舍楼二级结构,隐藏宿舍区层级,校区不可选,只有宿舍楼可以选择
+     */
+    @SaCheckPermission("xgss:dormBuildingTree:list")
+    @GetMapping("/simplifiedListAll")
+    public R<List<DormBuildingTreeSimplifiedVo>> getAllSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
+        List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getAllSimplifiedDormBuildingTree(bo);
+        return R.ok(treeData);
+    }
+
 }

+ 1 - 1
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/XgDormHygieneCheck.java

@@ -111,7 +111,7 @@ public class XgDormHygieneCheck extends TenantEntity {
     private String campusName;
 
     /**
-     * 宿舍总分(0-100分)
+     * 宿舍扣分(0-100分)
      */
     private Double totalScore;
 

+ 1 - 1
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/XgDormHygieneStudentScore.java

@@ -94,7 +94,7 @@ public class XgDormHygieneStudentScore extends TenantEntity {
     private String bedCode;
 
     /**
-     * 学生个人得分(0-100分)
+     * 学生个人扣分(0-100分)
      */
     private Double studentScore;
 

+ 2 - 1
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgDormBuildingBo.java

@@ -41,7 +41,8 @@ public class XgDormBuildingBo extends BaseEntity {
     /**
      * 所属宿舍区ID
      */
-    @NotNull(message = "所属宿舍区ID不能为空", groups = { AddGroup.class, EditGroup.class })
+    // @NotNull(message = "所属宿舍区ID不能为空", groups = { AddGroup.class, EditGroup.class
+    // }) // 宿舍区轻量化改造:移除必填验证
     private Long areaId;
 
     /**

+ 104 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/DormBuildingTreeSimplifiedVo.java

@@ -0,0 +1,104 @@
+package org.dromara.xg.domain.vo;
+
+import java.io.Serializable;
+import java.util.List;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+/**
+ * 宿舍楼树形结构简化VO
+ * 用于简化界面显示,只显示校区→宿舍楼的二级结构,隐藏宿舍区层级
+ *
+ * @author wuzilong
+ * @date 2025-01-03
+ */
+@Data
+public class DormBuildingTreeSimplifiedVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 节点ID
+     */
+    private Long id;
+
+    /**
+     * 节点名称
+     */
+    private String label;
+
+    /**
+     * 节点类型 (campus:校区, building:宿舍楼)
+     * 注意:简化版本中移除了 area:宿舍区 类型
+     */
+    private String type;
+
+    /**
+     * 是否禁用节点(校区节点禁用点击,宿舍楼节点可点击)
+     */
+    private Boolean disabled;
+
+    /**
+     * 宿舍楼层数(仅宿舍楼节点有此字段)
+     */
+    private Integer buildingFloors;
+
+    /**
+     * 宿舍楼类型(1男生楼 2女生楼 3混合楼)(仅宿舍楼节点有此字段)
+     */
+    private String buildingType;
+
+    /**
+     * 子节点
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<DormBuildingTreeSimplifiedVo> children;
+
+    /**
+     * 从完整树形VO转换为简化树形VO
+     * 将三级结构(校区→宿舍区→宿舍楼)转换为二级结构(校区→宿舍楼)
+     */
+    public static DormBuildingTreeSimplifiedVo fromFullTreeVo(DormBuildingTreeVo fullTreeVo) {
+        if (fullTreeVo == null) {
+            return null;
+        }
+
+        DormBuildingTreeSimplifiedVo simplified = new DormBuildingTreeSimplifiedVo();
+        simplified.setId(fullTreeVo.getId());
+        simplified.setLabel(fullTreeVo.getLabel());
+        simplified.setBuildingFloors(fullTreeVo.getBuildingFloors());
+        simplified.setBuildingType(fullTreeVo.getBuildingType());
+
+        // 根据节点类型进行转换
+        if ("campus".equals(fullTreeVo.getType())) {
+            // 校区节点:保持不变
+            simplified.setType("campus");
+            simplified.setDisabled(true);
+            // 处理子节点:跳过宿舍区层级,直接提取宿舍楼
+            simplified.setChildren(flattenAreaChildren(fullTreeVo.getChildren()));
+        } else if ("building".equals(fullTreeVo.getType())) {
+            // 宿舍楼节点:保持不变
+            simplified.setType("building");
+            simplified.setDisabled(false);
+        }
+
+        return simplified;
+    }
+
+    /**
+     * 扁平化宿舍区子节点,将宿舍区下的宿舍楼直接提升为校区的子节点
+     */
+    private static List<DormBuildingTreeSimplifiedVo> flattenAreaChildren(List<DormBuildingTreeVo> areaNodes) {
+        if (areaNodes == null || areaNodes.isEmpty()) {
+            return null;
+        }
+
+        return areaNodes.stream()
+                .filter(node -> "area".equals(node.getType())) // 找到宿舍区节点
+                .flatMap(areaNode -> areaNode.getChildren() != null ? areaNode.getChildren().stream()
+                        : java.util.stream.Stream.empty()) // 提取宿舍楼
+                .filter(buildingNode -> "building".equals(buildingNode.getType())) // 确保是宿舍楼节点
+                .map(DormBuildingTreeSimplifiedVo::fromFullTreeVo) // 转换为简化VO
+                .toList();
+    }
+}

+ 103 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormBuildingSimplifiedVo.java

@@ -0,0 +1,103 @@
+package org.dromara.xg.domain.vo;
+
+import org.dromara.xg.domain.XgDormBuilding;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 宿舍楼信息简化视图对象 xg_dorm_building
+ * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
+ *
+ * @author zlwu
+ * @date 2025-01-03
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = XgDormBuilding.class)
+public class XgDormBuildingSimplifiedVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 宿舍楼编码
+     */
+    @ExcelProperty(value = "宿舍楼编码")
+    private String buildingCode;
+
+    /**
+     * 宿舍楼名称
+     */
+    @ExcelProperty(value = "宿舍楼名称")
+    private String buildingName;
+
+    /**
+     * 所属校区ID
+     */
+    @ExcelProperty(value = "所属校区ID")
+    private Long campusId;
+
+    /**
+     * 校区名称
+     */
+    @ExcelProperty(value = "校区名称")
+    private String campusName;
+
+    /**
+     * 宿舍楼类型(1男生楼 2女生楼 3混合楼)
+     */
+    @ExcelProperty(value = "宿舍楼类型(1男生楼 2女生楼 3混合楼)", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "dorm_type")
+    private String buildingType;
+
+    /**
+     * 宿舍楼描述
+     */
+    @ExcelProperty(value = "宿舍楼描述")
+    private String buildingDescription;
+
+    /**
+     * 排序号
+     */
+    @ExcelProperty(value = "排序号")
+    private Long sortOrder;
+
+    /**
+     * 总楼层数
+     */
+    @ExcelProperty(value = "总楼层数")
+    private Integer floors;
+
+    // 基础字段
+    private Long createBy; // 创建者
+    private Date createTime; // 创建时间
+    private Long updateBy; // 更新者
+    private Date updateTime; // 更新时间
+
+    /**
+     * 从完整VO转换为简化VO
+     */
+    public static XgDormBuildingSimplifiedVo fromFullVo(XgDormBuildingVo fullVo) {
+        if (fullVo == null) {
+            return null;
+        }
+        XgDormBuildingSimplifiedVo simplified = new XgDormBuildingSimplifiedVo();
+        BeanUtils.copyProperties(fullVo, simplified);
+        return simplified;
+    }
+}

+ 183 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormHygieneCheckSimplifiedVo.java

@@ -0,0 +1,183 @@
+package org.dromara.xg.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.xg.domain.XgDormHygieneCheck;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.springframework.beans.BeanUtils;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 宿舍卫生检查简化视图对象 xg_dorm_hygiene_check
+ * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼→房间结构
+ *
+ * @author zlwu
+ * @date 2025-01-03
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = XgDormHygieneCheck.class)
+public class XgDormHygieneCheckSimplifiedVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 删除标志(0代表存在 1代表删除)
+     */
+    @ExcelProperty(value = "删除标志", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=代表存在,1=代表删除")
+    private Long deleted;
+
+    /**
+     * 检查标题
+     */
+    @ExcelProperty(value = "检查标题")
+    private String checkTitle;
+
+    /**
+     * 检查日期
+     */
+    @ExcelProperty(value = "检查日期")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date checkDate;
+
+    /**
+     * 检查员ID,关联sys_user.id
+     */
+    @ExcelProperty(value = "检查员ID,关联sys_user.id")
+    private Long checkerId;
+
+    /**
+     * 检查员姓名
+     */
+    @ExcelProperty(value = "检查员姓名")
+    private String checkerName;
+
+    /**
+     * 检查类型(1日常检查 2专项检查 3突击检查 4复查)
+     */
+    @ExcelProperty(value = "检查类型", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "xg_dorm_hygiene_check_type")
+    private String checkType;
+
+    /**
+     * 检查级别(1宿管员 2学院 3学校)
+     */
+    @ExcelProperty(value = "检查级别", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "xg_dorm_hygiene_check_level")
+    private String checkLevel;
+
+    /**
+     * 宿舍房间ID,关联xg_dorm_room.id
+     */
+    @ExcelProperty(value = "宿舍房间ID,关联xg_dorm_room.id")
+    private Long roomId;
+
+    /**
+     * 房间编号
+     */
+    @ExcelProperty(value = "房间编号")
+    private String roomCode;
+
+    /**
+     * 房间名称
+     */
+    @ExcelProperty(value = "房间名称")
+    private String roomName;
+
+    /**
+     * 宿舍楼ID,关联xg_dorm_building.id
+     */
+    @ExcelProperty(value = "宿舍楼ID,关联xg_dorm_building.id")
+    private Long buildingId;
+
+    /**
+     * 宿舍楼名称
+     */
+    @ExcelProperty(value = "宿舍楼名称")
+    private String buildingName;
+
+    /**
+     * 校区ID,关联xg_dorm_campus.id
+     */
+    @ExcelProperty(value = "校区ID,关联xg_dorm_campus.id")
+    private Long campusId;
+
+    /**
+     * 校区名称
+     */
+    @ExcelProperty(value = "校区名称")
+    private String campusName;
+
+    /**
+     * 宿舍总分(0-100分)
+     */
+    @ExcelProperty(value = "宿舍总分", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=-100分")
+    private Double totalScore;
+
+    /**
+     * 卫生等级(A优秀 B良好 C合格 D不合格)
+     */
+    @ExcelProperty(value = "卫生等级", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "xg_dorm_hygiene_grade")
+    private String hygieneGrade;
+
+    /**
+     * 附件OSS ID列表,逗号分隔
+     */
+    @ExcelProperty(value = "附件OSS ID列表,逗号分隔")
+    private String attachmentIds;
+
+    /**
+     * 检查总结
+     */
+    @ExcelProperty(value = "检查总结")
+    private String checkSummary;
+
+    /**
+     * 整改建议
+     */
+    @ExcelProperty(value = "整改建议")
+    private String improvementSuggestions;
+
+    /**
+     * 检查备注
+     */
+    @ExcelProperty(value = "检查备注")
+    private String checkRemarks;
+
+    // 基础字段
+    private Long createBy; // 创建者
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime; // 创建时间
+    private Long updateBy; // 更新者
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime; // 更新时间
+
+    /**
+     * 从完整VO转换为简化VO
+     */
+    public static XgDormHygieneCheckSimplifiedVo fromFullVo(XgDormHygieneCheckVo fullVo) {
+        if (fullVo == null) {
+            return null;
+        }
+        XgDormHygieneCheckSimplifiedVo simplified = new XgDormHygieneCheckSimplifiedVo();
+        BeanUtils.copyProperties(fullVo, simplified);
+        return simplified;
+    }
+}

+ 1 - 1
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBedStudentService.java

@@ -107,7 +107,7 @@ public interface IXgDormBedStudentService {
 
     /**
      * 获取当前用户二级学院的宿舍楼树形结构
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      *
      * @return 宿舍楼树形结构数据
      */

+ 20 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingService.java

@@ -1,6 +1,7 @@
 package org.dromara.xg.service;
 
 import org.dromara.xg.domain.vo.XgDormBuildingVo;
+import org.dromara.xg.domain.vo.XgDormBuildingSimplifiedVo;
 import org.dromara.xg.domain.bo.XgDormBuildingBo;
 import org.dromara.xg.domain.vo.BuildingTreeSelectVo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -74,4 +75,23 @@ public interface IXgDormBuildingService {
      * @return 树形结构数据
      */
     List<BuildingTreeSelectVo> getBuildingTreeData();
+
+    /**
+     * 分页查询宿舍楼信息简化列表
+     * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 宿舍楼信息简化分页列表
+     */
+    TableDataInfo<XgDormBuildingSimplifiedVo> querySimplifiedPageList(XgDormBuildingBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的宿舍楼信息简化列表
+     * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
+     *
+     * @param bo 查询条件
+     * @return 宿舍楼信息简化列表
+     */
+    List<XgDormBuildingSimplifiedVo> querySimplifiedList(XgDormBuildingBo bo);
 }

+ 19 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingTreeService.java

@@ -2,6 +2,7 @@ package org.dromara.xg.service;
 
 import java.util.List;
 import org.dromara.xg.domain.vo.DormBuildingTreeVo;
+import org.dromara.xg.domain.vo.DormBuildingTreeSimplifiedVo;
 import org.dromara.xg.domain.bo.DormBuildingTreeBo;
 
 /**
@@ -28,4 +29,22 @@ public interface IXgDormBuildingTreeService {
      */
     List<DormBuildingTreeVo> getAllDormBuildingTree(DormBuildingTreeBo bo);
 
+    /**
+     * 获取宿舍楼树形结构简化数据
+     * 校区-宿舍楼二级结构,隐藏宿舍区层级
+     *
+     * @param bo 查询参数
+     * @return 简化树形结构数据
+     */
+    List<DormBuildingTreeSimplifiedVo> getSimplifiedDormBuildingTree(DormBuildingTreeBo bo);
+
+    /**
+     * 获取所有宿舍楼树形结构简化数据(不考虑权限)
+     * 校区-宿舍楼二级结构,隐藏宿舍区层级
+     *
+     * @param bo 查询参数
+     * @return 简化树形结构数据
+     */
+    List<DormBuildingTreeSimplifiedVo> getAllSimplifiedDormBuildingTree(DormBuildingTreeBo bo);
+
 }

+ 59 - 4
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java

@@ -983,7 +983,8 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
                     Long roomId = entry.getKey();
                     List<Long> roomUnallocatedBeds = entry.getValue();
                     String roomCode = roomCodeMap.get(roomId);
-                    log.error("房间{}({})有{}个床位未分配:{}", roomCode, roomId, roomUnallocatedBeds.size(), roomUnallocatedBeds);
+                    log.error("房间{}({})有{}个床位未分配:{}", roomCode, roomId, roomUnallocatedBeds.size(),
+                            roomUnallocatedBeds);
                 }
 
                 throw new RuntimeException("床位分配不完整,存在" + (totalExpectedBeds - totalAllocatedBeds) + "个床位未分配");
@@ -1008,7 +1009,7 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
 
     /**
      * 获取当前用户二级学院的宿舍楼树形结构
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      *
      * @return 宿舍楼树形结构数据
      */
@@ -1159,8 +1160,8 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
                     .orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId);
             List<XgDormCampus> campuses = xgDormCampusMapper.selectList(campusWrapper);
 
-            // 构建树形结构
-            return buildTreeStructure(campuses, areas, buildings);
+            // 构建简化版树形结构(校区-宿舍楼,去除宿舍区层级)
+            return buildSimplifiedTreeStructure(campuses, areas, buildings);
 
         } catch (Exception e) {
             log.error("构建宿舍楼树形结构失败", e);
@@ -1232,6 +1233,60 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
         return new ArrayList<>(campusMap.values());
     }
 
+    /**
+     * 构建简化树形结构:校区-宿舍楼(去除宿舍区层级)
+     */
+    private List<DormBuildingTreeVo> buildSimplifiedTreeStructure(List<XgDormCampus> campuses,
+            List<XgDormArea> areas,
+            List<XgDormBuilding> buildings) {
+
+        // 构建校区节点(第一层)
+        Map<Long, DormBuildingTreeVo> campusMap = new LinkedHashMap<>();
+        for (XgDormCampus campus : campuses) {
+            // 检查该校区下是否有宿舍楼(通过宿舍区关联)
+            boolean hasBuildings = buildings.stream().anyMatch(building -> areas.stream().anyMatch(
+                    area -> area.getId().equals(building.getAreaId()) && area.getCampusId().equals(campus.getId())));
+
+            if (hasBuildings) {
+                DormBuildingTreeVo campusNode = new DormBuildingTreeVo();
+                campusNode.setId(campus.getId());
+                campusNode.setLabel(campus.getCampusName());
+                campusNode.setType("campus");
+                campusNode.setDisabled(true); // 校区节点禁止点击
+                campusNode.setChildren(new ArrayList<>());
+                campusMap.put(campus.getId(), campusNode);
+            }
+        }
+
+        // 直接构建宿舍楼节点(第二层),跳过宿舍区
+        for (XgDormBuilding building : buildings) {
+            // 通过宿舍区找到对应的校区
+            XgDormArea area = areas.stream()
+                    .filter(a -> a.getId().equals(building.getAreaId()))
+                    .findFirst()
+                    .orElse(null);
+
+            if (area != null) {
+                DormBuildingTreeVo buildingNode = new DormBuildingTreeVo();
+                buildingNode.setId(building.getId());
+                buildingNode.setLabel(building.getBuildingName());
+                buildingNode.setType("building");
+                buildingNode.setDisabled(false); // 宿舍楼节点可以点击
+                buildingNode.setBuildingFloors(building.getFloors());
+                buildingNode.setBuildingType(building.getBuildingType());
+                buildingNode.setChildren(new ArrayList<>());
+
+                // 直接添加到校区下,跳过宿舍区层级
+                DormBuildingTreeVo campusNode = campusMap.get(area.getCampusId());
+                if (campusNode != null) {
+                    campusNode.getChildren().add(buildingNode);
+                }
+            }
+        }
+
+        return new ArrayList<>(campusMap.values());
+    }
+
     /**
      * 获取班主任管理的班级宿舍楼树
      * 通过当前用户所在的班级,获取该班级分配的宿舍楼

+ 71 - 46
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingServiceImpl.java

@@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.dromara.xg.domain.bo.XgDormBuildingBo;
 import org.dromara.xg.domain.vo.XgDormBuildingVo;
+import org.dromara.xg.domain.vo.XgDormBuildingSimplifiedVo;
 import org.dromara.xg.domain.XgDormBuilding;
 import org.dromara.xg.domain.XgDormArea;
 import org.dromara.xg.domain.XgDormCampus;
@@ -145,7 +146,7 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService {
 
     /**
      * 获取宿舍楼树形结构数据
-     * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
+     * 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
      *
      * @return 宿舍楼树形结构数据
      */
@@ -156,59 +157,41 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService {
                 Wrappers.<XgDormCampus>lambdaQuery()
                         .orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId));
 
-        // 2. 获取所有宿舍区数据
-        List<XgDormArea> areaList = areaMapper.selectList(
-                Wrappers.<XgDormArea>lambdaQuery()
-                        .orderByAsc(XgDormArea::getSortOrder, XgDormArea::getId));
-
-        // 3. 获取所有宿舍楼数据
+        // 2. 获取所有宿舍楼数据
         List<XgDormBuilding> buildingList = baseMapper.selectList(
                 Wrappers.<XgDormBuilding>lambdaQuery()
                         .orderByAsc(XgDormBuilding::getSortOrder, XgDormBuilding::getId));
 
-        // 4. 构建树形结构
+        // 3. 构建树形结构
         List<BuildingTreeSelectVo> treeList = new ArrayList<>();
 
-        // 5. 先构建校区节点
+        // 4. 先构建校区节点
         for (XgDormCampus campus : campusList) {
-            BuildingTreeSelectVo campusNode = new BuildingTreeSelectVo();
-            campusNode.setId(campus.getId());
-            campusNode.setLabel(campus.getCampusName());
-            campusNode.setNodeType("campus");
-            campusNode.setDisabled(true); // 校区不可选
-            campusNode.setChildren(new ArrayList<>());
-
-            // 设置创建者和更新者字段
-            campusNode.setCreateBy(campus.getCreateBy());
-            campusNode.setCreateTime(campus.getCreateTime());
-            campusNode.setUpdateBy(campus.getUpdateBy());
-            campusNode.setUpdateTime(campus.getUpdateTime());
-
-            // 添加该校区下的宿舍区
-            List<XgDormArea> campusAreas = areaList.stream()
-                    .filter(area -> area.getCampusId().equals(campus.getId()))
+            // 检查该校区下是否有宿舍楼
+            List<XgDormBuilding> campusBuildings = buildingList.stream()
+                    .filter(building -> {
+                        // 通过宿舍区找到校区
+                        XgDormArea area = areaMapper.selectById(building.getAreaId());
+                        return area != null && area.getCampusId().equals(campus.getId());
+                    })
                     .collect(Collectors.toList());
 
-            for (XgDormArea area : campusAreas) {
-                BuildingTreeSelectVo areaNode = new BuildingTreeSelectVo();
-                areaNode.setId(area.getId());
-                areaNode.setLabel(area.getAreaName());
-                areaNode.setNodeType("area");
-                areaNode.setDisabled(true); // 宿舍区不可选
-                areaNode.setChildren(new ArrayList<>());
+            if (!campusBuildings.isEmpty()) {
+                BuildingTreeSelectVo campusNode = new BuildingTreeSelectVo();
+                campusNode.setId(campus.getId());
+                campusNode.setLabel(campus.getCampusName());
+                campusNode.setNodeType("campus");
+                campusNode.setDisabled(true); // 校区不可选
+                campusNode.setChildren(new ArrayList<>());
 
                 // 设置创建者和更新者字段
-                areaNode.setCreateBy(area.getCreateBy());
-                areaNode.setCreateTime(area.getCreateTime());
-                areaNode.setUpdateBy(area.getUpdateBy());
-                areaNode.setUpdateTime(area.getUpdateTime());
-
-                // 添加该宿舍区下的宿舍楼
-                List<XgDormBuilding> areaBuildings = buildingList.stream()
-                        .filter(building -> building.getAreaId().equals(area.getId()))
-                        .collect(Collectors.toList());
+                campusNode.setCreateBy(campus.getCreateBy());
+                campusNode.setCreateTime(campus.getCreateTime());
+                campusNode.setUpdateBy(campus.getUpdateBy());
+                campusNode.setUpdateTime(campus.getUpdateTime());
 
-                for (XgDormBuilding building : areaBuildings) {
+                // 直接添加该校区下的宿舍楼,跳过宿舍区层级
+                for (XgDormBuilding building : campusBuildings) {
                     BuildingTreeSelectVo buildingNode = new BuildingTreeSelectVo();
                     buildingNode.setId(building.getId());
                     buildingNode.setLabel(building.getBuildingName());
@@ -222,15 +205,57 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService {
                     buildingNode.setUpdateBy(building.getUpdateBy());
                     buildingNode.setUpdateTime(building.getUpdateTime());
 
-                    areaNode.getChildren().add(buildingNode);
+                    campusNode.getChildren().add(buildingNode);
                 }
 
-                campusNode.getChildren().add(areaNode);
+                treeList.add(campusNode);
             }
-
-            treeList.add(campusNode);
         }
 
         return treeList;
     }
+
+    /**
+     * 分页查询宿舍楼信息简化列表
+     * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 宿舍楼信息简化分页列表
+     */
+    @Override
+    public TableDataInfo<XgDormBuildingSimplifiedVo> querySimplifiedPageList(XgDormBuildingBo bo, PageQuery pageQuery) {
+        // 先查询完整的分页数据
+        TableDataInfo<XgDormBuildingVo> fullPageList = queryPageList(bo, pageQuery);
+
+        // 转换为简化版VO
+        List<XgDormBuildingSimplifiedVo> simplifiedList = fullPageList.getRows().stream()
+                .map(XgDormBuildingSimplifiedVo::fromFullVo)
+                .collect(Collectors.toList());
+
+        // 创建简化版分页结果
+        TableDataInfo<XgDormBuildingSimplifiedVo> simplifiedPageList = new TableDataInfo<>();
+        simplifiedPageList.setRows(simplifiedList);
+        simplifiedPageList.setTotal(fullPageList.getTotal());
+
+        return simplifiedPageList;
+    }
+
+    /**
+     * 查询符合条件的宿舍楼信息简化列表
+     * 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
+     *
+     * @param bo 查询条件
+     * @return 宿舍楼信息简化列表
+     */
+    @Override
+    public List<XgDormBuildingSimplifiedVo> querySimplifiedList(XgDormBuildingBo bo) {
+        // 先查询完整的数据
+        List<XgDormBuildingVo> fullList = queryList(bo);
+
+        // 转换为简化版VO
+        return fullList.stream()
+                .map(XgDormBuildingSimplifiedVo::fromFullVo)
+                .collect(Collectors.toList());
+    }
 }

+ 39 - 0
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingTreeServiceImpl.java

@@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor;
 import org.dromara.xg.service.IXgDormBuildingTreeService;
 import org.dromara.xg.mapper.XgDormBuildingTreeMapper;
 import org.dromara.xg.domain.vo.DormBuildingTreeVo;
+import org.dromara.xg.domain.vo.DormBuildingTreeSimplifiedVo;
 import org.dromara.xg.domain.vo.DormBuildingInfoVo;
 import org.dromara.xg.domain.bo.DormBuildingTreeBo;
 import org.dromara.common.satoken.utils.LoginHelper;
@@ -231,4 +232,42 @@ public class XgDormBuildingTreeServiceImpl implements IXgDormBuildingTreeService
         return new ArrayList<>(campusMap.values());
     }
 
+    /**
+     * 获取宿舍楼树形结构简化数据
+     * 校区-宿舍楼二级结构,隐藏宿舍区层级
+     *
+     * @param bo 查询参数
+     * @return 简化树形结构数据
+     */
+    @Override
+    public List<DormBuildingTreeSimplifiedVo> getSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
+        // 先获取完整的树形结构数据
+        List<DormBuildingTreeVo> fullTreeData = getDormBuildingTree(bo);
+
+        // 转换为简化版树形结构
+        return fullTreeData.stream()
+                .map(DormBuildingTreeSimplifiedVo::fromFullTreeVo)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 获取所有宿舍楼树形结构简化数据(不考虑权限)
+     * 校区-宿舍楼二级结构,隐藏宿舍区层级
+     *
+     * @param bo 查询参数
+     * @return 简化树形结构数据
+     */
+    @Override
+    public List<DormBuildingTreeSimplifiedVo> getAllSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
+        // 先获取完整的树形结构数据(不考虑权限)
+        List<DormBuildingTreeVo> fullTreeData = getAllDormBuildingTree(bo);
+
+        // 转换为简化版树形结构
+        return fullTreeData.stream()
+                .map(DormBuildingTreeSimplifiedVo::fromFullTreeVo)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
 }

+ 2 - 2
backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java

@@ -144,8 +144,8 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
     private LambdaQueryWrapper<XgDormRoom> buildQueryWrapper(XgDormRoomBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<XgDormRoom> lqw = Wrappers.lambdaQuery();
-        lqw.orderByAsc(XgDormRoom::getSort); // 第一优先级:按排序号升序
-        lqw.orderByAsc(XgDormRoom::getFloorNum); // 第二优先级:按楼层升序
+        lqw.orderByAsc(XgDormRoom::getFloorNum); // 第一优先级:按楼层升序
+        lqw.orderByAsc(XgDormRoom::getSort); // 第二优先级:按排序号升序
         lqw.orderByAsc(XgDormRoom::getRoomName); // 第三优先级:按房间名称升序
         lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), XgDormRoom::getRoomCode, bo.getRoomCode());
         lqw.like(StringUtils.isNotBlank(bo.getRoomName()), XgDormRoom::getRoomName, bo.getRoomName());

+ 80 - 1
docs/开发文档/API/宿舍卫生检查管理API.md

@@ -333,4 +333,83 @@ public interface DormHygieneStudentScoreMapper extends BaseMapperPlus<DormHygien
 
 **文档版本:** v1.0  
 **创建时间:** 2025-01-28  
-**维护人员:** 系统开发团队 
+**维护人员:** 系统开发团队 
+
+---
+
+## 修复记录
+
+### 2025-01-29 界面问题修复
+
+#### 修复问题一:新增时个人扣分默认值显示
+**问题现象:** 点击新增按钮时,弹窗中房间学生信息列表的个人扣分列显示默认0分placeholder,而不是直接填入0。
+
+**解决方案:** 修改`DormHygieneCheckDialog.vue`中`loadRoomStudents`方法,将新增模式下学生的`student_score`默认值从`null`改为`0`。
+
+```javascript
+// 修改前
+student_score: student.student_score || null, // 个人得分,默认为空
+
+// 修改后  
+student_score: 0, // 个人得分,新增时默认为0
+```
+
+#### 修复问题二:宿舍扣分变为0时个人扣分不同步更新
+**问题现象:** 当宿舍扣分从1改成0时,房间学生信息列表中个人扣分还是1,没有变成0。
+
+**解决方案:** 修改`handleTotalScoreChange`方法,添加对0分的特别处理逻辑。
+
+```javascript
+// 修改后的逻辑
+const handleTotalScoreChange = () => {
+  // 验证宿舍总分范围
+  if (form.totalScore !== null && form.totalScore !== undefined && form.totalScore !== '') {
+    // 处理非0分情况
+    const score = parseFloat(form.totalScore.toString());
+    if (isNaN(score) || score < 0 || score > 100) {
+      ElMessage.warning('宿舍总分必须在0-100分之间');
+      form.totalScore = 0;
+      return;
+    }
+    // 自动为所有学生设置相同的个人得分(包括0分)
+    if (roomStudents.value.length > 0) {
+      roomStudents.value.forEach((student: any) => {
+        student.student_score = score;
+      });
+      ElMessage.success(`已自动为${roomStudents.value.length}名学生设置个人得分:${score}分`);
+    }
+  } else if (form.totalScore === 0 || form.totalScore === '0') {
+    // 特别处理0分的情况
+    if (roomStudents.value.length > 0) {
+      roomStudents.value.forEach((student: any) => {
+        student.student_score = 0;
+      });
+      ElMessage.success(`已自动为${roomStudents.value.length}名学生设置个人得分:0分`);
+    }
+  }
+};
+```
+
+#### 修复问题三:房间排序问题
+**问题现象:** 选择宿舍楼名称后,房间名称按照sort序号进行排序返回,但因为每层房间的sort都从0开始编码,导致返回数据把每个楼层的第一个房间先返回。
+
+**解决方案:** 修改后端`XgDormRoomServiceImpl.java`中的`buildQueryWrapper`方法,调整排序逻辑为先按楼层再按sort排序。
+
+```java
+// 修改前
+lqw.orderByAsc(XgDormRoom::getSort); // 第一优先级:按排序号升序
+lqw.orderByAsc(XgDormRoom::getFloorNum); // 第二优先级:按楼层升序
+
+// 修改后
+lqw.orderByAsc(XgDormRoom::getFloorNum); // 第一优先级:按楼层升序  
+lqw.orderByAsc(XgDormRoom::getSort); // 第二优先级:按排序号升序
+```
+
+#### 修复效果
+1. **问题一**:新增时个人扣分直接显示0,用户体验更好
+2. **问题二**:宿舍扣分与个人扣分完全同步,包括0分的情况
+3. **问题三**:房间列表按楼层顺序显示,每层内部按sort排序,符合用户期望
+
+#### 涉及文件
+- `web/src/views/xg/xgss/dormHygieneCheck/dormHygieneCheck/DormHygieneCheckDialog.vue`
+- `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java` 

+ 135 - 41
docs/开发文档/API/宿舍楼树形结构API.md

@@ -2,11 +2,13 @@
 
 ## 接口说明
 
-本文档描述了获取宿舍楼树形结构数据的API接口,该接口返回校区-宿舍区-宿舍楼的三级树形结构,其中校区和宿舍区节点不可选,只有宿舍楼节点可以选择。
+本文档描述了获取宿舍楼树形结构数据的API接口。**重要变更**:根据业务需求调整,主要接口已从 "校区-宿舍区-宿舍楼" 三级结构改为 "校区-宿舍楼" 二级结构,隐藏宿舍区层级,简化用户操作。
 
 ## 接口定义
 
-### 获取宿舍楼树形结构
+### 🔄 主要接口(二级结构)
+
+#### 1. 获取宿舍楼树形结构(推荐使用)
 
 **请求URL**:`/sslxx/dormBuilding/buildingTree`
 
@@ -14,6 +16,8 @@
 
 **权限标识**:`sslxx:dormBuilding:list`
 
+**结构说明**:校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
+
 **请求参数**:无
 
 **响应示例**:
@@ -30,24 +34,16 @@
       "disabled": true,
       "children": [
         {
-          "id": 101,
-          "label": "东区宿舍区",
-          "nodeType": "area",
-          "disabled": true,
-          "children": [
-            {
-              "id": 1001,
-              "label": "1号楼",
-              "nodeType": "building",
-              "disabled": false
-            },
-            {
-              "id": 1002,
-              "label": "2号楼",
-              "nodeType": "building",
-              "disabled": false
-            }
-          ]
+          "id": 1001,
+          "label": "1号楼",
+          "nodeType": "building",
+          "disabled": false
+        },
+        {
+          "id": 1002,
+          "label": "2号楼",
+          "nodeType": "building",
+          "disabled": false
         }
       ]
     },
@@ -58,22 +54,92 @@
       "disabled": true,
       "children": [
         {
-          "id": 201,
-          "label": "西区宿舍区",
-          "nodeType": "area",
+          "id": 2001,
+          "label": "3号楼",
+          "nodeType": "building",
+          "disabled": false
+        },
+        {
+          "id": 2002,
+          "label": "4号楼",
+          "nodeType": "building",
+          "disabled": false
+        }
+      ]
+    }
+  ]
+}
+```
+
+#### 2. 获取宿舍楼树形结构(基于权限)
+
+**请求URL**:`/xgss/dormBuildingTree/list`
+
+**请求方式**:`GET`
+
+**权限标识**:`xgss:dormBuildingTree:list`
+
+**结构说明**:校区-宿舍楼二级结构,根据当前用户权限过滤
+
+**请求参数**:
+
+| 参数名     | 类型   | 必填 | 描述           |
+|-----------|--------|------|----------------|
+| campusId  | Long   | 否   | 校区ID过滤条件 |
+| buildingName | String | 否 | 宿舍楼名称过滤条件 |
+
+**响应格式**:与上述接口相同
+
+#### 3. 获取所有宿舍楼树形结构(不考虑权限)
+
+**请求URL**:`/xgss/dormBuildingTree/listAll`
+
+**请求方式**:`GET`
+
+**权限标识**:`xgss:dormBuildingTree:list`
+
+**结构说明**:校区-宿舍楼二级结构,返回所有数据,不进行权限过滤
+
+**响应格式**:与上述接口相同
+
+### 📋 特殊用途接口(三级结构)
+
+#### 4. 获取完整宿舍楼树形结构(包含宿舍区)
+
+**请求URL**:`/xgss/dormBuildingTree/fullList`
+
+**请求方式**:`GET`
+
+**权限标识**:`xgss:dormBuildingTree:list`
+
+**结构说明**:校区-宿舍区-宿舍楼三级结构,仅用于特殊需求
+
+**响应示例**:
+
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    {
+      "id": 1,
+      "label": "东校区",
+      "type": "campus",
+      "disabled": true,
+      "children": [
+        {
+          "id": 101,
+          "label": "东区宿舍区",
+          "type": "area",
           "disabled": true,
           "children": [
             {
-              "id": 2001,
-              "label": "3号楼",
-              "nodeType": "building",
-              "disabled": false
-            },
-            {
-              "id": 2002,
-              "label": "4号楼",
-              "nodeType": "building",
-              "disabled": false
+              "id": 1001,
+              "label": "1号楼",
+              "type": "building",
+              "disabled": false,
+              "buildingFloors": 6,
+              "buildingType": "1"
             }
           ]
         }
@@ -85,7 +151,7 @@
 
 ## 数据结构
 
-### BuildingTreeSelectVo
+### BuildingTreeSelectVo(二级结构)
 
 树形结构节点对象:
 
@@ -93,7 +159,7 @@
 |------------|-------------------|----------------------------------------|
 | id         | Long              | 节点ID                                  |
 | label      | String            | 节点名称                                |
-| nodeType   | String            | 节点类型:campus(校区)、area(宿舍区)、building(宿舍楼) |
+| nodeType   | String            | 节点类型:campus(校区)、building(宿舍楼) |
 | disabled   | Boolean           | 是否禁用选择                            |
 | children   | List<BuildingTreeSelectVo> | 子节点列表                                |
 | createBy   | Long              | 创建者                                  |
@@ -101,6 +167,20 @@
 | updateBy   | Long              | 更新者                                  |
 | updateTime | Date              | 更新时间                                |
 
+### DormBuildingTreeVo(完整结构)
+
+完整三级结构节点对象:
+
+| 字段名           | 类型               | 描述                                    |
+|-----------------|-------------------|----------------------------------------|
+| id              | Long              | 节点ID                                  |
+| label           | String            | 节点名称                                |
+| type            | String            | 节点类型:campus(校区)、area(宿舍区)、building(宿舍楼) |
+| disabled        | Boolean           | 是否禁用选择                            |
+| children        | List<DormBuildingTreeVo> | 子节点列表                                |
+| buildingFloors  | Integer           | 宿舍楼层数(仅宿舍楼节点)              |
+| buildingType    | String            | 宿舍楼类型(仅宿舍楼节点)              |
+
 ## 使用方法
 
 ### 前端使用示例
@@ -114,7 +194,7 @@ import type { BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types';
 // 在组件的setup函数中
 const treeData = ref<BuildingTreeSelectVo[]>([]);
 
-// 加载宿舍楼树形数据
+// 加载宿舍楼树形数据(推荐使用二级结构)
 const loadBuildingTree = async () => {
   try {
     const res = await getBuildingTree();
@@ -155,20 +235,34 @@ loadBuildingTree();
 
 ## 特殊说明
 
-1. 接口返回的树形结构中,校区和宿舍区节点已设置 `disabled=true`,前端无需额外处理即可实现只能选择宿舍楼节点的效果
-2. 使用 `check-strictly=true` 可以确保树形选择器的选中状态不会级联影响父子节点
-3. 该接口已支持管理员分配宿舍楼管理范围的业务需求
+### ⚠️ 重要变更说明
+
+1. **主要接口结构调整**:为简化用户操作,去除宿舍区概念,主要接口已改为二级结构
+2. **向后兼容**:保留了 `fullList` 接口供需要完整三级结构的特殊场景使用
+3. **业务影响**:前端界面将不再显示宿舍区层级,用户直接在校区下选择宿舍楼
+
+### 📋 使用建议
+
+1. **推荐使用二级结构接口**:适用于绝大多数业务场景
+2. **校区节点设置为不可选**:确保用户只能选择宿舍楼
+3. **使用权限过滤接口**:根据用户权限显示相应的宿舍楼范围
 
 ## 相关API接口
 
 - [宿舍管理员授权API](./宿舍管理员授权API.md)
+- [宿舍床位分配管理API](./宿舍床位分配管理API.md)
 
 ## 数据库关系
 
 - `xg_dorm_building` 表通过 `campus_id` 字段关联 `xg_dorm_campus` 表
-- `xg_dorm_building` 表通过 `area_id` 字段关联 `xg_dorm_area` 表
+- `xg_dorm_building` 表通过 `area_id` 字段关联 `xg_dorm_area` 表(数据库保留,UI隐藏)
 - `xg_dorm_area` 表通过 `campus_id` 字段关联 `xg_dorm_campus` 表
 
+## 版本历史
+
+- **2025-01-29**: 接口结构重大调整,主要接口从三级改为二级结构
+- **2025-07-20**: 初始版本,三级结构
+
 ## 最后更新时间
 
-2025-07-20 
+2025-01-29 

+ 2 - 2
docs/设计文档/database/hzdyjs_xg0820.sql

@@ -4376,7 +4376,7 @@ CREATE TABLE `xg_dorm_hygiene_check` (
   `area_name` varchar(100) DEFAULT NULL COMMENT '宿舍区名称',
   `campus_id` bigint(20) DEFAULT NULL COMMENT '校区ID,关联xg_dorm_campus.id',
   `campus_name` varchar(100) DEFAULT NULL COMMENT '校区名称',
-  `total_score` decimal(5,2) DEFAULT NULL COMMENT '宿舍总分(0-100分)',
+  `total_score` decimal(5,2) DEFAULT NULL COMMENT '宿舍扣分(0-100分)',
   `hygiene_grade` char(1) DEFAULT NULL COMMENT '卫生等级(A优秀 B良好 C合格 D不合格)',
   `attachment_ids` text COMMENT '附件OSS ID列表,逗号分隔',
   `check_summary` text COMMENT '检查总结',
@@ -4422,7 +4422,7 @@ CREATE TABLE `xg_dorm_hygiene_student_score` (
   `college_name` varchar(100) DEFAULT NULL COMMENT '学院名称',
   `bed_id` bigint(20) DEFAULT NULL COMMENT '床位ID,关联xg_dorm_bed.id',
   `bed_code` varchar(50) DEFAULT NULL COMMENT '床位编号',
-  `student_score` decimal(5,2) DEFAULT NULL COMMENT '学生个人得分(0-100分)',
+  `student_score` decimal(5,2) DEFAULT NULL COMMENT '学生个人扣分(0-100分)',
   `attendance_status` char(1) DEFAULT '1' COMMENT '出勤状态(1在寝 2外出 3请假 4其他)',
   `student_grade` char(1) DEFAULT NULL COMMENT '学生评级(A优秀 B良好 C合格 D不合格)',
   `is_responsible_person` tinyint(1) DEFAULT '0' COMMENT '是否为寝室长(0否 1是)',

+ 60 - 125
web/src/views/xg/xgss/dormHygieneCheck/dormHygieneCheck/DormHygieneCheckDialog.vue

@@ -1,7 +1,7 @@
 <template>
   <el-dialog :title="dialogTitle" v-model="dialogVisible" width="1200px" append-to-body @close="handleClose">
     <el-form ref="dormHygieneCheckFormRef" :model="form" :rules="rules" label-width="120px">
-      <!-- 第一行:检查标题、校区名称、宿舍区名称 -->
+      <!-- 第一行:检查标题、校区名称、宿舍楼名称 -->
       <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="检查标题" prop="checkTitle">
@@ -23,26 +23,6 @@
             </el-select>
           </el-form-item>
         </el-col>
-        <el-col :span="8">
-          <el-form-item label="宿舍区名称" prop="areaId">
-            <el-select
-              v-model="form.areaId"
-              placeholder="请选择宿舍区"
-              clearable
-              filterable
-              :loading="dormLoading"
-              @change="handleAreaChange"
-              style="width: 100%"
-              :disabled="!form.campusId"
-            >
-              <el-option v-for="area in areaOptions" :key="area.id" :label="area.areaName" :value="area.id" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-      </el-row>
-
-      <!-- 第二行:宿舍楼名称、房间名称、宿舍总分 -->
-      <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="宿舍楼名称" prop="buildingId">
             <el-select
@@ -53,12 +33,16 @@
               :loading="dormLoading"
               @change="handleBuildingChange"
               style="width: 100%"
-              :disabled="!form.areaId"
+              :disabled="!form.campusId"
             >
-              <el-option v-for="building in buildingOptions" :key="building.id" :label="building.buildingName" :value="building.id" />
+              <el-option v-for="building in buildingOptions" :key="building.id" :label="getBuildingDisplayName(building)" :value="building.id" />
             </el-select>
           </el-form-item>
         </el-col>
+      </el-row>
+
+      <!-- 第二行:房间名称、宿舍扣分、卫生等级 -->
+      <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="房间名称" prop="roomId">
             <el-select
@@ -76,10 +60,10 @@
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="宿舍总分" prop="totalScore">
+          <el-form-item label="宿舍扣分" prop="totalScore">
             <el-input
               v-model="form.totalScore"
-              placeholder="请输入宿舍总分(0-100分)"
+              placeholder="请输入宿舍扣分(默认0分)"
               type="number"
               :min="0"
               :max="100"
@@ -88,10 +72,6 @@
             />
           </el-form-item>
         </el-col>
-      </el-row>
-
-      <!-- 第三行:卫生等级、检查类型、检查级别 -->
-      <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="卫生等级" prop="hygieneGrade">
             <el-select v-model="form.hygieneGrade" placeholder="请选择卫生等级" style="width: 100%" @change="handleHygieneGradeChange">
@@ -99,6 +79,10 @@
             </el-select>
           </el-form-item>
         </el-col>
+      </el-row>
+
+      <!-- 第三行:检查类型、检查级别、检查员姓名 -->
+      <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="检查类型" prop="checkType">
             <el-select v-model="form.checkType" placeholder="请选择检查类型" style="width: 100%">
@@ -113,10 +97,6 @@
             </el-select>
           </el-form-item>
         </el-col>
-      </el-row>
-
-      <!-- 第四行:检查员姓名、检查日期 -->
-      <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="检查员姓名" prop="checkerName">
             <el-select
@@ -140,6 +120,10 @@
             </el-select>
           </el-form-item>
         </el-col>
+      </el-row>
+
+      <!-- 第四行:检查日期 -->
+      <el-row :gutter="20">
         <el-col :span="8">
           <el-form-item label="检查日期" prop="checkDate">
             <el-date-picker
@@ -167,12 +151,12 @@
             <div class="room-students-container">
               <div class="room-students-table-wrapper">
                 <el-table :data="roomStudents" stripe size="small" table-layout="auto">
-                  <!-- 学生个人得分 -->
-                  <el-table-column label="个人得分" width="120" fixed="left">
+                  <!-- 学生个人扣分 -->
+                  <el-table-column label="个人扣分" width="120" fixed="left">
                     <template #default="scope">
                       <el-input
                         v-model="scope.row.student_score"
-                        placeholder="0-100分"
+                        placeholder="默认0分"
                         size="small"
                         type="number"
                         :min="0"
@@ -415,14 +399,10 @@ interface CampusOptionVO {
   campusName: string;
 }
 
-interface AreaOptionVO {
-  id: string | number;
-  areaName: string;
-}
-
 interface BuildingOptionVO {
   id: string | number;
   buildingName: string;
+  buildingType?: string; // 宿舍楼类型(1男生楼 2女生楼 3混合楼)
 }
 
 interface RoomOptionVO {
@@ -457,7 +437,6 @@ const dormHygieneCheckFormRef = ref();
 
 // 宿舍级联选择器相关状态
 const campusOptions = ref<CampusOptionVO[]>([]);
-const areaOptions = ref<AreaOptionVO[]>([]);
 const buildingOptions = ref<BuildingOptionVO[]>([]);
 const roomOptions = ref<RoomOptionVO[]>([]);
 const dormLoading = ref(false);
@@ -517,11 +496,9 @@ const initFormData: DormHygieneCheckForm = {
   roomName: undefined,
   buildingId: undefined,
   buildingName: undefined,
-  areaId: undefined,
-  areaName: undefined,
   campusId: undefined,
   campusName: undefined,
-  totalScore: undefined,
+  totalScore: 0,
   hygieneGrade: 'A', // 默认 A - 优秀
   attachmentIds: undefined,
   checkSummary: undefined,
@@ -722,8 +699,7 @@ const resetForm = () => {
   attachmentList.value = [];
   roomStudents.value = [];
 
-  // 清空宿舍级联选项
-  areaOptions.value = [];
+  // 清空宿舍级联选项 - 移除宿舍区相关
   buildingOptions.value = [];
   roomOptions.value = [];
 
@@ -812,15 +788,12 @@ const loadCampusOptions = async () => {
 /** 校区选择变化处理 */
 const handleCampusChange = async (campusId: string | number) => {
   console.log('校区选择变化处理', campusId);
-  // 清空下级选项
-  form.areaId = undefined;
-  form.areaName = undefined;
+  // 清空下级选项 - 移除宿舍区相关字段
   form.buildingId = undefined;
   form.buildingName = undefined;
   form.roomId = undefined;
   form.roomName = undefined;
 
-  areaOptions.value = [];
   buildingOptions.value = [];
   roomOptions.value = [];
 
@@ -832,77 +805,22 @@ const handleCampusChange = async (campusId: string | number) => {
       form.campusName = selectedCampus.campusName;
     }
 
-    // 加载宿舍区选项
-    await loadAreaOptions(campusId);
+    // 直接加载宿舍楼选项(根据校区过滤)
+    await loadBuildingOptions(campusId);
   } else {
     form.campusId = undefined;
     form.campusName = undefined;
   }
 };
 
-/** 加载宿舍区选项 */
-const loadAreaOptions = async (campusId: string | number) => {
-  try {
-    const cacheKey = `area_${campusId}`;
-    const cachedData = getCachedData(cacheKey);
-
-    if (cachedData) {
-      areaOptions.value = cachedData;
-      return;
-    }
-
-    dormLoading.value = true;
-    const res = await request({
-      url: '/ssqxx/dormArea/list',
-      method: 'get',
-      params: { campusId }
-    });
-    const data = res.rows || [];
-    areaOptions.value = data;
-    setCachedData(cacheKey, data);
-  } catch (error) {
-    console.error('加载宿舍区选项失败:', error);
-    areaOptions.value = [];
-  } finally {
-    dormLoading.value = false;
-  }
-};
-
-/** 宿舍区选择变化处理 */
-const handleAreaChange = async (areaId: string | number) => {
-  // 清空下级选项
-  form.buildingId = undefined;
-  form.buildingName = undefined;
-  form.roomId = undefined;
-  form.roomName = undefined;
-
-  buildingOptions.value = [];
-  roomOptions.value = [];
-
-  if (areaId) {
-    // 设置宿舍区名称
-    const selectedArea = areaOptions.value.find((area) => area.id === areaId);
-    if (selectedArea) {
-      form.areaId = areaId;
-      form.areaName = selectedArea.areaName;
-    }
-
-    // 加载宿舍楼选项
-    await loadBuildingOptions(areaId);
-  } else {
-    form.areaId = undefined;
-    form.areaName = undefined;
-  }
-};
-
-/** 加载宿舍楼选项 */
-const loadBuildingOptions = async (areaId: string | number) => {
+/** 加载宿舍楼选项 - 修改为直接根据校区ID过滤 */
+const loadBuildingOptions = async (campusId: string | number) => {
   try {
     dormLoading.value = true;
     const res = await request({
       url: '/sslxx/dormBuilding/list',
       method: 'get',
-      params: { areaId }
+      params: { campusId } // 直接使用校区ID过滤,不再使用areaId
     });
     buildingOptions.value = res.rows || [];
   } catch (error) {
@@ -1075,18 +993,13 @@ const loadCascadeOptionsForUpdate = async (formData: DormHygieneCheckForm) => {
     // 并行加载所有需要的宿舍选项,提升性能
     const loadTasks = [];
 
-    // 如果有校区ID,加载宿舍区选项
+    // 如果有校区ID,加载宿舍楼选项
     if (formData.campusId) {
-      loadTasks.push(loadAreaOptions(formData.campusId));
-
-      // 如果有宿舍区ID,加载宿舍楼选项
-      if (formData.areaId) {
-        loadTasks.push(loadBuildingOptions(formData.areaId));
+      loadTasks.push(loadBuildingOptions(formData.campusId));
 
-        // 如果有宿舍楼ID,加载房间选项
-        if (formData.buildingId) {
-          loadTasks.push(loadRoomOptions(formData.buildingId));
-        }
+      // 如果有宿舍楼ID,加载房间选项
+      if (formData.buildingId) {
+        loadTasks.push(loadRoomOptions(formData.buildingId));
       }
     }
 
@@ -1163,7 +1076,7 @@ const loadRoomStudents = async () => {
       // 为每个学生设置默认值
       roomStudents.value = res.data.map((student: any) => ({
         ...student,
-        student_score: student.student_score || null, // 个人得分,默认为空
+        student_score: 0, // 个人得分,新增时默认为0
         attendance_status: student.attendance_status || '1', // 出勤状态,默认1-在寝
         student_grade: student.student_grade || 'A' // 学生评级,默认A-优秀
       }));
@@ -1414,6 +1327,20 @@ const handleAttachmentData = async () => {
   }
 };
 
+// 宿舍楼选项显示格式
+const getBuildingDisplayName = (building: BuildingOptionVO) => {
+  let displayName = building.buildingName;
+  if (building.buildingType) {
+    if (building.buildingType === '1') {
+      displayName = `(男)${displayName}`;
+    } else if (building.buildingType === '2') {
+      displayName = `(女)${displayName}`;
+    }
+    // 混合楼(3)不显示性别标识
+  }
+  return displayName;
+};
+
 // 组件挂载时加载校区选项
 const initCampusOptions = async () => {
   await loadCampusOptions();
@@ -1482,21 +1409,29 @@ const handleStudentGradeChange = (student: any) => {
 // 处理宿舍总分变化 - 自动填写学生个人得分
 const handleTotalScoreChange = () => {
   // 验证宿舍总分范围
-  if (form.totalScore !== null && form.totalScore !== undefined && form.totalScore !== 0 && String(form.totalScore) !== '0') {
+  if (form.totalScore !== null && form.totalScore !== undefined && form.totalScore !== '') {
     const score = parseFloat(form.totalScore.toString());
     if (isNaN(score) || score < 0 || score > 100) {
       ElMessage.warning('宿舍总分必须在0-100分之间');
-      form.totalScore = null;
+      form.totalScore = 0;
       return;
     }
 
-    // 如果分数有效且有学生,自动为所有学生设置相同的个人得分
+    // 如果分数有效且有学生,自动为所有学生设置相同的个人得分(包括0分)
     if (roomStudents.value.length > 0) {
       roomStudents.value.forEach((student: any) => {
         student.student_score = score;
       });
       ElMessage.success(`已自动为${roomStudents.value.length}名学生设置个人得分:${score}分`);
     }
+  } else if (form.totalScore === 0 || form.totalScore === '0') {
+    // 特别处理0分的情况
+    if (roomStudents.value.length > 0) {
+      roomStudents.value.forEach((student: any) => {
+        student.student_score = 0;
+      });
+      ElMessage.success(`已自动为${roomStudents.value.length}名学生设置个人得分:0分`);
+    }
   }
 };
 

+ 6 - 6
web/src/views/xg/xgss/dormHygieneCheck/dormHygieneCheck/index.vue

@@ -106,9 +106,8 @@
         </el-table-column>
         <el-table-column label="房间名称" align="center" prop="roomName" />
         <el-table-column label="宿舍楼名称" align="center" prop="buildingName" />
-        <el-table-column label="宿舍区名称" align="center" prop="areaName" />
         <el-table-column label="校区名称" align="center" prop="campusName" />
-        <el-table-column label="宿舍总分" align="center" prop="totalScore" />
+        <el-table-column label="宿舍扣分" align="center" prop="totalScore" />
         <el-table-column label="卫生等级" align="center" prop="hygieneGrade">
           <template #default="scope">
             <dict-tag :options="xg_dorm_hygiene_grade" :value="scope.row.hygieneGrade" />
@@ -138,16 +137,17 @@
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" :total="total" :page="queryParams.pageNum" :limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
 
     <!-- 宿舍卫生检查弹窗组件 -->
     <DormHygieneCheckDialog
-      v-model="dialog.visible"
+      :visible="dialog.visible"
       :title="dialog.title"
       :form-data="form"
       @submit="handleDialogSubmit"
       @close="handleDialogClose"
+      @update:visible="(value) => (dialog.visible = value)"
     />
   </div>
 </template>
@@ -164,7 +164,7 @@ import {
   addDormHygieneCheck,
   updateDormHygieneCheck,
   exportDormHygieneCheck
-} from '@/api/xg/xgss/dormHygieneCheck/dormHygieneCheck';
+} from '@/api/xg/xgss/dormHygieneCheck/dormHygieneCheck/index';
 import {
   DormHygieneCheckVO,
   DormHygieneCheckQuery,
@@ -223,7 +223,7 @@ const initFormData: DormHygieneCheckForm = {
   areaName: undefined,
   campusId: undefined,
   campusName: undefined,
-  totalScore: undefined,
+  totalScore: 0,
   hygieneGrade: 'A',
   attachmentIds: undefined,
   checkSummary: undefined,

+ 48 - 271
web/src/views/xg/xgss/sslxx/dormBuilding/index.vue

@@ -17,24 +17,11 @@
               </el-col>
               <el-col :span="6">
                 <el-form-item label="所属校区" prop="campusId">
-                  <el-select v-model="queryParams.campusId" placeholder="请选择所属校区" clearable @change="handleCampusChange">
+                  <el-select v-model="queryParams.campusId" placeholder="请选择所属校区" clearable>
                     <el-option v-for="item in campusList" :key="item.id" :label="item.campusName" :value="item.id" />
                   </el-select>
                 </el-form-item>
               </el-col>
-              <el-col :span="6">
-                <el-form-item label="所属宿舍区" prop="areaId">
-                  <el-tree-select
-                    v-model="queryParams.areaId"
-                    :data="areaTreeData"
-                    :props="{ label: 'areaName', value: 'id' }"
-                    placeholder="请选择所属宿舍区"
-                    clearable
-                  />
-                </el-form-item>
-              </el-col>
-            </el-row>
-            <el-row :gutter="20">
               <el-col :span="6">
                 <el-form-item label="宿舍楼类型" prop="buildingType">
                   <el-select v-model="queryParams.buildingType" placeholder="请选择宿舍楼类型" clearable>
@@ -72,9 +59,6 @@
               >删除</el-button
             >
           </el-col>
-          <!-- <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['sslxx:dormBuilding:export']">导出</el-button>
-          </el-col> -->
           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
         </el-row>
       </template>
@@ -85,7 +69,6 @@
         <el-table-column label="宿舍楼编码" align="center" prop="buildingCode" />
         <el-table-column label="宿舍楼名称" align="center" prop="buildingName" />
         <el-table-column label="所属校区" align="center" prop="campusName" />
-        <el-table-column label="所属宿舍区" align="center" prop="areaName" />
         <el-table-column label="总楼层数" align="center" prop="floors" />
         <el-table-column label="宿舍楼类型" align="center" prop="buildingType">
           <template #default="scope">
@@ -112,19 +95,10 @@
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
       <el-form ref="dormBuildingFormRef" :model="form" :rules="rules" label-width="120px">
         <el-form-item label="所属校区" prop="campusId">
-          <el-select v-model="form.campusId" placeholder="请选择所属校区" clearable @change="handleFormCampusChange">
+          <el-select v-model="form.campusId" placeholder="请选择所属校区" clearable>
             <el-option v-for="item in campusList" :key="item.id" :label="item.campusName" :value="item.id" />
           </el-select>
         </el-form-item>
-        <el-form-item label="所属宿舍区" prop="areaId">
-          <el-tree-select
-            v-model="form.areaId"
-            :data="formAreaTreeData"
-            :props="{ label: 'areaName', value: 'id' }"
-            placeholder="请选择所属宿舍区"
-            clearable
-          />
-        </el-form-item>
         <el-form-item label="宿舍楼编码" prop="buildingCode">
           <el-input v-model="form.buildingCode" placeholder="请输入宿舍楼编码" />
         </el-form-item>
@@ -171,13 +145,12 @@ import {
   delDormBuilding,
   addDormBuilding,
   updateDormBuilding,
-  listCampusOptions,
-  listAreaTreeData
+  listCampusOptions
 } from '@/api/xg/xgss/sslxx/dormBuilding';
 import { DormBuildingVO, DormBuildingQuery, DormBuildingForm } from '@/api/xg/xgss/sslxx/dormBuilding/types';
 import { DormCampusVO } from '@/api/xg/xgss/xqxx/dormCampus/types';
-import { DormAreaVO } from '@/api/xg/xgss/ssqxx/dormArea/types';
 import { getCurrentInstance, ComponentInternalInstance, ref, reactive, toRefs, onMounted } from 'vue';
+import { ElForm, ElMessageBox, ElMessage } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { dorm_type } = toRefs<any>(proxy?.useDict('dorm_type'));
@@ -191,11 +164,9 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 const campusList = ref<DormCampusVO[]>([]); // 校区列表
-const areaTreeData = ref<any[]>([]); // 宿舍区树形数据
-const formAreaTreeData = ref<any[]>([]); // 表单宿舍区树形数据
 
-const queryFormRef = ref<ElFormInstance>();
-const dormBuildingFormRef = ref<ElFormInstance>();
+const queryFormRef = ref<InstanceType<typeof ElForm>>();
+const dormBuildingFormRef = ref<InstanceType<typeof ElForm>>();
 
 const dialog = reactive<DialogOption>({
   visible: false,
@@ -206,7 +177,6 @@ const initFormData: DormBuildingForm = {
   id: undefined,
   buildingCode: undefined,
   buildingName: undefined,
-  areaId: undefined,
   campusId: undefined,
   buildingType: undefined,
   buildingDescription: undefined,
@@ -220,7 +190,6 @@ const data = reactive<PageData<DormBuildingForm, DormBuildingQuery>>({
     pageSize: 10,
     buildingCode: undefined,
     buildingName: undefined,
-    areaId: undefined,
     campusId: undefined,
     buildingType: undefined,
     sortOrder: undefined,
@@ -230,7 +199,6 @@ const data = reactive<PageData<DormBuildingForm, DormBuildingQuery>>({
     id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
     buildingCode: [{ required: true, message: '宿舍楼编码不能为空', trigger: 'blur' }],
     buildingName: [{ required: true, message: '宿舍楼名称不能为空', trigger: 'blur' }],
-    areaId: [{ required: true, message: '所属宿舍区ID不能为空', trigger: 'blur' }],
     campusId: [{ required: true, message: '所属校区ID不能为空', trigger: 'blur' }]
   }
 });
@@ -252,102 +220,6 @@ const loadCampusOptions = async () => {
   campusList.value = res.rows || [];
 };
 
-/** 加载宿舍区树形数据 */
-const loadAreaTreeData = async (campusId?: string | number) => {
-  const res = await listAreaTreeData(campusId);
-  if (campusId) {
-    // 如果指定了校区ID,只展示该校区的宿舍区
-    areaTreeData.value = res.rows || [];
-    formAreaTreeData.value = res.rows || []; // 同时更新表单树形数据
-  } else {
-    // 如果没有指定校区ID,按照校区分组展示宿舍区
-    const campusMap = new Map();
-
-    // 先将校区列表转为Map
-    campusList.value.forEach((campus) => {
-      campusMap.set(campus.id, {
-        id: campus.id,
-        areaName: campus.campusName,
-        children: []
-      });
-    });
-
-    // 将宿舍区按校区分组
-    const areas = res.rows || [];
-    areas.forEach((area: DormAreaVO) => {
-      if (campusMap.has(area.campusId)) {
-        campusMap.get(area.campusId).children.push({
-          id: area.id,
-          areaName: area.areaName
-        });
-      }
-    });
-
-    // 转换为树形结构
-    areaTreeData.value = Array.from(campusMap.values());
-    formAreaTreeData.value = Array.from(campusMap.values());
-  }
-};
-
-/** 校区选择变化处理函数 */
-const handleCampusChange = (value: string | number) => {
-  queryParams.value.areaId = undefined; // 清空已选择的宿舍区
-  loadAreaTreeData(value);
-};
-
-/** 表单校区选择变化处理函数 */
-const handleFormCampusChange = (value: string | number) => {
-  form.value.areaId = undefined; // 清空已选择的宿舍区
-  loadFormAreaTreeData(value);
-};
-
-/** 加载表单宿舍区树形数据 */
-const loadFormAreaTreeData = async (campusId?: string | number) => {
-  const res = await listAreaTreeData(campusId);
-  if (campusId) {
-    // 如果指定了校区ID,只展示该校区的宿舍区
-    formAreaTreeData.value = res.rows || [];
-  } else {
-    // 如果没有指定校区ID,按照校区分组展示宿舍区
-    const campusMap = new Map();
-
-    // 先将校区列表转为Map
-    campusList.value.forEach((campus) => {
-      campusMap.set(campus.id, {
-        id: campus.id,
-        areaName: campus.campusName,
-        children: []
-      });
-    });
-
-    // 将宿舍区按校区分组
-    const areas = res.rows || [];
-    areas.forEach((area: DormAreaVO) => {
-      if (campusMap.has(area.campusId)) {
-        campusMap.get(area.campusId).children.push({
-          id: area.id,
-          areaName: area.areaName
-        });
-      }
-    });
-
-    // 转换为树形结构
-    formAreaTreeData.value = Array.from(campusMap.values());
-  }
-};
-
-/** 取消按钮 */
-const cancel = () => {
-  reset();
-  dialog.visible = false;
-};
-
-/** 表单重置 */
-const reset = () => {
-  form.value = { ...initFormData };
-  dormBuildingFormRef.value?.resetFields();
-};
-
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
@@ -363,7 +235,7 @@ const resetQuery = () => {
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: DormBuildingVO[]) => {
   ids.value = selection.map((item) => item.id);
-  single.value = selection.length != 1;
+  single.value = selection.length !== 1;
   multiple.value = !selection.length;
 };
 
@@ -380,10 +252,6 @@ const handleUpdate = async (row?: DormBuildingVO) => {
   const _id = row?.id || ids.value[0];
   const res = await getDormBuilding(_id);
   Object.assign(form.value, res.data);
-  // 加载表单中的宿舍区数据
-  if (form.value.campusId) {
-    loadFormAreaTreeData(form.value.campusId);
-  }
   dialog.visible = true;
   dialog.title = '修改宿舍楼信息';
 };
@@ -394,13 +262,22 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateDormBuilding(form.value).finally(() => (buttonLoading.value = false));
+        await updateDormBuilding(form.value)
+          .then(() => {
+            ElMessage.success('修改成功');
+            dialog.visible = false;
+            getList();
+          })
+          .finally(() => (buttonLoading.value = false));
       } else {
-        await addDormBuilding(form.value).finally(() => (buttonLoading.value = false));
+        await addDormBuilding(form.value)
+          .then(() => {
+            ElMessage.success('新增成功');
+            dialog.visible = false;
+            getList();
+          })
+          .finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess('操作成功');
-      dialog.visible = false;
-      await getList();
     }
   });
 };
@@ -408,148 +285,48 @@ const submitForm = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: DormBuildingVO) => {
   const _ids = row?.id || ids.value;
+  await ElMessageBox.confirm('是否确认删除宿舍楼信息编号为"' + _ids + '"的数据项?')
+    .then(() => {
+      loading.value = true;
+      return delDormBuilding(_ids);
+    })
+    .then(() => {
+      loading.value = false;
+      getList();
+      ElMessage.success('删除成功');
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
 
-  let confirmMsg = '';
-  if (row) {
-    confirmMsg = `是否确认删除宿舍楼信息编号为"${row?.buildingName}"的数据项?`;
-  } else if (Array.isArray(ids.value) && ids.value.length > 1) {
-    confirmMsg = `是否确认删除选中的${ids.value.length}个宿舍楼信息?`;
-  } else {
-    confirmMsg = '是否确认删除选中的宿舍楼信息?';
-  }
-  await proxy?.$modal.confirm(confirmMsg).finally(() => (loading.value = false));
-
-  await delDormBuilding(_ids);
-  proxy?.$modal.msgSuccess('删除成功');
-  await getList();
+/** 重置操作表单 */
+const reset = () => {
+  form.value = { ...initFormData };
+  dormBuildingFormRef.value?.resetFields();
 };
 
-/** 导出按钮操作 */
-const handleExport = () => {
-  proxy?.download(
-    'sslxx/dormBuilding/export',
-    {
-      ...queryParams.value
-    },
-    `dormBuilding_${new Date().getTime()}.xlsx`
-  );
+/** 取消按钮 */
+const cancel = () => {
+  dialog.visible = false;
+  reset();
 };
 
 onMounted(() => {
   getList();
-  loadCampusOptions().then(() => {
-    loadAreaTreeData();
-  });
+  loadCampusOptions();
 });
 </script>
+
 <style scoped>
-/* 页面容器样式 */
 .page-container {
-  padding: 8px;
-}
-
-/* 表格卡片布局 */
-.table-card {
-  margin-top: 0;
-}
-
-.table-card :deep(.el-card__body) {
-  padding: 0px 20px 20px 20px !important;
-}
-
-/* 移除按钮栏底部边框 */
-.button-card :deep(.el-card__header) {
-  border-bottom: none !important;
-}
-
-.image-gallery {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 12px;
-  padding: 8px;
-}
-
-.image-item {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  border: 1px solid #dcdfe6;
-  border-radius: 6px;
-  background-color: #fff;
-  padding: 4px;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-  transition: all 0.3s ease;
-}
-
-.image-item:hover {
-  transform: translateY(-2px);
-  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
-
-.no-image {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 120px;
-  height: 80px;
-  border: 1px dashed #dcdfe6;
-  border-radius: 4px;
-  background-color: #fafafa;
-}
-
-.no-image-text {
-  color: #909399;
-  font-size: 12px;
-  text-align: center;
-}
-
-.table-no-image {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 50px;
-  height: 50px;
-  border: 1px dashed #dcdfe6;
-  border-radius: 4px;
-  background-color: #fafafa;
-  margin: 0 auto;
-}
-
-.table-no-image-text {
-  color: #909399;
-  font-size: 10px;
-  text-align: center;
-}
-
-.view-text {
-  font-size: 14px;
-  color: #303133;
-  line-height: 1.5;
+  background-color: #f5f5f5;
 }
 
-.view-description {
-  padding: 12px;
-  border: 1px solid #e4e7ed;
-  border-radius: 4px;
-  width: 100%;
-  height: 200px;
-  font-size: 14px;
-  color: #303133;
-  line-height: 1.6;
-  white-space: pre-wrap;
-  word-break: break-word;
-  overflow-y: auto;
-}
-/* 搜索按钮容器样式 */
 .search-btn-container {
-  display: flex;
-  justify-content: flex-end;
-  margin-top: 10px;
-
-  .el-form-item {
-    margin-bottom: 0 !important;
-  }
+  text-align: left;
 }
+
 .fixed-width-input {
   width: 100%;
 }

+ 121 - 43
web/src/views/xg/xgss/xsssfjgl/index.vue

@@ -98,52 +98,73 @@
               </el-row>
             </template>
 
-            <!-- 楼层卡片 -->
-            <div v-for="floor in floorList" :key="floor" class="mb-4">
-              <el-divider>
-                <el-tag type="success" effect="dark" class="mr-2">{{ floor }}层</el-tag>
-                <el-button type="primary" icon="Plus" size="small" @click="handleAddAllRoom(floor)">自动添加房间</el-button>
-                <el-button type="primary" icon="Plus" size="small" @click="handleAddRoom(floor)">添加房间</el-button>
-              </el-divider>
-
-              <div class="room-container">
-                <el-empty v-if="getRoomsByFloor(floor).length === 0" description="暂无房间数据" />
-                <div v-else class="room-grid">
-                  <el-card
-                    v-for="room in getRoomsByFloor(floor)"
-                    :key="room.id"
-                    class="room-card"
-                    :class="{ 'room-disabled': room.roomStatus !== '0' }"
-                  >
-                    <template #header>
-                      <div class="flex items-center justify-between">
-                        <span class="font-bold">{{ room.roomName }}</span>
-                        <div>
-                          <el-tag v-if="room.roomStatus === '0'" type="success" size="small">正常</el-tag>
-                          <el-tag v-else-if="room.roomStatus === '1'" type="warning" size="small">维修中</el-tag>
-                          <el-tag v-else type="danger" size="small">停用</el-tag>
-                        </div>
-                      </div>
-                    </template>
-                    <div class="room-info">
-                      <div class="mb-2">
-                        <span class="text-gray-500">类型:</span>{{ room.roomType === '1' ? '标准间' : room.roomType === '2' ? '单人间' : '套间' }}
-                      </div>
-                      <div class="mb-2"><span class="text-gray-500">床位:</span>{{ room.currentBeds || 0 }}/{{ room.actualBeds }}</div>
-                      <div class="mb-2"><span class="text-gray-500">排序:</span>{{ room.sort || 0 }}</div>
-                      <div class="flex justify-between mt-4">
-                        <div>
-                          <el-button type="primary" link size="small" @click="handleManageBeds(room)">床位管理</el-button>
-                        </div>
-                        <div>
-                          <el-button type="primary" link icon="Edit" @click="handleEditRoom(room)" />
-                          <el-button type="danger" link icon="Delete" @click="handleDeleteRoom(room)" />
+            <!-- 右侧房间信息区域 -->
+            <div class="room-info-area">
+              <!-- 加载状态 -->
+              <div v-if="roomLoading" class="loading-container">
+                <div class="loading-content">
+                  <el-icon class="loading-icon" :size="32">
+                    <Loading />
+                  </el-icon>
+                  <p class="loading-text">正在加载房间数据...</p>
+                </div>
+              </div>
+
+              <!-- 房间数据展示 -->
+              <div v-else-if="roomList.length > 0" class="room-display">
+                <div v-for="floor in floorList" :key="floor" class="mb-4">
+                  <el-divider>
+                    <el-tag type="success" effect="dark" class="mr-2">{{ floor }}层</el-tag>
+                    <el-button type="primary" icon="Plus" size="small" @click="handleAddAllRoom(floor)">自动添加房间</el-button>
+                    <el-button type="primary" icon="Plus" size="small" @click="handleAddRoom(floor)">添加房间</el-button>
+                  </el-divider>
+
+                  <div class="room-container">
+                    <el-empty v-if="getRoomsByFloor(floor).length === 0" description="暂无房间数据" />
+                    <div v-else class="room-grid">
+                      <el-card
+                        v-for="room in getRoomsByFloor(floor)"
+                        :key="room.id"
+                        class="room-card"
+                        :class="{ 'room-disabled': room.roomStatus !== '0' }"
+                      >
+                        <template #header>
+                          <div class="flex items-center justify-between">
+                            <span class="font-bold">{{ room.roomName }}</span>
+                            <div>
+                              <el-tag v-if="room.roomStatus === '0'" type="success" size="small">正常</el-tag>
+                              <el-tag v-else-if="room.roomStatus === '1'" type="warning" size="small">维修中</el-tag>
+                              <el-tag v-else type="danger" size="small">停用</el-tag>
+                            </div>
+                          </div>
+                        </template>
+                        <div class="room-info">
+                          <div class="mb-2">
+                            <span class="text-gray-500">类型:</span
+                            >{{ room.roomType === '1' ? '标准间' : room.roomType === '2' ? '单人间' : '套间' }}
+                          </div>
+                          <div class="mb-2"><span class="text-gray-500">床位:</span>{{ room.currentBeds || 0 }}/{{ room.actualBeds }}</div>
+                          <div class="mb-2"><span class="text-gray-500">排序:</span>{{ room.sort || 0 }}</div>
+                          <div class="flex justify-between mt-4">
+                            <div>
+                              <el-button type="primary" size="small" @click="handleManageBeds(room)">床位管理</el-button>
+                            </div>
+                            <div>
+                              <el-button type="primary" link size="small" icon="Edit" @click="handleEditRoom(room)" />
+                              <el-button type="danger" link size="small" icon="Delete" @click="handleDeleteRoom(room)" />
+                            </div>
+                          </div>
                         </div>
-                      </div>
+                      </el-card>
                     </div>
-                  </el-card>
+                  </div>
                 </div>
               </div>
+
+              <!-- 空状态展示 -->
+              <div v-else class="empty-state">
+                <el-empty description="请先选择左侧宿舍楼查看房间信息" />
+              </div>
             </div>
           </el-card>
         </template>
@@ -213,7 +234,7 @@
 <script setup name="DormRoomManagement" lang="ts">
 import { ref, computed, reactive, onMounted, nextTick, watch } from 'vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
-import { InfoFilled, Search } from '@element-plus/icons-vue';
+import { InfoFilled, Search, Loading } from '@element-plus/icons-vue';
 import { DormTreeNode, BedInfo, DormQuery, BedForm } from '@/api/xg/xgss/xsssfjgl/types';
 import { DormRoomVO, DormRoomQuery } from '@/api/xg/xgss/dormRoom/types';
 import { getDormTree } from '@/api/xg/xgss/xsssfjgl';
@@ -230,6 +251,8 @@ const dormTreeRef = ref();
 const queryFormRef = ref();
 const buildingName = ref('');
 const showSearch = ref(true);
+// 添加房间数据加载状态
+const roomLoading = ref(false);
 const animate = reactive({
   searchAnimate: {
     enter: 'animate__animated animate__fadeInDown',
@@ -356,6 +379,9 @@ const handleNodeClick = (data: DormTreeNode) => {
 const loadRoomData = async () => {
   if (!queryParams.buildingId) return;
 
+  // 开始加载,设置loading状态
+  roomLoading.value = true;
+
   try {
     const res = await listDormRoom(queryParams);
     roomList.value = res?.rows;
@@ -375,6 +401,9 @@ const loadRoomData = async () => {
     );
   } catch (error) {
     console.error('获取房间列表失败', error);
+  } finally {
+    // 加载完成,取消loading状态
+    roomLoading.value = false;
   }
 };
 
@@ -862,4 +891,53 @@ watch(
   min-width: 100%; /* 确保树至少占满容器宽度 */
   width: max-content; /* 允许内容扩展 */
 }
+
+/* 加载状态样式 */
+.loading-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: 400px;
+  background: #fafafa;
+  border-radius: 8px;
+  border: 1px dashed #d9d9d9;
+  margin: 20px 0;
+}
+
+.loading-content {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 16px;
+}
+
+.loading-icon {
+  color: var(--el-color-primary);
+  animation: rotate 1s linear infinite;
+}
+
+@keyframes rotate {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+.loading-text {
+  font-size: 14px;
+  color: var(--el-text-color-regular);
+  margin: 0;
+  font-weight: 500;
+}
+
+/* 空状态样式 */
+.empty-state {
+  min-height: 400px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
 </style>

+ 2 - 1
web/src/views/xg/xgss/xsssgly/index.vue

@@ -103,8 +103,8 @@
             </el-table>
           </el-card>
         </el-tab-pane>
+        <!-- 隐藏宿舍区管理员tab页
         <el-tab-pane label="宿舍区管理员" name="area">
-          <!-- 检索栏(宿舍区管理员) -->
           <div class="mb-[10px]">
             <el-card shadow="hover">
               <el-form :inline="true" :model="areaSearchForm" class="search-form">
@@ -155,6 +155,7 @@
             </el-table>
           </el-card>
         </el-tab-pane>
+        -->
         <el-tab-pane label="宿舍楼管理员" name="building">
           <!-- 检索栏(宿舍楼管理员) -->
           <div class="mb-[10px]">