menuExtras.ts
4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import type { MenuNode } from "@/api/admin";
function normPath(p: string | undefined): string {
if (!p) return "";
const s = p.trim();
return s.startsWith("/") ? s : `/${s}`.replace(/^\/+/, "/");
}
function hasMpUserMenu(nodes: MenuNode[]): boolean {
for (const n of nodes) {
if (normPath(n.path) === "/system/mp-user") return true;
if (n.children?.length && hasMpUserMenu(n.children)) return true;
}
return false;
}
function hasDownloadAssetsMenu(nodes: MenuNode[]): boolean {
for (const n of nodes) {
if (normPath(n.path) === "/content/download-assets") return true;
if (n.children?.length && hasDownloadAssetsMenu(n.children)) return true;
}
return false;
}
/** 去掉「内容管理」目录,子项(作品审核、轮播等)提升为侧栏一级 */
export function flattenContentMenus(list: MenuNode[]): MenuNode[] {
if (!list.length) return list;
const out: MenuNode[] = [];
for (const n of list) {
const p = normPath(n.path);
const isContentDir =
n.type === 1 && (p === "/content" || n.name === "内容管理");
if (isContentDir && n.children?.length) {
const parentSort = n.sort ?? 10;
const sorted = [...n.children].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
sorted.forEach((ch, idx) => {
out.push({
...ch,
parent_id: 0,
sort: parentSort + idx + 1,
});
});
continue;
}
out.push(n);
}
out.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
return out;
}
/** 将「用户管理」从系统管理下提升为侧栏一级(排在内容菜单后、系统管理前) */
export function flattenMpUserMenu(list: MenuNode[]): MenuNode[] {
if (!list.length) return list;
const hoisted: MenuNode[] = [];
const out: MenuNode[] = [];
const hoistSort = 15;
for (const n of list) {
const p = normPath(n.path);
const isSystemDir = n.type === 1 && (p === "/system" || n.name === "系统管理");
if (isSystemDir && n.children?.length) {
const rest: MenuNode[] = [];
for (const ch of n.children) {
if (normPath(ch.path) === "/system/mp-user") {
hoisted.push({
...ch,
parent_id: 0,
sort: hoistSort,
});
} else {
rest.push(ch);
}
}
out.push({
...n,
children: rest.length ? rest : undefined,
});
continue;
}
out.push(n);
}
const merged = [...out, ...hoisted];
merged.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
return merged;
}
/** 接口未返回用户管理菜单时,在根级补一项(一级侧栏) */
export function withMpUserMenu(list: MenuNode[]): MenuNode[] {
if (!list.length || hasMpUserMenu(list)) {
return list;
}
const item: MenuNode = {
id: 999001,
parent_id: 0,
name: "用户管理",
type: 2,
path: "/system/mp-user",
component: "",
perms: "",
icon: "avatar",
sort: 15,
};
return [...list, item].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
}
/** 接口未返回下载素材菜单时,在根级补一项(一级侧栏) */
export function withDownloadAssetsMenu(list: MenuNode[]): MenuNode[] {
if (!list.length || hasDownloadAssetsMenu(list)) {
return list;
}
const item: MenuNode = {
id: 999002,
parent_id: 0,
name: "下载素材",
type: 2,
path: "/content/download-assets",
component: "",
perms: "",
icon: "picture",
sort: 11,
};
return [...list, item].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
}
/**
* 保证轮播图、作品审核排在「系统管理」之上(避免库中 sort 相同时按 id 把系统顶到前面)
*/
export function ensureContentBeforeSystem(list: MenuNode[]): MenuNode[] {
if (!list.length) return list;
const contentOrder: Record<string, number> = {
"/content/download-assets": 10,
"/content/banner": 11,
"/content/work": 12,
};
const patched = list.map((n) => {
const p = normPath(n.path);
if (n.type === 1 && (p === "/system" || n.name === "系统管理")) {
const s = n.sort ?? 0;
return { ...n, sort: s < 20 ? 20 : s };
}
if (contentOrder[p] !== undefined) {
return { ...n, sort: contentOrder[p] };
}
return n;
});
patched.sort((a, b) => {
const sa = a.sort ?? 0;
const sb = b.sort ?? 0;
if (sa !== sb) return sa - sb;
return (a.id ?? 0) - (b.id ?? 0);
});
return patched;
}
/** 接口未配置「工作台」菜单时,前置仪表盘入口 */
export function withDashboardMenu(list: MenuNode[]): MenuNode[] {
const dash: MenuNode = {
id: 0,
parent_id: 0,
name: "工作台",
type: 2,
path: "/dashboard",
component: "",
perms: "",
icon: "odometer",
sort: -999,
};
const has = list.some(
(m) => m.path === "/dashboard" || m.children?.some((c) => c.path === "/dashboard")
);
if (has) {
return list;
}
return [dash, ...list];
}