✨ 角色增删改查
This commit is contained in:
parent
b799b81efc
commit
04e4a15136
|
@ -20,4 +20,9 @@ public class WebController {
|
|||
public String showUserPage() {
|
||||
return "userPage";
|
||||
}
|
||||
|
||||
@GetMapping("/role")
|
||||
public String showRolePage() {
|
||||
return "rolePage";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.spring.step2.domain.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -19,12 +20,15 @@ public class RoleDto {
|
|||
private Long id;
|
||||
|
||||
@Schema(name = "roleName", title = "角色名称")
|
||||
@NotBlank(message = "角色名称不能为空")
|
||||
private String roleName;
|
||||
|
||||
@Schema(name = "description", title = "角色描述")
|
||||
@NotBlank(message = "角色描述不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(name = "remark", title = "备注信息")
|
||||
@NotBlank(message = "备注信息不能为空")
|
||||
private String remark;
|
||||
|
||||
@Schema(name = "createTime", title = "创建时间")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.spring.step2.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
@ -23,6 +24,7 @@ public class PermissionEntity extends BaseEntity {
|
|||
private String remark;
|
||||
|
||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||
@TableField(exist = false)
|
||||
private Boolean isDeleted;
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.spring.step2.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
@ -23,6 +24,7 @@ public class RoleEntity extends BaseEntity {
|
|||
private String remark;
|
||||
|
||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||
@TableField(exist = false)
|
||||
private Boolean isDeleted;
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.spring.step2.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
|
@ -20,6 +21,7 @@ public class RolePermissionEntity extends BaseEntity {
|
|||
private Long permissionId;
|
||||
|
||||
@Schema(name = "isDeleted", title = "是否删除:0-未删除,1-已删除")
|
||||
@TableField(exist = false)
|
||||
private Boolean isDeleted;
|
||||
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
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 lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
@ -14,6 +17,8 @@ import java.time.LocalDateTime;
|
|||
public class RoleVo {
|
||||
|
||||
@Schema(name = "id", title = "主键ID")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
@Schema(name = "roleName", title = "角色名称")
|
||||
|
|
|
@ -44,5 +44,7 @@ mybatis-plus:
|
|||
|
||||
logging:
|
||||
level:
|
||||
com.spring: debug
|
||||
root: info
|
||||
com.spring: debug
|
||||
org.springframework.security: debug
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
const DialogRole = {
|
||||
name: "DialogRole",
|
||||
template: `
|
||||
<div class="modal fade" id="roleBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
|
||||
aria-labelledby="roleBackdropLabel" 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="dialogRoleName"><i class="fas fa-user-alt me-1"></i>角色名</label>
|
||||
<input autocomplete="false" class="form-control" id="dialogRoleName" placeholder="请输入角色名"
|
||||
type="text" v-model="form.roleName" 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,225 @@
|
|||
<!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="dialogFormFlag" :on-search="onSearch" :role-info="roleInfo"></dialog-role>
|
||||
|
||||
<!-- 头部 -->
|
||||
<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="roleName"><i class="fas fa-user-alt me-1"></i>角色名</label>
|
||||
<input autocomplete="false" class="form-control" id="roleName" placeholder="请输入角色名"
|
||||
type="text" v-model="searchForm.roleName">
|
||||
</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.roleName}}</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/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({
|
||||
roleName: undefined,
|
||||
description: undefined,
|
||||
remark: undefined,
|
||||
pageNo: 1,
|
||||
pageSize: 30,
|
||||
pages: 0
|
||||
}),
|
||||
// 角色信息
|
||||
roleInfo: 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(`/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.roleName = undefined;
|
||||
this.searchForm.description = undefined;
|
||||
this.onSearch();
|
||||
},
|
||||
|
||||
/* 添加 */
|
||||
onAdd() {
|
||||
this.dialogFormFlag = true;
|
||||
this.roleInfo = {};
|
||||
},
|
||||
|
||||
/* 修改 */
|
||||
onEdit(roleInfo) {
|
||||
this.dialogFormFlag = 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('Pagination', Pagination)
|
||||
app.component('DialogRole', DialogRole)
|
||||
app.mount('#app');
|
||||
</script>
|
||||
</html>
|
|
@ -7,6 +7,7 @@
|
|||
<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>
|
||||
|
@ -198,9 +199,10 @@
|
|||
const {code, message} = await axiosInstance.delete(`/user`, {data: [user.id]});
|
||||
if (code === 200) {
|
||||
this.onSearch();
|
||||
antd.message.success(message);
|
||||
} else {
|
||||
antd.message.error(message);
|
||||
}
|
||||
|
||||
antd.message.success(message);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
|
Loading…
Reference in New Issue