@epxing/utils 0.0.0-stage → 5.3.0-beta.2

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 (230) hide show
  1. package/API.md +602 -0
  2. package/README.md +22 -2
  3. package/dist/_vendor/.pnpm/jsencrypt@3.5.4/_vendor/jsencrypt/bin/jsencrypt.min.js +1691 -0
  4. package/dist/_virtual/_commonjsHelpers.js +6 -0
  5. package/dist/_virtual/jsencrypt.min.js +31 -0
  6. package/dist/_virtual/jsencrypt.min2.js +4 -0
  7. package/dist/_virtual/preload-helper.js +88 -0
  8. package/dist/assets/ai-BBFn3QRy.png +0 -0
  9. package/dist/assets/ai_import-BxQ7Ohn6.png +0 -0
  10. package/dist/assets/app-DBNIokDP.png +0 -0
  11. package/dist/assets/approval-DGcBv-re.png +0 -0
  12. package/dist/assets/create_market_system-BH__UVbt.png +0 -0
  13. package/dist/assets/create_system-irg--ePh.png +0 -0
  14. package/dist/assets/custom-C-ujlHz1.png +0 -0
  15. package/dist/assets/default-icon-2193FMjv.png +0 -0
  16. package/dist/assets/ex_link-4fYPd9nh.png +0 -0
  17. package/dist/assets/excel-BYqRm2Y8.png +0 -0
  18. package/dist/assets/folder-CFVsNbjj.png +0 -0
  19. package/dist/assets/form-DD9HV-jN.png +0 -0
  20. package/dist/assets/import-tfKWbWVS.png +0 -0
  21. package/dist/assets/meta-Qorpi70B.png +0 -0
  22. package/dist/assets/module-DQrs7VAS.png +0 -0
  23. package/dist/assets/null-B2An29h4.png +0 -0
  24. package/dist/assets/option-CG02tIgh.svg +1 -0
  25. package/dist/assets/photo-uscRzRXF.png +0 -0
  26. package/dist/assets/process-Dcndu9m2.png +0 -0
  27. package/dist/assets/rule-DcYhYse0.png +0 -0
  28. package/dist/assets/service-CLYLpPl3.png +0 -0
  29. package/dist/assets/single_file-B3TJtJli.png +0 -0
  30. package/dist/assets/snapshot-history-BsVY9cVj.png +0 -0
  31. package/dist/assets/snapshot-manual-DBRfFHYI.png +0 -0
  32. package/dist/assets/snapshot-realtime-DjHnJI6C.png +0 -0
  33. package/dist/assets/staff-Bn_-_00l.png +0 -0
  34. package/dist/assets/sync_append-Bm8mtvZs.png +0 -0
  35. package/dist/assets/sync_append_update-DzjxqJ_U.png +0 -0
  36. package/dist/assets/sync_loading-D7LoNPFP.png +0 -0
  37. package/dist/assets/sync_replace-Cbbzz327.png +0 -0
  38. package/dist/assets/sync_update-Birao6Cr.png +0 -0
  39. package/dist/assets/userRole-D1LAdM6N.png +0 -0
  40. package/dist/assets/user_bg-BFHtaZjz.png +0 -0
  41. package/dist/src/Config.js +25 -0
  42. package/dist/src/asset-images.js +125 -0
  43. package/dist/src/assets/images/add.png.js +4 -0
  44. package/dist/src/assets/images/ai-button.png.js +4 -0
  45. package/dist/src/assets/images/ai.png.js +4 -0
  46. package/dist/src/assets/images/ai_import.png.js +4 -0
  47. package/dist/src/assets/images/app.png.js +4 -0
  48. package/dist/src/assets/images/approval.png.js +4 -0
  49. package/dist/src/assets/images/book.png.js +4 -0
  50. package/dist/src/assets/images/canvas-editor/alignment.svg.js +4 -0
  51. package/dist/src/assets/images/canvas-editor/arrow-left.svg.js +4 -0
  52. package/dist/src/assets/images/canvas-editor/arrow-right.svg.js +4 -0
  53. package/dist/src/assets/images/canvas-editor/block.svg.js +4 -0
  54. package/dist/src/assets/images/canvas-editor/bold.svg.js +4 -0
  55. package/dist/src/assets/images/canvas-editor/catalog.svg.js +4 -0
  56. package/dist/src/assets/images/canvas-editor/center.svg.js +4 -0
  57. package/dist/src/assets/images/canvas-editor/checkbox.svg.js +4 -0
  58. package/dist/src/assets/images/canvas-editor/close.svg.js +4 -0
  59. package/dist/src/assets/images/canvas-editor/codeblock.svg.js +4 -0
  60. package/dist/src/assets/images/canvas-editor/color.svg.js +4 -0
  61. package/dist/src/assets/images/canvas-editor/control.svg.js +4 -0
  62. package/dist/src/assets/images/canvas-editor/date.svg.js +4 -0
  63. package/dist/src/assets/images/canvas-editor/exit-fullscreen.svg.js +4 -0
  64. package/dist/src/assets/images/canvas-editor/format.svg.js +4 -0
  65. package/dist/src/assets/images/canvas-editor/highlight.svg.js +4 -0
  66. package/dist/src/assets/images/canvas-editor/hyperlink.svg.js +4 -0
  67. package/dist/src/assets/images/canvas-editor/image.svg.js +4 -0
  68. package/dist/src/assets/images/canvas-editor/italic.svg.js +4 -0
  69. package/dist/src/assets/images/canvas-editor/justify.svg.js +4 -0
  70. package/dist/src/assets/images/canvas-editor/latex.svg.js +4 -0
  71. package/dist/src/assets/images/canvas-editor/left.svg.js +4 -0
  72. package/dist/src/assets/images/canvas-editor/line-dash-dot-dot.svg.js +4 -0
  73. package/dist/src/assets/images/canvas-editor/line-dash-dot.svg.js +4 -0
  74. package/dist/src/assets/images/canvas-editor/line-dash-large-gap.svg.js +4 -0
  75. package/dist/src/assets/images/canvas-editor/line-dash-small-gap.svg.js +4 -0
  76. package/dist/src/assets/images/canvas-editor/line-dot.svg.js +4 -0
  77. package/dist/src/assets/images/canvas-editor/line-double.svg.js +4 -0
  78. package/dist/src/assets/images/canvas-editor/line-single.svg.js +4 -0
  79. package/dist/src/assets/images/canvas-editor/line-wavy.svg.js +4 -0
  80. package/dist/src/assets/images/canvas-editor/list.svg.js +4 -0
  81. package/dist/src/assets/images/canvas-editor/option.svg.js +4 -0
  82. package/dist/src/assets/images/canvas-editor/page-break.svg.js +4 -0
  83. package/dist/src/assets/images/canvas-editor/page-mode.svg.js +4 -0
  84. package/dist/src/assets/images/canvas-editor/page-scale-add.svg.js +4 -0
  85. package/dist/src/assets/images/canvas-editor/page-scale-minus.svg.js +4 -0
  86. package/dist/src/assets/images/canvas-editor/painter.svg.js +4 -0
  87. package/dist/src/assets/images/canvas-editor/paper-direction.svg.js +4 -0
  88. package/dist/src/assets/images/canvas-editor/paper-margin.svg.js +4 -0
  89. package/dist/src/assets/images/canvas-editor/paper-size.svg.js +4 -0
  90. package/dist/src/assets/images/canvas-editor/print.svg.js +4 -0
  91. package/dist/src/assets/images/canvas-editor/radio.svg.js +4 -0
  92. package/dist/src/assets/images/canvas-editor/redo.svg.js +4 -0
  93. package/dist/src/assets/images/canvas-editor/request-fullscreen.svg.js +4 -0
  94. package/dist/src/assets/images/canvas-editor/right.svg.js +4 -0
  95. package/dist/src/assets/images/canvas-editor/row-margin.svg.js +4 -0
  96. package/dist/src/assets/images/canvas-editor/search.svg.js +4 -0
  97. package/dist/src/assets/images/canvas-editor/separator.svg.js +4 -0
  98. package/dist/src/assets/images/canvas-editor/signature-undo.svg.js +4 -0
  99. package/dist/src/assets/images/canvas-editor/signature.svg.js +4 -0
  100. package/dist/src/assets/images/canvas-editor/size-add.svg.js +4 -0
  101. package/dist/src/assets/images/canvas-editor/size-minus.svg.js +4 -0
  102. package/dist/src/assets/images/canvas-editor/strikeout.svg.js +4 -0
  103. package/dist/src/assets/images/canvas-editor/subscript.svg.js +4 -0
  104. package/dist/src/assets/images/canvas-editor/superscript.svg.js +4 -0
  105. package/dist/src/assets/images/canvas-editor/table.svg.js +4 -0
  106. package/dist/src/assets/images/canvas-editor/title.svg.js +4 -0
  107. package/dist/src/assets/images/canvas-editor/trash.svg.js +4 -0
  108. package/dist/src/assets/images/canvas-editor/underline.svg.js +4 -0
  109. package/dist/src/assets/images/canvas-editor/undo.svg.js +4 -0
  110. package/dist/src/assets/images/canvas-editor/watermark.svg.js +4 -0
  111. package/dist/src/assets/images/canvas-editor/word-tool.svg.js +4 -0
  112. package/dist/src/assets/images/clear.png.js +4 -0
  113. package/dist/src/assets/images/create_market_system.png.js +4 -0
  114. package/dist/src/assets/images/create_system.png.js +4 -0
  115. package/dist/src/assets/images/custom.png.js +4 -0
  116. package/dist/src/assets/images/default-icon.png.js +4 -0
  117. package/dist/src/assets/images/ex_link.png.js +4 -0
  118. package/dist/src/assets/images/excel.png.js +4 -0
  119. package/dist/src/assets/images/file.png.js +4 -0
  120. package/dist/src/assets/images/folder.png.js +4 -0
  121. package/dist/src/assets/images/hall/form.png.js +4 -0
  122. package/dist/src/assets/images/hall/meta.png.js +4 -0
  123. package/dist/src/assets/images/hall/process.png.js +4 -0
  124. package/dist/src/assets/images/hall/rule.png.js +4 -0
  125. package/dist/src/assets/images/hall/service.png.js +4 -0
  126. package/dist/src/assets/images/hall/userRole.png.js +4 -0
  127. package/dist/src/assets/images/hr.png.js +4 -0
  128. package/dist/src/assets/images/import.png.js +4 -0
  129. package/dist/src/assets/images/jian.png.js +4 -0
  130. package/dist/src/assets/images/module.png.js +4 -0
  131. package/dist/src/assets/images/null.png.js +4 -0
  132. package/dist/src/assets/images/photo.png.js +4 -0
  133. package/dist/src/assets/images/qq.png.js +4 -0
  134. package/dist/src/assets/images/robot.png.js +4 -0
  135. package/dist/src/assets/images/single_file.png.js +4 -0
  136. package/dist/src/assets/images/snapshot-history.png.js +4 -0
  137. package/dist/src/assets/images/snapshot-manual.png.js +4 -0
  138. package/dist/src/assets/images/snapshot-realtime.png.js +4 -0
  139. package/dist/src/assets/images/staff.png.js +4 -0
  140. package/dist/src/assets/images/switch_app.png.js +4 -0
  141. package/dist/src/assets/images/sync_append.png.js +4 -0
  142. package/dist/src/assets/images/sync_append_update.png.js +4 -0
  143. package/dist/src/assets/images/sync_loading.png.js +4 -0
  144. package/dist/src/assets/images/sync_replace.png.js +4 -0
  145. package/dist/src/assets/images/sync_update.png.js +4 -0
  146. package/dist/src/assets/images/user_bg.png.js +4 -0
  147. package/dist/src/assets/images/weixin.png.js +4 -0
  148. package/dist/src/chart-config-update.js +17 -0
  149. package/dist/src/chart-data-adapters.js +112 -0
  150. package/dist/src/chart-option-override.js +128 -0
  151. package/dist/src/chart-option-paths.js +64 -0
  152. package/dist/src/chart-registry.js +46 -0
  153. package/dist/src/chart-render-host.js +57 -0
  154. package/dist/src/chart-request-broker.js +176 -0
  155. package/dist/src/chartTheme.js +683 -0
  156. package/dist/src/collection.js +25 -0
  157. package/dist/src/date-helper.js +60 -0
  158. package/dist/src/dom-helper.js +22 -0
  159. package/dist/src/eval-with.js +14 -0
  160. package/dist/src/fieldFactory.js +5 -0
  161. package/dist/src/formula.js +365 -0
  162. package/dist/src/hljs-lite.js +29 -0
  163. package/dist/src/index.js +24 -0
  164. package/dist/src/lazy-jsencrypt.js +13 -0
  165. package/dist/src/legacy.js +25 -0
  166. package/dist/src/locale.js +88 -0
  167. package/dist/src/menu-open.js +43 -0
  168. package/dist/src/mermaid.js +79 -0
  169. package/dist/src/meta.js +4 -0
  170. package/dist/src/mobile-chart-appearance.js +148 -0
  171. package/dist/src/moment-compat.js +558 -0
  172. package/dist/src/nav-history.js +184 -0
  173. package/dist/src/page.js +116 -0
  174. package/dist/src/pdf.viewer.js +4 -0
  175. package/dist/src/placeholder.js +64 -0
  176. package/dist/src/public.js +49 -0
  177. package/dist/src/security.js +26 -0
  178. package/dist/src/storage.js +107 -0
  179. package/dist/src/token-storage.js +108 -0
  180. package/dist/src/util.js +4 -0
  181. package/package.json +109 -3
  182. package/src/Config.js +25 -0
  183. package/src/asset-images.js +16 -0
  184. package/src/chart-config-update.js +16 -0
  185. package/src/chart-data-adapters.js +106 -0
  186. package/src/chart-option-override.js +126 -0
  187. package/src/chart-option-paths.js +63 -0
  188. package/src/chart-registry.js +41 -0
  189. package/src/chart-render-host.js +56 -0
  190. package/src/chart-request-broker.js +171 -0
  191. package/src/chartTheme.js +711 -0
  192. package/src/collection.js +28 -0
  193. package/src/date-helper.js +72 -0
  194. package/src/dom-helper.js +26 -0
  195. package/src/eval-with.js +21 -0
  196. package/src/fieldFactory.js +3 -0
  197. package/src/formula.js +362 -0
  198. package/src/hljs-lite.js +41 -0
  199. package/src/index.js +2 -0
  200. package/src/lazy-jsencrypt.js +36 -0
  201. package/src/legacy.js +29 -0
  202. package/src/locale.js +104 -0
  203. package/src/menu-open.js +72 -0
  204. package/src/mermaid.js +115 -0
  205. package/src/meta.js +2 -0
  206. package/src/mobile-chart-appearance.js +147 -0
  207. package/src/moment-compat.d.ts +91 -0
  208. package/src/moment-compat.js +744 -0
  209. package/src/nav-history.js +274 -0
  210. package/src/page.js +129 -0
  211. package/src/pdf.viewer.js +2 -0
  212. package/src/placeholder.js +107 -0
  213. package/src/public.js +11 -0
  214. package/src/security.js +29 -0
  215. package/src/storage.js +135 -0
  216. package/src/token-storage.js +120 -0
  217. package/src/util.js +2 -0
  218. package/types/Config.d.ts +4 -0
  219. package/types/collection.d.ts +40 -0
  220. package/types/date-helper.d.ts +11 -0
  221. package/types/date-time.d.ts +2 -0
  222. package/types/date.d.ts +1 -0
  223. package/types/dom-helper.d.ts +3 -0
  224. package/types/dom.d.ts +1 -0
  225. package/types/index.d.ts +1 -0
  226. package/types/moment-compat.d.ts +91 -0
  227. package/types/page.d.ts +56 -0
  228. package/types/placeholder.d.ts +42 -0
  229. package/types/public.d.ts +10 -0
  230. package/types/storage.d.ts +31 -0
