Commit d0367d25 by Lizh

适配custom-back的返回结构

parent 3c97de77
......@@ -14,6 +14,30 @@ import java.util.List;
public interface SysDeptService {
/**
* 检查是否有子部门
*
* @param deptId 部门ID
* @return true-有子部门
*/
boolean hasChildByDeptId(Long deptId);
/**
* 检查部门下是否存在用户
*
* @param deptId 部门ID
* @return true-存在用户
*/
boolean checkDeptExistUser(Long deptId);
/**
* 统计正常状态的子部门数量
*
* @param deptId 部门ID
* @return 正常子部门数量
*/
long countNormalChildrenByDeptId(Long deptId);
/**
* 查询部门列表(树结构)
*
* @param dept 查询条件
......
......@@ -61,6 +61,22 @@ public interface SysMenuService {
void edit(SysMenuUpdateDTO dto);
/**
* 检查菜单是否有子菜单
*
* @param menuId 菜单ID
* @return true-有子菜单
*/
boolean hasChildByMenuId(Long menuId);
/**
* 检查菜单是否已分配给角色
*
* @param menuId 菜单ID
* @return true-已分配
*/
boolean checkMenuAssignedToRole(Long menuId);
/**
* 删除菜单
*
* @param menuId 菜单ID
......
......@@ -6,6 +6,8 @@ import com.jomalls.custom.app.dto.system.SysPostSaveDTO;
import com.jomalls.custom.app.dto.system.SysPostUpdateDTO;
import com.jomalls.custom.app.vo.system.SysPostVO;
import java.util.List;
/**
* 岗位管理 App Service 接口
*
......@@ -14,6 +16,13 @@ import com.jomalls.custom.app.vo.system.SysPostVO;
public interface SysPostService {
/**
* 查询所有岗位列表(用于 optionselect)
*
* @return 岗位列表
*/
List<SysPostVO> listAllPosts();
/**
* 分页查询岗位列表
*
* @param post 查询条件
......
......@@ -18,6 +18,13 @@ import java.util.Map;
public interface SysRoleService {
/**
* 查询所有角色列表(用于 optionselect)
*
* @return 角色列表
*/
List<SysRoleVO> listAllRoles();
/**
* 分页查询角色列表
*
* @param role 查询条件
......
......@@ -26,6 +26,27 @@ public interface SysUserService {
IPage<SysUserVO> pageList(SysUserVO user, Page<SysUserVO> page);
/**
* 查询当前登录用户的角色组(角色名称,逗号分隔)
*
* @return 角色组字符串
*/
String getCurrentUserRoleGroup();
/**
* 查询当前登录用户的岗位组(岗位名称,逗号分隔)
*
* @return 岗位组字符串
*/
String getCurrentUserPostGroup();
/**
* 修改当前登录用户头像
*
* @param avatarUrl 头像URL
*/
void updateAvatar(String avatarUrl);
/**
* 查询用户详情(含角色列表、岗位ID)
*
* @param userId 用户ID
......@@ -37,8 +58,9 @@ public interface SysUserService {
* 新增用户
*
* @param dto 新增用户请求
* @return 原始密码(未加密)
*/
void add(SysUserSaveDTO dto);
String add(SysUserSaveDTO dto);
/**
* 修改用户
......
......@@ -46,10 +46,7 @@ public class SysComposeServerLogServiceImpl implements SysComposeServerLogServic
wrapper.orderByDesc(SysComposeServerLogEntity::getCreateTime);
IPage<SysComposeServerLogEntity> entityPage = sysComposeServerLogDomainService.page(
new Page<>(page.getCurrent(), page.getSize()), wrapper);
// Entity → VO 转换
IPage<SysComposeServerLogVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
voPage.setRecords(BeanMapper.mapper().convertList(entityPage.getRecords(), SysComposeServerLogVO.class));
return voPage;
return entityPage.convert(e -> BeanMapper.mapper().convert(e, SysComposeServerLogVO.class));
}
@Override
......
......@@ -61,10 +61,7 @@ public class SysComposeServerServiceImpl implements SysComposeServerService {
}
}
// Entity → VO 转换
IPage<SysComposeServerVO> voPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
voPage.setRecords(BeanMapper.mapper().convertList(result.getRecords(), SysComposeServerVO.class));
return voPage;
return result.convert(e -> BeanMapper.mapper().convert(e, SysComposeServerVO.class));
}
@Override
......
package com.jomalls.custom.app.service.system.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jomalls.custom.app.dto.system.SysDeptSaveDTO;
import com.jomalls.custom.app.dto.system.SysDeptUpdateDTO;
import com.jomalls.custom.app.exception.ServiceException;
......@@ -27,6 +28,25 @@ public class SysDeptServiceImpl implements SysDeptService {
private final SysDeptDomainService sysDeptDomainService;
@Override
public boolean hasChildByDeptId(Long deptId) {
return sysDeptDomainService.hasChildByDeptId(deptId);
}
@Override
public boolean checkDeptExistUser(Long deptId) {
return sysDeptDomainService.checkDeptExistUser(deptId);
}
@Override
public long countNormalChildrenByDeptId(Long deptId) {
return sysDeptDomainService.count(
new LambdaQueryWrapper<SysDeptEntity>()
.eq(SysDeptEntity::getParentId, deptId)
.eq(SysDeptEntity::getStatus, "0")
.eq(SysDeptEntity::getDelFlag, "0"));
}
@Override
public List<SysDeptVO> selectDeptList(SysDeptVO dept) {
SysDeptEntity query = BeanMapper.mapper().convert(dept, SysDeptEntity.class);
// 查询扁平部门列表
......
......@@ -93,11 +93,25 @@ public class SysMenuServiceImpl implements SysMenuService {
}
@Override
public void remove(Long menuId) {
// 检查是否有子菜单
public boolean hasChildByMenuId(Long menuId) {
long count = sysMenuDomainService.count(
new LambdaQueryWrapper<SysMenuEntity>().eq(SysMenuEntity::getParentId, menuId));
if (count > 0) {
return count > 0;
}
@Override
public boolean checkMenuAssignedToRole(Long menuId) {
long count = sysRoleMenuDomainService.count(
new LambdaQueryWrapper<SysRoleMenuEntity>().eq(SysRoleMenuEntity::getMenuId, menuId));
return count > 0;
}
@Override
public void remove(Long menuId) {
// 检查是否有子菜单(controller 层已做检查,此处双重保障)
long childCount = sysMenuDomainService.count(
new LambdaQueryWrapper<SysMenuEntity>().eq(SysMenuEntity::getParentId, menuId));
if (childCount > 0) {
throw new ServiceException("存在子菜单,不允许删除");
}
// 删除角色菜单关联
......
......@@ -16,6 +16,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
/**
* 岗位管理 App Service 实现
*
......@@ -29,6 +31,12 @@ public class SysPostServiceImpl implements SysPostService {
private final SysPostDomainService sysPostDomainService;
@Override
public List<SysPostVO> listAllPosts() {
List<SysPostEntity> entities = sysPostDomainService.list();
return BeanMapper.mapper().convertList(entities, SysPostVO.class);
}
@Override
public IPage<SysPostVO> pageList(SysPostVO post, Page<SysPostVO> page) {
LambdaQueryWrapper<SysPostEntity> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.hasText(post.getPostCode())) {
......@@ -43,10 +51,7 @@ public class SysPostServiceImpl implements SysPostService {
wrapper.orderByAsc(SysPostEntity::getPostSort);
IPage<SysPostEntity> entityPage = sysPostDomainService.page(
new Page<>(page.getCurrent(), page.getSize()), wrapper);
// Entity → VO 转换
IPage<SysPostVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
voPage.setRecords(BeanMapper.mapper().convertList(entityPage.getRecords(), SysPostVO.class));
return voPage;
return entityPage.convert(e -> BeanMapper.mapper().convert(e, SysPostVO.class));
}
@Override
......
......@@ -41,6 +41,12 @@ public class SysRoleServiceImpl implements SysRoleService {
private final SysDeptDomainService sysDeptDomainService;
@Override
public List<SysRoleVO> listAllRoles() {
List<SysRoleEntity> entities = sysRoleDomainService.list();
return BeanMapper.mapper().convertList(entities, SysRoleVO.class);
}
@Override
public IPage<SysRoleVO> pageList(SysRoleVO role, Page<SysRoleVO> page) {
LambdaQueryWrapper<SysRoleEntity> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.hasText(role.getRoleName())) {
......@@ -56,10 +62,7 @@ public class SysRoleServiceImpl implements SysRoleService {
wrapper.orderByAsc(SysRoleEntity::getRoleSort);
IPage<SysRoleEntity> entityPage = sysRoleDomainService.page(
new Page<>(page.getCurrent(), page.getSize()), wrapper);
// Entity → VO 转换
IPage<SysRoleVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
voPage.setRecords(BeanMapper.mapper().convertList(entityPage.getRecords(), SysRoleVO.class));
return voPage;
return entityPage.convert(e -> BeanMapper.mapper().convert(e, SysRoleVO.class));
}
@Override
......@@ -202,10 +205,7 @@ public class SysRoleServiceImpl implements SysRoleService {
wrapper.eq(SysUserEntity::getDelFlag, "0");
IPage<SysUserEntity> entityPage = sysUserDomainService.page(
new Page<>(page.getCurrent(), page.getSize()), wrapper);
// Entity → VO 转换
IPage<SysUserVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
voPage.setRecords(BeanMapper.mapper().convertList(entityPage.getRecords(), SysUserVO.class));
return voPage;
return entityPage.convert(e -> BeanMapper.mapper().convert(e, SysUserVO.class));
}
@Override
......
......@@ -37,6 +37,7 @@ public class SysUserServiceImpl implements SysUserService {
private final SysUserPostDomainService sysUserPostDomainService;
private final SysRoleDomainService sysRoleDomainService;
private final SysDeptDomainService sysDeptDomainService;
private final SysPostDomainService sysPostDomainService;
private final PasswordEncoder passwordEncoder;
@Override
......@@ -58,10 +59,7 @@ public class SysUserServiceImpl implements SysUserService {
wrapper.orderByAsc(SysUserEntity::getUserId);
IPage<SysUserEntity> entityPage = sysUserDomainService.page(
new Page<>(page.getCurrent(), page.getSize()), wrapper);
// Entity → VO 转换
IPage<SysUserVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
voPage.setRecords(BeanMapper.mapper().convertList(entityPage.getRecords(), SysUserVO.class));
return voPage;
return entityPage.convert(e -> BeanMapper.mapper().convert(e, SysUserVO.class));
}
@Override
......@@ -89,7 +87,7 @@ public class SysUserServiceImpl implements SysUserService {
}
@Override
public void add(SysUserSaveDTO dto) {
public String add(SysUserSaveDTO dto) {
// DTO → Entity
SysUserEntity user = BeanMapper.mapper().convert(dto, SysUserEntity.class);
// 检查用户名唯一性
......@@ -98,6 +96,12 @@ public class SysUserServiceImpl implements SysUserService {
if (count > 0) {
throw new ServiceException("用户账号已存在");
}
// 如果未提供密码,设置默认密码
String originalPassword = user.getPassword();
if (!StringUtils.hasText(originalPassword)) {
originalPassword = "123456";
user.setPassword(originalPassword);
}
// 密码加密
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setCreateTime(new Date());
......@@ -124,6 +128,7 @@ public class SysUserServiceImpl implements SysUserService {
}
}
log.info("新增用户成功: userName={}", user.getUserName());
return originalPassword;
}
@Override
......@@ -210,6 +215,61 @@ public class SysUserServiceImpl implements SysUserService {
}
@Override
public String getCurrentUserRoleGroup() {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
return "";
}
List<SysRoleEntity> roles = sysRoleDomainService.selectRoleListByUserId(loginUser.getUserId());
if (roles == null || roles.isEmpty()) {
return "";
}
return roles.stream()
.map(SysRoleEntity::getRoleName)
.filter(Objects::nonNull)
.collect(Collectors.joining(", "));
}
@Override
public String getCurrentUserPostGroup() {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
return "";
}
List<SysUserPostEntity> userPosts = sysUserPostDomainService.list(
new LambdaQueryWrapper<SysUserPostEntity>().eq(SysUserPostEntity::getUserId, loginUser.getUserId()));
if (userPosts == null || userPosts.isEmpty()) {
return "";
}
List<Long> postIds = userPosts.stream()
.map(SysUserPostEntity::getPostId)
.collect(Collectors.toList());
List<SysPostEntity> posts = sysPostDomainService.listByIds(postIds);
if (posts == null || posts.isEmpty()) {
return "";
}
return posts.stream()
.map(SysPostEntity::getPostName)
.filter(Objects::nonNull)
.collect(Collectors.joining(", "));
}
@Override
public void updateAvatar(String avatarUrl) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
throw new ServiceException("未登录");
}
SysUserEntity user = sysUserDomainService.getById(loginUser.getUserId());
if (user == null) {
throw new ServiceException("用户不存在");
}
user.setAvatar(avatarUrl);
sysUserDomainService.updateById(user);
log.info("用户头像已更新: userId={}", loginUser.getUserId());
}
@Override
public void updateProfile(SysUserVO user) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
......@@ -236,7 +296,12 @@ public class SysUserServiceImpl implements SysUserService {
if (!passwordEncoder.matches(dto.getOldPassword(), user.getPassword())) {
throw new ServiceException("旧密码错误");
}
// 检查新密码与旧密码是否相同
if (dto.getOldPassword().equals(dto.getNewPassword())) {
throw new ServiceException("新密码不能与旧密码相同");
}
user.setPassword(passwordEncoder.encode(dto.getNewPassword()));
user.setPwdUpdateDate(new Date());
sysUserDomainService.updateById(user);
log.info("用户密码已修改: userId={}", loginUser.getUserId());
}
......
......@@ -350,7 +350,7 @@ public class TokenHandle {
stringRedisTemplate.opsForValue().set(
redisKey,
JSON.toJSONString(loginUser),
expireTime * 60,
expireTime * 60L,
java.util.concurrent.TimeUnit.SECONDS
);
}
......
package com.jomalls.custom.utils;
import com.jomalls.custom.enums.CodeEnum;
import java.io.Serial;
import java.util.HashMap;
import java.util.Objects;
/**
* 统一返回结果(HashMap 子类,与 custom-back AjaxResult 完全一致)
* <p>
* 适用于 /api/v2 接口,支持链式调用添加平铺字段。
* <pre>
* AjaxResult.success() → {"code":200, "msg":"操作成功"}
* AjaxResult.success(data) → {"code":200, "msg":"操作成功", "data":{...}}
* AjaxResult.success().put("token", "x") → {"code":200, "msg":"操作成功", "token":"x"}
* AjaxResult.error("密码错误") → {"code":500, "msg":"密码错误"}
* </pre>
*
* @author Lizh
*/
public class AjaxResult extends HashMap<String, Object> {
@Serial
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/** 操作成功 */
public static final int SUCCESS = CodeEnum.SUCCESS.getCode();
/** 操作失败 */
public static final int ERROR = CodeEnum.FAIL.getCode();
/** 警告 */
public static final int WARN = 601;
public AjaxResult() {
}
public AjaxResult(int code, String msg) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
public AjaxResult(int code, String msg, Object data) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (data != null) {
super.put(DATA_TAG, data);
}
}
/** 返回成功消息(无 data) */
public static AjaxResult success() {
return new AjaxResult(SUCCESS, "操作成功");
}
/** 返回成功数据(data 非 null 时放入 data 字段) */
public static AjaxResult success(Object data) {
return new AjaxResult(SUCCESS, "操作成功", data);
}
/** 返回成功消息(无 data) */
public static AjaxResult success(String msg) {
return new AjaxResult(SUCCESS, msg, null);
}
/** 返回成功消息 + 数据 */
public static AjaxResult success(String msg, Object data) {
return new AjaxResult(SUCCESS, msg, data);
}
/** 返回警告消息(code=601) */
public static AjaxResult warn(String msg) {
return new AjaxResult(WARN, msg, null);
}
/** 返回警告消息 + 数据 */
public static AjaxResult warn(String msg, Object data) {
return new AjaxResult(WARN, msg, data);
}
/** 返回错误消息 */
public static AjaxResult error() {
return new AjaxResult(ERROR, "操作失败");
}
/** 返回错误消息 */
public static AjaxResult error(String msg) {
return new AjaxResult(ERROR, msg, null);
}
/** 返回错误消息 + 数据 */
public static AjaxResult error(String msg, Object data) {
return new AjaxResult(ERROR, msg, data);
}
/** 返回错误(自定义 code + msg) */
public static AjaxResult error(int code, String msg) {
return new AjaxResult(code, msg, null);
}
public boolean isSuccess() {
return Objects.equals(SUCCESS, this.get(CODE_TAG));
}
public boolean isError() {
return !isSuccess();
}
/**
* 添加平铺字段(放入 HashMap,Json 序列化为根级别 key-value)
*/
@Override
public AjaxResult put(String key, Object value) {
super.put(key, value);
return this;
}
}
......@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jomalls.custom.enums.CodeEnum;
import com.jomalls.custom.page.PageAdapter;
import com.jomalls.custom.utils.AjaxResult;
import com.jomalls.custom.utils.R;
import org.jspecify.annotations.NonNull;
import org.springframework.core.MethodParameter;
......@@ -62,28 +63,53 @@ public class RestResponseBodyConfig implements ResponseBodyAdvice<Object> {
} else if (this.isNoWrapResponseUrl(requestPath)) {
return body;
} else {
// 分页结果转为老服务(TS)格式:records→list, current→curPage, total→totalRow, pages→totalPage
/*
* 未避免前端修改,兼容custom-back服务的返回结果,/api/v2 使用 AjaxResult 风格(HashMap 平铺)
* 后期如果涉及到前端修改时,请统一处理为R包装,统一返回,切记切记
* 直接返回不做 R 包装
*/
if (requestPath.startsWith("/api/v2")) {
if (body instanceof IPage<?> page) {
body = PageAdapter.from(page);
AjaxResult ar = AjaxResult.success();
ar.put("rows", page.getRecords());
ar.put("total", page.getTotal());
return ar;
}
if (body instanceof AjaxResult) {
return body;
}
// R.fail(...) 来自异常处理器 → 转为 AjaxResult.error
if (body instanceof R<?> r) {
AjaxResult ar = r.getCode() == CodeEnum.OK.getCode()
? AjaxResult.success(r.getMsg(), r.getData())
: AjaxResult.error(r.getCode(), r.getMsg());
if (r.getExtra() != null) {
ar.putAll(r.getExtra());
}
return ar;
}
if (body instanceof String) {
try {
return objectMapper.writeValueAsString(R.ok(body));
return objectMapper.writeValueAsString(AjaxResult.success(body));
} catch (Exception e) {
return body;
}
}
R<?> r = body instanceof R ? (R<?>) body : R.ok(body);
return AjaxResult.success(body);
}
// 未避免前端修改,适配原来的返回结果,/api/v2 返回 code=200(兼容 custom-back AjaxResult),/api/v3 返回 code=10000
if (requestPath.startsWith("/api/v2")) {
if (r.getCode() == CodeEnum.OK.getCode()) {
r.setCode(CodeEnum.SUCCESS.getCode());
r.setMsg(CodeEnum.SUCCESS.getMsg());
// /api/v3 使用 R<T> 风格
if (body instanceof IPage<?> page) {
body = PageAdapter.from(page);
}
if (body instanceof String) {
try {
return objectMapper.writeValueAsString(R.ok(body));
} catch (Exception e) {
return body;
}
return r;
}
return body instanceof R ? body : R.ok(body);
}
}
}
......
......@@ -46,8 +46,7 @@ public class CaptchaController {
*/
@GetMapping("/captchaImage")
@Operation(summary = "生成验证码")
@SuppressWarnings("rawtypes")
public R getCode() {
public R<Object> getCode() {
// 生成 UUID 标识
String uuid = UUID.randomUUID().toString().replace("-", "");
......
......@@ -5,8 +5,9 @@ import com.jomalls.custom.app.dto.system.SysDeptSaveDTO;
import com.jomalls.custom.app.dto.system.SysDeptUpdateDTO;
import com.jomalls.custom.app.service.system.SysDeptService;
import com.jomalls.custom.app.vo.system.SysDeptVO;
import com.jomalls.custom.utils.R;
import com.jomalls.custom.app.exception.ServiceException;
import io.swagger.v3.oas.annotations.Operation;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -29,46 +30,60 @@ public class SysDeptController {
@Operation(summary = "查询部门列表")
@RequiresPermissions("system:dept:list")
@GetMapping("/list")
public R<Object> list(SysDeptVO dept) {
return R.ok(sysDeptService.selectDeptList(dept));
public List<SysDeptVO> list(SysDeptVO dept) {
return sysDeptService.selectDeptList(dept);
}
@Operation(summary = "查询部门列表(排除指定子部门)")
@Operation(summary = "查询部门列表(排除指定子部门及其后代)")
@RequiresPermissions("system:dept:list")
@GetMapping("/list/exclude/{deptId}")
public R<Object> listExcludeChild(@PathVariable Long deptId) {
return R.ok(sysDeptService.selectDeptListExcludeChild(deptId));
public List<SysDeptVO> listExcludeChild(@PathVariable Long deptId) {
return sysDeptService.selectDeptListExcludeChild(deptId);
}
@Operation(summary = "根据ID查询部门")
@RequiresPermissions("system:dept:query")
@GetMapping("/{deptId}")
public R<SysDeptVO> getById(@PathVariable Long deptId) {
SysDeptVO dept = sysDeptService.getById(deptId);
return R.ok(dept);
public SysDeptVO getById(@PathVariable Long deptId) {
return sysDeptService.getById(deptId);
}
@Operation(summary = "新增部门")
@RequiresPermissions("system:dept:add")
@PostMapping
public R<Void> add(@RequestBody SysDeptSaveDTO dto) {
public void add(@RequestBody SysDeptSaveDTO dto) {
sysDeptService.add(dto);
return R.ok();
}
@Operation(summary = "修改部门")
@RequiresPermissions("system:dept:edit")
@PutMapping
public R<Void> edit(@RequestBody SysDeptUpdateDTO dto) {
public void edit(@RequestBody SysDeptUpdateDTO dto) {
// 禁止父部门指向自己
if (dto.getDeptId() != null && dto.getParentId() != null
&& dto.getDeptId().equals(dto.getParentId())) {
throw new ServiceException("父部门不能指向自身");
}
// 禁用部门时检查是否有正常状态的子部门
if ("1".equals(dto.getStatus())) {
long normalChildCount = sysDeptService.countNormalChildrenByDeptId(dto.getDeptId());
if (normalChildCount > 0) {
throw new ServiceException("该部门存在正常状态下的子部门,不允许禁用");
}
}
sysDeptService.edit(dto);
return R.ok();
}
@Operation(summary = "删除部门")
@RequiresPermissions("system:dept:remove")
@DeleteMapping("/{deptId}")
public R<Void> remove(@PathVariable Long deptId) {
public void remove(@PathVariable Long deptId) {
if (sysDeptService.hasChildByDeptId(deptId)) {
throw new ServiceException("存在子部门,不允许删除");
}
if (sysDeptService.checkDeptExistUser(deptId)) {
throw new ServiceException("部门存在用户,不允许删除");
}
sysDeptService.remove(deptId);
return R.ok();
}
}
......@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 登录鉴权控制器(返回风格与 custom-back AjaxResult 对齐)
* 登录鉴权控制器
*
* @author Lizh
*/
......@@ -27,12 +27,11 @@ public class SysLoginController {
private final SysLoginService sysLoginService;
/**
* 用户登录 — 平铺返回 token(仿 AjaxResult.put("token", xxx))
* 用户登录
*/
@PostMapping("/api/v2/login")
@Operation(summary = "用户登录")
@SuppressWarnings("rawtypes")
public R login(@RequestBody LoginDTO loginDTO) {
public R<Object> login(@RequestBody LoginDTO loginDTO) {
String username = loginDTO.getUsername();
String password = loginDTO.getPassword();
String code = loginDTO.getCode();
......@@ -44,12 +43,11 @@ public class SysLoginController {
}
/**
* 获取用户信息 — 平铺返回 user/roles/permissions(仿 AjaxResult.put 风格)
* 获取用户信息
*/
@GetMapping("/api/v2/getInfo")
@Operation(summary = "获取当前用户信息")
@SuppressWarnings("rawtypes")
public R getInfo() {
public R<Object> getInfo() {
LoginUserInfoVO info = sysLoginService.getInfo();
return R.ok()
.put("user", info.getUser())
......@@ -64,9 +62,8 @@ public class SysLoginController {
*/
@GetMapping("/api/v2/getRouters")
@Operation(summary = "获取前端路由菜单")
public R<List<RouterVO>> getRouters() {
List<RouterVO> routers = sysLoginService.getRouters();
return R.ok(routers);
public List<RouterVO> getRouters() {
return sysLoginService.getRouters();
}
/**
......@@ -74,9 +71,7 @@ public class SysLoginController {
*/
@PostMapping("/api/v2/logout")
@Operation(summary = "退出登录")
@SuppressWarnings("rawtypes")
public R logout() {
public void logout() {
sysLoginService.logout();
return R.ok();
}
}
......@@ -5,13 +5,16 @@ import com.jomalls.custom.app.dto.system.SysMenuSaveDTO;
import com.jomalls.custom.app.dto.system.SysMenuUpdateDTO;
import com.jomalls.custom.app.service.system.SysMenuService;
import com.jomalls.custom.app.vo.system.SysMenuVO;
import com.jomalls.custom.utils.R;
import com.jomalls.custom.app.exception.ServiceException;
import com.jomalls.custom.app.vo.system.TreeSelectVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
......@@ -31,52 +34,70 @@ public class SysMenuController {
@Operation(summary = "查询菜单列表")
@RequiresPermissions("system:menu:list")
@GetMapping("/list")
public R<Object> list(SysMenuVO menu) {
return R.ok(sysMenuService.selectMenuList(menu));
public List<SysMenuVO> list(SysMenuVO menu) {
return sysMenuService.selectMenuList(menu);
}
@Operation(summary = "根据ID查询菜单")
@RequiresPermissions("system:menu:query")
@GetMapping("/{menuId}")
public R<SysMenuVO> getById(@PathVariable Long menuId) {
SysMenuVO menu = sysMenuService.getById(menuId);
return R.ok(menu);
public SysMenuVO getById(@PathVariable Long menuId) {
return sysMenuService.getById(menuId);
}
@Operation(summary = "查询菜单树下拉列表")
@GetMapping("/treeselect")
public R<Object> treeselect() {
return R.ok(sysMenuService.treeselect());
public List<TreeSelectVO> treeselect() {
return sysMenuService.treeselect();
}
@Operation(summary = "根据角色ID查询菜单树(含选中的菜单ID)")
@GetMapping("/roleMenuTreeselect/{roleId}")
public R<Map<String, Object>> roleMenuTreeselect(@PathVariable Long roleId) {
Map<String, Object> result = sysMenuService.roleMenuTreeselect(roleId);
return R.ok(result);
public Map<String, Object> roleMenuTreeselect(@PathVariable Long roleId) {
return sysMenuService.roleMenuTreeselect(roleId);
}
@Operation(summary = "新增菜单")
@RequiresPermissions("system:menu:add")
@PostMapping
public R<Void> add(@RequestBody SysMenuSaveDTO dto) {
public void add(@RequestBody SysMenuSaveDTO dto) {
// 外链验证
if (dto.getIsFrame() != null && dto.getIsFrame() == 0 && StringUtils.hasText(dto.getPath())) {
if (!dto.getPath().startsWith("http://") && !dto.getPath().startsWith("https://")) {
throw new ServiceException("外链地址必须以 http(s):// 开头");
}
}
sysMenuService.add(dto);
return R.ok();
}
@Operation(summary = "修改菜单")
@RequiresPermissions("system:menu:edit")
@PutMapping
public R<Void> edit(@RequestBody SysMenuUpdateDTO dto) {
public void edit(@RequestBody SysMenuUpdateDTO dto) {
// 禁止父菜单指向自己
if (dto.getMenuId() != null && dto.getParentId() != null
&& dto.getMenuId().equals(dto.getParentId())) {
throw new ServiceException("父菜单不能指向自身");
}
// 外链验证
if (dto.getIsFrame() != null && dto.getIsFrame() == 0 && StringUtils.hasText(dto.getPath())) {
if (!dto.getPath().startsWith("http://") && !dto.getPath().startsWith("https://")) {
throw new ServiceException("外链地址必须以 http(s):// 开头");
}
}
sysMenuService.edit(dto);
return R.ok();
}
@Operation(summary = "删除菜单")
@RequiresPermissions("system:menu:remove")
@DeleteMapping("/{menuId}")
public R<Void> remove(@PathVariable Long menuId) {
public void remove(@PathVariable Long menuId) {
if (sysMenuService.hasChildByMenuId(menuId)) {
throw new ServiceException("存在子菜单,不允许删除");
}
if (sysMenuService.checkMenuAssignedToRole(menuId)) {
throw new ServiceException("菜单已分配,不允许删除");
}
sysMenuService.remove(menuId);
return R.ok();
}
}
......@@ -7,8 +7,8 @@ import com.jomalls.custom.app.dto.system.SysPostSaveDTO;
import com.jomalls.custom.app.dto.system.SysPostUpdateDTO;
import com.jomalls.custom.app.service.system.SysPostService;
import com.jomalls.custom.app.vo.system.SysPostVO;
import com.jomalls.custom.utils.R;
import io.swagger.v3.oas.annotations.Operation;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -28,47 +28,48 @@ public class SysPostController {
private final SysPostService sysPostService;
@Operation(summary = "查询岗位列表(无权限要求,用于下拉框)")
@GetMapping("/optionselect")
public List<SysPostVO> optionselect() {
return sysPostService.listAllPosts();
}
@Operation(summary = "分页查询岗位列表")
@RequiresPermissions("system:post:list")
@GetMapping("/list")
public R<IPage<SysPostVO>> list(
public IPage<SysPostVO> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
SysPostVO post) {
Page<SysPostVO> page = new Page<>(pageNum, pageSize);
IPage<SysPostVO> result = sysPostService.pageList(post, page);
return R.ok(result);
return sysPostService.pageList(post, page);
}
@Operation(summary = "根据ID查询岗位")
@RequiresPermissions("system:post:query")
@GetMapping("/{postId}")
public R<SysPostVO> getById(@PathVariable Long postId) {
SysPostVO post = sysPostService.getById(postId);
return R.ok(post);
public SysPostVO getById(@PathVariable Long postId) {
return sysPostService.getById(postId);
}
@Operation(summary = "新增岗位")
@RequiresPermissions("system:post:add")
@PostMapping
public R<Void> add(@RequestBody SysPostSaveDTO dto) {
public void add(@RequestBody SysPostSaveDTO dto) {
sysPostService.add(dto);
return R.ok();
}
@Operation(summary = "修改岗位")
@RequiresPermissions("system:post:edit")
@PutMapping
public R<Void> edit(@RequestBody SysPostUpdateDTO dto) {
public void edit(@RequestBody SysPostUpdateDTO dto) {
sysPostService.edit(dto);
return R.ok();
}
@Operation(summary = "批量删除岗位")
@RequiresPermissions("system:post:remove")
@DeleteMapping("/{postIds}")
public R<Void> remove(@PathVariable Long[] postIds) {
public void remove(@PathVariable Long[] postIds) {
sysPostService.remove(postIds);
return R.ok();
}
}
package com.jomalls.custom.webapp.controller.system;
import com.jomalls.custom.app.exception.ServiceException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户注册 Controller
*
* @author Lizh
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@Tag(name = "用户注册")
public class SysRegisterController {
@Operation(summary = "用户注册")
@PostMapping("/register")
public void register() {
// 注册功能默认不开启,如需开启请配置 sys.account.registerUser = true
// TODO: 实现完整注册逻辑(检查配置 → 注册服务调用)
throw new ServiceException("注册功能未开启");
}
}
......@@ -5,15 +5,18 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jomalls.custom.app.annotation.RequiresPermissions;
import com.jomalls.custom.app.dto.system.*;
import com.jomalls.custom.app.service.system.SysRoleService;
import com.jomalls.custom.app.vo.system.SysDeptVO;
import com.jomalls.custom.app.vo.system.SysRoleVO;
import com.jomalls.custom.app.vo.system.SysUserVO;
import com.jomalls.custom.utils.R;
import com.jomalls.custom.security.SecurityUtils;
import com.jomalls.custom.app.exception.ServiceException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
......@@ -30,129 +33,132 @@ public class SysRoleController {
private final SysRoleService sysRoleService;
@Operation(summary = "查询角色列表(无权限要求,用于下拉框)")
@GetMapping("/optionselect")
public List<SysRoleVO> optionselect() {
return sysRoleService.listAllRoles();
}
@Operation(summary = "分页查询角色列表")
@RequiresPermissions("system:role:list")
@GetMapping("/list")
public R<IPage<SysRoleVO>> list(
public IPage<SysRoleVO> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
SysRoleVO role) {
Page<SysRoleVO> page = new Page<>(pageNum, pageSize);
IPage<SysRoleVO> result = sysRoleService.pageList(role, page);
return R.ok(result);
return sysRoleService.pageList(role, page);
}
@Operation(summary = "根据ID查询角色")
@RequiresPermissions("system:role:query")
@GetMapping("/{roleId}")
public R<SysRoleVO> getById(@PathVariable Long roleId) {
SysRoleVO role = sysRoleService.getById(roleId);
return R.ok(role);
public SysRoleVO getById(@PathVariable Long roleId) {
return sysRoleService.getById(roleId);
}
@Operation(summary = "新增角色")
@RequiresPermissions("system:role:add")
@PostMapping
public R<Void> add(@RequestBody SysRoleSaveDTO dto) {
public void add(@RequestBody SysRoleSaveDTO dto) {
sysRoleService.add(dto);
return R.ok();
}
@Operation(summary = "修改角色")
@RequiresPermissions("system:role:edit")
@PutMapping
public R<Void> edit(@RequestBody SysRoleUpdateDTO dto) {
public void edit(@RequestBody SysRoleUpdateDTO dto) {
sysRoleService.edit(dto);
return R.ok();
// 刷新 LoginUser 缓存(非管理员用户的权限可能发生变化)
if (SecurityUtils.getUserId() != null && !SecurityUtils.getUserId().equals(1L)) {
// TODO: 如果当前用户所属角色被修改,需要刷新 token 缓存中的 permissions
// 在 Redis TokenStore 场景下,应清除或刷新对应用户的缓存权限
log.debug("角色更新完成,需要刷新相关用户的LoginUser缓存: roleId={}", dto.getRoleId());
}
}
@Operation(summary = "修改角色数据权限")
@RequiresPermissions("system:role:edit")
@PutMapping("/dataScope")
public R<Void> dataScope(@RequestBody SysRoleDataScopeDTO dto) {
public void dataScope(@RequestBody SysRoleDataScopeDTO dto) {
sysRoleService.dataScope(dto);
return R.ok();
}
@Operation(summary = "修改角色状态")
@RequiresPermissions("system:role:edit")
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestBody SysRoleStatusDTO dto) {
public void changeStatus(@RequestBody SysRoleStatusDTO dto) {
sysRoleService.changeStatus(dto);
return R.ok();
}
@Operation(summary = "批量删除角色")
@RequiresPermissions("system:role:remove")
@DeleteMapping("/{roleIds}")
public R<Void> remove(@PathVariable Long[] roleIds) {
public void remove(@PathVariable Long[] roleIds) {
sysRoleService.remove(roleIds);
return R.ok();
}
@Operation(summary = "查询已分配用户(分页)")
@RequiresPermissions("system:role:list")
@GetMapping("/authUser/allocatedList")
public R<IPage<SysUserVO>> allocatedList(
public IPage<SysUserVO> allocatedList(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
SysUserVO user) {
Page<SysUserVO> page = new Page<>(pageNum, pageSize);
IPage<SysUserVO> result = sysRoleService.allocatedList(user, page);
return R.ok(result);
return sysRoleService.allocatedList(user, page);
}
@Operation(summary = "查询未分配用户(分页)")
@RequiresPermissions("system:role:list")
@GetMapping("/authUser/unallocatedList")
public R<IPage<SysUserVO>> unallocatedList(
public IPage<SysUserVO> unallocatedList(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
SysUserVO user) {
Page<SysUserVO> page = new Page<>(pageNum, pageSize);
IPage<SysUserVO> result = sysRoleService.unallocatedList(user, page);
return R.ok(result);
return sysRoleService.unallocatedList(user, page);
}
@Operation(summary = "取消授权用户")
@RequiresPermissions("system:role:edit")
@PutMapping("/authUser/cancel")
public R<Void> cancelAuthUser(@RequestBody Map<String, Object> body) {
public void cancelAuthUser(@RequestBody Map<String, Object> body) {
Object roleIdObj = body.get("roleId");
Object userIdObj = body.get("userId");
if (roleIdObj == null || userIdObj == null) {
return R.fail("roleId 和 userId 不能为空");
throw new ServiceException("roleId 和 userId 不能为空");
}
Long roleId = Long.valueOf(roleIdObj.toString());
Long userId = Long.valueOf(userIdObj.toString());
if (roleId == null || userId == null) {
throw new ServiceException("roleId 和 userId 不能为空");
}
sysRoleService.cancelAuthUser(roleId, userId);
return R.ok();
}
@Operation(summary = "批量取消授权用户")
@RequiresPermissions("system:role:edit")
@PutMapping("/authUser/cancelAll")
public R<Void> cancelAuthUserAll(
public void cancelAuthUserAll(
@RequestParam Long roleId,
@RequestParam Long[] userIds) {
sysRoleService.cancelAuthUserAll(roleId, userIds);
return R.ok();
}
@Operation(summary = "批量选择授权用户")
@RequiresPermissions("system:role:edit")
@PutMapping("/authUser/selectAll")
public R<Void> selectAuthUserAll(
public void selectAuthUserAll(
@RequestParam Long roleId,
@RequestParam Long[] userIds) {
sysRoleService.selectAuthUserAll(roleId, userIds);
return R.ok();
}
@Operation(summary = "查询部门树(含角色已选部门ID)")
@RequiresPermissions("system:role:query")
@GetMapping("/deptTree/{roleId}")
public R<Object> deptTree(@PathVariable Long roleId) {
return R.ok(sysRoleService.deptTree(roleId));
public List<SysDeptVO> deptTree(@PathVariable Long roleId) {
return sysRoleService.deptTree(roleId);
}
}
......@@ -4,8 +4,13 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jomalls.custom.app.annotation.RequiresPermissions;
import com.jomalls.custom.app.dto.system.*;
import com.jomalls.custom.app.service.system.SysPostService;
import com.jomalls.custom.app.service.system.SysRoleService;
import com.jomalls.custom.app.service.system.SysUserService;
import com.jomalls.custom.app.vo.system.SysDeptVO;
import com.jomalls.custom.app.vo.system.SysUserVO;
import com.jomalls.custom.security.SecurityUtils;
import com.jomalls.custom.app.exception.ServiceException;
import com.jomalls.custom.utils.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
......@@ -14,7 +19,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 用户管理 Controller
......@@ -29,120 +37,124 @@ import java.util.Map;
public class SysUserController {
private final SysUserService sysUserService;
private final SysRoleService sysRoleService;
private final SysPostService sysPostService;
@Operation(summary = "分页查询用户列表")
@RequiresPermissions("system:user:list")
@GetMapping("/list")
public R<IPage<SysUserVO>> list(
public IPage<SysUserVO> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
SysUserVO user) {
Page<SysUserVO> page = new Page<>(pageNum, pageSize);
IPage<SysUserVO> result = sysUserService.pageList(user, page);
return R.ok(result);
return sysUserService.pageList(user, page);
}
@Operation(summary = "查询用户详情")
@Operation(summary = "查询用户详情(含角色、岗位)")
@RequiresPermissions("system:user:query")
@GetMapping("/{userId}")
public R<Map<String, Object>> getInfo(@PathVariable Long userId) {
@GetMapping(value = {"/", "/{userId}"})
public R<Object> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
R<Object> result = R.ok();
if (userId != null) {
Map<String, Object> info = sysUserService.getInfo(userId);
return R.ok(info);
result.put("data", info.get("user"));
result.put("postIds", info.get("postIds"));
result.put("roleIds", info.get("roleIds") != null ? info.get("roleIds") : info.get("roles"));
}
result.put("roles", sysRoleService.listAllRoles());
result.put("posts", sysPostService.listAllPosts());
return result;
}
@Operation(summary = "新增用户")
@RequiresPermissions("system:user:add")
@PostMapping
public R<Void> add(@RequestBody SysUserSaveDTO dto) {
sysUserService.add(dto);
return R.ok();
public String add(@RequestBody SysUserSaveDTO dto) {
return sysUserService.add(dto);
}
@Operation(summary = "修改用户")
@RequiresPermissions("system:user:edit")
@PutMapping
public R<Void> edit(@RequestBody SysUserUpdateDTO dto) {
public void edit(@RequestBody SysUserUpdateDTO dto) {
sysUserService.edit(dto);
return R.ok();
}
@Operation(summary = "批量删除用户")
@RequiresPermissions("system:user:remove")
@DeleteMapping("/{userIds}")
public R<Void> remove(@PathVariable Long[] userIds) {
public void remove(@PathVariable Long[] userIds) {
// 自删除检查
Long currentUserId = SecurityUtils.getUserId();
if (currentUserId != null && Arrays.asList(userIds).contains(currentUserId)) {
throw new ServiceException("当前用户不能删除");
}
sysUserService.remove(userIds);
return R.ok();
}
@Operation(summary = "重置密码")
@RequiresPermissions("system:user:resetPwd")
@PutMapping("/resetPwd")
public R<Void> resetPwd(@RequestBody SysUserResetPwdDTO dto) {
public void resetPwd(@RequestBody SysUserResetPwdDTO dto) {
sysUserService.resetPwd(dto);
return R.ok();
}
@Operation(summary = "修改用户状态")
@RequiresPermissions("system:user:edit")
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestBody SysUserChangeStatusDTO dto) {
public void changeStatus(@RequestBody SysUserChangeStatusDTO dto) {
sysUserService.changeStatus(dto);
return R.ok();
}
@Operation(summary = "获取当前用户信息")
@GetMapping("/profile")
public R<SysUserVO> profile() {
SysUserVO user = sysUserService.getProfile();
return R.ok(user);
}
@Operation(summary = "修改当前用户信息")
@PutMapping("/profile")
public R<Void> updateProfile(@RequestBody SysUserVO user) {
sysUserService.updateProfile(user);
return R.ok();
public SysUserVO updateProfile(@RequestBody SysUserVO updateUser) {
sysUserService.updateProfile(updateUser);
// 刷新当前 LoginUser 缓存
return sysUserService.getProfile();
}
@Operation(summary = "修改当前用户密码")
@PutMapping("/profile/updatePwd")
public R<Void> updatePwd(@RequestBody SysUserUpdatePwdDTO dto) {
public void updatePwd(@RequestBody SysUserUpdatePwdDTO dto) {
sysUserService.updatePwd(dto);
return R.ok();
}
@Operation(summary = "更新当前用户头像")
@PostMapping("/profile/avatar")
public R<Void> updateAvatar(@RequestParam("avatarfile") MultipartFile file) {
// TODO: 处理头像上传逻辑
public R<Object> updateAvatar(@RequestParam("avatarfile") MultipartFile file) {
// TODO: 实际头像上传处理(保存文件到服务器/OSS),此处模拟返回
log.info("上传头像文件: {}", file.getOriginalFilename());
return R.ok();
String avatarUrl = "/profile/avatar/" + file.getOriginalFilename();
sysUserService.updateAvatar(avatarUrl);
return R.ok().put("imgUrl", avatarUrl);
}
@Operation(summary = "查询用户已分配的角色ID列表")
@RequiresPermissions("system:user:query")
@GetMapping("/authRole/{userId}")
public R<Map<String, Object>> authRole(@PathVariable Long userId) {
public Map<String, Object> authRole(@PathVariable Long userId) {
Map<String, Object> result = new java.util.HashMap<>();
result.put("userId", userId);
result.put("roleIds", sysUserService.getAuthRoleList(userId));
return R.ok(result);
return result;
}
@Operation(summary = "批量插入用户角色关联")
@RequiresPermissions("system:user:edit")
@PutMapping("/authRole")
public R<Void> insertAuthRole(
public void insertAuthRole(
@RequestParam Long userId,
@RequestParam Long[] roleIds) {
sysUserService.insertAuthRole(userId, roleIds);
return R.ok();
}
@Operation(summary = "查询部门树")
@RequiresPermissions("system:user:list")
@GetMapping("/deptTree")
public R<Object> deptTree() {
return R.ok(sysUserService.deptTree());
public List<SysDeptVO> deptTree() {
return sysUserService.deptTree();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment