@gct-paas/word 0.1.72 → 0.1.73-patch.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/dist/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @gct-paas/word v0.1.72 */
1
+ /*! @gct-paas/word v0.1.73-patch.1 */
2
2
  import { Fragment, Suspense, Teleport, Transition, TransitionGroup, cloneVNode, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createStaticVNode, createTextVNode, createVNode, defineAsyncComponent, defineComponent, getCurrentInstance, getCurrentScope, guardReactiveProps, h, inject, isRef, isVNode, markRaw, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onBeforeMount, onBeforeUnmount, onMounted, onScopeDispose, onUnmounted, openBlock, provide, reactive, readonly, ref, render, renderList, renderSlot, resolveComponent, resolveDynamicComponent, shallowRef, toDisplayString, toRaw, toRef, toValue, unref, useCssVars, useModel, useSlots, vModelText, vShow, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers } from "vue";
3
3
  import FloatingVue, { PopperWrapper } from "floating-vue";
4
4
  import VueKonva from "vue-konva";
@@ -2226,10 +2226,345 @@ var init_input$1 = __esmMin((() => {
2226
2226
  input_default = /*#__PURE__*/ _plugin_vue_export_helper_default(input_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-aa7f65fb"]]);
2227
2227
  }));
2228
2228
  //#endregion
2229
+ //#region src/utils/func/core.ts
2230
+ /** 基础工具 */
2231
+ function fallbackUUID() {
2232
+ var _crypto, _crypto$getRandomValu;
2233
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
2234
+ (_crypto = crypto) === null || _crypto === void 0 || (_crypto$getRandomValu = _crypto.getRandomValues) === null || _crypto$getRandomValu === void 0 || _crypto$getRandomValu.call(_crypto, bytes);
2235
+ bytes[6] = bytes[6] & 15 | 64;
2236
+ bytes[8] = bytes[8] & 63 | 128;
2237
+ const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0"));
2238
+ return hex.slice(0, 4).join("") + "-" + hex.slice(4, 6).join("") + "-" + hex.slice(6, 8).join("") + "-" + hex.slice(8, 10).join("") + "-" + hex.slice(10, 16).join("");
2239
+ }
2240
+ /**
2241
+ * 生成唯一 id
2242
+ */
2243
+ function uuid() {
2244
+ try {
2245
+ return crypto.randomUUID();
2246
+ } catch {
2247
+ return fallbackUUID();
2248
+ }
2249
+ }
2250
+ /** 字段值是否「空」:null / undefined / 空串 */
2251
+ function isBlank(value) {
2252
+ return value == null || value === "";
2253
+ }
2254
+ /** 字段值是否「有值」 */
2255
+ function isPresent(value) {
2256
+ return !isBlank(value);
2257
+ }
2258
+ /**
2259
+ * 去掉货币符号、千分位等,保证能解析为纯数字
2260
+ * 例:`3,300,000` / `$3,300,000` → `3300000`
2261
+ */
2262
+ function stripNumberNoise(raw) {
2263
+ return raw.replace(/\$\s?|,|,|\s/g, "");
2264
+ }
2265
+ function parseFormTmplRefId(refId) {
2266
+ if (!refId) return {
2267
+ baseId: "",
2268
+ id: ""
2269
+ };
2270
+ const [baseId, versionId] = refId.split(":");
2271
+ return {
2272
+ baseId: versionId ? baseId : "",
2273
+ id: versionId || baseId
2274
+ };
2275
+ }
2276
+ /**
2277
+ * 安全解析 JSON
2278
+ * @param data 待解析数据
2279
+ * @param fallback 失败时返回值,默认 null
2280
+ * @param validator 结果校验器
2281
+ */
2282
+ function safeParseJson(data, fallback = null, validator) {
2283
+ if (typeof data !== "string") return fallback;
2284
+ try {
2285
+ const parsed = JSON.parse(data);
2286
+ if (validator && !validator(parsed)) return fallback;
2287
+ return parsed;
2288
+ } catch {
2289
+ return fallback;
2290
+ }
2291
+ }
2292
+ /** 设置字段的默认valuePath */
2293
+ function generateValuePath(fieldLink, subFieldKey) {
2294
+ if (subFieldKey) return `$.${subFieldKey}${subFieldKey.includes(":") ? "[n_y][n_x]" : "[n]"}.${fieldLink}`;
2295
+ else return `$.${fieldLink}`;
2296
+ }
2297
+ /**
2298
+ * 按分隔符截取字符串最后一个片段,处理空值/无分隔符边界
2299
+ * @param str 待截取的字符串(允许空/undefined)
2300
+ * @param separator 分隔符,默认.
2301
+ * @returns 最后一个片段,空值返回空字符串
2302
+ */
2303
+ function getLastSegment$1(str, separator = ".") {
2304
+ if (!str) return "";
2305
+ const index = str.lastIndexOf(separator);
2306
+ return index === -1 ? str : str.slice(index + 1);
2307
+ }
2308
+ /**
2309
+ * 根据参考路径 / index 替换模板中的占位符
2310
+ *
2311
+ * - 传入 x 时替换 [n_x]
2312
+ * - 传入 y 时替换 [n_y]
2313
+ * - 未传入时保留原占位符
2314
+ * - 最后再统一处理普通 [n]
2315
+ *
2316
+ * 示例:
2317
+ * replacePathIndexPlaceholders({
2318
+ * x: 1,
2319
+ * y: undefined,
2320
+ * templatePath: '$.table[n_y].cross[n_x].value[n]',
2321
+ * })
2322
+ * =>
2323
+ * '$.table[n_y].cross[1].value[n]'
2324
+ */
2325
+ function replacePathIndexPlaceholders(params) {
2326
+ const { refPath, templatePath } = params;
2327
+ let n = params.n;
2328
+ let x = params.x;
2329
+ let y = params.y;
2330
+ if (refPath) {
2331
+ const indices = [...refPath.matchAll(/\[(\d+)\]/g)].map((m) => Number(m[1]));
2332
+ y ??= indices[0];
2333
+ x ??= indices[1] ?? indices[0];
2334
+ n ??= indices[0];
2335
+ }
2336
+ let path = templatePath;
2337
+ path = replacePathIndexPlaceholder(y, path, "n_y");
2338
+ path = replacePathIndexPlaceholder(x, path, "n_x");
2339
+ path = replacePathIndexPlaceholder(n ?? x, path, "n");
2340
+ return path;
2341
+ }
2342
+ /**
2343
+ * 提取参考路径中的索引,替换模板路径中的占位符
2344
+ *
2345
+ * @param refPath 参考路径(如 $.a[1].b)或直接传数字
2346
+ * @param templatePath 模板路径(如 $.list[n].value)
2347
+ * @param placeholder 占位符名称,默认 n
2348
+ *
2349
+ * @example
2350
+ * replacePathIndexPlaceholder(1, '$.a[n].b')
2351
+ * // $.a[1].b
2352
+ *
2353
+ * @example
2354
+ * replacePathIndexPlaceholder(2, '$.a[n_x].b', 'n_x')
2355
+ * // $.a[2].b
2356
+ */
2357
+ function replacePathIndexPlaceholder(refPath, templatePath, placeholder = "n") {
2358
+ let index;
2359
+ if (refPath === void 0) return templatePath;
2360
+ if (typeof refPath === "number") index = refPath.toString();
2361
+ else {
2362
+ const indexMatch = refPath.match(/\[(\d+)\]/);
2363
+ index = indexMatch ? indexMatch[1] : placeholder;
2364
+ }
2365
+ return templatePath.replaceAll(`[${placeholder}]`, `[${index}]`);
2366
+ }
2367
+ /**
2368
+ * 判断运行时路径是否匹配 valuePath 模板(支持 [n] / [n_x] / [n_y] 占位符)
2369
+ *
2370
+ * @example
2371
+ * runtimePathMatchesTemplate('$.items[n].name', '$.items[2].name') // true
2372
+ */
2373
+ function runtimePathMatchesTemplate(template, runtimePath) {
2374
+ if (template === runtimePath) return true;
2375
+ const regex = template.replace(/\[n_y\]/g, "\0NY\0").replace(/\[n_x\]/g, "\0NX\0").replace(/\[n\]/g, "\0N\0").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\u0000NY\u0000/g, "\\[\\d+\\]").replace(/\u0000NX\u0000/g, "\\[\\d+\\]").replace(/\u0000N\u0000/g, "\\[\\d+\\]");
2376
+ return new RegExp(`^${regex}$`).test(runtimePath);
2377
+ }
2378
+ /** 由 valuePath 模板生成 enricher 用的 path 匹配函数 */
2379
+ function createValuePathMatcher(template) {
2380
+ return (runtimePath) => runtimePathMatchesTemplate(template, runtimePath);
2381
+ }
2382
+ function parseValuePath(valuePath) {
2383
+ if (!valuePath) return {
2384
+ raw: "",
2385
+ normalized: "",
2386
+ fieldKey: "",
2387
+ fieldPath: "",
2388
+ isRoot: false,
2389
+ isSubTable: false,
2390
+ isLink: false,
2391
+ hasIndex: false,
2392
+ segments: []
2393
+ };
2394
+ const normalized = valuePath.replace(/^\$\./, "");
2395
+ const segments = normalized.split(".").filter(Boolean);
2396
+ const only = segments[0] || "";
2397
+ const parentRaw = segments.length > 1 ? only : only.includes(":") ? only : "";
2398
+ const fieldKey = segments.length > 1 ? segments.at(-1) || "" : only.includes(":") ? "" : only;
2399
+ const hasIndex = /\[[^\]]+\]/.test(valuePath);
2400
+ const isLink = parentRaw.includes(":");
2401
+ let parentFieldKey = "";
2402
+ let linkFieldKey = "";
2403
+ if (isLink) {
2404
+ const colonIdx = parentRaw.indexOf(":");
2405
+ const subFieldKey = colonIdx >= 0 ? parentRaw.slice(0, colonIdx) : parentRaw;
2406
+ const linkKey = colonIdx >= 0 ? parentRaw.slice(colonIdx + 1) : "";
2407
+ parentFieldKey = (subFieldKey || "").replace(/\[[^\]]*\]/g, "");
2408
+ linkFieldKey = (linkKey || "").replace(/\[[^\]]*\]/g, "");
2409
+ } else parentFieldKey = parentRaw.replace(/\[.*?\]/g, "");
2410
+ return {
2411
+ raw: valuePath,
2412
+ normalized,
2413
+ fieldKey,
2414
+ fieldPath: fieldKey ? `$.${fieldKey}` : "",
2415
+ parentFieldKey,
2416
+ parentFieldPath: parentFieldKey ? `$.${parentFieldKey}` : "",
2417
+ isRoot: segments.length === 1,
2418
+ isSubTable: segments.length > 1,
2419
+ isLink,
2420
+ linkFieldKey,
2421
+ linkFieldPath: linkFieldKey ? `$.${linkFieldKey}` : "",
2422
+ hasIndex,
2423
+ segments
2424
+ };
2425
+ }
2426
+ /**
2427
+ * 提取 $.变量名[内容] 格式的方法(截取到 ] 并包含 ])
2428
+ * @param str
2429
+ * @returns
2430
+ */
2431
+ function getBeforeBracket(str) {
2432
+ var _str$match, _str$match2;
2433
+ const m = (_str$match = str.match(/\$\.[a-z0-9_$:]+(?:\[[^\]]+\])+/i)) === null || _str$match === void 0 ? void 0 : _str$match[0];
2434
+ if (m) return m;
2435
+ return ((_str$match2 = str.match(/\$\.[a-z_]+\[[^\]]+\]/i)) === null || _str$match2 === void 0 ? void 0 : _str$match2[0]) || "";
2436
+ }
2437
+ /** 防抖特性的RAF,同一帧内多次调用 schedule() 只会执行一次 */
2438
+ function createRafOnce() {
2439
+ let rafId = null;
2440
+ let pending = null;
2441
+ const schedule = (fn) => {
2442
+ if (rafId) return;
2443
+ rafId = requestAnimationFrame(() => {
2444
+ rafId = null;
2445
+ fn();
2446
+ });
2447
+ };
2448
+ const syncSchedule = (fn) => {
2449
+ if (pending) return pending;
2450
+ pending = new Promise((resolve) => {
2451
+ rafId = requestAnimationFrame(() => {
2452
+ rafId = null;
2453
+ try {
2454
+ resolve(fn());
2455
+ } finally {
2456
+ pending = null;
2457
+ }
2458
+ });
2459
+ });
2460
+ return pending;
2461
+ };
2462
+ const cancel = () => {
2463
+ if (rafId) {
2464
+ cancelAnimationFrame(rafId);
2465
+ rafId = null;
2466
+ pending = null;
2467
+ }
2468
+ };
2469
+ return {
2470
+ schedule,
2471
+ syncSchedule,
2472
+ cancel
2473
+ };
2474
+ }
2475
+ function listToTree(list, transform = (n) => n) {
2476
+ const map = /* @__PURE__ */ new Map();
2477
+ const roots = [];
2478
+ list.forEach((item) => {
2479
+ map.set(item.value, item);
2480
+ item.children = [];
2481
+ });
2482
+ list.forEach((node) => {
2483
+ var _node$_item;
2484
+ const parentId = (_node$_item = node._item) === null || _node$_item === void 0 ? void 0 : _node$_item.parentId;
2485
+ if (!parentId || parentId === "ROOT") roots.push(transform(node));
2486
+ else {
2487
+ var _parent$children;
2488
+ const parent = map.get(parentId);
2489
+ parent === null || parent === void 0 || (_parent$children = parent.children) === null || _parent$children === void 0 || _parent$children.push(transform(node));
2490
+ }
2491
+ });
2492
+ return roots;
2493
+ }
2494
+ function flattenTree(tree, childrenKey = "children") {
2495
+ const result = [];
2496
+ function traverse(nodes) {
2497
+ nodes.forEach((node) => {
2498
+ const { [childrenKey]: children, ...rest } = node;
2499
+ result.push({
2500
+ ...rest,
2501
+ [childrenKey]: children
2502
+ });
2503
+ if (children === null || children === void 0 ? void 0 : children.length) traverse(children);
2504
+ });
2505
+ }
2506
+ traverse(tree);
2507
+ return result;
2508
+ }
2509
+ /** 从 URL 提取 name */
2510
+ function getFileName(url) {
2511
+ try {
2512
+ return decodeURIComponent(url.split("/").pop() || "");
2513
+ } catch {
2514
+ return url.split("/").pop() || "";
2515
+ }
2516
+ }
2517
+ /**
2518
+ * 合并两个按钮数组
2519
+ * @param {Array} A - 基础数组
2520
+ * @param {Array} B - 更新数组
2521
+ * @param {Object} options
2522
+ * @param {string[]} options.keyFields - 用于唯一匹配的字段
2523
+ * @param {string[]} options.fieldsToMerge - 从 B 合并到 A 的字段
2524
+ * @param {boolean} options.isAllowMerge - 是否允许合并
2525
+ * @param {boolean} options.isConcat - 如果 A数组是空是否直接用B 数组
2526
+ * @returns {Array} 合并后的数组
2527
+ */
2528
+ function mergeByMultiKey(A, B, { keyFields = ["type", "isCustom"], fieldsToMerge = ["alias", "enable"], isAllowMerge = true, isConcat = false } = {}) {
2529
+ if (!Array.isArray(A)) return [];
2530
+ if (!isAllowMerge || !Array.isArray(B) || B.length === 0) return [...A];
2531
+ if (isConcat && Array.isArray(A) && A.length === 0) return [...B];
2532
+ const keyFn = (item) => keyFields.map((k) => {
2533
+ const v = item === null || item === void 0 ? void 0 : item[k];
2534
+ if (typeof v === "boolean") return String(v);
2535
+ return v == null ? "" : String(v);
2536
+ }).join("::");
2537
+ const bMap = keyBy(B, keyFn);
2538
+ return A.map((a) => {
2539
+ const info = bMap[keyFn(a)];
2540
+ return info ? {
2541
+ ...a,
2542
+ ...pick(info, fieldsToMerge)
2543
+ } : { ...a };
2544
+ });
2545
+ }
2546
+ var halfPixel, isEmptyValue$1;
2547
+ var init_core$1 = __esmMin((() => {
2548
+ halfPixel = (n) => Math.round(n) + .5;
2549
+ isEmptyValue$1 = (value) => {
2550
+ if (value === void 0 || value === null) return true;
2551
+ if (typeof value === "string") return value.trim() === "";
2552
+ if (typeof value === "number") return Number.isNaN(value);
2553
+ if (Array.isArray(value)) {
2554
+ if (value.length === 0) return true;
2555
+ }
2556
+ if (value instanceof Map || value instanceof Set) return value.size === 0;
2557
+ if (value instanceof Date) return Number.isNaN(value.getTime());
2558
+ if (typeof value === "object") return Object.keys(value).length === 0;
2559
+ return false;
2560
+ };
2561
+ }));
2562
+ //#endregion
2229
2563
  //#region src/base/input/src/input-number.vue?vue&type=script&setup=true&lang.ts
