@epxing/utils 0.0.0-stage → 5.3.0-beta.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.
- 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/package.json
CHANGED
|
@@ -1,6 +1,112 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epxing/utils",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "5.3.0-beta.1",
|
|
4
|
+
"description": "工具函数(util/fieldFactory/meta/formula/pdf 等;深路径 @epxing/utils/src/* 为公共 API)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/src/public.js",
|
|
7
|
+
"module": "./dist/src/public.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./types/index.d.ts",
|
|
11
|
+
"import": "./dist/src/public.js",
|
|
12
|
+
"default": "./dist/src/public.js"
|
|
13
|
+
},
|
|
14
|
+
"./src": "./dist/src/legacy.js",
|
|
15
|
+
"./config": {
|
|
16
|
+
"types": "./types/Config.d.ts",
|
|
17
|
+
"import": "./dist/src/Config.js",
|
|
18
|
+
"default": "./dist/src/Config.js"
|
|
19
|
+
},
|
|
20
|
+
"./page": {
|
|
21
|
+
"types": "./types/page.d.ts",
|
|
22
|
+
"import": "./dist/src/page.js",
|
|
23
|
+
"default": "./dist/src/page.js"
|
|
24
|
+
},
|
|
25
|
+
"./placeholder": {
|
|
26
|
+
"types": "./types/placeholder.d.ts",
|
|
27
|
+
"import": "./dist/src/placeholder.js",
|
|
28
|
+
"default": "./dist/src/placeholder.js"
|
|
29
|
+
},
|
|
30
|
+
"./storage": {
|
|
31
|
+
"types": "./types/storage.d.ts",
|
|
32
|
+
"import": "./dist/src/storage.js",
|
|
33
|
+
"default": "./dist/src/storage.js"
|
|
34
|
+
},
|
|
35
|
+
"./date": {
|
|
36
|
+
"types": "./types/date-helper.d.ts",
|
|
37
|
+
"import": "./dist/src/date-helper.js",
|
|
38
|
+
"default": "./dist/src/date-helper.js"
|
|
39
|
+
},
|
|
40
|
+
"./dom": {
|
|
41
|
+
"types": "./types/dom-helper.d.ts",
|
|
42
|
+
"import": "./dist/src/dom-helper.js",
|
|
43
|
+
"default": "./dist/src/dom-helper.js"
|
|
44
|
+
},
|
|
45
|
+
"./date-time": {
|
|
46
|
+
"types": "./types/moment-compat.d.ts",
|
|
47
|
+
"import": "./dist/src/moment-compat.js",
|
|
48
|
+
"default": "./dist/src/moment-compat.js"
|
|
49
|
+
},
|
|
50
|
+
"./collection": {
|
|
51
|
+
"types": "./types/collection.d.ts",
|
|
52
|
+
"import": "./dist/src/collection.js",
|
|
53
|
+
"default": "./dist/src/collection.js"
|
|
54
|
+
},
|
|
55
|
+
"./src/*.css": "./src/*.css",
|
|
56
|
+
"./src/*.scss": "./src/*.scss",
|
|
57
|
+
"./src/*.png": "./src/*.png",
|
|
58
|
+
"./src/*.svg": "./src/*.svg",
|
|
59
|
+
"./src/*.jpg": "./src/*.jpg",
|
|
60
|
+
"./src/*.gif": "./src/*.gif",
|
|
61
|
+
"./src/*.woff": "./src/*.woff",
|
|
62
|
+
"./src/*.woff2": "./src/*.woff2",
|
|
63
|
+
"./src/*.ttf": "./src/*.ttf",
|
|
64
|
+
"./src/*.js": "./dist/src/*.js",
|
|
65
|
+
"./src/*.jsx": "./dist/src/*.js",
|
|
66
|
+
"./src/*.vue": "./dist/src/*.js",
|
|
67
|
+
"./src/*": "./dist/src/*.js",
|
|
68
|
+
"./package.json": "./package.json"
|
|
69
|
+
},
|
|
70
|
+
"files": [
|
|
71
|
+
"dist",
|
|
72
|
+
"src",
|
|
73
|
+
"types",
|
|
74
|
+
"API.md"
|
|
75
|
+
],
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"dayjs": "^1.11.21",
|
|
78
|
+
"highlight.js": "^11.11.1",
|
|
79
|
+
"lodash-es": "^4.17.23"
|
|
80
|
+
},
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"@epxing/core": "^5.3.0-beta",
|
|
83
|
+
"mermaid": "^11.17.2"
|
|
84
|
+
},
|
|
85
|
+
"peerDependenciesMeta": {
|
|
86
|
+
"@epxing/core": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"mermaid": {
|
|
90
|
+
"optional": true
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"types": "./types/index.d.ts",
|
|
94
|
+
"sideEffects": [
|
|
95
|
+
"**/*.css",
|
|
96
|
+
"**/*.scss",
|
|
97
|
+
"**/*.vue",
|
|
98
|
+
"./dist/src/app.js",
|
|
99
|
+
"./dist/src/plugins/**",
|
|
100
|
+
"./dist/src/store/**",
|
|
101
|
+
"./dist/src/mixins/**",
|
|
102
|
+
"./dist/src/runtime-utils/util.js",
|
|
103
|
+
"./dist/src/runtime-services.js"
|
|
104
|
+
],
|
|
105
|
+
"publishConfig": {
|
|
106
|
+
"access": "public",
|
|
107
|
+
"registry": "https://registry.npmjs.org/"
|
|
108
|
+
},
|
|
109
|
+
"scripts": {
|
|
110
|
+
"build": "cd ../.. && cross-env PKG=utils vite build -c build/vite.pkg.config.mjs"
|
|
111
|
+
}
|
|
6
112
|
}
|
package/src/Config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isObject } from 'lodash-es'
|
|
2
|
+
|
|
3
|
+
class Config {
|
|
4
|
+
// 设置配置
|
|
5
|
+
set (config) {
|
|
6
|
+
for (const key in config) {
|
|
7
|
+
try {
|
|
8
|
+
if (isObject(config[key])) {
|
|
9
|
+
if (Array.isArray(config[key])) {
|
|
10
|
+
this[key] = [...config[key]]
|
|
11
|
+
} else {
|
|
12
|
+
if (!this[key]) this[key] = {}
|
|
13
|
+
this[key] = { ...this[key], ...config[key] }
|
|
14
|
+
}
|
|
15
|
+
} else {
|
|
16
|
+
this[key] = config[key]
|
|
17
|
+
}
|
|
18
|
+
} catch (error) {
|
|
19
|
+
this[key] = config[key]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default Config
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// 动态路径图片资产表(Vite 版)—— 与 asset-images.js(webpack 版)保持同步!
|
|
2
|
+
// vite.config alias 把 '@/utils/asset-images.js' 切到本文件(webpack 4 不认 import.meta,无法单文件双兼容)。
|
|
3
|
+
const hall = import.meta.glob('@/assets/images/hall/*.png', { eager: true, query: '?url', import: 'default' })
|
|
4
|
+
const root = import.meta.glob('@/assets/images/*.png', { eager: true, query: '?url', import: 'default' })
|
|
5
|
+
const ce = import.meta.glob('@/assets/images/canvas-editor/*.{png,svg}', { eager: true, query: '?url', import: 'default' })
|
|
6
|
+
|
|
7
|
+
const map = {}
|
|
8
|
+
const strip = key => key.split('/assets/images/')[1]
|
|
9
|
+
Object.keys(hall).forEach(key => { map[strip(key)] = hall[key] })
|
|
10
|
+
Object.keys(root).forEach(key => { map[strip(key)] = root[key] })
|
|
11
|
+
Object.keys(ce).forEach(key => { map[strip(key)] = ce[key] })
|
|
12
|
+
|
|
13
|
+
// 按相对路径取图片 URL,如 imageAsset(`hall/${key}.png`)
|
|
14
|
+
export function imageAsset (relPath) {
|
|
15
|
+
return map[relPath]
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Unknown outer settings conservatively retain the designer's existing reload behavior.
|
|
2
|
+
const visualKeys = new Set(['chartConfig', 'theme', 'color', 'componentName', 'title', 'title_i18n', 'height', 'minHeight', 'backgroundColor', 'backgroundStyle', 'backgroundImage', 'items', 'showFullscreenBtn'])
|
|
3
|
+
const dataConfig = config => {
|
|
4
|
+
const chart = config.chartConfig || {}
|
|
5
|
+
const map = chart['series-map'] || {}
|
|
6
|
+
return {
|
|
7
|
+
...Object.fromEntries(Object.entries(config).filter(([key]) => !visualKeys.has(key))),
|
|
8
|
+
refresh: chart.realtimeRefresh,
|
|
9
|
+
mapDimension: map.dimension,
|
|
10
|
+
mapAdcode: map.adcode
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function chartConfigRequiresReload (before, after, isEqual) {
|
|
15
|
+
return !isEqual(dataConfig(before || {}), dataConfig(after || {}))
|
|
16
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// New types reuse verified report protocols. No data snapshots are written to chartConfig.
|
|
2
|
+
export function excludeBoxplotMissingValues (params) {
|
|
3
|
+
const fields = [...new Set((params.chartData?.statisticalList || []).map(item => item.fieldCode).filter(Boolean))]
|
|
4
|
+
if (!fields.length) return
|
|
5
|
+
const scopes = JSON.parse(params.scopeParams || '[]').map(item => ({ ...item }))
|
|
6
|
+
if (scopes.length) {
|
|
7
|
+
scopes[0].lb = '(' + (scopes[0].lb || '')
|
|
8
|
+
const last = scopes[scopes.length - 1]
|
|
9
|
+
last.rb = (last.rb || '') + ')'
|
|
10
|
+
last.link = 'and'
|
|
11
|
+
}
|
|
12
|
+
fields.forEach(field => scopes.push({ field, mode: 'not_null', link: 'and' }))
|
|
13
|
+
scopes[scopes.length - 1].link = ''
|
|
14
|
+
params.scopeParams = JSON.stringify(scopes)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numeric = value => {
|
|
18
|
+
if (value === undefined || value === null || String(value).trim() === '') return null
|
|
19
|
+
const number = typeof value === 'number' ? value : Number(String(value ?? '').replace(/%$/, ''))
|
|
20
|
+
return Number.isFinite(number) && value !== null && value !== '' ? number : null
|
|
21
|
+
}
|
|
22
|
+
const failure = message => ({ hasData: false, message })
|
|
23
|
+
const quantile = (sorted, p) => {
|
|
24
|
+
const index = (sorted.length - 1) * p
|
|
25
|
+
const lower = Math.floor(index)
|
|
26
|
+
return sorted[lower] + (sorted[Math.ceil(index)] - sorted[lower]) * (index - lower)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function summarizeBoxplot (values) {
|
|
30
|
+
const sorted = values.map(numeric).filter(value => value !== null).sort((a, b) => a - b)
|
|
31
|
+
if (!sorted.length) return null
|
|
32
|
+
const q1 = quantile(sorted, 0.25)
|
|
33
|
+
const median = quantile(sorted, 0.5)
|
|
34
|
+
const q3 = quantile(sorted, 0.75)
|
|
35
|
+
const gap = (q3 - q1) * 1.5
|
|
36
|
+
const retained = sorted.filter(value => value >= q1 - gap && value <= q3 + gap)
|
|
37
|
+
return { value: [retained[0], q1, median, q3, retained[retained.length - 1]], outliers: sorted.filter(value => value < q1 - gap || value > q3 + gap), count: sorted.length }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function buildAdvancedChartOption (type, data, config = {}, chartData = {}, theme = '') {
|
|
41
|
+
const option = Object.fromEntries(Object.entries(config).filter(([key]) => key !== 'title' && !key.startsWith('series-') && key !== 'echartsOptionOverride'))
|
|
42
|
+
option.tooltip = { trigger: 'item', confine: true, ...option.tooltip }
|
|
43
|
+
if (option.legend?._orient) {
|
|
44
|
+
const { direction = 'bottom', horizontal = 'center', vertical = 'center' } = option.legend._orient
|
|
45
|
+
const across = direction === 'top' || direction === 'bottom'
|
|
46
|
+
option.legend = { ...option.legend, orient: across ? 'horizontal' : 'vertical', top: direction === 'top' ? '20px' : !across && vertical === 'top' ? '20px' : !across && vertical === 'center' ? 'center' : 'auto', bottom: direction === 'bottom' || (!across && vertical === 'bottom') ? '20px' : 'auto', left: direction === 'left' || (across && horizontal === 'left') ? '20px' : across && horizontal === 'center' ? 'center' : 'auto', right: direction === 'right' || (across && horizontal === 'right') ? '20px' : 'auto' }
|
|
47
|
+
delete option.legend._orient
|
|
48
|
+
}
|
|
49
|
+
if (option.dataZoom?.show) {
|
|
50
|
+
option.dataZoom = [{ type: 'slider', startValue: 0, ...option.dataZoom, endValue: Number(option.dataZoom.endValue || 5) - 1 }]
|
|
51
|
+
} else if (option.dataZoom && !Array.isArray(option.dataZoom)) delete option.dataZoom
|
|
52
|
+
if (type === 'boxplot') {
|
|
53
|
+
if (chartData.categoryList?.length || chartData.statisticalList?.length !== 2) return failure('箱线图需要两个数字统计字段,并且不设置分类维度')
|
|
54
|
+
if (chartData.statisticalList.some(item => item.type !== 'indexField' || !item.fieldCode || item.fieldCode === 'record')) return failure('箱线图请使用数字字段,不支持记录数或自定义统计项')
|
|
55
|
+
const rows = data?.data
|
|
56
|
+
if (!Array.isArray(rows) || !rows.length) return failure()
|
|
57
|
+
if (rows.some(row => !Array.isArray(row) || row.length !== 2)) return failure('箱线图需要原始数字对数据')
|
|
58
|
+
const summaries = [0, 1].map(index => summarizeBoxplot(rows.map(row => row[index])))
|
|
59
|
+
if (summaries.some(item => !item)) return failure()
|
|
60
|
+
const names = chartData.statisticalList.map((item, index) => item.name || `指标 ${index + 1}`)
|
|
61
|
+
option.grid = { containLabel: true, left: 30, right: 20, top: 30, bottom: 30, ...option.grid }
|
|
62
|
+
option.xAxis = { ...option.xAxis, type: 'category', data: names }
|
|
63
|
+
option.yAxis = { type: 'value', ...option.yAxis }
|
|
64
|
+
option.series = [{ type: 'boxplot', name: '箱线', ...config['series-boxplot'], data: summaries.map((item, index) => ({ name: names[index], value: item.value })) }]
|
|
65
|
+
const outliers = summaries.flatMap((item, index) => item.outliers.map(value => [index, value]))
|
|
66
|
+
option.series.push({ type: 'scatter', name: '离群值', data: outliers })
|
|
67
|
+
return { hasData: true, option }
|
|
68
|
+
}
|
|
69
|
+
const series = data?.series
|
|
70
|
+
if (!Array.isArray(series) || !series.length || series.every(item => !item.data?.length)) return failure()
|
|
71
|
+
if (series.some(row => !Array.isArray(row.data) || row.data.some(item => numeric(item.value) === null))) return failure('当前统计结果包含非数值,不能生成此图表')
|
|
72
|
+
if (type === 'gauge') {
|
|
73
|
+
const cells = series.flatMap(row => row.data)
|
|
74
|
+
if (cells.length !== 1) return failure('仪表盘需要单个统计值;请设置一个指标且不拆分分类')
|
|
75
|
+
const cell = cells[0]
|
|
76
|
+
const value = numeric(cell.value)
|
|
77
|
+
option.series = [{ type: 'gauge', min: Math.min(0, value), max: Math.max(100, value), progress: { show: true }, detail: { formatter: '{value}' }, ...config['series-gauge'], data: [{ ...cell, value }] }]
|
|
78
|
+
if (['dark', 'technology'].includes(theme)) {
|
|
79
|
+
const gauge = option.series[0]
|
|
80
|
+
gauge.axisLabel = { color: '#d9e1ec', ...gauge.axisLabel }
|
|
81
|
+
gauge.detail = { color: '#d9e1ec', ...gauge.detail }
|
|
82
|
+
gauge.title = { color: '#d9e1ec', ...gauge.title }
|
|
83
|
+
}
|
|
84
|
+
if (!(Number(option.series[0].max) > Number(option.series[0].min))) return failure('仪表盘最大刻度必须大于最小刻度')
|
|
85
|
+
delete option.xAxis
|
|
86
|
+
delete option.yAxis
|
|
87
|
+
delete option.grid
|
|
88
|
+
} else if (type === 'treemap') {
|
|
89
|
+
if (series.some(row => row.data.some(item => numeric(item.value) < 0))) return failure('矩形树图的统计值不能为负数')
|
|
90
|
+
option.series = [{ type: 'treemap', roam: false, breadcrumb: { show: true }, ...config['series-treemap'], data: series.map((row, index) => ({ name: row.name || `指标 ${index + 1}`, children: row.data.map(cell => ({ ...cell, value: numeric(cell.value) })) })) }]
|
|
91
|
+
delete option.xAxis
|
|
92
|
+
delete option.yAxis
|
|
93
|
+
delete option.grid
|
|
94
|
+
} else if (type === 'heatmap') {
|
|
95
|
+
const categories = series[0].data.map(item => item.name || '')
|
|
96
|
+
if (series.some(row => row.data.length !== categories.length || row.data.some((cell, index) => (cell.name || '') !== categories[index]))) return failure('热力图要求各指标使用同一组分类维度')
|
|
97
|
+
const cells = series.flatMap((row, rowIndex) => row.data.map((cell, colIndex) => ({ ...cell, value: [colIndex, rowIndex, numeric(cell.value)] })))
|
|
98
|
+
const values = cells.map(cell => cell.value[2])
|
|
99
|
+
option.grid = { containLabel: true, left: 30, right: 30, top: 30, bottom: 60, ...option.grid }
|
|
100
|
+
option.xAxis = { type: 'category', splitArea: { show: true }, ...option.xAxis, data: categories }
|
|
101
|
+
option.yAxis = { type: 'category', splitArea: { show: true }, ...option.yAxis, data: series.map((row, index) => row.name || `指标 ${index + 1}`) }
|
|
102
|
+
option.visualMap = { min: values.reduce((min, value) => Math.min(min, value), Infinity), max: values.reduce((max, value) => Math.max(max, value), 1), calculable: true, orient: 'horizontal', left: 'center', bottom: 0, ...option.visualMap }
|
|
103
|
+
option.series = [{ type: 'heatmap', label: { show: false }, ...config['series-heatmap'], data: cells }]
|
|
104
|
+
} else return failure('不支持的图表类型')
|
|
105
|
+
return { hasData: true, option }
|
|
106
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { getChartType } from './chart-registry'
|
|
2
|
+
|
|
3
|
+
const own = (value, key) => Object.prototype.hasOwnProperty.call(value, key)
|
|
4
|
+
const object = value => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
5
|
+
const unsafeKeys = new Set(['__proto__', 'prototype', 'constructor'])
|
|
6
|
+
const MAX_OVERRIDE_BYTES = 64 * 1024
|
|
7
|
+
|
|
8
|
+
// The override is JSON option syntax. Platform statistics still own all data arrays.
|
|
9
|
+
export function validateChartOptionOverride (override, baseOption = {}, chartType = '') {
|
|
10
|
+
const errors = []
|
|
11
|
+
if (!object(override)) return [{ path: '$', message: '覆盖层必须是 JSON 对象' }]
|
|
12
|
+
let encoded
|
|
13
|
+
try { encoded = JSON.stringify(override) } catch { return [{ path: '$', message: '覆盖层必须是可序列化的 JSON 对象' }] }
|
|
14
|
+
const size = new TextEncoder().encode(encoded).length
|
|
15
|
+
if (size > MAX_OVERRIDE_BYTES) errors.push({ path: '$', message: '覆盖层不能超过 64 KB' })
|
|
16
|
+
const visit = (value, path, depth = 0) => {
|
|
17
|
+
if (depth > 64) {
|
|
18
|
+
errors.push({ path, message: '配置层级不能超过 64 层' })
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
value.forEach((item, index) => visit(item, `${path}[${index}]`, depth + 1))
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
if (!object(value)) return
|
|
26
|
+
for (const [key, child] of Object.entries(value)) {
|
|
27
|
+
const childPath = path === '$' ? key : `${path}.${key}`
|
|
28
|
+
if (unsafeKeys.has(key)) errors.push({ path: childPath, message: '不支持的属性名' })
|
|
29
|
+
if (key === 'source' && (path === 'dataset' || /^dataset\[\d+\]$/.test(path))) errors.push({ path: childPath, message: '数据源由平台维护' })
|
|
30
|
+
if (key === 'data' && /^series\[\d+\]$/.test(path)) errors.push({ path: childPath, message: '系列数据由平台维护' })
|
|
31
|
+
visit(child, childPath, depth + 1)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
visit(override, '$')
|
|
35
|
+
|
|
36
|
+
if (own(override, 'series')) {
|
|
37
|
+
const baseSeries = Array.isArray(baseOption.series) ? baseOption.series : [baseOption.series].filter(Boolean)
|
|
38
|
+
if (!Array.isArray(override.series) || override.series.length !== baseSeries.length || !override.series.every(object)) {
|
|
39
|
+
errors.push({ path: 'series', message: `系列覆盖必须与当前 ${baseSeries.length} 个系列逐项对应` })
|
|
40
|
+
} else {
|
|
41
|
+
override.series.forEach((series, index) => {
|
|
42
|
+
if (own(series, 'type') && series.type !== baseSeries[index]?.type) errors.push({ path: `series[${index}].type`, message: '不能改变平台系列类型' })
|
|
43
|
+
if (own(series, 'coordinateSystem')) {
|
|
44
|
+
const coordinate = baseSeries[index]?.coordinateSystem || getChartType(chartType)?.coordinate
|
|
45
|
+
if (series.coordinateSystem !== coordinate) errors.push({ path: `series[${index}].coordinateSystem`, message: '不能改变平台坐标系' })
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(override.dataset)) errors.push({ path: 'dataset', message: '暂不支持替换数据集数组' })
|
|
51
|
+
if (own(override, 'dataset') && (!object(override.dataset) || Array.isArray(baseOption.dataset))) errors.push({ path: 'dataset', message: '不能替换平台数据集结构' })
|
|
52
|
+
for (const axis of ['xAxis', 'yAxis']) {
|
|
53
|
+
if (own(override, axis) && !(object(override[axis]) || (Array.isArray(override[axis]) && override[axis].length && override[axis].every(object)))) {
|
|
54
|
+
errors.push({ path: axis, message: '坐标轴必须是对象或非空对象数组' })
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (getChartType(chartType) && getChartType(chartType).coordinate !== 'cartesian2d') {
|
|
58
|
+
for (const axis of ['xAxis', 'yAxis', 'grid', 'dataZoom']) {
|
|
59
|
+
if (own(override, axis)) errors.push({ path: axis, message: '当前图表类型不使用直角坐标系' })
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return errors
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function mergeObject (base, patch) {
|
|
66
|
+
const result = object(base) ? { ...base } : {}
|
|
67
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
68
|
+
if (object(value)) result[key] = mergeObject(result[key], value)
|
|
69
|
+
else if (Array.isArray(value)) result[key] = value.map(item => object(item) ? mergeObject({}, item) : item)
|
|
70
|
+
else result[key] = value
|
|
71
|
+
}
|
|
72
|
+
return result
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function applyChartOptionOverride (baseOption, override, chartType = '') {
|
|
76
|
+
// Identity is intentional: charts saved before code mode keep the old option.
|
|
77
|
+
if (override === undefined) return baseOption
|
|
78
|
+
const errors = validateChartOptionOverride(override, baseOption, chartType)
|
|
79
|
+
if (errors.length) return baseOption
|
|
80
|
+
const { series, ...other } = override
|
|
81
|
+
const result = mergeObject(baseOption, other)
|
|
82
|
+
// Native component patches preserve platform axes/data; ordinary arrays still replace.
|
|
83
|
+
for (const key of ['xAxis', 'yAxis', 'grid', 'legend', 'visualMap', 'dataZoom']) {
|
|
84
|
+
if (Array.isArray(other[key])) {
|
|
85
|
+
const base = Array.isArray(baseOption[key]) ? baseOption[key] : [baseOption[key]].filter(Boolean)
|
|
86
|
+
result[key] = Array.from({ length: Math.max(base.length, other[key].length) }, (_, index) => mergeObject(base[index], other[key][index] || {}))
|
|
87
|
+
} else if (object(other[key]) && Array.isArray(baseOption[key])) {
|
|
88
|
+
result[key] = baseOption[key].map((item, index) => index === 0 ? mergeObject(item, other[key]) : item)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (series) {
|
|
92
|
+
result.series = baseOption.series.map((item, index) => mergeObject(item, series[index]))
|
|
93
|
+
}
|
|
94
|
+
return result
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function setChartOption (host, baseOption, override) {
|
|
98
|
+
host.chartOption = applyChartOptionOverride(baseOption, override, host.chartType)
|
|
99
|
+
if (host.designMode && host.$refs?.container) {
|
|
100
|
+
host.$refs.container.dispatchEvent(new CustomEvent('epx-chart-option-built', {
|
|
101
|
+
bubbles: true,
|
|
102
|
+
detail: { base: baseOption, effective: host.chartOption }
|
|
103
|
+
}))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Render an explicit editor preview in a temporary host; the visible chart stays untouched on failure.
|
|
108
|
+
export function validateChartOptionRendering (option, echarts) {
|
|
109
|
+
if (!echarts) return [{ path: '$', message: '等待图表加载后再预览' }]
|
|
110
|
+
const element = document.createElement('div')
|
|
111
|
+
element.style.cssText = 'position:fixed;left:-10000px;top:0;width:800px;height:400px;visibility:hidden;pointer-events:none'
|
|
112
|
+
document.body.appendChild(element)
|
|
113
|
+
let chart
|
|
114
|
+
try {
|
|
115
|
+
chart = echarts.init(element)
|
|
116
|
+
chart.setOption(option, { notMerge: true })
|
|
117
|
+
const expected = Array.isArray(option.series) ? option.series.length : option.series ? 1 : 0
|
|
118
|
+
if (chart.getOption && (chart.getOption().series?.length || 0) !== expected) throw new Error('当前 ECharts 未能加载全部系列类型')
|
|
119
|
+
return []
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return [{ path: '$', message: `图表预览失败:${error.message}` }]
|
|
122
|
+
} finally {
|
|
123
|
+
if (chart) chart.dispose()
|
|
124
|
+
element.remove()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Maps legacy visual fields to the native option paths they actually control.
|
|
2
|
+
export function chartOverridePaths (key, base = {}, patch = {}) {
|
|
3
|
+
if (key === 'title' || key.startsWith('title.')) return []
|
|
4
|
+
if (key.startsWith('series-')) {
|
|
5
|
+
const [group, ...parts] = key.split('.')
|
|
6
|
+
const type = group.slice(7) === 'wordcloud' ? 'wordCloud' : group.slice(7)
|
|
7
|
+
if (['total', 'totalText'].includes(parts[0])) return []
|
|
8
|
+
const native = parts[0] === 'showArea' ? ['areaStyle'] : parts[0] === 'barType' ? ['stack'] : parts.join('.') === 'label.customFormatter' ? ['label', 'formatter'] : parts
|
|
9
|
+
return (base.series || []).flatMap((series, index) => series.type === type ? [['series', index, ...native]] : [])
|
|
10
|
+
}
|
|
11
|
+
if (/^yAxis\.(leftAxis|rightAxis)\./.test(key)) {
|
|
12
|
+
const [, side, ...parts] = key.split('.')
|
|
13
|
+
return [['yAxis', side === 'leftAxis' ? 0 : 1, ...parts]]
|
|
14
|
+
}
|
|
15
|
+
if (['yAxis.leftName', 'yAxis.rightName'].includes(key)) return [['yAxis', key === 'yAxis.leftName' ? 0 : 1, 'name']]
|
|
16
|
+
if (key.startsWith('legend._orient.')) {
|
|
17
|
+
const fields = key.endsWith('.horizontal') ? ['left', 'right'] : key.endsWith('.vertical') ? ['top', 'bottom'] : ['orient', 'left', 'right', 'top', 'bottom']
|
|
18
|
+
return fields.map(field => ['legend', field])
|
|
19
|
+
}
|
|
20
|
+
const [root, ...parts] = key.split('.')
|
|
21
|
+
if (Array.isArray(patch[root])) return patch[root].map((_, index) => [root, index, ...parts])
|
|
22
|
+
return [[root, ...parts]]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const readPath = (value, path) => {
|
|
26
|
+
if (!path.length) return value
|
|
27
|
+
if (Array.isArray(value) && typeof path[0] !== 'number') return value.map(item => readPath(item, path)).find(item => item !== undefined)
|
|
28
|
+
if (!Array.isArray(value) && typeof path[0] === 'number') return path[0] === 0 ? readPath(value, path.slice(1)) : undefined
|
|
29
|
+
return readPath(value?.[path[0]], path.slice(1))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isChartPathOverridden (patch, key, base) {
|
|
33
|
+
return chartOverridePaths(key, base, patch).some(path => readPath(patch, path) !== undefined)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function clearChartOverridePath (patch, key, base) {
|
|
37
|
+
const remove = (value, path) => {
|
|
38
|
+
if (!value || !path.length) return
|
|
39
|
+
if (Array.isArray(value) && typeof path[0] !== 'number') {
|
|
40
|
+
value.forEach(item => remove(item, path))
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(value) && typeof path[0] === 'number') {
|
|
44
|
+
if (path[0] === 0) remove(value, path.slice(1))
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
const [part, ...rest] = path
|
|
48
|
+
if (!rest.length) {
|
|
49
|
+
if (Array.isArray(value)) value[part] = {}
|
|
50
|
+
else delete value[part]
|
|
51
|
+
} else {
|
|
52
|
+
remove(value[part], rest)
|
|
53
|
+
if (value[part] && !Array.isArray(value[part]) && typeof value[part] === 'object' && !Object.keys(value[part]).length && !Array.isArray(value)) delete value[part]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const paths = chartOverridePaths(key, base, patch)
|
|
57
|
+
for (const path of paths) remove(patch, path)
|
|
58
|
+
for (const root of new Set(paths.map(path => path[0]))) {
|
|
59
|
+
const value = patch[root]
|
|
60
|
+
if (Array.isArray(value) && value.every(item => item && typeof item === 'object' && !Object.keys(item).length)) delete patch[root]
|
|
61
|
+
}
|
|
62
|
+
return patch
|
|
63
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Shared metadata; persisted type names and backend request types retain their existing meaning.
|
|
2
|
+
export const chartTypes = [
|
|
3
|
+
{ type: 'table', text: '统计表', icon: 'epx-icon-tongjibiao', component: 'chart-table', requestType: 'table', coordinate: 'none' },
|
|
4
|
+
{ type: 'pie', text: '饼状图', icon: 'epx-icon-bingzhuangtu', component: 'chart-common', requestType: 'pie', coordinate: 'none' },
|
|
5
|
+
{ type: 'circularPie', text: '环形饼图', icon: 'epx-icon-bingzhuangtu', component: 'chart-common', requestType: 'pie', coordinate: 'none' },
|
|
6
|
+
{ type: 'line', text: '折线图', icon: 'epx-icon-zhexiantu', component: 'chart-common', requestType: 'line', coordinate: 'cartesian2d' },
|
|
7
|
+
{ type: 'column', text: '柱状图', icon: 'epx-icon-zhuzhuangtu', component: 'chart-common', requestType: 'bar', coordinate: 'cartesian2d' },
|
|
8
|
+
{ type: 'horiColumn', text: '横向柱图', icon: 'epx-icon-zhuzhuangtu', component: 'chart-common', requestType: 'bar', cellScopeType: 'column', coordinate: 'cartesian2d' },
|
|
9
|
+
{ type: 'funnel', text: '漏斗图', icon: 'epx-icon-loudoutu', component: 'chart-common', requestType: 'funnel', coordinate: 'none' },
|
|
10
|
+
{ type: 'wordcloud', text: '词云', icon: 'epx-icon-ciyun', component: 'chart-wordcloud', requestType: 'wordCloud', coordinate: 'none' },
|
|
11
|
+
{ type: 'radar', text: '雷达图', icon: 'epx-icon-leidatu', component: 'chart-radar', requestType: 'radar', coordinate: 'radar' },
|
|
12
|
+
{ type: 'columnAndLine', text: '折柱混合', icon: 'epx-icon-zhezhutu', component: 'chart-common', requestType: 'bar', coordinate: 'cartesian2d' },
|
|
13
|
+
{ type: 'scatter', text: '散点图', icon: 'epx-icon-sandiantu', component: 'chart-scatter', requestType: 'scatter', coordinate: 'cartesian2d', binding: 'numericPairs', drill: false },
|
|
14
|
+
{ type: 'map', text: '地图', icon: 'epx-icon-ditu', component: 'chart-map', requestType: 'map', coordinate: 'geo' },
|
|
15
|
+
{ type: 'gauge', text: '仪表盘', icon: 'epx-icon-leidatu', component: 'chart-advanced', requestType: 'bar', cellScopeType: 'column', coordinate: 'none', dataHint: '单个统计值;设置一个指标且不拆分分类。' },
|
|
16
|
+
{ type: 'treemap', text: '矩形树图', icon: 'epx-icon-tongjibiao', component: 'chart-advanced', requestType: 'bar', cellScopeType: 'column', coordinate: 'none', dataHint: '按指标、分类组成两层矩形树,使用非负统计值;叶子支持钻取。' },
|
|
17
|
+
{ type: 'heatmap', text: '热力图', icon: 'epx-icon-zhuzhuangtu', component: 'chart-advanced', requestType: 'bar', cellScopeType: 'column', coordinate: 'cartesian2d', dataHint: '横轴为分类,纵轴为指标;各指标使用同一组分类。' },
|
|
18
|
+
{ type: 'boxplot', text: '箱线图', selectable: false, icon: 'epx-icon-zhexiantu', component: 'chart-advanced', requestType: 'scatter', coordinate: 'cartesian2d', binding: 'numericPairs', drill: false, dataHint: '选择两个数字统计字段,不设置分类;使用原始值计算四分位数与 1.5 倍四分位距的离群值,不支持钻取。' }
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
export const selectableChartTypes = chartTypes.filter(item => item.selectable !== false)
|
|
22
|
+
|
|
23
|
+
export function getChartType (type) {
|
|
24
|
+
return chartTypes.find(item => item.type === (type === 'bar' ? 'column' : type))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const chartConfigCategories = [
|
|
28
|
+
{ key: 'all', label: '全部' },
|
|
29
|
+
{ key: 'appearance', label: '外观' }, { key: 'axis', label: '坐标与刻度' },
|
|
30
|
+
{ key: 'shape', label: '图形' }, { key: 'label', label: '标签与提示' },
|
|
31
|
+
{ key: 'interaction', label: '交互' }, { key: 'advanced', label: '高级' }
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
export function getChartConfigCategory (key) {
|
|
35
|
+
if (['title', 'grid', 'color', 'backgroundColor'].includes(key)) return 'appearance'
|
|
36
|
+
if (['xAxis', 'yAxis', 'dualAxes', 'dataZoom'].includes(key)) return 'axis'
|
|
37
|
+
if (key.startsWith('series-') || ['series.map', 'radar', 'scatter', 'table', 'visualMap'].includes(key)) return 'shape'
|
|
38
|
+
if (['legend', 'tooltip'].includes(key)) return 'label'
|
|
39
|
+
if (key === 'toolbox') return 'interaction'
|
|
40
|
+
return 'advanced'
|
|
41
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Shared lifecycle for inline charts and saved report charts.
|
|
2
|
+
import { getChartType } from './chart-registry'
|
|
3
|
+
|
|
4
|
+
const registeredThemes = new WeakSet()
|
|
5
|
+
export function registerChartThemes (echarts, themes) {
|
|
6
|
+
if (registeredThemes.has(echarts)) return
|
|
7
|
+
for (const key in themes) echarts.registerTheme(key, themes[key])
|
|
8
|
+
registeredThemes.add(echarts)
|
|
9
|
+
}
|
|
10
|
+
export function disposeChartHost (host) {
|
|
11
|
+
if (host.observedChartDom) {
|
|
12
|
+
host.resizeObserver?.unobserve(host.observedChartDom)
|
|
13
|
+
host.observedChartDom = null
|
|
14
|
+
}
|
|
15
|
+
if (!host.myChart) return
|
|
16
|
+
host.myChart.off('click', host.openPivotPage)
|
|
17
|
+
host.myChart.dispose()
|
|
18
|
+
host.myChart = null
|
|
19
|
+
host.renderedChartTheme = null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function renderChartHost (host, option, settings) {
|
|
23
|
+
const element = host.$refs?.chart
|
|
24
|
+
if (!element || !host.echarts || !option) return false
|
|
25
|
+
const { width, height } = element.getBoundingClientRect()
|
|
26
|
+
if (width <= 0 || height <= 0) return false
|
|
27
|
+
|
|
28
|
+
const staleDom = host.myChart && host.myChart.getDom && host.myChart.getDom() !== element
|
|
29
|
+
const theme = settings && Object.prototype.hasOwnProperty.call(settings, 'theme') ? settings.theme : host.chartTheme
|
|
30
|
+
const changedTheme = host.myChart && host.renderedChartTheme !== theme
|
|
31
|
+
if (staleDom || changedTheme) disposeChartHost(host)
|
|
32
|
+
if (!host.myChart) {
|
|
33
|
+
host.myChart = host.echarts.init(element, theme)
|
|
34
|
+
host.renderedChartTheme = theme
|
|
35
|
+
if (host.openClickEvent) host.myChart.on('click', host.openPivotPage)
|
|
36
|
+
}
|
|
37
|
+
// Header/search controls can change the plot height while the outer card stays fixed.
|
|
38
|
+
if (host.resizeObserver && host.observedChartDom !== element) {
|
|
39
|
+
if (host.observedChartDom) host.resizeObserver.unobserve(host.observedChartDom)
|
|
40
|
+
host.resizeObserver.observe(element)
|
|
41
|
+
host.observedChartDom = element
|
|
42
|
+
}
|
|
43
|
+
// Old code disposed on every update, so notMerge preserves its full-replacement semantics.
|
|
44
|
+
try {
|
|
45
|
+
host.myChart.setOption(option, { notMerge: true })
|
|
46
|
+
const expected = Array.isArray(option.series) ? option.series.length : option.series ? 1 : 0
|
|
47
|
+
const enforceSeries = getChartType(host.chartType)?.component === 'chart-advanced' || host.chartConfigs?.chartConfig?.echartsOptionOverride !== undefined
|
|
48
|
+
if (enforceSeries && host.myChart.getOption && (host.myChart.getOption().series?.length || 0) !== expected) throw new Error('未能加载全部系列类型')
|
|
49
|
+
} catch (error) {
|
|
50
|
+
disposeChartHost(host)
|
|
51
|
+
host.error = true
|
|
52
|
+
host.chartErrorText = `图表配置无法渲染:${error.message}`
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
return true
|
|
56
|
+
}
|