@epxing/core 5.3.0-beta.2 → 5.3.0-beta.3
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 +26 -25
- package/README.md +3 -1
- package/dist/.cache/route-chart-release/frontend/frame/public/js/ecStat.min.js +4 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts-wordcloud.min.js +4 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts.min.js +4 -0
- package/dist/_virtual/_plugin-vue_export-helper.js +10 -0
- package/dist/_virtual/jsencrypt.min.js +1 -1
- package/dist/assets/ecStat.min-BrTYPOXX.js +1 -0
- package/dist/assets/echarts-wordcloud.min-nWR4Hzny.js +3 -0
- package/dist/assets/echarts.min-DROS9E5X.js +45 -0
- package/dist/assets/role_select-DTqRlFNz.webp +0 -0
- package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/jsencrypt@3.5.4/_vendor/jsencrypt/bin/jsencrypt.min.js +1 -1
- package/dist/src/RootApp.js +54 -0
- package/dist/src/api/createHttp.js +6 -0
- package/dist/src/app-ui-settings.js +49 -0
- package/dist/src/axios.js +10 -15
- package/dist/src/chart-runtime-assets.js +9 -0
- package/dist/src/create-app.js +3 -6
- package/dist/src/index.js +2 -0
- package/dist/src/loadComponent.js +2 -2
- package/dist/src/menu-route.js +11 -0
- package/dist/src/mixins/component.js +3 -0
- package/dist/src/navigation-context.js +47 -0
- package/dist/src/navigation.js +43 -12
- package/dist/src/package-install.js +3 -2
- package/dist/src/plugins/element-plus.js +8 -8
- package/dist/src/public-api.js +4 -2
- package/dist/src/route-components.js +9 -0
- package/dist/src/router/config.js +7 -8
- package/dist/src/runtime-services.js +1 -1
- package/dist/src/runtime-utils/meta.js +3 -0
- package/dist/src/runtime-utils/pdf.viewer.js +31 -15
- package/dist/src/runtime-utils/util.js +29 -5
- package/dist/src/shared-packages.js +1 -3
- package/dist/src/store/modules/list.js +25 -3
- package/dist/src/store/modules/meta.js +49 -7
- package/dist/src/style-presets.js +4 -4
- package/dist/src/ui-settings.js +90 -18
- package/dist/src/views/App.js +48 -0
- package/dist/src/views/AppRoleSelect.js +233 -0
- package/dist/src/views/Error.js +210 -0
- package/dist/src/views/Module.js +173 -0
- package/dist/style.css +251 -0
- package/package.json +4 -4
- package/src/RootApp.vue +75 -0
- package/src/api/createHttp.js +7 -0
- package/src/api/index.js +47 -47
- package/src/app-ui-settings.js +31 -0
- package/src/axios.js +311 -318
- package/src/chart-runtime-assets.js +7 -0
- package/src/create-app.js +3 -7
- package/src/index.js +28 -28
- package/src/install.js +157 -157
- package/src/loadComponent.js +187 -187
- package/src/loadLibrary.js +99 -99
- package/src/menu-route.js +12 -1
- package/src/mixins/component.js +1464 -1461
- package/src/navigation-context.js +49 -0
- package/src/navigation.js +208 -176
- package/src/package-install.js +2 -1
- package/src/plugins/element-plus.js +302 -302
- package/src/plugins/frame.js +178 -178
- package/src/public-api.js +1 -0
- package/src/route-components.js +7 -0
- package/src/router/config.js +861 -864
- package/src/router/public.js +1 -1
- package/src/runtime-services.js +1 -1
- package/src/runtime-utils/fieldFactory.js +179 -179
- package/src/runtime-utils/meta.js +399 -378
- package/src/runtime-utils/pdf.viewer.js +672 -644
- package/src/runtime-utils/util.js +1357 -1330
- package/src/shared-packages.js +1 -3
- package/src/store/modules/config.js +351 -351
- package/src/store/modules/list.js +30 -3
- package/src/store/modules/locale.js +236 -236
- package/src/store/modules/meta.js +314 -265
- package/src/style-presets.js +4 -4
- package/src/ui-settings.js +84 -23
- package/src/views/App.vue +53 -0
- package/src/views/AppRoleSelect.vue +334 -0
- package/src/views/Error.vue +63 -0
- package/src/views/Module.vue +210 -0
- package/src/xss.js +26 -26
- package/types/app.d.ts +10 -10
- package/types/axios.d.ts +1 -1
- package/types/component-mixin.d.ts +1 -1
- package/types/field-factory.d.ts +1 -1
- package/types/global-mixin.d.ts +1 -1
- package/types/http.d.ts +1 -1
- package/types/index.d.ts +3 -0
- package/types/meta.d.ts +1 -1
- package/types/navigation.d.ts +21 -21
- package/types/pdf-viewer.d.ts +1 -1
- package/types/runtime.d.ts +13 -13
- package/types/store.d.ts +1 -1
- package/types/util.d.ts +2 -2
- /package/dist/{build → .cache/route-chart-release/frontend/frame/build}/stubs/empty-components.js +0 -0
- /package/dist/{src → .cache/route-chart-release/frontend/frame/src}/element-icons.names.js +0 -0
- /package/dist/{src → .cache/route-chart-release/frontend/frame/src}/element-plus.lazy.js +0 -0
- /package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/element-plus@2.14.3_vue@3.5.39_typescript@5.9.3_/_vendor/element-plus/dist/locale/en.js +0 -0
- /package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/element-plus@2.14.3_vue@3.5.39_typescript@5.9.3_/_vendor/element-plus/dist/locale/zh-cn.js +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import '../../style.css';
|
|
2
2
|
import util from "./util.js";
|
|
3
3
|
const DEFAULT_CACHE_SIZE = 10;
|
|
4
|
+
const MAX_CANVAS_PIXELS = 16777216;
|
|
5
|
+
function releaseCanvas(canvas) {
|
|
6
|
+
canvas.width = 0;
|
|
7
|
+
canvas.height = 0;
|
|
8
|
+
}
|
|
4
9
|
function binarySearchFirstItem(items, condition) {
|
|
5
10
|
var minIndex = 0;
|
|
6
11
|
var maxIndex = items.length - 1;
|
|
@@ -167,18 +172,18 @@ class PdfViewer {
|
|
|
167
172
|
}
|
|
168
173
|
this.scrollState = null;
|
|
169
174
|
for (const item of this.pages) {
|
|
170
|
-
if (item.div
|
|
175
|
+
if (!item.div) continue;
|
|
176
|
+
for (const canvas of item.div.querySelectorAll("canvas")) releaseCanvas(canvas);
|
|
177
|
+
if (item.div.parentNode) item.div.parentNode.removeChild(item.div);
|
|
171
178
|
}
|
|
172
179
|
this.pages = [];
|
|
173
180
|
this.loadViews = [];
|
|
174
181
|
this.searchTextArr = [];
|
|
175
|
-
if (this.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
} catch (e) {
|
|
179
|
-
}
|
|
180
|
-
this.pdfDocument = null;
|
|
182
|
+
if (this.loadingTask) {
|
|
183
|
+
this.loadingTask.destroy();
|
|
184
|
+
this.loadingTask = null;
|
|
181
185
|
}
|
|
186
|
+
this.pdfDocument = null;
|
|
182
187
|
}
|
|
183
188
|
async searchTextInPDF(searchText) {
|
|
184
189
|
const numPages = this.pdfDocument.numPages;
|
|
@@ -296,12 +301,16 @@ class PdfViewer {
|
|
|
296
301
|
pageRotate: 0
|
|
297
302
|
};
|
|
298
303
|
await this.loadPdf();
|
|
299
|
-
|
|
304
|
+
if (this.destroyed) return;
|
|
305
|
+
this.loadingTask = this.pdfJs.getDocument({
|
|
300
306
|
url: this.pdfConfig.url,
|
|
301
307
|
cMapUrl: this.pdfConfig.cMapUrl,
|
|
302
308
|
cMapPacked: this.pdfConfig.cMapPacked
|
|
303
|
-
})
|
|
309
|
+
});
|
|
310
|
+
return this.loadingTask.promise.then((pdfDocument) => {
|
|
304
311
|
this.load(pdfDocument);
|
|
312
|
+
}).catch((err) => {
|
|
313
|
+
if (!this.destroyed) throw err;
|
|
305
314
|
});
|
|
306
315
|
}
|
|
307
316
|
load(pdfDocument) {
|
|
@@ -424,6 +433,7 @@ class PdfViewer {
|
|
|
424
433
|
if (node.className.includes("pdf-viewer-loading")) {
|
|
425
434
|
node.style.display = "block";
|
|
426
435
|
} else {
|
|
436
|
+
if (node.tagName === "CANVAS") releaseCanvas(node);
|
|
427
437
|
div.removeChild(node);
|
|
428
438
|
}
|
|
429
439
|
}
|
|
@@ -435,18 +445,18 @@ class PdfViewer {
|
|
|
435
445
|
if (div.getAttribute("data-loaded")) continue;
|
|
436
446
|
div.setAttribute("data-loaded", true);
|
|
437
447
|
this.pdfDocument.getPage(item.view.id).then((page) => {
|
|
448
|
+
if (this.destroyed) return;
|
|
438
449
|
const canvas = document.createElement("canvas");
|
|
439
450
|
const ctx = canvas.getContext("2d", {
|
|
440
451
|
alpha: false
|
|
441
452
|
});
|
|
442
453
|
const initViewport = page.getViewport({ scale: 1 });
|
|
443
|
-
let scale = 1;
|
|
444
|
-
if (this.pdfConfig.zoom === "page-width") {
|
|
445
|
-
scale = Math.ceil(document.body.offsetWidth / initViewport.width);
|
|
446
|
-
} else {
|
|
447
|
-
scale = this.pdfConfig.zoom;
|
|
448
|
-
}
|
|
449
454
|
const rotation = (this.pdfConfig.pageRotate + initViewport.rotation) % 360;
|
|
455
|
+
const baseViewport = page.getViewport({ scale: 1, rotation });
|
|
456
|
+
const cssWidth = div.clientWidth || this.pdfConfig.viewerContainer.offsetWidth || baseViewport.width;
|
|
457
|
+
let scale = cssWidth / baseViewport.width * (window.devicePixelRatio || 1);
|
|
458
|
+
const pixels = baseViewport.width * baseViewport.height * scale * scale;
|
|
459
|
+
if (pixels > MAX_CANVAS_PIXELS) scale *= Math.sqrt(MAX_CANVAS_PIXELS / pixels);
|
|
450
460
|
const viewport = page.getViewport({ scale, rotation });
|
|
451
461
|
canvas.width = viewport.width;
|
|
452
462
|
canvas.height = viewport.height;
|
|
@@ -459,11 +469,17 @@ class PdfViewer {
|
|
|
459
469
|
};
|
|
460
470
|
var renderTask = page.render(renderContext);
|
|
461
471
|
renderTask.promise.then(() => {
|
|
472
|
+
if (this.destroyed) {
|
|
473
|
+
releaseCanvas(canvas);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
462
476
|
const loading = item.view.div.querySelector(".pdf-viewer-loading");
|
|
463
477
|
loading.style.display = "none";
|
|
464
478
|
item.view.div.appendChild(canvas);
|
|
465
479
|
this.loadViews.push(item.view);
|
|
466
480
|
cb && cb();
|
|
481
|
+
}, () => {
|
|
482
|
+
releaseCanvas(canvas);
|
|
467
483
|
});
|
|
468
484
|
});
|
|
469
485
|
}
|
|
@@ -7,6 +7,8 @@ import * as formula from "@epxing/utils/src/formula";
|
|
|
7
7
|
import { evalWith } from "@epxing/utils/src/eval-with";
|
|
8
8
|
import { useVuePlugin, getApp } from "../app.js";
|
|
9
9
|
import { resolveRouteRole } from "../menu-route.js";
|
|
10
|
+
import chartRuntimeAssets from "../chart-runtime-assets.js";
|
|
11
|
+
import wordcloudUrl from "../../.cache/route-chart-release/frontend/frame/public/js/echarts-wordcloud.min.js";
|
|
10
12
|
const installingLibraries = /* @__PURE__ */ new Map();
|
|
11
13
|
class Util {
|
|
12
14
|
constructor() {
|
|
@@ -585,7 +587,8 @@ class Util {
|
|
|
585
587
|
}
|
|
586
588
|
script.onerror = function() {
|
|
587
589
|
console.error("[util.loadJS] 加载失败:" + url);
|
|
588
|
-
|
|
590
|
+
if (options.onerror) options.onerror(new Error("脚本加载失败:" + url));
|
|
591
|
+
else callback();
|
|
589
592
|
};
|
|
590
593
|
script.src = url;
|
|
591
594
|
document.getElementsByTagName("head")[0].appendChild(script);
|
|
@@ -788,7 +791,7 @@ class Util {
|
|
|
788
791
|
const publicPath = this.getPublicPath();
|
|
789
792
|
const jsDir = this.getStaticJsDir();
|
|
790
793
|
if (plugin === "luckysheet") {
|
|
791
|
-
const loadPromise = loadFile([publicPath + "luckysheet/pluginsCss.css", publicPath + "luckysheet/plugins.css", publicPath + "luckysheet/luckysheet.css", publicPath + "
|
|
794
|
+
const loadPromise = loadFile([publicPath + "luckysheet/pluginsCss.css", publicPath + "luckysheet/plugins.css", publicPath + "luckysheet/luckysheet.css", publicPath + "luckysheet/iconfont.css", publicPath + "luckysheet/plugin.js", publicPath + "luckysheet/luckysheet.umd.js"]).then(() => globalThis.luckysheet);
|
|
792
795
|
this.loadPlugins[plugin] = loadPromise;
|
|
793
796
|
return loadPromise;
|
|
794
797
|
} else if (plugin === "BMap") {
|
|
@@ -828,7 +831,26 @@ class Util {
|
|
|
828
831
|
this.loadPlugins[plugin] = loadPromise;
|
|
829
832
|
return loadPromise;
|
|
830
833
|
} else if (plugin === "echarts") {
|
|
831
|
-
const
|
|
834
|
+
const files = window.STATIC_JS_DIR ? [publicPath + jsDir + "echarts.min.js?v=6.0.0-full", publicPath + jsDir + "ecStat.min.js"] : chartRuntimeAssets;
|
|
835
|
+
const loadPromise = Promise.all(files.map((url) => new Promise((resolve, reject) => {
|
|
836
|
+
this.loadJS({ url, callback: resolve, onerror: reject });
|
|
837
|
+
}))).then(() => {
|
|
838
|
+
if (!globalThis.echarts || !globalThis.ecStat) throw new Error("图表资源加载失败,请检查 ECharts 和 ecStat 脚本");
|
|
839
|
+
return globalThis.echarts;
|
|
840
|
+
}).catch((error) => {
|
|
841
|
+
delete this.loadPlugins[plugin];
|
|
842
|
+
throw error;
|
|
843
|
+
});
|
|
844
|
+
this.loadPlugins[plugin] = loadPromise;
|
|
845
|
+
return loadPromise;
|
|
846
|
+
} else if (plugin === "echarts-wordcloud") {
|
|
847
|
+
const url = window.STATIC_JS_DIR ? publicPath + jsDir + "echarts-wordcloud.min.js" : wordcloudUrl;
|
|
848
|
+
const loadPromise = new Promise((resolve, reject) => {
|
|
849
|
+
this.loadJS({ url, callback: resolve, onerror: reject });
|
|
850
|
+
}).catch((error) => {
|
|
851
|
+
delete this.loadPlugins[plugin];
|
|
852
|
+
throw error;
|
|
853
|
+
});
|
|
832
854
|
this.loadPlugins[plugin] = loadPromise;
|
|
833
855
|
return loadPromise;
|
|
834
856
|
} else if (plugin === "pdf") {
|
|
@@ -1054,7 +1076,8 @@ class Util {
|
|
|
1054
1076
|
}
|
|
1055
1077
|
encrypt(content, key, { type } = {}) {
|
|
1056
1078
|
if (type === "aes") {
|
|
1057
|
-
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((
|
|
1079
|
+
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((cryptoModule) => {
|
|
1080
|
+
const CryptoJS = "default" in cryptoModule ? cryptoModule.default : cryptoModule;
|
|
1058
1081
|
const base64Key = atob(key);
|
|
1059
1082
|
const aesKey = CryptoJS.enc.Utf8.parse(base64Key.toString(CryptoJS.enc.Utf8));
|
|
1060
1083
|
const encrypted = CryptoJS.AES.encrypt(content, aesKey, {
|
|
@@ -1074,7 +1097,8 @@ class Util {
|
|
|
1074
1097
|
}
|
|
1075
1098
|
decrypt(content, { type, key }) {
|
|
1076
1099
|
if (type === "aes") {
|
|
1077
|
-
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((
|
|
1100
|
+
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((cryptoModule) => {
|
|
1101
|
+
const CryptoJS = "default" in cryptoModule ? cryptoModule.default : cryptoModule;
|
|
1078
1102
|
const base64Key = atob(key);
|
|
1079
1103
|
const aesKey = CryptoJS.enc.Utf8.parse(base64Key.toString(CryptoJS.enc.Utf8));
|
|
1080
1104
|
const decrypted = CryptoJS.AES.decrypt(content, aesKey, {
|
|
@@ -4,9 +4,7 @@ function publishSharedPackage(name, api) {
|
|
|
4
4
|
const registry = globalThis.__EPX_PACKAGES__ || (globalThis.__EPX_PACKAGES__ = /* @__PURE__ */ Object.create(null));
|
|
5
5
|
const namespace = registry[name] || (registry[name] = {});
|
|
6
6
|
Object.assign(namespace, api);
|
|
7
|
-
if (name === "@epxing/
|
|
8
|
-
registry["@epxing/component"] = namespace;
|
|
9
|
-
registry["@epxing/components"] = namespace;
|
|
7
|
+
if (name === "@epxing/components") {
|
|
10
8
|
if (!namespace.install) namespace.install = (app) => installComponents(app, Object.fromEntries(
|
|
11
9
|
Object.entries(namespace).filter(([key]) => key !== "install" && key !== "default")
|
|
12
10
|
));
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import '../../../style.css';
|
|
2
|
-
import { markRaw } from "vue";
|
|
2
|
+
import { reactive, markRaw } from "vue";
|
|
3
3
|
import client from "../../api/index.js";
|
|
4
4
|
import { ADD_TAG, ADD_LIST, ADD_OBJECT_COUNT, ADD_OBJECT } from "../actions.js";
|
|
5
5
|
import { touchKeys, prune, touch } from "../lru.js";
|
|
6
|
+
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
|
|
7
|
+
const lists = reactive({});
|
|
8
|
+
const listSignals = /* @__PURE__ */ new Map();
|
|
9
|
+
const signalOf = (key) => {
|
|
10
|
+
let signal = listSignals.get(key);
|
|
11
|
+
if (!signal) {
|
|
12
|
+
signal = reactive({ version: 0 });
|
|
13
|
+
listSignals.set(key, signal);
|
|
14
|
+
}
|
|
15
|
+
return signal;
|
|
16
|
+
};
|
|
6
17
|
const formatData = (array, values = [], list2) => {
|
|
7
18
|
return array.map((item) => {
|
|
8
19
|
item.defaultIndex = 0;
|
|
@@ -35,7 +46,7 @@ const markPayloadRaw = (data) => {
|
|
|
35
46
|
};
|
|
36
47
|
const list = {
|
|
37
48
|
state: {
|
|
38
|
-
lists
|
|
49
|
+
lists,
|
|
39
50
|
treeList: {},
|
|
40
51
|
objects: {},
|
|
41
52
|
object_counts: {},
|
|
@@ -44,6 +55,7 @@ const list = {
|
|
|
44
55
|
},
|
|
45
56
|
getters: {
|
|
46
57
|
getCodeById: (state) => (id) => {
|
|
58
|
+
signalOf(id).version;
|
|
47
59
|
const list2 = state.lists[id];
|
|
48
60
|
if (list2) {
|
|
49
61
|
touch("lists", id);
|
|
@@ -69,12 +81,22 @@ const list = {
|
|
|
69
81
|
getTagListByMetaId: (state) => (id) => state.tags[id]
|
|
70
82
|
},
|
|
71
83
|
mutations: {
|
|
84
|
+
// 逐 key 写入并只通知该 key 的信号,不整体替换 lists
|
|
72
85
|
[ADD_LIST](state, data) {
|
|
73
86
|
touchKeys("lists", Object.keys(data));
|
|
74
|
-
|
|
87
|
+
const rawData = markPayloadRaw(data);
|
|
88
|
+
for (const key in rawData) {
|
|
89
|
+
state.lists[key] = rawData[key];
|
|
90
|
+
signalOf(key).version++;
|
|
91
|
+
}
|
|
92
|
+
const keep = prune("lists", { ...state.lists }, LIMITS.lists);
|
|
93
|
+
for (const key in state.lists) {
|
|
94
|
+
if (!hasOwn(keep, key)) delete state.lists[key];
|
|
95
|
+
}
|
|
75
96
|
},
|
|
76
97
|
"DELETE_LIST"(state, payload) {
|
|
77
98
|
delete state.lists[payload.key];
|
|
99
|
+
signalOf(payload.key).version++;
|
|
78
100
|
},
|
|
79
101
|
"ADD_TREE_LIST"(state, data) {
|
|
80
102
|
touchKeys("treeList", Object.keys(data));
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import '../../../style.css';
|
|
2
|
-
import { markRaw } from "vue";
|
|
2
|
+
import { reactive, markRaw, toRaw } from "vue";
|
|
3
3
|
import client from "../../api/index.js";
|
|
4
4
|
import Meta from "../../runtime-utils/meta.js";
|
|
5
5
|
import { ADD_META } from "../actions.js";
|
|
6
6
|
import { touch, touchKeys, prune } from "../lru.js";
|
|
7
7
|
const ADD_SIMPLE_META = "ADD_SIMPLE_META";
|
|
8
|
+
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
|
|
9
|
+
const metas = reactive({});
|
|
10
|
+
const metaAliases = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
const aliasesOf = (state) => {
|
|
12
|
+
const cache = toRaw(state.metas);
|
|
13
|
+
if (!metaAliases.has(cache)) metaAliases.set(cache, {});
|
|
14
|
+
return metaAliases.get(cache);
|
|
15
|
+
};
|
|
16
|
+
const metaSignals = /* @__PURE__ */ new Map();
|
|
17
|
+
const signalOf = (key) => {
|
|
18
|
+
let signal = metaSignals.get(key);
|
|
19
|
+
if (!signal) {
|
|
20
|
+
signal = reactive({ version: 0 });
|
|
21
|
+
metaSignals.set(key, signal);
|
|
22
|
+
}
|
|
23
|
+
return signal;
|
|
24
|
+
};
|
|
25
|
+
const notifyMeta = (key) => {
|
|
26
|
+
const signal = metaSignals.get(key);
|
|
27
|
+
if (signal) signal.version++;
|
|
28
|
+
};
|
|
8
29
|
const ADD_META_RELATION_FIELDS = "ADD_META_RELATION_FIELDS";
|
|
9
30
|
const ADD_META_VIEW_FIELDS = "ADD_META_VIEW_FIELDS";
|
|
10
31
|
const LIMITS = {
|
|
@@ -12,9 +33,9 @@ const LIMITS = {
|
|
|
12
33
|
metaRelationFields: { soft: 50, hard: 120 },
|
|
13
34
|
metaViewFields: { soft: 50, hard: 200 }
|
|
14
35
|
};
|
|
15
|
-
const findMeta = (
|
|
16
|
-
for (const key in
|
|
17
|
-
const item =
|
|
36
|
+
const findMeta = (metas2, matcher) => {
|
|
37
|
+
for (const key in metas2) {
|
|
38
|
+
const item = metas2[key];
|
|
18
39
|
if (item && matcher(item)) {
|
|
19
40
|
touch("metas", key);
|
|
20
41
|
return item;
|
|
@@ -46,7 +67,7 @@ const formatFields = (arr, flag = "") => {
|
|
|
46
67
|
};
|
|
47
68
|
const meta = {
|
|
48
69
|
state: {
|
|
49
|
-
metas
|
|
70
|
+
metas,
|
|
50
71
|
simpleMetas: {},
|
|
51
72
|
metaStatus: {},
|
|
52
73
|
simpleMetaStatus: {},
|
|
@@ -56,9 +77,24 @@ const meta = {
|
|
|
56
77
|
metaViewFieldStatus: {}
|
|
57
78
|
},
|
|
58
79
|
mutations: {
|
|
80
|
+
// 逐 key 写入并只通知该 key(及其别名)的信号,不整体替换 metas
|
|
59
81
|
[ADD_META](state, data) {
|
|
60
82
|
touchKeys("metas", Object.keys(data));
|
|
61
|
-
|
|
83
|
+
const metaAlias = aliasesOf(state);
|
|
84
|
+
for (const key in data) {
|
|
85
|
+
const meta2 = data[key];
|
|
86
|
+
state.metas[key] = meta2;
|
|
87
|
+
const aliases = [meta2.id, meta2.code, `${meta2.code}@${meta2.systemCode}@${meta2.clientCode}`];
|
|
88
|
+
aliases.forEach((alias) => {
|
|
89
|
+
if (alias && alias !== key) metaAlias[alias] = key;
|
|
90
|
+
});
|
|
91
|
+
notifyMeta(key);
|
|
92
|
+
aliases.forEach(notifyMeta);
|
|
93
|
+
}
|
|
94
|
+
const keep = prune("metas", { ...state.metas }, LIMITS.metas);
|
|
95
|
+
for (const key in state.metas) {
|
|
96
|
+
if (!hasOwn(keep, key)) delete state.metas[key];
|
|
97
|
+
}
|
|
62
98
|
},
|
|
63
99
|
[ADD_SIMPLE_META](state, data) {
|
|
64
100
|
state.simpleMetas = { ...state.simpleMetas, ...data };
|
|
@@ -74,12 +110,18 @@ const meta = {
|
|
|
74
110
|
},
|
|
75
111
|
getters: {
|
|
76
112
|
getMetaById: (state) => (id) => {
|
|
113
|
+
signalOf(id).version;
|
|
77
114
|
const meta2 = state.metas[id];
|
|
78
115
|
if (meta2) touch("metas", id);
|
|
79
116
|
return meta2;
|
|
80
117
|
},
|
|
81
118
|
getMeta: (state) => (id) => {
|
|
82
|
-
|
|
119
|
+
if (!id) return void 0;
|
|
120
|
+
signalOf(id).version;
|
|
121
|
+
const key = hasOwn(state.metas, id) ? id : aliasesOf(state)[id];
|
|
122
|
+
const meta2 = key ? state.metas[key] : void 0;
|
|
123
|
+
if (meta2) touch("metas", key);
|
|
124
|
+
return meta2;
|
|
83
125
|
},
|
|
84
126
|
getSimpleMeta: (state) => (id) => {
|
|
85
127
|
return state.simpleMetas[id] || findMeta(state.metas, (item) => item.id === id || item.code === id);
|
|
@@ -45,16 +45,16 @@ const STYLE_AXES = [
|
|
|
45
45
|
]
|
|
46
46
|
}
|
|
47
47
|
];
|
|
48
|
-
function applyStylePreset(presetKey) {
|
|
48
|
+
function applyStylePreset(presetKey, settings = uiSettings) {
|
|
49
49
|
const preset = STYLE_PRESETS.find((p) => p.key === presetKey);
|
|
50
50
|
if (!preset) return;
|
|
51
51
|
Object.keys(AXIS_ATTRS).forEach((k) => {
|
|
52
|
-
|
|
52
|
+
settings[k] = preset[k];
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
-
function matchStylePreset() {
|
|
55
|
+
function matchStylePreset(settings = uiSettings) {
|
|
56
56
|
const cur = {};
|
|
57
|
-
for (const k of Object.keys(AXIS_ATTRS)) cur[k] =
|
|
57
|
+
for (const k of Object.keys(AXIS_ATTRS)) cur[k] = settings[k];
|
|
58
58
|
const hit = STYLE_PRESETS.find((p) => Object.keys(AXIS_ATTRS).every((k) => cur[k] === p[k]));
|
|
59
59
|
return hit ? hit.key : "";
|
|
60
60
|
}
|
package/dist/src/ui-settings.js
CHANGED
|
@@ -16,6 +16,8 @@ const DEFAULTS = {
|
|
|
16
16
|
// 主题模式 light|dark|auto(auto 跟随系统 prefers-color-scheme)
|
|
17
17
|
themeColor: "",
|
|
18
18
|
// 主题色预设名(classicblue/purple/...;'' = 默认蓝,走既有 data-theme 兜底)
|
|
19
|
+
customTheme: null,
|
|
20
|
+
// 用户选择的自定义主题色快照 { code, color },刷新后也能在引导期恢复
|
|
19
21
|
grayMode: false,
|
|
20
22
|
// 灰色模式(全站置灰,哀悼日用)
|
|
21
23
|
weakMode: false,
|
|
@@ -61,7 +63,7 @@ const DEFAULTS = {
|
|
|
61
63
|
// 页签风格 smart|card|chrome(谷歌)
|
|
62
64
|
tabsKeepAlive: true,
|
|
63
65
|
// 页签缓存(会话级 keep-alive):开=切走保活/点回保持原样;关=切走即销毁/每次点开重新加载。不落盘不整组恢复
|
|
64
|
-
settingsGroups: ["theme", "layout", "tabs", "page", "security"]
|
|
66
|
+
settingsGroups: ["theme", "style", "layout", "tabs", "page", "security"]
|
|
65
67
|
// 设置抽屉折叠分组的展开态(记住用户的折叠选择,跨会话)
|
|
66
68
|
};
|
|
67
69
|
const NAV_MODES = [
|
|
@@ -142,16 +144,15 @@ if (!("isDark" in uiSettings)) {
|
|
|
142
144
|
let _watching = false;
|
|
143
145
|
let _suppressPersist = false;
|
|
144
146
|
const _appDefaultVals = {};
|
|
145
|
-
function persistDiff() {
|
|
147
|
+
function persistDiff(current, previous) {
|
|
146
148
|
try {
|
|
147
|
-
const out = {};
|
|
149
|
+
const out = JSON.parse(window.localStorage.getItem(KEY) || "{}") || {};
|
|
150
|
+
const next = JSON.parse(current);
|
|
151
|
+
const before = JSON.parse(previous);
|
|
148
152
|
for (const k of Object.keys(DEFAULTS)) {
|
|
149
|
-
if (k
|
|
150
|
-
const cur = uiSettings[k];
|
|
151
|
-
const def = DEFAULTS[k];
|
|
152
|
-
const changed = Array.isArray(def) ? JSON.stringify(cur) !== JSON.stringify(def) : cur !== def;
|
|
153
|
-
if (changed) out[k] = cur;
|
|
153
|
+
if (k !== "tabsKeepAlive" && JSON.stringify(next[k]) !== JSON.stringify(before[k])) out[k] = next[k];
|
|
154
154
|
}
|
|
155
|
+
delete out.tabsKeepAlive;
|
|
155
156
|
window.localStorage.setItem(KEY, JSON.stringify(out));
|
|
156
157
|
} catch (e) {
|
|
157
158
|
}
|
|
@@ -159,18 +160,46 @@ function persistDiff() {
|
|
|
159
160
|
function persistUiSettings() {
|
|
160
161
|
if (_watching) return;
|
|
161
162
|
_watching = true;
|
|
162
|
-
watch(uiSettings, () => {
|
|
163
|
+
watch(() => JSON.stringify(Object.fromEntries(Object.keys(DEFAULTS).map((k) => [k, uiSettings[k]]))), (current, previous) => {
|
|
163
164
|
if (_suppressPersist) return;
|
|
164
|
-
persistDiff();
|
|
165
|
-
}, {
|
|
165
|
+
persistDiff(current, previous);
|
|
166
|
+
}, { flush: "sync" });
|
|
166
167
|
}
|
|
167
168
|
persistUiSettings();
|
|
168
169
|
let _mql = null;
|
|
169
170
|
let _baseTheme = "";
|
|
171
|
+
function normalizeThemeColor(color) {
|
|
172
|
+
if (typeof color !== "string") return "";
|
|
173
|
+
const value = color.trim();
|
|
174
|
+
const hex = value.match(/^#([\da-f]{3}|[\da-f]{6})$/i);
|
|
175
|
+
if (hex) {
|
|
176
|
+
const full = hex[1].length === 3 ? [...hex[1]].map((c) => c + c).join("") : hex[1];
|
|
177
|
+
return [0, 2, 4].map((i) => parseInt(full.slice(i, i + 2), 16)).join(",");
|
|
178
|
+
}
|
|
179
|
+
const rgb = value.match(/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i);
|
|
180
|
+
return rgb && rgb.slice(1).every((c) => Number(c) <= 255) ? rgb.slice(1).map(Number).join(",") : "";
|
|
181
|
+
}
|
|
170
182
|
function applyTheme() {
|
|
183
|
+
var _a;
|
|
171
184
|
const html = document.documentElement;
|
|
185
|
+
const preset = THEME_COLORS.find((c) => c.name === uiSettings.themeColor);
|
|
186
|
+
const custom = ((_a = uiSettings.customTheme) == null ? void 0 : _a.code) === uiSettings.themeColor ? uiSettings.customTheme : null;
|
|
187
|
+
const channels = normalizeThemeColor((preset == null ? void 0 : preset.color) || (custom == null ? void 0 : custom.color));
|
|
188
|
+
let colorStyle = document.getElementById("epx-ui-theme-color");
|
|
189
|
+
if (channels) {
|
|
190
|
+
html.style.removeProperty("--color-primary");
|
|
191
|
+
if (!colorStyle) {
|
|
192
|
+
colorStyle = document.createElement("style");
|
|
193
|
+
colorStyle.id = "epx-ui-theme-color";
|
|
194
|
+
document.head.appendChild(colorStyle);
|
|
195
|
+
}
|
|
196
|
+
const selector = `html[data-theme="${preset ? preset.name : "custom"}"]`;
|
|
197
|
+
colorStyle.textContent = `${selector}, ${selector} body { --color-primary: ${channels}; }`;
|
|
198
|
+
} else if (colorStyle) {
|
|
199
|
+
colorStyle.remove();
|
|
200
|
+
}
|
|
172
201
|
if (uiSettings.themeColor) {
|
|
173
|
-
html.setAttribute("data-theme", uiSettings.themeColor);
|
|
202
|
+
html.setAttribute("data-theme", custom && channels ? "custom" : uiSettings.themeColor);
|
|
174
203
|
} else if (_baseTheme) {
|
|
175
204
|
html.setAttribute("data-theme", _baseTheme);
|
|
176
205
|
} else {
|
|
@@ -198,6 +227,7 @@ function initTheme() {
|
|
|
198
227
|
watch(() => [
|
|
199
228
|
uiSettings.themeMode,
|
|
200
229
|
uiSettings.themeColor,
|
|
230
|
+
uiSettings.customTheme,
|
|
201
231
|
uiSettings.grayMode,
|
|
202
232
|
uiSettings.weakMode,
|
|
203
233
|
uiSettings.styleRadius,
|
|
@@ -214,7 +244,8 @@ function initTheme() {
|
|
|
214
244
|
else if (_mql.addListener) _mql.addListener(onChange);
|
|
215
245
|
}
|
|
216
246
|
}
|
|
217
|
-
function applyAppDefaults(defaults = {}) {
|
|
247
|
+
function applyAppDefaults(defaults = {}, { replace = false } = {}) {
|
|
248
|
+
var _a;
|
|
218
249
|
let userSet = {};
|
|
219
250
|
try {
|
|
220
251
|
userSet = JSON.parse(window.localStorage.getItem(KEY) || "{}") || {};
|
|
@@ -222,15 +253,25 @@ function applyAppDefaults(defaults = {}) {
|
|
|
222
253
|
}
|
|
223
254
|
_suppressPersist = true;
|
|
224
255
|
try {
|
|
256
|
+
if (replace) {
|
|
257
|
+
Object.keys(_appDefaultVals).forEach((k) => {
|
|
258
|
+
delete _appDefaultVals[k];
|
|
259
|
+
});
|
|
260
|
+
_baseTheme = "";
|
|
261
|
+
(_a = document.getElementById("custom-theme")) == null ? void 0 : _a.remove();
|
|
262
|
+
document.documentElement.style.removeProperty("--color-primary");
|
|
263
|
+
}
|
|
225
264
|
for (const k of Object.keys(DEFAULTS)) {
|
|
226
|
-
if (defaults[k] !== void 0
|
|
227
|
-
|
|
228
|
-
_appDefaultVals[k]
|
|
265
|
+
if (defaults[k] !== void 0) _appDefaultVals[k] = defaults[k];
|
|
266
|
+
if (replace || defaults[k] !== void 0) {
|
|
267
|
+
const value = userSet[k] !== void 0 ? userSet[k] : _appDefaultVals[k] ?? DEFAULTS[k];
|
|
268
|
+
uiSettings[k] = Array.isArray(value) ? [...value] : value;
|
|
229
269
|
}
|
|
230
270
|
}
|
|
231
271
|
} finally {
|
|
232
272
|
_suppressPersist = false;
|
|
233
273
|
}
|
|
274
|
+
if (replace) applyTheme();
|
|
234
275
|
}
|
|
235
276
|
function migrateLegacyTheme(src) {
|
|
236
277
|
if (!src) return "";
|
|
@@ -247,15 +288,44 @@ function migrateLegacyTheme(src) {
|
|
|
247
288
|
return src;
|
|
248
289
|
}
|
|
249
290
|
function resetUiSettings() {
|
|
250
|
-
|
|
291
|
+
_suppressPersist = true;
|
|
292
|
+
Object.assign(uiSettings, DEFAULTS, { settingsGroups: [...DEFAULTS.settingsGroups] });
|
|
293
|
+
_suppressPersist = false;
|
|
294
|
+
Object.keys(_appDefaultVals).forEach((k) => {
|
|
295
|
+
delete _appDefaultVals[k];
|
|
296
|
+
});
|
|
297
|
+
try {
|
|
298
|
+
window.localStorage.removeItem(KEY);
|
|
299
|
+
} catch (e) {
|
|
300
|
+
}
|
|
251
301
|
_baseTheme = "";
|
|
252
302
|
try {
|
|
253
303
|
const legacyKeys = ["epx_frame_theme", LEGACY_STYLE, LEGACY_PERSIST];
|
|
254
|
-
legacyKeys.forEach((k) =>
|
|
304
|
+
legacyKeys.forEach((k) => {
|
|
305
|
+
window.localStorage.removeItem(k);
|
|
306
|
+
window.sessionStorage.removeItem(k);
|
|
307
|
+
});
|
|
255
308
|
} catch (e) {
|
|
256
309
|
}
|
|
257
310
|
const custom = document.getElementById("custom-theme");
|
|
258
311
|
if (custom && custom.parentNode) custom.parentNode.removeChild(custom);
|
|
312
|
+
document.documentElement.style.removeProperty("--color-primary");
|
|
313
|
+
applyTheme();
|
|
314
|
+
}
|
|
315
|
+
function restoreAppUiDefaults() {
|
|
316
|
+
var _a;
|
|
317
|
+
const defaults = { ..._appDefaultVals };
|
|
318
|
+
const baseTheme = _baseTheme;
|
|
319
|
+
const legacyColor = (_a = document.getElementById("custom-theme")) == null ? void 0 : _a.textContent;
|
|
320
|
+
resetUiSettings();
|
|
321
|
+
applyAppDefaults(defaults, { replace: true });
|
|
322
|
+
_baseTheme = baseTheme;
|
|
323
|
+
if (legacyColor) {
|
|
324
|
+
const style = document.createElement("style");
|
|
325
|
+
style.id = "custom-theme";
|
|
326
|
+
style.textContent = legacyColor;
|
|
327
|
+
document.head.appendChild(style);
|
|
328
|
+
}
|
|
259
329
|
applyTheme();
|
|
260
330
|
}
|
|
261
331
|
if (typeof window !== "undefined") window.__epxUiSettings = uiSettings;
|
|
@@ -273,7 +343,9 @@ export {
|
|
|
273
343
|
initTheme,
|
|
274
344
|
migrateLegacyTheme,
|
|
275
345
|
navModeFlags,
|
|
346
|
+
normalizeThemeColor,
|
|
276
347
|
persistUiSettings,
|
|
277
348
|
resetUiSettings,
|
|
349
|
+
restoreAppUiDefaults,
|
|
278
350
|
uiSettings
|
|
279
351
|
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import '../../style.css';
|
|
2
|
+
import { openBlock, createBlock, resolveDynamicComponent, createCommentVNode } from "vue";
|
|
3
|
+
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
+
const _sfc_main = {
|
|
5
|
+
name: "epx-app",
|
|
6
|
+
computed: {
|
|
7
|
+
appConfig() {
|
|
8
|
+
return this.$store.state.config.appConfig;
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
data() {
|
|
12
|
+
return {
|
|
13
|
+
load: false,
|
|
14
|
+
component: "epx-app-index",
|
|
15
|
+
firstPage: {}
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
methods: {
|
|
19
|
+
getPage() {
|
|
20
|
+
const { FIRST_PAGE, MOBILE_FIRST_PAGE } = this.appConfig;
|
|
21
|
+
this.$store.dispatch({
|
|
22
|
+
// 加回调
|
|
23
|
+
type: "ADD_PAGE",
|
|
24
|
+
pageId: this.$isMobile ? MOBILE_FIRST_PAGE : FIRST_PAGE
|
|
25
|
+
}).then((page = {}) => {
|
|
26
|
+
const { pagePath } = page;
|
|
27
|
+
this.firstPage = page;
|
|
28
|
+
this.component = this.$loadComponent(pagePath, this.component);
|
|
29
|
+
this.load = true;
|
|
30
|
+
}).catch(() => {
|
|
31
|
+
this.load = true;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
created() {
|
|
36
|
+
this.getPage();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
40
|
+
return $data.load ? (openBlock(), createBlock(resolveDynamicComponent($data.component), {
|
|
41
|
+
key: 0,
|
|
42
|
+
page: $data.firstPage
|
|
43
|
+
}, null, 8, ["page"])) : createCommentVNode("", true);
|
|
44
|
+
}
|
|
45
|
+
const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
46
|
+
export {
|
|
47
|
+
App as default
|
|
48
|
+
};
|