@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.
- package/API.md +602 -0
- package/README.md +22 -2
- package/dist/_vendor/.pnpm/jsencrypt@3.5.4/_vendor/jsencrypt/bin/jsencrypt.min.js +1691 -0
- package/dist/_virtual/_commonjsHelpers.js +6 -0
- package/dist/_virtual/jsencrypt.min.js +31 -0
- package/dist/_virtual/jsencrypt.min2.js +4 -0
- package/dist/_virtual/preload-helper.js +88 -0
- package/dist/assets/ai-BBFn3QRy.png +0 -0
- package/dist/assets/ai_import-BxQ7Ohn6.png +0 -0
- package/dist/assets/app-DBNIokDP.png +0 -0
- package/dist/assets/approval-DGcBv-re.png +0 -0
- package/dist/assets/create_market_system-BH__UVbt.png +0 -0
- package/dist/assets/create_system-irg--ePh.png +0 -0
- package/dist/assets/custom-C-ujlHz1.png +0 -0
- package/dist/assets/default-icon-2193FMjv.png +0 -0
- package/dist/assets/ex_link-4fYPd9nh.png +0 -0
- package/dist/assets/excel-BYqRm2Y8.png +0 -0
- package/dist/assets/folder-CFVsNbjj.png +0 -0
- package/dist/assets/form-DD9HV-jN.png +0 -0
- package/dist/assets/import-tfKWbWVS.png +0 -0
- package/dist/assets/meta-Qorpi70B.png +0 -0
- package/dist/assets/module-DQrs7VAS.png +0 -0
- package/dist/assets/null-B2An29h4.png +0 -0
- package/dist/assets/option-CG02tIgh.svg +1 -0
- package/dist/assets/photo-uscRzRXF.png +0 -0
- package/dist/assets/process-Dcndu9m2.png +0 -0
- package/dist/assets/rule-DcYhYse0.png +0 -0
- package/dist/assets/service-CLYLpPl3.png +0 -0
- package/dist/assets/single_file-B3TJtJli.png +0 -0
- package/dist/assets/snapshot-history-BsVY9cVj.png +0 -0
- package/dist/assets/snapshot-manual-DBRfFHYI.png +0 -0
- package/dist/assets/snapshot-realtime-DjHnJI6C.png +0 -0
- package/dist/assets/staff-Bn_-_00l.png +0 -0
- package/dist/assets/sync_append-Bm8mtvZs.png +0 -0
- package/dist/assets/sync_append_update-DzjxqJ_U.png +0 -0
- package/dist/assets/sync_loading-D7LoNPFP.png +0 -0
- package/dist/assets/sync_replace-Cbbzz327.png +0 -0
- package/dist/assets/sync_update-Birao6Cr.png +0 -0
- package/dist/assets/userRole-D1LAdM6N.png +0 -0
- package/dist/assets/user_bg-BFHtaZjz.png +0 -0
- package/dist/src/Config.js +25 -0
- package/dist/src/asset-images.js +125 -0
- package/dist/src/assets/images/add.png.js +4 -0
- package/dist/src/assets/images/ai-button.png.js +4 -0
- package/dist/src/assets/images/ai.png.js +4 -0
- package/dist/src/assets/images/ai_import.png.js +4 -0
- package/dist/src/assets/images/app.png.js +4 -0
- package/dist/src/assets/images/approval.png.js +4 -0
- package/dist/src/assets/images/book.png.js +4 -0
- package/dist/src/assets/images/canvas-editor/alignment.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/arrow-left.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/arrow-right.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/block.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/bold.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/catalog.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/center.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/checkbox.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/close.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/codeblock.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/color.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/control.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/date.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/exit-fullscreen.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/format.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/highlight.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/hyperlink.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/image.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/italic.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/justify.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/latex.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/left.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-dash-dot-dot.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-dash-dot.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-dash-large-gap.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-dash-small-gap.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-dot.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-double.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-single.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/line-wavy.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/list.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/option.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/page-break.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/page-mode.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/page-scale-add.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/page-scale-minus.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/painter.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/paper-direction.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/paper-margin.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/paper-size.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/print.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/radio.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/redo.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/request-fullscreen.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/right.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/row-margin.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/search.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/separator.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/signature-undo.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/signature.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/size-add.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/size-minus.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/strikeout.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/subscript.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/superscript.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/table.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/title.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/trash.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/underline.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/undo.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/watermark.svg.js +4 -0
- package/dist/src/assets/images/canvas-editor/word-tool.svg.js +4 -0
- package/dist/src/assets/images/clear.png.js +4 -0
- package/dist/src/assets/images/create_market_system.png.js +4 -0
- package/dist/src/assets/images/create_system.png.js +4 -0
- package/dist/src/assets/images/custom.png.js +4 -0
- package/dist/src/assets/images/default-icon.png.js +4 -0
- package/dist/src/assets/images/ex_link.png.js +4 -0
- package/dist/src/assets/images/excel.png.js +4 -0
- package/dist/src/assets/images/file.png.js +4 -0
- package/dist/src/assets/images/folder.png.js +4 -0
- package/dist/src/assets/images/hall/form.png.js +4 -0
- package/dist/src/assets/images/hall/meta.png.js +4 -0
- package/dist/src/assets/images/hall/process.png.js +4 -0
- package/dist/src/assets/images/hall/rule.png.js +4 -0
- package/dist/src/assets/images/hall/service.png.js +4 -0
- package/dist/src/assets/images/hall/userRole.png.js +4 -0
- package/dist/src/assets/images/hr.png.js +4 -0
- package/dist/src/assets/images/import.png.js +4 -0
- package/dist/src/assets/images/jian.png.js +4 -0
- package/dist/src/assets/images/module.png.js +4 -0
- package/dist/src/assets/images/null.png.js +4 -0
- package/dist/src/assets/images/photo.png.js +4 -0
- package/dist/src/assets/images/qq.png.js +4 -0
- package/dist/src/assets/images/robot.png.js +4 -0
- package/dist/src/assets/images/single_file.png.js +4 -0
- package/dist/src/assets/images/snapshot-history.png.js +4 -0
- package/dist/src/assets/images/snapshot-manual.png.js +4 -0
- package/dist/src/assets/images/snapshot-realtime.png.js +4 -0
- package/dist/src/assets/images/staff.png.js +4 -0
- package/dist/src/assets/images/switch_app.png.js +4 -0
- package/dist/src/assets/images/sync_append.png.js +4 -0
- package/dist/src/assets/images/sync_append_update.png.js +4 -0
- package/dist/src/assets/images/sync_loading.png.js +4 -0
- package/dist/src/assets/images/sync_replace.png.js +4 -0
- package/dist/src/assets/images/sync_update.png.js +4 -0
- package/dist/src/assets/images/user_bg.png.js +4 -0
- package/dist/src/assets/images/weixin.png.js +4 -0
- package/dist/src/chart-config-update.js +17 -0
- package/dist/src/chart-data-adapters.js +112 -0
- package/dist/src/chart-option-override.js +128 -0
- package/dist/src/chart-option-paths.js +64 -0
- package/dist/src/chart-registry.js +46 -0
- package/dist/src/chart-render-host.js +57 -0
- package/dist/src/chart-request-broker.js +176 -0
- package/dist/src/chartTheme.js +683 -0
- package/dist/src/collection.js +25 -0
- package/dist/src/date-helper.js +60 -0
- package/dist/src/dom-helper.js +22 -0
- package/dist/src/eval-with.js +14 -0
- package/dist/src/fieldFactory.js +5 -0
- package/dist/src/formula.js +365 -0
- package/dist/src/hljs-lite.js +29 -0
- package/dist/src/index.js +24 -0
- package/dist/src/lazy-jsencrypt.js +13 -0
- package/dist/src/legacy.js +25 -0
- package/dist/src/locale.js +88 -0
- package/dist/src/menu-open.js +43 -0
- package/dist/src/mermaid.js +79 -0
- package/dist/src/meta.js +4 -0
- package/dist/src/mobile-chart-appearance.js +148 -0
- package/dist/src/moment-compat.js +558 -0
- package/dist/src/nav-history.js +184 -0
- package/dist/src/page.js +116 -0
- package/dist/src/pdf.viewer.js +4 -0
- package/dist/src/placeholder.js +64 -0
- package/dist/src/public.js +49 -0
- package/dist/src/security.js +26 -0
- package/dist/src/storage.js +107 -0
- package/dist/src/token-storage.js +108 -0
- package/dist/src/util.js +4 -0
- package/package.json +109 -3
- package/src/Config.js +25 -0
- package/src/asset-images.js +16 -0
- package/src/chart-config-update.js +16 -0
- package/src/chart-data-adapters.js +106 -0
- package/src/chart-option-override.js +126 -0
- package/src/chart-option-paths.js +63 -0
- package/src/chart-registry.js +41 -0
- package/src/chart-render-host.js +56 -0
- package/src/chart-request-broker.js +171 -0
- package/src/chartTheme.js +711 -0
- package/src/collection.js +28 -0
- package/src/date-helper.js +72 -0
- package/src/dom-helper.js +26 -0
- package/src/eval-with.js +21 -0
- package/src/fieldFactory.js +3 -0
- package/src/formula.js +362 -0
- package/src/hljs-lite.js +41 -0
- package/src/index.js +2 -0
- package/src/lazy-jsencrypt.js +36 -0
- package/src/legacy.js +29 -0
- package/src/locale.js +104 -0
- package/src/menu-open.js +72 -0
- package/src/mermaid.js +115 -0
- package/src/meta.js +2 -0
- package/src/mobile-chart-appearance.js +147 -0
- package/src/moment-compat.d.ts +91 -0
- package/src/moment-compat.js +744 -0
- package/src/nav-history.js +274 -0
- package/src/page.js +129 -0
- package/src/pdf.viewer.js +2 -0
- package/src/placeholder.js +107 -0
- package/src/public.js +11 -0
- package/src/security.js +29 -0
- package/src/storage.js +135 -0
- package/src/token-storage.js +120 -0
- package/src/util.js +2 -0
- package/types/Config.d.ts +4 -0
- package/types/collection.d.ts +40 -0
- package/types/date-helper.d.ts +11 -0
- package/types/date-time.d.ts +2 -0
- package/types/date.d.ts +1 -0
- package/types/dom-helper.d.ts +3 -0
- package/types/dom.d.ts +1 -0
- package/types/index.d.ts +1 -0
- package/types/moment-compat.d.ts +91 -0
- package/types/page.d.ts +56 -0
- package/types/placeholder.d.ts +42 -0
- package/types/public.d.ts +10 -0
- 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
|
+
}
|
package/src/menu-open.js
ADDED
|
@@ -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,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[]
|