diff --git a/xs-api/src/main/java/com/xiang/xs/api/code/Code01UserErrorCode.java b/xs-api/src/main/java/com/xiang/xs/api/code/Code01UserErrorCode.java new file mode 100644 index 0000000..baead53 --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/code/Code01UserErrorCode.java @@ -0,0 +1,22 @@ +package com.xiang.xs.api.code; + +import com.xiang.xservice.basic.exception.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum Code01UserErrorCode implements BaseErrorCode { + + USER_NOT_EXISTS("A1000101", "用户不存在"), + USER_EXISTS("A1000102", "用户已存在"), + USER_LOGIN_ERROR("A1000103", "用户登录失败!"), + USER_REGISTER_ERROR("1000104", "用户注册失败!"), + REFRESH_TOKEN_NOT_EXISTS("1000105", "refreshToken不匹配"), + TOKEN_NOT_VALID("1000106", "token校验失败"), + ; + + private final String code; + private final String message; + +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/code/Code02RoleErrorCode.java b/xs-api/src/main/java/com/xiang/xs/api/code/Code02RoleErrorCode.java new file mode 100644 index 0000000..7bacd17 --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/code/Code02RoleErrorCode.java @@ -0,0 +1,21 @@ +package com.xiang.xs.api.code; + +import com.xiang.xservice.basic.exception.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @Author: xiang + * @Date: 2025-08-29 16:27 + */ +@Getter +@AllArgsConstructor +public enum Code02RoleErrorCode implements BaseErrorCode { + + ROLE_NOT_EXISTS("A1000201", "角色不存在"), + USER_ROLE_NOT_EXISTS("A1000202", "用户角色权限不存在!") + ; + + private final String code; + private final String message; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/code/Code03DeptErrorCode.java b/xs-api/src/main/java/com/xiang/xs/api/code/Code03DeptErrorCode.java new file mode 100644 index 0000000..2e27b57 --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/code/Code03DeptErrorCode.java @@ -0,0 +1,20 @@ +package com.xiang.xs.api.code; + +import com.xiang.xservice.basic.exception.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @Author: xiang + * @Date: 2025-08-29 16:27 + */ +@Getter +@AllArgsConstructor +public enum Code03DeptErrorCode implements BaseErrorCode { + + DEPT_NOT_EXISTS("A1000301", "部门不存在"), + ; + + private final String code; + private final String message; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/RegisterRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/RegisterRequest.java new file mode 100644 index 0000000..7a5b02d --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/RegisterRequest.java @@ -0,0 +1,54 @@ +package com.xiang.xs.api.pojo.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RegisterRequest { + + /** + * 用户名(昵称) + */ + @NotBlank(message = "用户名(昵称)不能为空") + @Size(min = 0, max = 20, message = "用户名长度不能超过20") + private String name; + /** + * 用户名 + */ + @NotBlank(message = "用户名不能为空") + private String username; + /** + * 密码 + */ + @NotBlank(message = "密码不能为空") + @Size(min = 6, max = 18, message = "密码长度需要在6-18位") + private String password; + /** + * 邮箱 + */ + @Email(message = "邮箱验证不能通过") + private String email; + /** + * 手机号 + */ + @NotBlank(message = "手机号码不能为空") + @Size(min = 11, max = 11, message = "手机号码长度验证失败") + private String phone; + /** + * 头像 + */ + private String avatar; + + /** + * 验证码 + */ + @NotBlank(message = "验证码不能为空") + private String code; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserAddRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserAddRequest.java new file mode 100644 index 0000000..12d5336 --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserAddRequest.java @@ -0,0 +1,49 @@ +package com.xiang.xs.api.pojo.request.user; + +import com.xiang.xservice.basic.common.req.BaseRequest; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserAddRequest extends BaseRequest { + + /** + * 用户名(昵称) + */ + private String name; + + /** + * 账号 + */ + private String username; + + /** + * 密码 + */ + private String password; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phone; + + /** + * 头像 + */ + private String avatar; + + /** + * 状态(0:禁用, 1:启用) + */ + private Integer status; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserDeptUpdateRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserDeptUpdateRequest.java new file mode 100644 index 0000000..7e5b5f4 --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserDeptUpdateRequest.java @@ -0,0 +1,4 @@ +package com.xiang.xs.api.pojo.request.user; + +public class UserDeptUpdateRequest { +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserQueryRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserQueryRequest.java new file mode 100644 index 0000000..169152d --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserQueryRequest.java @@ -0,0 +1,36 @@ +package com.xiang.xs.api.pojo.request.user; + +import com.xiang.xservice.basic.common.req.BaseRequest; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserQueryRequest extends BaseRequest { + /** + * 用户名(昵称) + */ + private String name; + + /** + * 账号 + */ + private String username; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phone; + + /** + * 状态(0:禁用, 1:启用) + */ + private Integer status; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserResetPwdRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserResetPwdRequest.java new file mode 100644 index 0000000..cd71d8f --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserResetPwdRequest.java @@ -0,0 +1,16 @@ +package com.xiang.xs.api.pojo.request.user; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +public class UserResetPwdRequest { + + @NotNull(message = "userId不能为空") + private Long userId; + + @NotBlank(message = "密码不能为空") + private String password; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserRoleUpdateRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserRoleUpdateRequest.java new file mode 100644 index 0000000..28b360d --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserRoleUpdateRequest.java @@ -0,0 +1,22 @@ +package com.xiang.xs.api.pojo.request.user; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserRoleUpdateRequest { + /** + * 用户id + */ + private Long userId; + + /** + * 角色id集合 + */ + private List roleIds; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserUpdateRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserUpdateRequest.java new file mode 100644 index 0000000..957db4a --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserUpdateRequest.java @@ -0,0 +1,12 @@ +package com.xiang.xs.api.pojo.request.user; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserUpdateRequest extends UserAddRequest { + private Long id; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserUpdateStatusRequest.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserUpdateStatusRequest.java new file mode 100644 index 0000000..bd7410c --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/request/user/UserUpdateStatusRequest.java @@ -0,0 +1,13 @@ +package com.xiang.xs.api.pojo.request.user; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +public class UserUpdateStatusRequest { + @NotNull(message = "id不能为空") + private Long id; + @NotNull(message = "状态不能为空") + private Integer status; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/MenuVO.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/MenuVO.java new file mode 100644 index 0000000..f10e04c --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/MenuVO.java @@ -0,0 +1,103 @@ +package com.xiang.xs.api.pojo.resp; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: xiang + * @Date: 2026-03-20 15:24 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MenuVO { + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 父菜单名称 + */ + private String parentName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String query; + + /** + * 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义) + */ + private String routeName; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限字符串 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 子菜单 + */ + private List children = new ArrayList(); +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/RegisterResp.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/RegisterResp.java new file mode 100644 index 0000000..9fb7f7f --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/RegisterResp.java @@ -0,0 +1,29 @@ +package com.xiang.xs.api.pojo.resp; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RegisterResp { + + /** + * 用户名(昵称) + */ + private String name; + /** + * 用户名 + */ + private String username; + /** + * 邮箱 + */ + private String email; + /** + * 手机号 + */ + private String phone; +} diff --git a/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/UserResp.java b/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/UserResp.java new file mode 100644 index 0000000..6da46e8 --- /dev/null +++ b/xs-api/src/main/java/com/xiang/xs/api/pojo/resp/UserResp.java @@ -0,0 +1,65 @@ +package com.xiang.xs.api.pojo.resp; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserResp { + + private Long id; + + /** + * 用户名(昵称) + */ + private String name; + + /** + * 账号 + */ + private String username; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phone; + + /** + * 头像 + */ + private String avatar; + + /** + * 最后登陆ip + */ + private String loginIp; + + /** + * 最后登陆时间 + */ + private LocalDateTime loginDate; + + /** + * 状态(0:禁用, 1:启用) + */ + private Integer status; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 租户id + */ + private Long tenantId; +} diff --git a/xs-server/src/main/java/com/xiang/xs/server/controller/SysMenuController.java b/xs-server/src/main/java/com/xiang/xs/server/controller/SysMenuController.java index 38689a2..bd873c2 100644 --- a/xs-server/src/main/java/com/xiang/xs/server/controller/SysMenuController.java +++ b/xs-server/src/main/java/com/xiang/xs/server/controller/SysMenuController.java @@ -5,6 +5,7 @@ import com.xiang.xs.service.contants.UserConstants; import com.xiang.xs.service.entity.SysMenu; import com.xiang.xs.service.entity.TreeSelect; import com.xiang.xs.service.entity.vo.RoleTreeVo; +import com.xiang.xs.service.entity.vo.RouterVo; import com.xiang.xservice.basic.common.resp.Result; import com.xiang.xservice.basic.utils.MyStringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @@ -111,4 +113,9 @@ public class SysMenuController { } return Result.data(menuService.deleteMenuById(menuId) > 0); } + + @GetMapping("/private/menu/getRouter") + public Result> getRouter(@RequestParam("userId") Long userId) { + return Result.data(menuService.getRouter(userId)); + } } \ No newline at end of file diff --git a/xs-server/src/main/java/com/xiang/xs/server/controller/UserController.java b/xs-server/src/main/java/com/xiang/xs/server/controller/UserController.java new file mode 100644 index 0000000..ae72ba1 --- /dev/null +++ b/xs-server/src/main/java/com/xiang/xs/server/controller/UserController.java @@ -0,0 +1,99 @@ +package com.xiang.xs.server.controller; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.xiang.xs.api.pojo.request.user.UserAddRequest; +import com.xiang.xs.api.pojo.request.user.UserQueryRequest; +import com.xiang.xs.api.pojo.request.user.UserResetPwdRequest; +import com.xiang.xs.api.pojo.request.user.UserUpdateRequest; +import com.xiang.xs.api.pojo.request.user.UserUpdateStatusRequest; +import com.xiang.xs.api.pojo.resp.UserResp; +import com.xiang.xs.service.biz.XUserService; +import com.xiang.xs.service.entity.vo.UserDTO; +import com.xiang.xservice.basic.common.resp.Result; +import com.xiang.xservice.basic.exception.BusinessException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class UserController { + + private final XUserService userService; + + @PostMapping("/private/user/list") + public Result> getUserList(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserQueryRequest request) { + return Result.data(userService.getUserList(request)); + } + + @GetMapping("/private/user/info/{id}") + public Result getUserById(@PathVariable("id") Long id) { + return Result.data(userService.getUserInfo(id)); + } + + @PostMapping("/private/user/add") + public Result addUser(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserAddRequest request) { + try { + return Result.data(userService.addUser(request)); + } catch (BusinessException e) { + log.error("用户新增异常,请求:{}", JSON.toJSONString(request), e); + return Result.error(e.getMessage()); + } catch (Exception e) { + log.error("用户新增异常,请求:{}", JSON.toJSONString(request), e); + } + return Result.error(); + } + @PostMapping("/private/user/updateStatus") + public Result updateStatus(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserUpdateStatusRequest request) { + return Result.data(userService.updateStatus(request.getId(), request.getStatus())); + } + + @PostMapping("/private/user/update") + public Result updateUser(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserUpdateRequest request) { + try { + return Result.data(userService.updateUser(request)); + } catch (BusinessException e) { + log.error("用户编辑异常,请求:{}", JSON.toJSONString(request), e); + return Result.error(e.getMessage()); + } catch (Exception e) { + log.error("用户编辑异常,请求:{}", JSON.toJSONString(request), e); + } + return Result.error(); + } + + @PostMapping("/private/user/del") + public Result delUser(@RequestBody @Valid @NotEmpty(message = "请求参数不能为空") List ids) { + try { + return Result.data(userService.delUser(ids)); + } catch (BusinessException e) { + log.error("用户删除异常,请求:{}", JSON.toJSONString(ids), e); + return Result.error(e.getMessage()); + } catch (Exception e) { + log.error("用户删除异常,请求:{}", JSON.toJSONString(ids), e); + } + return Result.error(); + } + + @PostMapping("/private/user/resetUserPwd") + public Result resetPwd(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserResetPwdRequest request) { + return Result.data(userService.resetPwd(request.getUserId(), request.getPassword())); + } + + @PostMapping("/private/auth/getInfo") + public Result getUserInfo(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserQueryRequest request) { + return Result.data(userService.getUserDetail(request.getUsername())); + } + + +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/biz/ISysMenuService.java b/xs-service/src/main/java/com/xiang/xs/service/biz/ISysMenuService.java index 4bc6ba5..e820ccc 100644 --- a/xs-service/src/main/java/com/xiang/xs/service/biz/ISysMenuService.java +++ b/xs-service/src/main/java/com/xiang/xs/service/biz/ISysMenuService.java @@ -158,4 +158,6 @@ public interface ISysMenuService { * @return 结果 */ boolean checkMenuNameUnique(SysMenu menu); + + List getRouter(Long userId); } diff --git a/xs-service/src/main/java/com/xiang/xs/service/biz/XUserService.java b/xs-service/src/main/java/com/xiang/xs/service/biz/XUserService.java new file mode 100644 index 0000000..0f806e6 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/biz/XUserService.java @@ -0,0 +1,27 @@ +package com.xiang.xs.service.biz; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.xiang.xs.api.pojo.request.LoginRequest; +import com.xiang.xs.api.pojo.request.RegisterRequest; +import com.xiang.xs.api.pojo.request.user.UserAddRequest; +import com.xiang.xs.api.pojo.request.user.UserQueryRequest; +import com.xiang.xs.api.pojo.request.user.UserUpdateRequest; +import com.xiang.xs.api.pojo.resp.LoginResp; +import com.xiang.xs.api.pojo.resp.RegisterResp; +import com.xiang.xs.api.pojo.resp.UserResp; +import com.xiang.xs.service.entity.vo.UserDTO; + +import java.util.List; + +public interface XUserService { + + RegisterResp userRegister(RegisterRequest request); + Page getUserList(UserQueryRequest request); + UserResp getUserInfo(Long id); + Boolean addUser(UserAddRequest request); + Boolean updateUser(UserUpdateRequest request); + Boolean delUser(List ids); + UserDTO getUserDetail(String username); + Boolean updateStatus(Long id, Integer status); + Boolean resetPwd(Long userId, String password); +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/biz/impl/SysMenuServiceImpl.java b/xs-service/src/main/java/com/xiang/xs/service/biz/impl/SysMenuServiceImpl.java index 93e6dfc..3630324 100644 --- a/xs-service/src/main/java/com/xiang/xs/service/biz/impl/SysMenuServiceImpl.java +++ b/xs-service/src/main/java/com/xiang/xs/service/biz/impl/SysMenuServiceImpl.java @@ -1,8 +1,12 @@ package com.xiang.xs.service.biz.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.Lists; import com.xiang.xs.service.biz.ISysMenuService; import com.xiang.xs.service.contants.Constants; import com.xiang.xs.service.contants.UserConstants; +import com.xiang.xs.service.converter.XMenuConverter; import com.xiang.xs.service.entity.SysMenu; import com.xiang.xs.service.entity.SysRole; import com.xiang.xs.service.entity.SysUser; @@ -46,6 +50,9 @@ public class SysMenuServiceImpl implements ISysMenuService { @Autowired private SysRoleMenuMapper roleMenuMapper; + @Autowired + private XMenuConverter menuConverter; + /** * 根据用户查询系统菜单列表 * @@ -328,6 +335,22 @@ public class SysMenuServiceImpl implements ISysMenuService { return UserConstants.UNIQUE; } + @Override + public List getRouter(Long userId) { + List xMenuDOS = Lists.newArrayList(); + // 超级管理员 admin + if (Objects.equals(userId, 1L)) { + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + lambdaQueryWrapper.eq(SysMenu::getStatus, 0); + lambdaQueryWrapper.in(SysMenu::getMenuType, 'M', 'C'); + lambdaQueryWrapper.orderByAsc(SysMenu::getParentId, SysMenu::getOrderNum); + xMenuDOS = menuMapper.selectList(lambdaQueryWrapper); + } else { + xMenuDOS = menuMapper.selectMenuTreeByUserId(userId); + } + return buildMenus(getChildPerms(xMenuDOS, 0)); + } + /** * 获取路由名称 * diff --git a/xs-service/src/main/java/com/xiang/xs/service/biz/impl/XUserServiceImpl.java b/xs-service/src/main/java/com/xiang/xs/service/biz/impl/XUserServiceImpl.java new file mode 100644 index 0000000..0673891 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/biz/impl/XUserServiceImpl.java @@ -0,0 +1,191 @@ +package com.xiang.xs.service.biz.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Sets; +import com.xiang.xmc.service.cache.service.IRedisService; +import com.xiang.xs.api.code.Code01UserErrorCode; +import com.xiang.xs.api.code.Code02RoleErrorCode; +import com.xiang.xs.api.code.Code03DeptErrorCode; +import com.xiang.xs.api.pojo.request.RegisterRequest; +import com.xiang.xs.api.pojo.request.user.UserAddRequest; +import com.xiang.xs.api.pojo.request.user.UserQueryRequest; +import com.xiang.xs.api.pojo.request.user.UserUpdateRequest; +import com.xiang.xs.api.pojo.resp.RegisterResp; +import com.xiang.xs.api.pojo.resp.UserResp; +import com.xiang.xs.service.biz.XUserService; +import com.xiang.xs.service.converter.XUserConvert; +import com.xiang.xs.service.entity.SysRole; +import com.xiang.xs.service.entity.SysUserRole; +import com.xiang.xs.service.entity.XUser; +import com.xiang.xs.service.entity.vo.UserDTO; +import com.xiang.xs.service.enums.UserStatusEnum; +import com.xiang.xs.service.repository.mapper.SysDeptMapper; +import com.xiang.xs.service.repository.mapper.SysRoleMapper; +import com.xiang.xs.service.repository.mapper.SysUserRoleMapper; +import com.xiang.xs.service.repository.mapper.XUserMapper; +import com.xiang.xservice.basic.enums.DelStatusEnum; +import com.xiang.xservice.basic.exception.BusinessException; +import com.xiang.xservice.basic.utils.PrimaryKeyUtils; +import com.xiang.xservice.basic.utils.RandomCodeUtils; +import com.xiang.xservice.basic.utils.SnowflakeIdGenerator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Service +@RequiredArgsConstructor +public class XUserServiceImpl implements XUserService { + + private final XUserMapper userMapper; + private final XUserConvert userConvert; + private final SysRoleMapper roleMapper; + private final SysUserRoleMapper userRoleMapper; + private final PasswordEncoder passwordEncoder; + + @Override + public RegisterResp userRegister(RegisterRequest request) { + // todo 手机号验证码校验 + XUser user = userMapper.selectByUsername(request.getUsername()); + if (Objects.nonNull(user)) { + throw new BusinessException(Code01UserErrorCode.USER_EXISTS); + } + user = new XUser(); + user.setName(request.getName()); + user.setUsername(request.getUsername()); + user.setPassword(passwordEncoder.encode(request.getPassword())); + user.setEmail(request.getEmail()); + user.setPhone(request.getPhone()); + user.setAvatar(request.getAvatar()); + user.setStatus(UserStatusEnum.USING.getCode()); + user.setDelFlag(DelStatusEnum.NOT_DELETED.getCode()); + user.setCreateBy("admin"); + user.setCreateTime(LocalDateTime.now()); + user.setUpdateBy("admin"); + user.setUpdateTime(LocalDateTime.now()); + user.setUserType(2); + user.setTenantId(8000000000000000L + SnowflakeIdGenerator.of16(RandomCodeUtils.getRandomNumber(1)).nextId()); + + int i = 0; + try { + i = userMapper.insert(user); + } catch (DuplicateKeyException e) { + throw new BusinessException(Code01UserErrorCode.USER_EXISTS); + } + if (i > 0) { + RegisterResp registerResp = new RegisterResp(); + registerResp.setName(user.getName()); + registerResp.setUsername(user.getUsername()); + registerResp.setEmail(user.getEmail()); + registerResp.setPhone(user.getPhone()); + return registerResp; + } + return null; + } + + @Override + public Page getUserList(UserQueryRequest request) { + Page page = new Page<>(request.getCurrent(), request.getPageSize()); + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + lambdaQueryWrapper.eq(XUser::getDelFlag, DelStatusEnum.NOT_DELETED.getCode()); + if (StringUtils.isNotBlank(request.getName())) { + lambdaQueryWrapper.like(XUser::getName, request.getName()); + } + if (StringUtils.isNotBlank(request.getUsername())) { + lambdaQueryWrapper.eq(XUser::getUsername, request.getUsername()); + } + if (StringUtils.isNotBlank(request.getEmail())) { + lambdaQueryWrapper.like(XUser::getEmail, request.getEmail()); + } + if (StringUtils.isNotBlank(request.getPhone())) { + lambdaQueryWrapper.like(XUser::getPhone, request.getPhone()); + } + if (Objects.nonNull(request.getStatus())) { + lambdaQueryWrapper.eq(XUser::getStatus, request.getStatus()); + } + lambdaQueryWrapper.orderByDesc(XUser::getCreateTime); + return userConvert.toPage(userMapper.selectPage(page, lambdaQueryWrapper)); + } + + @Override + public UserResp getUserInfo(Long id) { + XUser user = userMapper.getUserById(id); + return userConvert.toResp(user); + } + + @Override + public Boolean addUser(UserAddRequest request) { + XUser user = userConvert.toDO(request); + user.setTenantId(PrimaryKeyUtils.snowflakeId()); + user.setCreateBy(request.getOperator()); + user.setCreateTime(request.getDateTime()); + user.setUpdateBy(request.getOperator()); + user.setUpdateTime(request.getDateTime()); + return userMapper.insert(user) > 0; + } + + @Override + public Boolean updateUser(UserUpdateRequest request) { + XUser user = userConvert.toDO(request); + user.setCreateBy(request.getOperator()); + user.setCreateTime(request.getDateTime()); + user.setUpdateBy(request.getOperator()); + user.setUpdateTime(request.getDateTime()); + return userMapper.updateById(user) > 0; + } + + @Override + public Boolean delUser(List ids) { + return userMapper.deleteBatch(ids, LocalDateTime.now(), "System") > 0; + } + + @Override + public UserDTO getUserDetail(String username) { + UserDTO dto = new UserDTO(); + XUser user = userMapper.selectByUsername(username); + if (Objects.isNull(user)) { + throw new BusinessException(Code01UserErrorCode.USER_NOT_EXISTS); + } + dto.setUser(userConvert.toResp(user)); + List userRoles = userRoleMapper.getByUserId(user.getId()); + List roleIds = userRoles.stream().map(SysUserRole::getRoleId).toList(); + List roles = roleMapper.getRoleByIds(roleIds); + if (CollectionUtils.isEmpty(roles)) { + throw new BusinessException(Code02RoleErrorCode.ROLE_NOT_EXISTS); + } + dto.setRoles(roles); + dto.setPermissions(Sets.newHashSet("*:*:*")); + return dto; + } + + @Override + public Boolean updateStatus(Long id, Integer status) { + XUser user = userMapper.getUserById(id); + if (Objects.isNull(user)) { + throw new BusinessException(Code01UserErrorCode.USER_NOT_EXISTS); + } + user.setStatus(status); + return userMapper.updateById(user) > 0; + } + + @Override + public Boolean resetPwd(Long userId, String password) { + XUser user = userMapper.getUserById(userId); + if (Objects.isNull(user)) { + throw new BusinessException(Code01UserErrorCode.USER_NOT_EXISTS); + } + String encodePwd = passwordEncoder.encode(password); + user.setPassword(encodePwd); + return userMapper.updateById(user) > 0; + } +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/config/PasswordConfig.java b/xs-service/src/main/java/com/xiang/xs/service/config/PasswordConfig.java new file mode 100644 index 0000000..39e0bc4 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/config/PasswordConfig.java @@ -0,0 +1,14 @@ +package com.xiang.xs.service.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordConfig { + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/converter/XMenuConverter.java b/xs-service/src/main/java/com/xiang/xs/service/converter/XMenuConverter.java new file mode 100644 index 0000000..daccadd --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/converter/XMenuConverter.java @@ -0,0 +1,17 @@ +package com.xiang.xs.service.converter; + +import com.xiang.xs.api.pojo.resp.MenuVO; +import com.xiang.xs.service.entity.SysMenu; +import org.mapstruct.Mapper; + +import java.util.List; + +/** + * @Author: xiang + * @Date: 2026-03-20 15:39 + */ +@Mapper(componentModel = "spring") +public interface XMenuConverter { + + +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/converter/XUserConvert.java b/xs-service/src/main/java/com/xiang/xs/service/converter/XUserConvert.java new file mode 100644 index 0000000..2b6f324 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/converter/XUserConvert.java @@ -0,0 +1,23 @@ +package com.xiang.xs.service.converter; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.xiang.xs.api.pojo.request.user.UserAddRequest; +import com.xiang.xs.api.pojo.request.user.UserQueryRequest; +import com.xiang.xs.api.pojo.request.user.UserUpdateRequest; +import com.xiang.xs.api.pojo.resp.UserResp; +import com.xiang.xs.service.entity.XUser; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper(componentModel = "spring") +public interface XUserConvert { + XUserConvert INSTANCE = Mappers.getMapper(XUserConvert.class); + + XUser toDO (UserQueryRequest request); + XUser toDO (UserAddRequest request); + XUser toDO (UserUpdateRequest request); + + UserResp toResp(XUser user); + + Page toPage(Page page); +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/entity/SysMenu.java b/xs-service/src/main/java/com/xiang/xs/service/entity/SysMenu.java index 2a5e8e1..ccaf1e8 100644 --- a/xs-service/src/main/java/com/xiang/xs/service/entity/SysMenu.java +++ b/xs-service/src/main/java/com/xiang/xs/service/entity/SysMenu.java @@ -1,5 +1,6 @@ package com.xiang.xs.service.entity; +import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -15,6 +16,7 @@ import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor +@TableName("sys_menu") public class SysMenu extends BaseEntity { private static final long serialVersionUID = 1L; diff --git a/xs-service/src/main/java/com/xiang/xs/service/entity/XUser.java b/xs-service/src/main/java/com/xiang/xs/service/entity/XUser.java new file mode 100644 index 0000000..a73ca5f --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/entity/XUser.java @@ -0,0 +1,112 @@ +package com.xiang.xs.service.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class XUser implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 用户名(昵称) + */ + private String name; + + /** + * 账号 + */ + private String username; + + /** + * 密码 + */ + private String password; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phone; + + /** + * 头像 + */ + private String avatar; + + /** + * 最后登陆ip + */ + private String loginIp; + + /** + * 最后登陆时间 + */ + private LocalDateTime loginDate; + + /** + * 状态(0:禁用, 1:启用) + */ + private Integer status; + + /** + * 删除标识(0:未删除 1:已删除) + */ + private Integer delFlag; + + /** + * 创建人 + */ + private String createBy; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改人 + */ + private String updateBy; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * token + */ + private String token; + /** + * 刷新token + */ + private String refreshToken; + /** + * 1:后台用户、2:中台用户、3:前台用户 + */ + private Integer userType; + +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/entity/vo/UserDTO.java b/xs-service/src/main/java/com/xiang/xs/service/entity/vo/UserDTO.java new file mode 100644 index 0000000..58fe025 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/entity/vo/UserDTO.java @@ -0,0 +1,23 @@ +package com.xiang.xs.service.entity.vo; + +import com.xiang.xs.api.pojo.resp.UserResp; +import com.xiang.xs.service.entity.SysDept; +import com.xiang.xs.service.entity.SysRole; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserDTO { + + private List roles; + private UserResp user; + private SysDept dept; +// private List permissionRoles; + private Set permissions; +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/enums/UserStatusEnum.java b/xs-service/src/main/java/com/xiang/xs/service/enums/UserStatusEnum.java new file mode 100644 index 0000000..cb8a7b2 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/enums/UserStatusEnum.java @@ -0,0 +1,17 @@ +package com.xiang.xs.service.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum UserStatusEnum { + + DISABLED(0, "禁用"), + USING(1, "启用"), + ; + + private final Integer code; + private final String msg; + +} diff --git a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysMenuMapper.java b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysMenuMapper.java index 26fe916..7d765a8 100644 --- a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysMenuMapper.java +++ b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysMenuMapper.java @@ -1,5 +1,6 @@ package com.xiang.xs.service.repository.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xiang.xs.service.entity.SysMenu; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -14,7 +15,7 @@ import java.util.List; */ @Mapper @Repository -public interface SysMenuMapper { +public interface SysMenuMapper extends BaseMapper { /** * 查询系统菜单列表 * diff --git a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysRoleMapper.java b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysRoleMapper.java index 141151a..49b8370 100644 --- a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysRoleMapper.java +++ b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysRoleMapper.java @@ -2,6 +2,7 @@ package com.xiang.xs.service.repository.mapper; import com.xiang.xs.service.entity.SysRole; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; @@ -119,4 +120,7 @@ public interface SysRoleMapper { * @return 结果 */ int deleteRoleByIds(Long[] roleIds); + + + List getRoleByIds(@Param("list") List roleIds); } diff --git a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysUserRoleMapper.java b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysUserRoleMapper.java index 9f235d4..d06891d 100644 --- a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysUserRoleMapper.java +++ b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/SysUserRoleMapper.java @@ -69,4 +69,7 @@ public interface SysUserRoleMapper { * @return 结果 */ int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds); + + + List getByUserId(@Param("userId") Long userId); } diff --git a/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/XUserMapper.java b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/XUserMapper.java new file mode 100644 index 0000000..46fe77a --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xs/service/repository/mapper/XUserMapper.java @@ -0,0 +1,47 @@ +package com.xiang.xs.service.repository.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.xiang.xs.service.entity.XUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; +import java.util.List; + +@Repository +@Mapper +public interface XUserMapper extends BaseMapper { + + /** + * 根据用户名查询用户 + * @param username + * @return + */ + XUser selectByUsername(String username); + + /** + * 查询用户列表 + * @param user + * @return + */ + Page getUserList(XUser user); + + /** + * 查询用户详情 + * @param id + * @return + */ + XUser getUserById(Long id); + + + /** + * 批量删除 + * @param ids + * @param time + * @param operator + * @return + */ + int deleteBatch(@Param("ids") List ids, @Param("time") LocalDateTime time, @Param("operator") String operator); +} diff --git a/xs-service/src/main/resources/mapper/SysRoleMapper.xml b/xs-service/src/main/resources/mapper/SysRoleMapper.xml index 132201b..956978e 100644 --- a/xs-service/src/main/resources/mapper/SysRoleMapper.xml +++ b/xs-service/src/main/resources/mapper/SysRoleMapper.xml @@ -87,8 +87,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where r.role_key=#{roleKey} and r.del_flag = '0' limit 1 - - + + + insert into sys_role( role_id, role_name, diff --git a/xs-service/src/main/resources/mapper/SysUserRoleMapper.xml b/xs-service/src/main/resources/mapper/SysUserRoleMapper.xml index 27ca00d..3b5a9d5 100644 --- a/xs-service/src/main/resources/mapper/SysUserRoleMapper.xml +++ b/xs-service/src/main/resources/mapper/SysUserRoleMapper.xml @@ -16,8 +16,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - + + + delete from sys_user_role where user_id in #{userId} diff --git a/xs-service/src/main/resources/mapper/XUserMapper.xml b/xs-service/src/main/resources/mapper/XUserMapper.xml new file mode 100644 index 0000000..bfd4380 --- /dev/null +++ b/xs-service/src/main/resources/mapper/XUserMapper.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + id, + name, + username, + password, + email, + phone, + avatar, + login_ip, + login_date, + status, + del_flag, + create_by, + create_time, + update_by, + update_time, + tenant_id, + token, + refresh_token + + + + update x_user set del_flag = 1 where id = #{id} + + + + update x_user set del_flag = 1, update_time = #{time}, update_by = #{operator} where id in + + #{id} + + + + + + + + + \ No newline at end of file