vome-core 0.0.1

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 (209) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/server/index.d.ts +1 -0
  4. package/dist/server/index.js +1 -0
  5. package/dist/src/auth/define-macro.d.ts +8 -0
  6. package/dist/src/auth/index.d.ts +2 -0
  7. package/dist/src/comm/daily-log.d.ts +8 -0
  8. package/dist/src/comm/env.d.ts +4 -0
  9. package/dist/src/comm/format-time.d.ts +10 -0
  10. package/dist/src/comm/merge.d.ts +2 -0
  11. package/dist/src/comm/scan.d.ts +4 -0
  12. package/dist/src/comm/startBanner.d.ts +1 -0
  13. package/dist/src/core/app.d.ts +37 -0
  14. package/dist/src/core/config.d.ts +2 -0
  15. package/dist/src/core/context/index.d.ts +22 -0
  16. package/dist/src/core/host-infra.d.ts +20 -0
  17. package/dist/src/core/index.d.ts +20 -0
  18. package/dist/src/core/plugins/async-context.d.ts +3 -0
  19. package/dist/src/core/plugins/error.d.ts +5 -0
  20. package/dist/src/core/plugins/logging.d.ts +3 -0
  21. package/dist/src/core/plugins/openapi.d.ts +3 -0
  22. package/dist/src/core/vome-config.d.ts +2 -0
  23. package/dist/src/ext/base-plugin.d.ts +13 -0
  24. package/dist/src/ext/index.d.ts +15 -0
  25. package/dist/src/ext/load-plugin.d.ts +12 -0
  26. package/dist/src/ext/micro-apps.d.ts +60 -0
  27. package/dist/src/ext/module-gateway.d.ts +10 -0
  28. package/dist/src/ext/module-registry.d.ts +45 -0
  29. package/dist/src/ext/path.d.ts +8 -0
  30. package/dist/src/index.d.ts +10 -0
  31. package/dist/src/ioc/container.d.ts +29 -0
  32. package/dist/src/ioc/decorators.d.ts +35 -0
  33. package/dist/src/ioc/host.d.ts +2 -0
  34. package/dist/src/ioc/index.d.ts +6 -0
  35. package/dist/src/ioc/metadata.d.ts +12 -0
  36. package/dist/src/ioc/scope.d.ts +9 -0
  37. package/dist/src/logger/bootstrap.d.ts +2 -0
  38. package/dist/src/logger/exception.d.ts +22 -0
  39. package/dist/src/logger/index.d.ts +5 -0
  40. package/dist/src/logger/logger.d.ts +18 -0
  41. package/dist/src/logger/pino.d.ts +8 -0
  42. package/dist/src/orm/base-columns.d.ts +11 -0
  43. package/dist/src/orm/column-comments.d.ts +25 -0
  44. package/dist/src/orm/crud-config.d.ts +7 -0
  45. package/dist/src/orm/crud-register.d.ts +5 -0
  46. package/dist/src/orm/data-scope.d.ts +24 -0
  47. package/dist/src/orm/db-store.d.ts +12 -0
  48. package/dist/src/orm/entity-schema.d.ts +7 -0
  49. package/dist/src/orm/index.d.ts +22 -0
  50. package/dist/src/orm/query-builder.d.ts +12 -0
  51. package/dist/src/orm/query-op.d.ts +27 -0
  52. package/dist/src/orm/repository.d.ts +74 -0
  53. package/dist/src/orm/service.d.ts +71 -0
  54. package/dist/src/orm/tenant.d.ts +24 -0
  55. package/dist/src/routing/base.d.ts +27 -0
  56. package/dist/src/routing/context.d.ts +14 -0
  57. package/dist/src/routing/crud-summary.d.ts +2 -0
  58. package/dist/src/routing/decorators.d.ts +48 -0
  59. package/dist/src/routing/eps.d.ts +16 -0
  60. package/dist/src/routing/index.d.ts +8 -0
  61. package/dist/src/routing/metadata.d.ts +28 -0
  62. package/dist/src/routing/openapi-tags.d.ts +23 -0
  63. package/dist/src/routing/path-utils.d.ts +5 -0
  64. package/dist/src/routing/perm.d.ts +18 -0
  65. package/dist/src/routing/register.d.ts +7 -0
  66. package/dist/src/server/index.d.ts +10 -0
  67. package/dist/src/shared/index.d.ts +8 -0
  68. package/dist/src/shared/tree.d.ts +18 -0
  69. package/dist/typings/comm/crud.d.ts +24 -0
  70. package/dist/typings/comm/page.d.ts +16 -0
  71. package/dist/typings/comm/scan.d.ts +6 -0
  72. package/dist/typings/common.d.ts +6 -0
  73. package/dist/typings/context/data.d.ts +10 -0
  74. package/dist/typings/ext/module.d.ts +45 -0
  75. package/dist/typings/ext/plugin.d.ts +40 -0
  76. package/dist/typings/ioc/metadata.d.ts +31 -0
  77. package/dist/typings/logger/config.d.ts +6 -0
  78. package/dist/typings/routing/crud.d.ts +99 -0
  79. package/dist/typings/routing/eps.d.ts +53 -0
  80. package/dist/typings/routing/meta.d.ts +56 -0
  81. package/dist/typings/routing/register.d.ts +15 -0
  82. package/dist/typings/routing/scan-context.d.ts +6 -0
  83. package/package.json +96 -0
  84. package/src/admin/api/client.ts +184 -0
  85. package/src/admin/components/vm-aside.vue +227 -0
  86. package/src/admin/components/vm-auto-perm-dialog.vue +361 -0
  87. package/src/admin/components/vm-check-tree.vue +338 -0
  88. package/src/admin/components/vm-dept-tree.vue +549 -0
  89. package/src/admin/components/vm-empty.vue +62 -0
  90. package/src/admin/components/vm-eps-perm-picker.vue +114 -0
  91. package/src/admin/components/vm-group-cascader.vue +563 -0
  92. package/src/admin/components/vm-icon-picker.vue +616 -0
  93. package/src/admin/components/vm-markdown.vue +141 -0
  94. package/src/admin/components/vm-ri-icon.vue +21 -0
  95. package/src/admin/components/vm-role-picker.vue +314 -0
  96. package/src/admin/components/vm-view-path-picker.vue +56 -0
  97. package/src/admin/config/plugin-dev.ts +31 -0
  98. package/src/admin/crud/components/vm-column-custom.vue +196 -0
  99. package/src/admin/crud/components/vm-context-menu.vue +99 -0
  100. package/src/admin/crud/components/vm-date-picker.vue +74 -0
  101. package/src/admin/crud/components/vm-date-range.vue +291 -0
  102. package/src/admin/crud/components/vm-date-text.vue +41 -0
  103. package/src/admin/crud/components/vm-dict-tag.vue +47 -0
  104. package/src/admin/crud/components/vm-file-icon.vue +54 -0
  105. package/src/admin/crud/components/vm-multi-select.vue +181 -0
  106. package/src/admin/crud/components/vm-number-range.vue +200 -0
  107. package/src/admin/crud/components/vm-radio.vue +87 -0
  108. package/src/admin/crud/components/vm-select.vue +131 -0
  109. package/src/admin/crud/components/vm-switch.vue +128 -0
  110. package/src/admin/crud/components/vm-tree-select.vue +456 -0
  111. package/src/admin/crud/components/vm-upload-item.vue +215 -0
  112. package/src/admin/crud/components/vm-upload.vue +323 -0
  113. package/src/admin/crud/components/vm-user-select.vue +234 -0
  114. package/src/admin/crud/config.ts +38 -0
  115. package/src/admin/crud/confirm.ts +135 -0
  116. package/src/admin/crud/dict.ts +49 -0
  117. package/src/admin/crud/index.ts +79 -0
  118. package/src/admin/crud/key.ts +47 -0
  119. package/src/admin/crud/mitt.ts +27 -0
  120. package/src/admin/crud/plugins.ts +298 -0
  121. package/src/admin/crud/registry.ts +45 -0
  122. package/src/admin/crud/span.ts +48 -0
  123. package/src/admin/crud/style.ts +112 -0
  124. package/src/admin/crud/useCrud.ts +81 -0
  125. package/src/admin/crud/validate.ts +109 -0
  126. package/src/admin/crud/vm-add-btn.vue +68 -0
  127. package/src/admin/crud/vm-adv-search.vue +73 -0
  128. package/src/admin/crud/vm-crud.vue +517 -0
  129. package/src/admin/crud/vm-dialog.vue +234 -0
  130. package/src/admin/crud/vm-flex1.vue +14 -0
  131. package/src/admin/crud/vm-form.vue +239 -0
  132. package/src/admin/crud/vm-multi-delete-btn.vue +48 -0
  133. package/src/admin/crud/vm-pagination.vue +125 -0
  134. package/src/admin/crud/vm-refresh-btn.vue +34 -0
  135. package/src/admin/crud/vm-row.vue +42 -0
  136. package/src/admin/crud/vm-search-key.vue +76 -0
  137. package/src/admin/crud/vm-search.vue +367 -0
  138. package/src/admin/crud/vm-table.vue +852 -0
  139. package/src/admin/crud/vm-toolbar.vue +245 -0
  140. package/src/admin/crud/vm-upsert.vue +530 -0
  141. package/src/admin/data/remixicon-all.json +1 -0
  142. package/src/admin/directives/perm.ts +18 -0
  143. package/src/admin/env.d.ts +5 -0
  144. package/src/admin/hooks/useBrowser.ts +27 -0
  145. package/src/admin/hooks/useUpload.ts +82 -0
  146. package/src/admin/hooks/useVome.ts +13 -0
  147. package/src/admin/index.ts +59 -0
  148. package/src/admin/lib/browser.ts +28 -0
  149. package/src/admin/lib/cn.ts +7 -0
  150. package/src/admin/lib/dialog-float.ts +14 -0
  151. package/src/admin/lib/eps.ts +43 -0
  152. package/src/admin/lib/menu.ts +15 -0
  153. package/src/admin/lib/module.ts +112 -0
  154. package/src/admin/lib/tree.ts +2 -0
  155. package/src/admin/lib/upload.ts +102 -0
  156. package/src/admin/router/index.ts +61 -0
  157. package/src/admin/router/menu-routes.ts +126 -0
  158. package/src/admin/service/base.ts +96 -0
  159. package/src/admin/service/index.ts +281 -0
  160. package/src/admin/static/fileicon/demo.css +539 -0
  161. package/src/admin/static/fileicon/demo_index.html +901 -0
  162. package/src/admin/static/fileicon/iconfont.css +139 -0
  163. package/src/admin/static/fileicon/iconfont.js +1 -0
  164. package/src/admin/static/fileicon/iconfont.json +226 -0
  165. package/src/admin/static/fileicon/iconfont.ttf +0 -0
  166. package/src/admin/static/fileicon/iconfont.woff +0 -0
  167. package/src/admin/static/fileicon/iconfont.woff2 +0 -0
  168. package/src/admin/static/scarce//344/270/213/350/275/275/345/244/261/350/264/245.svg +1 -0
  169. package/src/admin/static/scarce//346/224/257/344/273/230/346/210/220/345/212/237.svg +1 -0
  170. package/src/admin/static/scarce//346/232/202/346/227/240/344/274/230/346/203/240/345/210/270.svg +1 -0
  171. package/src/admin/static/scarce//346/232/202/346/227/240/345/206/205/345/256/271.svg +1 -0
  172. package/src/admin/static/scarce//346/232/202/346/227/240/345/217/221/347/245/250.svg +1 -0
  173. package/src/admin/static/scarce//346/232/202/346/227/240/345/233/276/347/211/207.svg +1 -0
  174. package/src/admin/static/scarce//346/232/202/346/227/240/345/234/260/345/235/200.svg +1 -0
  175. package/src/admin/static/scarce//346/232/202/346/227/240/345/272/227/351/223/272.svg +1 -0
  176. package/src/admin/static/scarce//346/232/202/346/227/240/346/216/250/351/200/201.svg +1 -0
  177. package/src/admin/static/scarce//346/232/202/346/227/240/346/220/234/347/264/242/347/273/223/346/236/234.svg +1 -0
  178. package/src/admin/static/scarce//346/232/202/346/227/240/346/224/266/350/227/217.svg +1 -0
  179. package/src/admin/static/scarce//346/232/202/346/227/240/346/225/260/346/215/256.svg +1 -0
  180. package/src/admin/static/scarce//346/232/202/346/227/240/346/235/203/351/231/220.svg +1 -0
  181. package/src/admin/static/scarce//346/232/202/346/227/240/346/266/210/346/201/257.svg +1 -0
  182. package/src/admin/static/scarce//346/232/202/346/227/240/347/244/274/347/211/251.svg +1 -0
  183. package/src/admin/static/scarce//346/232/202/346/227/240/347/247/257/345/210/206.svg +1 -0
  184. package/src/admin/static/scarce//346/232/202/346/227/240/347/275/221/347/273/234.svg +1 -0
  185. package/src/admin/static/scarce//346/232/202/346/227/240/350/247/206/351/242/221.svg +1 -0
  186. package/src/admin/static/scarce//346/232/202/346/227/240/350/256/242/345/215/225.svg +1 -0
  187. package/src/admin/static/scarce//346/232/202/346/227/240/350/257/204/350/256/272.svg +1 -0
  188. package/src/admin/static/scarce//346/232/202/346/227/240/351/205/215/351/200/201.svg +1 -0
  189. package/src/admin/static/scarce//346/232/202/346/227/240/351/223/266/350/241/214/345/215/241.svg +1 -0
  190. package/src/admin/static/scarce//346/232/202/346/227/240/351/237/263/344/271/220.svg +1 -0
  191. package/src/admin/static/scarce//351/241/265/351/235/242/344/270/215/345/255/230/345/234/250.svg +1 -0
  192. package/src/admin/stores/app.ts +30 -0
  193. package/src/admin/stores/tags.ts +73 -0
  194. package/src/admin/stores/user.ts +52 -0
  195. package/src/admin/styles/base.css +137 -0
  196. package/src/admin/tsconfig.json +19 -0
  197. package/typings/admin/base/auth.ts +23 -0
  198. package/typings/admin/base/permission.ts +19 -0
  199. package/typings/admin/comm/cascader.ts +7 -0
  200. package/typings/admin/comm/check-tree.ts +7 -0
  201. package/typings/admin/comm/crud.ts +294 -0
  202. package/typings/admin/comm/eps.ts +52 -0
  203. package/typings/admin/comm/request.ts +12 -0
  204. package/typings/admin/comm/service.ts +35 -0
  205. package/typings/admin/comm/upload.ts +39 -0
  206. package/typings/admin/host.d.ts +61 -0
  207. package/typings/admin/vome/browser.ts +11 -0
  208. package/typings/admin/vome/module.ts +13 -0
  209. package/typings/admin/vome/tags.ts +9 -0
