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

fix: 修复菜单排序后侧边栏不刷新 + 客户菜单重复问题

1. 侧边栏刷新:排序成功后通过 emitter 事件通知三个布局组件
   (NavVertical/NavMix/NavHorizontal),强制 el-menu 重渲染
2. 客户菜单重复:移除 customer.ts 静态路由模块,改为后端路由
   动态加载组件(seed_menu.sql 中设置 component 字段)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 1 неделя назад
Родитель
Сommit
b364d5a075

+ 1 - 1
docs/database/seed_menu.sql

@@ -75,7 +75,7 @@ INSERT INTO t_menu (id, parent_id, menu_type, title, name, path, component, `ran
 (600, 0, 0, '客户管理', 'Customer', '/customer', '', 6, 'ri:user-heart-line', 1, 0, '/customer/list', 1);
 
 INSERT INTO t_menu (id, parent_id, menu_type, title, name, path, component, `rank`, show_link, show_parent) VALUES
-(601, 600, 0, '客户列表', 'CustomerList', '/customer/list', '', 1, 1, 0);
+(601, 600, 0, '客户列表', 'CustomerList', '/customer/list', 'customer/index', 1, 1, 0);
 
 -- =====================================================
 -- 7. 分销管理 (Distribution) - rank 6

+ 4 - 0
docs/database/update_customer_component.sql

@@ -0,0 +1,4 @@
+-- 为已有数据库的客户列表菜单设置 component 路径
+-- 移除 customer.ts 静态路由后,后端路由需要 component 字段来加载页面组件
+
+UPDATE t_menu SET component = 'customer/index' WHERE id = 601 AND (component IS NULL OR component = '');

+ 11 - 1
haha-admin-web/src/layout/components/lay-sidebar/NavHorizontal.vue

@@ -4,7 +4,7 @@ import { useNav } from "@/layout/hooks/useNav";
 import LaySearch from "../lay-search/index.vue";
 import LayNotice from "../lay-notice/index.vue";
 import { responsiveStorageNameSpace } from "@/config";
-import { ref, nextTick, computed, onMounted } from "vue";
+import { ref, nextTick, computed, onMounted, onBeforeUnmount } from "vue";
 import { storageLocal, isAllEmpty } from "@pureadmin/utils";
 import { useTranslationLang } from "../../hooks/useTranslationLang";
 import { usePermissionStoreHook } from "@/store/modules/permission";
@@ -17,6 +17,7 @@ import Setting from "~icons/ri/settings-3-line";
 import Check from "~icons/ep/check";
 
 const menuRef = ref();
+const menuKey = ref(0);
 const showLogo = ref(
   storageLocal().getItem<StorageConfigs>(
     `${responsiveStorageNameSpace()}configure`
@@ -50,6 +51,14 @@ onMounted(() => {
   emitter.on("logoChange", key => {
     showLogo.value = key;
   });
+  emitter.on("menuRefresh", () => {
+    menuKey.value++;
+  });
+});
+
+onBeforeUnmount(() => {
+  emitter.off("logoChange");
+  emitter.off("menuRefresh");
 });
 </script>
 
@@ -64,6 +73,7 @@ onMounted(() => {
     </div>
     <el-menu
       ref="menuRef"
+      :key="menuKey"
       mode="horizontal"
       popper-class="pure-scrollbar"
       class="horizontal-header-menu"

+ 11 - 1
haha-admin-web/src/layout/components/lay-sidebar/NavMix.vue

@@ -4,7 +4,8 @@ import { useNav } from "@/layout/hooks/useNav";
 import { transformI18n } from "@/plugins/i18n";
 import LaySearch from "../lay-search/index.vue";
 import LayNotice from "../lay-notice/index.vue";
-import { ref, toRaw, watch, onMounted, nextTick } from "vue";
+import { ref, toRaw, watch, onMounted, onBeforeUnmount, nextTick } from "vue";
+import { emitter } from "@/utils/mitt";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 import { getParentPaths, findRouteByPath } from "@/router/utils";
 import { useTranslationLang } from "../../hooks/useTranslationLang";
@@ -19,6 +20,7 @@ import Check from "~icons/ep/check";
 
 const menuRef = ref();
 const defaultActive = ref(null);
+const menuKey = ref(0);
 
 const { t, route, locale, translationCh, translationEn } =
   useTranslationLang(menuRef);
@@ -46,12 +48,19 @@ function getDefaultActive(routePath) {
 
 onMounted(() => {
   getDefaultActive(route.path);
+  emitter.on("menuRefresh", () => {
+    menuKey.value++;
+  });
 });
 
 nextTick(() => {
   menuRef.value?.handleResize();
 });
 
+onBeforeUnmount(() => {
+  emitter.off("menuRefresh");
+});
+
 watch(
   () => [route.path, usePermissionStoreHook().wholeMenus],
   () => {
@@ -68,6 +77,7 @@ watch(
   >
     <el-menu
       ref="menuRef"
+      :key="menuKey"
       router
       mode="horizontal"
       popper-class="pure-scrollbar"

+ 6 - 1
haha-admin-web/src/layout/components/lay-sidebar/NavVertical.vue

@@ -14,6 +14,7 @@ import LaySidebarCenterCollapse from "../lay-sidebar/components/SidebarCenterCol
 
 const route = useRoute();
 const isShow = ref(false);
+const menuKey = ref(0);
 const showLogo = ref(
   storageLocal().getItem<StorageConfigs>(
     `${responsiveStorageNameSpace()}configure`
@@ -78,11 +79,14 @@ onMounted(() => {
   emitter.on("logoChange", key => {
     showLogo.value = key;
   });
+  emitter.on("menuRefresh", () => {
+    menuKey.value++;
+  });
 });
 
 onBeforeUnmount(() => {
-  // 解绑`logoChange`公共事件,防止多次触发
   emitter.off("logoChange");
+  emitter.off("menuRefresh");
 });
 </script>
 
@@ -99,6 +103,7 @@ onBeforeUnmount(() => {
       :class="[device === 'mobile' ? 'mobile' : 'pc']"
     >
       <el-menu
+        :key="menuKey"
         unique-opened
         mode="vertical"
         popper-class="pure-scrollbar"

+ 0 - 21
haha-admin-web/src/router/modules/customer.ts

@@ -1,21 +0,0 @@
-export default {
-  path: "/customer",
-  redirect: "/customer/list",
-  meta: {
-    icon: "ri:user-heart-line",
-    title: "客户管理",
-    rank: 6,
-    roles: ["admin", "operator"]
-  },
-  children: [
-    {
-      path: "/customer/list",
-      name: "CustomerList",
-      component: () => import("@/views/customer/index.vue"),
-      meta: {
-        icon: "ri:group-line",
-        title: "客户列表"
-      }
-    }
-  ]
-} satisfies RouteConfigsTable;

+ 1 - 0
haha-admin-web/src/utils/mitt.ts

@@ -9,6 +9,7 @@ type Events = {
   tagViewsChange: string;
   changLayoutRoute: string;
   tagViewsTagsStyle: string;
+  menuRefresh: void;
   imageInfo: {
     img: HTMLImageElement;
     height: number;

+ 2 - 0
haha-admin-web/src/views/system/menu/utils/hook.tsx

@@ -9,6 +9,7 @@ import type { FormItemProps } from "../utils/types";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils";
 import { initRouter } from "@/router/utils";
+import { emitter } from "@/utils/mitt";
 import Sortable from "sortablejs";
 
 export function useMenu() {
@@ -307,6 +308,7 @@ export function useMenu() {
           // 刷新侧边栏路由顺序
           try {
             await initRouter();
+            emitter.emit("menuRefresh");
           } catch (e) {
             console.error("侧边栏路由刷新失败:", e);
           }