package/src/locale.js ADDED
@@ -0,0 +1,104 @@
1
+ import storage from '@epxing/utils/src/storage'
2
+
3
+ const STANDARD_SEGMENT = /^[A-Za-z0-9_]+$/
4
+ const LEGACY_LOCALES = {
5
+ '010': 'zh-CN',
6
+ '011': 'en-US'
7
+ }
8
+
9
+ // 导出:调用 setCurrentLanguage/CHANGE_LOCALE 前,凡是从 clientConfig.LANGUAGES 原始拆分
10
+ // 拿到候选 id(可能仍是 '010'/'011' 这类旧三位码)的调用点,都要先过这一层再传下去——
11
+ // CHANGE_LOCALE 只认 configuredLocales() 吐出来的归一化形式,两边不归一化会静默/报错不匹配
12
+ // (已在 AppNav.vue switchLanguage 实测复现:传 '010' 时 supportedLocales 里是 'zh-CN',
13
+ // find 不到,throw '当前客户未启用语言:010')。
14
+ export function normalizeLocale (locale) {
15
+ return LEGACY_LOCALES[locale] || locale
16
+ }
17
+
18
+ export function languagePreferenceKey (clientCode) {
19
+ return `${clientCode || ''}-language`
20
+ }
21
+
22
+ export function configuredLocales (clientConfig = {}) {
23
+ const languages = String(clientConfig.LANGUAGES || '')
24
+ .split(',')
25
+ .map(value => normalizeLocale(value.trim()))
26
+ .filter(Boolean)
27
+ const defaultLocale = normalizeLocale(clientConfig.LANGUAGE_DEFAULT || 'zh-CN')
28
+ const supportedLocales = languages.length > 0 ? languages : [defaultLocale]
29
+ return {
30
+ enabled: clientConfig.LANGUAGE_FLAG === '1',
31
+ defaultLocale,
32
+ supportedLocales
33
+ }
34
+ }
35
+
36
+ export function resolveCurrentLocale (clientConfig = {}, userInfo = {}) {
37
+ const clientCode = clientConfig.CODE || ''
38
+ const configuration = configuredLocales(clientConfig)
39
+ if (!configuration.enabled) return configuration.defaultLocale
40
+
41
+ const preferred = normalizeLocale(storage.get(languagePreferenceKey(clientCode)) || userInfo.LANGUAGE)
42
+ const matched = configuration.supportedLocales.find(locale => locale.toLowerCase() === String(preferred || '').toLowerCase())
43
+ return matched || configuration.defaultLocale
44
+ }
45
+
46
+ function utf8Hex (value) {
47
+ return Array.from(new TextEncoder().encode(value))
48
+ .map(byte => byte.toString(16).padStart(2, '0'))
49
+ .join('')
50
+ }
51
+
52
+ function resourceSegment (value) {
53
+ const normalized = String(value || '').trim()
54
+ if (!normalized) throw new Error('国际化消息名称不能为空')
55
+ return STANDARD_SEGMENT.test(normalized) ? normalized.toLowerCase() : `x_${utf8Hex(normalized)}`
56
+ }
57
+
58
+ export function uiMessageResourceKey (messageName, systemId) {
59
+ const raw = String(messageName || '').trim().split('.')
60
+ // 与后端 Java String.split("\\.") 保持一致:丢弃末尾空段,但保留中间空段供合法性校验。
61
+ while (raw.length > 0 && raw[raw.length - 1] === '') raw.pop()
62
+ const start = raw[0] && raw[0].toLowerCase() === 'frame' ? 1 : 0
63
+ const segments = raw.slice(start).map(resourceSegment)
64
+ if (segments.length === 1) segments.unshift(resourceSegment(systemId))
65
+ if (segments.length < 2) throw new Error(`国际化消息名称缺少有效语义段:${messageName}`)
66
+ return `page.${segments.join('.')}`
67
+ }
68
+
69
+ export function createUiMessageCatalog (rows = [], systemId) {
70
+ const fallbackMessages = {}
71
+ const aliases = {}
72
+ rows.forEach(row => {
73
+ const name = String(row.NAME || '').trim()
74
+ if (!name) return
75
+ const resourceKey = uiMessageResourceKey(name, systemId)
76
+ fallbackMessages[name] = row.CONTENT
77
+ fallbackMessages[resourceKey] = row.CONTENT
78
+ const keys = aliases[resourceKey] || (aliases[resourceKey] = [])
79
+ keys.push(name)
80
+ // 组件里内置的默认文案(如按钮「保存」)直接以默认语言原文调 $t,
81
+ // 这里按原文再登记一个别名,让它们复用已有消息的译文,不必改写成消息编码。
82
+ // 同一原文对应多条消息时以先登记的为准,都是同义文案,取哪条都成立。
83
+ const source = String(row.CONTENT || '').trim()
84
+ if (source && source !== name && !Object.prototype.hasOwnProperty.call(fallbackMessages, source)) {
85
+ fallbackMessages[source] = row.CONTENT
86
+ keys.push(source)
87
+ }
88
+ })
89
+ return { fallbackMessages, aliases }
90
+ }
91
+
92
+ export function createRuntimeMessages (publishedMessages = {}, catalog = {}) {
93
+ const messages = { ...publishedMessages }
94
+ const aliases = catalog.aliases || {}
95
+ Object.keys(aliases).forEach(resourceKey => {
96
+ if (!Object.prototype.hasOwnProperty.call(publishedMessages, resourceKey)) return
97
+ aliases[resourceKey].forEach(key => {
98
+ if (!Object.prototype.hasOwnProperty.call(messages, key)) {
99
+ messages[key] = publishedMessages[resourceKey]
100
+ }
101
+ })
102
+ })
103
+ return messages
104
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 菜单「外部打开」类打开方式的统一处理
3
+ *
4
+ * 背景:菜单打开方式(FM_MODULE.OPEN_TYPE)里有两种不进内部页面栈、直接开新窗口的:
5
+ * 「链接」(6) 跳手填地址,「打开应用」(7) 跳指定应用。二者点击语义完全相同
6
+ * (开新窗 + 不产生页签 + 不参与菜单高亮),差别只在目标 URL 从哪来,故收在本模块,
7
+ * 避免各菜单组件(AppNav / ModuleIndexPage / ModuleTabsPage / ConfigModuleIndex …)
8
+ * 各写一份 OPEN_TYPE 分支。
9
+ *
10
+ * 为什么 7 要现查:拼应用地址需要「应用编码 + 所属系统编码 + 客户编码」三级值,
11
+ * 而菜单树接口(getUserMenuTreeData → ModuleNode)只逐字段透传 FM_MODULE 本表列,
12
+ * 带不出关联应用的这三个编码,故点击时才按 REFERENCE_APP 查一次。
13
+ * 又因浏览器会拦截非用户手势的 window.open,先在点击的同步阶段占一个空白新窗,
14
+ * 取到地址后再回写它的 location。
15
+ */
16
+
17
+ // 开新窗、不产生页签的打开方式:6=链接、7=打开应用
18
+ const EXTERNAL_OPEN_TYPES = ['6', '7']
19
+
20
+ /**
21
+ * 是否为「开新窗」类菜单(点击后不产生页签,也不需要 MAIN_PAGE)
22
+ */
23
+ export function isExternalMenu (module) {
24
+ return !!module && EXTERNAL_OPEN_TYPES.indexOf(module.OPEN_TYPE) > -1
25
+ }
26
+
27
+ /**
28
+ * 打开「开新窗」类菜单。返回是否已由本模块接管(true 时调用方应直接 return,不要再走建页面逻辑)
29
+ * @param {Object} module 菜单节点(菜单树接口返回的 ModuleNode)
30
+ * @param {Object} vm 调用方组件实例,用其 $http / $util / $message
31
+ */
32
+ export function openExternalMenu (module, vm) {
33
+ if (!isExternalMenu(module)) return false
34
+ if (module.OPEN_TYPE === '6') {
35
+ if (module.LINK_URL) window.open(module.LINK_URL)
36
+ return true
37
+ }
38
+ // 打开方式=7(打开应用):没配目标应用时按「已接管」处理,避免退化成打开空白页面
39
+ if (!module.REFERENCE_APP) {
40
+ vm.$message.error('该菜单未配置目标应用')
41
+ return true
42
+ }
43
+ // 先同步占窗,规避异步回调里 window.open 被浏览器拦截
44
+ const win = window.open('', '_blank')
45
+ // link 取到所属系统及其客户的编码,三段一起用于拼应用地址
46
+ vm.$http.get({
47
+ entityId: 'FM_SERVICE',
48
+ id: module.REFERENCE_APP,
49
+ link: 'system,system|client'
50
+ })
51
+ .then(res => {
52
+ const app = (res && res.data) || {}
53
+ const clientCode = app['SYSTEM|CLIENT|CODE']
54
+ const systemCode = app['SYSTEM|CODE']
55
+ if (!app.CODE || !systemCode || !clientCode) {
56
+ if (win) win.close()
57
+ vm.$message.error('没有找到该应用')
58
+ return
59
+ }
60
+ const url = `${vm.$util.getRootPath()}/app/${clientCode}/${systemCode}/${app.CODE}`
61
+ if (win) {
62
+ win.location = url
63
+ } else {
64
+ // 占窗被拦截时退化为当前窗口打开,保证功能可用
65
+ window.open(url)
66
+ }
67
+ })
68
+ .catch(() => {
69
+ if (win) win.close()
70
+ })
71
+ return true
72
+ }
package/src/mermaid.js ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Markdown 正文里的 mermaid 图渲染。
3
+ *
4
+ * Wiki 的设计文档、流程说明大量用 mermaid 写图(Beaver 侧还有 MermaidLintTool 专门校验它),
5
+ * 不渲染的话读者看到的是一坨 `flowchart LR ...` 源码——那正是这份文档想省掉的东西。
6
+ *
7
+ * **懒加载**:mermaid 打出来两三兆,而绝大多数页面根本没有图。所以按需 import,
8
+ * 一个进程只加载一次;没有图的页面完全不碰它。
9
+ *
10
+ * 站点正文与问答的引用抽屉共用这一份:同一段 md 在两处必须画出同一张图,
11
+ * 各写一份迟早会分叉。
12
+ */
13
+
14
+ let loading = null
15
+
16
+ /** 每张图要一个全局唯一 id,mermaid 用它建临时 DOM。 */
17
+ let seq = 0
18
+
19
+ /**
20
+ * 加载 mermaid 并初始化。
21
+ *
22
+ * `startOnLoad: false`——我们自己控制渲染时机;让它自动扫全文档的话,
23
+ * 抽屉这种动态插入的内容它根本扫不到。
24
+ */
25
+ function load () {
26
+ if (!loading) {
27
+ loading = import(/* webpackChunkName: "mermaid" */ 'mermaid')
28
+ .then(mod => {
29
+ const mermaid = mod.default || mod
30
+ mermaid.initialize({
31
+ startOnLoad: false,
32
+ // 图里的标签可能来自 Wiki 正文,正文不是可信输入——securityLevel 保持严格,
33
+ // 让 mermaid 转义标签内容,别给它注入 HTML 的机会
34
+ securityLevel: 'strict',
35
+ // Mermaid 默认会在语法错误时把一张“Syntax error”错误图挂到 document.body。
36
+ // Wiki 正文捕获异常后本来就会在代码块旁显示错误说明,因此关闭 Mermaid 自带
37
+ // 错误图,避免它逃出正文容器并把整个应用页面撑高。
38
+ suppressErrorRendering: true,
39
+ theme: 'default',
40
+ fontFamily: 'inherit',
41
+ flowchart: { htmlLabels: false, useMaxWidth: true },
42
+ sequence: { useMaxWidth: true },
43
+ er: { useMaxWidth: true }
44
+ })
45
+ return mermaid
46
+ })
47
+ .catch(err => {
48
+ // 加载失败不能连累正文:图出不来是遗憾,整页白屏是事故
49
+ loading = null
50
+ throw err
51
+ })
52
+ }
53
+ return loading
54
+ }
55
+
56
+ /**
57
+ * 把容器里的 mermaid 代码块画成图。
58
+ *
59
+ * markdown-it 把 ```mermaid 渲染成 `<pre><code class="language-mermaid">`,
60
+ * 这里找出这些块,逐个交给 mermaid,用 `<div class="mermaid-figure">` 换掉。
61
+ *
62
+ * @param {HTMLElement} root 正文容器
63
+ * @returns {Promise<number>} 画出来几张
64
+ */
65
+ export async function renderMermaid (root) {
66
+ if (!root) return 0
67
+ const blocks = Array.from(root.querySelectorAll('pre > code.language-mermaid, pre > code.mermaid'))
68
+ if (!blocks.length) return 0
69
+
70
+ let mermaid
71
+ try {
72
+ mermaid = await load()
73
+ } catch (e) {
74
+ blocks.forEach(block => fallback(block, '图表组件加载失败,下面是原始定义'))
75
+ return 0
76
+ }
77
+
78
+ let done = 0
79
+ for (const block of blocks) {
80
+ const code = block.textContent || ''
81
+ const pre = block.parentElement
82
+ if (!code.trim() || !pre) continue
83
+ try {
84
+ const { svg } = await mermaid.render('wiki-mermaid-' + (++seq), code)
85
+ const figure = document.createElement('div')
86
+ figure.className = 'mermaid-figure'
87
+ figure.innerHTML = svg
88
+ pre.replaceWith(figure)
89
+ done++
90
+ } catch (e) {
91
+ // 图画不出来通常是语法写错了。保留原始定义并说明原因——
92
+ // 直接吞掉的话,作者只会看到「我的图没了」,无从判断是自己写错还是平台不支持
93
+ fallback(block, '这张图没画出来:' + shortMessage(e))
94
+ }
95
+ }
96
+ return done
97
+ }
98
+
99
+ /** 渲染不了时保留源码,并在上面写清为什么。 */
100
+ function fallback (block, reason) {
101
+ const pre = block.parentElement
102
+ if (!pre || pre.previousElementSibling?.classList?.contains('mermaid-figure__error')) return
103
+ const tip = document.createElement('div')
104
+ tip.className = 'mermaid-figure__error'
105
+ tip.textContent = reason
106
+ pre.parentNode.insertBefore(tip, pre)
107
+ }
108
+
109
+ /** mermaid 的报错常常带一大段解析器状态,取第一行够定位了。 */
110
+ function shortMessage (e) {
111
+ const msg = (e && (e.message || e.str)) || '语法有误'
112
+ return String(msg).split('\n')[0].slice(0, 120)
113
+ }
114
+
115
+ export default renderMermaid
package/src/meta.js ADDED
@@ -0,0 +1,2 @@
1
+ // 兼容旧路径;新代码从 @epxing/core 导入。
2
+ export { default } from '@epxing/core/src/runtime-utils/meta'
@@ -0,0 +1,147 @@
1
+ import { getChartType } from './chart-registry'
2
+
3
+ // 移动端只允许覆盖展示属性,不能通过该配置改变数据、指标或事件。
4
+ export const MOBILE_APPEARANCE_FIELDS = [
5
+ { key: 'showTitle', label: '显示标题', options: [{ label: '显示', value: true }, { label: '隐藏', value: false }] },
6
+ { key: 'titleFontSize', label: '标题字号', min: 10, max: 40, defaultValue: 14 },
7
+ { key: 'legendPosition', label: '图例位置', options: ['top', 'bottom', 'left', 'right', 'hidden'].map((value, i) => ({ value, label: ['顶部', '底部', '左侧', '右侧', '隐藏'][i] })) },
8
+ { key: 'legendFontSize', label: '图例字号', min: 8, max: 32, defaultValue: 12 },
9
+ { key: 'axisFontSize', label: '坐标轴字号', min: 8, max: 32, defaultValue: 12 },
10
+ { key: 'axisLabelRotate', label: '横轴文字角度', min: -90, max: 90, defaultValue: 0 },
11
+ ...['Top', 'Bottom', 'Left', 'Right'].map((side, i) => ({ key: `grid${side}`, label: `绘图区${['上', '下', '左', '右'][i]}留白`, min: 0, max: 200, defaultValue: 24 })),
12
+ { key: 'showLabel', label: '显示数据标签', options: [{ label: '显示', value: true }, { label: '隐藏', value: false }] },
13
+ { key: 'labelFontSize', label: '数据标签字号', min: 8, max: 32, defaultValue: 12 },
14
+ { key: 'pieRadius', label: '饼图外半径(%)', min: 10, max: 95, defaultValue: 65 }
15
+ ]
16
+
17
+ export function getMobileAppearanceFields (type) {
18
+ const cartesian = getChartType(type)?.coordinate === 'cartesian2d'
19
+ const pie = ['pie', 'circularPie'].includes(type)
20
+ if (!cartesian && !pie && !['funnel', 'radar', 'map', 'wordcloud', 'gauge', 'treemap'].includes(type)) return []
21
+ return MOBILE_APPEARANCE_FIELDS.filter(field => {
22
+ if (field.key.startsWith('axis') || field.key.startsWith('grid')) return cartesian
23
+ if (field.key === 'pieRadius') return pie
24
+ if (field.key.startsWith('legend')) return !['map', 'wordcloud'].includes(type)
25
+ if (['showLabel', 'labelFontSize'].includes(field.key)) return type !== 'wordcloud'
26
+ return true
27
+ })
28
+ }
29
+
30
+ export function normalizeMobileAppearance (value = {}) {
31
+ const result = {}
32
+ for (const field of MOBILE_APPEARANCE_FIELDS) {
33
+ const v = value?.[field.key]
34
+ if (field.options) {
35
+ if (field.options.some(o => o.value === v)) result[field.key] = v
36
+ } else if (typeof v === 'number' && Number.isFinite(v) && v >= field.min && v <= field.max) {
37
+ result[field.key] = v
38
+ }
39
+ }
40
+ return result
41
+ }
42
+
43
+ // 只复制将修改的对象;保留 formatter 等函数以及完整系列数据。
44
+ export function applyMobileChartAppearance (option, appearance) {
45
+ const a = normalizeMobileAppearance(appearance)
46
+ if (!option || !Object.keys(a).length) return option
47
+ const result = { ...option }
48
+ const mapPart = (key, update) => {
49
+ if (Array.isArray(option[key])) result[key] = option[key].map(part => update({ ...part }))
50
+ else result[key] = update({ ...(option[key] || {}) })
51
+ }
52
+ if (a.legendPosition !== undefined || a.legendFontSize !== undefined) {
53
+ mapPart('legend', legend => {
54
+ if (a.legendPosition !== undefined) {
55
+ const pos = a.legendPosition
56
+ legend.show = pos !== 'hidden'
57
+ if (pos !== 'hidden') {
58
+ Object.assign(legend, { top: 'auto', bottom: 'auto', left: 'auto', right: 'auto', orient: ['left', 'right'].includes(pos) ? 'vertical' : 'horizontal' })
59
+ legend[pos] = 8
60
+ if (legend.orient === 'horizontal') legend.left = 'center'
61
+ else legend.top = 'center'
62
+ }
63
+ }
64
+ if (a.legendFontSize !== undefined) legend.textStyle = { ...legend.textStyle, fontSize: a.legendFontSize }
65
+ return legend
66
+ })
67
+ }
68
+ for (const key of ['xAxis', 'yAxis']) {
69
+ if (!option[key] || (a.axisFontSize === undefined && (key !== 'xAxis' || a.axisLabelRotate === undefined))) continue
70
+ mapPart(key, axis => {
71
+ axis.axisLabel = { ...axis.axisLabel }
72
+ if (a.axisFontSize !== undefined) axis.axisLabel.fontSize = a.axisFontSize
73
+ if (key === 'xAxis' && a.axisLabelRotate !== undefined) axis.axisLabel.rotate = a.axisLabelRotate
74
+ return axis
75
+ })
76
+ }
77
+ if (['Top', 'Bottom', 'Left', 'Right'].some(s => a[`grid${s}`] !== undefined)) {
78
+ mapPart('grid', grid => {
79
+ for (const s of ['Top', 'Bottom', 'Left', 'Right']) {
80
+ if (a[`grid${s}`] !== undefined) grid[s.toLowerCase()] = a[`grid${s}`]
81
+ }
82
+ return grid
83
+ })
84
+ }
85
+ if (Array.isArray(option.series)) {
86
+ result.series = option.series.map(series => {
87
+ const next = { ...series }
88
+ if (a.showLabel !== undefined || a.labelFontSize !== undefined) {
89
+ if (series.type === 'gauge') {
90
+ next.detail = { ...series.detail }
91
+ if (a.showLabel !== undefined) next.detail.show = a.showLabel
92
+ if (a.labelFontSize !== undefined) next.detail.fontSize = a.labelFontSize
93
+ }
94
+ next.label = { ...series.label }
95
+ if (a.showLabel !== undefined) next.label.show = a.showLabel
96
+ if (a.labelFontSize !== undefined) next.label.fontSize = a.labelFontSize
97
+ }
98
+ if (series.type === 'pie' && a.pieRadius !== undefined) {
99
+ const outer = `${a.pieRadius}%`
100
+ next.radius = Array.isArray(series.radius) ? [`${Math.min(parseFloat(series.radius[0]) || 0, a.pieRadius)}%`, outer] : outer
101
+ }
102
+ return next
103
+ })
104
+ }
105
+ return result
106
+ }
107
+
108
+ export const mobileChartAppearanceMixin = {
109
+ props: { mobileAppearance: { type: Object, default: () => ({}) } },
110
+ inject: {
111
+ epxMobilePreview: { default: false },
112
+ registerMobileChartLabel: { default: null },
113
+ getMobileDashboard: { default: () => () => false }
114
+ },
115
+ watch: {
116
+ mobileChartLabel: {
117
+ immediate: true,
118
+ handler (label) {
119
+ if (this.epxMobilePreview && label && this.registerMobileChartLabel) this.registerMobileChartLabel(this.compId, label, this.chartType)
120
+ }
121
+ },
122
+ chartType: {
123
+ immediate: true,
124
+ handler (type) {
125
+ if (this.epxMobilePreview && type && this.registerMobileChartLabel) this.registerMobileChartLabel(this.compId, this.mobileChartLabel, type)
126
+ }
127
+ },
128
+ activeMobileAppearance: {
129
+ deep: true,
130
+ handler () {
131
+ if (this.myChart && this.chartOption) this.createChart()
132
+ }
133
+ }
134
+ },
135
+ computed: {
136
+ mobileChartLabel () {
137
+ return this.titleText || (typeof this.title === 'string' ? this.title : '')
138
+ },
139
+ activeMobileAppearance () {
140
+ return this.$isMobile || this.epxMobilePreview || this.getMobileDashboard() ? normalizeMobileAppearance(this.mobileAppearance) : {}
141
+ },
142
+ mobileTitleFontStyle () {
143
+ const size = this.activeMobileAppearance.titleFontSize
144
+ return size === undefined ? {} : { fontSize: `${size}px` }
145
+ }
146
+ }
147
+ }
@@ -0,0 +1,91 @@
1
+ import type { Dayjs } from 'dayjs'
2
+ import type { Duration } from 'dayjs/plugin/duration'
3
+
4
+ /** 对应 moment-compat.js 的 READ_METHODS / WRITE_METHODS,保留可变链式语义。 */
5
+ export interface MomentLike {
6
+ format(format?: string): string
7
+ valueOf(): number
8
+ unix(): number
9
+ toDate(): Date
10
+ toISOString(): string | null
11
+ toJSON(): string | null
12
+ toString(): string
13
+ toArray(): number[]
14
+ toObject(): Record<string, number>
15
+ isValid(): boolean
16
+ clone(): MomentLike
17
+ diff(input?: unknown, unit?: string, precise?: boolean): number
18
+ isBefore(input?: unknown, unit?: string): boolean
19
+ isAfter(input?: unknown, unit?: string): boolean
20
+ isSame(input?: unknown, unit?: string): boolean
21
+ isSameOrBefore(input?: unknown, unit?: string): boolean
22
+ isSameOrAfter(input?: unknown, unit?: string): boolean
23
+ isBetween(start: unknown, end: unknown, unit?: string | null, inclusivity?: string): boolean
24
+ isLeapYear(): boolean
25
+ daysInMonth(): number
26
+ get(unit: string): number
27
+ from(input: unknown, withoutSuffix?: boolean): string
28
+ to(input: unknown, withoutSuffix?: boolean): string
29
+ fromNow(withoutSuffix?: boolean): string
30
+ toNow(withoutSuffix?: boolean): string
31
+ calendar(reference?: unknown, formats?: Record<string, string | ((...args: any[]) => string)>): string
32
+ utcOffset(): number
33
+ utcOffset(offset: number | string, keepLocalTime?: boolean): MomentLike
34
+ weekday(): number
35
+ weekday(value: number): MomentLike
36
+ isoWeekday(): number
37
+ isoWeekday(value: number): MomentLike
38
+ add(amount: number | Duration, unit?: string): this
39
+ subtract(amount: number | Duration, unit?: string): this
40
+ startOf(unit: string): this
41
+ endOf(unit: string): this
42
+ set(unit: string, value: number): this
43
+ set(values: Record<string, number>): this
44
+ local(): this
45
+ utc(keepLocalTime?: boolean): this
46
+ locale(): string
47
+ locale(name: string): this
48
+ year(): number
49
+ year(value: number): this
50
+ month(): number
51
+ month(value: number): this
52
+ date(): number
53
+ date(value: number): this
54
+ day(): number
55
+ day(value: number): this
56
+ hour(): number
57
+ hour(value: number): this
58
+ minute(): number
59
+ minute(value: number): this
60
+ second(): number
61
+ second(value: number): this
62
+ millisecond(): number
63
+ millisecond(value: number): this
64
+ quarter(): number
65
+ quarter(value: number): this
66
+ week(): number
67
+ week(value: number): this
68
+ isoWeek(): number
69
+ isoWeek(value: number): this
70
+ dayOfYear(): number
71
+ dayOfYear(value: number): this
72
+ }
73
+ export interface MomentFactory {
74
+ (input?: unknown, ...formatAndOptions: any[]): MomentLike
75
+ duration(input?: unknown, ...unit: any[]): Duration
76
+ locale(name?: string): string
77
+ isMoment(value: unknown): value is MomentLike
78
+ unix(seconds: number): MomentLike
79
+ utc(input?: unknown, ...formatAndOptions: any[]): MomentLike
80
+ max(...dates: (MomentLike | Dayjs | (MomentLike | Dayjs)[])[]): MomentLike
81
+ min(...dates: (MomentLike | Dayjs | (MomentLike | Dayjs)[])[]): MomentLike
82
+ }
83
+ declare const moment: MomentFactory
84
+ export { moment as createMoment }
85
+ export default moment
86
+ export declare function preprocessFormat(format: string, milliseconds?: number, year?: number): string
87
+ export declare const READ_METHODS: string[]
88
+ export declare const WRITE_METHODS: string[]
89
+ export declare const DUAL_METHODS: Set<string>
90
+ export declare const PASSTHROUGH: Set<string>
91
+ export declare const UNSUPPORTED_FORMAT_TOKENS: string[]