vome-core 0.0.9 → 0.0.11

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.
Files changed (198) hide show
  1. package/dist/admin/api/client.d.ts +32 -0
  2. package/dist/admin/api/client.js +1 -0
  3. package/dist/admin/config/plugin-dev.d.ts +30 -0
  4. package/dist/admin/config/plugin-dev.js +1 -0
  5. package/dist/admin/crud/config.d.ts +5 -0
  6. package/dist/admin/crud/config.js +1 -0
  7. package/dist/admin/crud/confirm.d.ts +11 -0
  8. package/dist/admin/crud/confirm.js +1 -0
  9. package/dist/admin/crud/dict.d.ts +3 -0
  10. package/dist/admin/crud/dict.js +1 -0
  11. package/dist/admin/crud/index.d.ts +40 -0
  12. package/dist/admin/crud/index.js +1 -0
  13. package/dist/admin/crud/key.d.ts +22 -0
  14. package/dist/admin/crud/key.js +1 -0
  15. package/dist/admin/crud/mitt.d.ts +10 -0
  16. package/dist/admin/crud/mitt.js +1 -0
  17. package/dist/admin/crud/plugins.d.ts +48 -0
  18. package/dist/admin/crud/plugins.js +1 -0
  19. package/dist/admin/crud/registry.d.ts +5 -0
  20. package/dist/admin/crud/registry.js +26 -0
  21. package/dist/admin/crud/span.d.ts +17 -0
  22. package/dist/admin/crud/span.js +1 -0
  23. package/dist/admin/crud/style.d.ts +36 -0
  24. package/dist/admin/crud/style.js +1 -0
  25. package/dist/admin/crud/useCrud.d.ts +18 -0
  26. package/dist/admin/crud/useCrud.js +1 -0
  27. package/dist/admin/crud/validate.d.ts +14 -0
  28. package/dist/admin/crud/validate.js +1 -0
  29. package/dist/admin/directives/perm.d.ts +3 -0
  30. package/dist/admin/directives/perm.js +1 -0
  31. package/dist/admin/hooks/useBrowser.d.ts +5 -0
  32. package/dist/admin/hooks/useBrowser.js +1 -0
  33. package/dist/admin/hooks/useUpload.d.ts +8 -0
  34. package/dist/admin/hooks/useUpload.js +1 -0
  35. package/dist/admin/hooks/useVome.d.ts +8 -0
  36. package/dist/admin/hooks/useVome.js +1 -0
  37. package/dist/admin/index.d.ts +26 -0
  38. package/dist/admin/index.js +1 -0
  39. package/dist/admin/lib/browser.d.ts +3 -0
  40. package/dist/admin/lib/browser.js +1 -0
  41. package/dist/admin/lib/cn.d.ts +2 -0
  42. package/dist/admin/lib/cn.js +1 -0
  43. package/dist/admin/lib/dialog-float.d.ts +4 -0
  44. package/dist/admin/lib/dialog-float.js +1 -0
  45. package/dist/admin/lib/eps.d.ts +11 -0
  46. package/dist/admin/lib/eps.js +1 -0
  47. package/dist/admin/lib/menu.d.ts +2 -0
  48. package/dist/admin/lib/menu.js +1 -0
  49. package/dist/admin/lib/module.d.ts +21 -0
  50. package/dist/admin/lib/module.js +1 -0
  51. package/dist/admin/lib/tree.d.ts +2 -0
  52. package/dist/admin/lib/tree.js +1 -0
  53. package/dist/admin/lib/upload.d.ts +13 -0
  54. package/dist/admin/lib/upload.js +1 -0
  55. package/dist/admin/router/index.d.ts +3 -0
  56. package/dist/admin/router/index.js +1 -0
  57. package/dist/admin/router/menu-routes.d.ts +7 -0
  58. package/dist/admin/router/menu-routes.js +1 -0
  59. package/dist/admin/service/base.d.ts +27 -0
  60. package/dist/admin/service/base.js +1 -0
  61. package/dist/admin/service/index.d.ts +15 -0
  62. package/dist/admin/service/index.js +1 -0
  63. package/dist/admin/stores/app.d.ts +1 -0
  64. package/dist/admin/stores/app.js +1 -0
  65. package/dist/admin/stores/tags.d.ts +1 -0
  66. package/dist/admin/stores/tags.js +1 -0
  67. package/dist/admin/stores/user.d.ts +1 -0
  68. package/dist/admin/stores/user.js +1 -0
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.js +1 -236
  71. package/dist/server/index.d.ts +1 -1
  72. package/dist/server/index.js +1 -3261
  73. package/dist/shared/index.js +1 -0
  74. package/dist/shared/tree.d.ts +18 -0
  75. package/dist/shared/tree.js +1 -0
  76. package/package.json +13 -10
  77. package/src/shared/tree.d.ts +18 -0
  78. package/typings/admin/base/auth.d.ts +20 -0
  79. package/typings/admin/base/permission.d.ts +19 -0
  80. package/typings/admin/comm/crud.d.ts +282 -0
  81. package/typings/admin/comm/request.d.ts +11 -0
  82. package/typings/admin/comm/service.d.ts +40 -0
  83. package/typings/admin/comm/upload.d.ts +26 -0
  84. package/typings/admin/vome/browser.d.ts +10 -0
  85. package/typings/admin/vome/module.d.ts +13 -0
  86. package/src/admin/api/client.ts +0 -184
  87. package/src/admin/config/plugin-dev.ts +0 -31
  88. package/src/admin/crud/config.ts +0 -38
  89. package/src/admin/crud/confirm.ts +0 -135
  90. package/src/admin/crud/dict.ts +0 -49
  91. package/src/admin/crud/index.ts +0 -79
  92. package/src/admin/crud/key.ts +0 -47
  93. package/src/admin/crud/mitt.ts +0 -27
  94. package/src/admin/crud/plugins.ts +0 -298
  95. package/src/admin/crud/registry.ts +0 -45
  96. package/src/admin/crud/span.ts +0 -48
  97. package/src/admin/crud/style.ts +0 -112
  98. package/src/admin/crud/useCrud.ts +0 -81
  99. package/src/admin/crud/validate.ts +0 -109
  100. package/src/admin/directives/perm.ts +0 -18
  101. package/src/admin/hooks/useBrowser.ts +0 -27
  102. package/src/admin/hooks/useUpload.ts +0 -82
  103. package/src/admin/hooks/useVome.ts +0 -13
  104. package/src/admin/index.ts +0 -59
  105. package/src/admin/lib/browser.ts +0 -28
  106. package/src/admin/lib/cn.ts +0 -7
  107. package/src/admin/lib/dialog-float.ts +0 -14
  108. package/src/admin/lib/eps.ts +0 -44
  109. package/src/admin/lib/menu.ts +0 -14
  110. package/src/admin/lib/module.ts +0 -112
  111. package/src/admin/lib/tree.ts +0 -2
  112. package/src/admin/lib/upload.ts +0 -102
  113. package/src/admin/router/index.ts +0 -68
  114. package/src/admin/router/menu-routes.ts +0 -126
  115. package/src/admin/service/base.ts +0 -96
  116. package/src/admin/service/index.ts +0 -413
  117. package/src/admin/stores/app.ts +0 -30
  118. package/src/admin/stores/tags.ts +0 -73
  119. package/src/admin/stores/user.ts +0 -52
  120. /package/{src → dist}/admin/components/vm-aside.vue +0 -0
  121. /package/{src → dist}/admin/components/vm-auto-perm-dialog.vue +0 -0
  122. /package/{src → dist}/admin/components/vm-check-tree.vue +0 -0
  123. /package/{src → dist}/admin/components/vm-dept-tree.vue +0 -0
  124. /package/{src → dist}/admin/components/vm-empty.vue +0 -0
  125. /package/{src → dist}/admin/components/vm-eps-perm-picker.vue +0 -0
  126. /package/{src → dist}/admin/components/vm-group-cascader.vue +0 -0
  127. /package/{src → dist}/admin/components/vm-icon-picker.vue +0 -0
  128. /package/{src → dist}/admin/components/vm-markdown.vue +0 -0
  129. /package/{src → dist}/admin/components/vm-ri-icon.vue +0 -0
  130. /package/{src → dist}/admin/components/vm-role-picker.vue +0 -0
  131. /package/{src → dist}/admin/components/vm-view-path-picker.vue +0 -0
  132. /package/{src → dist}/admin/crud/components/vm-column-custom.vue +0 -0
  133. /package/{src → dist}/admin/crud/components/vm-context-menu.vue +0 -0
  134. /package/{src → dist}/admin/crud/components/vm-date-picker.vue +0 -0
  135. /package/{src → dist}/admin/crud/components/vm-date-range.vue +0 -0
  136. /package/{src → dist}/admin/crud/components/vm-date-text.vue +0 -0
  137. /package/{src → dist}/admin/crud/components/vm-dict-tag.vue +0 -0
  138. /package/{src → dist}/admin/crud/components/vm-file-icon.vue +0 -0
  139. /package/{src → dist}/admin/crud/components/vm-multi-select.vue +0 -0
  140. /package/{src → dist}/admin/crud/components/vm-number-range.vue +0 -0
  141. /package/{src → dist}/admin/crud/components/vm-radio.vue +0 -0
  142. /package/{src → dist}/admin/crud/components/vm-select.vue +0 -0
  143. /package/{src → dist}/admin/crud/components/vm-switch.vue +0 -0
  144. /package/{src → dist}/admin/crud/components/vm-tree-select.vue +0 -0
  145. /package/{src → dist}/admin/crud/components/vm-upload-item.vue +0 -0
  146. /package/{src → dist}/admin/crud/components/vm-upload.vue +0 -0
  147. /package/{src → dist}/admin/crud/components/vm-user-select.vue +0 -0
  148. /package/{src → dist}/admin/crud/vm-add-btn.vue +0 -0
  149. /package/{src → dist}/admin/crud/vm-adv-search.vue +0 -0
  150. /package/{src → dist}/admin/crud/vm-crud.vue +0 -0
  151. /package/{src → dist}/admin/crud/vm-dialog.vue +0 -0
  152. /package/{src → dist}/admin/crud/vm-flex1.vue +0 -0
  153. /package/{src → dist}/admin/crud/vm-form.vue +0 -0
  154. /package/{src → dist}/admin/crud/vm-multi-delete-btn.vue +0 -0
  155. /package/{src → dist}/admin/crud/vm-pagination.vue +0 -0
  156. /package/{src → dist}/admin/crud/vm-refresh-btn.vue +0 -0
  157. /package/{src → dist}/admin/crud/vm-row.vue +0 -0
  158. /package/{src → dist}/admin/crud/vm-search-key.vue +0 -0
  159. /package/{src → dist}/admin/crud/vm-search.vue +0 -0
  160. /package/{src → dist}/admin/crud/vm-table.vue +0 -0
  161. /package/{src → dist}/admin/crud/vm-toolbar.vue +0 -0
  162. /package/{src → dist}/admin/crud/vm-upsert.vue +0 -0
  163. /package/{src → dist}/admin/data/remixicon-all.json +0 -0
  164. /package/{src → dist}/admin/env.d.ts +0 -0
  165. /package/{src → dist}/admin/static/fileicon/demo.css +0 -0
  166. /package/{src → dist}/admin/static/fileicon/demo_index.html +0 -0
  167. /package/{src → dist}/admin/static/fileicon/iconfont.css +0 -0
  168. /package/{src → dist}/admin/static/fileicon/iconfont.js +0 -0
  169. /package/{src → dist}/admin/static/fileicon/iconfont.json +0 -0
  170. /package/{src → dist}/admin/static/fileicon/iconfont.ttf +0 -0
  171. /package/{src → dist}/admin/static/fileicon/iconfont.woff +0 -0
  172. /package/{src → dist}/admin/static/fileicon/iconfont.woff2 +0 -0
  173. /package/{src → dist}/admin/static/scarce//344/270/213/350/275/275/345/244/261/350/264/245.svg" +0 -0
  174. /package/{src → dist}/admin/static/scarce//346/224/257/344/273/230/346/210/220/345/212/237.svg" +0 -0
  175. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/344/274/230/346/203/240/345/210/270.svg" +0 -0
  176. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/345/206/205/345/256/271.svg" +0 -0
  177. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/345/217/221/347/245/250.svg" +0 -0
  178. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/345/233/276/347/211/207.svg" +0 -0
  179. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/345/234/260/345/235/200.svg" +0 -0
  180. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/345/272/227/351/223/272.svg" +0 -0
  181. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/346/216/250/351/200/201.svg" +0 -0
  182. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/346/220/234/347/264/242/347/273/223/346/236/234.svg" +0 -0
  183. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/346/224/266/350/227/217.svg" +0 -0
  184. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/346/225/260/346/215/256.svg" +0 -0
  185. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/346/235/203/351/231/220.svg" +0 -0
  186. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/346/266/210/346/201/257.svg" +0 -0
  187. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/347/244/274/347/211/251.svg" +0 -0
  188. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/347/247/257/345/210/206.svg" +0 -0
  189. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/347/275/221/347/273/234.svg" +0 -0
  190. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/350/247/206/351/242/221.svg" +0 -0
  191. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/350/256/242/345/215/225.svg" +0 -0
  192. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/350/257/204/350/256/272.svg" +0 -0
  193. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/351/205/215/351/200/201.svg" +0 -0
  194. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/351/223/266/350/241/214/345/215/241.svg" +0 -0
  195. /package/{src → dist}/admin/static/scarce//346/232/202/346/227/240/351/237/263/344/271/220.svg" +0 -0
  196. /package/{src → dist}/admin/static/scarce//351/241/265/351/235/242/344/270/215/345/255/230/345/234/250.svg" +0 -0
  197. /package/{src → dist}/admin/styles/base.css +0 -0
  198. /package/{src → dist}/admin/tsconfig.json +0 -0
