yangg 10 hours ago
parent
commit
e380427ca2
4 changed files with 424 additions and 22 deletions
  1. 22 20
      src/components/PermissionConfig/index.vue
  2. 6 0
      src/router/menu.js
  3. 37 2
      src/views/report.vue
  4. 359 0
      src/views/role.vue

+ 22 - 20
src/components/PermissionConfig/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="permission-config">
-    <div class="config-header" @click="togglePanel">
+    <!-- <div class="config-header" @click="togglePanel">
       <img src="../../assets/lock.png" alt="permission" class="config-icon" />
       <span>权限配置</span>
       <img
@@ -8,17 +8,21 @@
         alt="toggle"
         class="toggle-icon"
       />
-    </div>
-    
-    <div v-show="isPanelOpen" class="config-panel">
+    </div> -->
+     <!-- v-show="isPanelOpen" :checked="getParentChecked(group)"   -->
+    <div class="config-panel">
       <div class="permission-list">
         <div class="permission-group" v-for="group in permissionGroups" :key="group.label">
           <div class="group-header"> 
             <a-checkbox :value="group.value"
-            :checked="getParentChecked(group)" 
+           
             @change="(e) => handleParentChange(group, e)">
                   {{ group.label }}
                 </a-checkbox>
+                 <a-button type="link" style="padding: 0;" size="small" @click="showButtonConfig(group)">
+
+                  <img src="../../assets/svg/setting.png" style="margin-top: 2px;" alt="">
+                </a-button>
             </div>
           <div class="checkbox-list">
             <a-checkbox-group v-model:value="selectedPermissions[group.key]">
@@ -55,11 +59,11 @@
         </div>
       </div>
     </a-modal>
-      <div class="action-buttons">
+      <!-- <div class="action-buttons">
         <a-button type="primary" :loading="saving" @click="saveConfig">
           保存配置
         </a-button>
-      </div>
+      </div> -->
     </div>
   </div>
 </template>
@@ -119,10 +123,8 @@ const getParentChecked = (group) => {
   if (!selectedPermissions[group.key] || !group.items || group.items.length === 0) {
     return false;
   }
-  // 如果所有子项都被选中,则父级也选中
-  return group.items.every(item => 
-    selectedPermissions[group.key].includes(item.value)
-  );
+ // 检查父级是否被选中
+  return selectedPermissions[group.key].includes(group.value);
 };
 // 处理父级选中状态变化
 const handleParentChange = (parent, e) => {
@@ -134,7 +136,7 @@ const handleParentChange = (parent, e) => {
   
   // 如果父级被选中,将所有子项添加到选中数组
   if (checked) {
-    selectedPermissions[parent.key] = parent.items.map(item => item.value);
+    selectedPermissions[parent.key] = [...parent.items.map(item => item.value), parent.value];
   } else {
     // 如果父级取消选中,清空该组的选中数组
     selectedPermissions[parent.key] = [];
@@ -180,9 +182,9 @@ const initConfig = () => {
 // 获取权限列表
 const fetchPermissionGroups = async () => {
   try {
-    const response = await axios.get(`https://backend.qicai321.com/api/system/role_menu_button_permission/get_role_menu/?roleId=5`,{
+    const response = await axios.get(`http://58.246.234.210:8085/api/system/role_menu_button_permission/get_role_menu/?roleId=9&merchant=1`,{
       headers: {
-        'authorization': `JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzg2Njg0Nzk0LCJpYXQiOjE3NTUxNDg3OTQsImp0aSI6IjdlYTI0Yzg2N2IzNTQ5NDA5Y2RlZGM1NGI5MGMxYWQzIiwidXNlcl9pZCI6MX0._yM1AMRyxVyf2J2-Kz9PlAErkXhEV5bfz9hBVkIg6OQ`
+        'authorization': `JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzU1MzE2MTY0LCJpYXQiOjE3NTUyMjk3NjQsImp0aSI6IjkzZTI2MjA5ZmQxYjRmMmQ4MGY0YjY3MzkzN2E4MDVmIiwidXNlcl9pZCI6OX0.mlQ6SUOCHIkpMJjUCToUDnsChPmg8wbSBBS0VB6GJ-E`
       }
     });
     console.log(response);
@@ -260,7 +262,7 @@ onMounted(async () => {
 
 <style scoped>
 .permission-config {
-  border-top: 1px solid rgba(0, 0, 0, 0.06);
+ 
   background: var(--secondary-bg);
   color: var(--primary-text);
 }
@@ -291,17 +293,17 @@ onMounted(async () => {
 
 .config-panel {
   padding: 12px 20px;
-  border-top: 1px solid rgba(0, 0, 0, 0.06);
+ 
 }
 
 .permission-list {
   margin-bottom: 16px;
-  height: 450px;
-    overflow: auto;
+  /* height: 100%;
+    overflow: auto; */
 }
 
 .permission-group {
-  margin-bottom: 16px;
+  /* margin-bottom: 16px; */
 }
 
 .permission-group:last-child {
@@ -358,7 +360,7 @@ margin-left: 14px;
   margin-bottom: 8px;
   display: flex;
   align-items: center;
-  justify-content: space-between;
+  /* justify-content: space-between; */
 }
 
 .button-config-list {

+ 6 - 0
src/router/menu.js

@@ -12,6 +12,12 @@ export const ROUTE = [
         title: '报表中心',
         component: () => import('@views/report.vue')
       },
+      {
+        path: '/role',
+        name: 'role',
+        title: '角色管理',
+        component: () => import('@views/role.vue')
+      }
     ]
   },
   {

+ 37 - 2
src/views/report.vue

@@ -95,9 +95,17 @@
         </div>
       </div>
 
-      <!-- 添加模型配置和语音配置的容器 -->
+      <!-- 添加模型配置和语音配置的容器 -->   <!-- <PermissionConfig/> -->
       <div class="config-container">
-        <PermissionConfig/>
+         <div class="config-header" @click="goToRoleManagement">
+            <img src="../assets/lock.png" alt="permission" class="config-icon" />
+            <span>角色管理</span>
+            
+          </div>
+        <!-- <div class="role-management-entry" @click="goToRoleManagement">
+          <img src="../assets/lock.png" alt="role" class="config-icon" />
+          <span>角色管理</span>
+        </div> -->
         <KnowledgeConfig />
         <ModelConfig />
         <VoiceConfig />
@@ -843,6 +851,9 @@ const messageList = ref(null);
 const store = useStore();
 const router = useRouter()
 
+const goToRoleManagement = () => {
+  router.push('/role');
+};
 // 会话数据
 const conversations = ref([
   {
@@ -4008,6 +4019,30 @@ const updateCollapsedState = () => {
   margin-top: auto;
   border-top: 1px solid rgba(0, 0, 0, 0.06);
 }
+.config-header {
+  padding: 12px 20px;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+}
+
+.config-header:hover {
+  background: rgba(0, 0, 0, 0.02);
+}
+
+.config-icon {
+  width: 16px;
+  height: 16px;
+}
+
+.toggle-icon {
+  width: 12px;
+  height: 12px;
+  margin-left: auto;
+}
+
 
 .web-search-toggle {
   display: flex;

+ 359 - 0
src/views/role.vue

@@ -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>