Просмотр исходного кода

优化用户信息存储逻辑,调整菜单项和权限下拉列表的生成方式,更新路由守卫实现,并重构组件代码以提升可读性和维护性。

张涛 1 год назад
Родитель
Сommit
81597328ce

+ 10 - 1
src/base/store/use-current-user.js

@@ -68,9 +68,18 @@ export const useCurrentUserStore = defineStore('current_user', {
         data: { routers }
       } = await QueyrRoutesList();
       if (code === 200) {
-        localST_RoutesList.setItem(JSON.stringify(routers));
+        // 将 setItem 包装在一个 Promise 中并等待完成
+        await new Promise((resolve, reject) => {
+          try {
+            localST_RoutesList.setItem(JSON.stringify(routers));
+            resolve();
+          } catch (error) {
+            reject(error);
+          }
+        });
       }
     },
+
     // 获取并且存储用户信息
     async getUserInfo() {
       const {

+ 10 - 9
src/modules/knowledge/MessageBody.vue

@@ -1,12 +1,7 @@
 <template>
   <div class="body-container" ref="body_container">
-    <CardItem
-      v-for="item in moke_data"
-      :key="item.id"
-      :name="item.name"
-      :img_src="item.img_src"
-      @click="handleToDetail(item)"
-    >
+    <CardItem v-for="item in moke_data" :key="item.id" :name="item.name" :img_src="item.img_src"
+      @click="handleToDetail(item)">
       <template #bottom>
         <div class="bottom">
           <div>{{ item.count }}{{ $t('management.document') }}</div>
@@ -15,7 +10,7 @@
         </div>
       </template>
       <template #settings>
-        <a-dropdown trigger="hover" @select="handleSelect($event, item)">
+        <a-dropdown v-hasPermi="'system:knowledge:delete'" trigger="hover" @select="handleSelect($event, item)">
           <icon-more :style="{ fontSize: '20px' }" />
           <template #content>
             <!-- <a-doption :value="{ value: 'edit' }">{{ $t('management.edit') }}</a-doption> -->
@@ -93,7 +88,7 @@ const toRemove = (item) => {
         deleteOwnKnow(item.id);
       }
     },
-    onCancel: () => {}
+    onCancel: () => { }
   });
 };
 const deleteOwnKnow = async (id) => {
@@ -173,28 +168,34 @@ onBeforeUnmount(() => {
   width: 100%;
   height: calc(100% - 80px);
 }
+
 .body-container::-webkit-scrollbar {
   display: none;
 }
+
 .bottom {
   display: flex;
   gap: 10px;
 }
+
 .loading-tips {
   grid-column: 1/-1;
   grid-row-start: auto;
   text-align: center;
 }
+
 .arco-spin-loading {
   /* width:  */
   height: calc(100% - 80px);
 }
+
 .arco-spin {
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
 }
+
 .arco-empty {
   position: absolute;
   top: 50%;

+ 3 - 8
src/modules/knowledge/TopSetting.vue

@@ -1,17 +1,12 @@
 <template>
   <a-space size="large">
-    <a-input
-      v-model="searchText"
-      :placeholder="$t('management.search')"
-      style="width: 300px"
-      allow-clear
-      @input="handleSearch"
-    >
+    <a-input v-model="searchText" :placeholder="$t('management.search')" style="width: 300px" allow-clear
+      @input="handleSearch">
       <template #prefix>
         <icon-search />
       </template>
     </a-input>
-    <a-button type="primary" size="large" @click="handleCreate">
+    <a-button v-hasPermi="'system:knowledge:add'" type="primary" size="large" @click="handleCreate">
       <template #icon>
         <icon-plus />
       </template>

+ 3 - 2
src/modules/login/FormItem.vue

@@ -76,11 +76,12 @@ const handleSubmit = (data) => {
     // 登录
     userStore
       .toLogin({ username: data.username, password: data.password })
-      .then((res) => {
+      .then(async (res) => {
         $message.success(res);
 
         // 登录成功后,获取路由列表
-        userStore.getRoutesList()
+        // 阻塞路由的获取,等待用户信息获取成功
+        await userStore.getRoutesList()
         // 登录成功后,获取用户权限
         userStore.getUserInfo()
 

+ 0 - 1
src/modules/permission/group/PermissionConfigModal.vue

@@ -88,7 +88,6 @@ const emit = defineEmits(['getActiveTab', 'close', 'ok']);
 const tabs = [
   { key: "1", icon: "icon-storage", title: "知识库" },
   { key: "2", icon: "icon-robot", title: "智能体" },
-  { key: "3", icon: "icon-relation", title: "模型" }
 ]
 const selected_tab_key = ref(tabs[0].key);
 

+ 0 - 7
src/modules/permission/group/index.vue

@@ -49,7 +49,6 @@ import MembertConfigModal from './MembertConfigModal.vue';
 import PermissionConfigModal from './PermissionConfigModal.vue';
 import { hasPermission } from '../../../utils/permission';
 import { QueryGroupList, QueryGroupUsers, SaveGroupUsers, ConfigGroupResource, GroupStatusSwitch, DeleteGroup, CreateGroup, UpdateGroup } from '../../../apis/permission/gruop';
-// TODO接口 模型tabs接口还没有
 import { QueryAllKnowledgeList, QueryAllDialogList } from '../../../apis/permission/common';
 
 const keywords = ref('');
@@ -288,12 +287,6 @@ const getConfigList = async (tabsKey) => {
       agents_list.value = rows;
     }
   }
-  if (tabsKey === '3') {
-    // const { code, data: { rows } } = await QueryAllDialogList();
-    // if (code === 200) {
-    //   agents_list.value = rows;
-    // }
-  }
 }
 
 onMounted(() => {

+ 1 - 0
src/router/guard.js

@@ -3,6 +3,7 @@ import { localST_RoutesList, kuky_Authorization } from '../base/storage';
 
 // /** 免登录白名单 */
 const whiteList = ['/login', '/reg'];
+// FIXME: 权限验证,白屏
 // router.beforeEach((to, from, next) => {
 //   if (kuky_Authorization.get()) {
 //     if (to.path === '/login') {

+ 12 - 0
src/router/index.js

@@ -1,5 +1,11 @@
 import { createRouter, createWebHashHistory } from 'vue-router';
 import { systemRoutes } from './route';
+import { localST_RoutesList } from '../base/storage';
+
+// import { formatRoutes } from '../utils/permission';
+
+// const routesList = JSON.parse(localST_RoutesList.getItem());
+// const accessRoutes = formatRoutes(routesList);
 
 const router = createRouter({
   history: createWebHashHistory(),
@@ -7,4 +13,10 @@ const router = createRouter({
   scrollBehavior: () => ({ left: 0, top: 0 })
 });
 
+// TODO 动态路由
+// accessRoutes.forEach((route) => {
+//   console.log('route', route);
+//   router.addRoute(route);
+// });
+
 export default router;

+ 36 - 0
src/utils/permission.js

@@ -6,3 +6,39 @@ export const hasPermission = (str) => {
   if (permissions.includes('*:*:*')) return true;
   return permissions.includes(str);
 };
+
+export const formatRoutes = (data) => {
+  const routes = [];
+
+  function convertRoute(item) {
+    if (item.component !== '-') {
+      const route = {
+        path: item.path || '',
+        component: `() => import('../views/${item.component}.vue')`
+      };
+
+      if (item.children && item.children.length > 0) {
+        route.children = item.children.map((child) => convertRoute(child));
+      }
+
+      return route;
+    }
+  }
+
+  function addRoutes(item) {
+    const formattedRoute = convertRoute(item);
+    routes.push(formattedRoute);
+  }
+
+  data.forEach((item) => {
+    addRoutes(item);
+  });
+
+  return routes;
+};
+
+const menuData = [];
+
+const formattedRoutes = formatRoutes(menuData);
+
+console.log(JSON.stringify(formattedRoutes, null, 2));

+ 46 - 23
src/views/common/Header.vue

@@ -8,28 +8,12 @@
 
     <div class="header-center">
       <a-space>
-        <NavItem
-          :label="$t('header.conversation')"
-          to="/chat/history"
-          v-hasPermi="'system:conversation:talk'"
-          icon_name="header-huihua"
-        />
-        <NavItem
-          :label="$t('header.knowledge')"
-          to="/knowledge"
-          v-hasPermi="'system:knowledge'"
-          icon_name="header-zhishiku"
-        />
-        <NavItem :label="$t('header.model')" to="/model" v-hasPermi="'system:model'" icon_name="header-moxingguanli" />
-        <!-- <NavItem :label="$t('header.agent')" to="/agent" icon_name="header-agent" /> -->
-        <NavItem :label="'小数'" to="/xiaoshu" v-hasPermi="'system:xiaoshu'" icon_name="header-agent" />
-        <NavItem
-          :label="$t('header.intelligent')"
-          to="/intelligent"
-          v-hasPermi="'system:conversation:talk'"
-          icon_name="header-zhinengti"
-        />
-        <PermissionDropdownV1 :label="$t('header.permission')" v-hasPermi="'system:permission'" />
+        <div v-for="item in nav_list" :key="item.to">
+          <NavItem :label="item.label" :to="item.to" :icon_name="item.icon_name" />
+        </div>
+
+        <PermissionDropdownV1 :dropdown_list="dropdown_list" :label="$t('header.permission')"
+          v-hasPermi="'system:permission'" />
 
         <NavItem label="临时: RagFlow Chat" to="/ragchat" icon_name="header-zhinengti" />
       </a-space>
@@ -54,11 +38,13 @@
 </template>
 
 <script setup>
+import { ref, onMounted } from 'vue';
 import { setI18nLanguage } from '../../i18n';
 import { getCurrentTheme, setThemeDark, setThemeLight } from '../../base/theme';
 import { requestScreenFull, toggleScreenFull } from '../../3rd-libs/screenfull';
 
 import { useCurrentUserStore } from '../../base/store/use-current-user';
+import { localST_RoutesList } from '../../base/storage';
 
 import NavItem from './NavItem.vue';
 
@@ -72,7 +58,8 @@ import BtnSettings from './header-btns/BtnSettings.vue';
 import BtnCurrentUser from './header-btns/BtnCurrentUser.vue';
 
 const currentUser = useCurrentUserStore();
-
+const nav_list = ref([])
+const dropdown_list = ref([])
 /**
  * 请求网页全屏
  */
@@ -84,6 +71,42 @@ const handleNameChange = () => {
   // const nm = Math.random() * 99989 + '';
   // currentUser.updateName(nm);
 };
+const formatMenuItems = (list) => {
+
+  return list.map(item => {
+    // 过滤掉meta.title为'权限管理'
+    if (item.meta.title === '权限管理') {
+      return null;
+    }
+
+    if (item.resourceType.id && item.resourceType.id == '0') {
+      // 只处理菜单项
+      return {
+        label: item.meta.title,
+        to: item.path,
+        icon_name: item.meta.icon || 'header-zhinengti' // 假设icon_name是根据name字段来命名的
+      };
+    }
+
+  }).filter(item => item !== null); // 过滤掉null值
+}
+const formatPermissionItems = (permissionList) => {
+  return permissionList.children.map(item => {
+    return {
+      label: item.meta.title,
+      path: item.path,
+    };
+  }).filter(item => item !== null); // 过滤掉null值
+}
+onMounted(() => {
+  // 延迟渲染菜单,防止菜单渲染时还没获取到权限信息
+  const routesList = JSON.parse(localST_RoutesList.getItem());
+
+  nav_list.value = formatMenuItems(routesList)
+  const permissionList = routesList.find(item => item.meta.title === '权限管理');
+  dropdown_list.value = permissionList ? formatPermissionItems(permissionList) : []
+
+});
 </script>
 
 <style lang="css" scoped>

+ 9 - 30
src/views/common/PermissionDropdownV1.vue

@@ -8,35 +8,13 @@
       </div>
 
       <template #content>
-        <a-doption v-hasPermi="'system:role'" class="dmx-header-permission-drop-item">
-          <div class="dropdown-menu-item" @click="handleChatTypeConfirm('/permission/role')">
-            {{ $t('permission.role') }}
-          </div>
-        </a-doption>
-
-        <a-doption v-hasPermi="'system:user'" class="dmx-header-permission-drop-item">
-          <div class="dropdown-menu-item" @click="handleChatTypeConfirm('/permission/account')">
-            {{ $t('permission.account') }}
-          </div>
-        </a-doption>
-
-        <a-doption v-hasPermi="'system:dept'" class="dmx-header-permission-drop-item">
-          <div class="dropdown-menu-item" @click="handleChatTypeConfirm('/permission/org')">
-            {{ $t('permission.organization') }}
-          </div>
-        </a-doption>
-
-        <a-doption v-hasPermi="'system:resource'" class="dmx-header-permission-drop-item">
-          <div class="dropdown-menu-item" @click="handleChatTypeConfirm('/permission/resource')">
-            {{ $t('permission.resource') }}
-          </div>
-        </a-doption>
-
-        <a-doption v-hasPermi="'system:group'" class="dmx-header-permission-drop-item">
-          <div class="dropdown-menu-item" @click="handleChatTypeConfirm('/permission/group')">
-            {{ $t('permission.group') }}
-          </div>
-        </a-doption>
+        <div>
+          <a-doption v-for="item in dropdown_list" :key="item.path" class="dmx-header-permission-drop-item">
+            <div class="dropdown-menu-item" @click="handleChatTypeConfirm(item.path)">
+              {{ item.label }}
+            </div>
+          </a-doption>
+        </div>
       </template>
     </a-dropdown>
   </a-space>
@@ -54,7 +32,8 @@ import { header_icon_quanxian } from './header-icon-map';
  */
 
 const props = defineProps({
-  label: String
+  label: String,
+  dropdown_list: Array
 });
 
 const route = useRoute();