@epxing/core 5.3.0-beta.1 → 5.3.0-beta.3
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/API.md +30 -27
- package/README.md +5 -4
- package/dist/.cache/route-chart-release/frontend/frame/public/js/ecStat.min.js +4 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts-wordcloud.min.js +4 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts.min.js +4 -0
- package/dist/_virtual/_plugin-vue_export-helper.js +10 -0
- package/dist/_virtual/jsencrypt.min.js +1 -1
- package/dist/assets/ecStat.min-BrTYPOXX.js +1 -0
- package/dist/assets/echarts-wordcloud.min-nWR4Hzny.js +3 -0
- package/dist/assets/echarts.min-DROS9E5X.js +45 -0
- package/dist/assets/role_select-DTqRlFNz.webp +0 -0
- package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/jsencrypt@3.5.4/_vendor/jsencrypt/bin/jsencrypt.min.js +1 -1
- package/dist/src/Container.js +1 -0
- package/dist/src/RootApp.js +54 -0
- package/dist/src/api/config.js +1 -0
- package/dist/src/api/createHttp.js +7 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/app-layout.js +1 -0
- package/dist/src/app-ui-settings.js +49 -0
- package/dist/src/app.js +1 -0
- package/dist/src/axios.js +11 -15
- package/dist/src/capture-ref.js +1 -0
- package/dist/src/chart-runtime-assets.js +9 -0
- package/dist/src/components/draggable/index.js +1 -0
- package/dist/src/create-app.js +4 -6
- package/dist/src/directives/clickoutside.js +1 -0
- package/dist/src/directives/global.js +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/lazy-library.js +1 -0
- package/dist/src/loadComponent.js +3 -2
- package/dist/src/loadLibrary.js +1 -0
- package/dist/src/menu-route.js +12 -0
- package/dist/src/mixins/component.js +4 -0
- package/dist/src/mixins/custom-option.js +1 -0
- package/dist/src/mixins/el-locale.js +1 -0
- package/dist/src/mixins/global.js +1 -0
- package/dist/src/mixins/index.js +1 -0
- package/dist/src/mixins/methods-to-prototype.js +1 -0
- package/dist/src/mixins/optimized-global.js +1 -0
- package/dist/src/mixins/popper.js +1 -0
- package/dist/src/navigation-context.js +47 -0
- package/dist/src/navigation.js +44 -12
- package/dist/src/package-install.js +4 -2
- package/dist/src/plugins/element-plus.js +9 -8
- package/dist/src/plugins/i18n.js +1 -0
- package/dist/src/plugins/library-locale.js +1 -0
- package/dist/src/progress-bar.js +1 -0
- package/dist/src/public-api.js +5 -2
- package/dist/src/register-components.js +1 -0
- package/dist/src/remote-deps.js +1 -0
- package/dist/src/route-components.js +9 -0
- package/dist/src/router/config.js +8 -8
- package/dist/src/router/index.js +1 -0
- package/dist/src/router/public.js +1 -0
- package/dist/src/runtime-services.js +2 -1
- package/dist/src/runtime-utils/fieldFactory.js +1 -0
- package/dist/src/runtime-utils/meta.js +4 -0
- package/dist/src/runtime-utils/pdf.viewer.js +32 -15
- package/dist/src/runtime-utils/util.js +30 -5
- package/dist/src/shallow-same.js +1 -0
- package/dist/src/shared-packages.js +2 -3
- package/dist/src/store/actions.js +1 -0
- package/dist/src/store/create-store.js +1 -0
- package/dist/src/store/index.js +1 -0
- package/dist/src/store/lru.js +1 -0
- package/dist/src/store/modules/config.js +1 -0
- package/dist/src/store/modules/file.js +1 -0
- package/dist/src/store/modules/index.js +1 -0
- package/dist/src/store/modules/list.js +26 -3
- package/dist/src/store/modules/locale.js +1 -0
- package/dist/src/store/modules/meta.js +50 -7
- package/dist/src/store/modules/page.js +1 -0
- package/dist/src/store/modules/router.js +1 -0
- package/dist/src/store/modules/tabs.js +1 -0
- package/dist/src/store/modules/user.js +1 -0
- package/dist/src/style-presets.js +5 -4
- package/dist/src/ui-settings.js +91 -18
- package/dist/src/viewport.js +1 -0
- package/dist/src/views/App.js +48 -0
- package/dist/src/views/AppRoleSelect.js +233 -0
- package/dist/src/views/Error.js +210 -0
- package/dist/src/views/Module.js +173 -0
- package/dist/src/vue.bus.js +1 -0
- package/dist/src/vue2-cancel-token-compat.js +1 -0
- package/dist/src/vue2-remote-shim.js +1 -0
- package/dist/src/vue2-render-compat.js +1 -0
- package/dist/src/vue2-select-style-compat.js +1 -0
- package/dist/src/watermark.js +1 -0
- package/dist/src/xss.js +1 -0
- package/dist/src/z-index.js +1 -0
- package/dist/style.css +251 -0
- package/package.json +6 -5
- package/src/RootApp.vue +75 -0
- package/src/api/createHttp.js +7 -0
- package/src/api/index.js +47 -47
- package/src/app-ui-settings.js +31 -0
- package/src/axios.js +311 -318
- package/src/chart-runtime-assets.js +7 -0
- package/src/create-app.js +3 -7
- package/src/index.js +28 -28
- package/src/install.js +157 -157
- package/src/loadComponent.js +187 -187
- package/src/loadLibrary.js +99 -99
- package/src/menu-route.js +12 -1
- package/src/mixins/component.js +1464 -1461
- package/src/navigation-context.js +49 -0
- package/src/navigation.js +208 -176
- package/src/package-install.js +2 -1
- package/src/plugins/element-plus.js +302 -302
- package/src/plugins/frame.js +178 -178
- package/src/public-api.js +1 -0
- package/src/route-components.js +7 -0
- package/src/router/config.js +861 -864
- package/src/router/public.js +1 -1
- package/src/runtime-services.js +1 -1
- package/src/runtime-utils/fieldFactory.js +179 -179
- package/src/runtime-utils/meta.js +399 -378
- package/src/runtime-utils/pdf.viewer.js +672 -644
- package/src/runtime-utils/util.js +1357 -1330
- package/src/shared-packages.js +1 -3
- package/src/store/modules/config.js +351 -351
- package/src/store/modules/list.js +30 -3
- package/src/store/modules/locale.js +236 -236
- package/src/store/modules/meta.js +314 -265
- package/src/style-presets.js +4 -4
- package/src/ui-settings.js +84 -23
- package/src/views/App.vue +53 -0
- package/src/views/AppRoleSelect.vue +334 -0
- package/src/views/Error.vue +63 -0
- package/src/views/Module.vue +210 -0
- package/src/xss.js +26 -26
- package/types/app.d.ts +10 -10
- package/types/axios.d.ts +1 -1
- package/types/component-mixin.d.ts +1 -1
- package/types/field-factory.d.ts +1 -1
- package/types/global-mixin.d.ts +1 -1
- package/types/http.d.ts +1 -1
- package/types/index.d.ts +3 -0
- package/types/meta.d.ts +1 -1
- package/types/navigation.d.ts +21 -21
- package/types/pdf-viewer.d.ts +1 -1
- package/types/runtime.d.ts +13 -13
- package/types/store.d.ts +1 -1
- package/types/util.d.ts +2 -2
- /package/dist/{build → .cache/route-chart-release/frontend/frame/build}/stubs/empty-components.js +0 -0
- /package/dist/{src → .cache/route-chart-release/frontend/frame/src}/element-icons.names.js +0 -0
- /package/dist/{src → .cache/route-chart-release/frontend/frame/src}/element-plus.lazy.js +0 -0
- /package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/element-plus@2.14.3_vue@3.5.39_typescript@5.9.3_/_vendor/element-plus/dist/locale/en.js +0 -0
- /package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/element-plus@2.14.3_vue@3.5.39_typescript@5.9.3_/_vendor/element-plus/dist/locale/zh-cn.js +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { effectiveRouteName, findMenuPath, resolveRouteRole } from './menu-route'
|
|
2
|
+
|
|
3
|
+
const fields = ['moduleId', 'pageId', 'component', 'metaId', 'flag', 'showMenu']
|
|
4
|
+
|
|
5
|
+
function storageKey (route, menuId, userId) {
|
|
6
|
+
const name = effectiveRouteName(route.name)
|
|
7
|
+
if (name !== 'app1' && name !== 'hall') return ''
|
|
8
|
+
const { client, system, app } = route.params || {}
|
|
9
|
+
return 'epx_nav_context:' + JSON.stringify([name, client, system, app, resolveRouteRole(route), userId, menuId])
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 只保留导航所需的标识,不序列化标签里的组件实例、回调和业务数据。
|
|
13
|
+
export function saveMenuContext (route, menu, context, userId = '') {
|
|
14
|
+
const key = storageKey(route, menu.ID, userId)
|
|
15
|
+
if (!key) return
|
|
16
|
+
try {
|
|
17
|
+
if (!context?.moduleId) {
|
|
18
|
+
window.sessionStorage.removeItem(key)
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
const saved = {}
|
|
22
|
+
for (const field of fields) {
|
|
23
|
+
const value = context[field]
|
|
24
|
+
if (typeof value === 'string' || typeof value === 'boolean') saved[field] = value
|
|
25
|
+
}
|
|
26
|
+
window.sessionStorage.setItem(key, JSON.stringify(saved))
|
|
27
|
+
} catch (error) {
|
|
28
|
+
// 存储被禁用时继续使用现有导航。
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function readMenuContext (route, menu, menus, userId = '') {
|
|
33
|
+
const key = storageKey(route, menu.ID, userId)
|
|
34
|
+
if (!key) return null
|
|
35
|
+
try {
|
|
36
|
+
const saved = JSON.parse(window.sessionStorage.getItem(key) || 'null')
|
|
37
|
+
if (!saved) return null
|
|
38
|
+
const path = findMenuPath(menus, menu.ID)
|
|
39
|
+
const root = path.find(item => item.ID === saved.moduleId)
|
|
40
|
+
// 角色权限、菜单归属或绑定页面变化后,旧上下文不再适用。
|
|
41
|
+
if (!root || (root.MAIN_PAGE || '') !== (saved.pageId || '')) {
|
|
42
|
+
window.sessionStorage.removeItem(key)
|
|
43
|
+
return null
|
|
44
|
+
}
|
|
45
|
+
return saved
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/navigation.js
CHANGED
|
@@ -1,176 +1,208 @@
|
|
|
1
|
-
// 平台导航服务 $nav(菜单直达 + 激活的单一实现;纯函数层在 menu-route.js,此处依赖 store/router 单例)。
|
|
2
|
-
//
|
|
3
|
-
// 背景:应用内导航(顶部 nav → 标签页 → 模块/菜单栈)原先只活在 Vuex,URL 停在应用级,
|
|
4
|
-
// 刷新即回首页。现在:点击菜单/程序跳转 → activateMenu()(原 $createPage({menuId}) 分支
|
|
5
|
-
// 迁入的单一实现)→ 同步 URL 到 /app/:client/:system/:app/m/:menuKey;刷新/直达/前进后退
|
|
6
|
-
// → activateFromRoute() 反查菜单树走同一条激活路径。
|
|
7
|
-
// 对外经 core/src/install.js 挂 app.config.globalProperties.$nav。
|
|
8
|
-
import { nextTick } from 'vue'
|
|
9
|
-
import { runtimeStore as store, runtimeRouter as router } from './runtime-services'
|
|
10
|
-
import { getMenuKey, findMenuByKey, roleStorage, effectiveRouteName, menuLocation } from './menu-route'
|
|
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
|
-
if (
|
|
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
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
export function
|
|
141
|
-
const
|
|
142
|
-
if (!
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
1
|
+
// 平台导航服务 $nav(菜单直达 + 激活的单一实现;纯函数层在 menu-route.js,此处依赖 store/router 单例)。
|
|
2
|
+
//
|
|
3
|
+
// 背景:应用内导航(顶部 nav → 标签页 → 模块/菜单栈)原先只活在 Vuex,URL 停在应用级,
|
|
4
|
+
// 刷新即回首页。现在:点击菜单/程序跳转 → activateMenu()(原 $createPage({menuId}) 分支
|
|
5
|
+
// 迁入的单一实现)→ 同步 URL 到 /app/:client/:system/:app/m/:menuKey;刷新/直达/前进后退
|
|
6
|
+
// → activateFromRoute() 反查菜单树走同一条激活路径。
|
|
7
|
+
// 对外经 core/src/install.js 挂 app.config.globalProperties.$nav。
|
|
8
|
+
import { nextTick } from 'vue'
|
|
9
|
+
import { runtimeStore as store, runtimeRouter as router } from './runtime-services'
|
|
10
|
+
import { getMenuKey, getRouteMenuKey, findMenuByKey, roleStorage, resolveRouteRole, effectiveRouteName, menuLocation } from './menu-route'
|
|
11
|
+
import { saveMenuContext, readMenuContext } from './navigation-context'
|
|
12
|
+
|
|
13
|
+
export * from './menu-route'
|
|
14
|
+
|
|
15
|
+
function findNavId (menus = [], menuId, parent) {
|
|
16
|
+
for (let i = 0; i < menus.length; i++) {
|
|
17
|
+
const menu = menus[i]
|
|
18
|
+
if (menu.ID === menuId) {
|
|
19
|
+
return { ...menu, parentMenu: parent }
|
|
20
|
+
} else if (menu.children) {
|
|
21
|
+
const activeMenu = findNavId(menu.children, menuId, menu)
|
|
22
|
+
if (activeMenu) return activeMenu
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 防「激活→URL push→route watcher→再激活」回环:记录最后一次由激活侧写入的 key
|
|
28
|
+
let lastSyncedKey = null
|
|
29
|
+
|
|
30
|
+
// 登录用户在路由守卫中已就绪,详细资料异步加载,不用它作为会话存储的首选标识。
|
|
31
|
+
const navigationUserId = () => store.state.user?.user?.id || store.state.user?.userInfo?.ID || ''
|
|
32
|
+
|
|
33
|
+
// 菜单激活的单一实现。**关键:顶级菜单和子菜单走不同的建表参数**——
|
|
34
|
+
// 顶级菜单(直接在 appMenus 里,即顶部导航项):与 AppNav.toPage 点击**完全一致**的极简
|
|
35
|
+
// 参数 {moduleId, pageId, title}。这类菜单可能自带 MAIN_PAGE(如人事异动既有绑定页面又有
|
|
36
|
+
// 子菜单)——极简参数让 module-index-page 走它的绑定页面;若给了 activeMenuPageId 会被
|
|
37
|
+
// 误判为"下钻到子页面"→ 渲染出自己的侧边菜单 + 绑定页内的侧边菜单 = 两个侧边导航。
|
|
38
|
+
// 子菜单(在某顶级项的 children 里):需要 activeMenuId/activeMenuPageId 下钻高亮子项。
|
|
39
|
+
export function activateMenu (menuId, extraProps = {}, { syncUrl = true, replaceUrl = false, query } = {}) {
|
|
40
|
+
const appMenus = store.state.config.appMenus || []
|
|
41
|
+
// 配置中心由专用菜单模板负责导航和上下文,直达时保留原首页容器,不另建普通模块页。
|
|
42
|
+
if (effectiveRouteName(router.currentRoute.value.name) === 'system') {
|
|
43
|
+
const menu = findMenuByKey(appMenus, menuId)
|
|
44
|
+
if (!menu) return false
|
|
45
|
+
nextTick(activateHome)
|
|
46
|
+
if (syncUrl) syncMenuUrl(menu, { replace: replaceUrl, query })
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
const topLevel = appMenus.find(m => m.ID === menuId)
|
|
50
|
+
let menuNode = null
|
|
51
|
+
let params = null
|
|
52
|
+
if (topLevel) {
|
|
53
|
+
// 顶级菜单:镜像 AppNav.toPage 的建表(不加 activeMenu*/openType,避免误触发子菜单下钻)
|
|
54
|
+
menuNode = topLevel
|
|
55
|
+
params = {
|
|
56
|
+
key: 'default-' + menuId,
|
|
57
|
+
moduleId: menuId,
|
|
58
|
+
component: 'module-index-page',
|
|
59
|
+
title: topLevel.NAME_ALIAS || topLevel.NAME || topLevel.text,
|
|
60
|
+
pageId: topLevel.MAIN_PAGE,
|
|
61
|
+
...extraProps
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
// 子菜单:定位所属顶部 nav,下钻高亮
|
|
65
|
+
let navId = null
|
|
66
|
+
let pageId = ''
|
|
67
|
+
let activeMenuPageId = extraProps.pageId
|
|
68
|
+
for (let i = 0; i < appMenus.length; i++) {
|
|
69
|
+
const menu = findNavId(appMenus[i].children, menuId, appMenus[i])
|
|
70
|
+
if (menu) {
|
|
71
|
+
menuNode = menu
|
|
72
|
+
navId = menu.parent
|
|
73
|
+
if (menu.parentMenu) pageId = menu.parentMenu.MAIN_PAGE
|
|
74
|
+
if (!activeMenuPageId) activeMenuPageId = menu.MAIN_PAGE
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!menuNode) return false
|
|
79
|
+
const moduleId = navId || menuId
|
|
80
|
+
const props = { ...extraProps }
|
|
81
|
+
delete props.pageId
|
|
82
|
+
params = {
|
|
83
|
+
key: 'default-' + moduleId,
|
|
84
|
+
openType: '1',
|
|
85
|
+
title: menuNode.NAME_ALIAS || menuNode.NAME || menuNode.text,
|
|
86
|
+
moduleId,
|
|
87
|
+
pageId,
|
|
88
|
+
activeMenuId: menuId,
|
|
89
|
+
activeMenuPageId,
|
|
90
|
+
...props,
|
|
91
|
+
component: 'module-index-page'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
store.commit('DESTORY_TAB', params.key)
|
|
95
|
+
nextTick(() => store.commit('CREATE_TAB', params))
|
|
96
|
+
if (syncUrl) syncMenuUrl(menuNode, { replace: replaceUrl, query, context: params })
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 激活后把菜单键写进 URL(push——浏览器前进/后退可在菜单间穿梭;恢复场景用 replace)
|
|
101
|
+
export function syncMenuUrl (menu, { replace = false, query, context } = {}) {
|
|
102
|
+
// URL 一律用菜单 ID(32 位 hex——路由参数正则与 app1 的 :role 段消歧的前提);
|
|
103
|
+
// 编号(MODULE_CODE)仍可作为 toMenu 入参,但不进 URL
|
|
104
|
+
const key = menu && menu.ID
|
|
105
|
+
if (!key || !/^[0-9A-Fa-f]{32}$/.test(key)) return
|
|
106
|
+
const route = router.currentRoute.value
|
|
107
|
+
const name = effectiveRouteName(route.name)
|
|
108
|
+
if (name !== 'app1' && name !== 'hall' && name !== 'system') return // 独立窗口页/manage 等场景不动 URL
|
|
109
|
+
saveMenuContext(route, menu, context, navigationUserId())
|
|
110
|
+
if (getRouteMenuKey(route) === key && query === undefined) return
|
|
111
|
+
lastSyncedKey = key
|
|
112
|
+
const loc = menuLocation(route, key, query)
|
|
113
|
+
;(replace ? router.replace(loc) : router.push(loc)).catch(() => {})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 路由跳转失败(重复导航 / 守卫中断)不是业务错误,不该弹用户提示:
|
|
117
|
+
// 具名成常量而不是就地写空 catch,是为了把「有意忽略」写在明面上。
|
|
118
|
+
const ignoreNavFailure = () => {}
|
|
119
|
+
|
|
120
|
+
// syncMenuUrl 的反向操作:回首页时清除菜单路径段,并兼容配置中心旧的查询参数——
|
|
121
|
+
// 菜单已不再激活,URL 不该继续指向它(刷新/分享会又回到那个菜单)。
|
|
122
|
+
// URL 上本就没有 menuKey 的场景(manage / 独立窗口页 / 本就在首页)直接早退,不动 URL。
|
|
123
|
+
export function clearMenuUrl ({ replace = false } = {}) {
|
|
124
|
+
const route = router.currentRoute.value
|
|
125
|
+
if (!getRouteMenuKey(route)) return
|
|
126
|
+
const { client, system, app } = route.params
|
|
127
|
+
const name = effectiveRouteName(route.name)
|
|
128
|
+
const query = { ...route.query }
|
|
129
|
+
if (name === 'system') delete query.menuKey
|
|
130
|
+
const loc = name === 'system'
|
|
131
|
+
? { name: 'system', params: { client, system, role: resolveRouteRole(route) }, query }
|
|
132
|
+
: name === 'hall'
|
|
133
|
+
? { name: 'hall', params: { client }, query: route.query }
|
|
134
|
+
: { name: 'app1', params: { client, system, app }, query: route.query }
|
|
135
|
+
;(replace ? router.replace(loc) : router.push(loc)).catch(ignoreNavFailure)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// URL → 激活(刷新恢复 / 浏览器前进后退 / 直达链接)。AppIndex 在菜单树就绪后与
|
|
139
|
+
// 当前菜单键变化时调用。找不到(权限变化/编号改了)返回 false 落应用首页。
|
|
140
|
+
export function activateFromRoute (route) {
|
|
141
|
+
const key = getRouteMenuKey(route)
|
|
142
|
+
if (!key) return false
|
|
143
|
+
if (key === lastSyncedKey) { // 自己刚 push 的,无需再激活
|
|
144
|
+
lastSyncedKey = null
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
const menu = findMenuByKey(store.state.config.appMenus || [], key)
|
|
148
|
+
if (!menu) {
|
|
149
|
+
console.warn(`[nav] 菜单直达:找不到 menuKey=${key}(权限变化或编号已改),落应用首页`)
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
const context = readMenuContext(route, menu, store.state.config.appMenus || [], navigationUserId())
|
|
153
|
+
if (context) {
|
|
154
|
+
const params = {
|
|
155
|
+
...context,
|
|
156
|
+
key: 'default-' + context.moduleId,
|
|
157
|
+
component: context.component || 'module-index-page',
|
|
158
|
+
title: menu.NAME_ALIAS || menu.NAME || menu.text,
|
|
159
|
+
// 来源容器与目标相同时沿用独立入口,避免额外生成一层侧栏。
|
|
160
|
+
...(context.moduleId !== menu.ID ? { activeMenuId: menu.ID, activeMenuPageId: menu.MAIN_PAGE } : {})
|
|
161
|
+
}
|
|
162
|
+
store.commit('DESTORY_TAB', params.key)
|
|
163
|
+
nextTick(() => store.commit('CREATE_TAB', params))
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
return activateMenu(menu.ID, {}, { syncUrl: false })
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// URL 上没有 menuKey 时的激活目标:应用首页(已开就选中,没开就用暂存的首页模板按需打开)。
|
|
170
|
+
// activateFromRoute 的对偶——菜单直达把「有 menuKey」这一侧接住了,这一侧接的是「无 menuKey」,
|
|
171
|
+
// 少了它,前进/后退落到无 menuKey 的那一格时地址栏变了、内容还停在上一个菜单上。
|
|
172
|
+
export function activateHome () {
|
|
173
|
+
const home = store.getters.getTab('default-index') || store.state.tabs.homeTab
|
|
174
|
+
if (!home) return false
|
|
175
|
+
if (store.getters.getTab(home.key)) store.commit('SELECT_TAB', home.key)
|
|
176
|
+
else store.commit('CREATE_TAB', home)
|
|
177
|
+
return true
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ── $nav 对外表面(组件内 this.$nav.xxx;组件外可直接 import { nav })──────────
|
|
181
|
+
export const nav = {
|
|
182
|
+
/** 跳到某菜单(key=编号或 ID)。等同用户点击菜单,URL 一并更新 */
|
|
183
|
+
toMenu (keyOrId, { replace = false, query } = {}) {
|
|
184
|
+
const menu = findMenuByKey(store.state.config.appMenus || [], String(keyOrId))
|
|
185
|
+
if (!menu) {
|
|
186
|
+
console.warn(`[nav] toMenu:找不到菜单 ${keyOrId}`)
|
|
187
|
+
return false
|
|
188
|
+
}
|
|
189
|
+
return activateMenu(menu.ID, {}, { syncUrl: true, replaceUrl: replace, query })
|
|
190
|
+
},
|
|
191
|
+
/** 生成包含菜单 ID 的分享地址;角色由打开者自己的登录上下文恢复。 */
|
|
192
|
+
menuUrl (keyOrId, query) {
|
|
193
|
+
const menu = findMenuByKey(store.state.config.appMenus || [], String(keyOrId))
|
|
194
|
+
if (!menu) return ''
|
|
195
|
+
const loc = menuLocation(router.currentRoute.value, menu.ID, query)
|
|
196
|
+
return window.location.origin + window.location.pathname + router.resolve(loc).href
|
|
197
|
+
},
|
|
198
|
+
/** 当前 URL 上的菜单键(无则 '') */
|
|
199
|
+
currentMenuKey () {
|
|
200
|
+
return getRouteMenuKey(router.currentRoute.value)
|
|
201
|
+
},
|
|
202
|
+
getMenuKey,
|
|
203
|
+
findMenuByKey,
|
|
204
|
+
/** 角色持久化读写(localStorage,客户+系统维度) */
|
|
205
|
+
role: roleStorage
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export default nav
|
package/src/package-install.js
CHANGED
|
@@ -13,6 +13,7 @@ import I18n from './plugins/i18n'
|
|
|
13
13
|
import installElementPlus from './plugins/element-plus'
|
|
14
14
|
import { setApp } from './app'
|
|
15
15
|
import { configureRuntime } from './runtime-services'
|
|
16
|
+
import routeComponents from './route-components'
|
|
16
17
|
import { installGlobalMethods } from './mixins/methods-to-prototype'
|
|
17
18
|
import optimizedGlobalMixin from './mixins/optimized-global'
|
|
18
19
|
import loadComponentFactory from './loadComponent'
|
|
@@ -27,7 +28,7 @@ export function installCore (app, options = {}) {
|
|
|
27
28
|
if (installed.has(app)) return installed.get(app)
|
|
28
29
|
const { store, router, http = defaultHttp, plugins = [], components = {} } = options
|
|
29
30
|
if (!store || !router) throw new TypeError('[epx/core] install 需要 store 和 router;可用 createFrameStore() 创建框架 store')
|
|
30
|
-
configureRuntime({ ...options, http })
|
|
31
|
+
configureRuntime({ ...options, http, routeComponents: { ...routeComponents, ...options.routeComponents } })
|
|
31
32
|
setApp(app)
|
|
32
33
|
// 存量运行时内部仍有 window 访问,统一在安装阶段桥接,消费方无需手工挂载。
|
|
33
34
|
window.store = store
|