2230
2564
  var _hoisted_1$155, _hoisted_2$95, _hoisted_3$73, _hoisted_4$55, _hoisted_5$44, input_number_vue_vue_type_script_setup_true_lang_default;
2231
2565
  var init_input_number_vue_vue_type_script_setup_true_lang = __esmMin((() => {
2232
2566
  init_base$2();
2567
+ init_core$1();
2233
2568
  _hoisted_1$155 = [
2234
2569
  "value",
2235
2570
  "min",
@@ -2323,6 +2658,8 @@ var init_input_number_vue_vue_type_script_setup_true_lang = __esmMin((() => {
2323
2658
  }
2324
2659
  /** 解析 */
2325
2660
  function parseInput(val) {
2661
+ if (!val) return null;
2662
+ val = stripNumberNoise(val);
2326
2663
  if (!val) return null;
2327
2664
  if (val.startsWith(".")) val = `0${val}`;
2328
2665
  let numericPart = null;
@@ -2501,17 +2838,17 @@ var init_input_number_vue_vue_type_script_setup_true_lang = __esmMin((() => {
2501
2838
  });
2502
2839
  }));
2503
2840
  //#endregion
2504
- //#region src/base/input/src/input-number.vue?vue&type=style&index=0&scoped=4b906773&lang.less
2505
- var init_input_number_vue_vue_type_style_index_0_scoped_4b906773_lang = __esmMin((() => {}));
2841
+ //#region src/base/input/src/input-number.vue?vue&type=style&index=0&scoped=d9ebd5e5&lang.less
2842
+ var init_input_number_vue_vue_type_style_index_0_scoped_d9ebd5e5_lang = __esmMin((() => {}));
2506
2843
  //#endregion
2507
2844
  //#region src/base/input/src/input-number.vue
2508
2845
  var input_number_default;
2509
2846
  var init_input_number = __esmMin((() => {
2510
2847
  init_input_number_vue_vue_type_script_setup_true_lang();
2511
2848
  init_input_number_vue_vue_type_script_setup_true_lang();
2512
- init_input_number_vue_vue_type_style_index_0_scoped_4b906773_lang();
2849
+ init_input_number_vue_vue_type_style_index_0_scoped_d9ebd5e5_lang();
2513
2850
  init__plugin_vue_export_helper();
2514
- input_number_default = /*#__PURE__*/ _plugin_vue_export_helper_default(input_number_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-4b906773"]]);
2851
+ input_number_default = /*#__PURE__*/ _plugin_vue_export_helper_default(input_number_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d9ebd5e5"]]);
2515
2852
  }));
2516
2853
  //#endregion
2517
2854
  //#region src/base/input/src/text-area.vue?vue&type=script&setup=true&lang.ts
@@ -8829,333 +9166,6 @@ var init_constants$1 = __esmMin((() => {
8829
9166
  init_paper();
8830
9167
  }));
8831
9168
  //#endregion
8832
- //#region src/utils/func/core.ts
8833
- /** 基础工具 */
8834
- function fallbackUUID() {
8835
- var _crypto, _crypto$getRandomValu;
8836
- const bytes = /* @__PURE__ */ new Uint8Array(16);
8837
- (_crypto = crypto) === null || _crypto === void 0 || (_crypto$getRandomValu = _crypto.getRandomValues) === null || _crypto$getRandomValu === void 0 || _crypto$getRandomValu.call(_crypto, bytes);
8838
- bytes[6] = bytes[6] & 15 | 64;
8839
- bytes[8] = bytes[8] & 63 | 128;
8840
- const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0"));
8841
- return hex.slice(0, 4).join("") + "-" + hex.slice(4, 6).join("") + "-" + hex.slice(6, 8).join("") + "-" + hex.slice(8, 10).join("") + "-" + hex.slice(10, 16).join("");
8842
- }
8843
- /**
8844
- * 生成唯一 id
8845
- */
8846
- function uuid() {
8847
- try {
8848
- return crypto.randomUUID();
8849
- } catch {
8850
- return fallbackUUID();
8851
- }
8852
- }
8853
- /** 字段值是否「空」:null / undefined / 空串 */
8854
- function isBlank(value) {
8855
- return value == null || value === "";
8856
- }
8857
- /** 字段值是否「有值」 */
8858
- function isPresent(value) {
8859
- return !isBlank(value);
8860
- }
8861
- function parseFormTmplRefId(refId) {
8862
- if (!refId) return {
8863
- baseId: "",
8864
- id: ""
8865
- };
8866
- const [baseId, versionId] = refId.split(":");
8867
- return {
8868
- baseId: versionId ? baseId : "",
8869
- id: versionId || baseId
8870
- };
8871
- }
8872
- /**
8873
- * 安全解析 JSON
8874
- * @param data 待解析数据
8875
- * @param fallback 失败时返回值,默认 null
8876
- * @param validator 结果校验器
8877
- */
8878
- function safeParseJson(data, fallback = null, validator) {
8879
- if (typeof data !== "string") return fallback;
8880
- try {
8881
- const parsed = JSON.parse(data);
8882
- if (validator && !validator(parsed)) return fallback;
8883
- return parsed;
8884
- } catch {
8885
- return fallback;
8886
- }
8887
- }
8888
- /** 设置字段的默认valuePath */
8889
- function generateValuePath(fieldLink, subFieldKey) {
8890
- if (subFieldKey) return `$.${subFieldKey}${subFieldKey.includes(":") ? "[n_y][n_x]" : "[n]"}.${fieldLink}`;
8891
- else return `$.${fieldLink}`;
8892
- }
8893
- /**
8894
- * 按分隔符截取字符串最后一个片段,处理空值/无分隔符边界
8895
- * @param str 待截取的字符串(允许空/undefined)
8896
- * @param separator 分隔符,默认.
8897
- * @returns 最后一个片段,空值返回空字符串
8898
- */
8899
- function getLastSegment$1(str, separator = ".") {
8900
- if (!str) return "";
8901
- const index = str.lastIndexOf(separator);
8902
- return index === -1 ? str : str.slice(index + 1);
8903
- }
8904
- /**
8905
- * 根据参考路径 / index 替换模板中的占位符
8906
- *
8907
- * - 传入 x 时替换 [n_x]
8908
- * - 传入 y 时替换 [n_y]
8909
- * - 未传入时保留原占位符
8910
- * - 最后再统一处理普通 [n]
8911
- *
8912
- * 示例:
8913
- * replacePathIndexPlaceholders({
8914
- * x: 1,
8915
- * y: undefined,
8916
- * templatePath: '$.table[n_y].cross[n_x].value[n]',
8917
- * })
8918
- * =>
8919
- * '$.table[n_y].cross[1].value[n]'
8920
- */
8921
- function replacePathIndexPlaceholders(params) {
8922
- const { refPath, templatePath } = params;
8923
- let n = params.n;
8924
- let x = params.x;
8925
- let y = params.y;
8926
- if (refPath) {
8927
- const indices = [...refPath.matchAll(/\[(\d+)\]/g)].map((m) => Number(m[1]));
8928
- y ??= indices[0];
8929
- x ??= indices[1] ?? indices[0];
8930
- n ??= indices[0];
8931
- }
8932
- let path = templatePath;
8933
- path = replacePathIndexPlaceholder(y, path, "n_y");
8934
- path = replacePathIndexPlaceholder(x, path, "n_x");
8935
- path = replacePathIndexPlaceholder(n ?? x, path, "n");
8936
- return path;
8937
- }
8938
- /**
8939
- * 提取参考路径中的索引,替换模板路径中的占位符
8940
- *
8941
- * @param refPath 参考路径(如 $.a[1].b)或直接传数字
8942
- * @param templatePath 模板路径(如 $.list[n].value)
8943
- * @param placeholder 占位符名称,默认 n
8944
- *
8945
- * @example
8946
- * replacePathIndexPlaceholder(1, '$.a[n].b')
8947
- * // $.a[1].b
8948
- *
8949
- * @example
8950
- * replacePathIndexPlaceholder(2, '$.a[n_x].b', 'n_x')
8951
- * // $.a[2].b
8952
- */
8953
- function replacePathIndexPlaceholder(refPath, templatePath, placeholder = "n") {
8954
- let index;
8955
- if (refPath === void 0) return templatePath;
8956
- if (typeof refPath === "number") index = refPath.toString();
8957
- else {
8958
- const indexMatch = refPath.match(/\[(\d+)\]/);
8959
- index = indexMatch ? indexMatch[1] : placeholder;
8960
- }
8961
- return templatePath.replaceAll(`[${placeholder}]`, `[${index}]`);
8962
- }
8963
- /**
8964
- * 判断运行时路径是否匹配 valuePath 模板(支持 [n] / [n_x] / [n_y] 占位符)
8965
- *
8966
- * @example
8967
- * runtimePathMatchesTemplate('$.items[n].name', '$.items[2].name') // true
8968
- */
8969
- function runtimePathMatchesTemplate(template, runtimePath) {
8970
- if (template === runtimePath) return true;
8971
- const regex = template.replace(/\[n_y\]/g, "\0NY\0").replace(/\[n_x\]/g, "\0NX\0").replace(/\[n\]/g, "\0N\0").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\u0000NY\u0000/g, "\\[\\d+\\]").replace(/\u0000NX\u0000/g, "\\[\\d+\\]").replace(/\u0000N\u0000/g, "\\[\\d+\\]");
8972
- return new RegExp(`^${regex}$`).test(runtimePath);
8973
- }
8974
- /** 由 valuePath 模板生成 enricher 用的 path 匹配函数 */
8975
- function createValuePathMatcher(template) {
8976
- return (runtimePath) => runtimePathMatchesTemplate(template, runtimePath);
8977
- }
8978
- function parseValuePath(valuePath) {
8979
- if (!valuePath) return {
8980
- raw: "",
8981
- normalized: "",
8982
- fieldKey: "",
8983
- fieldPath: "",
8984
- isRoot: false,
8985
- isSubTable: false,
8986
- isLink: false,
8987
- hasIndex: false,
8988
- segments: []
8989
- };
8990
- const normalized = valuePath.replace(/^\$\./, "");
8991
- const segments = normalized.split(".").filter(Boolean);
8992
- const only = segments[0] || "";
8993
- const parentRaw = segments.length > 1 ? only : only.includes(":") ? only : "";
8994
- const fieldKey = segments.length > 1 ? segments.at(-1) || "" : only.includes(":") ? "" : only;
8995
- const hasIndex = /\[[^\]]+\]/.test(valuePath);
8996
- const isLink = parentRaw.includes(":");
8997
- let parentFieldKey = "";
8998
- let linkFieldKey = "";
8999
- if (isLink) {
9000
- const colonIdx = parentRaw.indexOf(":");
9001
- const subFieldKey = colonIdx >= 0 ? parentRaw.slice(0, colonIdx) : parentRaw;
9002
- const linkKey = colonIdx >= 0 ? parentRaw.slice(colonIdx + 1) : "";
9003
- parentFieldKey = (subFieldKey || "").replace(/\[[^\]]*\]/g, "");
9004
- linkFieldKey = (linkKey || "").replace(/\[[^\]]*\]/g, "");
9005
- } else parentFieldKey = parentRaw.replace(/\[.*?\]/g, "");
9006
- return {
9007
- raw: valuePath,
9008
- normalized,
9009
- fieldKey,
9010
- fieldPath: fieldKey ? `$.${fieldKey}` : "",
9011
- parentFieldKey,
9012
- parentFieldPath: parentFieldKey ? `$.${parentFieldKey}` : "",
9013
- isRoot: segments.length === 1,
9014
- isSubTable: segments.length > 1,
9015
- isLink,
9016
- linkFieldKey,
9017
- linkFieldPath: linkFieldKey ? `$.${linkFieldKey}` : "",
9018
- hasIndex,
9019
- segments
9020
- };
9021
- }
9022
- /**
9023
- * 提取 $.变量名[内容] 格式的方法(截取到 ] 并包含 ])
9024
- * @param str
9025
- * @returns
9026
- */
9027
- function getBeforeBracket(str) {
9028
- var _str$match, _str$match2;
9029
- const m = (_str$match = str.match(/\$\.[a-z0-9_$:]+(?:\[[^\]]+\])+/i)) === null || _str$match === void 0 ? void 0 : _str$match[0];
9030
- if (m) return m;
9031
- return ((_str$match2 = str.match(/\$\.[a-z_]+\[[^\]]+\]/i)) === null || _str$match2 === void 0 ? void 0 : _str$match2[0]) || "";
9032
- }
9033
- /** 防抖特性的RAF,同一帧内多次调用 schedule() 只会执行一次 */
9034
- function createRafOnce() {
9035
- let rafId = null;
9036
- let pending = null;
9037
- const schedule = (fn) => {
9038
- if (rafId) return;
9039
- rafId = requestAnimationFrame(() => {
9040
- rafId = null;
9041
- fn();
9042
- });
9043
- };
9044
- const syncSchedule = (fn) => {
9045
- if (pending) return pending;
9046
- pending = new Promise((resolve) => {
9047
- rafId = requestAnimationFrame(() => {
9048
- rafId = null;
9049
- try {
9050
- resolve(fn());
9051
- } finally {
9052
- pending = null;
9053
- }
9054
- });
9055
- });
9056
- return pending;
9057
- };
9058
- const cancel = () => {
9059
- if (rafId) {
9060
- cancelAnimationFrame(rafId);
9061
- rafId = null;
9062
- pending = null;
9063
- }
9064
- };
9065
- return {
9066
- schedule,
9067
- syncSchedule,
9068
- cancel
9069
- };
9070
- }
9071
- function listToTree(list, transform = (n) => n) {
9072
- const map = /* @__PURE__ */ new Map();
9073
- const roots = [];
9074
- list.forEach((item) => {
9075
- map.set(item.value, item);
9076
- item.children = [];
9077
- });
9078
- list.forEach((node) => {
9079
- var _node$_item;
9080
- const parentId = (_node$_item = node._item) === null || _node$_item === void 0 ? void 0 : _node$_item.parentId;
9081
- if (!parentId || parentId === "ROOT") roots.push(transform(node));
9082
- else {
9083
- var _parent$children;
9084
- const parent = map.get(parentId);
9085
- parent === null || parent === void 0 || (_parent$children = parent.children) === null || _parent$children === void 0 || _parent$children.push(transform(node));
9086
- }
9087
- });
9088
- return roots;
9089
- }
9090
- function flattenTree(tree, childrenKey = "children") {
9091
- const result = [];
9092
- function traverse(nodes) {
9093
- nodes.forEach((node) => {
9094
- const { [childrenKey]: children, ...rest } = node;
9095
- result.push({
9096
- ...rest,
9097
- [childrenKey]: children
9098
- });
9099
- if (children === null || children === void 0 ? void 0 : children.length) traverse(children);
9100
- });
9101
- }
9102
- traverse(tree);
9103
- return result;
9104
- }
9105
- /** 从 URL 提取 name */
9106
- function getFileName(url) {
9107
- try {
9108
- return decodeURIComponent(url.split("/").pop() || "");
9109
- } catch {
9110
- return url.split("/").pop() || "";
9111
- }
9112
- }
9113
- /**
9114
- * 合并两个按钮数组
9115
- * @param {Array} A - 基础数组
9116
- * @param {Array} B - 更新数组
9117
- * @param {Object} options
9118
- * @param {string[]} options.keyFields - 用于唯一匹配的字段
9119
- * @param {string[]} options.fieldsToMerge - 从 B 合并到 A 的字段
9120
- * @param {boolean} options.isAllowMerge - 是否允许合并
9121
- * @param {boolean} options.isConcat - 如果 A数组是空是否直接用B 数组
9122
- * @returns {Array} 合并后的数组
9123
- */
9124
- function mergeByMultiKey(A, B, { keyFields = ["type", "isCustom"], fieldsToMerge = ["alias", "enable"], isAllowMerge = true, isConcat = false } = {}) {
9125
- if (!Array.isArray(A)) return [];
9126
- if (!isAllowMerge || !Array.isArray(B) || B.length === 0) return [...A];
9127
- if (isConcat && Array.isArray(A) && A.length === 0) return [...B];
9128
- const keyFn = (item) => keyFields.map((k) => {
9129
- const v = item === null || item === void 0 ? void 0 : item[k];
9130
- if (typeof v === "boolean") return String(v);
9131
- return v == null ? "" : String(v);
9132
- }).join("::");
9133
- const bMap = keyBy(B, keyFn);
9134
- return A.map((a) => {
9135
- const info = bMap[keyFn(a)];
9136
- return info ? {
9137
- ...a,
9138
- ...pick(info, fieldsToMerge)
9139
- } : { ...a };
9140
- });
9141
- }
9142
- var halfPixel, isEmptyValue$1;
9143
- var init_core$1 = __esmMin((() => {
9144
- halfPixel = (n) => Math.round(n) + .5;
9145
- isEmptyValue$1 = (value) => {
9146
- if (value === void 0 || value === null) return true;
9147
- if (typeof value === "string") return value.trim() === "";
9148
- if (typeof value === "number") return Number.isNaN(value);
9149
- if (Array.isArray(value)) {
9150
- if (value.length === 0) return true;
9151
- }
9152
- if (value instanceof Map || value instanceof Set) return value.size === 0;
9153
- if (value instanceof Date) return Number.isNaN(value.getTime());
9154
- if (typeof value === "object") return Object.keys(value).length === 0;
9155
- return false;
9156
- };
9157
- }));
9158
- //#endregion
9159
9169
  //#region src/core/model/capability/index.ts
9160
9170
  /**
9161
9171
  * 获取当前节点在父节点中的索引
@@ -13287,7 +13297,7 @@ function countDecimals(val) {
13287
13297
  function extractNumericPrefix(raw, integer) {
13288
13298
  var _value$match;
13289
13299
  if (!raw) return null;
13290
- let value = raw.replace(/\s+/g, "");
13300
+ let value = stripNumberNoise(raw);
13291
13301
  if (value.startsWith("-.")) value = `-0${value.slice(1)}`;
13292
13302
  else if (value.startsWith("+.") || value.startsWith(".")) value = `0${value.replace(/^\+/, "")}`;
13293
13303
  const reg = integer ? /^[-+]?\d+/ : /^[-+]?\d*(\.\d*)?/;
@@ -13390,6 +13400,7 @@ var DATE_STORAGE_FORMAT_FALLBACK, DATETIME_STORAGE_FORMAT_FALLBACK;
13390
13400
  var init_form_value = __esmMin((() => {
13391
13401
  init_enum();
13392
13402
  init_field_type();
13403
+ init_core$1();
13393
13404
  DATE_STORAGE_FORMAT_FALLBACK = "YYYY-MM-DD";
13394
13405
  DATETIME_STORAGE_FORMAT_FALLBACK = "YYYY-MM-DD HH:mm:ss";
13395
13406
  }));
@@ -90760,6 +90771,10 @@ var init_render = __esmMin((() => {
90760
90771
  }));
90761
90772
  //#endregion
90762
90773
  //#region src/runtime/interface/data.ts
90774
+ /** edhr 套件使用独立的审批历史模型,其他套件统一用 em_approve_his */
90775
+ function resolveApproveHisModelKey(suiteKey) {
90776
+ return suiteKey === "edhr" ? "em_edhr_summary_approve_his" : "em_approve_his";
90777
+ }
90763
90778
  /**
90764
90779
  * 拉取子模型key并添加到fieldScope进行初始化
90765
90780
  * @param modelKey 主模型key
@@ -90806,7 +90821,7 @@ async function fetchMultipleModelData(requests) {
90806
90821
  }
90807
90822
  /** 请求真实填报的渲染数据 */
90808
90823
  async function fetchRenderData(payload) {
90809
- const { info, fetchConfig, queryConfig, isMockReport } = payload || {};
90824
+ const { info, fetchConfig, queryConfig, isMockReport, suiteKey } = payload || {};
90810
90825
  if (isMockReport) return Promise.resolve();
90811
90826
  if (info.formType === FormTypeConst.VIEW) {
90812
90827
  let requestName;
@@ -90838,7 +90853,7 @@ async function fetchRenderData(payload) {
90838
90853
  if (isSupport) {
90839
90854
  const res = await api$1.apaas.modelComprehensive.postBizServiceModelCategoryModelKeyBsKey({
90840
90855
  modelCategory: "entity",
90841
- modelKey: "em_edhr_summary_approve_his",
90856
+ modelKey: resolveApproveHisModelKey(suiteKey),
90842
90857
  bsKey: "getOne"
90843
90858
  }, {}, { query: {
90844
90859
  ...other,
@@ -91282,7 +91297,7 @@ function isInLinkSubTableLayoutScope(row, col, region, options = {}) {
91282
91297
  var init_link_sub_table_layout = __esmMin((() => {}));
91283
91298
  //#endregion
91284
91299
  //#region src/suites/edhr/manifest/field/_common_/basic.ts
91285
- var initComponentDependency, commonDefaultRenderers, commonDefaultProps, autofillFieldDefaultProps, dateFieldDefaultProps, numberFieldDefaultProps, signFieldDefaultProps, fileFieldDefaultProps, styleDefaultProps, styleSizeDefaultProps, labelPriorityConfig, labelResolveDateConfig, labelResolveUserConfig, labelResolveOrgConfig, labelResolveEnumConfig, optionsMapEnumConfig, labelOnValueChangeRule, hyperlinkOnValueChangeRule, idOnValueChangeRule, hyperlinkAndIdOnValueChangeRules;
91300
+ var initComponentDependency, commonDefaultRenderers, commonDefaultProps, autofillFieldDefaultProps, dateFieldDefaultProps, numberFieldDefaultProps, signFieldDefaultProps, fileFieldDefaultProps, styleDefaultProps, styleSizeDefaultProps, signStyleSizeDefaultProps, labelPriorityConfig, labelResolveDateConfig, labelResolveUserConfig, labelResolveOrgConfig, labelResolveEnumConfig, optionsMapEnumConfig, labelOnValueChangeRule, hyperlinkOnValueChangeRule, idOnValueChangeRule, hyperlinkAndIdOnValueChangeRules;
91286
91301
  var init_basic = __esmMin((() => {
91287
91302
  init_enum();
91288
91303
  initComponentDependency = {
@@ -91376,6 +91391,10 @@ var init_basic = __esmMin((() => {
91376
91391
  /** 组件默认高度 */
91377
91392
  height: 68
91378
91393
  };
91394
+ signStyleSizeDefaultProps = {
91395
+ width: 180,
91396
+ height: 102
91397
+ };
91379
91398
  labelPriorityConfig = {
91380
91399
  type: "priority",
91381
91400
  fields: ["defaultValue"]
@@ -110789,12 +110808,14 @@ var init_ImageWidget = __esmMin((() => {
110789
110808
  _defineProperty(this, "valuePath", void 0);
110790
110809
  _defineProperty(this, "widgetMeta", void 0);
110791
110810
  _defineProperty(this, "signature", void 0);
110811
+ _defineProperty(this, "signTime", void 0);
110792
110812
  _defineProperty(this, "pageWidgetMeta", void 0);
110793
110813
  _defineProperty(this, "dataSlotIndex", void 0);
110794
110814
  this.src = options.src;
110795
110815
  this.valuePath = options.valuePath;
110796
110816
  this.widgetMeta = options.widgetMeta;
110797
110817
  this.signature = options.signature;
110818
+ this.signTime = options.signTime;
110798
110819
  this.pageWidgetMeta = options.pageWidgetMeta;
110799
110820
  this.dataSlotIndex = options.dataSlotIndex;
110800
110821
  }
@@ -110926,7 +110947,7 @@ var init_SignatureHandler = __esmMin((() => {
110926
110947
  static layoutField(ctx) {
110927
110948
  var _wr$widgetMeta2;
110928
110949
  const { context, wr } = ctx;
110929
- const { width = 120, height = 68 } = ((_wr$widgetMeta2 = wr.widgetMeta) === null || _wr$widgetMeta2 === void 0 ? void 0 : _wr$widgetMeta2.props) || {};
110950
+ const { width = 180, height = 102 } = ((_wr$widgetMeta2 = wr.widgetMeta) === null || _wr$widgetMeta2 === void 0 ? void 0 : _wr$widgetMeta2.props) || {};
110930
110951
  let doc = context.doc;
110931
110952
  let valueJson = this.getValue(ctx, wr.valuePath);
110932
110953
  if (valueJson) JSON.parse(valueJson).forEach((item, index) => {
@@ -110940,6 +110961,7 @@ var init_SignatureHandler = __esmMin((() => {
110940
110961
  y: 0,
110941
110962
  src: item.url || "",
110942
110963
  signature: item.url ? void 0 : item.username,
110964
+ signTime: item.url ? void 0 : item.time,
110943
110965
  modelRef: {
110944
110966
  id: this.getModelRefId(context, wr),
110945
110967
  start: index,
@@ -124122,6 +124144,7 @@ var initObjectTypeFieldDefaultValue = (rawData, instances, fieldList, runtimeJso
124122
124144
  });
124123
124145
  };
124124
124146
  async function prepareDocumentRenderData(options) {
124147
+ var _payload$ctx;
124125
124148
  const { requestInfo, payload, materialNo, query, instances, subTableInfoList, fieldList, masterSlaveList } = options;
124126
124149
  const rawData = conversionFormState({
124127
124150
  masterSlaveList,
@@ -124130,7 +124153,8 @@ async function prepareDocumentRenderData(options) {
124130
124153
  fetchConfig: { _gct_materialNo_: materialNo },
124131
124154
  queryConfig: query,
124132
124155
  instances,
124133
- isMockReport: payload.isMockReport || payload.factoryType === "template"
124156
+ isMockReport: payload.isMockReport || payload.factoryType === "template",
124157
+ suiteKey: (_payload$ctx = payload.ctx) === null || _payload$ctx === void 0 ? void 0 : _payload$ctx.suiteKey
124134
124158
  }),
124135
124159
  subTableInfoList
124136
124160
  });
@@ -129277,40 +129301,184 @@ function computeImageDisplaySize(natural, opts = {}) {
129277
129301
  height: Math.round(nh * scale)
129278
129302
  };
129279
129303
  }
129280
- /** 将签名姓名绘制为图片 DataURL */
129281
- function createSignatureImageDataUrl(name, width, height) {
129282
- const canvas = document.createElement("canvas");
129283
- canvas.width = width;
129284
- canvas.height = height;
129285
- const ctx = canvas.getContext("2d");
129286
- ctx.fillStyle = "#fff";
129287
- ctx.fillRect(0, 0, width, height);
129288
- let fontSize = Math.floor(height / 2);
129289
- const setFont = () => {
129290
- ctx.font = `${fontSize}px Arial`;
129304
+ /**
129305
+ * 在目标框内等比缩放(contain),不压缩、不拉伸
129306
+ */
129307
+ function computeContainDisplaySize(natural, box) {
129308
+ const nw = natural.width;
129309
+ const nh = natural.height;
129310
+ if (!nw || !nh || !box.width || !box.height) return {
129311
+ width: box.width || nw,
129312
+ height: box.height || nh
129313
+ };
129314
+ const scale = Math.min(box.width / nw, box.height / nh);
129315
+ return {
129316
+ width: Math.round(nw * scale),
129317
+ height: Math.round(nh * scale)
129318
+ };
129319
+ }
129320
+ function wrapText(text, maxWidth, context) {
129321
+ const characters = text.split("");
129322
+ const lines = [];
129323
+ let currentLine = "";
129324
+ for (const char of characters) {
129325
+ const testLine = currentLine + char;
129326
+ if (context.measureText(testLine).width > maxWidth && currentLine !== "") {
129327
+ lines.push(currentLine);
129328
+ currentLine = char;
129329
+ } else currentLine = testLine;
129330
+ }
129331
+ if (currentLine) lines.push(currentLine);
129332
+ return lines;
129333
+ }
129334
+ /** 将姓名按字数均分为多行(如四字 → 2+2) */
129335
+ function splitBalancedNameLines(name, maxLines) {
129336
+ if (name.length <= 1 || maxLines <= 1) return [name];
129337
+ const lineCount = Math.min(maxLines, name.length);
129338
+ const chunkSize = Math.ceil(name.length / lineCount);
129339
+ const lines = [];
129340
+ for (let i = 0; i < name.length; i += chunkSize) lines.push(name.slice(i, i + chunkSize));
129341
+ return lines;
129342
+ }
129343
+ function measureLinesWidth(lines, ctx) {
129344
+ return Math.max(...lines.map((line) => ctx.measureText(line).width));
129345
+ }
129346
+ /** 左侧姓名优先单行展示,四字可 2+2,仍超出才按字符换行 */
129347
+ function fitNameInSection(name, maxWidth, maxHeight, ctx, initialFontSize, minFontSize = 10) {
129348
+ const tryFitLines = (lines, startFontSize) => {
129349
+ let fontSize = startFontSize;
129350
+ while (fontSize >= minFontSize) {
129351
+ const lineHeight = fontSize * 1.2;
129352
+ ctx.font = `bold ${fontSize}px Arial, sans-serif`;
129353
+ const fitsWidth = measureLinesWidth(lines, ctx) <= maxWidth;
129354
+ const fitsHeight = lines.length * lineHeight <= maxHeight;
129355
+ if (fitsWidth && fitsHeight) return {
129356
+ fontSize,
129357
+ lines,
129358
+ lineHeight
129359
+ };
129360
+ fontSize--;
129361
+ }
129362
+ return null;
129291
129363
  };
129292
- setFont();
129293
- while (ctx.measureText(name).width > width * .9 && fontSize > 12) {
129364
+ const singleLineFit = tryFitLines([name], initialFontSize);
129365
+ if (singleLineFit) return singleLineFit;
129366
+ if (name.length >= 3 && name.length <= 6) {
129367
+ const balancedFit = tryFitLines(splitBalancedNameLines(name, 2), initialFontSize);
129368
+ if (balancedFit) return balancedFit;
129369
+ }
129370
+ let fontSize = minFontSize;
129371
+ ctx.font = `bold ${fontSize}px Arial, sans-serif`;
129372
+ let lines = wrapText(name, maxWidth, ctx);
129373
+ let lineHeight = fontSize * 1.2;
129374
+ while (lines.length * lineHeight > maxHeight && fontSize > 10) {
129294
129375
  fontSize--;
129295
- setFont();
129376
+ lineHeight = fontSize * 1.2;
129377
+ ctx.font = `bold ${fontSize}px Arial, sans-serif`;
129378
+ lines = wrapText(name, maxWidth, ctx);
129296
129379
  }
129297
- ctx.fillStyle = "#000";
129298
- ctx.textAlign = "center";
129380
+ return {
129381
+ fontSize,
129382
+ lines,
129383
+ lineHeight
129384
+ };
129385
+ }
129386
+ /** 与原无图签名 canvas 一致的水平边距(maxTextWidth = width * 0.9 时,240px 画布为 12px) */
129387
+ function getSignCanvasHorizontalMargin(width) {
129388
+ return (width - width * .9) / 2;
129389
+ }
129390
+ /** 左右内容区间距,随 canvas 宽度等比缩放(240px 基准为 8px) */
129391
+ function getFormSignSectionGap(width) {
129392
+ return Math.round(8 * (width / SIGN_CANVAS_BASE_WIDTH));
129393
+ }
129394
+ /** 右侧信息禁止换行,空间不够只缩小字号 */
129395
+ function fitMetaInSection(lines, maxWidth, maxHeight, ctx, initialFontSize, minFontSize = 8) {
129396
+ let fontSize = initialFontSize;
129397
+ while (fontSize >= minFontSize) {
129398
+ const lineHeight = fontSize * 1.35;
129399
+ ctx.font = `${fontSize}px Arial, sans-serif`;
129400
+ const fitsWidth = measureLinesWidth(lines, ctx) <= maxWidth;
129401
+ const fitsHeight = lines.length * lineHeight <= maxHeight;
129402
+ if (fitsWidth && fitsHeight) return {
129403
+ fontSize,
129404
+ lines,
129405
+ lineHeight
129406
+ };
129407
+ fontSize--;
129408
+ }
129409
+ ctx.font = `${minFontSize}px Arial, sans-serif`;
129410
+ return {
129411
+ fontSize: minFontSize,
129412
+ lines,
129413
+ lineHeight: minFontSize * 1.35
129414
+ };
129415
+ }
129416
+ /**
129417
+ * 无签名图片时,按字段实际宽高绘制用户名 + 电子签名 + 日期
129418
+ */
129419
+ function createFormSignFallbackImage(name, width, height, time) {
129420
+ const canvas = document.createElement("canvas");
129421
+ canvas.width = Math.max(1, Math.round(width * FALLBACK_SIGN_DPR));
129422
+ canvas.height = Math.max(1, Math.round(height * FALLBACK_SIGN_DPR));
129423
+ const ctx = canvas.getContext("2d");
129424
+ ctx.scale(FALLBACK_SIGN_DPR, FALLBACK_SIGN_DPR);
129425
+ ctx.fillStyle = "#ffffff";
129426
+ ctx.fillRect(0, 0, width, height);
129427
+ const margin = getSignCanvasHorizontalMargin(width);
129428
+ const sectionGap = getFormSignSectionGap(width);
129429
+ const contentWidth = Math.max(1, width - margin * 2);
129430
+ const dateStr = time ? dayjs(time).format("YYYY-MM-DD") : dayjs().format("YYYY-MM-DD");
129431
+ const sourceMetaLines = [`${ELECTRONIC_SIGNATURE_LABEL}:${name}`, `${DATE_LABEL}:${dateStr}`];
129432
+ const initialMetaFont = Math.min(Math.max(12, Math.floor(height * .22)), Math.max(11, Math.floor(height / 2.8)));
129433
+ ctx.font = `${initialMetaFont}px Arial, sans-serif`;
129434
+ const naturalMetaWidth = measureLinesWidth(sourceMetaLines, ctx);
129435
+ const minNameWidth = Math.max(24, Math.floor(contentWidth * .28));
129436
+ const metaMaxWidth = Math.max(40, Math.min(naturalMetaWidth, contentWidth - sectionGap - minNameWidth));
129437
+ const { fontSize: metaFontSize, lines: metaLines, lineHeight: metaLineHeight } = fitMetaInSection(sourceMetaLines, metaMaxWidth, height, ctx, initialMetaFont);
129438
+ ctx.font = `${metaFontSize}px Arial, sans-serif`;
129439
+ const metaWidth = Math.min(metaMaxWidth, measureLinesWidth(metaLines, ctx));
129440
+ const metaTotalHeight = metaLines.length * metaLineHeight;
129441
+ const rightSectionX = width - margin - metaWidth;
129442
+ const { fontSize: nameFontSize, lines: nameLines, lineHeight: nameLineHeight } = fitNameInSection(name, Math.max(32, rightSectionX - margin - sectionGap), height, ctx, Math.floor(height * .42));
129443
+ ctx.fillStyle = "#000000";
129444
+ ctx.textAlign = "left";
129299
129445
  ctx.textBaseline = "middle";
129300
- const offsetY = (Math.random() - .5) * 4;
129301
- ctx.fillText(name, width / 2, height / 2 + offsetY);
129446
+ const nameStartY = (height - nameLines.length * nameLineHeight) / 2 + nameLineHeight / 2;
129447
+ nameLines.forEach((line, index) => {
129448
+ ctx.font = `bold ${nameFontSize}px Arial, sans-serif`;
129449
+ ctx.fillText(line, margin, nameStartY + index * nameLineHeight);
129450
+ });
129451
+ const metaStartY = (height - metaTotalHeight) / 2 + metaLineHeight / 2;
129452
+ metaLines.forEach((line, index) => {
129453
+ ctx.font = `${metaFontSize}px Arial, sans-serif`;
129454
+ ctx.fillText(line, rightSectionX, metaStartY + index * metaLineHeight);
129455
+ });
129302
129456
  return canvas.toDataURL("image/png");
129303
129457
  }
129304
- /** 创建签名图片 */
129305
- function createSignatureImage(name, width, height) {
129306
- const base64 = createSignatureImageDataUrl(name, width, height);
129458
+ function loadDataUrlAsImage(dataUrl) {
129307
129459
  return new Promise((resolve) => {
129308
129460
  const img = new Image();
129309
- img.src = base64;
129461
+ img.src = dataUrl;
129310
129462
  img.onload = () => resolve(img);
129311
129463
  });
129312
129464
  }
129313
- var init_image_size_util = __esmMin((() => {}));
129465
+ /**
129466
+ * 创建无图签名兜底图(用户名 + 电子签名 + 验证日期)
129467
+ * 按字段宽高绘制,显示框设多大,字就按多大排
129468
+ */
129469
+ function createSignatureImageDataUrl(name, width = 180, height = 102, time) {
129470
+ return createFormSignFallbackImage(name, Math.max(1, Math.round(width)), Math.max(1, Math.round(height)), time);
129471
+ }
129472
+ function createSignatureImage(name, width = 180, height = 102, time) {
129473
+ return loadDataUrlAsImage(createSignatureImageDataUrl(name, width, height, time));
129474
+ }
129475
+ var SIGN_CANVAS_BASE_WIDTH, FALLBACK_SIGN_DPR, ELECTRONIC_SIGNATURE_LABEL, DATE_LABEL;
129476
+ var init_image_size_util = __esmMin((() => {
129477
+ SIGN_CANVAS_BASE_WIDTH = 240;
129478
+ FALLBACK_SIGN_DPR = 2;
129479
+ ELECTRONIC_SIGNATURE_LABEL = "电子签名";
129480
+ DATE_LABEL = "日期";
129481
+ }));
129314
129482
  //#endregion
129315
129483
  //#region src/runtime/renderer/dialogs/signature/logic.ts
129316
129484
  /**
@@ -129481,8 +129649,8 @@ var init_signature_dialog_vue_vue_type_script_setup_true_lang = __esmMin((() =>
129481
129649
  _hoisted_11$5 = ["src", "onClick"];
129482
129650
  _hoisted_12$4 = ["onClick"];
129483
129651
  _hoisted_13$3 = ["src"];
129484
- SIGNATURE_PREVIEW_WIDTH = 120;
129485
- SIGNATURE_PREVIEW_HEIGHT = 68;
129652
+ SIGNATURE_PREVIEW_WIDTH = 180;
129653
+ SIGNATURE_PREVIEW_HEIGHT = 102;
129486
129654
  signature_dialog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
129487
129655
  __name: "signature-dialog",
129488
129656
  props: {
@@ -129536,7 +129704,7 @@ var init_signature_dialog_vue_vue_type_script_setup_true_lang = __esmMin((() =>
129536
129704
  });
129537
129705
  function buildDisplaySrc(item) {
129538
129706
  if (item.url) return AssetHelper.resolveUrl(item.url) || "";
129539
- if (item.username) return createSignatureImageDataUrl(item.username, signatureSize.value.width, signatureSize.value.height);
129707
+ if (item.username) return createSignatureImageDataUrl(item.username, signatureSize.value.width, signatureSize.value.height, item.time);
129540
129708
  return "";
129541
129709
  }
129542
129710
  function ensureDisplaySrc(list) {
@@ -129688,8 +129856,8 @@ var init_signature_dialog_vue_vue_type_script_setup_true_lang = __esmMin((() =>
129688
129856
  });
129689
129857
  }));
129690
129858
  //#endregion
129691
- //#region src/runtime/renderer/dialogs/signature/signature-dialog.vue?vue&type=style&index=0&scoped=4c3fe309&lang.less
129692
- var init_signature_dialog_vue_vue_type_style_index_0_scoped_4c3fe309_lang = __esmMin((() => {}));
129859
+ //#region src/runtime/renderer/dialogs/signature/signature-dialog.vue?vue&type=style&index=0&scoped=f5f7562d&lang.less
129860
+ var init_signature_dialog_vue_vue_type_style_index_0_scoped_f5f7562d_lang = __esmMin((() => {}));
129693
129861
  //#endregion
129694
129862
  //#region src/runtime/renderer/dialogs/signature/signature-dialog.vue
129695
129863
  var signature_dialog_exports = /* @__PURE__ */ __exportAll({ default: () => signature_dialog_default });
@@ -129697,9 +129865,9 @@ var signature_dialog_default;
129697
129865
  var init_signature_dialog = __esmMin((() => {
129698
129866
  init_signature_dialog_vue_vue_type_script_setup_true_lang();
129699
129867
  init_signature_dialog_vue_vue_type_script_setup_true_lang();
129700
- init_signature_dialog_vue_vue_type_style_index_0_scoped_4c3fe309_lang();
129868
+ init_signature_dialog_vue_vue_type_style_index_0_scoped_f5f7562d_lang();
129701
129869
  init__plugin_vue_export_helper();
129702
- signature_dialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(signature_dialog_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-4c3fe309"]]);
129870
+ signature_dialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(signature_dialog_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-f5f7562d"]]);
129703
129871
  }));
129704
129872
  //#endregion
129705
129873
  //#region src/runtime/renderer/dropdowns/factories/dropdown-factory.ts
@@ -140839,7 +141007,7 @@ var manifest$51 = {
140839
141007
  defaultProps: {
140840
141008
  ...commonDefaultProps,
140841
141009
  ...signFieldDefaultProps,
140842
- ...styleSizeDefaultProps
141010
+ ...signStyleSizeDefaultProps
140843
141011
  }
140844
141012
  };
140845
141013
  //#endregion
@@ -141267,7 +141435,7 @@ var manifest$34 = {
141267
141435
  defaultProps: {
141268
141436
  ...commonDefaultProps,
141269
141437
  ...signFieldDefaultProps,
141270
- ...styleSizeDefaultProps
141438
+ ...signStyleSizeDefaultProps
141271
141439
  }
141272
141440
  };
141273
141441
  //#endregion
@@ -142103,10 +142271,14 @@ var withFieldIcon = (f) => {
142103
142271
  version: (manifest === null || manifest === void 0 ? void 0 : manifest.version) ?? "v1"
142104
142272
  };
142105
142273
  };
142106
- var edhrFieldProvider = new EdhrFieldProvider({
142107
- suiteKey: "edhr",
142108
- cacheTime: -1
142109
- }, fetcherFactory, filterFn);
142274
+ /** 创建字段 Provider,供 edhr / eqm 等复用 edhr 能力的套件使用 */
142275
+ function createEdhrFieldProvider(suiteKey) {
142276
+ return new EdhrFieldProvider({
142277
+ suiteKey,
142278
+ cacheTime: -1
142279
+ }, fetcherFactory, filterFn);
142280
+ }
142281
+ var edhrFieldProvider = createEdhrFieldProvider("edhr");
142110
142282
  //#endregion
142111
142283
  //#region src/capabilities/model-field-runtime/provider/ModelProviderBase.ts
142112
142284
  init_defineProperty();
@@ -142151,7 +142323,11 @@ var EdhrModelProvider = class extends ModelProviderBase {
142151
142323
  }
142152
142324
  }
142153
142325
  };
142154
- var edhrModelProvider = new EdhrModelProvider({ suiteKey: "edhr" });
142326
+ /** 创建模型 Provider,供 edhr / eqm 等复用 edhr 能力的套件使用 */
142327
+ function createEdhrModelProvider(suiteKey) {
142328
+ return new EdhrModelProvider({ suiteKey });
142329
+ }
142330
+ var edhrModelProvider = createEdhrModelProvider("edhr");
142155
142331
  //#endregion
142156
142332
  //#region src/suites/edhr/manifest/paper-widget/basic/barcode-manifest.ts
142157
142333
  var barcode_manifest_exports = /* @__PURE__ */ __exportAll({ manifest: () => manifest$7 });
@@ -143362,22 +143538,22 @@ var gct_signature_render_vue_vue_type_script_setup_true_name_gct_signature_rende
143362
143538
  height: imageHeight.value
143363
143539
  });
143364
143540
  const placeholder = computed(() => ({
143365
- width: imageWidth.value ?? 120,
143366
- height: imageHeight.value ?? 68,
143541
+ width: imageWidth.value ?? 180,
143542
+ height: imageHeight.value ?? 102,
143367
143543
  fill: "#f3f3f3"
143368
143544
  }));
143369
143545
  async function loadImage() {
143370
- const { src, signature } = props.widget;
143371
- if (signature) return await createSignatureImage(signature, imageWidth.value, imageHeight.value);
143546
+ const { src, signature, signTime } = props.widget;
143547
+ if (signature) return await createSignatureImage(signature, imageWidth.value, imageHeight.value, signTime);
143372
143548
  if (src) return await AssetHelper.loadImage(src);
143373
143549
  return null;
143374
143550
  }
143375
143551
  watch(() => [
143376
143552
  props.widget.src,
143377
143553
  props.widget.signature,
143554
+ props.widget.signTime,
143378
143555
  imageWidth.value,
143379
- imageHeight.value,
143380
- props.widget.keepAspect
143556
+ imageHeight.value
143381
143557
  ], async () => {
143382
143558
  const img = await loadImage();
143383
143559
  if (!img) return;
@@ -143385,17 +143561,15 @@ var gct_signature_render_vue_vue_type_script_setup_true_name_gct_signature_rende
143385
143561
  width: img.naturalWidth,
143386
143562
  height: img.naturalHeight
143387
143563
  };
143388
- display.value = computeImageDisplaySize(natural.value, {
143564
+ display.value = computeContainDisplaySize(natural.value, {
143389
143565
  width: imageWidth.value,
143390
- height: imageHeight.value,
143391
- keepAspect: props.widget.keepAspect ?? true,
143392
- maxDefaultWidth: 200
143566
+ height: imageHeight.value
143393
143567
  });
143394
143568
  imgRef.value = img;
143395
143569
  }, { immediate: true });
143396
143570
  const imageConfig = computed(() => ({
143397
- x: 0,
143398
- y: 0,
143571
+ x: (imageWidth.value - display.value.width) / 2,
143572
+ y: (imageHeight.value - display.value.height) / 2,
143399
143573
  image: imgRef.value,
143400
143574
  width: display.value.width,
143401
143575
  height: display.value.height
@@ -157798,13 +157972,42 @@ init_component_registry();
157798
157972
  init_registry$3();
157799
157973
  init_registry$2();
157800
157974
  init_registry$1();
157801
- var SUITE_KEY = "edhr";
157975
+ var SUITE_KEY$1 = "edhr";
157802
157976
  function installEdhrSuite() {
157803
157977
  FieldEngine.bootstrap({
157804
- suiteKey: SUITE_KEY,
157978
+ suiteKey: SUITE_KEY$1,
157805
157979
  fieldProvider: edhrFieldProvider,
157806
157980
  modelProvider: edhrModelProvider
157807
157981
  });
157982
+ fieldManifestRegistry.register(SUITE_KEY$1, fieldManifestMap);
157983
+ paperWidgetManifestRegistry.register(SUITE_KEY$1, paperWidgetManifestMap);
157984
+ componentRegistry.register(SUITE_KEY$1, vueComponentMap);
157985
+ panelRouterRegistry.register(SUITE_KEY$1, registryPanelRouters());
157986
+ panelSchemaRegistry.register(SUITE_KEY$1, registryPanelSchemas());
157987
+ panelConfigRegistry.register(SUITE_KEY$1, panelConfigComponentMap);
157988
+ }
157989
+ /** EDHR 套件插件注册 */
157990
+ var edhrSuitePlugin = {
157991
+ key: SUITE_KEY$1,
157992
+ install: installEdhrSuite
157993
+ };
157994
+ //#endregion
157995
+ //#region src/suites/eqm/index.ts
157996
+ init_model_field_runtime();
157997
+ init_field_manifest();
157998
+ init_paper_widget_manifest();
157999
+ init_component_registry();
158000
+ init_registry$3();
158001
+ init_registry$2();
158002
+ init_registry$1();
158003
+ var SUITE_KEY = "eqm";
158004
+ /** 当前复用 edhr 全套能力,后续 eqm 差异化时再拆分 */
158005
+ function installEqmSuite() {
158006
+ FieldEngine.bootstrap({
158007
+ suiteKey: SUITE_KEY,
158008
+ fieldProvider: createEdhrFieldProvider(SUITE_KEY),
158009
+ modelProvider: createEdhrModelProvider(SUITE_KEY)
158010
+ });
157808
158011
  fieldManifestRegistry.register(SUITE_KEY, fieldManifestMap);
157809
158012
  paperWidgetManifestRegistry.register(SUITE_KEY, paperWidgetManifestMap);
157810
158013
  componentRegistry.register(SUITE_KEY, vueComponentMap);
@@ -157812,10 +158015,10 @@ function installEdhrSuite() {
157812
158015
  panelSchemaRegistry.register(SUITE_KEY, registryPanelSchemas());
157813
158016
  panelConfigRegistry.register(SUITE_KEY, panelConfigComponentMap);
157814
158017
  }
157815
- /** EDHR 套件插件注册 */
157816
- var edhrSuitePlugin = {
158018
+ /** EQM 套件插件注册(当前复用 edhr 能力) */
158019
+ var eqmSuitePlugin = {
157817
158020
  key: SUITE_KEY,
157818
- install: installEdhrSuite
158021
+ install: installEqmSuite
157819
158022
  };
157820
158023
  //#endregion
157821
158024
  //#region src/sdk/plugins/register-panel-schemas.ts
@@ -157845,4 +158048,4 @@ function registerSuite(plugin) {
157845
158048
  plugin.install();
157846
158049
  }
157847
158050
  //#endregion
157848
- export { BuiltinComponentTypeConst, doc_design_layout_default as DocDesignLayout, DocModeTypeConst, doc_render_layout_default as DocRenderLayout, layout_default as GctLayout, PaperSizeConst, calcUsedFieldsFromRuntimeJson, edhrSuitePlugin, registerPanelSchemas, registerSuite, setupPlatformAdapters, setupVueRuntime, useDocController, useDocOperations, useDocRuntimeProvider, useDocSuite, useDocumentFactory, useFormTmplAndModelInit, useWord };
158051
+ export { BuiltinComponentTypeConst, doc_design_layout_default as DocDesignLayout, DocModeTypeConst, doc_render_layout_default as DocRenderLayout, layout_default as GctLayout, PaperSizeConst, calcUsedFieldsFromRuntimeJson, edhrSuitePlugin, eqmSuitePlugin, registerPanelSchemas, registerSuite, setupPlatformAdapters, setupVueRuntime, useDocController, useDocOperations, useDocRuntimeProvider, useDocSuite, useDocumentFactory, useFormTmplAndModelInit, useWord };