fix: correct menu activation status display
This commit is contained in:
@@ -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("本部门及以下");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user