hrp-ui-base 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components.cjs +10 -1
- package/dist/components.es.js +3577 -2398
- package/dist/index.cjs +1 -1
- package/dist/index.es.js +87 -80
- package/dist/style.css +1 -1
- package/package.json +4 -2
- package/src/components/layout/LayoutContainer.vue +503 -0
- package/src/components/layout/index.ts +8 -0
- package/src/components/layout/plugin.ts +32 -0
- package/src/components/layout/sideMenu.vue +2 -2
- package/src/components/layout/stores/index.ts +5 -0
- package/src/components/layout/stores/useLayoutConfigStore.ts +229 -0
- package/src/components/layout/stores/useLayoutMenuStore.ts +232 -0
- package/src/components/layout/stores/useLayoutNoticeStore.ts +77 -0
- package/src/components/layout/stores/useLayoutTabsStore.ts +367 -0
- package/src/components.ts +5 -3
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import { defineStore } from "pinia";
|
|
3
|
+
|
|
4
|
+
/** 标签页配置项 */
|
|
5
|
+
export interface TabsOptions {
|
|
6
|
+
/** 标签页标题 */
|
|
7
|
+
title: string;
|
|
8
|
+
/** 路由路径 */
|
|
9
|
+
path: string;
|
|
10
|
+
/** 路由名称 */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** 路由参数 */
|
|
13
|
+
query?: Record<string, any>;
|
|
14
|
+
/** 缓存码,'0'表示缓存 */
|
|
15
|
+
cachedCode?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 不显示在标签页的黑名单路径 */
|
|
19
|
+
const TABS_BLACK_LIST: string[] = ["/login", "/application-entry", "/redirect"];
|
|
20
|
+
|
|
21
|
+
/** 存储键名前缀 */
|
|
22
|
+
const STORAGE_PREFIX = "SYSTEM_TABS";
|
|
23
|
+
|
|
24
|
+
/** 从路由路径中解析系统ID(第一个/后面的内容) */
|
|
25
|
+
function getSystemIdFromPath(path: string): string {
|
|
26
|
+
if (!path || path === "/") return "default";
|
|
27
|
+
const cleanPath = path.startsWith("/") ? path.slice(1) : path;
|
|
28
|
+
const firstSegment = cleanPath.split("/")[0];
|
|
29
|
+
return firstSegment || "default";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** 标签页 Store */
|
|
33
|
+
export const useLayoutTabsStore = defineStore("layout-tabs", () => {
|
|
34
|
+
/** 当前系统ID */
|
|
35
|
+
const currentSystemId = ref<string>("");
|
|
36
|
+
/** 是否已从存储恢复数据 */
|
|
37
|
+
const isRestored = ref<boolean>(false);
|
|
38
|
+
/** 需要缓存的路由名称列表 */
|
|
39
|
+
const keepAliveRoutes = ref<string[]>([]);
|
|
40
|
+
/** 标签页列表 */
|
|
41
|
+
const tabsMenuList = ref<TabsOptions[]>([]);
|
|
42
|
+
/** 当前激活的标签页路径 */
|
|
43
|
+
const tabsMenuValue = ref<string>("");
|
|
44
|
+
|
|
45
|
+
/** 获取带系统前缀的存储键名 */
|
|
46
|
+
function getStorageKey(suffix: string): string {
|
|
47
|
+
const systemId = currentSystemId.value || "default";
|
|
48
|
+
return `${STORAGE_PREFIX}_${systemId}_${suffix}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getTabsKey(): string {
|
|
52
|
+
return getStorageKey("LIST");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getActiveTabKey(): string {
|
|
56
|
+
return getStorageKey("ACTIVE");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getKeepAliveKey(): string {
|
|
60
|
+
return getStorageKey("KEEP_ALIVE");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** 初始化系统ID(从当前路由解析) */
|
|
64
|
+
function initSystemId(systemId?: string) {
|
|
65
|
+
if (systemId) {
|
|
66
|
+
currentSystemId.value = systemId;
|
|
67
|
+
} else {
|
|
68
|
+
const currentPath =
|
|
69
|
+
window.location.hash.replace("#", "") || window.location.pathname;
|
|
70
|
+
currentSystemId.value = getSystemIdFromPath(currentPath);
|
|
71
|
+
}
|
|
72
|
+
sessionStorage.setItem("CURRENT_TABS_SYSTEM_ID", currentSystemId.value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** 重置所有标签页状态 */
|
|
76
|
+
function reset() {
|
|
77
|
+
keepAliveRoutes.value = [];
|
|
78
|
+
tabsMenuValue.value = "";
|
|
79
|
+
tabsMenuList.value = [];
|
|
80
|
+
sessionStorage.removeItem(getTabsKey());
|
|
81
|
+
sessionStorage.removeItem(getActiveTabKey());
|
|
82
|
+
sessionStorage.removeItem(getKeepAliveKey());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 添加标签页 */
|
|
86
|
+
function addTabs(tabItem: TabsOptions) {
|
|
87
|
+
if (!currentSystemId.value) {
|
|
88
|
+
initSystemId();
|
|
89
|
+
}
|
|
90
|
+
if (!isRestored.value) {
|
|
91
|
+
restoreTabsFromStorage();
|
|
92
|
+
}
|
|
93
|
+
if (
|
|
94
|
+
!tabItem.path ||
|
|
95
|
+
TABS_BLACK_LIST.some((path) => tabItem.path.startsWith(path))
|
|
96
|
+
) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const tabInfo: TabsOptions = {
|
|
101
|
+
title: tabItem.title || "未命名页面",
|
|
102
|
+
path: tabItem.path,
|
|
103
|
+
name: tabItem.name,
|
|
104
|
+
query: tabItem.query,
|
|
105
|
+
cachedCode: tabItem.cachedCode,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const existIndex = tabsMenuList.value.findIndex(
|
|
109
|
+
(item) => item.path === tabItem.path
|
|
110
|
+
);
|
|
111
|
+
if (existIndex === -1) {
|
|
112
|
+
tabsMenuList.value.push(tabInfo);
|
|
113
|
+
tabsChange();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setTabsMenuValue(tabItem.path);
|
|
117
|
+
sessionStorage.setItem(getActiveTabKey(), tabItem.path);
|
|
118
|
+
|
|
119
|
+
if (tabItem.name && tabItem.cachedCode === "0") {
|
|
120
|
+
setKeepAlive(tabItem.name);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** 移除标签页(需要传入 router 实例处理跳转) */
|
|
125
|
+
function removeTabs(tabPath: string, router?: any, nextTabPath?: string) {
|
|
126
|
+
const tabIndex = tabsMenuList.value.findIndex(
|
|
127
|
+
(item) => item.path === tabPath
|
|
128
|
+
);
|
|
129
|
+
if (tabIndex === -1) return;
|
|
130
|
+
|
|
131
|
+
if (tabsMenuValue.value === tabPath) {
|
|
132
|
+
let targetPath = nextTabPath;
|
|
133
|
+
let targetQuery: Record<string, any> | undefined;
|
|
134
|
+
|
|
135
|
+
if (!targetPath) {
|
|
136
|
+
const nextTab =
|
|
137
|
+
tabsMenuList.value[tabIndex + 1] || tabsMenuList.value[tabIndex - 1];
|
|
138
|
+
if (nextTab) {
|
|
139
|
+
targetPath = nextTab.path;
|
|
140
|
+
targetQuery = nextTab.query;
|
|
141
|
+
} else {
|
|
142
|
+
targetPath = "/application-entry";
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
const targetTab = tabsMenuList.value.find(
|
|
146
|
+
(item) => item.path === targetPath
|
|
147
|
+
);
|
|
148
|
+
targetQuery = targetTab?.query;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const doRemove = () => {
|
|
152
|
+
tabsMenuValue.value = targetPath!;
|
|
153
|
+
const removedTab = tabsMenuList.value.find(
|
|
154
|
+
(item) => item.path === tabPath
|
|
155
|
+
);
|
|
156
|
+
tabsMenuList.value = tabsMenuList.value.filter(
|
|
157
|
+
(item) => item.path !== tabPath
|
|
158
|
+
);
|
|
159
|
+
if (removedTab?.name) {
|
|
160
|
+
delKeepAlive(removedTab.name);
|
|
161
|
+
}
|
|
162
|
+
tabsChange();
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
if (router) {
|
|
166
|
+
router.push({ path: targetPath, query: targetQuery }).then(doRemove);
|
|
167
|
+
} else {
|
|
168
|
+
doRemove();
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
const removedTab = tabsMenuList.value[tabIndex];
|
|
172
|
+
if (removedTab?.name) {
|
|
173
|
+
delKeepAlive(removedTab.name);
|
|
174
|
+
}
|
|
175
|
+
tabsMenuList.value = tabsMenuList.value.filter(
|
|
176
|
+
(item) => item.path !== tabPath
|
|
177
|
+
);
|
|
178
|
+
tabsChange();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** 设置当前激活的标签页 */
|
|
183
|
+
function setTabsMenuValue(value: string) {
|
|
184
|
+
tabsMenuValue.value = value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** 添加缓存路由 */
|
|
188
|
+
function setKeepAlive(routerName: string) {
|
|
189
|
+
if (routerName && !keepAliveRoutes.value.includes(routerName)) {
|
|
190
|
+
keepAliveRoutes.value.push(routerName);
|
|
191
|
+
sessionStorage.setItem(
|
|
192
|
+
getKeepAliveKey(),
|
|
193
|
+
JSON.stringify(keepAliveRoutes.value)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** 删除缓存路由 */
|
|
199
|
+
function delKeepAlive(routerName: string) {
|
|
200
|
+
const index = keepAliveRoutes.value.indexOf(routerName);
|
|
201
|
+
if (index > -1) {
|
|
202
|
+
keepAliveRoutes.value.splice(index, 1);
|
|
203
|
+
sessionStorage.setItem(
|
|
204
|
+
getKeepAliveKey(),
|
|
205
|
+
JSON.stringify(keepAliveRoutes.value)
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** 关闭其他标签页 */
|
|
211
|
+
function closeMultipleTab(targetPath?: string) {
|
|
212
|
+
tabsMenuList.value = tabsMenuList.value.filter((item) => {
|
|
213
|
+
return item.path === targetPath;
|
|
214
|
+
});
|
|
215
|
+
keepAliveRoutes.value = keepAliveRoutes.value.filter((name) => {
|
|
216
|
+
return tabsMenuList.value.some((tab) => tab.name === name);
|
|
217
|
+
});
|
|
218
|
+
tabsChange();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** 关闭左侧标签页 */
|
|
222
|
+
function closeLeftTabs(targetPath?: string, router?: any) {
|
|
223
|
+
const targetIndex = tabsMenuList.value.findIndex(
|
|
224
|
+
(item) => item.path === targetPath
|
|
225
|
+
);
|
|
226
|
+
if (targetIndex <= 0) return;
|
|
227
|
+
|
|
228
|
+
const currentIndex = tabsMenuList.value.findIndex(
|
|
229
|
+
(item) => item.path === tabsMenuValue.value
|
|
230
|
+
);
|
|
231
|
+
const isCurrentClosed = currentIndex < targetIndex;
|
|
232
|
+
|
|
233
|
+
const removedTabs = tabsMenuList.value.splice(0, targetIndex);
|
|
234
|
+
removedTabs.forEach((tab) => {
|
|
235
|
+
if (tab.name) delKeepAlive(tab.name);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (isCurrentClosed && tabsMenuList.value.length > 0 && router) {
|
|
239
|
+
const newPath = tabsMenuList.value[0].path;
|
|
240
|
+
router.push(newPath);
|
|
241
|
+
tabsMenuValue.value = newPath;
|
|
242
|
+
}
|
|
243
|
+
tabsChange();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** 关闭右侧标签页 */
|
|
247
|
+
function closeRightTabs(targetPath?: string, router?: any) {
|
|
248
|
+
const targetIndex = tabsMenuList.value.findIndex(
|
|
249
|
+
(item) => item.path === targetPath
|
|
250
|
+
);
|
|
251
|
+
if (targetIndex === -1 || targetIndex >= tabsMenuList.value.length - 1)
|
|
252
|
+
return;
|
|
253
|
+
|
|
254
|
+
const currentIndex = tabsMenuList.value.findIndex(
|
|
255
|
+
(item) => item.path === tabsMenuValue.value
|
|
256
|
+
);
|
|
257
|
+
const isCurrentClosed = currentIndex > targetIndex;
|
|
258
|
+
|
|
259
|
+
const removedTabs = tabsMenuList.value.splice(targetIndex + 1);
|
|
260
|
+
removedTabs.forEach((tab) => {
|
|
261
|
+
if (tab.name) delKeepAlive(tab.name);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (isCurrentClosed && tabsMenuList.value.length > 0 && router) {
|
|
265
|
+
const newPath = tabsMenuList.value[tabsMenuList.value.length - 1].path;
|
|
266
|
+
router.push(newPath);
|
|
267
|
+
tabsMenuValue.value = newPath;
|
|
268
|
+
}
|
|
269
|
+
tabsChange();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** 关闭全部标签页 */
|
|
273
|
+
function closeAllTabs(router?: any) {
|
|
274
|
+
tabsMenuList.value = [];
|
|
275
|
+
keepAliveRoutes.value = [];
|
|
276
|
+
tabsMenuValue.value = "";
|
|
277
|
+
if (router) {
|
|
278
|
+
router.push("/application-entry");
|
|
279
|
+
}
|
|
280
|
+
tabsChange();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** 标签页变化时保存到 sessionStorage */
|
|
284
|
+
function tabsChange() {
|
|
285
|
+
sessionStorage.setItem(getTabsKey(), JSON.stringify(tabsMenuList.value));
|
|
286
|
+
sessionStorage.setItem(getActiveTabKey(), tabsMenuValue.value);
|
|
287
|
+
sessionStorage.setItem(
|
|
288
|
+
getKeepAliveKey(),
|
|
289
|
+
JSON.stringify(keepAliveRoutes.value)
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** 从 sessionStorage 恢复标签页 */
|
|
294
|
+
function restoreTabsFromStorage() {
|
|
295
|
+
if (!currentSystemId.value) {
|
|
296
|
+
initSystemId();
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
const storedTabs = sessionStorage.getItem(getTabsKey());
|
|
300
|
+
tabsMenuList.value = storedTabs ? JSON.parse(storedTabs) : [];
|
|
301
|
+
|
|
302
|
+
const storedActiveTab = sessionStorage.getItem(getActiveTabKey());
|
|
303
|
+
tabsMenuValue.value = storedActiveTab || "";
|
|
304
|
+
|
|
305
|
+
const storedKeepAlive = sessionStorage.getItem(getKeepAliveKey());
|
|
306
|
+
keepAliveRoutes.value = storedKeepAlive ? JSON.parse(storedKeepAlive) : [];
|
|
307
|
+
|
|
308
|
+
isRestored.value = true;
|
|
309
|
+
} catch (e) {
|
|
310
|
+
console.error("恢复标签页失败:", e);
|
|
311
|
+
tabsMenuList.value = [];
|
|
312
|
+
keepAliveRoutes.value = [];
|
|
313
|
+
tabsMenuValue.value = "";
|
|
314
|
+
isRestored.value = true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** 切换系统时重新加载对应系统的标签页数据 */
|
|
319
|
+
function switchSystem(newSystemId?: string) {
|
|
320
|
+
if (newSystemId) {
|
|
321
|
+
currentSystemId.value = newSystemId;
|
|
322
|
+
sessionStorage.setItem("CURRENT_TABS_SYSTEM_ID", newSystemId);
|
|
323
|
+
} else {
|
|
324
|
+
initSystemId();
|
|
325
|
+
}
|
|
326
|
+
isRestored.value = false;
|
|
327
|
+
restoreTabsFromStorage();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** 刷新当前页面 */
|
|
331
|
+
function refreshPage() {
|
|
332
|
+
const currentTab = tabsMenuList.value.find(
|
|
333
|
+
(item) => item.path === tabsMenuValue.value
|
|
334
|
+
);
|
|
335
|
+
if (currentTab?.name) {
|
|
336
|
+
delKeepAlive(currentTab.name);
|
|
337
|
+
setTimeout(() => {
|
|
338
|
+
if (currentTab.cachedCode === "0") {
|
|
339
|
+
setKeepAlive(currentTab.name!);
|
|
340
|
+
}
|
|
341
|
+
}, 100);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
currentSystemId,
|
|
347
|
+
isRestored,
|
|
348
|
+
keepAliveRoutes,
|
|
349
|
+
tabsMenuList,
|
|
350
|
+
tabsMenuValue,
|
|
351
|
+
reset,
|
|
352
|
+
addTabs,
|
|
353
|
+
removeTabs,
|
|
354
|
+
setTabsMenuValue,
|
|
355
|
+
setKeepAlive,
|
|
356
|
+
delKeepAlive,
|
|
357
|
+
closeMultipleTab,
|
|
358
|
+
closeLeftTabs,
|
|
359
|
+
closeRightTabs,
|
|
360
|
+
closeAllTabs,
|
|
361
|
+
tabsChange,
|
|
362
|
+
restoreTabsFromStorage,
|
|
363
|
+
refreshPage,
|
|
364
|
+
initSystemId,
|
|
365
|
+
switchSystem,
|
|
366
|
+
};
|
|
367
|
+
});
|
package/src/components.ts
CHANGED
|
@@ -9,7 +9,7 @@ import AnnexUploadWeijian from './components/annex-upload-weijian/index.vue'
|
|
|
9
9
|
import BaseLayout from './components/base-layout/index.vue'
|
|
10
10
|
|
|
11
11
|
// Layout components
|
|
12
|
-
import { SysHeader, SysHeaderTabs, PersonalizationGuideDialog, SideMenu } from './components/layout'
|
|
12
|
+
import { SysHeader, SysHeaderTabs, PersonalizationGuideDialog, SideMenu, LayoutContainer } from './components/layout'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* 这里默认导出一个vue支持的install方法
|
|
@@ -32,6 +32,7 @@ export default {
|
|
|
32
32
|
app.component("SysHeaderTabs", SysHeaderTabs);
|
|
33
33
|
app.component("PersonalizationGuideDialog", PersonalizationGuideDialog);
|
|
34
34
|
app.component("SideMenu", SideMenu);
|
|
35
|
+
app.component("LayoutContainer", LayoutContainer);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -40,7 +41,7 @@ export default {
|
|
|
40
41
|
* 为了将来支持类似这样按需使用 import {AnnexUpload} from "hrp-ui-base";
|
|
41
42
|
* 有多少个组件就添加多少个组件
|
|
42
43
|
*/
|
|
43
|
-
export { CustomButton, CustonSwitch, AnnexUpload, ListSearchContent, AnnexImgUpload, AnnexUploadWeijian, BaseLayout };
|
|
44
|
+
export { CustomButton, CustonSwitch, AnnexUpload, ListSearchContent, AnnexImgUpload, AnnexUploadWeijian, BaseLayout, LayoutContainer };
|
|
44
45
|
|
|
45
46
|
// 重新导出布局组件
|
|
46
47
|
export * from './components/layout';
|
|
@@ -60,6 +61,7 @@ declare module "vue" {
|
|
|
60
61
|
SysHeader: typeof SysHeader,
|
|
61
62
|
SysHeaderTabs: typeof SysHeaderTabs,
|
|
62
63
|
PersonalizationGuideDialog: typeof PersonalizationGuideDialog,
|
|
63
|
-
SideMenu: typeof SideMenu
|
|
64
|
+
SideMenu: typeof SideMenu,
|
|
65
|
+
LayoutContainer: typeof LayoutContainer
|
|
64
66
|
}
|
|
65
67
|
}
|