From 7ce20647f079a2dd9b2c0577caea635d5d4f135e Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Mon, 21 Jul 2025 20:15:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xg/controller/XgDormAreaController.java | 17 +- .../controller/XgDormBuildingController.java | 18 +- .../XgDormManagerSourceController.java | 16 +- .../xg/domain/bo/XgDormManagerSourceBo.java | 1 - .../xg/domain/vo/BuildingTreeSelectVo.java | 65 +++ .../dromara/xg/domain/vo/TreeSelectVo.java | 63 +++ .../xg/domain/vo/XgDormManagerSourceVo.java | 3 - .../xg/mapper/XgDormManagerSourceMapper.java | 26 ++ .../xg/service/IXgDormAreaService.java | 9 + .../xg/service/IXgDormBuildingService.java | 9 + .../service/IXgDormManagerSourceService.java | 35 +- .../service/impl/XgDormAreaServiceImpl.java | 59 +++ .../impl/XgDormBuildingServiceImpl.java | 100 +++++ .../impl/XgDormManagerSourceServiceImpl.java | 106 +++-- .../glysqgx/XgDormManagerSourceMapper.xml | 41 ++ .../code-adjust-record-2025-07-20-zlwu.md | 68 ++++ docs/开发文档/API/API文档总览.md | 199 ++-------- docs/开发文档/API/宿舍楼树形结构API.md | 174 +++++++++ docs/开发文档/API/宿舍管理员授权API.md | 112 ++++++ web/src/api/ssglyxx/dormManager/index.ts | 34 ++ web/src/api/ssglyxx/dormManager/types.ts | 5 + web/src/api/sslxx/dormBuilding/index.ts | 13 +- web/src/api/sslxx/dormBuilding/types.ts | 127 ++---- web/src/api/ssqxx/dormArea/index.ts | 13 +- web/src/api/ssqxx/dormArea/types.ts | 16 + .../views/xsssgly/components/ScopeDialog.vue | 369 ++++++++++++++++-- web/src/views/xsssgly/index.vue | 169 +++++--- 工程本地启动指导.md | 4 +- 28 files changed, 1451 insertions(+), 420 deletions(-) create mode 100644 backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/BuildingTreeSelectVo.java create mode 100644 backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/TreeSelectVo.java create mode 100644 docs/变更管理/code-adjust-record-2025-07-20-zlwu.md create mode 100644 docs/开发文档/API/宿舍楼树形结构API.md create mode 100644 docs/开发文档/API/宿舍管理员授权API.md diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormAreaController.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormAreaController.java index 97bbc3a1..aa265e96 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormAreaController.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormAreaController.java @@ -19,6 +19,7 @@ import org.dromara.common.log.enums.BusinessType; import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.xg.domain.vo.XgDormAreaVo; import org.dromara.xg.domain.bo.XgDormAreaBo; +import org.dromara.xg.domain.vo.TreeSelectVo; import org.dromara.xg.service.IXgDormAreaService; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -63,8 +64,7 @@ public class XgDormAreaController extends BaseController { */ @SaCheckPermission("ssqxx:dormArea:query") @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { return R.ok(xgDormAreaService.queryById(id)); } @@ -98,8 +98,17 @@ public class XgDormAreaController extends BaseController { @SaCheckPermission("ssqxx:dormArea:remove") @Log(title = "宿舍区信息", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { return toAjax(xgDormAreaService.deleteWithValidByIds(List.of(ids), true)); } + + /** + * 获取宿舍区树形结构数据 + * 以校区为根节点,宿舍区为子节点 + */ + @SaCheckPermission("ssqxx:dormArea:query") + @GetMapping("/tree") + public R> getAreaTree() { + return R.ok(xgDormAreaService.getAreaTree()); + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingController.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingController.java index fb7f45c2..30420e62 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingController.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormBuildingController.java @@ -19,6 +19,7 @@ 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.bo.XgDormBuildingBo; +import org.dromara.xg.domain.vo.BuildingTreeSelectVo; import org.dromara.xg.service.IXgDormBuildingService; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -63,8 +64,7 @@ public class XgDormBuildingController extends BaseController { */ @SaCheckPermission("sslxx:dormBuilding:query") @GetMapping("/{id}") - public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { return R.ok(xgDormBuildingService.queryById(id)); } @@ -98,8 +98,18 @@ public class XgDormBuildingController extends BaseController { @SaCheckPermission("sslxx:dormBuilding:remove") @Log(title = "宿舍楼信息", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") - public R remove(@NotEmpty(message = "主键不能为空") - @PathVariable Long[] ids) { + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { return toAjax(xgDormBuildingService.deleteWithValidByIds(List.of(ids), true)); } + + /** + * 获取宿舍楼树形结构数据 + * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择 + */ + @SaCheckPermission("sslxx:dormBuilding:list") + @GetMapping("/buildingTree") + public R> getBuildingTree() { + List treeData = xgDormBuildingService.getBuildingTreeData(); + return R.ok(treeData); + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormManagerSourceController.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormManagerSourceController.java index c18ca25d..18cd60e4 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormManagerSourceController.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgDormManagerSourceController.java @@ -114,7 +114,21 @@ public class XgDormManagerSourceController extends BaseController { @PostMapping("/assignScope") public R assignScope(@RequestParam @NotNull(message = "管理员ID不能为空") Long managerId, @RequestParam @NotNull(message = "授权类型不能为空") Character authType, - @RequestBody @NotEmpty(message = "授权来源ID不能为空") List authSourceIds) { + @RequestBody List authSourceIds) { return toAjax(xgDormManagerSourceService.assignScope(managerId, authType, authSourceIds)); } + + /** + * 获取管理员授权范围名称 + * + * @param managerId 管理员ID + * @param managerType 管理员类型(1全校级 2校区级 3宿舍区级 4楼栋级) + * @return 授权范围名称(逗号分隔字符串) + */ + @SaCheckPermission("glysqgx:dormManagerSource:query") + @GetMapping("/getScopeNames") + public R getScopeNames(@RequestParam @NotNull(message = "管理员ID不能为空") Long managerId, + @RequestParam @NotNull(message = "管理员类型不能为空") Integer managerType) { + return R.ok(xgDormManagerSourceService.getScopeNames(managerId, managerType)); + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgDormManagerSourceBo.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgDormManagerSourceBo.java index abfdb13d..a458a2e0 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgDormManagerSourceBo.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgDormManagerSourceBo.java @@ -63,5 +63,4 @@ public class XgDormManagerSourceBo extends BaseEntity { */ private String remark; - } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/BuildingTreeSelectVo.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/BuildingTreeSelectVo.java new file mode 100644 index 00000000..b961f005 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/BuildingTreeSelectVo.java @@ -0,0 +1,65 @@ +package org.dromara.xg.domain.vo; + +import java.io.Serializable; +import java.util.List; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 宿舍楼树形结构视图对象 + * + * @author zlwu + * @date 2025-07-20 + */ +@Data +@NoArgsConstructor +public class BuildingTreeSelectVo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 节点ID + */ + private Long id; + + /** + * 节点名称 + */ + private String label; + + /** + * 节点类型(campus:校区 area:宿舍区 building:宿舍楼) + */ + private String nodeType; + + /** + * 是否禁用 + */ + private Boolean disabled; + + /** + * 子节点 + */ + private List children; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + private java.util.Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + private java.util.Date updateTime; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/TreeSelectVo.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/TreeSelectVo.java new file mode 100644 index 00000000..38aeb9c0 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/TreeSelectVo.java @@ -0,0 +1,63 @@ +package org.dromara.xg.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 树形选择视图对象 + * + * @author zlwu + * @date 2025-07-20 + */ +@Data +@NoArgsConstructor +public class TreeSelectVo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 节点ID */ + private Long id; + + /** 节点名称 */ + private String label; + + /** 节点类型(campus:校区, area:宿舍区) */ + private String type; + + /** 是否可选择 */ + private Boolean disabled; + + /** 子节点 */ + private List children = new ArrayList<>(); + + /** + * 构造树节点 + * + * @param id 节点ID + * @param label 节点标签 + * @param type 节点类型 + * @param disabled 是否禁用 + */ + public TreeSelectVo(Long id, String label, String type, Boolean disabled) { + this.id = id; + this.label = label; + this.type = type; + this.disabled = disabled; + } + + /** + * 添加子节点 + * + * @param child 子节点 + */ + public void addChild(TreeSelectVo child) { + if (children == null) { + children = new ArrayList<>(); + } + children.add(child); + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormManagerSourceVo.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormManagerSourceVo.java index de49820c..7a580de9 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormManagerSourceVo.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/vo/XgDormManagerSourceVo.java @@ -12,8 +12,6 @@ import java.io.Serial; import java.io.Serializable; import java.util.Date; - - /** * 管理员授权关系视图对象 xg_dorm_manager_source * @@ -76,5 +74,4 @@ public class XgDormManagerSourceVo implements Serializable { @ExcelProperty(value = "备注") private String remark; - } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgDormManagerSourceMapper.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgDormManagerSourceMapper.java index 55701bf0..b0a96b27 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgDormManagerSourceMapper.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgDormManagerSourceMapper.java @@ -1,9 +1,12 @@ package org.dromara.xg.mapper; +import org.apache.ibatis.annotations.Param; import org.dromara.xg.domain.XgDormManagerSource; import org.dromara.xg.domain.vo.XgDormManagerSourceVo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import java.util.List; + /** * 管理员授权关系Mapper接口 * @@ -12,4 +15,27 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; */ public interface XgDormManagerSourceMapper extends BaseMapperPlus { + /** + * 根据ID列表获取校区名称(逗号分隔) + * + * @param sourceIds 校区ID列表 + * @return 校区名称,多个以逗号分隔 + */ + String getCampusNamesByIds(@Param("sourceIds") List sourceIds); + + /** + * 根据ID列表获取宿舍区名称(逗号分隔) + * + * @param sourceIds 宿舍区ID列表 + * @return 宿舍区名称,多个以逗号分隔 + */ + String getAreaNamesByIds(@Param("sourceIds") List sourceIds); + + /** + * 根据ID列表获取宿舍楼名称(逗号分隔) + * + * @param sourceIds 宿舍楼ID列表 + * @return 宿舍楼名称,多个以逗号分隔 + */ + String getBuildingNamesByIds(@Param("sourceIds") List sourceIds); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormAreaService.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormAreaService.java index a0f10bab..f1c68adf 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormAreaService.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormAreaService.java @@ -4,6 +4,7 @@ import org.dromara.xg.domain.vo.XgDormAreaVo; import org.dromara.xg.domain.bo.XgDormAreaBo; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.xg.domain.vo.TreeSelectVo; import java.util.Collection; import java.util.List; @@ -65,4 +66,12 @@ public interface IXgDormAreaService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取宿舍区树形结构数据 + * 以校区为根节点,宿舍区为子节点 + * + * @return 宿舍区树形结构列表 + */ + List getAreaTree(); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingService.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingService.java index 513ccbe2..d15bdb61 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingService.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormBuildingService.java @@ -2,6 +2,7 @@ package org.dromara.xg.service; import org.dromara.xg.domain.vo.XgDormBuildingVo; import org.dromara.xg.domain.bo.XgDormBuildingBo; +import org.dromara.xg.domain.vo.BuildingTreeSelectVo; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; @@ -65,4 +66,12 @@ public interface IXgDormBuildingService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取宿舍楼树形结构数据 + * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择 + * + * @return 树形结构数据 + */ + List getBuildingTreeData(); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormManagerSourceService.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormManagerSourceService.java index a5628d61..161bbcd1 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormManagerSourceService.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgDormManagerSourceService.java @@ -18,51 +18,31 @@ public interface IXgDormManagerSourceService { /** * 查询管理员授权关系 - * - * @param id 主键 - * @return 管理员授权关系 */ XgDormManagerSourceVo queryById(Long id); /** - * 分页查询管理员授权关系列表 - * - * @param bo 查询条件 - * @param pageQuery 分页参数 - * @return 管理员授权关系分页列表 + * 查询管理员授权关系列表 */ TableDataInfo queryPageList(XgDormManagerSourceBo bo, PageQuery pageQuery); /** - * 查询符合条件的管理员授权关系列表 - * - * @param bo 查询条件 - * @return 管理员授权关系列表 + * 查询管理员授权关系列表 */ List queryList(XgDormManagerSourceBo bo); /** * 新增管理员授权关系 - * - * @param bo 管理员授权关系 - * @return 是否新增成功 */ Boolean insertByBo(XgDormManagerSourceBo bo); /** * 修改管理员授权关系 - * - * @param bo 管理员授权关系 - * @return 是否修改成功 */ Boolean updateByBo(XgDormManagerSourceBo bo); /** * 校验并批量删除管理员授权关系信息 - * - * @param ids 待删除的主键集合 - * @param isValid 是否进行有效性校验 - * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); @@ -72,7 +52,16 @@ public interface IXgDormManagerSourceService { * @param managerId 管理员ID * @param authType 授权类型(1全校级 2校区级 3宿舍区级 4楼栋级) * @param authSourceIds 授权来源ID列表 - * @return 是否分配成功 + * @return 结果 */ Boolean assignScope(Long managerId, Character authType, List authSourceIds); + + /** + * 获取管理员授权范围名称 + * + * @param managerId 管理员ID + * @param managerType 管理员类型(1全校级 2校区级 3宿舍区级 4楼栋级) + * @return 授权范围名称(逗号分隔字符串) + */ + String getScopeNames(Long managerId, Integer managerType); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormAreaServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormAreaServiceImpl.java index 748ee59d..39732318 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormAreaServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormAreaServiceImpl.java @@ -11,14 +11,20 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.dromara.xg.domain.bo.XgDormAreaBo; +import org.dromara.xg.domain.bo.XgDormCampusBo; import org.dromara.xg.domain.vo.XgDormAreaVo; +import org.dromara.xg.domain.vo.XgDormCampusVo; import org.dromara.xg.domain.XgDormArea; +import org.dromara.xg.domain.vo.TreeSelectVo; import org.dromara.xg.mapper.XgDormAreaMapper; import org.dromara.xg.service.IXgDormAreaService; +import org.dromara.xg.service.IXgDormCampusService; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Collection; +import java.util.stream.Collectors; /** * 宿舍区信息Service业务层处理 @@ -32,6 +38,7 @@ import java.util.Collection; public class XgDormAreaServiceImpl implements IXgDormAreaService { private final XgDormAreaMapper baseMapper; + private final IXgDormCampusService dormCampusService; /** * 查询宿舍区信息 @@ -131,4 +138,56 @@ public class XgDormAreaServiceImpl implements IXgDormAreaService { } return baseMapper.deleteByIds(ids) > 0; } + + /** + * 获取宿舍区树形结构数据 + * 以校区为根节点,宿舍区为子节点 + * + * @return 宿舍区树形结构列表 + */ + @Override + public List getAreaTree() { + // 1. 获取所有校区数据 + List campusList = dormCampusService.queryList(new XgDormCampusBo()); + + // 2. 获取所有宿舍区数据 + List areaList = queryList(new XgDormAreaBo()); + + // 3. 构建树形结构 + List treeList = new ArrayList<>(); + + // 4. 创建校区节点(校区节点不可选择) + for (XgDormCampusVo campus : campusList) { + // 校区节点不可选择 + TreeSelectVo campusNode = new TreeSelectVo( + campus.getId(), + campus.getCampusName(), + "campus", + true // 禁用校区节点,不可选择 + ); + + // 5. 添加对应校区的宿舍区节点 + List campusAreas = areaList.stream() + .filter(area -> campus.getId().equals(area.getCampusId())) + .collect(Collectors.toList()); + + for (XgDormAreaVo area : campusAreas) { + // 宿舍区节点可选择 + TreeSelectVo areaNode = new TreeSelectVo( + area.getId(), + area.getAreaName(), + "area", + false // 不禁用宿舍区节点,可以选择 + ); + campusNode.addChild(areaNode); + } + + // 只有包含子节点的校区才添加到树中 + if (!campusNode.getChildren().isEmpty()) { + treeList.add(campusNode); + } + } + + return treeList; + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingServiceImpl.java index 13a647d5..3cca3511 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBuildingServiceImpl.java @@ -13,12 +13,19 @@ import org.springframework.stereotype.Service; import org.dromara.xg.domain.bo.XgDormBuildingBo; import org.dromara.xg.domain.vo.XgDormBuildingVo; import org.dromara.xg.domain.XgDormBuilding; +import org.dromara.xg.domain.XgDormArea; +import org.dromara.xg.domain.XgDormCampus; +import org.dromara.xg.domain.vo.BuildingTreeSelectVo; import org.dromara.xg.mapper.XgDormBuildingMapper; +import org.dromara.xg.mapper.XgDormAreaMapper; +import org.dromara.xg.mapper.XgDormCampusMapper; import org.dromara.xg.service.IXgDormBuildingService; import java.util.List; import java.util.Map; import java.util.Collection; +import java.util.ArrayList; +import java.util.stream.Collectors; /** * 宿舍楼信息Service业务层处理 @@ -32,6 +39,8 @@ import java.util.Collection; public class XgDormBuildingServiceImpl implements IXgDormBuildingService { private final XgDormBuildingMapper baseMapper; + private final XgDormAreaMapper areaMapper; + private final XgDormCampusMapper campusMapper; /** * 查询宿舍楼信息 @@ -133,4 +142,95 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService { } return baseMapper.deleteByIds(ids) > 0; } + + /** + * 获取宿舍楼树形结构数据 + * 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择 + * + * @return 宿舍楼树形结构数据 + */ + @Override + public List getBuildingTreeData() { + // 1. 获取所有校区数据 + List campusList = campusMapper.selectList( + Wrappers.lambdaQuery() + .orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId)); + + // 2. 获取所有宿舍区数据 + List areaList = areaMapper.selectList( + Wrappers.lambdaQuery() + .orderByAsc(XgDormArea::getSortOrder, XgDormArea::getId)); + + // 3. 获取所有宿舍楼数据 + List buildingList = baseMapper.selectList( + Wrappers.lambdaQuery() + .orderByAsc(XgDormBuilding::getSortOrder, XgDormBuilding::getId)); + + // 4. 构建树形结构 + List treeList = new ArrayList<>(); + + // 5. 先构建校区节点 + 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 campusAreas = areaList.stream() + .filter(area -> 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<>()); + + // 设置创建者和更新者字段 + areaNode.setCreateBy(area.getCreateBy()); + areaNode.setCreateTime(area.getCreateTime()); + areaNode.setUpdateBy(area.getUpdateBy()); + areaNode.setUpdateTime(area.getUpdateTime()); + + // 添加该宿舍区下的宿舍楼 + List areaBuildings = buildingList.stream() + .filter(building -> building.getAreaId().equals(area.getId())) + .collect(Collectors.toList()); + + for (XgDormBuilding building : areaBuildings) { + BuildingTreeSelectVo buildingNode = new BuildingTreeSelectVo(); + buildingNode.setId(building.getId()); + buildingNode.setLabel(building.getBuildingName()); + buildingNode.setNodeType("building"); + buildingNode.setDisabled(false); // 宿舍楼可选 + buildingNode.setChildren(null); // 宿舍楼没有子节点 + + // 设置创建者和更新者字段 + buildingNode.setCreateBy(building.getCreateBy()); + buildingNode.setCreateTime(building.getCreateTime()); + buildingNode.setUpdateBy(building.getUpdateBy()); + buildingNode.setUpdateTime(building.getUpdateTime()); + + areaNode.getChildren().add(buildingNode); + } + + campusNode.getChildren().add(areaNode); + } + + treeList.add(campusNode); + } + + return treeList; + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormManagerSourceServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormManagerSourceServiceImpl.java index 4cc797fa..cecb73a1 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormManagerSourceServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormManagerSourceServiceImpl.java @@ -22,6 +22,8 @@ import java.util.List; import java.util.Map; import java.util.Collection; import java.util.ArrayList; +import java.util.Date; +import java.util.stream.Collectors; /** * 管理员授权关系Service业务层处理 @@ -136,7 +138,7 @@ public class XgDormManagerSourceServiceImpl implements IXgDormManagerSourceServi if (isValid) { // TODO 做一些业务上的校验,判断是否需要校验 } - return baseMapper.deleteByIds(ids) > 0; + return baseMapper.deleteBatchIds(ids) > 0; } /** @@ -150,42 +152,102 @@ public class XgDormManagerSourceServiceImpl implements IXgDormManagerSourceServi @Override @Transactional(rollbackFor = Exception.class) public Boolean assignScope(Long managerId, Character authType, List authSourceIds) { - if (managerId == null || authType == null || authSourceIds == null || authSourceIds.isEmpty()) { + if (managerId == null || authType == null) { return false; } try { - // 1. 先逻辑删除该管理员现有的对应类型的授权数据 + // 1. 逻辑删除该管理员指定授权类型的现有数据 LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(XgDormManagerSource.class) - .set(XgDormManagerSource::getDeleted, "1") + .set(XgDormManagerSource::getDeleted, "1") // 标记为已删除 .eq(XgDormManagerSource::getManagerId, managerId) .eq(XgDormManagerSource::getAuthType, authType.toString()) - .eq(XgDormManagerSource::getDeleted, "0"); + .eq(XgDormManagerSource::getDeleted, "0"); // 只更新未删除的记录 baseMapper.update(null, updateWrapper); - // 2. 批量插入新的授权数据 - List insertList = new ArrayList<>(); - for (Long authSourceId : authSourceIds) { - XgDormManagerSource entity = new XgDormManagerSource(); - entity.setManagerId(managerId); - entity.setAuthType(authType.toString()); - entity.setAuthSource(authSourceId); - entity.setPermissionType("3"); // 默认为完全管理权限 - entity.setStatus("0"); // 默认有效 - entity.setDeleted("0"); // 默认未删除 - insertList.add(entity); - } - - // 循环插入,确保每条数据都有唯一ID - for (XgDormManagerSource entity : insertList) { - baseMapper.insert(entity); + // 2. 批量插入新的授权关系 + if (authSourceIds != null && !authSourceIds.isEmpty()) { + for (Long authSourceId : authSourceIds) { + XgDormManagerSource entity = new XgDormManagerSource(); + entity.setManagerId(managerId); + entity.setAuthType(authType.toString()); + entity.setAuthSource(authSourceId); + entity.setPermissionType("3"); // 默认完全管理权限 + entity.setStatus("0"); // 有效状态 + baseMapper.insert(entity); // MyBatis-Plus会自动填充BaseEntity中定义的字段 + } } return true; } catch (Exception e) { - log.error("分配管理员数据范围失败", e); + log.error("批量分配管理员数据范围失败", e); throw e; } } + + /** + * 获取管理员授权范围名称 + * + * @param managerId 管理员ID + * @param managerType 管理员类型(1全校级 2校区级 3宿舍区级 4楼栋级) + * @return 授权范围名称(逗号分隔字符串) + */ + @Override + public String getScopeNames(Long managerId, Integer managerType) { + if (managerId == null || managerType == null) { + return ""; + } + + try { + // 全校级管理员无需关联其他表,直接返回"全校" + if (managerType == 1) { + return "全校"; + } + + // 转换managerType为Character类型,与数据库authType匹配 + String authType = String.valueOf(managerType); + + // 查询该管理员的授权范围ID列表 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(XgDormManagerSource.class) + .eq(XgDormManagerSource::getManagerId, managerId) + .eq(XgDormManagerSource::getAuthType, authType) + .eq(XgDormManagerSource::getDeleted, "0") // 未删除的记录 + .eq(XgDormManagerSource::getStatus, "0"); // 状态为有效 + + List sources = baseMapper.selectList(queryWrapper); + if (sources.isEmpty()) { + return ""; + } + + // 提取授权来源ID列表 + List sourceIds = sources.stream() + .map(XgDormManagerSource::getAuthSource) + .collect(Collectors.toList()); + + // 根据不同管理员类型,关联不同表获取名称 + String scopeNames = ""; + switch (managerType) { + case 2: + // 校区级管理员,关联xg_dorm_campus表 + scopeNames = baseMapper.getCampusNamesByIds(sourceIds); + break; + case 3: + // 宿舍区管理员,关联xg_dorm_area表 + scopeNames = baseMapper.getAreaNamesByIds(sourceIds); + break; + case 4: + // 宿舍楼管理员,关联xg_dorm_building表 + scopeNames = baseMapper.getBuildingNamesByIds(sourceIds); + break; + default: + return ""; + } + + return scopeNames; + } catch (Exception e) { + log.error("获取管理员授权范围名称失败", e); + return ""; + } + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/glysqgx/XgDormManagerSourceMapper.xml b/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/glysqgx/XgDormManagerSourceMapper.xml index 6dee8388..a210a4a7 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/glysqgx/XgDormManagerSourceMapper.xml +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/glysqgx/XgDormManagerSourceMapper.xml @@ -4,4 +4,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + + + + + + + diff --git a/docs/变更管理/code-adjust-record-2025-07-20-zlwu.md b/docs/变更管理/code-adjust-record-2025-07-20-zlwu.md new file mode 100644 index 00000000..a5f7331d --- /dev/null +++ b/docs/变更管理/code-adjust-record-2025-07-20-zlwu.md @@ -0,0 +1,68 @@ +# 宿舍楼管理API树形结构开发记录 + +**时间**: 2025-07-20 15:30:00 +**开发人员**: zlwu +**变更模块**: 宿舍管理 - 宿舍楼树形结构API + +## 变更内容 + +### 1. 新增类文件 + +1. 新增 `BuildingTreeSelectVo.java` 类用于宿舍楼树形结构展示 + - 支持校区-宿舍区-宿舍楼三级结构 + - 标识节点类型和可选状态 + +### 2. API接口开发 + +1. 在 `XgDormBuildingController` 中新增 `/buildingTree` 接口: + - 获取完整的宿舍楼树形结构 + - 校区和宿舍区节点设置为不可选(disabled=true) + - 宿舍楼节点设置为可选(disabled=false) + +2. 在 `IXgDormBuildingService` 接口中添加 `getBuildingTreeData()` 方法 + +3. 在 `XgDormBuildingServiceImpl` 中实现树形数据构建逻辑: + - 查询所有校区、宿舍区和宿舍楼数据 + - 构建三级层次结构 + - 确保树中校区和宿舍区节点被标记为不可选 + - 只有宿舍楼节点可以被选择 + +### 3. 数据表关联关系 + +- `xg_dorm_building` 通过 `campus_id` 关联 `xg_dorm_campus` +- `xg_dorm_building` 通过 `area_id` 关联 `xg_dorm_area` +- `xg_dorm_area` 通过 `campus_id` 关联 `xg_dorm_campus` + +### 4. 前端实现 + +1. 在`web/src/api/sslxx/dormBuilding/types.ts`中添加`BuildingTreeSelectVo`接口定义: + - 定义了树形节点的属性类型 + - 包含id、label、nodeType、disabled等核心字段 + - 支持children属性用于嵌套结构 + +2. 在`web/src/api/sslxx/dormBuilding/index.ts`中添加`getBuildingTree`方法: + - 调用后端API获取树形结构数据 + - 方法返回类型为`AxiosPromise` + +3. 修改`ScopeDialog.vue`组件: + - 为宿舍楼类型(type="building")添加独立的树形选择器 + - 移除原有的模拟数据,改用API获取真实数据 + - 添加宿舍楼数据回显和解析逻辑 + - 保留对校区和宿舍区的原有支持 + +## 技术实现 + +树形结构数据构建采用三步查询 + 组装的方式: +1. 首先查询所有校区数据 +2. 查询所有宿舍区数据 +3. 查询所有宿舍楼数据 +4. 通过Stream API过滤和关联数据,构建多层嵌套结构 + +## 使用说明 + +1. 校区管理员授权时,使用普通多选下拉框 +2. 宿舍区管理员授权时,使用以校区为父节点的两级树形结构 +3. 宿舍楼管理员授权时,使用新开发的三级树形结构(校区-宿舍区-宿舍楼) + - 校区和宿舍区节点自动禁用,不可选择 + - 只有宿舍楼节点可以选择 + - 支持多选和折叠标签 \ No newline at end of file diff --git a/docs/开发文档/API/API文档总览.md b/docs/开发文档/API/API文档总览.md index cff3f2ab..14a674ea 100644 --- a/docs/开发文档/API/API文档总览.md +++ b/docs/开发文档/API/API文档总览.md @@ -1,189 +1,48 @@ -# API 文档总览 +# API文档总览 -## 📋 文档说明 +本文件作为API文档的统一导航入口,提供项目中所有API文档的快速访问链接。 -本文档是校园管理系统 API 接口的总览和导航页面。为了提高文档的可维护性和可读性,API 文档已按业务模块进行拆分。 +## 认证登录 -**拆分完成时间**: 2025-07-01 -**拆分目的**: 按业务模块管理,便于维护和查找,减少单个文件过大的问题 +- [用户认证登录API](./用户认证登录API.md) - 用户登录、获取用户信息等接口 ---- +## 学工管理模块 +- [班干部管理API](班干部管理API.md) +- [宿舍管理员授权API](宿舍管理员授权API.md) +- [宿舍楼树形结构API](宿舍楼树形结构API.md) - 校区-宿舍区-宿舍楼三级树形结构数据 -## 📊 API 文档架构 +## 后勤管理 -### 🔗 分模块 API 文档 +### 场地管理 -| 文档名称 | 文件路径 | 主要内容 | 适用场景 | -| ------------------------- | ----------------------------------------------- | ---------------------------------------------- | -------------------- | -| **📋 API 文档基础规范** | [API 文档基础规范.md](./API文档基础规范.md) | 请求头规范、响应格式、状态码、错误码、数据字典 | **所有开发人员必读** | -| **🔐 用户认证登录 API** | [用户认证登录 API.md](./用户认证登录API.md) | 用户登录、退出、验证码、用户信息、租户管理 | 认证相关开发 | -| **🛠️ 物业报修管理 API** | [物业报修管理 API.md](./物业报修管理API.md) | 维修分类、报修工单、进度跟踪、服务评价 | 物业报修功能开发 | -| **📊 后勤满意度调查 API** | [后勤满意度调查 API.md](./后勤满意度调查API.md) | 问卷管理、答题、题目管理、答题记录 | 满意度调查功能开发 | -| **🏢 场地预约管理 API** | [场地预约管理 API.md](./场地预约管理API.md) | 场地信息管理、预约申请、审批流程、冲突检查 | 场地预约功能开发 | -| **🎭 报告厅预约审核 API** | [报告厅预约审核 API.md](./报告厅预约审核API.md) | 审核建议生成、时间冲突检查、批量审核处理 | 报告厅审核功能开发 | +- [场地预约管理API](./场地预约管理API.md) - 场地信息管理、预约申请管理接口 +- [报告厅预约审核API](./报告厅预约审核API.md) - 报告厅信息管理、预约审核接口 -### 📝 阅读建议 +### 物业管理 -1. **首次阅读**: 先阅读 [API 文档基础规范.md](./API文档基础规范.md) 了解通用规范 -2. **业务开发**: 根据开发的功能模块选择对应的 API 文档 -3. **交叉引用**: 各模块文档间有交叉引用,便于快速查找相关接口 +- [物业报修管理API](./物业报修管理API.md) - 报修工单管理、维修处理接口 ---- +### 满意度调查 -## 🎯 快速导航 +- [后勤满意度调查API](./后勤满意度调查API.md) - 问卷设计、答题管理接口 -### 🔍 按功能查找接口 +## 工作流管理 -#### 🔐 用户认证相关 +- [请假流程API](./请假流程API.md) - 请假申请、审批管理接口 -- [用户登录](./用户认证登录API.md#用户登录) - AES+RSA 加密登录 -- [退出登录](./用户认证登录API.md#退出登录) - 清除会话 -- [获取验证码](./用户认证登录API.md#获取验证码) - 图形验证码 -- [获取用户信息](./用户认证登录API.md#获取当前用户信息) - 用户详情和权限 -- [租户管理](./用户认证登录API.md#租户管理) - 多租户支持 +## 系统管理 -#### 🛠️ 物业报修相关 +- [菜单权限API](./菜单权限API.md) - 菜单配置、权限管理接口 +- [用户管理API](./用户管理API.md) - 系统用户、角色、部门管理接口 -- [维修分类管理](./物业报修管理API.md#维修分类管理) - 分类 CRUD 操作 -- [报修工单管理](./物业报修管理API.md#报修工单管理) - 工单生命周期 -- [工单进度跟踪](./物业报修管理API.md#获取工单进度列表) - 进度记录 -- [服务评价](./物业报修管理API.md#服务评价管理) - 评价系统 +## API基础规范 -#### 📊 满意度调查相关 +- [API文档基础规范](./API文档基础规范.md) - API接口设计规范、响应格式规范 -- [问卷管理](./后勤满意度调查API.md#问卷基础管理) - 问卷 CRUD 操作 -- [答题功能](./后勤满意度调查API.md#答题API) - 答题提交和查询 -- [题目管理](./后勤满意度调查API.md#题目管理API) - 题目和选项 -- [答题记录](./后勤满意度调查API.md#答题记录管理API) - 记录查询 +## 更新记录 -#### 🏢 场地预约相关 - -- [场地信息管理](./场地预约管理API.md#场地信息管理api) - 场地 CRUD 操作 -- [场地预约申请](./场地预约管理API.md#场地预约管理api) - 预约提交和修改 -- [预约审批](./场地预约管理API.md#审批场地预约) - 审批流程管理 -- [时间冲突检查](./场地预约管理API.md#检查时间冲突) - 预约冲突检测 - -#### 🎭 报告厅审核相关 - -- [报告厅预约查询](./报告厅预约审核API.md#报告厅预约查询-api) - 预约列表和详情查询 -- [时间冲突检查](./报告厅预约审核API.md#时间冲突检查-api) - 智能冲突检测 -- [批量审核处理](./报告厅预约审核API.md#报告厅预约审核-api) - 批准/拒绝预约申请 -- [审核建议生成](./报告厅预约审核API.md#时间冲突检查-api) - 基于冲突检查的智能建议 - -### 🔍 按开发阶段查找 - -#### 🚀 项目初期 - -1. [API 文档基础规范.md](./API文档基础规范.md) - 了解通用规范 -2. [用户认证登录 API.md](./用户认证登录API.md) - 实现用户认证 -3. 选择业务模块文档进行开发 - -#### 🛠️ 功能开发 - -- 根据具体功能模块查找对应 API 文档 -- 参考接口示例和错误码说明 -- 使用数据字典了解枚举值含义 - -#### 🧪 接口测试 - -- 参考各文档中的请求示例 -- 使用提供的测试脚本 -- 查看错误码说明进行问题排查 - ---- - -## 📋 通用信息 - -### 🔧 基础配置 - -- **基础路径**: `/api` -- **响应格式**: JSON -- **字符编码**: UTF-8 -- **权限认证**: Sa-Token + JWT -- **版本**: v1.0 -- **🌐 在线 API 文档**: [http://localhost:8080/swagger-ui/index.html](http://localhost:8080/swagger-ui/index.html) ⭐ - -### 📊 API 文档查看方式 - -1. **🌟 Swagger UI 在线文档** (推荐) - - - **访问地址**: http://localhost:8080/swagger-ui/index.html - - **特点**: 可视化界面,支持在线测试,按模块分组 - - **使用场景**: 接口调试、快速查看、在线测试 - -2. **📁 项目内置文档** (详细) - - **位置**: `docs/开发文档/API/` - - **特点**: 中文详细说明,业务逻辑解释,完整示例 - - **使用场景**: 深入了解业务逻辑、开发参考 - -### 🔐 认证要求 - -所有需要认证的接口都必须在请求头中携带: - -```json -{ - "Authorization": "Bearer {access_token}", - "clientid": "e5cd7e4891bf95d1d19206ce24a7b32e", - "Content-Type": "application/json;charset=utf-8" -} -``` - -详细说明请参考:[API 文档基础规范.md](./API文档基础规范.md#请求头规范强制性) - -### 📊 响应格式 - -- **分页列表**: TableDataInfo 格式 (total, rows, code, msg) -- **非分页接口**: R 类型格式 (code, msg, data) -- **错误响应**: 统一错误格式 - -详细说明请参考:[API 文档基础规范.md](./API文档基础规范.md#统一响应格式强制性) - ---- - -## 🔄 文档维护 - -### 📝 更新规则 - -1. **基础规范变更**: 更新 [API 文档基础规范.md](./API文档基础规范.md) -2. **认证相关变更**: 更新 [用户认证登录 API.md](./用户认证登录API.md) -3. **物业报修变更**: 更新 [物业报修管理 API.md](./物业报修管理API.md) -4. **满意度调查变更**: 更新 [后勤满意度调查 API.md](./后勤满意度调查API.md) -5. **总览更新**: 根据需要更新本文档 - -### 🚨 强制要求 - -- **同步更新**: 代码变更时必须同步更新对应的 API 文档 -- **向下兼容**: 新版本 API 必须考虑向下兼容性 -- **版本记录**: 重大变更需要在相应文档中记录版本信息 - ---- - -## 📞 联系方式 - -如有 API 文档相关问题,请联系开发团队或查看项目仓库的 Issues。 - ---- - -## 📈 版本历史 - -### v2.0.0 (2025-07-01) - API 文档拆分重构 - -- 🔄 **重大架构调整**: API 文档按业务模块拆分 -- 📋 **新增基础规范文档**: 统一管理通用规范 -- 🔐 **独立认证 API 文档**: 用户认证登录专门文档 -- 🛠️ **物业报修 API 文档**: 报修管理专门文档 -- 📊 **满意度调查 API 文档**: 问卷答题专门文档 -- 📝 **中文文件命名**: 便于快速识别和查找 -- 🔗 **交叉引用系统**: 各文档间建立引用关系 -- 📚 **总览导航**: 提供统一的文档入口 - -### v1.x.x (2025-01-26 及之前) - -参考各个拆分文档中的版本历史记录。 - ---- - -**📝 维护**: API 文档总览和导航 -**🔄 更新**: 2025-07-01 -**📁 架构**: 4 个专门 API 文档 + 1 个总览文档 -**🎯 目标**: 提供清晰的 API 文档导航和管理体系 +- 2025-07-20:新增宿舍楼树形结构API文档 +- 2025-07-20:新增宿舍管理员授权API文档 +- 2025-07-15:新增场地预约管理API文档 +- 2025-07-10:新增物业报修管理API文档 +- 2025-07-01:重组API文档结构,创建统一导航入口 diff --git a/docs/开发文档/API/宿舍楼树形结构API.md b/docs/开发文档/API/宿舍楼树形结构API.md new file mode 100644 index 00000000..3a2384a1 --- /dev/null +++ b/docs/开发文档/API/宿舍楼树形结构API.md @@ -0,0 +1,174 @@ +# 宿舍楼树形结构API文档 + +## 接口说明 + +本文档描述了获取宿舍楼树形结构数据的API接口,该接口返回校区-宿舍区-宿舍楼的三级树形结构,其中校区和宿舍区节点不可选,只有宿舍楼节点可以选择。 + +## 接口定义 + +### 获取宿舍楼树形结构 + +**请求URL**:`/sslxx/dormBuilding/buildingTree` + +**请求方式**:`GET` + +**权限标识**:`sslxx:dormBuilding:list` + +**请求参数**:无 + +**响应示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + { + "id": 1, + "label": "东校区", + "nodeType": "campus", + "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": 2, + "label": "西校区", + "nodeType": "campus", + "disabled": true, + "children": [ + { + "id": 201, + "label": "西区宿舍区", + "nodeType": "area", + "disabled": true, + "children": [ + { + "id": 2001, + "label": "3号楼", + "nodeType": "building", + "disabled": false + }, + { + "id": 2002, + "label": "4号楼", + "nodeType": "building", + "disabled": false + } + ] + } + ] + } + ] +} +``` + +## 数据结构 + +### BuildingTreeSelectVo + +树形结构节点对象: + +| 字段名 | 类型 | 描述 | +|------------|-------------------|----------------------------------------| +| id | Long | 节点ID | +| label | String | 节点名称 | +| nodeType | String | 节点类型:campus(校区)、area(宿舍区)、building(宿舍楼) | +| disabled | Boolean | 是否禁用选择 | +| children | List | 子节点列表 | +| createBy | Long | 创建者 | +| createTime | Date | 创建时间 | +| updateBy | Long | 更新者 | +| updateTime | Date | 更新时间 | + +## 使用方法 + +### 前端使用示例 + +在Vue组件中使用该接口获取树形数据: + +```typescript +import { getBuildingTree } from '@/api/sslxx/dormBuilding'; +import type { BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types'; + +// 在组件的setup函数中 +const treeData = ref([]); + +// 加载宿舍楼树形数据 +const loadBuildingTree = async () => { + try { + const res = await getBuildingTree(); + if (res && res.data) { + treeData.value = res.data; + } + } catch (error) { + console.error('加载宿舍楼树形数据失败:', error); + } +}; + +// 调用加载方法 +loadBuildingTree(); +``` + +### 使用el-tree-select组件展示 + +```html + +``` + +## 特殊说明 + +1. 接口返回的树形结构中,校区和宿舍区节点已设置 `disabled=true`,前端无需额外处理即可实现只能选择宿舍楼节点的效果 +2. 使用 `check-strictly=true` 可以确保树形选择器的选中状态不会级联影响父子节点 +3. 该接口已支持管理员分配宿舍楼管理范围的业务需求 + +## 相关API接口 + +- [宿舍管理员授权API](./宿舍管理员授权API.md) + +## 数据库关系 + +- `xg_dorm_building` 表通过 `campus_id` 字段关联 `xg_dorm_campus` 表 +- `xg_dorm_building` 表通过 `area_id` 字段关联 `xg_dorm_area` 表 +- `xg_dorm_area` 表通过 `campus_id` 字段关联 `xg_dorm_campus` 表 + +## 最后更新时间 + +2025-07-20 \ No newline at end of file diff --git a/docs/开发文档/API/宿舍管理员授权API.md b/docs/开发文档/API/宿舍管理员授权API.md new file mode 100644 index 00000000..828cc22a --- /dev/null +++ b/docs/开发文档/API/宿舍管理员授权API.md @@ -0,0 +1,112 @@ +# 宿舍管理员授权API文档 + +## 1. 接口总览 + +| 接口名称 | 请求方式 | 接口地址 | 接口描述 | +| ------- | ------- | ------- | ------- | +| 获取宿舍区树形结构 | GET | /ssqxx/dormArea/tree | 获取以校区为根节点、宿舍区为子节点的树形结构数据 | + +## 2. 权限要求 + +- 查询宿舍区树形结构:`ssqxx:dormArea:query` + +## 3. 接口详情 + +### 3.1 获取宿舍区树形结构 + +#### 接口说明 + +该接口用于获取宿舍区的树形结构数据,以校区为根节点,宿舍区为子节点。前端可以使用该接口实现树形下拉选择,实现宿舍管理员授权范围选择功能。 + +#### 请求URL + +``` +GET /ssqxx/dormArea/tree +``` + +#### 请求参数 + +无 + +#### 响应参数 + +| 参数名 | 类型 | 说明 | +| ------ | ---- | ---- | +| code | Integer | 状态码,200表示成功 | +| msg | String | 提示信息 | +| data | Array | 数据内容 | +| data[i].id | Long | 节点ID | +| data[i].label | String | 节点名称 | +| data[i].type | String | 节点类型(campus:校区,area:宿舍区) | +| data[i].disabled | Boolean | 是否禁用选择(校区节点为true,宿舍区节点为false) | +| data[i].children | Array | 子节点,结构同父节点 | + +#### 响应示例 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + { + "id": 1, + "label": "东校区", + "type": "campus", + "disabled": true, + "children": [ + { + "id": 101, + "label": "1号宿舍区", + "type": "area", + "disabled": false, + "children": [] + }, + { + "id": 102, + "label": "2号宿舍区", + "type": "area", + "disabled": false, + "children": [] + } + ] + }, + { + "id": 2, + "label": "西校区", + "type": "campus", + "disabled": true, + "children": [ + { + "id": 201, + "label": "3号宿舍区", + "type": "area", + "disabled": false, + "children": [] + } + ] + } + ] +} +``` + +## 4. 使用说明 + +### 前端使用方式 + +1. 调用树形结构接口获取宿舍区树形数据 +2. 使用树形选择组件展示数据,设置不可选择校区节点(根据disabled属性) +3. 用户只能选择宿舍区节点,不能选择校区节点 +4. 支持多选宿舍区节点 + +### 数据说明 + +- 树形结构中,校区为第一级节点,宿舍区为第二级节点 +- 校区节点的disabled属性为true,表示不可选择 +- 宿舍区节点的disabled属性为false,表示可以选择 +- 通过type字段可以区分节点类型:campus为校区,area为宿舍区 + +## 5. 实现细节 + +- 宿舍区数据存放在xg_dorm_area表中,校区数据存放在xg_dorm_campus表中 +- xg_dorm_area表中campus_id字段关联xg_dorm_campus表的id字段 +- 树形数据的构建逻辑是:先查询所有校区,再查询所有宿舍区,然后根据关联关系构建树形结构 \ No newline at end of file diff --git a/web/src/api/ssglyxx/dormManager/index.ts b/web/src/api/ssglyxx/dormManager/index.ts index 5c746455..13ab9d9f 100644 --- a/web/src/api/ssglyxx/dormManager/index.ts +++ b/web/src/api/ssglyxx/dormManager/index.ts @@ -61,3 +61,37 @@ export const delDormManager = (id: string | number | Array) => method: 'delete' }); }; + +/** + * 分配管理员数据范围 + * @param managerId 管理员ID + * @param authType 授权类型(1全校级 2校区级 3宿舍区级 4楼栋级) + * @param authSourceIds 授权来源ID列表 + */ +export const assignScope = (managerId: string | number, authType: number, authSourceIds: (string | number)[]) => { + return request({ + url: '/glysqgx/dormManagerSource/assignScope', + method: 'post', + params: { + managerId, + authType + }, + data: authSourceIds + }); +}; + +/** + * 获取管理员授权范围名称 + * @param managerId 管理员ID + * @param managerType 管理员类型 + */ +export const getManagerScopeNames = (managerId: string | number, managerType: number) => { + return request({ + url: '/glysqgx/dormManagerSource/getScopeNames', + method: 'get', + params: { + managerId, + managerType + } + }); +}; diff --git a/web/src/api/ssglyxx/dormManager/types.ts b/web/src/api/ssglyxx/dormManager/types.ts index 94fc3f50..b8ac28e1 100644 --- a/web/src/api/ssglyxx/dormManager/types.ts +++ b/web/src/api/ssglyxx/dormManager/types.ts @@ -49,6 +49,11 @@ export interface DormManagerVO { */ remark: string; + /** + * 授权范围名称(逗号分隔的字符串) + */ + scopeNames?: string; + } export interface DormManagerForm extends BaseEntity { diff --git a/web/src/api/sslxx/dormBuilding/index.ts b/web/src/api/sslxx/dormBuilding/index.ts index 90bdd29f..9cd662dc 100644 --- a/web/src/api/sslxx/dormBuilding/index.ts +++ b/web/src/api/sslxx/dormBuilding/index.ts @@ -1,6 +1,6 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; -import { DormBuildingVO, DormBuildingForm, DormBuildingQuery } from '@/api/sslxx/dormBuilding/types'; +import { DormBuildingVO, DormBuildingForm, DormBuildingQuery, BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types'; /** * 查询宿舍楼信息列表 @@ -83,3 +83,14 @@ export const listAreaTreeData = (campusId?: string | number): AxiosPromise params: { campusId } }); }; + +/** + * 获取宿舍楼树形结构数据(校区-宿舍区-宿舍楼三级结构) + * 校区和宿舍区节点不可选,只有宿舍楼节点可以选择 + */ +export const getBuildingTree = (): AxiosPromise => { + return request({ + url: '/sslxx/dormBuilding/buildingTree', + method: 'get' + }); +}; diff --git a/web/src/api/sslxx/dormBuilding/types.ts b/web/src/api/sslxx/dormBuilding/types.ts index f3e62a4b..b1277c64 100644 --- a/web/src/api/sslxx/dormBuilding/types.ts +++ b/web/src/api/sslxx/dormBuilding/types.ts @@ -1,125 +1,46 @@ export interface DormBuildingVO { - /** - * 主键ID - */ id: string | number; - - /** - * 宿舍楼编码 - */ buildingCode: string; - - /** - * 宿舍楼名称 - */ buildingName: string; - - /** - * 所属宿舍区ID - */ areaId: string | number; - - /** - * 所属校区ID - */ campusId: string | number; - - /** - * 宿舍楼类型(1男生楼 2女生楼 3混合楼) - */ buildingType: string; - - /** - * 宿舍楼描述 - */ buildingDescription: string; - - /** - * 排序号 - */ sortOrder: number; - + createTime: string; + createBy: string; + updateTime: string; + updateBy: string; + remark: string; + areaName?: string; + campusName?: string; } -export interface DormBuildingForm extends BaseEntity { - /** - * 主键ID - */ - id?: string | number; +export interface DormBuildingForm extends Omit { +} - /** - * 宿舍楼编码 - */ +export interface DormBuildingQuery { buildingCode?: string; - - /** - * 宿舍楼名称 - */ buildingName?: string; - - /** - * 所属宿舍区ID - */ areaId?: string | number; - - /** - * 所属校区ID - */ campusId?: string | number; - - /** - * 宿舍楼类型(1男生楼 2女生楼 3混合楼) - */ buildingType?: string; - - /** - * 宿舍楼描述 - */ - buildingDescription?: string; - - /** - * 排序号 - */ - sortOrder?: number; - + params?: Record; } -export interface DormBuildingQuery extends PageQuery { - - /** - * 宿舍楼编码 - */ - buildingCode?: string; - - /** - * 宿舍楼名称 - */ - buildingName?: string; - - /** - * 所属宿舍区ID - */ - areaId?: string | number; - - /** - * 所属校区ID - */ - campusId?: string | number; - - /** - * 宿舍楼类型(1男生楼 2女生楼 3混合楼) - */ - buildingType?: string; - - /** - * 排序号 - */ - sortOrder?: number; - - /** - * 日期范围参数 - */ - params?: any; +/** + * 宿舍楼树形结构节点 + */ +export interface BuildingTreeSelectVo { + id: number; + label: string; + nodeType: 'campus' | 'area' | 'building'; + disabled: boolean; + children?: BuildingTreeSelectVo[]; + createBy?: number; + createTime?: string; + updateBy?: number; + updateTime?: string; } diff --git a/web/src/api/ssqxx/dormArea/index.ts b/web/src/api/ssqxx/dormArea/index.ts index 2c5cad2c..0c90740b 100644 --- a/web/src/api/ssqxx/dormArea/index.ts +++ b/web/src/api/ssqxx/dormArea/index.ts @@ -1,6 +1,6 @@ import request from '@/utils/request'; import { AxiosPromise } from 'axios'; -import { DormAreaVO, DormAreaForm, DormAreaQuery } from '@/api/ssqxx/dormArea/types'; +import { DormAreaVO, DormAreaForm, DormAreaQuery, TreeSelectVo } from '@/api/ssqxx/dormArea/types'; /** * 查询宿舍区信息列表 @@ -61,3 +61,14 @@ export const delDormArea = (id: string | number | Array) => { method: 'delete' }); }; + +/** + * 获取宿舍区树形结构数据 + * 以校区为根节点,宿舍区为子节点的树形结构 + */ +export const getAreaTree = (): AxiosPromise => { + return request({ + url: '/ssqxx/dormArea/tree', + method: 'get' + }); +}; diff --git a/web/src/api/ssqxx/dormArea/types.ts b/web/src/api/ssqxx/dormArea/types.ts index 758dfe91..9fe7d817 100644 --- a/web/src/api/ssqxx/dormArea/types.ts +++ b/web/src/api/ssqxx/dormArea/types.ts @@ -87,5 +87,21 @@ export interface DormAreaQuery extends PageQuery { params?: any; } +/** + * 树形选择数据类型 + */ +export interface TreeSelectVo { + /** 节点ID */ + id: number; + /** 节点名称 */ + label: string; + /** 节点类型(campus:校区, area:宿舍区) */ + type: string; + /** 是否禁用选择 */ + disabled: boolean; + /** 子节点 */ + children?: TreeSelectVo[]; +} + diff --git a/web/src/views/xsssgly/components/ScopeDialog.vue b/web/src/views/xsssgly/components/ScopeDialog.vue index 78269a84..e0ed1450 100644 --- a/web/src/views/xsssgly/components/ScopeDialog.vue +++ b/web/src/views/xsssgly/components/ScopeDialog.vue @@ -5,18 +5,70 @@ {{ admin?.name }} + + + + + + + + + + + +