|
@@ -0,0 +1,359 @@
|
|
|
+<template>
|
|
|
+ <div class="role-management">
|
|
|
+ <div class="header-bar">
|
|
|
+ <a-button type="text" @click="goBack">
|
|
|
+ <arrow-left-outlined />
|
|
|
+ 返回
|
|
|
+ </a-button>
|
|
|
+ <h2>角色管理</h2>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="role-content">
|
|
|
+ <div class="operation-bar">
|
|
|
+ <div class="search-box">
|
|
|
+ <a-input-search
|
|
|
+ v-model:value="searchKeyword"
|
|
|
+ placeholder="请输入角色名称搜索"
|
|
|
+ @search="handleSearch"
|
|
|
+ style="width: 250px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <a-button type="primary" @click="showAddModal">
|
|
|
+ <plus-outlined />
|
|
|
+ 添加角色
|
|
|
+ </a-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <a-table
|
|
|
+ :columns="columns"
|
|
|
+ :data-source="roleList"
|
|
|
+ :loading="loading"
|
|
|
+ :pagination="pagination"
|
|
|
+ @change="handleTableChange"
|
|
|
+ >
|
|
|
+ <template #bodyCell="{ column, record }">
|
|
|
+ <template v-if="column.key === 'action'">
|
|
|
+ <a-space>
|
|
|
+ <a @click="handleEdit(record)">编辑</a>
|
|
|
+ <a-divider type="vertical" />
|
|
|
+ <a-popconfirm
|
|
|
+ title="确定要删除这个角色吗?"
|
|
|
+ @confirm="handleDelete(record)"
|
|
|
+ >
|
|
|
+ <a class="delete-link">删除</a>
|
|
|
+ </a-popconfirm>
|
|
|
+ <a-divider type="vertical" />
|
|
|
+ <a @click="handleAssignPermissions(record)">分配权限</a>
|
|
|
+
|
|
|
+
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+
|
|
|
+ <!-- 添加/编辑角色弹窗 -->
|
|
|
+ <a-modal
|
|
|
+ v-model:visible="modalVisible"
|
|
|
+ :title="modalTitle"
|
|
|
+ @ok="handleModalOk"
|
|
|
+ @cancel="handleModalCancel"
|
|
|
+ >
|
|
|
+ <a-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formState"
|
|
|
+ :rules="rules"
|
|
|
+ layout="vertical"
|
|
|
+ >
|
|
|
+ <a-form-item label="角色名称" name="name">
|
|
|
+ <a-input v-model:value="formState.name" placeholder="请输入角色名称" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="角色描述" name="description">
|
|
|
+ <a-textarea
|
|
|
+ v-model:value="formState.description"
|
|
|
+ placeholder="请输入角色描述"
|
|
|
+ :rows="4"
|
|
|
+ />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </a-modal>
|
|
|
+
|
|
|
+ <!-- 权限配置抽屉 -->
|
|
|
+ <a-drawer
|
|
|
+ v-model:visible="drawerVisible"
|
|
|
+ title="权限配置"
|
|
|
+ placement="right"
|
|
|
+ :width="500"
|
|
|
+ @close="handleDrawerClose"
|
|
|
+ >
|
|
|
+ <div class="permission-drawer-content">
|
|
|
+ <PermissionConfig ref="permissionConfigRef" />
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <div style="text-align: right">
|
|
|
+ <a-button style="margin-right: 8px" @click="handleDrawerClose">取消</a-button>
|
|
|
+ <a-button type="primary" @click="handlePermissionSave">确定</a-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </a-drawer>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, onMounted } from 'vue';
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
+import { ArrowLeftOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+import PermissionConfig from '@/components/PermissionConfig/index.vue';
|
|
|
+
|
|
|
+const router = useRouter();
|
|
|
+const loading = ref(false);
|
|
|
+const searchKeyword = ref('');
|
|
|
+const modalVisible = ref(false);
|
|
|
+const modalTitle = ref('添加角色');
|
|
|
+const formRef = ref();
|
|
|
+
|
|
|
+// 表格列定义
|
|
|
+const columns = [
|
|
|
+ {
|
|
|
+ title: '角色名称',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '描述',
|
|
|
+ dataIndex: 'description',
|
|
|
+ key: 'description',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '创建时间',
|
|
|
+ dataIndex: 'createTime',
|
|
|
+ key: 'createTime',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ width: 200,
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+// 表格数据
|
|
|
+const roleList = ref([]);
|
|
|
+
|
|
|
+// 分页配置
|
|
|
+const pagination = reactive({
|
|
|
+ current: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0,
|
|
|
+ showTotal: (total) => `共 ${total} 条`,
|
|
|
+});
|
|
|
+
|
|
|
+// 表单数据
|
|
|
+const formState = reactive({
|
|
|
+ name: '',
|
|
|
+ description: '',
|
|
|
+});
|
|
|
+
|
|
|
+// 表单验证规则
|
|
|
+const rules = {
|
|
|
+ name: [
|
|
|
+ { required: true, message: '请输入角色名称', trigger: 'blur' },
|
|
|
+ { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' },
|
|
|
+ ],
|
|
|
+ description: [
|
|
|
+ { max: 200, message: '描述最多 200 个字符', trigger: 'blur' },
|
|
|
+ ],
|
|
|
+};
|
|
|
+
|
|
|
+// 返回上一页
|
|
|
+const goBack = () => {
|
|
|
+ router.back();
|
|
|
+};
|
|
|
+
|
|
|
+// 获取角色列表
|
|
|
+const fetchRoleList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ // 这里添加获取角色列表的接口调用
|
|
|
+ // const response = await axios.get('/api/roles', {
|
|
|
+ // params: {
|
|
|
+ // page: pagination.current,
|
|
|
+ // pageSize: pagination.pageSize,
|
|
|
+ // keyword: searchKeyword.value,
|
|
|
+ // },
|
|
|
+ // });
|
|
|
+ // roleList.value = response.data.list;
|
|
|
+ // pagination.total = response.data.total;
|
|
|
+
|
|
|
+ // 模拟数据
|
|
|
+ roleList.value = [
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ name: '管理员',
|
|
|
+ description: '系统管理员',
|
|
|
+ createTime: '2024-01-20 12:00:00',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ name: '普通用户',
|
|
|
+ description: '普通用户角色',
|
|
|
+ createTime: '2024-01-20 12:00:00',
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ pagination.total = 2;
|
|
|
+ } catch (error) {
|
|
|
+ message.error('获取角色列表失败');
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 搜索
|
|
|
+const handleSearch = () => {
|
|
|
+ pagination.current = 1;
|
|
|
+ fetchRoleList();
|
|
|
+};
|
|
|
+
|
|
|
+// 表格变化处理
|
|
|
+const handleTableChange = (pag) => {
|
|
|
+ pagination.current = pag.current;
|
|
|
+ pagination.pageSize = pag.pageSize;
|
|
|
+ fetchRoleList();
|
|
|
+};
|
|
|
+
|
|
|
+// 显示添加弹窗
|
|
|
+const showAddModal = () => {
|
|
|
+ modalTitle.value = '添加角色';
|
|
|
+ formState.name = '';
|
|
|
+ formState.description = '';
|
|
|
+ modalVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 显示编辑弹窗
|
|
|
+const handleEdit = (record) => {
|
|
|
+ modalTitle.value = '编辑角色';
|
|
|
+ formState.name = record.name;
|
|
|
+ formState.description = record.description;
|
|
|
+ modalVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 删除角色
|
|
|
+const handleDelete = async (record) => {
|
|
|
+ try {
|
|
|
+ // 这里添加删除角色的接口调用
|
|
|
+ // await axios.delete(`/api/roles/${record.id}`);
|
|
|
+ message.success('删除成功');
|
|
|
+ fetchRoleList();
|
|
|
+ } catch (error) {
|
|
|
+ message.error('删除失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 弹窗确认
|
|
|
+const handleModalOk = () => {
|
|
|
+ formRef.value.validate().then(async () => {
|
|
|
+ try {
|
|
|
+ // 这里添加保存角色的接口调用
|
|
|
+ // if (modalTitle.value === '添加角色') {
|
|
|
+ // await axios.post('/api/roles', formState);
|
|
|
+ // } else {
|
|
|
+ // await axios.put(`/api/roles/${editingId}`, formState);
|
|
|
+ // }
|
|
|
+ message.success(`${modalTitle.value}成功`);
|
|
|
+ modalVisible.value = false;
|
|
|
+ fetchRoleList();
|
|
|
+ } catch (error) {
|
|
|
+ message.error(`${modalTitle.value}失败`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 弹窗取消
|
|
|
+const handleModalCancel = () => {
|
|
|
+ modalVisible.value = false;
|
|
|
+ formRef.value?.resetFields();
|
|
|
+};
|
|
|
+
|
|
|
+// 权限配置相关
|
|
|
+const drawerVisible = ref(false);
|
|
|
+const permissionConfigRef = ref(null);
|
|
|
+const currentRole = ref(null);
|
|
|
+
|
|
|
+// 显示权限配置抽屉
|
|
|
+const handleAssignPermissions = (record) => {
|
|
|
+ currentRole.value = record;
|
|
|
+ drawerVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 关闭抽屉
|
|
|
+const handleDrawerClose = () => {
|
|
|
+ drawerVisible.value = false;
|
|
|
+ currentRole.value = null;
|
|
|
+};
|
|
|
+
|
|
|
+// 保存权限配置
|
|
|
+const handlePermissionSave = async () => {
|
|
|
+ try {
|
|
|
+ // 这里可以从 PermissionConfig 组件中获取选中的权限
|
|
|
+ // const permissions = permissionConfigRef.value.getSelectedPermissions();
|
|
|
+ // 调用保存接口
|
|
|
+ // await saveRolePermissions(currentRole.value.id, permissions);
|
|
|
+ message.success('权限配置保存成功');
|
|
|
+ drawerVisible.value = false;
|
|
|
+ } catch (error) {
|
|
|
+ message.error('权限配置保存失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 组件挂载时获取数据
|
|
|
+onMounted(() => {
|
|
|
+ fetchRoleList();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.role-management {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16px;
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-bar h2 {
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.role-content {
|
|
|
+ background: #fff;
|
|
|
+ padding: 24px;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.operation-bar {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.delete-link {
|
|
|
+ color: #ff4d4f;
|
|
|
+}
|
|
|
+
|
|
|
+.delete-link:hover {
|
|
|
+ color: #ff7875;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+.permission-drawer-content {
|
|
|
+ height: calc(100% - 55px);
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.ant-drawer-body) {
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+</style>
|