@@ -0,0 +1,281 @@
1
+ import { loadEps } from '../lib/eps'
2
+ import { BaseService } from './base'
3
+ const SIDE_ID = 'admin'
4
+
5
+ /** EPS 不可用时仍保证业务页链式可调 */
6
+ const FALLBACK_PREFIXES = [
7
+ '/admin/base/menu',
8
+ '/admin/base/user',
9
+ '/admin/base/role',
10
+ '/admin/base/department',
11
+ '/admin/base/tenant',
12
+ '/admin/base/task',
13
+ '/admin/base/log',
14
+ '/admin/base/plugin-info',
15
+ '/admin/user/user-role',
16
+ ]
17
+
18
+ function toCamel(str: string) {
19
+ return str.replace(/([^-])(?:-+([^-]))/g, (_m, a, b) => a + String(b).toUpperCase())
20
+ }
21
+
22
+ function methodName(path: string) {
23
+ return path.replace(/^\//, '').replace(/[:,\s/-]/g, '')
24
+ }
25
+
26
+ function isValidName(name: string) {
27
+ return Boolean(name) && !['{', '}', ':'].some((c) => name.includes(c))
28
+ }
29
+
30
+ /** 无 EPS perms 时生成权限码 */
31
+ function resolvePermCode(prefix: string, action: string) {
32
+ const parts = prefix.replace(/^\//, '').split('/').filter(Boolean)
33
+ // admin / module / resource...
34
+ const module = parts[1] || parts[0] || 'base'
35
+ let resource = parts.slice(2).join(':')
36
+ if (resource === module) {
37
+ resource = module
38
+ } else if (resource.startsWith(`${module}:`)) {
39
+ resource = resource.slice(module.length + 1)
40
+ }
41
+ const head = `${module}-`
42
+ if (resource.startsWith(head)) resource = resource.slice(head.length)
43
+ resource = resource.replace(/-/g, ':')
44
+ if (!resource) resource = module
45
+ return `${module}:${resource}:${action}`
46
+ }
47
+
48
+ function getMethodKeys(leaf: Record<string, unknown>) {
49
+ return Object.keys(leaf).filter(
50
+ (k) => !['namespace', 'permission', '_permission', 'request', 'search'].includes(k),
51
+ )
52
+ }
53
+
54
+ function createLeaf(namespace: string, apis: EpsApiItem[] = []): ServiceLeaf {
55
+ const base = new BaseService(namespace)
56
+ const leaf = base as unknown as ServiceLeaf
57
+ leaf.namespace = namespace.replace(/^\//, '')
58
+ leaf.permission = {}
59
+ leaf._permission = {}
60
+
61
+ // 挂到实例自身,避免业务侧 `...leaf` 丢失原型方法
62
+ const proto = BaseService.prototype as unknown as Record<string, unknown>
63
+ for (const name of [
64
+ 'request',
65
+ 'page',
66
+ 'list',
67
+ 'info',
68
+ 'add',
69
+ 'update',
70
+ 'delete',
71
+ 'restore',
72
+ ]) {
73
+ const fn = proto[name]
74
+ if (typeof fn === 'function') {
75
+ ;(leaf as Record<string, unknown>)[name] = (fn as (...a: unknown[]) => unknown).bind(base)
76
+ }
77
+ }
78
+
79
+ for (const api of apis) {
80
+ const name = methodName(api.path)
81
+ if (!isValidName(name) || /[-:]/g.test(name)) continue
82
+ const method = (api.method || 'get').toLowerCase()
83
+ leaf[name] = function (this: BaseService, data?: unknown) {
84
+ return this.request({
85
+ url: api.path.startsWith('/') ? api.path : `/${api.path}`,
86
+ method,
87
+ [method === 'post' ? 'data' : 'params']: data,
88
+ })
89
+ }.bind(base)
90
+ leaf.permission[name] =
91
+ api.perms?.[0] || resolvePermCode(`/${leaf.namespace}`, name)
92
+ }
93
+
94
+ // 标准 CRUD 权限兜底(EPS 未列时仍有码)
95
+ for (const name of getMethodKeys(leaf as unknown as Record<string, unknown>)) {
96
+ if (!leaf.permission[name]) {
97
+ leaf.permission[name] = resolvePermCode(`/${leaf.namespace}`, name)
98
+ }
99
+ }
100
+
101
+ return leaf
102
+ }
103
+
104
+ function attachLeaf(tree: ServiceTree | Eps.Service, prefix: string, apis: EpsApiItem[] = []) {
105
+ const raw = prefix.replace(/^\//, '')
106
+ const arr = raw
107
+ .replace(new RegExp(`^${SIDE_ID}/?`), '')
108
+ .split('/')
109
+ .filter(Boolean)
110
+ .map(toCamel)
111
+
112
+ if (!arr.length) return undefined
113
+
114
+ let node: Record<string, unknown> = tree as unknown as Record<string, unknown>
115
+ for (let i = 0; i < arr.length; i++) {
116
+ const key = arr[i]!
117
+ const isLast = i === arr.length - 1
118
+ if (!isLast) {
119
+ if (!node[key] || typeof node[key] !== 'object') node[key] = {}
120
+ node = node[key] as Record<string, unknown>
121
+ continue
122
+ }
123
+ const existing = node[key] as ServiceLeaf | undefined
124
+ if (existing?.namespace) {
125
+ // 已有叶子:补方法
126
+ const next = createLeaf(raw, apis)
127
+ Object.assign(existing, next)
128
+ return existing
129
+ }
130
+ const leaf = createLeaf(raw, apis)
131
+ node[key] = leaf
132
+ return leaf
133
+ }
134
+ return undefined
135
+ }
136
+
137
+ function buildFromEps(map: EpsModuleMap) {
138
+ const list = Object.values(map).flat() as EpsEntity[]
139
+ for (const e of list) {
140
+ if (!e.prefix) continue
141
+ const leaf = attachLeaf(service, e.prefix, e.api || [])
142
+ if (leaf) {
143
+ const op = (e as { pageQueryOp?: Record<string, unknown> }).pageQueryOp
144
+ if (op) {
145
+ ;(leaf as ServiceLeaf & { search?: unknown }).search = {
146
+ fieldEq: op.fieldEq,
147
+ fieldLike: op.fieldLike,
148
+ fieldArray: op.fieldArray,
149
+ fieldRange: op.fieldRange,
150
+ keyWordLikeFields: op.keyWordLikeFields,
151
+ }
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ function buildFallback() {
158
+ for (const prefix of FALLBACK_PREFIXES) {
159
+ const path = prefix.replace(/^\//, '')
160
+ const arr = path
161
+ .replace(new RegExp(`^${SIDE_ID}/?`), '')
162
+ .split('/')
163
+ .filter(Boolean)
164
+ .map(toCamel)
165
+ let node: Record<string, unknown> = service as unknown as Record<string, unknown>
166
+ let exists = true
167
+ for (let i = 0; i < arr.length; i++) {
168
+ const key = arr[i]!
169
+ if (!node[key]) {
170
+ exists = false
171
+ break
172
+ }
173
+ node = node[key] as Record<string, unknown>
174
+ }
175
+ if (!exists || !(node as ServiceLeaf).namespace) {
176
+ attachLeaf(service, prefix)
177
+ }
178
+ }
179
+ }
180
+
181
+ const root = new BaseService()
182
+
183
+ /** 全局链式 service(service.base.user.page()) */
184
+ export const service = {
185
+ request: root.request.bind(root),
186
+ } as unknown as Eps.Service
187
+
188
+ // 同步兜底,保证页面 import 时即可 service.base.xxx
189
+ buildFallback()
190
+
191
+ /** 从 EPS 构建/刷新 service 树;失败时用兜底 prefix */
192
+ export async function createEps(force = false) {
193
+ try {
194
+ const map = (await loadEps(force)) || {}
195
+ if (Object.keys(map).length) buildFromEps(map)
196
+ } catch (e) {
197
+ console.warn('[vome-eps] load failed', e)
198
+ }
199
+ buildFallback()
200
+ return service
201
+ }
202
+
203
+ // Vite 保存源码 / 刷新时:插件重拉 EPS 后通知客户端热更新 service 树
204
+ if (import.meta.hot) {
205
+ import.meta.hot.on('eps-update', () => {
206
+ void createEps(true).then(() => {
207
+ if (import.meta.env.DEV) console.log('[vome-eps] service hot updated')
208
+ })
209
+ })
210
+ }
211
+
212
+ /** 登录后写入 _permission,供 CRUD / 按钮显隐 */
213
+ export function setServicePerms(perms: string[], isSuper = false) {
214
+ const list = perms || []
215
+
216
+ function deep(d: unknown) {
217
+ if (!d || typeof d !== 'object') return
218
+ const obj = d as ServiceLeaf & Record<string, unknown>
219
+ if (obj.permission && obj.namespace) {
220
+ obj._permission = {}
221
+ for (const key of Object.keys(obj.permission)) {
222
+ if (isSuper) {
223
+ obj._permission[key] = true
224
+ continue
225
+ }
226
+ const code = obj.permission[key]
227
+ obj._permission[key] =
228
+ list.includes(code) ||
229
+ list.some((p) =>
230
+ p
231
+ .replace(/:/g, '/')
232
+ .includes(`${obj.namespace.replace(/^admin\//, '')}/${key}`),
233
+ )
234
+ }
235
+ return
236
+ }
237
+ for (const k of Object.keys(obj)) {
238
+ if (k === 'request') continue
239
+ deep(obj[k])
240
+ }
241
+ }
242
+
243
+ deep(service)
244
+ }
245
+
246
+ /** 解析 service.base.user 或 'base.user' */
247
+ export function resolveService(path: string): ServiceLeaf | undefined {
248
+ const parts = path.replace(/^\//, '').split('.').filter(Boolean)
249
+ let cur: unknown = service
250
+ for (const p of parts) {
251
+ if (!cur || typeof cur !== 'object') return undefined
252
+ cur = (cur as Record<string, unknown>)[p]
253
+ }
254
+ if (cur && typeof cur === 'object' && 'namespace' in (cur as object)) {
255
+ return cur as ServiceLeaf
256
+ }
257
+ return undefined
258
+ }
259
+
260
+ /** 按 prefix 取或创建 service 叶子 */
261
+ export function serviceOf(prefix: string): ServiceLeaf {
262
+ const raw = prefix.replace(/\/$/, '')
263
+ const path = raw
264
+ .replace(/^\//, '')
265
+ .replace(new RegExp(`^${SIDE_ID}/?`), '')
266
+ .split('/')
267
+ .filter(Boolean)
268
+ .map(toCamel)
269
+ .join('.')
270
+ const hit = resolveService(path)
271
+ if (hit) return hit
272
+ return attachLeaf(service, raw) as ServiceLeaf
273
+ }
274
+
275
+ /** @deprecated 请用 service.base.xxx */
276
+ export function createEpsService(prefix: string) {
277
+ return serviceOf(prefix)
278
+ }
279
+
280
+ export { BaseService }
281
+ export type { ServiceLeaf, ServiceTree } from '../../../typings/admin/comm/service'