提交代码
This commit is contained in:
1 parent
225a268e32
commit
7ce20647f0
28 files changed
+1451
-420
No files matched your search
+13
-4
@@ -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<XgDormAreaVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
public R<XgDormAreaVo> 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<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(xgDormAreaService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿舍区树形结构数据
|
||||
* 以校区为根节点,宿舍区为子节点
|
||||
*/
|
||||
@SaCheckPermission("ssqxx:dormArea:query")
|
||||
@GetMapping("/tree")
|
||||
public R<List<TreeSelectVo>> getAreaTree() {
|
||||
return R.ok(xgDormAreaService.getAreaTree());
|
||||
}
|
||||
}
|
||||
+14
-4
@@ -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<XgDormBuildingVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
public R<XgDormBuildingVo> 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<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(xgDormBuildingService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构数据
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("sslxx:dormBuilding:list")
|
||||
@GetMapping("/buildingTree")
|
||||
public R<List<BuildingTreeSelectVo>> getBuildingTree() {
|
||||
List<BuildingTreeSelectVo> treeData = xgDormBuildingService.getBuildingTreeData();
|
||||
return R.ok(treeData);
|
||||
}
|
||||
}
|
||||
+15
-1
@@ -114,7 +114,21 @@ public class XgDormManagerSourceController extends BaseController {
|
||||
@PostMapping("/assignScope")
|
||||
public R<Void> assignScope(@RequestParam @NotNull(message = "管理员ID不能为空") Long managerId,
|
||||
@RequestParam @NotNull(message = "授权类型不能为空") Character authType,
|
||||
@RequestBody @NotEmpty(message = "授权来源ID不能为空") List<Long> authSourceIds) {
|
||||
@RequestBody List<Long> 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<String> getScopeNames(@RequestParam @NotNull(message = "管理员ID不能为空") Long managerId,
|
||||
@RequestParam @NotNull(message = "管理员类型不能为空") Integer managerType) {
|
||||
return R.ok(xgDormManagerSourceService.getScopeNames(managerId, managerType));
|
||||
}
|
||||
}
|
||||
-1
@@ -63,5 +63,4 @@ public class XgDormManagerSourceBo extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
+65
@@ -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<BuildingTreeSelectVo> children;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private java.util.Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private java.util.Date updateTime;
|
||||
}
|
||||
+63
@@ -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<TreeSelectVo> 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);
|
||||
}
|
||||
}
|
||||
-3
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
+26
@@ -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<XgDormManagerSource, XgDormManagerSourceVo> {
|
||||
|
||||
/**
|
||||
* 根据ID列表获取校区名称(逗号分隔)
|
||||
*
|
||||
* @param sourceIds 校区ID列表
|
||||
* @return 校区名称,多个以逗号分隔
|
||||
*/
|
||||
String getCampusNamesByIds(@Param("sourceIds") List<Long> sourceIds);
|
||||
|
||||
/**
|
||||
* 根据ID列表获取宿舍区名称(逗号分隔)
|
||||
*
|
||||
* @param sourceIds 宿舍区ID列表
|
||||
* @return 宿舍区名称,多个以逗号分隔
|
||||
*/
|
||||
String getAreaNamesByIds(@Param("sourceIds") List<Long> sourceIds);
|
||||
|
||||
/**
|
||||
* 根据ID列表获取宿舍楼名称(逗号分隔)
|
||||
*
|
||||
* @param sourceIds 宿舍楼ID列表
|
||||
* @return 宿舍楼名称,多个以逗号分隔
|
||||
*/
|
||||
String getBuildingNamesByIds(@Param("sourceIds") List<Long> sourceIds);
|
||||
}
|
||||
+9
@@ -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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 获取宿舍区树形结构数据
|
||||
* 以校区为根节点,宿舍区为子节点
|
||||
*
|
||||
* @return 宿舍区树形结构列表
|
||||
*/
|
||||
List<TreeSelectVo> getAreaTree();
|
||||
}
|
||||
+9
@@ -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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构数据
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
*
|
||||
* @return 树形结构数据
|
||||
*/
|
||||
List<BuildingTreeSelectVo> getBuildingTreeData();
|
||||
}
|
||||
+12
-23
@@ -18,51 +18,31 @@ public interface IXgDormManagerSourceService {
|
||||
|
||||
/**
|
||||
* 查询管理员授权关系
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 管理员授权关系
|
||||
*/
|
||||
XgDormManagerSourceVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询管理员授权关系列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 管理员授权关系分页列表
|
||||
* 查询管理员授权关系列表
|
||||
*/
|
||||
TableDataInfo<XgDormManagerSourceVo> queryPageList(XgDormManagerSourceBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的管理员授权关系列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 管理员授权关系列表
|
||||
* 查询管理员授权关系列表
|
||||
*/
|
||||
List<XgDormManagerSourceVo> 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<Long> 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<Long> authSourceIds);
|
||||
|
||||
/**
|
||||
* 获取管理员授权范围名称
|
||||
*
|
||||
* @param managerId 管理员ID
|
||||
* @param managerType 管理员类型(1全校级 2校区级 3宿舍区级 4楼栋级)
|
||||
* @return 授权范围名称(逗号分隔字符串)
|
||||
*/
|
||||
String getScopeNames(Long managerId, Integer managerType);
|
||||
}
|
||||
+59
@@ -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<TreeSelectVo> getAreaTree() {
|
||||
// 1. 获取所有校区数据
|
||||
List<XgDormCampusVo> campusList = dormCampusService.queryList(new XgDormCampusBo());
|
||||
|
||||
// 2. 获取所有宿舍区数据
|
||||
List<XgDormAreaVo> areaList = queryList(new XgDormAreaBo());
|
||||
|
||||
// 3. 构建树形结构
|
||||
List<TreeSelectVo> treeList = new ArrayList<>();
|
||||
|
||||
// 4. 创建校区节点(校区节点不可选择)
|
||||
for (XgDormCampusVo campus : campusList) {
|
||||
// 校区节点不可选择
|
||||
TreeSelectVo campusNode = new TreeSelectVo(
|
||||
campus.getId(),
|
||||
campus.getCampusName(),
|
||||
"campus",
|
||||
true // 禁用校区节点,不可选择
|
||||
);
|
||||
|
||||
// 5. 添加对应校区的宿舍区节点
|
||||
List<XgDormAreaVo> 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;
|
||||
}
|
||||
}
|
||||
+100
@@ -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<BuildingTreeSelectVo> getBuildingTreeData() {
|
||||
// 1. 获取所有校区数据
|
||||
List<XgDormCampus> campusList = campusMapper.selectList(
|
||||
Wrappers.<XgDormCampus>lambdaQuery()
|
||||
.orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId));
|
||||
|
||||
// 2. 获取所有宿舍区数据
|
||||
List<XgDormArea> areaList = areaMapper.selectList(
|
||||
Wrappers.<XgDormArea>lambdaQuery()
|
||||
.orderByAsc(XgDormArea::getSortOrder, XgDormArea::getId));
|
||||
|
||||
// 3. 获取所有宿舍楼数据
|
||||
List<XgDormBuilding> buildingList = baseMapper.selectList(
|
||||
Wrappers.<XgDormBuilding>lambdaQuery()
|
||||
.orderByAsc(XgDormBuilding::getSortOrder, XgDormBuilding::getId));
|
||||
|
||||
// 4. 构建树形结构
|
||||
List<BuildingTreeSelectVo> 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<XgDormArea> 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<XgDormBuilding> 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;
|
||||
}
|
||||
}
|
||||
+84
-22
@@ -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<Long> authSourceIds) {
|
||||
if (managerId == null || authType == null || authSourceIds == null || authSourceIds.isEmpty()) {
|
||||
if (managerId == null || authType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 先逻辑删除该管理员现有的对应类型的授权数据
|
||||
// 1. 逻辑删除该管理员指定授权类型的现有数据
|
||||
LambdaUpdateWrapper<XgDormManagerSource> 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<XgDormManagerSource> 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<XgDormManagerSource> queryWrapper = Wrappers.lambdaQuery(XgDormManagerSource.class)
|
||||
.eq(XgDormManagerSource::getManagerId, managerId)
|
||||
.eq(XgDormManagerSource::getAuthType, authType)
|
||||
.eq(XgDormManagerSource::getDeleted, "0") // 未删除的记录
|
||||
.eq(XgDormManagerSource::getStatus, "0"); // 状态为有效
|
||||
|
||||
List<XgDormManagerSource> sources = baseMapper.selectList(queryWrapper);
|
||||
if (sources.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 提取授权来源ID列表
|
||||
List<Long> 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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -4,4 +4,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.xg.mapper.XgDormManagerSourceMapper">
|
||||
|
||||
<!-- 根据ID列表获取校区名称(逗号分隔) -->
|
||||
<select id="getCampusNamesByIds" resultType="String">
|
||||
SELECT
|
||||
GROUP_CONCAT(campus_name SEPARATOR ',')
|
||||
FROM
|
||||
xg_dorm_campus
|
||||
WHERE
|
||||
id IN
|
||||
<foreach collection="sourceIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = '0'
|
||||
</select>
|
||||
|
||||
<!-- 根据ID列表获取宿舍区名称(逗号分隔) -->
|
||||
<select id="getAreaNamesByIds" resultType="String">
|
||||
SELECT
|
||||
GROUP_CONCAT(area_name SEPARATOR ',')
|
||||
FROM
|
||||
xg_dorm_area
|
||||
WHERE
|
||||
id IN
|
||||
<foreach collection="sourceIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = '0'
|
||||
</select>
|
||||
|
||||
<!-- 根据ID列表获取宿舍楼名称(逗号分隔) -->
|
||||
<select id="getBuildingNamesByIds" resultType="String">
|
||||
SELECT
|
||||
GROUP_CONCAT(building_name SEPARATOR ',')
|
||||
FROM
|
||||
xg_dorm_building
|
||||
WHERE
|
||||
id IN
|
||||
<foreach collection="sourceIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = '0'
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -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<BuildingTreeSelectVo[]>`
|
||||
|
||||
3. 修改`ScopeDialog.vue`组件:
|
||||
- 为宿舍楼类型(type="building")添加独立的树形选择器
|
||||
- 移除原有的模拟数据,改用API获取真实数据
|
||||
- 添加宿舍楼数据回显和解析逻辑
|
||||
- 保留对校区和宿舍区的原有支持
|
||||
|
||||
## 技术实现
|
||||
|
||||
树形结构数据构建采用三步查询 + 组装的方式:
|
||||
1. 首先查询所有校区数据
|
||||
2. 查询所有宿舍区数据
|
||||
3. 查询所有宿舍楼数据
|
||||
4. 通过Stream API过滤和关联数据,构建多层嵌套结构
|
||||
|
||||
## 使用说明
|
||||
|
||||
1. 校区管理员授权时,使用普通多选下拉框
|
||||
2. 宿舍区管理员授权时,使用以校区为父节点的两级树形结构
|
||||
3. 宿舍楼管理员授权时,使用新开发的三级树形结构(校区-宿舍区-宿舍楼)
|
||||
- 校区和宿舍区节点自动禁用,不可选择
|
||||
- 只有宿舍楼节点可以选择
|
||||
- 支持多选和折叠标签
|
||||
+29
-170
@@ -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文档结构,创建统一导航入口
|
||||
@@ -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<BuildingTreeSelectVo> | 子节点列表 |
|
||||
| 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<BuildingTreeSelectVo[]>([]);
|
||||
|
||||
// 加载宿舍楼树形数据
|
||||
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
|
||||
<el-tree-select
|
||||
v-model="selectedBuildings"
|
||||
placeholder="请选择宿舍楼"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:data="treeData"
|
||||
:props="{
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
disabled: 'disabled',
|
||||
value: 'id'
|
||||
}"
|
||||
check-strictly
|
||||
/>
|
||||
```
|
||||
|
||||
## 特殊说明
|
||||
|
||||
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
|
||||
@@ -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字段
|
||||
- 树形数据的构建逻辑是:先查询所有校区,再查询所有宿舍区,然后根据关联关系构建树形结构
|
||||
@@ -61,3 +61,37 @@ export const delDormManager = (id: string | number | Array<string | number>) =>
|
||||
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
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -49,6 +49,11 @@ export interface DormManagerVO {
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
/**
|
||||
* 授权范围名称(逗号分隔的字符串)
|
||||
*/
|
||||
scopeNames?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface DormManagerForm extends BaseEntity {
|
||||
|
||||
@@ -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<any>
|
||||
params: { campusId }
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构数据(校区-宿舍区-宿舍楼三级结构)
|
||||
* 校区和宿舍区节点不可选,只有宿舍楼节点可以选择
|
||||
*/
|
||||
export const getBuildingTree = (): AxiosPromise<BuildingTreeSelectVo[]> => {
|
||||
return request({
|
||||
url: '/sslxx/dormBuilding/buildingTree',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
@@ -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<DormBuildingVO, 'createTime' | 'createBy' | 'updateTime' | 'updateBy' | 'areaName' | 'campusName'> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 宿舍楼编码
|
||||
*/
|
||||
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<string, any>;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<string | number>) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取宿舍区树形结构数据
|
||||
* 以校区为根节点,宿舍区为子节点的树形结构
|
||||
*/
|
||||
export const getAreaTree = (): AxiosPromise<TreeSelectVo[]> => {
|
||||
return request({
|
||||
url: '/ssqxx/dormArea/tree',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
@@ -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[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,18 +5,70 @@
|
||||
<span>{{ admin?.name }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="管理范围" prop="scope">
|
||||
<!-- 校区类型使用原有的多选下拉框 -->
|
||||
<el-select
|
||||
v-if="type === 'campus'"
|
||||
v-model="form.scope"
|
||||
placeholder="请选择管理范围"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
filterable
|
||||
:multiple="isCampusType"
|
||||
multiple
|
||||
collapse-tags
|
||||
default-expand-all
|
||||
collapse-tags-tooltip
|
||||
>
|
||||
<el-option v-for="item in scopeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
|
||||
<!-- 宿舍区类型使用树形选择器 -->
|
||||
<el-tree-select
|
||||
v-else-if="type === 'area'"
|
||||
v-model="form.scope"
|
||||
placeholder="请选择宿舍区"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
default-expand-all
|
||||
:data="treeData"
|
||||
:props="{
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
disabled: 'disabled',
|
||||
value: 'id'
|
||||
}"
|
||||
check-strictly
|
||||
/>
|
||||
|
||||
<!-- 宿舍楼类型使用新的树形选择器 -->
|
||||
<el-tree-select
|
||||
v-else-if="type === 'building'"
|
||||
v-model="form.scope"
|
||||
placeholder="请选择宿舍楼"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
default-expand-all
|
||||
:data="buildingTreeData"
|
||||
:props="{
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
disabled: 'disabled',
|
||||
value: 'id'
|
||||
}"
|
||||
check-strictly
|
||||
/>
|
||||
|
||||
<!-- 其他类型保持原有的单选下拉框 -->
|
||||
<el-select v-else v-model="form.scope" placeholder="请选择管理范围" style="width: 100%" clearable filterable>
|
||||
<el-option v-for="item in scopeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@@ -31,6 +83,10 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import { listDormCampus } from '@/api/xqxx/dormCampus';
|
||||
import { getAreaTree } from '@/api/ssqxx/dormArea';
|
||||
import { getBuildingTree } from '@/api/sslxx/dormBuilding';
|
||||
import type { TreeSelectVo } from '@/api/ssqxx/dormArea/types';
|
||||
import type { BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ScopeDialog',
|
||||
@@ -59,47 +115,231 @@ export default defineComponent({
|
||||
|
||||
// 判断是否为校区类型的计算属性
|
||||
const isCampusType = computed(() => props.type === 'campus');
|
||||
// 判断是否为宿舍区类型的计算属性
|
||||
const isAreaType = computed(() => props.type === 'area');
|
||||
// 判断是否为宿舍楼类型的计算属性
|
||||
const isBuildingType = computed(() => props.type === 'building');
|
||||
|
||||
const formRef = ref();
|
||||
const form = reactive({
|
||||
scope: isCampusType.value ? [] : ''
|
||||
scope: isCampusType.value || isAreaType.value || isBuildingType.value ? [] : ''
|
||||
});
|
||||
|
||||
// 选项数据
|
||||
// 下拉选项数据
|
||||
const scopeOptions = ref<any[]>([]);
|
||||
|
||||
// 宿舍区树形数据
|
||||
const treeData = ref<TreeSelectVo[]>([]);
|
||||
|
||||
// 宿舍楼树形数据
|
||||
const buildingTreeData = ref<BuildingTreeSelectVo[]>([]);
|
||||
|
||||
// 标记是否完成数据加载的状态
|
||||
const dataLoaded = ref(false);
|
||||
|
||||
// 处理scope字符串为数组的辅助函数(校区使用)
|
||||
const parseScopeString = (scopeString: string) => {
|
||||
if (!scopeString) return [];
|
||||
// 尝试按逗号分隔并提取ID (假设格式为: "东校区,西校区")
|
||||
return scopeString
|
||||
.split(',')
|
||||
.map((item) => {
|
||||
// 在校区选项中查找匹配的校区名称
|
||||
const option = scopeOptions.value.find((opt) => opt.label === item.trim());
|
||||
return option ? option.value : null;
|
||||
})
|
||||
.filter((id) => id !== null); // 过滤掉未找到的项
|
||||
};
|
||||
|
||||
// 处理宿舍区scope字符串为数组的辅助函数
|
||||
const parseAreaScopeString = (scopeString: string) => {
|
||||
if (!scopeString) return [];
|
||||
// 尝试按逗号分隔宿舍区名称
|
||||
const areaNames = scopeString.split(',').map((item) => item.trim());
|
||||
|
||||
// 在树形数据中查找匹配的宿舍区ID
|
||||
const findAreaIds = (nodes: TreeSelectVo[]): number[] => {
|
||||
if (!nodes || nodes.length === 0) return [];
|
||||
|
||||
let result: number[] = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
// 如果节点标签匹配任何一个宿舍区名称,添加该节点ID
|
||||
if (areaNames.includes(node.label)) {
|
||||
result.push(node.id);
|
||||
}
|
||||
|
||||
// 如果有子节点,递归查找
|
||||
if (node.children && node.children.length > 0) {
|
||||
result = [...result, ...findAreaIds(node.children)];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return findAreaIds(treeData.value);
|
||||
};
|
||||
|
||||
// 处理宿舍楼scope字符串为数组的辅助函数
|
||||
const parseBuildingScopeString = (scopeString: string) => {
|
||||
if (!scopeString) return [];
|
||||
// 尝试按逗号分隔宿舍楼名称
|
||||
const buildingNames = scopeString.split(',').map((item) => item.trim());
|
||||
|
||||
// 在树形数据中查找匹配的宿舍楼ID
|
||||
const findBuildingIds = (nodes: BuildingTreeSelectVo[]): number[] => {
|
||||
if (!nodes || nodes.length === 0) return [];
|
||||
|
||||
let result: number[] = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
// 如果是宿舍楼节点,且名称匹配,添加该节点ID
|
||||
if (node.nodeType === 'building' && buildingNames.includes(node.label)) {
|
||||
result.push(node.id);
|
||||
}
|
||||
|
||||
// 如果有子节点,递归查找
|
||||
if (node.children && node.children.length > 0) {
|
||||
result = [...result, ...findBuildingIds(node.children)];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return findBuildingIds(buildingTreeData.value);
|
||||
};
|
||||
|
||||
// 根据类型加载选项
|
||||
const loadScopeOptions = async () => {
|
||||
dataLoaded.value = false;
|
||||
if (isCampusType.value) {
|
||||
// 调用API获取校区列表
|
||||
const res = await listDormCampus();
|
||||
// 适配el-select格式
|
||||
console.log(res);
|
||||
scopeOptions.value = (res.rows || []).map((item: any) => ({
|
||||
value: item.id,
|
||||
label: item.campusName
|
||||
}));
|
||||
// 校区支持多选,初始化为数组
|
||||
form.scope = Array.isArray(form.scope) ? form.scope : [];
|
||||
} else if (props.type === 'area') {
|
||||
scopeOptions.value = [
|
||||
{ value: '1号宿舍区', label: '1号宿舍区' },
|
||||
{ value: '2号宿舍区', label: '2号宿舍区' },
|
||||
{ value: '3号宿舍区', label: '3号宿舍区' }
|
||||
];
|
||||
// 非校区为单选,初始化为字符串
|
||||
form.scope = Array.isArray(form.scope) ? '' : form.scope;
|
||||
try {
|
||||
const res = await listDormCampus();
|
||||
// 适配el-select格式
|
||||
console.log('校区数据加载成功:', res);
|
||||
scopeOptions.value = (res.rows || []).map((item: any) => ({
|
||||
value: item.id,
|
||||
label: item.campusName
|
||||
}));
|
||||
// 校区支持多选,初始化为数组
|
||||
form.scope = Array.isArray(form.scope) ? form.scope : [];
|
||||
dataLoaded.value = true;
|
||||
// 数据加载完成后,处理当前管理员的scope
|
||||
handleAdminScope();
|
||||
} catch (error) {
|
||||
console.error('加载校区数据失败:', error);
|
||||
dataLoaded.value = true;
|
||||
}
|
||||
} else if (isAreaType.value) {
|
||||
// 宿舍区类型时加载树形数据
|
||||
try {
|
||||
const res = await getAreaTree();
|
||||
if (res && res.data) {
|
||||
treeData.value = res.data;
|
||||
console.log('宿舍区树形数据加载成功:', treeData.value);
|
||||
}
|
||||
// 宿舍区使用树形选择,支持多选
|
||||
form.scope = Array.isArray(form.scope) ? form.scope : [];
|
||||
dataLoaded.value = true;
|
||||
// 数据加载完成后,处理当前管理员的scope
|
||||
handleAdminScope();
|
||||
} catch (error) {
|
||||
console.error('加载树形数据失败:', error);
|
||||
dataLoaded.value = true;
|
||||
}
|
||||
} else if (isBuildingType.value) {
|
||||
// 宿舍楼类型时加载树形数据
|
||||
try {
|
||||
const res = await getBuildingTree();
|
||||
if (res && res.data) {
|
||||
buildingTreeData.value = res.data;
|
||||
console.log('宿舍楼树形数据加载成功:', buildingTreeData.value);
|
||||
}
|
||||
// 宿舍楼使用树形选择,支持多选
|
||||
form.scope = Array.isArray(form.scope) ? form.scope : [];
|
||||
dataLoaded.value = true;
|
||||
// 数据加载完成后,处理当前管理员的scope
|
||||
handleAdminScope();
|
||||
} catch (error) {
|
||||
console.error('加载宿舍楼树形数据失败:', error);
|
||||
dataLoaded.value = true;
|
||||
}
|
||||
} else if (props.type === 'building') {
|
||||
scopeOptions.value = [
|
||||
{ value: '1号楼', label: '1号楼' },
|
||||
{ value: '2号楼', label: '2号楼' },
|
||||
{ value: '3号楼', label: '3号楼' },
|
||||
{ value: '4号楼', label: '4号楼' }
|
||||
];
|
||||
// 非校区为单选,初始化为字符串
|
||||
form.scope = Array.isArray(form.scope) ? '' : form.scope;
|
||||
// 这段代码已被上面的isBuildingType.value条件替代,保留此处以兼容旧代码
|
||||
// 将在下一次重构时移除
|
||||
dataLoaded.value = true;
|
||||
// 数据加载完成后,处理当前管理员的scope
|
||||
handleAdminScope();
|
||||
} else {
|
||||
scopeOptions.value = [];
|
||||
dataLoaded.value = true;
|
||||
// 数据加载完成后,处理当前管理员的scope
|
||||
handleAdminScope();
|
||||
}
|
||||
};
|
||||
|
||||
// 创建单独的函数处理admin的scope,确保在数据加载完成后执行
|
||||
const handleAdminScope = () => {
|
||||
const admin = props.admin;
|
||||
if (!admin || !dataLoaded.value) return;
|
||||
|
||||
// 根据类型决定如何设置scope值
|
||||
if (isCampusType.value) {
|
||||
// 校区类型 - 支持多选
|
||||
if (admin.scope) {
|
||||
// 判断scope的类型
|
||||
if (Array.isArray(admin.scope)) {
|
||||
// 如果已经是数组,直接使用
|
||||
form.scope = admin.scope;
|
||||
} else if (typeof admin.scope === 'string') {
|
||||
// 如果是字符串,需要解析
|
||||
form.scope = parseScopeString(admin.scope);
|
||||
} else {
|
||||
// 其他情况,初始化为空数组
|
||||
form.scope = [];
|
||||
}
|
||||
console.log('校区管理员回显数据:', form.scope);
|
||||
} else {
|
||||
form.scope = [];
|
||||
}
|
||||
} else if (isAreaType.value) {
|
||||
// 宿舍区类型 - 支持多选
|
||||
if (admin.scope) {
|
||||
if (Array.isArray(admin.scope)) {
|
||||
// 如果已经是数组,直接使用
|
||||
form.scope = admin.scope;
|
||||
} else if (typeof admin.scope === 'string') {
|
||||
// 如果是字符串,需要解析为树形选择器所需的ID数组
|
||||
form.scope = parseAreaScopeString(admin.scope);
|
||||
} else {
|
||||
form.scope = [];
|
||||
}
|
||||
console.log('宿舍区管理员回显数据:', form.scope);
|
||||
} else {
|
||||
form.scope = [];
|
||||
}
|
||||
} else if (isBuildingType.value) {
|
||||
// 宿舍楼类型 - 支持多选
|
||||
if (admin.scope) {
|
||||
if (Array.isArray(admin.scope)) {
|
||||
// 如果已经是数组,直接使用
|
||||
form.scope = admin.scope;
|
||||
} else if (typeof admin.scope === 'string') {
|
||||
// 如果是字符串,需要解析为树形选择器所需的ID数组
|
||||
form.scope = parseBuildingScopeString(admin.scope);
|
||||
} else {
|
||||
form.scope = [];
|
||||
}
|
||||
console.log('宿舍楼管理员回显数据:', form.scope);
|
||||
} else {
|
||||
form.scope = [];
|
||||
}
|
||||
} else {
|
||||
// 其他类型 - 单选
|
||||
form.scope = admin.scope || '';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,35 +352,82 @@ export default defineComponent({
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 监听对话框可见性,确保每次打开时都重新加载数据
|
||||
watch(
|
||||
() => dialogVisible.value,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// 对话框打开时,确保重新加载数据
|
||||
loadScopeOptions();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听admin变化
|
||||
watch(
|
||||
() => props.admin,
|
||||
(newVal) => {
|
||||
if (newVal && newVal.scope) {
|
||||
// 根据类型决定如何设置scope值
|
||||
if (isCampusType.value) {
|
||||
// 校区支持多选,确保scope是数组
|
||||
form.scope = Array.isArray(newVal.scope) ? newVal.scope : [newVal.scope];
|
||||
} else {
|
||||
// 其他类型是单选
|
||||
form.scope = newVal.scope;
|
||||
}
|
||||
() => {
|
||||
// 如果数据已加载完成,则立即处理admin的scope
|
||||
if (dataLoaded.value) {
|
||||
handleAdminScope();
|
||||
}
|
||||
// 否则,会在loadScopeOptions完成后自动调用handleAdminScope
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const submitForm = () => {
|
||||
emit('submit', form.scope);
|
||||
// 将form.scope转换为API所需的格式
|
||||
let result;
|
||||
if (Array.isArray(form.scope)) {
|
||||
// 对于多选,发送选中的ID数组
|
||||
result = {
|
||||
sourceIds: form.scope
|
||||
};
|
||||
} else {
|
||||
// 对于单选,将字符串ID包装在数组中
|
||||
result = {
|
||||
sourceIds: form.scope ? [form.scope] : []
|
||||
};
|
||||
}
|
||||
emit('submit', result);
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
// 在对话框打开时,重置数据状态,防止旧数据影响新的显示
|
||||
watch(
|
||||
() => dialogVisible.value,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// 对话框打开时,先清空数据,确保重新加载
|
||||
scopeOptions.value = [];
|
||||
treeData.value = [];
|
||||
buildingTreeData.value = [];
|
||||
dataLoaded.value = false;
|
||||
|
||||
// 根据类型设置默认值
|
||||
if (isCampusType.value || isAreaType.value || isBuildingType.value) {
|
||||
form.scope = [];
|
||||
} else {
|
||||
form.scope = '';
|
||||
}
|
||||
|
||||
// 然后加载新数据
|
||||
loadScopeOptions();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
dialogVisible,
|
||||
form,
|
||||
formRef,
|
||||
scopeOptions,
|
||||
treeData,
|
||||
buildingTreeData,
|
||||
submitForm,
|
||||
isCampusType
|
||||
isCampusType,
|
||||
type: computed(() => props.type)
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
+125
-44
@@ -218,11 +218,17 @@
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import AdminDialog from './components/AdminDialog.vue';
|
||||
import ScopeDialog from './components/ScopeDialog.vue';
|
||||
import axios from 'axios';
|
||||
import { listDormManager } from '@/api/ssglyxx/dormManager';
|
||||
import { delDormManager } from '@/api/ssglyxx/dormManager';
|
||||
import request from '@/utils/request';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
// API路径
|
||||
const apiUrl = {
|
||||
list: '/ssglyxx/dormManager/list',
|
||||
delete: '/ssglyxx/dormManager/',
|
||||
assignScope: '/glysqgx/dormManagerSource/assignScope',
|
||||
getScopeNames: '/glysqgx/dormManagerSource/getScopeNames'
|
||||
};
|
||||
|
||||
const activeTab = ref('school');
|
||||
|
||||
// 各tab独立检索表单
|
||||
@@ -287,38 +293,80 @@ async function fetchAdmins(type: string) {
|
||||
Object.keys(params).forEach((key) => {
|
||||
if (params[key] === '' || params[key] === undefined) delete params[key];
|
||||
});
|
||||
// const res = await axios.get('/ssglyxx/dormManager/list', { params });
|
||||
const res = await listDormManager(params);
|
||||
// 兼容TableDataInfo和R结构
|
||||
let data = [];
|
||||
if (Array.isArray(res.data)) {
|
||||
data = res.data;
|
||||
} else if (res.rows) {
|
||||
data = res?.rows;
|
||||
}
|
||||
// console.log(data);
|
||||
const mappedData = data.map((item: any) => ({
|
||||
id: item.id,
|
||||
name: item.managerName, // 映射
|
||||
phone: item.phone,
|
||||
sex: typeof item.gender === 'number' ? item.gender : Number(item.gender), // gender转数字
|
||||
remark: item.remark
|
||||
// 其他字段按需添加
|
||||
}));
|
||||
// console.log(mappedData);
|
||||
switch (type) {
|
||||
case 'school':
|
||||
schoolAdmins.value = mappedData;
|
||||
break;
|
||||
case 'campus':
|
||||
campusAdmins.value = mappedData;
|
||||
break;
|
||||
case 'area':
|
||||
areaAdmins.value = mappedData;
|
||||
break;
|
||||
case 'building':
|
||||
buildingAdmins.value = mappedData;
|
||||
break;
|
||||
|
||||
try {
|
||||
// 获取管理员列表
|
||||
const res = await request({
|
||||
url: apiUrl.list,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
|
||||
// 兼容TableDataInfo和R结构
|
||||
let data = [];
|
||||
if (Array.isArray(res.data)) {
|
||||
data = res.data;
|
||||
} else if (res.rows) {
|
||||
data = res?.rows;
|
||||
}
|
||||
|
||||
// 预处理管理员数据
|
||||
const mappedData = await Promise.all(
|
||||
data.map(async (item: any) => {
|
||||
// 基础字段映射
|
||||
const manager = {
|
||||
id: item.id,
|
||||
name: item.managerName, // 映射
|
||||
phone: item.phone,
|
||||
sex: typeof item.gender === 'number' ? item.gender : Number(item.gender), // gender转数字
|
||||
remark: item.remark,
|
||||
scope: '' // 初始化scope字段
|
||||
};
|
||||
|
||||
// 非全校级管理员需要获取授权范围
|
||||
if (managerType > 1) {
|
||||
try {
|
||||
// 获取授权范围名称
|
||||
const scopeRes = await request({
|
||||
url: apiUrl.getScopeNames,
|
||||
method: 'get',
|
||||
params: {
|
||||
managerId: item.id,
|
||||
managerType: managerType
|
||||
}
|
||||
});
|
||||
|
||||
console.log(scopeRes.msg);
|
||||
if (scopeRes) {
|
||||
manager.scope = scopeRes.msg;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取管理员授权范围失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
return manager;
|
||||
})
|
||||
);
|
||||
|
||||
// 更新对应类型的管理员数据
|
||||
switch (type) {
|
||||
case 'school':
|
||||
schoolAdmins.value = mappedData;
|
||||
break;
|
||||
case 'campus':
|
||||
campusAdmins.value = mappedData;
|
||||
break;
|
||||
case 'area':
|
||||
areaAdmins.value = mappedData;
|
||||
break;
|
||||
case 'building':
|
||||
buildingAdmins.value = mappedData;
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取管理员列表失败:', error);
|
||||
ElMessage.error('获取管理员列表失败');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,8 +384,6 @@ function onAdd(type: string) {
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
function onEdit(type: string, admin: any) {
|
||||
console.log('onEdit=============');
|
||||
console.log(admin);
|
||||
dialogMode.value = 'edit';
|
||||
currentAdmin.value = { ...admin };
|
||||
activeTab.value = type; // 确保当前标签页与编辑的管理员类型一致
|
||||
@@ -352,7 +398,10 @@ async function onDelete(type: string, admin: any) {
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
await delDormManager(admin.id);
|
||||
await request({
|
||||
url: apiUrl.delete + admin.id,
|
||||
method: 'delete'
|
||||
});
|
||||
ElMessage.success('删除成功');
|
||||
fetchAdmins(type); // 删除后刷新
|
||||
} catch (e) {
|
||||
@@ -380,12 +429,44 @@ function onDialogSubmit(admin: any) {
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
function onScopeSubmit(scope: string) {
|
||||
// TODO: 分配范围时调用API,成功后刷新
|
||||
const list = getListByType(scopeType.value);
|
||||
const idx = list.value.findIndex((a: any) => a.id === currentAdmin.value.id);
|
||||
if (idx !== -1) list.value[idx].scope = scope;
|
||||
scopeDialogVisible.value = false;
|
||||
async function onScopeSubmit(scope: any) {
|
||||
try {
|
||||
// 将scope类型转换为数字
|
||||
let authType = 1;
|
||||
switch (scopeType.value) {
|
||||
case 'school':
|
||||
authType = 1;
|
||||
break;
|
||||
case 'campus':
|
||||
authType = 2;
|
||||
break;
|
||||
case 'area':
|
||||
authType = 3;
|
||||
break;
|
||||
case 'building':
|
||||
authType = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// 调用API
|
||||
await request({
|
||||
url: apiUrl.assignScope,
|
||||
method: 'post',
|
||||
params: {
|
||||
managerId: currentAdmin.value.id,
|
||||
authType: authType
|
||||
},
|
||||
data: scope.sourceIds
|
||||
});
|
||||
|
||||
// 成功后刷新数据并提示
|
||||
ElMessage.success('管理范围分配成功');
|
||||
fetchAdmins(scopeType.value);
|
||||
scopeDialogVisible.value = false;
|
||||
} catch (error) {
|
||||
ElMessage.error('管理范围分配失败');
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
function getListByType(type: string) {
|
||||
switch (type) {
|
||||
|
||||
+2
-2
@@ -232,7 +232,7 @@ cd backend
|
||||
#### 3. 启动主应用服务
|
||||
|
||||
```bash
|
||||
./hot-start.sh
|
||||
./start-main.sh
|
||||
```
|
||||
|
||||
**等待提示**: 看到 "主应用启动成功" 或访问 `http://localhost:8080` 正常返回
|
||||
@@ -255,7 +255,7 @@ cd backend
|
||||
cd backend
|
||||
bash start-monitor.sh
|
||||
bash start-job.sh
|
||||
bash hot-start.sh
|
||||
bash start-main.sh
|
||||
|
||||
# 或者直接运行 Java 命令
|
||||
java -jar ruoyi-extend/ruoyi-monitor-admin/target/ruoyi-monitor-admin.jar
|
||||
|
||||
Reference in new issue
Block a user