@@ -1,27 +0,0 @@
1
- import { useEventListener } from '@vueuse/core'
2
- import { reactive, watch } from 'vue'
3
- import { getBrowser } from '../lib/browser'
4
- const browser = reactive(getBrowser()) as BrowserInfo
5
- const events: Array<() => void> = []
6
-
7
- watch(
8
- () => browser.screen,
9
- () => {
10
- events.forEach((ev) => ev())
11
- },
12
- )
13
-
14
- useEventListener(window, 'resize', () => {
15
- Object.assign(browser, getBrowser())
16
- })
17
-
18
- /** 响应式浏览器信息 + 断点变化回调 */
19
- export function useBrowser() {
20
- return {
21
- browser,
22
- onScreenChange(ev: () => void, immediate = true) {
23
- events.push(ev)
24
- if (immediate) ev()
25
- },
26
- }
27
- }
@@ -1,82 +0,0 @@
1
- import { toast } from 'vue-sonner'
2
- import { request } from '../api/client'
3
- import { extname, filename, pathJoin, uploadUid } from '../lib/upload'
4
- import type { UploadOptions, UploadResult } from '../../../typings/admin/comm/upload'
5
-
6
- const UPLOAD_PATH = '/admin/base/comm/upload'
7
-
8
- type SignPayload = Record<string, unknown>
9
-
10
- const SIGN_SKIP = new Set([
11
- 'url',
12
- 'host',
13
- 'uploadUrl',
14
- 'publicDomain',
15
- 'previewUrl',
16
- 'preview',
17
- ])
18
-
19
- /**
20
- * 云端直传:向服务端取签名 → 直传对象存储
21
- * 需已安装 hook=upload 插件;配置错误由插件/接口直接抛错
22
- */
23
- export function useUpload() {
24
- async function toUpload(file: File, opts: UploadOptions = {}): Promise<UploadResult> {
25
- const { prefixPath = 'app/base', onProgress } = opts
26
- const fileId = uploadUid()
27
- const ext = extname(file.name)
28
- const name = `${filename(file.name)}_${fileId}${ext ? `.${ext}` : ''}`
29
- const key = pathJoin(prefixPath, name)
30
-
31
- const sign = await request<SignPayload>(UPLOAD_PATH, {
32
- method: 'POST',
33
- body: JSON.stringify({}),
34
- })
35
-
36
- const host = String(sign.host || sign.url || sign.uploadUrl || '')
37
- if (!host) throw new Error('上传地址无效')
38
-
39
- const fd = new FormData()
40
- fd.append('key', key)
41
- for (const [k, v] of Object.entries(sign)) {
42
- if (SIGN_SKIP.has(k) || v == null || fd.has(k)) continue
43
- fd.append(k, String(v))
44
- }
45
- // OSS 要求 file 为最后一个字段
46
- fd.append('file', file)
47
-
48
- await xhrUpload(host, fd, onProgress)
49
-
50
- const preview = String(sign.publicDomain || sign.previewUrl || host)
51
- return { url: pathJoin(preview, key), key, fileId }
52
- }
53
-
54
- return { toUpload }
55
- }
56
-
57
- function xhrUpload(
58
- url: string,
59
- body: FormData,
60
- onProgress?: (n: number) => void,
61
- ): Promise<void> {
62
- return new Promise((resolve, reject) => {
63
- const xhr = new XMLHttpRequest()
64
- xhr.open('POST', url)
65
- xhr.upload.onprogress = (e) => {
66
- if (!e.lengthComputable) return
67
- onProgress?.(Math.min(100, Math.floor((e.loaded / e.total) * 100)))
68
- }
69
- xhr.onload = () => {
70
- if (xhr.status < 200 || xhr.status >= 300) {
71
- const msg = xhr.responseText || `上传失败 (${xhr.status})`
72
- toast.error(msg.slice(0, 200))
73
- reject(new Error(msg))
74
- return
75
- }
76
- onProgress?.(100)
77
- resolve()
78
- }
79
- xhr.onerror = () => reject(new Error('上传网络错误'))
80
- xhr.send(body)
81
- })
82
- }
@@ -1,13 +0,0 @@
1
- import { useRoute, useRouter } from 'vue-router'
2
- import { service } from '../service'
3
- import { useBrowser } from './useBrowser'
4
-
5
- /** service + router + browser */
6
- export function useVome() {
7
- return {
8
- service,
9
- route: useRoute(),
10
- router: useRouter(),
11
- ...useBrowser(),
12
- }
13
- }
@@ -1,59 +0,0 @@
1
- export {
2
- resolveView,
3
- listViews,
4
- listViewsTree,
5
- viewPathToName,
6
- registerViews,
7
- VIEWS_RESCAN_EVENT,
8
- } from './lib/module'
9
- export type { ViewsTreeNode } from '../../typings/admin/vome/module'
10
- export { getBrowser } from './lib/browser'
11
- export type { BrowserInfo, BrowserScreen } from '../../typings/admin/vome/browser'
12
- export { useBrowser } from './hooks/useBrowser'
13
- /** CRUD 组件走自动引入;此处只再导出 composable / 工具,避免桶导入拖入全部 SFC */
14
- export {
15
- useCrud,
16
- useTable,
17
- useUpsert,
18
- useSearch,
19
- useCore,
20
- CRUD_KEY,
21
- } from './crud/useCrud'
22
- export {
23
- Plugins,
24
- toTree,
25
- setFocus,
26
- setRules,
27
- setAuto,
28
- buildAutoSearchItems,
29
- } from './crud/plugins'
30
- export {
31
- setCrudConfig,
32
- getCrudConfig,
33
- getCrudStyle,
34
- } from './crud/style'
35
- export { resolveCrudComponent, registerCrudComponent } from './crud/registry'
36
- export { vmConfirm } from './crud/confirm'
37
- export { deepTree, flattenTree } from './lib/tree'
38
- export { config } from '#vome-host/config'
39
- export { pluginDev } from './config/plugin-dev'
40
- export type { PluginDevConfig, PluginScaffoldKey } from './config/plugin-dev'
41
- export { router, resetMenuRoutesFlag } from './router'
42
- export { useAppStore } from './stores/app'
43
- export { useUserStore } from './stores/user'
44
- export { useTagsStore } from './stores/tags'
45
- export { loadEps, loadAllEps, getEps, findEpsEntity } from './lib/eps'
46
- export type { EpsSide } from './lib/eps'
47
- export { api, request, apiUrl } from './api/client'
48
- export {
49
- service,
50
- createEps,
51
- setServicePerms,
52
- resolveService,
53
- serviceOf,
54
- createEpsService,
55
- BaseService,
56
- } from './service'
57
- export { useVome } from './hooks/useVome'
58
- export { vPerm } from './directives/perm'
59
- export { cn } from './lib/cn'
@@ -1,28 +0,0 @@
1
- export type { BrowserInfo, BrowserScreen } from '../../../typings/admin/vome/browser'
2
-
3
- /** 根据视口计算断点与 isMini */
4
- export function getBrowser(): BrowserInfo {
5
- const { clientHeight: height, clientWidth: width } = document.documentElement
6
- const ua = navigator.userAgent.toLowerCase()
7
-
8
- let type = (ua.match(/firefox|chrome|safari|opera/g) || ['other'])[0]
9
- if ((ua.match(/msie|trident/g) || [])[0]) type = 'msie'
10
-
11
- let screen: BrowserScreen = 'full'
12
- if (width < 768) screen = 'xs'
13
- else if (width < 992) screen = 'sm'
14
- else if (width < 1200) screen = 'md'
15
- else if (width < 1920) screen = 'xl'
16
-
17
- const isPC = !/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(
18
- ua,
19
- )
20
-
21
- return {
22
- height,
23
- width,
24
- type,
25
- screen,
26
- isMini: screen === 'xs' || !isPC,
27
- }
28
- }
@@ -1,7 +0,0 @@
1
- import type { ClassValue } from 'clsx'
2
- import { clsx } from 'clsx'
3
- import { twMerge } from 'tailwind-merge'
4
-
5
- export function cn(...inputs: ClassValue[]) {
6
- return twMerge(clsx(inputs))
7
- }
@@ -1,14 +0,0 @@
1
- /** Dialog 内 Teleport 浮层统一标记:点浮层时勿关闭宿主 Dialog */
2
- export const DIALOG_FLOAT_CLASS = 'vm-dialog-float'
3
-
4
- /** 判断 pointer/focus/interact-outside 是否落在 Dialog 浮层上 */
5
- export function isDialogFloatTarget(event: Event): boolean {
6
- const detail = (event as CustomEvent).detail as
7
- | { originalEvent?: Event }
8
- | undefined
9
- const t = (detail?.originalEvent?.target ?? event.target) as Node | null
10
- if (!t) return false
11
- // 点击文字节点时 target 不是 Element,需回退到 parentElement
12
- const el = t instanceof Element ? t : t.parentElement
13
- return Boolean(el?.closest(`.${DIALOG_FLOAT_CLASS}`))
14
- }
@@ -1,44 +0,0 @@
1
- import { request } from '../api/client'
2
-
3
- export type EpsSide = 'admin' | 'app'
4
-
5
- const EPS_URL: Record<EpsSide, string> = {
6
- admin: '/admin/base/open/eps',
7
- app: '/app/base/open/eps',
8
- }
9
-
10
- const cache: Record<EpsSide, EpsModuleMap | null> = {
11
- admin: null,
12
- app: null,
13
- }
14
-
15
- /** 拉取 EPS(默认 admin);公开接口失败不弹 toast */
16
- export async function loadEps(force = false, side: EpsSide = 'admin') {
17
- if (cache[side] && !force) return cache[side]
18
- cache[side] =
19
- (await request<EpsModuleMap>(EPS_URL[side], { toast: false })) || {}
20
- return cache[side]
21
- }
22
-
23
- /** 并行拉取 admin + app */
24
- export async function loadAllEps(force = false) {
25
- await Promise.all([loadEps(force, 'admin'), loadEps(force, 'app')])
26
- return { admin: cache.admin, app: cache.app }
27
- }
28
-
29
- export function getEps(side: EpsSide = 'admin') {
30
- return cache[side]
31
- }
32
-
33
- /** 按 prefix 找实体描述,如 /admin/base/user */
34
- export function findEpsEntity(prefix: string, side: EpsSide = 'admin') {
35
- const map = cache[side]
36
- if (!map) return undefined
37
- for (const list of Object.values(map)) {
38
- const hit = list.find(
39
- (e) => e.prefix === prefix || e.prefix === prefix.replace(/\/$/, ''),
40
- )
41
- if (hit) return hit
42
- }
43
- return undefined
44
- }
@@ -1,14 +0,0 @@
1
- /** 侧栏可见菜单(过滤隐藏节点) */
2
- export function filterShowMenus(nodes: MenuTreeNode[] | null | undefined): MenuTreeNode[] {
3
- if (!Array.isArray(nodes) || !nodes.length) return []
4
- return nodes
5
- .filter((n) => n && n.isShow !== false)
6
- .map((n) => ({
7
- ...n,
8
- children: n.children?.length ? filterShowMenus(n.children) : undefined,
9
- }))
10
- .filter((n) => {
11
- const t = Number(n.type)
12
- return t === 0 || (t === 1 && n.router) || (n.children?.length ?? 0) > 0
13
- })
14
- }
@@ -1,112 +0,0 @@
1
- import type { ViewLoader, ViewsTreeNode } from '../../../typings/admin/vome/module'
2
-
3
- /** 视图重扫事件:保存 views 触发 HMR 后派发,选择器监听刷新 */
4
- export const VIEWS_RESCAN_EVENT = 'vome:views-rescan'
5
-
6
- const viewMap = new Map<string, ViewLoader>()
7
-
8
-
9
- function rebuildViewMap(files: Record<string, ViewLoader>) {
10
- viewMap.clear()
11
- for (const [file, loader] of Object.entries(files)) {
12
- if (file.includes('/components/')) continue
13
- const m = file.match(/modules\/.+\.vue$/)
14
- if (!m) continue
15
- const rel = m[0].replace(/\.vue$/, '').replace(/\/index$/, '')
16
- viewMap.set(rel, loader)
17
- }
18
- }
19
-
20
- /** 宿主注册业务视图 glob(包内无法扫描宿主 modules) */
21
- export function registerViews(
22
- files: Record<string, () => Promise<{ default: import('vue').Component }>>,
23
- ) {
24
- rebuildViewMap(files)
25
- if (typeof window !== 'undefined') {
26
- window.dispatchEvent(new CustomEvent(VIEWS_RESCAN_EVENT))
27
- }
28
- }
29
-
30
- /** 解析菜单 viewPath,如 modules/base/views/menu */
31
- export function resolveView(viewPath: string | null | undefined): ViewLoader | undefined {
32
- if (!viewPath) return undefined
33
- const normalized = viewPath
34
- .replace(/^\/+/, '')
35
- .replace(/\.vue$/, '')
36
- .replace(/\/index$/, '')
37
- return (
38
- viewMap.get(normalized) ||
39
- viewMap.get(`modules/${normalized.replace(/^modules\//, '')}`)
40
- )
41
- }
42
-
43
- /**
44
- * viewPath → 页面组件 name
45
- * modules/base/views/role → base-role
46
- * modules/user/views/info → user-info
47
- */
48
- export function viewPathToName(viewPath: string | null | undefined): string | undefined {
49
- if (!viewPath) return undefined
50
- const normalized = viewPath
51
- .replace(/^\/+/, '')
52
- .replace(/\.vue$/, '')
53
- .replace(/\/index$/, '')
54
- const m = normalized.match(/^(?:modules\/)?([^/]+)\/views\/(.+)$/)
55
- if (m) return `${m[1]}-${m[2]!.replace(/\//g, '-')}`
56
- return undefined
57
- }
58
-
59
- export function listViews() {
60
- return [...viewMap.keys()].sort()
61
- }
62
-
63
- /**
64
- * 将扁平 viewPath 建成多列树(展示从 modules/ 后分段)
65
- * modules/base/views/menu → base > views > menu
66
- */
67
- export function listViewsTree(): ViewsTreeNode[] {
68
- const root: ViewsTreeNode[] = []
69
-
70
- for (const full of listViews()) {
71
- const parts = full.replace(/^modules\//, '').split('/').filter(Boolean)
72
- if (!parts.length) continue
73
-
74
- let level = root
75
- let acc = 'modules'
76
- for (let i = 0; i < parts.length; i++) {
77
- const label = parts[i]!
78
- acc += `/${label}`
79
- const isLeaf = i === parts.length - 1
80
- let node = level.find((n) => n.label === label)
81
- if (!node) {
82
- node = {
83
- label,
84
- value: isLeaf ? full : acc,
85
- isLeaf,
86
- children: isLeaf ? undefined : [],
87
- }
88
- level.push(node)
89
- } else if (isLeaf) {
90
- node.isLeaf = true
91
- node.value = full
92
- node.children = undefined
93
- }
94
- if (!isLeaf) {
95
- if (!node.children) node.children = []
96
- level = node.children
97
- }
98
- }
99
- }
100
-
101
- const sortTree = (nodes: ViewsTreeNode[]) => {
102
- nodes.sort((a, b) => {
103
- if (!!a.isLeaf !== !!b.isLeaf) return a.isLeaf ? 1 : -1
104
- return a.label.localeCompare(b.label)
105
- })
106
- for (const n of nodes) {
107
- if (n.children?.length) sortTree(n.children)
108
- }
109
- }
110
- sortTree(root)
111
- return root
112
- }
@@ -1,2 +0,0 @@
1
- /** 树工具:同构实现见 @vome-core */
2
- export { deepTree, flattenTree } from '../../shared/tree'
@@ -1,102 +0,0 @@
1
- import type { UploadFileType, UploadRule } from '../../../typings/admin/comm/upload'
2
-
3
- /** 默认上传规则 */
4
- export const DEFAULT_UPLOAD_RULES: UploadRule[] = [
5
- {
6
- name: '图片',
7
- type: 'image',
8
- color: '#67C23A',
9
- exts: ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'gif', 'svg', 'webp'],
10
- },
11
- {
12
- name: '视频',
13
- type: 'video',
14
- color: '#826aec',
15
- exts: ['avi', 'wmv', 'mpg', 'mpeg', 'mov', 'rm', 'ram', 'swf', 'flv', 'mp4', '3gp'],
16
- },
17
- {
18
- name: '音频',
19
- type: 'audio',
20
- color: '#826aec',
21
- exts: ['mp3', 'wav', 'wma', 'mp2', 'flac', 'midi', 'ra', 'ape', 'aac', 'cda'],
22
- },
23
- {
24
- name: '文档',
25
- type: 'word',
26
- color: '#53B7F4',
27
- exts: ['doc', 'docx', 'docm', 'dot', 'dotx', 'dotm'],
28
- },
29
- {
30
- name: '表格',
31
- type: 'excel',
32
- color: '#53D39C',
33
- exts: ['xls', 'xlsx', 'xlsm', 'xlt', 'xltx', 'xltm'],
34
- },
35
- {
36
- name: '演示',
37
- type: 'ppt',
38
- color: '#F56C6C',
39
- exts: ['ppt', 'pptx', 'pptm', 'ppsx', 'ppsm', 'pps', 'potx', 'potm', 'dpt', 'dps'],
40
- },
41
- {
42
- name: 'PDF',
43
- type: 'pdf',
44
- color: '#8f3500',
45
- exts: ['pdf'],
46
- },
47
- {
48
- name: '压缩包',
49
- type: 'rar',
50
- color: '#FFC757',
51
- exts: ['rar', 'zip', '7z', 'tar', 'gz'],
52
- },
53
- {
54
- name: '文件',
55
- type: 'file',
56
- color: '#909399',
57
- exts: [],
58
- },
59
- ]
60
-
61
- export function extname(path = '') {
62
- const m = String(path).split('?')[0]?.match(/\.([^.]+)$/)
63
- return m ? m[1].toLowerCase() : ''
64
- }
65
-
66
- export function filename(path = '') {
67
- const base = String(path).split('?')[0]?.split('/').pop() || ''
68
- const ext = extname(base)
69
- return ext ? base.slice(0, -(ext.length + 1)) : base
70
- }
71
-
72
- export function fileRule(path?: string, rules = DEFAULT_UPLOAD_RULES) {
73
- if (path?.includes('data:image/')) {
74
- return rules.find((r) => r.type === 'image')!
75
- }
76
- const ext = extname(path || '')
77
- const hit = rules.find((r) => r.exts.includes(ext))
78
- return hit || rules.find((r) => r.type === 'file')!
79
- }
80
-
81
- export function getFileType(path: string, rules = DEFAULT_UPLOAD_RULES): UploadFileType {
82
- return fileRule(path, rules).type
83
- }
84
-
85
- export function getUploadRule(type: string, rules = DEFAULT_UPLOAD_RULES) {
86
- return rules.find((r) => r.type === type) || rules[rules.length - 1]!
87
- }
88
-
89
- export function getUrls(list: Array<{ url?: string }>) {
90
- return list.map((e) => String(e.url || '').replace(/,/g, encodeURIComponent(',')))
91
- }
92
-
93
- export function pathJoin(...parts: string[]) {
94
- return parts
95
- .map((p) => p.replace(/(^\/+|\/+$)/g, ''))
96
- .filter(Boolean)
97
- .join('/')
98
- }
99
-
100
- export function uploadUid() {
101
- return `${Date.now()}_${Math.random().toString(36).slice(2, 9)}`
102
- }
@@ -1,68 +0,0 @@
1
- import { createRouter, createWebHistory } from 'vue-router'
2
- import { api, clearTokens, getAccessToken, getRefreshToken } from '../api/client'
3
- import {
4
- clearMenuRoutesFlag,
5
- ensureMenuRoutes,
6
- removeAllMenuRoutes,
7
- } from './menu-routes'
8
- import Home from '#vome-host/pages/home/index.vue'
9
- import Layout from '#vome-host/pages/layout/index.vue'
10
- import Login from '#vome-host/pages/login/index.vue'
11
-
12
- export const router = createRouter({
13
- history: createWebHistory(),
14
- routes: [
15
- {
16
- path: '/login',
17
- name: 'login',
18
- component: Login,
19
- meta: { public: true },
20
- },
21
- {
22
- path: '/',
23
- name: 'layout',
24
- component: Layout,
25
- children: [
26
- {
27
- path: '',
28
- name: 'home',
29
- component: Home,
30
- meta: { title: '首页' },
31
- },
32
- ],
33
- },
34
- ],
35
- })
36
-
37
- let menusReady = false
38
-
39
- router.beforeEach(async (to) => {
40
- if (to.meta.public) return true
41
- // 无 access 时若仍有 refresh,交给 perms 请求内自动续期
42
- if (!getAccessToken() && !getRefreshToken()) {
43
- return { name: 'login', query: { redirect: to.fullPath } }
44
- }
45
- if (!menusReady) {
46
- try {
47
- const authz = await api.perms({ toast: false })
48
- const menus = Array.isArray(authz?.menus) ? authz.menus : []
49
- await ensureMenuRoutes(router, menus)
50
- menusReady = true
51
- if (to.matched.length <= 1 && to.path !== '/') {
52
- return { ...to, replace: true }
53
- }
54
- } catch {
55
- menusReady = false
56
- clearTokens()
57
- return { name: 'login', query: { redirect: to.fullPath } }
58
- }
59
- }
60
- return true
61
- })
62
-
63
- /** 退出/重登:卸动态路由并允许再次 ensureMenuRoutes */
64
- export function resetMenuRoutesFlag() {
65
- menusReady = false
66
- removeAllMenuRoutes(router)
67
- clearMenuRoutesFlag()
68
- }