fix: correct menu activation status display

This commit is contained in:
duanshuwen
2026-08-27 10:26:12 +08:00
parent 1efd0d1857
commit 041d65566e
3 changed files with 41 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { buildSystemTree, dataScopeLabel, filterSystemTree } from "@/lib/system-resource";
import { buildSystemTree, dataScopeLabel, filterSystemTree, hydrateMenuTree } from "@/lib/system-resource";
import type { SystemMenuItem, SystemMenuTreeItem } from "@/types";
describe("system resource tree helpers", () => {
const items = [
@@ -21,6 +22,28 @@ describe("system resource tree helpers", () => {
]);
});
it("hydrates menu tree nodes with status fields from the flat response", () => {
const flatItems = [{
id: "dashboard",
name: "仪表盘",
type: "page",
parentId: null,
sortOrder: 10,
isVisible: true,
isActive: true,
}] as SystemMenuItem[];
const tree = [{
id: "dashboard",
name: "仪表盘",
type: "page",
parentId: null,
sortOrder: 10,
children: [],
}] as unknown as SystemMenuTreeItem[];
expect(hydrateMenuTree(tree, flatItems)[0]).toMatchObject({ isVisible: true, isActive: true });
});
it("uses RuoYi-compatible Chinese labels for data scope", () => {
expect(dataScopeLabel("all")).toBe("全部数据");
expect(dataScopeLabel("dept_and_children")).toBe("本部门及以下");

View File

@@ -1,6 +1,6 @@
import { ref, watch, type Ref } from "vue";
import { getSystemResource } from "@/api/client";
import type { SystemRoleItem } from "@/types";
import type { SystemMenuItem, SystemMenuTreeItem, SystemRoleItem } from "@/types";
export type SystemResourceResponse = { items: unknown[] };
export type SystemResourceFetcher = (resource: string) => Promise<SystemResourceResponse>;
@@ -25,6 +25,18 @@ export function buildSystemTree<T extends TreeSource>(items: T[]): Array<SystemT
return roots;
}
export function hydrateMenuTree(tree: SystemMenuTreeItem[], items: readonly SystemMenuItem[]): SystemMenuTreeItem[] {
const itemMap = new Map(items.map((item) => [item.id, item]));
const hydrate = (nodes: SystemMenuTreeItem[]): SystemMenuTreeItem[] => nodes.map((node) => {
const item = itemMap.get(node.id);
return {
...(item ? { ...item, ...node } : node),
children: hydrate(node.children ?? []),
};
});
return hydrate(tree);
}
export function filterSystemTree<T extends TreeSource>(nodes: Array<SystemTreeNode<T>>, keyword: string): Array<SystemTreeNode<T>> {
const normalized = keyword.trim().toLowerCase();
if (!normalized) return nodes;

View File

@@ -23,7 +23,7 @@ import {
import LayoutIcon from "@/components/layout/LayoutIcon.vue";
import SystemResourceEditor, { type SystemEditorSavePayload, type SystemResourceName } from "@/components/system/SystemResourceEditor.vue";
import { getMenuIconName } from "@/lib/menu-display";
import { buildSystemTree, dataScopeLabel, filterSystemTree } from "@/lib/system-resource";
import { buildSystemTree, dataScopeLabel, filterSystemTree, hydrateMenuTree } from "@/lib/system-resource";
import type {
SystemDeptCreate,
SystemDeptItem,
@@ -144,7 +144,8 @@ async function loadResource() {
if (resource.value === "menus") {
const result = await getSystemMenus();
menuItems.value = result.items;
menuTree.value = result.tree?.length ? result.tree : buildMenuTree(result.items);
const responseTree = result.tree?.length ? result.tree : buildMenuTree(result.items);
menuTree.value = hydrateMenuTree(responseTree, result.items);
items.value = result.items;
}
if (resource.value === "depts") {
@@ -412,7 +413,7 @@ onMounted(loadResource);
<el-table-column prop="path" label="路由路径" min-width="150" show-overflow-tooltip />
<el-table-column prop="permission" label="权限标识" min-width="170" show-overflow-tooltip />
<el-table-column prop="component" label="组件路径" min-width="150" show-overflow-tooltip />
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag :type="row.isActive && row.isVisible ? 'success' : 'info'" effect="plain">{{ row.isActive && row.isVisible ? '正常' : '停用' }}</el-tag></template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag :type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? '启用' : '停用' }}</el-tag></template></el-table-column>
<el-table-column label="操作" width="230" fixed="right"><template #default="{ row }"><el-button v-permission="updatePermission" link type="primary" @click="openEdit(row)">修改</el-button><el-button v-if="row.type !== 'button'" v-permission="createPermission" link type="primary" @click="openCreate(row.id)">新增</el-button><el-button v-permission="deletePermission" link type="danger" :loading="deletingId === row.id" @click="removeItem(row)">删除</el-button></template></el-table-column>
</el-table>