@epxing/core 5.3.0-beta.2 → 5.3.0-beta.4
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 +715 -714
- 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 +6 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts.min.js +49 -0
- package/dist/_virtual/_plugin-vue_export-helper.js +10 -0
- package/dist/_virtual/jsencrypt.min.js +1 -1
- 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 +19 -0
- package/dist/src/chart-runtime-sources.js +8 -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 +28 -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 +13 -0
- package/src/chart-runtime-sources.js +5 -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 +1359 -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,4 +1,5 @@
|
|
|
1
1
|
import '../../style.css';
|
|
2
|
+
import { restoreChatWikiRoute } from "@epxing/utils/src/wiki-path";
|
|
2
3
|
import { runtimeRouteComponent, getRuntimeService, runtimeStore } from "../runtime-services.js";
|
|
3
4
|
import { isEmpty } from "lodash-es";
|
|
4
5
|
import util from "../runtime-utils/util.js";
|
|
@@ -10,7 +11,6 @@ import { setElementPlusLocale } from "../plugins/element-plus.js";
|
|
|
10
11
|
import { MENU_ROUTE_ALIAS, roleStorage, effectiveRouteName } from "../menu-route.js";
|
|
11
12
|
const Page = runtimeRouteComponent("Page");
|
|
12
13
|
const Login = runtimeRouteComponent("Login");
|
|
13
|
-
const QyWechat = runtimeRouteComponent("QyWechat");
|
|
14
14
|
const App = runtimeRouteComponent("App");
|
|
15
15
|
const WikiSitePage = runtimeRouteComponent("WikiSitePage");
|
|
16
16
|
const Module = runtimeRouteComponent("Module");
|
|
@@ -239,9 +239,11 @@ const routes = [
|
|
|
239
239
|
props: (route) => ({ query: route.query })
|
|
240
240
|
},
|
|
241
241
|
{
|
|
242
|
-
|
|
242
|
+
// 32 位菜单 ID 与旧角色编号消歧;旧的 /system/.../SYSTEM 地址仍可使用。
|
|
243
|
+
path: "/system/:client/:system/:menuKey([0-9A-Fa-f]{32})?/:role?",
|
|
243
244
|
name: "system",
|
|
244
245
|
component: App,
|
|
246
|
+
meta: { refresh: false },
|
|
245
247
|
props: (route) => ({ query: route.query })
|
|
246
248
|
},
|
|
247
249
|
{
|
|
@@ -317,11 +319,6 @@ const routes = [
|
|
|
317
319
|
component: App,
|
|
318
320
|
props: (route) => ({ query: route.query })
|
|
319
321
|
},
|
|
320
|
-
{
|
|
321
|
-
path: "/qywechat",
|
|
322
|
-
name: "qywechat",
|
|
323
|
-
component: QyWechat
|
|
324
|
-
},
|
|
325
322
|
{
|
|
326
323
|
// 旧形态 /m/:menuKey 链接兼容:重定向到无 /m/ 的新形态
|
|
327
324
|
path: "/app/:client/:system/:app/m/:menuKey",
|
|
@@ -344,6 +341,8 @@ const routes = [
|
|
|
344
341
|
}
|
|
345
342
|
];
|
|
346
343
|
const beforeEach = async (to, from, next) => {
|
|
344
|
+
const restoredWikiRoute = restoreChatWikiRoute(to);
|
|
345
|
+
if (restoredWikiRoute) return next(restoredWikiRoute);
|
|
347
346
|
try {
|
|
348
347
|
subscribeToLogout();
|
|
349
348
|
return await runBeforeEach(to, from, next);
|
|
@@ -366,7 +365,7 @@ const runBeforeEach = async (to, from, rawNext) => {
|
|
|
366
365
|
}
|
|
367
366
|
return rawNext(location);
|
|
368
367
|
};
|
|
369
|
-
const isMenuRoute = !!MENU_ROUTE_ALIAS[to.name];
|
|
368
|
+
const isMenuRoute = !!MENU_ROUTE_ALIAS[to.name] || to.name === "system" && !!to.params.menuKey;
|
|
370
369
|
if (isMenuRoute) {
|
|
371
370
|
const storedRole = roleStorage.get(to.params.client, to.params.system);
|
|
372
371
|
to = { ...to, name: effectiveRouteName(to.name), params: { ...to.params, role: to.params.role || storedRole || void 0 } };
|
|
@@ -34,7 +34,7 @@ function registerRouteComponents(components) {
|
|
|
34
34
|
function runtimeRouteComponent(name) {
|
|
35
35
|
return async () => {
|
|
36
36
|
const component = routeComponents.get(name);
|
|
37
|
-
if (!component) throw new Error(`[epx/core] 路由组件 ${name}
|
|
37
|
+
if (!component) throw new Error(`[epx/core] 路由组件 ${name} 尚未注册,请安装提供该页面的 components/business 包或传入 routeComponents`);
|
|
38
38
|
return component;
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../../style.css';
|
|
2
2
|
import util from "./util.js";
|
|
3
|
+
const appliedLanguage = /* @__PURE__ */ new WeakMap();
|
|
3
4
|
class Meta {
|
|
4
5
|
constructor(props = {}) {
|
|
5
6
|
var me = this;
|
|
@@ -56,6 +57,8 @@ class Meta {
|
|
|
56
57
|
}
|
|
57
58
|
getAttributes() {
|
|
58
59
|
const currentLanguage = util.getCurrentLanguage();
|
|
60
|
+
if (appliedLanguage.get(this) === currentLanguage) return this.attributes;
|
|
61
|
+
appliedLanguage.set(this, currentLanguage);
|
|
59
62
|
for (const key in this.attributes) {
|
|
60
63
|
const item = this.attributes[key];
|
|
61
64
|
for (const key2 in item.languageMap) {
|
|
@@ -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,7 @@ 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 { loadChartRuntimeAssets } from "../chart-runtime-assets.js";
|
|
10
11
|
const installingLibraries = /* @__PURE__ */ new Map();
|
|
11
12
|
class Util {
|
|
12
13
|
constructor() {
|
|
@@ -585,7 +586,8 @@ class Util {
|
|
|
585
586
|
}
|
|
586
587
|
script.onerror = function() {
|
|
587
588
|
console.error("[util.loadJS] 加载失败:" + url);
|
|
588
|
-
|
|
589
|
+
if (options.onerror) options.onerror(new Error("脚本加载失败:" + url));
|
|
590
|
+
else callback();
|
|
589
591
|
};
|
|
590
592
|
script.src = url;
|
|
591
593
|
document.getElementsByTagName("head")[0].appendChild(script);
|
|
@@ -788,7 +790,7 @@ class Util {
|
|
|
788
790
|
const publicPath = this.getPublicPath();
|
|
789
791
|
const jsDir = this.getStaticJsDir();
|
|
790
792
|
if (plugin === "luckysheet") {
|
|
791
|
-
const loadPromise = loadFile([publicPath + "luckysheet/pluginsCss.css", publicPath + "luckysheet/plugins.css", publicPath + "luckysheet/luckysheet.css", publicPath + "
|
|
793
|
+
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
794
|
this.loadPlugins[plugin] = loadPromise;
|
|
793
795
|
return loadPromise;
|
|
794
796
|
} else if (plugin === "BMap") {
|
|
@@ -828,7 +830,26 @@ class Util {
|
|
|
828
830
|
this.loadPlugins[plugin] = loadPromise;
|
|
829
831
|
return loadPromise;
|
|
830
832
|
} else if (plugin === "echarts") {
|
|
831
|
-
const
|
|
833
|
+
const loading = window.STATIC_JS_DIR ? Promise.all([publicPath + jsDir + "echarts.min.js?v=6.0.0-full", publicPath + jsDir + "ecStat.min.js"].map((url) => new Promise((resolve, reject) => {
|
|
834
|
+
this.loadJS({ url, callback: resolve, onerror: reject });
|
|
835
|
+
}))) : loadChartRuntimeAssets(this.loadJS.bind(this));
|
|
836
|
+
const loadPromise = loading.then(() => {
|
|
837
|
+
if (!globalThis.echarts || !globalThis.ecStat) throw new Error("图表资源加载失败,请检查 ECharts 和 ecStat 脚本");
|
|
838
|
+
return globalThis.echarts;
|
|
839
|
+
}).catch((error) => {
|
|
840
|
+
delete this.loadPlugins[plugin];
|
|
841
|
+
throw error;
|
|
842
|
+
});
|
|
843
|
+
this.loadPlugins[plugin] = loadPromise;
|
|
844
|
+
return loadPromise;
|
|
845
|
+
} else if (plugin === "echarts-wordcloud") {
|
|
846
|
+
const loading = window.STATIC_JS_DIR ? new Promise((resolve, reject) => {
|
|
847
|
+
this.loadJS({ url: publicPath + jsDir + "echarts-wordcloud.min.js", callback: resolve, onerror: reject });
|
|
848
|
+
}) : loadChartRuntimeAssets(this.loadJS.bind(this), ["wordcloud"]);
|
|
849
|
+
const loadPromise = loading.catch((error) => {
|
|
850
|
+
delete this.loadPlugins[plugin];
|
|
851
|
+
throw error;
|
|
852
|
+
});
|
|
832
853
|
this.loadPlugins[plugin] = loadPromise;
|
|
833
854
|
return loadPromise;
|
|
834
855
|
} else if (plugin === "pdf") {
|
|
@@ -1054,7 +1075,8 @@ class Util {
|
|
|
1054
1075
|
}
|
|
1055
1076
|
encrypt(content, key, { type } = {}) {
|
|
1056
1077
|
if (type === "aes") {
|
|
1057
|
-
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((
|
|
1078
|
+
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((cryptoModule) => {
|
|
1079
|
+
const CryptoJS = "default" in cryptoModule ? cryptoModule.default : cryptoModule;
|
|
1058
1080
|
const base64Key = atob(key);
|
|
1059
1081
|
const aesKey = CryptoJS.enc.Utf8.parse(base64Key.toString(CryptoJS.enc.Utf8));
|
|
1060
1082
|
const encrypted = CryptoJS.AES.encrypt(content, aesKey, {
|
|
@@ -1074,7 +1096,8 @@ class Util {
|
|
|
1074
1096
|
}
|
|
1075
1097
|
decrypt(content, { type, key }) {
|
|
1076
1098
|
if (type === "aes") {
|
|
1077
|
-
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((
|
|
1099
|
+
return __epxPackagePreload(() => import("crypto-js"), true ? [] : void 0, import.meta.url).then((cryptoModule) => {
|
|
1100
|
+
const CryptoJS = "default" in cryptoModule ? cryptoModule.default : cryptoModule;
|
|
1078
1101
|
const base64Key = atob(key);
|
|
1079
1102
|
const aesKey = CryptoJS.enc.Utf8.parse(base64Key.toString(CryptoJS.enc.Utf8));
|
|
1080
1103
|
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
|
};
|