Compare commits
10 Commits
c25e96b93d
...
27e3b6772f
Author | SHA1 | Date |
---|---|---|
|
27e3b6772f | |
|
90b6a285b3 | |
|
7652b505f7 | |
|
04e4a15136 | |
|
b799b81efc | |
|
7c49dc4b86 | |
|
84770198c8 | |
|
ae77d2905c | |
|
b4bb4f8418 | |
|
9d29b21171 |
|
@ -1,18 +0,0 @@
|
||||||
package com.spring.step2.controller;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
public class LoginController {
|
|
||||||
|
|
||||||
@GetMapping("")
|
|
||||||
public String indexPage() {
|
|
||||||
return "index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/login-page")
|
|
||||||
public String showLoginPage() {
|
|
||||||
return "login";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Tag(name = "系统权限表", description = "系统权限表相关接口")
|
@Tag(name = "系统权限表", description = "系统权限表相关接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/coupon/permission")
|
@RequestMapping("/api/permission")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PermissionController {
|
public class PermissionController {
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Tag(name = "系统角色表", description = "系统角色表相关接口")
|
@Tag(name = "系统角色表", description = "系统角色表相关接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/coupon/role")
|
@RequestMapping("/api/role")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RoleController {
|
public class RoleController {
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Tag(name = "角色权限关联表", description = "角色权限关联表相关接口")
|
@Tag(name = "角色权限关联表", description = "角色权限关联表相关接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/coupon/role-permission")
|
@RequestMapping("/api/role-permission")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RolePermissionController {
|
public class RolePermissionController {
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Tag(name = "用户基本信息表", description = "用户基本信息表相关接口")
|
@Tag(name = "用户基本信息表", description = "用户基本信息表相关接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/coupon/user")
|
@RequestMapping("/api/user")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ public class UserController {
|
||||||
UserDto dto) {
|
UserDto dto) {
|
||||||
Page<UserEntity> pageParams = new Page<>(page, limit);
|
Page<UserEntity> pageParams = new Page<>(page, limit);
|
||||||
PageResult<UserVo> pageResult = userService.getUserPage(pageParams, dto);
|
PageResult<UserVo> pageResult = userService.getUserPage(pageParams, dto);
|
||||||
return Result.success(pageResult);
|
return Result.success(pageResult, ResultCodeEnum.LOAD_FINISHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "添加用户基本信息表", description = "添加用户基本信息表")
|
@Operation(summary = "添加用户基本信息表", description = "添加用户基本信息表")
|
||||||
|
|
|
@ -28,7 +28,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Tag(name = "用户角色关联表", description = "用户角色关联表相关接口")
|
@Tag(name = "用户角色关联表", description = "用户角色关联表相关接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/coupon/user-role")
|
@RequestMapping("/api/user-role")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserRoleController {
|
public class UserRoleController {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.spring.step2.controller;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class WebController {
|
||||||
|
|
||||||
|
@GetMapping("")
|
||||||
|
public String indexPage() {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/login")
|
||||||
|
public String showLoginPage() {
|
||||||
|
return "loginPage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/user")
|
||||||
|
public String showUserPage() {
|
||||||
|
return "userPage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/role")
|
||||||
|
public String showRolePage() {
|
||||||
|
return "rolePage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/permission")
|
||||||
|
public String showPermissionPage() {
|
||||||
|
return "permissionPage";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package com.spring.step2.domain.dto;
|
package com.spring.step2.domain.dto;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -18,13 +19,16 @@ public class RoleDto {
|
||||||
@Schema(name = "id", title = "主键ID")
|
@Schema(name = "id", title = "主键ID")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(name = "roleName", title = "角色名称")
|
@Schema(name = "roleCode", title = "角色码")
|
||||||
private String roleName;
|
@NotBlank(message = "角色码不能为空")
|
||||||
|
private String roleCode;
|
||||||
|
|
||||||
@Schema(name = "description", title = "角色描述")
|
@Schema(name = "description", title = "角色描述")
|
||||||
|
@NotBlank(message = "角色描述不能为空")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@Schema(name = "remark", title = "备注信息")
|
@Schema(name = "remark", title = "备注信息")
|
||||||
|
@NotBlank(message = "备注信息不能为空")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@Schema(name = "createTime", title = "创建时间")
|
@Schema(name = "createTime", title = "创建时间")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.spring.step2.domain.dto;
|
package com.spring.step2.domain.dto;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -13,13 +14,18 @@ import lombok.NoArgsConstructor;
|
||||||
@Schema(name = "UserDTO对象", title = "用户", description = "用户的DTO对象")
|
@Schema(name = "UserDTO对象", title = "用户", description = "用户的DTO对象")
|
||||||
public class UserDto {
|
public class UserDto {
|
||||||
|
|
||||||
|
@Schema(name = "id", title = "主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
@Schema(name = "username", title = "用户名")
|
@Schema(name = "username", title = "用户名")
|
||||||
|
@NotBlank(message = "用户名不能为空")
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
@Schema(name = "password", title = "密码")
|
@Schema(name = "password", title = "密码")
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Schema(name = "email", title = "邮箱")
|
@Schema(name = "email", title = "邮箱")
|
||||||
|
@NotBlank(message = "邮箱不能为空")
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.spring.step2.domain.entity;
|
package com.spring.step2.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
@ -23,6 +24,7 @@ public class PermissionEntity extends BaseEntity {
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||||
|
@TableField(exist = false)
|
||||||
private Boolean isDeleted;
|
private Boolean isDeleted;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.spring.step2.domain.entity;
|
package com.spring.step2.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
@ -13,8 +14,8 @@ import lombok.experimental.Accessors;
|
||||||
@Schema(name = "Role对象", title = "系统角色表", description = "系统角色表的实体类对象")
|
@Schema(name = "Role对象", title = "系统角色表", description = "系统角色表的实体类对象")
|
||||||
public class RoleEntity extends BaseEntity {
|
public class RoleEntity extends BaseEntity {
|
||||||
|
|
||||||
@Schema(name = "roleName", title = "角色名称")
|
@Schema(name = "roleCode", title = "角色码")
|
||||||
private String roleName;
|
private String roleCode;
|
||||||
|
|
||||||
@Schema(name = "description", title = "角色描述")
|
@Schema(name = "description", title = "角色描述")
|
||||||
private String description;
|
private String description;
|
||||||
|
@ -23,6 +24,7 @@ public class RoleEntity extends BaseEntity {
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||||
|
@TableField(exist = false)
|
||||||
private Boolean isDeleted;
|
private Boolean isDeleted;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.spring.step2.domain.entity;
|
package com.spring.step2.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
@ -20,6 +21,7 @@ public class RolePermissionEntity extends BaseEntity {
|
||||||
private Long permissionId;
|
private Long permissionId;
|
||||||
|
|
||||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||||
|
@TableField(exist = false)
|
||||||
private Boolean isDeleted;
|
private Boolean isDeleted;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package com.spring.step2.domain.entity;
|
package com.spring.step2.domain.entity;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
@ -24,7 +24,7 @@ public class UserEntity extends BaseEntity {
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
@Schema(name = "isDeleted", title = "是否被删除")
|
@Schema(name = "isDeleted", title = "是否被删除")
|
||||||
@TableLogic
|
@TableField(exist = false)
|
||||||
private Boolean isDeleted;
|
private Boolean isDeleted;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.spring.step2.domain.entity;
|
package com.spring.step2.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
@ -20,6 +21,7 @@ public class UserRoleEntity extends BaseEntity {
|
||||||
private Long userId;
|
private Long userId;
|
||||||
|
|
||||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||||
|
@TableField(exist = false)
|
||||||
private Boolean isDeleted;
|
private Boolean isDeleted;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
package com.spring.step2.domain.vo;
|
package com.spring.step2.domain.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -14,10 +17,12 @@ import java.time.LocalDateTime;
|
||||||
public class RoleVo {
|
public class RoleVo {
|
||||||
|
|
||||||
@Schema(name = "id", title = "主键ID")
|
@Schema(name = "id", title = "主键ID")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(name = "roleName", title = "角色名称")
|
@Schema(name = "roleCode", title = "角色名称")
|
||||||
private String roleName;
|
private String roleCode;
|
||||||
|
|
||||||
@Schema(name = "description", title = "角色描述")
|
@Schema(name = "description", title = "角色描述")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package com.spring.step2.domain.vo;
|
package com.spring.step2.domain.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -14,14 +17,13 @@ import java.time.LocalDateTime;
|
||||||
public class UserVo {
|
public class UserVo {
|
||||||
|
|
||||||
@Schema(name = "id", title = "主键")
|
@Schema(name = "id", title = "主键")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(name = "username", title = "用户名")
|
@Schema(name = "username", title = "用户名")
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
@Schema(name = "password", title = "密码")
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
@Schema(name = "email", title = "邮箱")
|
@Schema(name = "email", title = "邮箱")
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
|
@ -37,8 +39,5 @@ public class UserVo {
|
||||||
@Schema(name = "updateUser", title = "更新用户ID")
|
@Schema(name = "updateUser", title = "更新用户ID")
|
||||||
private Long updateUser;
|
private Long updateUser;
|
||||||
|
|
||||||
@Schema(name = "isDeleted", title = "是否被删除")
|
|
||||||
private Boolean isDeleted;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ public class PageResult<T> implements Serializable {
|
||||||
@Schema(name = "pageSize", title = "每页记录数")
|
@Schema(name = "pageSize", title = "每页记录数")
|
||||||
private Long pageSize;
|
private Long pageSize;
|
||||||
|
|
||||||
|
@Schema(name = "pages", title = "总分页数")
|
||||||
|
private Long pages;
|
||||||
|
|
||||||
@Schema(name = "total", title = "总记录数")
|
@Schema(name = "total", title = "总记录数")
|
||||||
private Long total;
|
private Long total;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.spring.step2.exception;
|
||||||
|
|
||||||
|
|
||||||
|
import com.spring.step2.domain.vo.result.Result;
|
||||||
|
import com.spring.step2.domain.vo.result.ResultCodeEnum;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import java.sql.SQLIntegrityConstraintViolationException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常拦截器
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
// 自定义异常信息
|
||||||
|
@ExceptionHandler(SecurityException.class)
|
||||||
|
@ResponseBody
|
||||||
|
public Result<Object> exceptionHandler(SecurityException exception) {
|
||||||
|
Integer code = exception.getCode() != null ? exception.getCode() : 500;
|
||||||
|
return Result.error(null, code, exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行时异常信息
|
||||||
|
@ExceptionHandler(RuntimeException.class)
|
||||||
|
@ResponseBody
|
||||||
|
public Result<Object> exceptionHandler(RuntimeException exception) {
|
||||||
|
String message = exception.getMessage();
|
||||||
|
message = StringUtils.hasText(message) ? message : "服务器异常";
|
||||||
|
exception.printStackTrace();
|
||||||
|
|
||||||
|
// 解析异常
|
||||||
|
String jsonParseError = "JSON parse error (.*)";
|
||||||
|
Matcher jsonParseErrorMatcher = Pattern.compile(jsonParseError).matcher(message);
|
||||||
|
if (jsonParseErrorMatcher.find()) {
|
||||||
|
return Result.error(null, 500, "JSON解析异常 " + jsonParseErrorMatcher.group(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据过大
|
||||||
|
String dataTooLongError = "Data too long for column (.*?) at row 1";
|
||||||
|
Matcher dataTooLongErrorMatcher = Pattern.compile(dataTooLongError).matcher(message);
|
||||||
|
if (dataTooLongErrorMatcher.find()) {
|
||||||
|
return Result.error(null, 500, dataTooLongErrorMatcher.group(1) + " 字段数据过大");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主键冲突
|
||||||
|
String primaryKeyError = "Duplicate entry '(.*?)' for key .*";
|
||||||
|
Matcher primaryKeyErrorMatcher = Pattern.compile(primaryKeyError).matcher(message);
|
||||||
|
if (primaryKeyErrorMatcher.find()) {
|
||||||
|
return Result.error(null, 500, "[" + primaryKeyErrorMatcher.group(1) + "]已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// corn表达式错误
|
||||||
|
String cronExpression = "CronExpression '(.*?)' is invalid";
|
||||||
|
Matcher cronExpressionMatcher = Pattern.compile(cronExpression).matcher(message);
|
||||||
|
if (cronExpressionMatcher.find()) {
|
||||||
|
return Result.error(null, 500, "表达式 " + cronExpressionMatcher.group(1) + " 不合法");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.error("GlobalExceptionHandler===>运行时异常信息:{}", message);
|
||||||
|
return Result.error(null, 500, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单验证字段
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Result<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
|
||||||
|
String errorMessage = ex.getBindingResult().getFieldErrors().stream()
|
||||||
|
.map(DefaultMessageSourceResolvable::getDefaultMessage)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
return Result.error(null, 201, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特定异常处理
|
||||||
|
@ExceptionHandler(ArithmeticException.class)
|
||||||
|
@ResponseBody
|
||||||
|
public Result<Object> error(ArithmeticException exception) {
|
||||||
|
log.error("GlobalExceptionHandler===>特定异常信息:{}", exception.getMessage());
|
||||||
|
|
||||||
|
return Result.error(null, 500, exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理SQL异常
|
||||||
|
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
|
||||||
|
@ResponseBody
|
||||||
|
public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException exception) {
|
||||||
|
log.error("GlobalExceptionHandler===>处理SQL异常:{}", exception.getMessage());
|
||||||
|
|
||||||
|
String message = exception.getMessage();
|
||||||
|
if (message.contains("Duplicate entry")) {
|
||||||
|
// 错误信息
|
||||||
|
return Result.error(ResultCodeEnum.USER_IS_EMPTY);
|
||||||
|
} else {
|
||||||
|
return Result.error(ResultCodeEnum.UNKNOWN_EXCEPTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.spring.step2.exception;
|
||||||
|
|
||||||
|
import com.spring.step2.domain.vo.result.ResultCodeEnum;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@Slf4j
|
||||||
|
public class SecurityException extends RuntimeException {
|
||||||
|
// 状态码
|
||||||
|
Integer code;
|
||||||
|
|
||||||
|
// 描述信息
|
||||||
|
String message = "服务异常";
|
||||||
|
|
||||||
|
// 返回结果状态
|
||||||
|
ResultCodeEnum resultCodeEnum;
|
||||||
|
|
||||||
|
public SecurityException(Integer code, String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityException(ResultCodeEnum codeEnum) {
|
||||||
|
super(codeEnum.getMessage());
|
||||||
|
this.code = codeEnum.getCode();
|
||||||
|
this.message = codeEnum.getMessage();
|
||||||
|
this.resultCodeEnum = codeEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityException(String message, Exception exception) {
|
||||||
|
super(message);
|
||||||
|
this.message = message;
|
||||||
|
log.error(message, exception);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permiss
|
||||||
.list(page.getRecords())
|
.list(page.getRecords())
|
||||||
.pageNo(page.getCurrent())
|
.pageNo(page.getCurrent())
|
||||||
.pageSize(page.getSize())
|
.pageSize(page.getSize())
|
||||||
|
.pages(page.getPages())
|
||||||
.total(page.getTotal())
|
.total(page.getTotal())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class RolePermissionServiceImpl extends ServiceImpl<RolePermissionMapper,
|
||||||
.list(page.getRecords())
|
.list(page.getRecords())
|
||||||
.pageNo(page.getCurrent())
|
.pageNo(page.getCurrent())
|
||||||
.pageSize(page.getSize())
|
.pageSize(page.getSize())
|
||||||
|
.pages(page.getPages())
|
||||||
.total(page.getTotal())
|
.total(page.getTotal())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, RoleEntity> impleme
|
||||||
.list(page.getRecords())
|
.list(page.getRecords())
|
||||||
.pageNo(page.getCurrent())
|
.pageNo(page.getCurrent())
|
||||||
.pageSize(page.getSize())
|
.pageSize(page.getSize())
|
||||||
|
.pages(page.getPages())
|
||||||
.total(page.getTotal())
|
.total(page.getTotal())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRoleEnt
|
||||||
.list(page.getRecords())
|
.list(page.getRecords())
|
||||||
.pageNo(page.getCurrent())
|
.pageNo(page.getCurrent())
|
||||||
.pageSize(page.getSize())
|
.pageSize(page.getSize())
|
||||||
|
.pages(page.getPages())
|
||||||
.total(page.getTotal())
|
.total(page.getTotal())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -45,10 +46,12 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> impleme
|
||||||
public PageResult<UserVo> getUserPage(Page<UserEntity> pageParams, UserDto dto) {
|
public PageResult<UserVo> getUserPage(Page<UserEntity> pageParams, UserDto dto) {
|
||||||
IPage<UserVo> page = baseMapper.selectListByPage(pageParams, dto);
|
IPage<UserVo> page = baseMapper.selectListByPage(pageParams, dto);
|
||||||
|
|
||||||
|
|
||||||
return PageResult.<UserVo>builder()
|
return PageResult.<UserVo>builder()
|
||||||
.list(page.getRecords())
|
.list(page.getRecords())
|
||||||
.pageNo(page.getCurrent())
|
.pageNo(page.getCurrent())
|
||||||
.pageSize(page.getSize())
|
.pageSize(page.getSize())
|
||||||
|
.pages(page.getPages())
|
||||||
.total(page.getTotal())
|
.total(page.getTotal())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -63,8 +66,11 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> impleme
|
||||||
UserEntity user = new UserEntity();
|
UserEntity user = new UserEntity();
|
||||||
BeanUtils.copyProperties(dto, user);
|
BeanUtils.copyProperties(dto, user);
|
||||||
|
|
||||||
// 设置用户密码
|
// 用户密码是否为空,为空设置默认密码
|
||||||
String password = user.getPassword();
|
String password = user.getPassword();
|
||||||
|
password = StringUtils.hasText(password) ? password : "123456";
|
||||||
|
|
||||||
|
// 设置用户密码
|
||||||
String encodePassword = passwordEncoder.encode(password);
|
String encodePassword = passwordEncoder.encode(password);
|
||||||
user.setPassword(encodePassword);
|
user.setPassword(encodePassword);
|
||||||
|
|
||||||
|
@ -80,6 +86,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> impleme
|
||||||
public void updateUser(UserDto dto) {
|
public void updateUser(UserDto dto) {
|
||||||
UserEntity user = new UserEntity();
|
UserEntity user = new UserEntity();
|
||||||
BeanUtils.copyProperties(dto, user);
|
BeanUtils.copyProperties(dto, user);
|
||||||
|
|
||||||
|
// 设置用户密码
|
||||||
|
String password = user.getPassword();
|
||||||
|
if (StringUtils.hasText(password)) {
|
||||||
|
String encodePassword = passwordEncoder.encode(password);
|
||||||
|
user.setPassword(encodePassword);
|
||||||
|
}
|
||||||
|
|
||||||
updateById(user);
|
updateById(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,5 +44,7 @@ mybatis-plus:
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
com.spring: debug
|
|
||||||
root: info
|
root: info
|
||||||
|
com.spring: debug
|
||||||
|
org.springframework.security: debug
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<!-- 通用查询映射结果 -->
|
<!-- 通用查询映射结果 -->
|
||||||
<resultMap id="BaseResultMap" type="com.spring.step2.domain.entity.RoleEntity">
|
<resultMap id="BaseResultMap" type="com.spring.step2.domain.entity.RoleEntity">
|
||||||
<id column="id" property="id"/>
|
<id column="id" property="id"/>
|
||||||
<id column="role_name" property="roleName"/>
|
<id column="role_name" property="roleCode"/>
|
||||||
<id column="description" property="description"/>
|
<id column="description" property="description"/>
|
||||||
<id column="remark" property="remark"/>
|
<id column="remark" property="remark"/>
|
||||||
<id column="create_time" property="createTime"/>
|
<id column="create_time" property="createTime"/>
|
||||||
|
@ -30,8 +30,8 @@
|
||||||
<if test="dto.id != null and dto.id != ''">
|
<if test="dto.id != null and dto.id != ''">
|
||||||
and id like CONCAT('%',#{dto.id},'%')
|
and id like CONCAT('%',#{dto.id},'%')
|
||||||
</if>
|
</if>
|
||||||
<if test="dto.roleName != null and dto.roleName != ''">
|
<if test="dto.roleCode != null and dto.roleCode != ''">
|
||||||
and role_name like CONCAT('%',#{dto.roleName},'%')
|
and role_code like CONCAT('%',#{dto.roleCode},'%')
|
||||||
</if>
|
</if>
|
||||||
<if test="dto.description != null and dto.description != ''">
|
<if test="dto.description != null and dto.description != ''">
|
||||||
and description like CONCAT('%',#{dto.description},'%')
|
and description like CONCAT('%',#{dto.description},'%')
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
const {defineComponent} = Vue;
|
||||||
|
|
||||||
|
const HeaderNavs = defineComponent({
|
||||||
|
name: 'HeaderNavs',
|
||||||
|
template: `
|
||||||
|
<ul class="nav nav-tabs justify-content-center my-1">
|
||||||
|
<li class="nav-item" v-for="(nav,index) in navList" :key="index">
|
||||||
|
<a class="nav-link" aria-current="page" :class="{active:activeItem(nav)}"
|
||||||
|
:href="nav.href">{{nav.title}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
navList: ref([
|
||||||
|
{href: "/login", title: "登录页面"},
|
||||||
|
{href: "/user", title: "用户页面"},
|
||||||
|
{href: "/role", title: "角色页面"},
|
||||||
|
{href: "/permission", title: "权限页面"},
|
||||||
|
])
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
activeItem(nav) {
|
||||||
|
const pathname = window.location.pathname;
|
||||||
|
return pathname === nav.href;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
// pagination 类型
|
||||||
|
const pagination = {
|
||||||
|
// 当前页
|
||||||
|
pageNo: 0,
|
||||||
|
// 分页大小
|
||||||
|
pageSize: 0,
|
||||||
|
// 总分页数
|
||||||
|
pages: 0,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Pagination = defineComponent({
|
||||||
|
name: "Pagination",
|
||||||
|
template: `
|
||||||
|
<nav aria-label="Page navigation" class="mt-3">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
<li class="page-item" :class="{disabled:this.pagination.pageNo == 1}">
|
||||||
|
<a @click="pageNoDecrease" class="page-link" href="javascript:">上一页</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li :class="{active:page===pagination.pageNo}" :key="index" class="page-item"
|
||||||
|
v-for="(page,index) in pagination.pages">
|
||||||
|
<a class="page-link" href="javascript:" @click="onCurrentPageClick(page)">{{page}}</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item" :class="{disabled:this.pagination.pageNo >= this.pagination.pages}">
|
||||||
|
<a @click="pageNoIncrease" class="page-link" href="javascript:">下一页</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
`,
|
||||||
|
props: {
|
||||||
|
pagination: {type: Object, required: true},
|
||||||
|
// 初始化加载数据
|
||||||
|
onSearch: {type: Function, required: true},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* 当前分页+1 */
|
||||||
|
pageNoIncrease() {
|
||||||
|
this.pagination.pageNo++;
|
||||||
|
this.$emit("update:pagination", this.pagination);
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
/* 当前分页-1 */
|
||||||
|
pageNoDecrease() {
|
||||||
|
this.pagination.pageNo--;
|
||||||
|
this.$emit("update:pagination", this.pagination);
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
/* 点击当前页 */
|
||||||
|
onCurrentPageClick(page) {
|
||||||
|
this.pagination.pageNo = page;
|
||||||
|
this.$emit("update:pagination", this.pagination);
|
||||||
|
this.onSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,6 +1,6 @@
|
||||||
// axios 配置
|
// axios 配置
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
baseURL: 'http://localhost:8800/api',
|
baseURL: 'http://localhost:8772/api',
|
||||||
timeout: 16000,
|
timeout: 16000,
|
||||||
headers: {'Content-Type': 'application/json;charset=utf-8'},
|
headers: {'Content-Type': 'application/json;charset=utf-8'},
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/* 提高 Antd Message 的 z-index,让提示框为最上层 */
|
||||||
|
.ant-message {
|
||||||
|
z-index: 1100 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式 OffCanvas 宽度 */
|
||||||
|
.offcanvas.offcanvas-start {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.offcanvas.offcanvas-start {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.offcanvas.offcanvas-start {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加自定义样式 */
|
||||||
|
.database-info-card {
|
||||||
|
border-left: 4px solid #0d6efd;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-info-section {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-list {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-item {
|
||||||
|
border-left: 3px solid #6c757d;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-item:hover {
|
||||||
|
border-left-color: #0d6efd;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-java {
|
||||||
|
background-color: #5382a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-jdbc {
|
||||||
|
background-color: #4479a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-js {
|
||||||
|
background-color: #f7df1e;
|
||||||
|
color: #000;
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
body {
|
body {
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
padding-top: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
6
spring-security/step-2/src/main/resources/static/src/lib/js/boostrap/popper.min.js
vendored
Normal file
6
spring-security/step-2/src/main/resources/static/src/lib/js/boostrap/popper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,97 @@
|
||||||
|
const DialogPermission = defineComponent({
|
||||||
|
name: "DialogPermission",
|
||||||
|
template: `
|
||||||
|
<div class="modal fade" id="permissionBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
|
||||||
|
aria-labelledby="permissionBackdropLabel" ref="modalRef">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{{isAdd?"新增权限":"修改权限"}}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form @submit.prevent="onSubmit">
|
||||||
|
<!-- 内容 -->
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogPermissionCode"><i class="fas fa-user-alt me-1"></i>权限码</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogPermissionCode" placeholder="请输入权限码"
|
||||||
|
type="text" v-model="form.permissionCode" required>
|
||||||
|
<div class="form-text">在这里输入你的权限码。</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogDescription"><i class="fas fa-user-alt me-1"></i>描述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogDescription" placeholder="请输入描述"
|
||||||
|
type="text" v-model="form.description" required>
|
||||||
|
<div class="form-text">在这里输入你的描述。</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogRemark"><i class="fas fa-user-alt me-1"></i>简述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogRemark" placeholder="请输入简述"
|
||||||
|
type="text" v-model="form.remark" required>
|
||||||
|
<div class="form-text">在这里输入你的简述。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部 -->
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||||
|
<button type="submit" class="btn btn-primary">确认</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
props: {
|
||||||
|
// 是否添加
|
||||||
|
isAdd: {type: Boolean, default: false},
|
||||||
|
// 权限信息
|
||||||
|
permissionInfo: {type: Object, required: true},
|
||||||
|
// 加载函数
|
||||||
|
onSearch: {type: Function, required: true},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
modalInstance: ref(null),
|
||||||
|
form: ref({}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async onSubmit() {
|
||||||
|
// 是否添加表单
|
||||||
|
const {code, message} = this.isAdd ?
|
||||||
|
await axiosInstance.post("/permission", this.form) :
|
||||||
|
await axiosInstance.put("/permission", this.form);
|
||||||
|
|
||||||
|
if (code === 200) {
|
||||||
|
antd.message.success(message);
|
||||||
|
// 关闭模态框
|
||||||
|
this.modalInstance.hide();
|
||||||
|
this.onSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
permissionInfo(val) {
|
||||||
|
// 创建深拷贝,而不是直接赋值
|
||||||
|
this.form = JSON.parse(JSON.stringify(val));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化模态框实例
|
||||||
|
const modalEl = this.$refs.modalRef;
|
||||||
|
this.modalInstance = new bootstrap.Modal(modalEl, {
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
// 组件销毁时清理模态框实例
|
||||||
|
if (this.modalInstance) {
|
||||||
|
this.modalInstance.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,97 @@
|
||||||
|
const DialogRole = defineComponent({
|
||||||
|
name: "DialogRole",
|
||||||
|
template: `
|
||||||
|
<div class="modal fade" id="roleBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
|
||||||
|
aria-labelledby="roleBackdropLabel" ref="modalRef">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{{isAdd?"新增角色":"修改角色"}}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form @submit.prevent="onSubmit">
|
||||||
|
<!-- 内容 -->
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogRoleCode"><i class="fas fa-user-alt me-1"></i>角色码</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogRoleCode" placeholder="请输入角色名"
|
||||||
|
type="text" v-model="form.roleCode" required>
|
||||||
|
<div class="form-text">在这里输入你的角色码。</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogDescription"><i class="fas fa-user-alt me-1"></i>描述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogDescription" placeholder="请输入描述"
|
||||||
|
type="text" v-model="form.description" required>
|
||||||
|
<div class="form-text">在这里输入你的描述。</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogRemark"><i class="fas fa-user-alt me-1"></i>简述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogRemark" placeholder="请输入简述"
|
||||||
|
type="text" v-model="form.remark" required>
|
||||||
|
<div class="form-text">在这里输入你的简述。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部 -->
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||||
|
<button type="submit" class="btn btn-primary">确认</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
props: {
|
||||||
|
// 是否添加
|
||||||
|
isAdd: {type: Boolean, default: false},
|
||||||
|
// 角色信息
|
||||||
|
roleInfo: {type: Object, required: true},
|
||||||
|
// 加载函数
|
||||||
|
onSearch: {type: Function, required: true},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
modalInstance: ref(null),
|
||||||
|
form: ref({}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async onSubmit() {
|
||||||
|
// 是否添加表单
|
||||||
|
const {code, message} = this.isAdd ?
|
||||||
|
await axiosInstance.post("/role", this.form) :
|
||||||
|
await axiosInstance.put("/role", this.form);
|
||||||
|
|
||||||
|
if (code === 200) {
|
||||||
|
antd.message.success(message);
|
||||||
|
// 关闭模态框
|
||||||
|
this.modalInstance.hide();
|
||||||
|
this.onSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
roleInfo(val) {
|
||||||
|
// 创建深拷贝,而不是直接赋值
|
||||||
|
this.form = JSON.parse(JSON.stringify(val));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化模态框实例
|
||||||
|
const modalEl = this.$refs.modalRef;
|
||||||
|
this.modalInstance = new bootstrap.Modal(modalEl, {
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
// 组件销毁时清理模态框实例
|
||||||
|
if (this.modalInstance) {
|
||||||
|
this.modalInstance.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,100 @@
|
||||||
|
const DialogUser = defineComponent({
|
||||||
|
name: "DialogUser",
|
||||||
|
template: `
|
||||||
|
<div class="modal fade" id="userBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
|
||||||
|
aria-labelledby="userBackdropLabel" aria-hidden="true" ref="modalRef">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{{isAdd?"新增用户":"修改用户"}}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form @submit.prevent="onSubmit">
|
||||||
|
<!-- 内容 -->
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogUsername"><i class="fas fa-user me-1"></i>用户名</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogUsername" placeholder="请输入用户名"
|
||||||
|
type="text" v-model="form.username" required>
|
||||||
|
<div class="form-text">在这里输入你的用户名。</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogPassword"><i class="fas fa-lock me-1"></i>密码</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogPassword" placeholder="请输入密码"
|
||||||
|
type="password" v-model="form.password">
|
||||||
|
<div class="form-text">如果不修改或添加不填写此项。</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="dialogEmail"><i class="fas fa-envelope me-1"></i>邮箱</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="dialogEmail" placeholder="请输入邮箱"
|
||||||
|
type="email" v-model="form.email" required>
|
||||||
|
<div class="form-text">在这里输入你的邮箱。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部 -->
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||||
|
<button type="submit" class="btn btn-primary">确认</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
props: {
|
||||||
|
// 是否添加
|
||||||
|
isAdd: {type: Boolean, default: false},
|
||||||
|
// 用户信息
|
||||||
|
userinfo: {type: Object, required: true},
|
||||||
|
// 加载函数
|
||||||
|
onSearch: {type: Function, required: true},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
modalInstance: ref(null),
|
||||||
|
form: ref({}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async onSubmit() {
|
||||||
|
// 是否添加表单
|
||||||
|
const {code, message} = this.isAdd ?
|
||||||
|
await axiosInstance.post("/user", this.form) :
|
||||||
|
await axiosInstance.put("/user", this.form);
|
||||||
|
|
||||||
|
if (code === 200) {
|
||||||
|
antd.message.success(message);
|
||||||
|
// 关闭模态框
|
||||||
|
this.modalInstance.hide();
|
||||||
|
this.onSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
userinfo(val) {
|
||||||
|
// 创建深拷贝,而不是直接赋值
|
||||||
|
this.form = JSON.parse(JSON.stringify(val));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化模态框实例
|
||||||
|
const modalEl = this.$refs.modalRef;
|
||||||
|
this.modalInstance = new bootstrap.Modal(modalEl, {
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
// 组件销毁时清理模态框实例
|
||||||
|
if (this.modalInstance) {
|
||||||
|
this.modalInstance.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -382,7 +382,7 @@
|
||||||
<li><a href="#docs" target="_blank">文档</a></li>
|
<li><a href="#docs" target="_blank">文档</a></li>
|
||||||
<li><a href="/doc.html" target="_blank">API 文档</a></li>
|
<li><a href="/doc.html" target="_blank">API 文档</a></li>
|
||||||
<li><a href="/swagger-ui/index.html" target="_blank">Swagger UI</a></li>
|
<li><a href="/swagger-ui/index.html" target="_blank">Swagger UI</a></li>
|
||||||
<li><a href="/login-page" target="_blank">登录</a></li>
|
<li><a href="/login" target="_blank">登录</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/bootstrap/5.1.3/css/bootstrap.min.css}">
|
||||||
|
<!-- Font Awesome -->
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/font-awesome/5.15.4/css/all.min.css}">
|
||||||
|
<link rel="stylesheet" th:href="@{/src/lib/css/style.css}">
|
||||||
|
<link rel="stylesheet" th:href="@{/src/lib/css/tablePage.css}">
|
||||||
|
<!-- Vue3 -->
|
||||||
|
<script th:src="@{/src/lib/js/vue/vue.global.js}"></script>
|
||||||
|
<!-- Bootstrap JS Bundle with Popper -->
|
||||||
|
<script th:src="@{/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js}"></script>
|
||||||
|
<!-- 本地引入 popper JS -->
|
||||||
|
<script th:src="@{/src/lib/js/boostrap/popper.min.js}"></script>
|
||||||
|
<!-- 本地引入 axios JS -->
|
||||||
|
<script th:src="@{/src/lib/js/axios/axios.min.js}"></script>
|
||||||
|
<!-- 引入dayjs -->
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/dayjs.min.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/customParseFormat.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekday.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/localeData.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekOfYear.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekYear.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/advancedFormat.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/quarterOfYear.js}"></script>
|
||||||
|
<!-- 引入 antd JS -->
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/antd.min.js}"></script>
|
||||||
|
|
||||||
|
<title>权限管理页面</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid" id="app">
|
||||||
|
<dialog-permission :is-add="isAdd" :on-search="onSearch"
|
||||||
|
:permission-info="permissionInfo"></dialog-permission>
|
||||||
|
|
||||||
|
<header-navs></header-navs>
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="fas fa-search me-2"></i>权限查询</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form @reset="onRest" @submit.prevent="onSearch">
|
||||||
|
<div class="row g-3 align-items-center">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="permissionCode"><i
|
||||||
|
class="fas fa-power-off me-1"></i>权限码</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="permissionCode" placeholder="请输入权限码"
|
||||||
|
type="text" v-model="searchForm.permissionCode">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="description"><i class="fas fa-text-width me-1"></i>描述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="description" placeholder="请输入描述"
|
||||||
|
type="text" v-model="searchForm.description">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="remark"><i class="fas fa-info me-1"></i>简述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="remark" placeholder="请输入简述"
|
||||||
|
type="text" v-model="searchForm.remark">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="search-btn-group">
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
<i class="fas fa-search me-1"></i>查询
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary" type="reset">
|
||||||
|
<i class="fas fa-redo me-1"></i>重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="fas fa-power-off me-2"></i>权限列表</span>
|
||||||
|
<button @click="onAdd" class="btn btn-sm btn-success"
|
||||||
|
data-bs-target="#permissionBackdrop" data-bs-toggle="modal">
|
||||||
|
<i class="fas fa-plus me-1"></i>新增权限
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" width="5%">#</th>
|
||||||
|
<th scope="col" width="15%">权限名</th>
|
||||||
|
<th scope="col" width="15%">描述</th>
|
||||||
|
<th scope="col" width="15%">简述</th>
|
||||||
|
<th scope="col" width="15%">创建时间</th>
|
||||||
|
<th scope="col" width="15%">更新时间</th>
|
||||||
|
<th scope="col" width="20%">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr :key="permission.id" v-for="(permission,index) in dataList">
|
||||||
|
<th scope="row">{{index + 1}}</th>
|
||||||
|
<td>{{permission.permissionCode}}</td>
|
||||||
|
<td>{{permission.description}}</td>
|
||||||
|
<td>{{permission.remark}}</td>
|
||||||
|
<td>{{formatDate(permission.createTime)}}</td>
|
||||||
|
<td>{{formatDate(permission.updateTime)}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<button @click="onEdit(permission)" class="btn btn-outline-primary btn-action"
|
||||||
|
data-bs-target="#permissionBackdrop" data-bs-toggle="modal">
|
||||||
|
<i class="fas fa-edit"></i> 修改
|
||||||
|
</button>
|
||||||
|
<button @click="onDeleted(permission)" class="btn btn-outline-danger btn-action">
|
||||||
|
<i class="fas fa-trash"></i> 删除
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格分页 -->
|
||||||
|
<pagination :on-search="onSearch" v-model:pagination="searchForm"></pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<!-- 设置 popper 提示框 -->
|
||||||
|
<script th:src="@{/src/config/popper-config.js}"></script>
|
||||||
|
<!-- 加载全局axios配置 -->
|
||||||
|
<script th:src="@{/src/config/axios-config.js}"></script>
|
||||||
|
|
||||||
|
<!-- 头部导航 -->
|
||||||
|
<script th:src="@{/src/components/HeaderNavs.js}"></script>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<script th:src="@{/src/components/Pagination.js}"></script>
|
||||||
|
<!-- 权限表单 -->
|
||||||
|
<script th:src="@{/src/views/permission/DialogPermission.js}"></script>
|
||||||
|
<script>
|
||||||
|
const {createApp, ref} = Vue;
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 查询表单
|
||||||
|
searchForm: ref({
|
||||||
|
permissionCode: undefined,
|
||||||
|
email: undefined,
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 30,
|
||||||
|
pages: 0
|
||||||
|
}),
|
||||||
|
// 权限信息
|
||||||
|
permissionInfo: ref({}),
|
||||||
|
// 弹窗标题
|
||||||
|
isAdd: ref(false),
|
||||||
|
// 查询权限列表
|
||||||
|
dataList: ref([])
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
/* 格式化时间 */
|
||||||
|
formatDate(date) {
|
||||||
|
return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 加载数据 */
|
||||||
|
async onSearch() {
|
||||||
|
const {pageNo, pageSize} = this.searchForm;
|
||||||
|
// 查询数据
|
||||||
|
const {data} = await axiosInstance.get(`/permission/${pageNo}/${pageSize}`, {params: this.searchForm})
|
||||||
|
|
||||||
|
// 赋值数据
|
||||||
|
this.dataList = data.list;
|
||||||
|
|
||||||
|
// 设置分页内容
|
||||||
|
this.searchForm.pageNo = data.pageNo;
|
||||||
|
this.searchForm.pageSize = data.pageSize;
|
||||||
|
this.searchForm.pages = data.pages;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 重制表单 */
|
||||||
|
onRest() {
|
||||||
|
this.searchForm.permissionCode = undefined;
|
||||||
|
this.searchForm.email = undefined;
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 添加 */
|
||||||
|
onAdd() {
|
||||||
|
this.isAdd = true;
|
||||||
|
this.permissionInfo = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 修改 */
|
||||||
|
onEdit(permission) {
|
||||||
|
this.isAdd = false;
|
||||||
|
this.permissionInfo = permission;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 删除 */
|
||||||
|
async onDeleted(permission) {
|
||||||
|
const result = confirm("确认删除?");
|
||||||
|
if (!result) return false;
|
||||||
|
|
||||||
|
// 删除权限
|
||||||
|
const {code, message} = await axiosInstance.delete(`/permission`, {data: [permission.id]});
|
||||||
|
if (code === 200) {
|
||||||
|
await this.onSearch();
|
||||||
|
antd.message.success(message);
|
||||||
|
} else {
|
||||||
|
antd.message.error(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.component('HeaderNavs', HeaderNavs)
|
||||||
|
app.component('Pagination', Pagination)
|
||||||
|
app.component('DialogPermission', DialogPermission)
|
||||||
|
app.mount('#app');
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,230 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/bootstrap/5.1.3/css/bootstrap.min.css}">
|
||||||
|
<!-- Font Awesome -->
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/font-awesome/5.15.4/css/all.min.css}">
|
||||||
|
<link rel="stylesheet" th:href="@{/src/lib/css/style.css}">
|
||||||
|
<link rel="stylesheet" th:href="@{/src/lib/css/tablePage.css}">
|
||||||
|
<!-- Vue3 -->
|
||||||
|
<script th:src="@{/src/lib/js/vue/vue.global.js}"></script>
|
||||||
|
<!-- Bootstrap JS Bundle with Popper -->
|
||||||
|
<script th:src="@{/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js}"></script>
|
||||||
|
<!-- 本地引入 popper JS -->
|
||||||
|
<script th:src="@{/src/lib/js/boostrap/popper.min.js}"></script>
|
||||||
|
<!-- 本地引入 axios JS -->
|
||||||
|
<script th:src="@{/src/lib/js/axios/axios.min.js}"></script>
|
||||||
|
<!-- 引入dayjs -->
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/dayjs.min.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/customParseFormat.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekday.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/localeData.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekOfYear.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekYear.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/advancedFormat.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/quarterOfYear.js}"></script>
|
||||||
|
<!-- 引入 antd JS -->
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/antd.min.js}"></script>
|
||||||
|
|
||||||
|
<title>角色管理页面</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid" id="app">
|
||||||
|
<dialog-role :is-add="isAdd" :on-search="onSearch" :role-info="roleInfo"></dialog-role>
|
||||||
|
|
||||||
|
<header-navs></header-navs>
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="fas fa-search me-2"></i>角色查询</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form @reset="onRest" @submit.prevent="onSearch">
|
||||||
|
<div class="row g-3 align-items-center">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="roleCode"><i class="fas fa-user-alt me-1"></i>角色名</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="roleCode" placeholder="请输入角色名"
|
||||||
|
type="text" v-model="searchForm.roleCode">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="description"><i class="fas fa-text-width me-1"></i>描述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="description" placeholder="请输入描述"
|
||||||
|
type="text" v-model="searchForm.description">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="remark"><i class="fas fa-info me-1"></i>简述</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="remark" placeholder="请输入简述"
|
||||||
|
type="text" v-model="searchForm.remark">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="search-btn-group">
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
<i class="fas fa-search me-1"></i>查询
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary" type="reset">
|
||||||
|
<i class="fas fa-redo me-1"></i>重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="fas fa-users me-2"></i>角色列表</span>
|
||||||
|
<button @click="onAdd" class="btn btn-sm btn-success" data-bs-target="#roleBackdrop" data-bs-toggle="modal">
|
||||||
|
<i class="fas fa-plus me-1"></i>新增角色
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" width="5%">#</th>
|
||||||
|
<th scope="col" width="15%">角色名</th>
|
||||||
|
<th scope="col" width="15%">描述</th>
|
||||||
|
<th scope="col" width="15%">简述</th>
|
||||||
|
<th scope="col" width="15%">创建时间</th>
|
||||||
|
<th scope="col" width="15%">更新时间</th>
|
||||||
|
<th scope="col" width="20%">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr :key="role.id" v-for="(role,index) in dataList">
|
||||||
|
<th scope="row">{{index + 1}}</th>
|
||||||
|
<td>{{role.roleCode}}</td>
|
||||||
|
<td>{{role.description}}</td>
|
||||||
|
<td>{{role.remark}}</td>
|
||||||
|
<td>{{formatDate(role.createTime)}}</td>
|
||||||
|
<td>{{formatDate(role.updateTime)}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<button @click="onEdit(role)" class="btn btn-outline-primary btn-action"
|
||||||
|
data-bs-target="#roleBackdrop" data-bs-toggle="modal">
|
||||||
|
<i class="fas fa-edit"></i> 修改
|
||||||
|
</button>
|
||||||
|
<button @click="onDeleted(role)" class="btn btn-outline-danger btn-action">
|
||||||
|
<i class="fas fa-trash"></i> 删除
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格分页 -->
|
||||||
|
<pagination :on-search="onSearch" v-model:pagination="searchForm"></pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<!-- 设置 popper 提示框 -->
|
||||||
|
<script th:src="@{/src/config/popper-config.js}"></script>
|
||||||
|
<!-- 加载全局axios配置 -->
|
||||||
|
<script th:src="@{/src/config/axios-config.js}"></script>
|
||||||
|
|
||||||
|
<!-- 头部导航 -->
|
||||||
|
<script th:src="@{/src/components/HeaderNavs.js}"></script>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<script th:src="@{/src/components/Pagination.js}"></script>
|
||||||
|
<!-- 角色表单 -->
|
||||||
|
<script th:src="@{/src/views/role/DialogRole.js}"></script>
|
||||||
|
<script>
|
||||||
|
const {createApp, ref, toRaw} = Vue;
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 查询表单
|
||||||
|
searchForm: ref({
|
||||||
|
roleCode: undefined,
|
||||||
|
description: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 30,
|
||||||
|
pages: 0
|
||||||
|
}),
|
||||||
|
// 角色信息
|
||||||
|
roleInfo: ref({}),
|
||||||
|
// 弹窗标题
|
||||||
|
isAdd: ref(false),
|
||||||
|
// 查询角色列表
|
||||||
|
dataList: ref([])
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
/* 格式化时间 */
|
||||||
|
formatDate(date) {
|
||||||
|
return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 加载数据 */
|
||||||
|
async onSearch() {
|
||||||
|
const {pageNo, pageSize} = this.searchForm;
|
||||||
|
// 查询数据
|
||||||
|
const {data} = await axiosInstance.get(`/role/${pageNo}/${pageSize}`, {params: this.searchForm})
|
||||||
|
|
||||||
|
// 赋值数据
|
||||||
|
this.dataList = data.list;
|
||||||
|
|
||||||
|
// 设置分页内容
|
||||||
|
this.searchForm.pageNo = data.pageNo;
|
||||||
|
this.searchForm.pageSize = data.pageSize;
|
||||||
|
this.searchForm.pages = data.pages;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 重制表单 */
|
||||||
|
onRest() {
|
||||||
|
this.searchForm.roleCode = undefined;
|
||||||
|
this.searchForm.description = undefined;
|
||||||
|
this.searchForm.remark = undefined;
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 添加 */
|
||||||
|
onAdd() {
|
||||||
|
this.isAdd = true;
|
||||||
|
this.roleInfo = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 修改 */
|
||||||
|
onEdit(roleInfo) {
|
||||||
|
this.isAdd = false;
|
||||||
|
this.roleInfo = roleInfo;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 删除 */
|
||||||
|
async onDeleted(roleInfo) {
|
||||||
|
const result = confirm("确认删除?");
|
||||||
|
if (!result) return false;
|
||||||
|
|
||||||
|
// 删除角色
|
||||||
|
const {code, message} = await axiosInstance.delete(`/role`, {data: [roleInfo.id]});
|
||||||
|
if (code === 200) {
|
||||||
|
await this.onSearch();
|
||||||
|
antd.message.success(message);
|
||||||
|
} else {
|
||||||
|
antd.message.error(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.component('HeaderNavs', HeaderNavs);
|
||||||
|
app.component('Pagination', Pagination);
|
||||||
|
app.component('DialogRole', DialogRole);
|
||||||
|
app.mount('#app');
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,221 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/bootstrap/5.1.3/css/bootstrap.min.css}">
|
||||||
|
<!-- Font Awesome -->
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/font-awesome/5.15.4/css/all.min.css}">
|
||||||
|
<link rel="stylesheet" th:href="@{/src/lib/css/style.css}">
|
||||||
|
<link rel="stylesheet" th:href="@{/src/lib/css/tablePage.css}">
|
||||||
|
<!-- Vue3 -->
|
||||||
|
<script th:src="@{/src/lib/js/vue/vue.global.js}"></script>
|
||||||
|
<!-- Bootstrap JS Bundle with Popper -->
|
||||||
|
<script th:src="@{/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js}"></script>
|
||||||
|
<!-- 本地引入 popper JS -->
|
||||||
|
<script th:src="@{/src/lib/js/boostrap/popper.min.js}"></script>
|
||||||
|
<!-- 本地引入 axios JS -->
|
||||||
|
<script th:src="@{/src/lib/js/axios/axios.min.js}"></script>
|
||||||
|
<!-- 引入dayjs -->
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/dayjs.min.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/customParseFormat.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekday.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/localeData.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekOfYear.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/weekYear.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/advancedFormat.js}"></script>
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/quarterOfYear.js}"></script>
|
||||||
|
<!-- 引入 antd JS -->
|
||||||
|
<script th:src="@{/src/lib/js/dayjs/antd.min.js}"></script>
|
||||||
|
|
||||||
|
<title>用户管理页面</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid" id="app">
|
||||||
|
<dialog-user :is-add="dialogFormFlag" :on-search="onSearch" :userinfo="userinfo"></dialog-user>
|
||||||
|
|
||||||
|
<header-navs></header-navs>
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="fas fa-search me-2"></i>用户查询</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form @reset="onRest" @submit.prevent="onSearch">
|
||||||
|
<div class="row g-3 align-items-center">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="username"><i class="fas fa-user me-1"></i>用户名</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="username" placeholder="请输入用户名"
|
||||||
|
type="text" v-model="searchForm.username">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label" for="email"><i class="fas fa-envelope me-1"></i>邮箱</label>
|
||||||
|
<input autocomplete="false" class="form-control" id="email" placeholder="请输入邮箱"
|
||||||
|
type="email" v-model="searchForm.email">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="search-btn-group">
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
<i class="fas fa-search me-1"></i>查询
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary" type="reset">
|
||||||
|
<i class="fas fa-redo me-1"></i>重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="fas fa-users me-2"></i>用户列表</span>
|
||||||
|
<button @click="onAdd" class="btn btn-sm btn-success" data-bs-target="#userBackdrop" data-bs-toggle="modal">
|
||||||
|
<i class="fas fa-plus me-1"></i>新增用户
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" width="5%">#</th>
|
||||||
|
<th scope="col" width="22%">用户名</th>
|
||||||
|
<th scope="col" width="22%">邮箱</th>
|
||||||
|
<th scope="col" width="17%">创建时间</th>
|
||||||
|
<th scope="col" width="17%">更新时间</th>
|
||||||
|
<th scope="col" width="16%">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr :key="user.id" v-for="(user,index) in dataList">
|
||||||
|
<th scope="row">{{index + 1}}</th>
|
||||||
|
<td>{{user.username}}</td>
|
||||||
|
<td>{{user.email}}</td>
|
||||||
|
<td>{{formatDate(user.createTime)}}</td>
|
||||||
|
<td>{{formatDate(user.updateTime)}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<button @click="onEdit(user)" class="btn btn-outline-primary btn-action"
|
||||||
|
data-bs-target="#userBackdrop" data-bs-toggle="modal">
|
||||||
|
<i class="fas fa-edit"></i> 修改
|
||||||
|
</button>
|
||||||
|
<button @click="onDeleted(user)" class="btn btn-outline-danger btn-action">
|
||||||
|
<i class="fas fa-trash"></i> 删除
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格分页 -->
|
||||||
|
<pagination :on-search="onSearch" v-model:pagination="searchForm"></pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<!-- 设置 popper 提示框 -->
|
||||||
|
<script th:src="@{/src/config/popper-config.js}"></script>
|
||||||
|
<!-- 加载全局axios配置 -->
|
||||||
|
<script th:src="@{/src/config/axios-config.js}"></script>
|
||||||
|
|
||||||
|
<!-- 头部导航 -->
|
||||||
|
<script th:src="@{/src/components/HeaderNavs.js}"></script>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<script th:src="@{/src/components/Pagination.js}"></script>
|
||||||
|
<!-- 用户表单 -->
|
||||||
|
<script th:src="@{/src/views/user/DialogUser.js}"></script>
|
||||||
|
<script>
|
||||||
|
const {createApp, ref} = Vue;
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 查询表单
|
||||||
|
searchForm: ref({
|
||||||
|
username: undefined,
|
||||||
|
email: undefined,
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 30,
|
||||||
|
pages: 0
|
||||||
|
}),
|
||||||
|
// 用户信息
|
||||||
|
userinfo: ref({}),
|
||||||
|
// 弹窗标题
|
||||||
|
dialogFormFlag: ref(false),
|
||||||
|
// 查询用户列表
|
||||||
|
dataList: ref([])
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
/* 格式化时间 */
|
||||||
|
formatDate(date) {
|
||||||
|
return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 加载数据 */
|
||||||
|
async onSearch() {
|
||||||
|
const {pageNo, pageSize} = this.searchForm;
|
||||||
|
// 查询数据
|
||||||
|
const {data} = await axiosInstance.get(`/user/${pageNo}/${pageSize}`, {params: this.searchForm})
|
||||||
|
|
||||||
|
// 赋值数据
|
||||||
|
this.dataList = data.list;
|
||||||
|
|
||||||
|
// 设置分页内容
|
||||||
|
this.searchForm.pageNo = data.pageNo;
|
||||||
|
this.searchForm.pageSize = data.pageSize;
|
||||||
|
this.searchForm.pages = data.pages;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 重制表单 */
|
||||||
|
onRest() {
|
||||||
|
this.searchForm.username = undefined;
|
||||||
|
this.searchForm.email = undefined;
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 添加 */
|
||||||
|
onAdd() {
|
||||||
|
this.dialogFormFlag = true;
|
||||||
|
this.userinfo = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 修改 */
|
||||||
|
onEdit(user) {
|
||||||
|
this.dialogFormFlag = false;
|
||||||
|
this.userinfo = user;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* 删除 */
|
||||||
|
async onDeleted(user) {
|
||||||
|
const result = confirm("确认删除?");
|
||||||
|
if (!result) return false;
|
||||||
|
|
||||||
|
// 删除用户
|
||||||
|
const {code, message} = await axiosInstance.delete(`/user`, {data: [user.id]});
|
||||||
|
if (code === 200) {
|
||||||
|
this.onSearch();
|
||||||
|
antd.message.success(message);
|
||||||
|
} else {
|
||||||
|
antd.message.error(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.onSearch();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.component('HeaderNavs', HeaderNavs);
|
||||||
|
app.component('Pagination', Pagination);
|
||||||
|
app.component('DialogUser', DialogUser);
|
||||||
|
app.mount('#app');
|
||||||
|
</script>
|
||||||
|
</html>
|
Loading…
Reference in New Issue