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,126 +0,0 @@
1
- import type { Router, RouteRecordRaw } from 'vue-router'
2
- import { defineComponent, h } from 'vue'
3
- import { resolveView, viewPathToName } from '../lib/module'
4
- import MissingView from '#vome-host/pages/missing/index.vue'
5
- import MicroAppView from '#vome-host/pages/micro/index.vue'
6
-
7
- /** 已挂载的动态菜单路由名 menu-${id} */
8
- const addedNames = new Set<string>()
9
-
10
- function isMicroMenu(m: MenuTreeNode) {
11
- return Boolean(m.appKey && m.router)
12
- }
13
-
14
- function walk(nodes: MenuTreeNode[], out: MenuTreeNode[]) {
15
- for (const n of nodes) {
16
- if (Number(n.type) === 1 && n.router) out.push(n)
17
- if (n.children?.length) walk(n.children, out)
18
- }
19
- }
20
-
21
- function missingView(viewPath: string) {
22
- return defineComponent({
23
- name: 'MissingViewPage',
24
- setup() {
25
- return () => h(MissingView, { path: viewPath })
26
- },
27
- })
28
- }
29
-
30
- function routeNameOf(id: number | string) {
31
- return `menu-${id}`
32
- }
33
-
34
- function buildRoute(item: MenuTreeNode): RouteRecordRaw {
35
- const full = item.router!
36
- const childPath = full.replace(/^\//, '')
37
- let component: RouteRecordRaw['component']
38
- const componentName = viewPathToName(item.viewPath)
39
- const meta: Record<string, unknown> = {
40
- title: item.name,
41
- keepAlive: item.keepAlive !== false,
42
- viewPath: item.viewPath,
43
- perms: item.perms,
44
- componentName,
45
- }
46
-
47
- if (isMicroMenu(item)) {
48
- component = MicroAppView
49
- meta.appKey = item.appKey
50
- meta.componentName = `micro-${item.appKey}`
51
- meta.keepAlive = false
52
- } else if (item.viewPath) {
53
- const loader = resolveView(item.viewPath)
54
- component = loader || missingView(item.viewPath)
55
- } else {
56
- component = missingView(full)
57
- }
58
-
59
- return {
60
- path: childPath,
61
- name: routeNameOf(item.id),
62
- component,
63
- meta,
64
- }
65
- }
66
-
67
- /** 根据权限菜单动态挂载:viewPath 本地模块 / appKey 微应用(仅补新增) */
68
- export async function ensureMenuRoutes(router: Router, menus: MenuTreeNode[]) {
69
- const items: MenuTreeNode[] = []
70
- walk(menus, items)
71
-
72
- for (const item of items) {
73
- const name = routeNameOf(item.id)
74
- if (addedNames.has(name)) continue
75
- addedNames.add(name)
76
- router.addRoute('layout', buildRoute(item))
77
- }
78
- }
79
-
80
- /** 全量同步:删旧补新,菜单改名/改路由/显隐后侧栏与路由一致 */
81
- export async function syncMenuRoutes(router: Router, menus: MenuTreeNode[]) {
82
- const items: MenuTreeNode[] = []
83
- walk(menus, items)
84
- const nextNames = new Set(items.map((i) => routeNameOf(i.id)))
85
-
86
- for (const name of [...addedNames]) {
87
- if (!nextNames.has(name)) {
88
- if (router.hasRoute(name)) router.removeRoute(name)
89
- addedNames.delete(name)
90
- }
91
- }
92
-
93
- for (const item of items) {
94
- const name = routeNameOf(item.id)
95
- const childPath = item.router!.replace(/^\//, '')
96
- if (addedNames.has(name) && router.hasRoute(name)) {
97
- const existing = router.getRoutes().find((r) => r.name === name)
98
- if (existing && existing.path.replace(/^\//, '') !== childPath) {
99
- router.removeRoute(name)
100
- addedNames.delete(name)
101
- } else if (existing?.meta) {
102
- existing.meta.title = item.name
103
- existing.meta.keepAlive = item.keepAlive !== false
104
- existing.meta.viewPath = item.viewPath
105
- existing.meta.perms = item.perms
106
- if (item.appKey) existing.meta.appKey = item.appKey
107
- continue
108
- }
109
- }
110
- if (!addedNames.has(name)) {
111
- addedNames.add(name)
112
- router.addRoute('layout', buildRoute(item))
113
- }
114
- }
115
- }
116
-
117
- export function clearMenuRoutesFlag() {
118
- addedNames.clear()
119
- }
120
-
121
- export function removeAllMenuRoutes(router: Router) {
122
- for (const name of [...addedNames]) {
123
- if (router.hasRoute(name)) router.removeRoute(name)
124
- }
125
- addedNames.clear()
126
- }
@@ -1,96 +0,0 @@
1
- import { request } from '../api/client'
2
- /** 系统时间由后端维护;所有方法请求体都不传 */
3
- function stripTimeMeta(data: unknown): unknown {
4
- if (Array.isArray(data)) return data.map((item) => stripTimeMeta(item))
5
- if (data && typeof data === 'object') {
6
- const out = { ...(data as Record<string, unknown>) }
7
- delete out.createTime
8
- delete out.updateTime
9
- return out
10
- }
11
- return data
12
- }
13
-
14
- /** BaseService:namespace + request + 标准 CRUD */
15
- export class BaseService {
16
- namespace?: string
17
-
18
- constructor(namespace?: string) {
19
- if (namespace) this.namespace = namespace.replace(/^\//, '')
20
- }
21
-
22
- async request(options: ServiceRequestOptions = {}) {
23
- let url = options.url || ''
24
-
25
- if (url && !/^https?:\/\//.test(url)) {
26
- if (this.namespace) {
27
- const ns = this.namespace.startsWith('/')
28
- ? this.namespace
29
- : `/${this.namespace}`
30
- url = url.startsWith('/') ? `${ns}${url}` : `${ns}/${url}`
31
- }
32
- if (!url.startsWith('/')) url = `/${url}`
33
- }
34
-
35
- const method = (options.method || 'GET').toUpperCase()
36
- if (method === 'GET') {
37
- const params = options.params || {}
38
- const q = new URLSearchParams()
39
- for (const [k, v] of Object.entries(params)) {
40
- if (v == null) continue
41
- q.set(k, String(v))
42
- }
43
- const qs = q.toString()
44
- return request(qs ? `${url}?${qs}` : url)
45
- }
46
-
47
- return request(url, {
48
- method,
49
- body: JSON.stringify(stripTimeMeta(options.data ?? {})),
50
- })
51
- }
52
-
53
- page(data: Record<string, unknown> = {}) {
54
- return this.request({ url: '/page', method: 'POST', data }) as Promise<{
55
- list: Record<string, unknown>[]
56
- pagination: { page: number; size: number; total: number }
57
- }>
58
- }
59
-
60
- list(data: Record<string, unknown> = {}) {
61
- return this.request({
62
- url: '/list',
63
- method: 'POST',
64
- data,
65
- }) as Promise<Record<string, unknown>[]>
66
- }
67
-
68
- info(params: { id: number | string }) {
69
- return this.request({
70
- url: '/info',
71
- method: 'GET',
72
- params: params as Record<string, unknown>,
73
- }) as Promise<Record<string, unknown>>
74
- }
75
-
76
- add(data: Record<string, unknown> | Record<string, unknown>[]) {
77
- return this.request({ url: '/add', method: 'POST', data })
78
- }
79
-
80
- update(data: Record<string, unknown> | Record<string, unknown>[]) {
81
- return this.request({ url: '/update', method: 'POST', data })
82
- }
83
-
84
- delete(
85
- data:
86
- | { ids: Array<number | string>; force?: boolean }
87
- | Array<number | string>
88
- | Array<Record<string, unknown>>,
89
- ) {
90
- return this.request({ url: '/delete', method: 'POST', data })
91
- }
92
-
93
- restore(data: { ids: Array<number | string> }) {
94
- return this.request({ url: '/restore', method: 'POST', data })
95
- }
96
- }
@@ -1,413 +0,0 @@
1
- import { loadEps } from '../lib/eps'
2
- import { BaseService } from './base'
3
-
4
- const SIDE_ID = 'admin'
5
-
6
- /**
7
- * 每次发版递增。globalThis 单例若跨 HMR/旧包残留,靠此戳强制换新根对象并重建。
8
- * 根因:旧 singleton 只有 CRUD、无 tree/roleMap,且 plugin-info 错名导致 base.plugin 缺失。
9
- */
10
- const SERVICE_BUILD = 9
11
-
12
- /** 标准 CRUD 之外的常用接口(不依赖 EPS 是否已返回) */
13
- const FALLBACK_EXTRA_APIS: Record<
14
- string,
15
- Array<{ method: string; path: string; perms?: string[] }>
16
- > = {
17
- '/admin/base/department': [{ method: 'get', path: '/tree' }],
18
- '/admin/base/menu': [{ method: 'get', path: '/tree' }],
19
- '/admin/base/role': [
20
- { method: 'get', path: '/menus' },
21
- { method: 'post', path: '/setMenus' },
22
- { method: 'get', path: '/departments' },
23
- { method: 'post', path: '/setDepartments' },
24
- ],
25
- '/admin/base/user': [
26
- { method: 'get', path: '/roles' },
27
- { method: 'get', path: '/roleMap' },
28
- { method: 'post', path: '/setRoles' },
29
- { method: 'post', path: '/transferSuper' },
30
- { method: 'post', path: '/moveDepartment' },
31
- ],
32
- '/admin/base/task': [
33
- { method: 'post', path: '/start' },
34
- { method: 'post', path: '/stop' },
35
- { method: 'post', path: '/once' },
36
- { method: 'get', path: '/log' },
37
- ],
38
- '/admin/base/log': [
39
- { method: 'post', path: '/clear' },
40
- { method: 'post', path: '/setKeep' },
41
- { method: 'post', path: '/getKeep' },
42
- ],
43
- '/admin/base/dict/info': [
44
- { method: 'get', path: '/types' },
45
- { method: 'post', path: '/data' },
46
- { method: 'post', path: '/get' },
47
- { method: 'post', path: '/find' },
48
- { method: 'post', path: '/getValues' },
49
- { method: 'post', path: '/pathValue' },
50
- { method: 'post', path: '/childValue' },
51
- ],
52
- '/admin/base/module': [{ method: 'post', path: '/install' }],
53
- '/admin/base/comm': [{ method: 'post', path: '/upload' }],
54
- '/admin/user/info': [
55
- { method: 'get', path: '/roles' },
56
- { method: 'get', path: '/roleMap' },
57
- { method: 'post', path: '/setRoles' },
58
- ],
59
- }
60
-
61
- const FALLBACK_PREFIXES = [
62
- '/admin/base/menu',
63
- '/admin/base/user',
64
- '/admin/base/role',
65
- '/admin/base/department',
66
- '/admin/base/tenant',
67
- '/admin/base/task',
68
- '/admin/base/log',
69
- '/admin/base/plugin',
70
- '/admin/base/dict/info',
71
- '/admin/base/dict/type',
72
- '/admin/base/module',
73
- '/admin/base/comm',
74
- '/admin/user/info',
75
- '/admin/user/role',
76
- ]
77
-
78
- function toCamel(str: string) {
79
- return str.replace(/([^-])(?:-+([^-]))/g, (_m, a, b) => a + String(b).toUpperCase())
80
- }
81
-
82
- function methodName(path: string) {
83
- return path.replace(/^\//, '').replace(/[:,\s/-]/g, '')
84
- }
85
-
86
- function isValidName(name: string) {
87
- return Boolean(name) && !['{', '}', ':'].some((c) => name.includes(c))
88
- }
89
-
90
- function resolvePermCode(prefix: string, action: string) {
91
- const parts = prefix.replace(/^\//, '').split('/').filter(Boolean)
92
- const module = parts[1] || parts[0] || 'base'
93
- let resource = parts.slice(2).join(':')
94
- if (resource === module) {
95
- resource = module
96
- } else if (resource.startsWith(`${module}:`)) {
97
- resource = resource.slice(module.length + 1)
98
- }
99
- const head = `${module}-`
100
- if (resource.startsWith(head)) resource = resource.slice(head.length)
101
- resource = resource.replace(/-/g, ':')
102
- if (!resource) resource = module
103
- return `${module}:${resource}:${action}`
104
- }
105
-
106
- function prefixToParts(prefix: string) {
107
- const raw = prefix.replace(/^\//, '')
108
- return raw
109
- .replace(new RegExp(`^${SIDE_ID}/?`), '')
110
- .split('/')
111
- .filter(Boolean)
112
- .map(toCamel)
113
- }
114
-
115
- function bindCrud(leaf: ServiceLeaf, base: BaseService) {
116
- const proto = BaseService.prototype as unknown as Record<string, unknown>
117
- for (const name of [
118
- 'request',
119
- 'page',
120
- 'list',
121
- 'info',
122
- 'add',
123
- 'update',
124
- 'delete',
125
- 'restore',
126
- ]) {
127
- const fn = proto[name]
128
- if (typeof fn === 'function') {
129
- ;(leaf as Record<string, unknown>)[name] = (
130
- fn as (...a: unknown[]) => unknown
131
- ).bind(base)
132
- }
133
- }
134
- }
135
-
136
- function bindApis(leaf: ServiceLeaf, base: BaseService, apis: EpsApiItem[]) {
137
- leaf.permission ||= {}
138
- for (const api of apis) {
139
- const name = methodName(api.path)
140
- if (!isValidName(name) || /[-:]/g.test(name)) continue
141
- const method = (api.method || 'get').toLowerCase()
142
- ;(leaf as Record<string, unknown>)[name] = function (
143
- this: BaseService,
144
- data?: unknown,
145
- ) {
146
- return this.request({
147
- url: api.path.startsWith('/') ? api.path : `/${api.path}`,
148
- method,
149
- [method === 'post' ? 'data' : 'params']: data,
150
- })
151
- }.bind(base)
152
- leaf.permission[name] =
153
- api.perms?.[0] || resolvePermCode(`/${leaf.namespace}`, name)
154
- }
155
- }
156
-
157
- /** 原地重挂方法,保持叶子对象引用不变(避免页面 const log = service.base.log 失效) */
158
- function remountLeaf(leaf: ServiceLeaf, namespace: string, apis: EpsApiItem[]) {
159
- const ns = namespace.replace(/^\//, '')
160
- const base = new BaseService(ns)
161
- leaf.namespace = ns
162
- leaf.permission = {}
163
- leaf._permission = leaf._permission || {}
164
-
165
- // 清掉旧方法再绑,避免残留错误实现
166
- for (const key of Object.keys(leaf as object)) {
167
- if (
168
- key === 'namespace' ||
169
- key === 'permission' ||
170
- key === '_permission' ||
171
- key === 'search'
172
- ) {
173
- continue
174
- }
175
- delete (leaf as Record<string, unknown>)[key]
176
- }
177
-
178
- bindCrud(leaf, base)
179
- bindApis(leaf, base, apis)
180
-
181
- for (const name of Object.keys(leaf.permission)) {
182
- if (leaf._permission[name] == null) leaf._permission[name] = false
183
- }
184
- return leaf
185
- }
186
-
187
- function createLeaf(namespace: string, apis: EpsApiItem[] = []): ServiceLeaf {
188
- const ns = namespace.replace(/^\//, '')
189
- const base = new BaseService(ns)
190
- const leaf = base as unknown as ServiceLeaf
191
- leaf.namespace = ns
192
- leaf.permission = {}
193
- leaf._permission = {}
194
- bindCrud(leaf, base)
195
- bindApis(leaf, base, apis)
196
- return leaf
197
- }
198
-
199
- function attachLeaf(
200
- tree: ServiceTree | Eps.Service,
201
- prefix: string,
202
- apis: EpsApiItem[] = [],
203
- ) {
204
- const raw = prefix.replace(/^\//, '')
205
- const arr = prefixToParts(prefix)
206
- if (!arr.length) return undefined
207
-
208
- let node: Record<string, unknown> = tree as unknown as Record<string, unknown>
209
- for (let i = 0; i < arr.length; i++) {
210
- const key = arr[i]!
211
- const isLast = i === arr.length - 1
212
- if (!isLast) {
213
- const cur = node[key] as ServiceLeaf | Record<string, unknown> | undefined
214
- // 中间节点若被误建成叶子,换成容器(否则 dict/info 挂不上)
215
- if (!cur || typeof cur !== 'object' || 'namespace' in cur) {
216
- node[key] = {}
217
- }
218
- node = node[key] as Record<string, unknown>
219
- continue
220
- }
221
-
222
- const existing = node[key] as ServiceLeaf | undefined
223
- if (existing && typeof existing === 'object' && existing.namespace) {
224
- return remountLeaf(existing, raw, apis)
225
- }
226
- const leaf = createLeaf(raw, apis)
227
- node[key] = leaf
228
- return leaf
229
- }
230
- return undefined
231
- }
232
-
233
- function buildFromEps(map: EpsModuleMap) {
234
- const list = Object.values(map).flat() as EpsEntity[]
235
- for (const e of list) {
236
- if (!e.prefix) continue
237
- const leaf = attachLeaf(service, e.prefix, e.api || [])
238
- if (leaf) {
239
- const op = (e as { pageQueryOp?: Record<string, unknown> }).pageQueryOp
240
- if (op) {
241
- ;(leaf as ServiceLeaf & { search?: unknown }).search = {
242
- fieldEq: op.fieldEq,
243
- fieldLike: op.fieldLike,
244
- fieldArray: op.fieldArray,
245
- fieldRange: op.fieldRange,
246
- keyWordLikeFields: op.keyWordLikeFields,
247
- }
248
- }
249
- }
250
- }
251
- }
252
-
253
- function extraApisOf(prefix: string): EpsApiItem[] {
254
- return (FALLBACK_EXTRA_APIS[prefix] || []).map(
255
- (a) =>
256
- ({
257
- method: a.method,
258
- path: a.path,
259
- perms: a.perms,
260
- }) as EpsApiItem,
261
- )
262
- }
263
-
264
- /**
265
- * 用 fallback 补全:已有叶子则合并补方法(不整棵删,避免打断引用)。
266
- * 对 fallback 前缀:若 EPS 已挂过,只补缺失的 extra;attachLeaf/remount 会重绑整叶。
267
- */
268
- function buildFallback() {
269
- for (const prefix of FALLBACK_PREFIXES) {
270
- const parts = prefixToParts(prefix)
271
- let node: Record<string, unknown> = service as unknown as Record<string, unknown>
272
- let missing = false
273
- for (let i = 0; i < parts.length; i++) {
274
- const key = parts[i]!
275
- if (!node[key]) {
276
- missing = true
277
- break
278
- }
279
- if (i < parts.length - 1) {
280
- node = node[key] as Record<string, unknown>
281
- }
282
- }
283
- const leaf = missing
284
- ? undefined
285
- : (node[parts[parts.length - 1]!] as ServiceLeaf | undefined)
286
-
287
- if (leaf?.namespace) {
288
- // 只补 extra 里还没有的方法,保留 EPS 已绑方法
289
- const extras = extraApisOf(prefix).filter((api) => {
290
- const name = methodName(api.path)
291
- return typeof (leaf as Record<string, unknown>)[name] !== 'function'
292
- })
293
- if (extras.length) {
294
- const base = new BaseService(leaf.namespace)
295
- bindApis(leaf, base, extras)
296
- }
297
- continue
298
- }
299
- attachLeaf(service, prefix, extraApisOf(prefix))
300
- }
301
- }
302
-
303
- type ServiceRoot = Eps.Service & { request: BaseService['request'] }
304
-
305
- const g = globalThis as typeof globalThis & {
306
- __vome_admin_service__?: ServiceRoot
307
- __vome_admin_service_build__?: number
308
- }
309
-
310
- function createServiceRoot(): ServiceRoot {
311
- const root = new BaseService()
312
- return {
313
- request: root.request.bind(root),
314
- } as ServiceRoot
315
- }
316
-
317
- function getOrCreateRoot(): ServiceRoot {
318
- if (
319
- !g.__vome_admin_service__ ||
320
- g.__vome_admin_service_build__ !== SERVICE_BUILD
321
- ) {
322
- g.__vome_admin_service__ = createServiceRoot()
323
- g.__vome_admin_service_build__ = SERVICE_BUILD
324
- }
325
- return g.__vome_admin_service__
326
- }
327
-
328
- /** 全局链式 service(service.base.user.page()) */
329
- export const service: ServiceRoot = getOrCreateRoot()
330
-
331
- buildFallback()
332
-
333
- /** 从 EPS 构建/刷新;再 fallback 补自定义方法 */
334
- export async function createEps(force = false) {
335
- try {
336
- const map = (await loadEps(force)) || {}
337
- if (Object.keys(map).length) buildFromEps(map)
338
- } catch (e) {
339
- console.warn('[vome-eps] load failed', e)
340
- }
341
- buildFallback()
342
- return service
343
- }
344
-
345
- if (import.meta.hot) {
346
- import.meta.hot.on('eps-update', () => {
347
- void createEps(true).then(() => {
348
- if (import.meta.env.DEV) console.log('[vome-eps] service hot updated')
349
- })
350
- })
351
- }
352
-
353
- export function setServicePerms(perms: string[], isSuper = false) {
354
- const list = perms || []
355
-
356
- function deep(d: unknown) {
357
- if (!d || typeof d !== 'object') return
358
- const obj = d as ServiceLeaf & Record<string, unknown>
359
- if (obj.permission && obj.namespace) {
360
- obj._permission = {}
361
- for (const key of Object.keys(obj.permission)) {
362
- if (isSuper) {
363
- obj._permission[key] = true
364
- continue
365
- }
366
- const code = obj.permission[key]
367
- obj._permission[key] =
368
- list.includes(code) ||
369
- list.some((p) =>
370
- p
371
- .replace(/:/g, '/')
372
- .includes(`${obj.namespace.replace(/^admin\//, '')}/${key}`),
373
- )
374
- }
375
- return
376
- }
377
- for (const k of Object.keys(obj)) {
378
- if (k === 'request') continue
379
- deep(obj[k])
380
- }
381
- }
382
-
383
- deep(service)
384
- }
385
-
386
- export function resolveService(path: string): ServiceLeaf | undefined {
387
- const parts = path.replace(/^\//, '').split('.').filter(Boolean)
388
- let cur: unknown = service
389
- for (const p of parts) {
390
- if (!cur || typeof cur !== 'object') return undefined
391
- cur = (cur as Record<string, unknown>)[p]
392
- }
393
- if (cur && typeof cur === 'object' && 'namespace' in (cur as object)) {
394
- return cur as ServiceLeaf
395
- }
396
- return undefined
397
- }
398
-
399
- export function serviceOf(prefix: string): ServiceLeaf {
400
- const raw = prefix.replace(/\/$/, '')
401
- const path = prefixToParts(raw).join('.')
402
- const hit = resolveService(path)
403
- if (hit) return hit
404
- return attachLeaf(service, raw, extraApisOf(raw.startsWith('/') ? raw : `/${raw}`)) as ServiceLeaf
405
- }
406
-
407
- /** @deprecated 请用 service.base.xxx */
408
- export function createEpsService(prefix: string) {
409
- return serviceOf(prefix)
410
- }
411
-
412
- export { BaseService }
413
- export type { ServiceLeaf, ServiceTree } from '../../../typings/admin/comm/service'
@@ -1,30 +0,0 @@
1
- import { defineStore } from 'pinia'
2
- import { nextTick } from 'vue'
3
-
4
- const FOLD_KEY = 'vome_admin_sidebar_fold'
5
-
6
- export const useAppStore = defineStore('app', {
7
- state: () => ({
8
- /** 桌面端手动折叠侧栏 */
9
- sidebarFold: localStorage.getItem(FOLD_KEY) === '1',
10
- /** 移动端抽屉开合 */
11
- mobileOpen: false,
12
- /** 为 false 时卸掉 RouterView,用于「刷新当前页」 */
13
- viewAlive: true,
14
- }),
15
- actions: {
16
- toggleSidebarFold() {
17
- this.sidebarFold = !this.sidebarFold
18
- localStorage.setItem(FOLD_KEY, this.sidebarFold ? '1' : '0')
19
- },
20
- setMobileOpen(open: boolean) {
21
- this.mobileOpen = open
22
- },
23
- /** 重挂载当前视图(非浏览器整页刷新) */
24
- async reloadView() {
25
- this.viewAlive = false
26
- await nextTick()
27
- this.viewAlive = true
28
- },
29
- },
30
- })