@canvas-components/react-list-table 0.3.45 → 0.3.47

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.cjs CHANGED
@@ -3,12 +3,16 @@
3
3
  var react = require('react');
4
4
  var reactDom = require('react-dom');
5
5
  var reactComponents = require('@canvas-components/react-components');
6
- var print = require('@canvas-components/print');
6
+ var reactPrintDesign = require('@canvas-components/react-print-design');
7
7
  var listTable = require('@canvas-components/list-table');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
9
  var chart = require('@canvas-components/chart');
10
10
  var date = require('@canvas-components/utils/date');
11
11
  var number = require('@canvas-components/utils/number');
12
+ var utils = require('@canvas-components/utils');
13
+ var printDesign = require('@canvas-components/print-design');
14
+ var print = require('@canvas-components/print');
15
+ var client = require('react-dom/client');
12
16
 
13
17
  // #style-inject:#style-inject
14
18
  function styleInject(css, { insertAt } = {}) {
@@ -33,7 +37,7 @@ function styleInject(css, { insertAt } = {}) {
33
37
  }
34
38
 
35
39
  // src/styles/table-overrides.css
36
- styleInject(".react-list-table-filter-option {\n transition: background-color 0.2s ease;\n}\n.react-list-table-filter-option:hover {\n background: #f3f4f6;\n}\n.react-list-table-menu-action,\n.react-list-table-menu-row {\n font-size: 14px;\n transition: background-color 0.2s ease, color 0.2s ease;\n}\n.react-list-table-menu-action:hover,\n.react-list-table-menu-row:hover {\n background: #f3f4f6 !important;\n}\n.react-list-table-custom-selection-copy {\n transition: background-color 0.2s ease;\n}\n.react-list-table-custom-selection-copy:hover {\n background: #4096ff !important;\n}\n.react-list-table-custom-selection-input > .canvas-react-input-number-handler-down {\n display: none;\n}\n.react-list-table-menu-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.react-list-table-menu-action:hover .react-list-table-menu-chevron,\n.react-list-table-menu-row:hover .react-list-table-menu-chevron {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n.react-list-table-menu-chevron-active {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n");
40
+ styleInject(".react-list-table-host {\n touch-action: none;\n min-width: 0;\n min-height: 0;\n}\n.react-list-table-filter-option {\n transition: background-color 0.2s ease;\n}\n.react-list-table-filter-option:hover {\n background: #f3f4f6;\n}\n.react-list-table-menu-action,\n.react-list-table-menu-row {\n font-size: 14px;\n transition: background-color 0.2s ease, color 0.2s ease;\n}\n.react-list-table-menu-action:hover,\n.react-list-table-menu-row:hover {\n background: #f3f4f6 !important;\n}\n.react-list-table-custom-selection-copy {\n transition: background-color 0.2s ease;\n}\n.react-list-table-custom-selection-copy:hover {\n background: #4096ff !important;\n}\n.react-list-table-custom-selection-input > .canvas-react-input-number-handler-down {\n display: none;\n}\n.react-list-table-menu-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.react-list-table-menu-action:hover .react-list-table-menu-chevron,\n.react-list-table-menu-row:hover .react-list-table-menu-chevron {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n.react-list-table-menu-chevron-active {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n");
37
41
  var conditionalOperators = {
38
42
  eq: "\u7B49\u4E8E",
39
43
  neq: "\u4E0D\u7B49\u4E8E",
@@ -949,11 +953,20 @@ function ReactTableContextMenuView(props) {
949
953
  }
950
954
  ),
951
955
  /* @__PURE__ */ jsxRuntime.jsx(ResetMenu, { request }),
952
- buildCacheMenuItems(request).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
956
+ request.columnSettingsCacheAvailable === true && buildCacheMenuItems(request).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
953
957
  MenuSubmenu,
954
958
  {
955
959
  label: "\u7F13\u5B58\u5230\u672C\u5730",
956
- items: buildCacheMenuItems(request)
960
+ items: [
961
+ ...buildCacheMenuItems(request),
962
+ {
963
+ key: "view-cache-config",
964
+ label: "\u67E5\u770B\u7F13\u5B58\u914D\u7F6E",
965
+ separatorBefore: true,
966
+ disabled: request.columnSettingsCacheAvailable !== true,
967
+ onClick: props.onViewCacheConfig
968
+ }
969
+ ]
957
970
  }
958
971
  ) : null
959
972
  ]
@@ -1050,22 +1063,41 @@ function ReactTableContextMenuView(props) {
1050
1063
  }
1051
1064
  ),
1052
1065
  /* @__PURE__ */ jsxRuntime.jsx(MenuAction, { label: "\u67E5\u627E", onClick: request.onOpenSearch }),
1053
- /* @__PURE__ */ jsxRuntime.jsx(
1066
+ request.onPrint ? /* @__PURE__ */ jsxRuntime.jsx(
1067
+ MenuAction,
1068
+ {
1069
+ label: "\u6253\u5370",
1070
+ onClick: () => {
1071
+ setMenuOpen(false);
1072
+ request.onPrint?.();
1073
+ }
1074
+ }
1075
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1054
1076
  MenuSubmenu,
1055
1077
  {
1056
1078
  label: "\u6253\u5370",
1057
1079
  items: [
1058
- {
1059
- key: "print-direct",
1060
- label: "\u76F4\u63A5\u6253\u5370",
1061
- onClick: request.onGetPrintData ? () => {
1080
+ ...props.printTemplates && props.printTemplates.length > 1 ? props.printTemplates.map((template) => ({
1081
+ key: `print-template-${template.key}`,
1082
+ label: `\u76F4\u63A5\u6253\u5370 ${template.label}`,
1083
+ disabled: template.disabled,
1084
+ onClick: template.disabled ? void 0 : () => {
1062
1085
  setMenuOpen(false);
1063
- props.onDirectPrint?.();
1064
- } : void 0
1065
- },
1086
+ props.onPrintTemplate?.(template.key);
1087
+ }
1088
+ })) : [
1089
+ {
1090
+ key: "print-direct",
1091
+ label: "\u76F4\u63A5\u6253\u5370",
1092
+ onClick: request.onGetPrintData ? () => {
1093
+ setMenuOpen(false);
1094
+ props.onDirectPrint?.();
1095
+ } : void 0
1096
+ }
1097
+ ],
1066
1098
  {
1067
1099
  key: "print-configure",
1068
- label: "\u6253\u5370\u914D\u7F6E",
1100
+ label: "\u6253\u5370\u8BBE\u8BA1",
1069
1101
  onClick: request.onGetPrintData ? () => {
1070
1102
  setMenuOpen(false);
1071
1103
  props.onPrint?.();
@@ -1074,6 +1106,14 @@ function ReactTableContextMenuView(props) {
1074
1106
  ]
1075
1107
  }
1076
1108
  ),
1109
+ request.customItems?.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1110
+ CustomContextMenuItem,
1111
+ {
1112
+ item,
1113
+ onClose: () => setMenuOpen(false)
1114
+ },
1115
+ item.key
1116
+ )),
1077
1117
  /* @__PURE__ */ jsxRuntime.jsx(
1078
1118
  MenuAction,
1079
1119
  {
@@ -1348,13 +1388,21 @@ function ReactTableContextMenuView(props) {
1348
1388
  }
1349
1389
  ),
1350
1390
  /* @__PURE__ */ jsxRuntime.jsx(ZoomMenu, { value: request.zoom ?? 1, onChange: request.onChangeZoom }),
1351
- /* @__PURE__ */ jsxRuntime.jsx(
1391
+ request.columnSettingsCacheAvailable === true ? /* @__PURE__ */ jsxRuntime.jsx(
1352
1392
  MenuSubmenu,
1353
1393
  {
1354
1394
  label: "\u7F13\u5B58\u5230\u672C\u5730",
1355
- items: buildCacheMenuItems(request)
1395
+ items: [
1396
+ ...buildCacheMenuItems(request),
1397
+ {
1398
+ key: "view-cache-config",
1399
+ label: "\u67E5\u770B\u7F13\u5B58\u914D\u7F6E",
1400
+ separatorBefore: true,
1401
+ onClick: props.onViewCacheConfig
1402
+ }
1403
+ ]
1356
1404
  }
1357
- ),
1405
+ ) : null,
1358
1406
  request.columns && request.onToggleColumn ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1359
1407
  /* @__PURE__ */ jsxRuntime.jsx(MenuDivider, {}),
1360
1408
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1499,6 +1547,31 @@ function MenuAction(props) {
1499
1547
  }
1500
1548
  );
1501
1549
  }
1550
+ function CustomContextMenuItem(props) {
1551
+ const { item, onClose } = props;
1552
+ const children = item.children?.filter(Boolean) ?? [];
1553
+ if (children.length > 0) {
1554
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuSubmenu, { label: item.label, items: [], minWidth: 240, children: children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
1555
+ CustomContextMenuItem,
1556
+ {
1557
+ item: child,
1558
+ onClose
1559
+ },
1560
+ child.key
1561
+ )) });
1562
+ }
1563
+ return /* @__PURE__ */ jsxRuntime.jsx(
1564
+ MenuAction,
1565
+ {
1566
+ label: item.label,
1567
+ disabled: item.disabled,
1568
+ onClick: item.disabled ? void 0 : () => {
1569
+ onClose();
1570
+ item.onClick?.();
1571
+ }
1572
+ }
1573
+ );
1574
+ }
1502
1575
  function MenuSubmenu(props) {
1503
1576
  const { label, items, header, footer, children, minWidth = 220 } = props;
1504
1577
  const menuItems = items.filter((item) => item.onClick || item.disabled);
@@ -3458,6 +3531,107 @@ var moreFormatChoiceSelectedStyle = {
3458
3531
  background: "#f3f4f6",
3459
3532
  color: "#1677ff"
3460
3533
  };
3534
+ function ReactListTableCacheConfigDialog(props) {
3535
+ const [rows, setRows] = react.useState([]);
3536
+ const [config, setConfig] = react.useState(null);
3537
+ const [loading, setLoading] = react.useState(true);
3538
+ react.useEffect(() => {
3539
+ let active = true;
3540
+ setLoading(true);
3541
+ void listTable.getListTableStoredColumnConfig(props.storageKey).then((config2) => {
3542
+ if (!active) return;
3543
+ setConfig(config2 ?? null);
3544
+ setRows(
3545
+ config2 ? createCacheConfigRows(config2) : []
3546
+ );
3547
+ setLoading(false);
3548
+ });
3549
+ return () => {
3550
+ active = false;
3551
+ };
3552
+ }, [props.storageKey]);
3553
+ const removeRow = (key) => {
3554
+ if (!config) return;
3555
+ const next = removeCacheConfigKey(config, key);
3556
+ setConfig(next);
3557
+ setRows((current) => current.filter((row) => row.key !== key));
3558
+ void listTable.saveListTableStoredColumnConfig(props.storageKey, next);
3559
+ };
3560
+ return /* @__PURE__ */ jsxRuntime.jsx(
3561
+ reactComponents.ReactModal,
3562
+ {
3563
+ open: true,
3564
+ title: "\u7F13\u5B58\u914D\u7F6E",
3565
+ width: 1180,
3566
+ fullscreenable: true,
3567
+ onCancel: props.onClose,
3568
+ footer: false,
3569
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 24, textAlign: "center", color: "#64748b" }, children: "\u6B63\u5728\u8BFB\u53D6\u7F13\u5B58\u914D\u7F6E\u2026" }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 24, textAlign: "center", color: "#64748b" }, children: "\u5F53\u524D\u6CA1\u6709\u7F13\u5B58\u914D\u7F6E" }) : props.renderTable({
3570
+ tableId: "list-table-cache-config",
3571
+ columns: [
3572
+ {
3573
+ key: "key",
3574
+ dataIndex: "key",
3575
+ title: "\u914D\u7F6E\u9879",
3576
+ width: 190,
3577
+ cellStyle: { verticalAlign: "top" }
3578
+ },
3579
+ {
3580
+ key: "value",
3581
+ dataIndex: "value",
3582
+ title: "\u7F13\u5B58\u503C",
3583
+ width: 850,
3584
+ cellType: "json",
3585
+ cellStyle: {
3586
+ verticalAlign: "top",
3587
+ fontFamily: "monospace",
3588
+ fontSize: 12
3589
+ }
3590
+ },
3591
+ {
3592
+ key: "operation",
3593
+ dataIndex: "key",
3594
+ title: "\u64CD\u4F5C",
3595
+ width: 90,
3596
+ render: (_value, row) => ({
3597
+ type: "button",
3598
+ text: "\u79FB\u9664",
3599
+ buttonType: "link",
3600
+ size: "small",
3601
+ danger: true,
3602
+ popconfirm: {
3603
+ title: "\u786E\u8BA4\u79FB\u9664\u7F13\u5B58\u914D\u7F6E\u5417\uFF1F",
3604
+ description: `\u5C06\u79FB\u9664\u201C${row.key}\u201D\u914D\u7F6E\u9879\u3002`,
3605
+ okText: "\u79FB\u9664",
3606
+ cancelText: "\u53D6\u6D88"
3607
+ },
3608
+ cursor: "pointer",
3609
+ onClick: () => removeRow(row.key)
3610
+ })
3611
+ }
3612
+ ],
3613
+ dataSource: rows,
3614
+ rowKey: "key",
3615
+ rowHeight: "auto",
3616
+ pagination: false,
3617
+ toolbar: false,
3618
+ contextMenu: false,
3619
+ style: { width: "100%", height: "min(68vh, 620px)" }
3620
+ })
3621
+ }
3622
+ );
3623
+ }
3624
+ function createCacheConfigRows(config) {
3625
+ return Object.entries(config).map(([key, value]) => ({
3626
+ key,
3627
+ value
3628
+ }));
3629
+ }
3630
+ function removeCacheConfigKey(config, key) {
3631
+ const next = { ...config };
3632
+ delete next[key];
3633
+ return next;
3634
+ }
3461
3635
  var SEARCH_MODAL_BODY_STYLE = {
3462
3636
  padding: 12
3463
3637
  };
@@ -3835,6 +4009,8 @@ function ReactListTableExportNameDialog({
3835
4009
  if (request.columns && !selectedKeys.length) return setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
3836
4010
  if (request.columns && cacheEnabled) {
3837
4011
  writeExportCache(storageKey, { version: 1, rows, selectedKeys: selectedKeys.map(String), includeSummary });
4012
+ } else if (request.columns) {
4013
+ writeExportCache(storageKey, null);
3838
4014
  }
3839
4015
  request.onConfirm(
3840
4016
  `${fileName.trim()}${extension}`,
@@ -3990,32 +4166,6 @@ function createPrintColumns(columns, summaryColumns = []) {
3990
4166
  };
3991
4167
  });
3992
4168
  }
3993
- function readPrintSettings(storageKey) {
3994
- if (!storageKey) return null;
3995
- try {
3996
- const value = JSON.parse(
3997
- localStorage.getItem(`canvas-table-print:${storageKey}`) ?? "null"
3998
- );
3999
- if (!value || typeof value !== "object") return null;
4000
- const settings = value;
4001
- if (settings.version !== 2 || settings.presetName !== void 0 && typeof settings.presetName !== "string" || !Array.isArray(settings.columns) || !settings.columns.every(
4002
- (column) => column && typeof column.key === "string" && Number.isFinite(column.width) && column.width >= 10
4003
- ) || !Array.isArray(settings.selectedKeys) || !settings.selectedKeys.every((key) => typeof key === "string") || !Number.isInteger(settings.rowsPerPage) || settings.rowsPerPage < 1)
4004
- return null;
4005
- return settings;
4006
- } catch {
4007
- return null;
4008
- }
4009
- }
4010
- function writePrintSettings(storageKey, settings) {
4011
- if (!storageKey) return;
4012
- try {
4013
- const key = `canvas-table-print:${storageKey}`;
4014
- if (settings) localStorage.setItem(key, JSON.stringify(settings));
4015
- else localStorage.removeItem(key);
4016
- } catch {
4017
- }
4018
- }
4019
4169
  function restorePrintColumns(columns, settings) {
4020
4170
  const current = new Map(columns.map((column) => [column.key, column]));
4021
4171
  const restored = [];
@@ -4028,1525 +4178,737 @@ function restorePrintColumns(columns, settings) {
4028
4178
  return [...restored, ...current.values()];
4029
4179
  }
4030
4180
  function resolvePrintSelectedKeys(sourceColumns, presetConfig, cached) {
4031
- const cachedColumnKeys = new Set(cached?.columns.map((column) => column.key));
4181
+ new Set(cached?.columns.map((column) => column.key));
4032
4182
  const presetKeys = presetConfig?.selectedKeys ? new Set(presetConfig.selectedKeys) : null;
4033
4183
  return sourceColumns.filter((column) => {
4034
- if (cached) {
4035
- return cachedColumnKeys.has(column.key) ? cached.selectedKeys.includes(column.key) : true;
4036
- }
4037
4184
  if (presetKeys) return presetKeys.has(column.key);
4038
4185
  return true;
4039
4186
  }).map((column) => column.key);
4040
4187
  }
4041
- function selectPrintColumns(columns, selectedKeys) {
4042
- const selected = new Set(selectedKeys.map(String));
4043
- return columns.filter((column) => selected.has(column.key));
4044
- }
4045
- function createCachedPrintTableOptions(source, storageKey, printPresets = []) {
4046
- const cached = readPrintSettings(storageKey);
4047
- const selectedPreset = cached?.presetName ? printPresets.find((preset) => preset.name === cached.presetName) : cached ? void 0 : printPresets[0];
4048
- const config = selectedPreset?.config;
4049
- const settings = { ...config, ...cached };
4188
+ function createTableDocument(source, preset) {
4189
+ const config = preset?.config;
4190
+ const page = printDesign.createPrintDesignPage("\u8868\u683C\u6253\u5370");
4191
+ const [paperWidth, paperHeight] = print.BROWSER_PRINT_PAPER_SIZES[config?.paperSize ?? "a4"];
4192
+ page.width = config?.orientation === "landscape" ? paperHeight : paperWidth;
4193
+ page.height = config?.orientation === "landscape" ? paperWidth : paperHeight;
4194
+ page.orientation = config?.orientation ?? "portrait";
4195
+ page.margins = config?.pageMargins ?? page.margins;
4196
+ const selectedKeys = resolvePrintSelectedKeys(source.columns, config);
4050
4197
  const columns = restorePrintColumns(
4051
- restorePrintColumns(
4052
- createPrintColumns(source.columns, source.summaryColumns),
4053
- config?.columns ? { columns: config.columns } : null
4054
- ),
4055
- cached
4198
+ createPrintColumns(source.columns, source.summaryColumns),
4199
+ config?.columns ? { columns: config.columns } : null
4200
+ ).filter((column) => selectedKeys.includes(column.key));
4201
+ const left = page.margins?.left ?? 10;
4202
+ const right = page.margins?.right ?? 10;
4203
+ const bottom = page.margins?.bottom ?? 10;
4204
+ const contentWidth = page.width - left - right;
4205
+ const widthSum = columns.reduce((sum, column) => sum + column.width, 0);
4206
+ const rowHeight = config?.rowHeight ?? 8;
4207
+ const footerY = page.height - bottom - 6;
4208
+ const tableY = 28;
4209
+ const tableHeight = footerY - tableY - 8;
4210
+ const rowsPerPage = Math.max(1, Math.floor((tableHeight - 9) / rowHeight));
4211
+ const pageCount = Math.max(1, Math.ceil(source.rows.length / rowsPerPage));
4212
+ const printedAt = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN");
4213
+ const pages = Array.from(
4214
+ { length: pageCount },
4215
+ (_, index) => ({
4216
+ ...page,
4217
+ id: index === 0 ? page.id : printDesign.createPrintDesignPage().id,
4218
+ name: `\u8868\u683C\u6253\u5370 ${index + 1}`,
4219
+ elements: [
4220
+ {
4221
+ id: `list-table-title-${index}`,
4222
+ type: "text",
4223
+ name: "\u6807\u9898",
4224
+ x: left,
4225
+ y: 12,
4226
+ width: contentWidth,
4227
+ height: 10,
4228
+ text: config?.title ?? "\u8868\u683C\u6253\u5370",
4229
+ fontSize: config?.titleFontSize ?? 18,
4230
+ fontWeight: "700",
4231
+ textAlign: "center"
4232
+ },
4233
+ {
4234
+ id: `list-table-data-${index}`,
4235
+ type: "table",
4236
+ name: "\u8868\u683C\u6570\u636E",
4237
+ x: left,
4238
+ y: tableY,
4239
+ width: contentWidth,
4240
+ height: tableHeight,
4241
+ dataMode: "binding",
4242
+ dataPath: `listTable.pages.${index}.rows`,
4243
+ dataSource: [],
4244
+ columns: columns.map((column) => ({
4245
+ key: column.key,
4246
+ title: column.title,
4247
+ dataIndex: column.key,
4248
+ width: widthSum > 0 ? Math.max(24, column.width / widthSum * 720) : 120,
4249
+ align: column.align
4250
+ })),
4251
+ rowHeight,
4252
+ headerRowHeight: 9,
4253
+ showHeader: true
4254
+ },
4255
+ {
4256
+ id: `list-table-print-time-${index}`,
4257
+ type: "text",
4258
+ name: "\u6253\u5370\u65F6\u95F4",
4259
+ x: left,
4260
+ y: footerY,
4261
+ width: contentWidth / 2,
4262
+ height: 6,
4263
+ text: `\u6253\u5370\u65F6\u95F4\uFF1A${printedAt}`,
4264
+ fontSize: 9,
4265
+ color: "#000000"
4266
+ },
4267
+ {
4268
+ id: `list-table-page-number-${index}`,
4269
+ type: "text",
4270
+ name: "\u5206\u9875\u4FE1\u606F",
4271
+ x: left + contentWidth / 2,
4272
+ y: footerY,
4273
+ width: contentWidth / 2,
4274
+ height: 6,
4275
+ text: `\u7B2C ${index + 1} \u9875 / \u5171 ${pageCount} \u9875`,
4276
+ textAlign: "right",
4277
+ fontSize: 9,
4278
+ color: "#000000"
4279
+ }
4280
+ ]
4281
+ })
4056
4282
  );
4057
- const selectedKeys = resolvePrintSelectedKeys(source.columns, config, cached);
4058
- return configurePrintTable(
4059
- source,
4060
- columns,
4061
- selectedKeys,
4062
- settings.rowsPerPage ?? 30,
4063
- {
4064
- includeSummary: settings.includeSummary ?? Boolean(
4065
- source.summaryRow || source.summaryColumns?.some(
4066
- (column) => column.summary.type !== "none"
4067
- )
4068
- ),
4069
- rowHeight: settings.rowHeight ?? 8,
4070
- title: settings.title ?? "\u8868\u683C\u6253\u5370",
4071
- subtitle: settings.subtitle ?? "",
4072
- titleFontSize: settings.titleFontSize ?? 18,
4073
- subtitleFontSize: settings.subtitleFontSize ?? 12,
4074
- summaryPosition: settings.summaryPosition ?? "last-page",
4075
- showPageNumbers: settings.showPageNumbers ?? false,
4076
- pageNumberPosition: settings.pageNumberPosition ?? "right",
4077
- showPrintTime: settings.showPrintTime ?? false,
4078
- printTimePosition: settings.printTimePosition ?? "left",
4079
- pageMargins: settings.pageMargins ?? {
4080
- top: 12,
4081
- right: 12,
4082
- bottom: 12,
4083
- left: 12
4084
- },
4085
- paperSize: settings.paperSize ?? "a4",
4086
- orientation: settings.orientation ?? "portrait",
4087
- useCellBorders: settings.useCellBorders ?? true,
4088
- borderColor: settings.borderColor ?? "#000000",
4089
- textColor: settings.textColor ?? "#000000",
4090
- headerBackgroundColor: settings.headerBackgroundColor ?? "#f2f5f8",
4091
- summaryBackgroundColor: settings.summaryBackgroundColor ?? "#f2f5f8"
4092
- }
4283
+ return printDesign.createPrintDesignDocument({
4284
+ name: preset?.name ?? "\u8868\u683C\u6253\u5370\u6A21\u677F",
4285
+ pages
4286
+ });
4287
+ }
4288
+ function mapPrintSourceRows(source) {
4289
+ return source.rows.map(
4290
+ (row) => Object.fromEntries(
4291
+ source.columns.map((column, index) => [column.key, row[index] ?? ""])
4292
+ )
4093
4293
  );
4094
4294
  }
4095
- async function configurePrintTable(source, columns, selectedKeys, rowsPerPage, settings = {}) {
4096
- const selected = new Set(selectedKeys);
4097
- const activeColumns = columns.filter((column) => selected.has(column.key));
4098
- const sourceIndexes = new Map(
4099
- source.columns.map((column, index) => [column.key, index])
4295
+ function mapPrintSourceRowsAsync(source, options) {
4296
+ return utils.mapInBatches(
4297
+ source.rows.length,
4298
+ (index) => Object.fromEntries(
4299
+ source.columns.map((column, columnIndex) => [
4300
+ column.key,
4301
+ source.rows[index][columnIndex] ?? ""
4302
+ ])
4303
+ ),
4304
+ options
4100
4305
  );
4101
- const summaries = Object.fromEntries(
4102
- activeColumns.map((column) => [
4103
- column.key,
4104
- {
4105
- type: column.summaryType ?? "none",
4106
- showTypePrefix: column.showTypePrefix === "yes",
4107
- precision: column.precision,
4108
- roundingMode: column.roundingMode ?? "round",
4109
- preserveTrailingZeros: column.preserveTrailingZeros === "yes"
4110
- }
4111
- ])
4306
+ }
4307
+ function getRowsPerPage(document2, rowCount) {
4308
+ const firstTable = document2.pages[0]?.elements.find(
4309
+ (item) => item.type === "table"
4112
4310
  );
4113
- const summaryRow = settings.includeSummary ? source.getSummaryRow ? await source.getSummaryRow({
4114
- columnKeys: activeColumns.map((column) => column.key),
4115
- sortState: [],
4116
- summaries,
4117
- includeSummary: true
4118
- }) : source.summaryRow ? activeColumns.map(
4119
- (column) => source.summaryRow?.[sourceIndexes.get(column.key) ?? -1] ?? ""
4120
- ) : void 0 : void 0;
4311
+ return firstTable?.type === "table" ? Math.max(
4312
+ 1,
4313
+ Math.floor(
4314
+ (firstTable.height - (firstTable.showHeader === false ? 0 : firstTable.headerRowHeight ?? 9)) / (firstTable.rowHeight ?? 8)
4315
+ )
4316
+ ) : Math.max(1, Math.ceil(rowCount / Math.max(1, document2.pages.length)));
4317
+ }
4318
+ function getPrintDesignSampleSize() {
4319
+ return getRowsPerPage(createTableDocument({ columns: [], rows: [] }), 0);
4320
+ }
4321
+ function createTableData(source, document2, rows = mapPrintSourceRows(source)) {
4322
+ const rowsPerPage = getRowsPerPage(document2, rows.length);
4121
4323
  return {
4122
- title: settings.title ?? "\u8868\u683C\u6253\u5370",
4123
- ...settings.subtitle ? { subtitle: settings.subtitle } : {},
4124
- titleFontSize: settings.titleFontSize ?? 18,
4125
- subtitleFontSize: settings.subtitleFontSize ?? 12,
4126
- columns: activeColumns.map(({ key, title, width, align, overflow }) => ({
4127
- key,
4128
- title,
4129
- width,
4130
- ...align ? { align } : {},
4131
- ...overflow ? { overflow } : {}
4132
- })),
4133
- rows: source.rows.map(
4134
- (row) => activeColumns.map(
4135
- (column) => row[sourceIndexes.get(column.key) ?? -1] ?? ""
4136
- )
4137
- ),
4138
- rowsPerPage,
4139
- rowHeight: settings.rowHeight ?? 8,
4140
- ...settings.includeSummary && summaryRow ? {
4141
- summaryRow: activeColumns.map(
4142
- (_column, index) => summaryRow[index] ?? ""
4143
- ),
4144
- summaryPosition: settings.summaryPosition ?? "last-page"
4145
- } : {},
4146
- showPageNumbers: settings.showPageNumbers ?? false,
4147
- pageNumberPosition: settings.pageNumberPosition ?? "right",
4148
- showPrintTime: settings.showPrintTime ?? false,
4149
- printTimePosition: settings.printTimePosition ?? "left",
4150
- pageMargins: settings.pageMargins ?? {
4151
- top: 12,
4152
- right: 12,
4153
- bottom: 12,
4154
- left: 12
4155
- },
4156
- paperSize: settings.paperSize ?? "a4",
4157
- orientation: settings.orientation ?? "portrait",
4158
- useCellBorders: settings.useCellBorders ?? true,
4159
- borderColor: settings.borderColor ?? "#000000",
4160
- textColor: settings.textColor ?? "#000000",
4161
- headerBackgroundColor: settings.headerBackgroundColor ?? "#f2f5f8",
4162
- summaryBackgroundColor: settings.summaryBackgroundColor ?? "#f2f5f8"
4324
+ listTable: {
4325
+ rows,
4326
+ columns: source.columns.map((column) => ({ key: column.key })),
4327
+ pages: document2.pages.map((_, index) => ({
4328
+ rows: rows.slice(index * rowsPerPage, (index + 1) * rowsPerPage)
4329
+ }))
4330
+ }
4163
4331
  };
4164
4332
  }
4165
- var summaryOptions2 = [
4166
- { value: "original", label: "\u539F\u6C47\u603B" },
4167
- { value: "none", label: "\u65E0\u6C47\u603B" },
4168
- { value: "title", label: "\u6807\u9898" },
4169
- { value: "sum", label: "\u6C42\u548C" },
4170
- { value: "avg", label: "\u5E73\u5747\u503C" },
4171
- { value: "count", label: "\u8BA1\u6570" },
4172
- { value: "unionCount", label: "\u53BB\u91CD\u8BA1\u6570" },
4173
- { value: "rowCount", label: "\u884C\u6570" },
4174
- { value: "mergedRowCount", label: "\u5408\u5E76\u884C\u6570" },
4175
- { value: "min", label: "\u6700\u5C0F\u503C" },
4176
- { value: "max", label: "\u6700\u5927\u503C" }
4177
- ];
4178
- var roundingOptions2 = [
4179
- { value: "round", label: "\u56DB\u820D\u4E94\u5165" },
4180
- { value: "floor", label: "\u5411\u4E0B\u53D6\u6574" },
4181
- { value: "ceil", label: "\u5411\u4E0A\u53D6\u6574" },
4182
- { value: "truncate", label: "\u622A\u65AD" }
4183
- ];
4184
- var booleanOptions2 = [
4185
- { value: "yes", label: "\u662F" },
4186
- { value: "no", label: "\u5426" }
4187
- ];
4188
- function ReactListTablePrintDialog(props) {
4189
- const tableId = react.useId();
4190
- const [cached] = react.useState(() => readPrintSettings(props.storageKey));
4191
- const initialPreset = cached?.presetName ? props.printPresets?.find((preset) => preset.name === cached.presetName) : cached ? void 0 : props.printPresets?.[0];
4192
- const initialConfig = initialPreset?.config;
4193
- const [columns, setColumns] = react.useState(
4194
- () => restorePrintColumns(
4195
- restorePrintColumns(
4196
- createPrintColumns(props.source.columns, props.source.summaryColumns),
4197
- initialConfig?.columns ? { columns: initialConfig.columns } : null
4198
- ),
4199
- cached
4200
- )
4201
- );
4202
- const [selectedKeys, setSelectedKeys] = react.useState(
4203
- () => resolvePrintSelectedKeys(props.source.columns, initialConfig, cached)
4204
- );
4205
- const [rowsPerPage, setRowsPerPage] = react.useState(
4206
- cached?.rowsPerPage ?? initialConfig?.rowsPerPage ?? 30
4207
- );
4208
- const [rowHeight, setRowHeight] = react.useState(
4209
- cached?.rowHeight ?? initialConfig?.rowHeight ?? 8
4210
- );
4211
- const [autoCalculateRows, setAutoCalculateRows] = react.useState(
4212
- cached?.autoCalculateRowsPerPage ?? initialConfig?.autoCalculateRowsPerPage ?? false
4213
- );
4214
- const [title, setTitle] = react.useState(
4215
- cached?.title ?? initialConfig?.title ?? "\u8868\u683C\u6253\u5370"
4216
- );
4217
- const [subtitle, setSubtitle] = react.useState(
4218
- cached?.subtitle ?? initialConfig?.subtitle ?? ""
4219
- );
4220
- const [titleFontSize, setTitleFontSize] = react.useState(
4221
- cached?.titleFontSize ?? initialConfig?.titleFontSize ?? 18
4222
- );
4223
- const [subtitleFontSize, setSubtitleFontSize] = react.useState(
4224
- cached?.subtitleFontSize ?? initialConfig?.subtitleFontSize ?? 12
4225
- );
4226
- const [includeSummary, setIncludeSummary] = react.useState(
4227
- () => cached?.includeSummary ?? initialConfig?.includeSummary ?? Boolean(
4228
- props.source.summaryRow || props.source.summaryColumns?.some(
4229
- (column) => column.summary.type !== "none"
4230
- )
4231
- )
4232
- );
4233
- const [summaryPosition, setSummaryPosition] = react.useState(cached?.summaryPosition ?? initialConfig?.summaryPosition ?? "last-page");
4234
- const [showPageNumbers, setShowPageNumbers] = react.useState(
4235
- cached?.showPageNumbers ?? initialConfig?.showPageNumbers ?? false
4236
- );
4237
- const [pageNumberPosition, setPageNumberPosition] = react.useState(cached?.pageNumberPosition ?? initialConfig?.pageNumberPosition ?? "right");
4238
- const [showPrintTime, setShowPrintTime] = react.useState(
4239
- cached?.showPrintTime ?? initialConfig?.showPrintTime ?? false
4333
+ async function createTableDataAsync(source, document2, rows, options) {
4334
+ const rowsPerPage = getRowsPerPage(document2, rows.length);
4335
+ const pages = await utils.mapInBatches(
4336
+ document2.pages.length,
4337
+ (index) => ({
4338
+ rows: rows.slice(index * rowsPerPage, (index + 1) * rowsPerPage)
4339
+ }),
4340
+ options
4240
4341
  );
4241
- const [printTimePosition, setPrintTimePosition] = react.useState(cached?.printTimePosition ?? initialConfig?.printTimePosition ?? "left");
4242
- const [pageMargins, setPageMargins] = react.useState(
4243
- cached?.pageMargins ?? initialConfig?.pageMargins ?? {
4244
- top: 12,
4245
- right: 12,
4246
- bottom: 12,
4247
- left: 12
4342
+ return {
4343
+ listTable: {
4344
+ rows,
4345
+ columns: source.columns.map((column) => ({ key: column.key })),
4346
+ pages
4248
4347
  }
4348
+ };
4349
+ }
4350
+ async function createTablePreviewSource(source, template, options, preparedRows) {
4351
+ const rows = preparedRows ?? await mapPrintSourceRowsAsync(source, options);
4352
+ const pageCount = Math.max(
4353
+ template.pages.length,
4354
+ Math.ceil(rows.length / getRowsPerPage(template, rows.length))
4249
4355
  );
4250
- const [paperSize, setPaperSize] = react.useState(cached?.paperSize ?? initialConfig?.paperSize ?? "a4");
4251
- const [orientation, setOrientation] = react.useState(
4252
- cached?.orientation ?? initialConfig?.orientation ?? "portrait"
4253
- );
4254
- const [useCellBorders, setUseCellBorders] = react.useState(
4255
- cached?.useCellBorders ?? initialConfig?.useCellBorders ?? true
4256
- );
4257
- const [borderColor, setBorderColor] = react.useState(
4258
- cached?.borderColor ?? initialConfig?.borderColor ?? "#000000"
4259
- );
4260
- const [textColor, setTextColor] = react.useState(
4261
- cached?.textColor ?? initialConfig?.textColor ?? "#000000"
4262
- );
4263
- const [headerBackgroundColor, setHeaderBackgroundColor] = react.useState(
4264
- cached?.headerBackgroundColor ?? initialConfig?.headerBackgroundColor ?? "#f2f5f8"
4265
- );
4266
- const [summaryBackgroundColor, setSummaryBackgroundColor] = react.useState(
4267
- cached?.summaryBackgroundColor ?? initialConfig?.summaryBackgroundColor ?? "#f2f5f8"
4268
- );
4269
- const [selectedPresetName, setSelectedPresetName] = react.useState(
4270
- initialPreset?.name ?? ""
4271
- );
4272
- const [showSectionDividers, setShowSectionDividers] = react.useState(
4273
- cached?.showSectionDividers ?? initialConfig?.showSectionDividers ?? true
4274
- );
4275
- const [sectionDividerTopSpacing, setSectionDividerTopSpacing] = react.useState(
4276
- cached?.sectionDividerTopSpacing ?? initialConfig?.sectionDividerTopSpacing ?? 4
4277
- );
4278
- const [sectionDividerBottomSpacing, setSectionDividerBottomSpacing] = react.useState(
4279
- cached?.sectionDividerBottomSpacing ?? initialConfig?.sectionDividerBottomSpacing ?? 4
4356
+ const pages = await utils.mapInBatches(
4357
+ pageCount,
4358
+ (index) => {
4359
+ const page = template.pages[index % template.pages.length];
4360
+ return {
4361
+ ...page,
4362
+ id: `${page.id}:print:${index}`,
4363
+ name: `\u8868\u683C\u6253\u5370 ${index + 1}`,
4364
+ elements: page.elements.map((element) => {
4365
+ const id = `${element.id}:print:${index}`;
4366
+ if (element.type === "table" && (element.dataPath === "listTable.rows" || /^listTable\.pages\.\d+\.rows$/.test(element.dataPath ?? ""))) {
4367
+ return {
4368
+ ...element,
4369
+ id,
4370
+ dataPath: `listTable.pages.${index}.rows`
4371
+ };
4372
+ }
4373
+ if (element.type === "text" && element.id.startsWith("list-table-page-number-")) {
4374
+ return {
4375
+ ...element,
4376
+ id,
4377
+ text: `\u7B2C ${index + 1} \u9875 / \u5171 ${pageCount} \u9875`
4378
+ };
4379
+ }
4380
+ return { ...element, id };
4381
+ })
4382
+ };
4383
+ },
4384
+ options
4280
4385
  );
4281
- const [formItemSpacing, setFormItemSpacing] = react.useState(
4282
- cached?.formItemSpacing ?? initialConfig?.formItemSpacing ?? 4
4386
+ const document2 = { ...template, pages };
4387
+ return {
4388
+ document: document2,
4389
+ data: await createTableDataAsync(source, document2, rows, options)
4390
+ };
4391
+ }
4392
+ function getPrintSourceFormat(source) {
4393
+ return JSON.stringify(
4394
+ source.columns.map((column) => String(column.key)).sort()
4283
4395
  );
4284
- const [cacheEnabled, setCacheEnabled] = react.useState(Boolean(props.storageKey));
4396
+ }
4397
+ function ReactListTablePrintDesignDialog(props) {
4398
+ const [fullscreen, setFullscreen] = react.useState(true);
4399
+ const [source, setSource] = react.useState(null);
4285
4400
  const [error, setError] = react.useState("");
4286
- const [previewHtml, setPreviewHtml] = react.useState("");
4287
- const [previewOpen, setPreviewOpen] = react.useState(false);
4288
- const [printFullscreen, setPrintFullscreen] = react.useState(false);
4289
- const [previewFullscreen, setPreviewFullscreen] = react.useState(false);
4290
- const [previewMode, setPreviewMode] = react.useState("render");
4291
- const [previewViewport, setPreviewViewport] = react.useState(() => ({
4292
- width: typeof window === "undefined" ? 1280 : window.innerWidth,
4293
- height: typeof window === "undefined" ? 900 : window.innerHeight
4294
- }));
4295
- const selectedColumnKeys = new Set(selectedKeys.map(String));
4296
- const layoutWarning = print.getBrowserPrintLayoutWarning({
4297
- columns: columns.filter((column) => selectedColumnKeys.has(column.key)),
4298
- pageMargins,
4299
- paperSize,
4300
- orientation
4301
- });
4302
- const rowLayoutWarning = print.getBrowserPrintRowLayoutWarning({
4303
- pageMargins,
4304
- paperSize,
4305
- orientation,
4306
- rowsPerPage,
4307
- rowHeight,
4308
- includeSummary,
4309
- summaryPosition,
4310
- showPageNumbers,
4311
- showPrintTime,
4312
- titleFontSize,
4313
- subtitleFontSize,
4314
- subtitle
4315
- });
4316
- const printLayoutWarning = [layoutWarning, rowLayoutWarning].filter(Boolean).join("\uFF1B");
4317
- const [paperWidth, paperHeight] = print.BROWSER_PRINT_PAPER_SIZES[paperSize];
4318
- const previewPaperWidth = orientation === "portrait" ? paperWidth : paperHeight;
4319
- const previewPaperHeight = orientation === "portrait" ? paperHeight : paperWidth;
4320
- const previewListHeight = Math.max(
4321
- 240,
4322
- previewFullscreen ? previewViewport.height - 168 : Math.min(previewViewport.height - 260, 900)
4401
+ const [attempt, setAttempt] = react.useState(0);
4402
+ const [emptyDocument] = react.useState(
4403
+ () => printDesign.createPrintDesignDocument({ name: "\u8868\u683C\u6253\u5370\u6A21\u677F" })
4323
4404
  );
4324
- const previewListWidth = Math.max(
4325
- 320,
4326
- (previewFullscreen ? previewViewport.width : Math.min(previewViewport.width * 0.96, 1280)) - 48
4327
- );
4328
- const pageWidthPixels = previewPaperWidth * 96 / 25.4;
4329
- const pageHeightPixels = previewPaperHeight * 96 / 25.4;
4330
- const previewScale = Math.min(
4331
- 1,
4332
- (previewListWidth - 24) / pageWidthPixels,
4333
- (previewListHeight - 24) / pageHeightPixels
4334
- );
4335
- const previewItemHeight = Math.ceil(pageHeightPixels * previewScale + 24);
4336
- const previewPages = react.useMemo(() => {
4337
- if (!previewHtml || typeof DOMParser === "undefined") return [];
4338
- const parsed = new DOMParser().parseFromString(previewHtml, "text/html");
4339
- const styles = Array.from(parsed.head.querySelectorAll("style")).map((style) => style.outerHTML).join("");
4340
- const pages = Array.from(parsed.body.children).filter(
4341
- (element) => element.classList.contains("page")
4342
- );
4343
- const pageStyles = `<style>html,body{box-sizing:border-box;width:${pageWidthPixels}px;height:${pageHeightPixels}px;max-width:none;max-height:none;margin:0;padding:0;overflow:hidden;background:#fff}body{display:block}.page{box-sizing:border-box;flex:0 0 auto;width:${previewPaperWidth}mm;max-width:none;height:${previewPaperHeight}mm;margin:0;overflow:hidden}</style>`;
4344
- return pages.map((page, index) => ({
4345
- index,
4346
- srcDoc: `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">${styles}${pageStyles}</head><body>${page.outerHTML}</body></html>`
4347
- }));
4348
- }, [
4349
- pageHeightPixels,
4350
- pageWidthPixels,
4351
- previewHtml,
4352
- previewPaperHeight,
4353
- previewPaperWidth
4354
- ]);
4355
4405
  react.useEffect(() => {
4356
- const updateViewport = () => {
4357
- setPreviewViewport({
4358
- width: window.innerWidth,
4359
- height: window.innerHeight
4406
+ const controller = new AbortController();
4407
+ setSource(null);
4408
+ setError("");
4409
+ const timer = setTimeout(() => {
4410
+ void Promise.resolve().then(
4411
+ () => props.loadSource({
4412
+ rowLimit: getPrintDesignSampleSize(),
4413
+ includeSummary: false,
4414
+ signal: controller.signal
4415
+ })
4416
+ ).then((value) => {
4417
+ if (!controller.signal.aborted) setSource(value);
4418
+ }).catch((cause) => {
4419
+ if (!controller.signal.aborted)
4420
+ setError(
4421
+ cause instanceof Error ? cause.message : "\u8BFB\u53D6\u6253\u5370\u6570\u636E\u5931\u8D25"
4422
+ );
4360
4423
  });
4424
+ }, 0);
4425
+ return () => {
4426
+ clearTimeout(timer);
4427
+ controller.abort();
4361
4428
  };
4362
- window.addEventListener("resize", updateViewport);
4363
- return () => window.removeEventListener("resize", updateViewport);
4364
- }, []);
4365
- const autoCalculateColumnWidths = () => {
4366
- const selectedColumns = selectPrintColumns(columns, selectedKeys);
4367
- const calculated = print.calculateBrowserPrintColumnWidths(selectedColumns, {
4368
- pageMargins,
4369
- paperSize,
4370
- orientation
4371
- });
4372
- if (!calculated) {
4373
- setError("\u5F53\u524D\u7EB8\u5F20\u53EF\u7528\u5BBD\u5EA6\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u6240\u9009\u5217\uFF08\u6BCF\u5217\u81F3\u5C11 10mm\uFF09");
4374
- return;
4375
- }
4376
- const widths = new Map(calculated.map(({ key, width }) => [key, width]));
4377
- setColumns(
4378
- (current) => current.map(
4379
- (column) => widths.has(column.key) ? { ...column, width: widths.get(column.key) } : column
4380
- )
4381
- );
4382
- setError("");
4383
- };
4384
- const autoCalculateRowsPerPage = () => {
4385
- const calculated = print.calculateBrowserPrintRowsPerPage({
4386
- pageMargins,
4387
- paperSize,
4388
- orientation,
4389
- rowHeight,
4390
- includeSummary,
4391
- summaryPosition,
4392
- showPageNumbers,
4393
- showPrintTime,
4394
- titleFontSize,
4395
- subtitleFontSize,
4396
- subtitle
4397
- });
4398
- if (!calculated) {
4399
- setError("\u5F53\u524D\u7EB8\u5F20\u53EF\u7528\u9AD8\u5EA6\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u4E00\u884C");
4400
- return;
4401
- }
4402
- setRowsPerPage(calculated);
4403
- setError("");
4404
- };
4405
- react.useEffect(() => {
4406
- if (autoCalculateRows) autoCalculateRowsPerPage();
4407
- }, [
4408
- autoCalculateRows,
4409
- rowHeight,
4410
- includeSummary,
4411
- summaryPosition,
4412
- showPageNumbers,
4413
- showPrintTime,
4414
- titleFontSize,
4415
- subtitleFontSize,
4416
- subtitle,
4417
- paperSize,
4418
- orientation,
4419
- pageMargins
4420
- ]);
4421
- react.useEffect(() => {
4422
- if (showPageNumbers && showPrintTime && pageNumberPosition === printTimePosition) {
4423
- setPrintTimePosition(pageNumberPosition === "left" ? "center" : "left");
4429
+ }, [props.loadSource, attempt]);
4430
+ return /* @__PURE__ */ jsxRuntime.jsx(
4431
+ reactComponents.ReactModal,
4432
+ {
4433
+ open: true,
4434
+ fullscreen,
4435
+ closable: false,
4436
+ fullscreenable: false,
4437
+ footer: false,
4438
+ width: "min(96vw, 1440px)",
4439
+ style: { height: fullscreen ? "100%" : "min(88vh, 900px)" },
4440
+ bodyStyle: {
4441
+ padding: 0,
4442
+ overflow: "hidden",
4443
+ display: "flex",
4444
+ position: "relative"
4445
+ },
4446
+ onCancel: props.onClose,
4447
+ children: source ? /* @__PURE__ */ jsxRuntime.jsx(
4448
+ LoadedPrintDesigner,
4449
+ {
4450
+ ...props,
4451
+ source,
4452
+ fullscreen,
4453
+ onFullscreenChange: setFullscreen
4454
+ }
4455
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4456
+ /* @__PURE__ */ jsxRuntime.jsx(
4457
+ reactPrintDesign.ReactPrintDesign,
4458
+ {
4459
+ document: emptyDocument,
4460
+ fullscreen,
4461
+ onClose: props.onClose,
4462
+ style: { flex: 1 }
4463
+ }
4464
+ ),
4465
+ /* @__PURE__ */ jsxRuntime.jsxs(
4466
+ "div",
4467
+ {
4468
+ role: "status",
4469
+ style: {
4470
+ position: "absolute",
4471
+ inset: 0,
4472
+ background: "rgba(255,255,255,0.85)",
4473
+ display: "flex",
4474
+ alignItems: "center",
4475
+ justifyContent: "center",
4476
+ gap: 12
4477
+ },
4478
+ children: [
4479
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: error || "\u6B63\u5728\u8BFB\u53D6\u7B2C\u4E00\u9875\u6570\u636E\u2026" }),
4480
+ error ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { onClick: () => setAttempt((value) => value + 1), children: "\u91CD\u8BD5" }) : null,
4481
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { onClick: props.onClose, children: "\u5173\u95ED" })
4482
+ ]
4483
+ }
4484
+ )
4485
+ ] })
4424
4486
  }
4425
- }, [showPageNumbers, showPrintTime, pageNumberPosition, printTimePosition]);
4426
- const createCurrentPrintOptions = () => configurePrintTable(
4427
- props.source,
4428
- columns,
4429
- selectedKeys.map(String),
4430
- rowsPerPage,
4487
+ );
4488
+ }
4489
+ function LoadedPrintDesigner(props) {
4490
+ const document2 = react.useMemo(
4491
+ () => createTableDocument({ ...props.source, rows: [] }),
4492
+ [props.source]
4493
+ );
4494
+ const [boundDocument, setBoundDocument] = react.useState(document2);
4495
+ const rows = react.useMemo(() => mapPrintSourceRows(props.source), [props.source]);
4496
+ const defaultTemplates = react.useMemo(
4497
+ () => [
4498
+ document2,
4499
+ ...props.printPresets?.map(
4500
+ (preset) => createTableDocument({ ...props.source, rows: [] }, preset)
4501
+ ) ?? [],
4502
+ ...props.printTemplates ?? []
4503
+ ],
4504
+ [document2, props.printPresets, props.printTemplates, props.source]
4505
+ );
4506
+ const data = react.useMemo(
4507
+ () => createTableData(props.source, boundDocument, rows),
4508
+ [props.source, boundDocument, rows]
4509
+ );
4510
+ const loadPreviewData = react.useCallback(
4511
+ async (template, options) => {
4512
+ const source = await props.loadSource(options);
4513
+ options.signal?.throwIfAborted();
4514
+ return createTablePreviewSource(source, template, options);
4515
+ },
4516
+ [props.loadSource]
4517
+ );
4518
+ return /* @__PURE__ */ jsxRuntime.jsx(
4519
+ reactPrintDesign.ReactPrintDesign,
4431
4520
  {
4432
- includeSummary,
4433
- rowHeight,
4434
- title,
4435
- subtitle,
4436
- titleFontSize,
4437
- subtitleFontSize,
4438
- summaryPosition,
4439
- showPageNumbers,
4440
- pageNumberPosition,
4441
- showPrintTime,
4442
- printTimePosition,
4443
- pageMargins,
4444
- paperSize,
4445
- orientation,
4446
- useCellBorders,
4447
- borderColor,
4448
- textColor,
4449
- headerBackgroundColor,
4450
- summaryBackgroundColor
4521
+ document: document2,
4522
+ defaultTemplates,
4523
+ data,
4524
+ dataFormatKey: getPrintSourceFormat(props.source),
4525
+ onChange: setBoundDocument,
4526
+ storeKey: props.storeKey,
4527
+ loadPreviewData,
4528
+ fullscreen: props.fullscreen,
4529
+ onFullscreenChange: props.onFullscreenChange,
4530
+ onClose: props.onClose,
4531
+ style: { flex: 1 }
4451
4532
  }
4452
4533
  );
4453
- const applyPrintPreset = (name) => {
4454
- setSelectedPresetName(name);
4455
- setError("");
4456
- if (!name) {
4457
- const defaultColumns = createPrintColumns(
4458
- props.source.columns,
4459
- props.source.summaryColumns
4460
- );
4461
- setColumns(defaultColumns);
4462
- setSelectedKeys(
4463
- resolvePrintSelectedKeys(props.source.columns, void 0, null)
4464
- );
4465
- setRowsPerPage(30);
4466
- setRowHeight(8);
4467
- setAutoCalculateRows(false);
4468
- setTitle("\u8868\u683C\u6253\u5370");
4469
- setSubtitle("");
4470
- setTitleFontSize(18);
4471
- setSubtitleFontSize(12);
4472
- setIncludeSummary(
4473
- Boolean(
4474
- props.source.summaryRow || props.source.summaryColumns?.some(
4475
- (column) => column.summary.type !== "none"
4476
- )
4477
- )
4478
- );
4479
- setSummaryPosition("last-page");
4480
- setShowPageNumbers(false);
4481
- setPageNumberPosition("right");
4482
- setShowPrintTime(false);
4483
- setPrintTimePosition("left");
4484
- setPageMargins({ top: 12, right: 12, bottom: 12, left: 12 });
4485
- setPaperSize("a4");
4486
- setOrientation("portrait");
4487
- setUseCellBorders(true);
4488
- setBorderColor("#000000");
4489
- setTextColor("#000000");
4490
- setHeaderBackgroundColor("#f2f5f8");
4491
- setSummaryBackgroundColor("#f2f5f8");
4492
- setShowSectionDividers(true);
4493
- setSectionDividerTopSpacing(4);
4494
- setSectionDividerBottomSpacing(4);
4495
- setFormItemSpacing(4);
4496
- return;
4497
- }
4498
- const preset = props.printPresets?.find((item) => item.name === name);
4499
- if (!preset) return;
4500
- const config = preset.config;
4501
- const baseColumns = createPrintColumns(
4502
- props.source.columns,
4503
- props.source.summaryColumns
4504
- );
4505
- setColumns(
4506
- restorePrintColumns(
4507
- baseColumns,
4508
- config.columns ? { columns: config.columns } : null
4509
- )
4510
- );
4511
- setSelectedKeys(
4512
- resolvePrintSelectedKeys(props.source.columns, config, null)
4513
- );
4514
- setRowsPerPage(config.rowsPerPage ?? 30);
4515
- setRowHeight(config.rowHeight ?? 8);
4516
- setAutoCalculateRows(config.autoCalculateRowsPerPage ?? false);
4517
- setTitle(config.title ?? "\u8868\u683C\u6253\u5370");
4518
- setSubtitle(config.subtitle ?? "");
4519
- setTitleFontSize(config.titleFontSize ?? 18);
4520
- setSubtitleFontSize(config.subtitleFontSize ?? 12);
4521
- setIncludeSummary(
4522
- config.includeSummary ?? Boolean(
4523
- props.source.summaryRow || props.source.summaryColumns?.some(
4524
- (column) => column.summary.type !== "none"
4534
+ }
4535
+ var PRINT_PROGRESS_MIN_DURATION = 500;
4536
+ function createPrintProgress(container, onCancel) {
4537
+ const host = container.ownerDocument.createElement("div");
4538
+ host.dataset.listTablePrintProgress = "";
4539
+ container.append(host);
4540
+ const root = client.createRoot(host);
4541
+ const startedAt = performance.now();
4542
+ let disposed = false;
4543
+ let open = true;
4544
+ let message = "\u6B63\u5728\u8BFB\u53D6\u6253\u5370\u6570\u636E";
4545
+ let percent = 0;
4546
+ let failed = false;
4547
+ let closeTimer;
4548
+ let resolveClose;
4549
+ let configuring = false;
4550
+ let batchSize = 50;
4551
+ let action;
4552
+ const confirm = () => {
4553
+ const pending = action;
4554
+ action = void 0;
4555
+ configuring = false;
4556
+ render();
4557
+ pending?.resolve();
4558
+ };
4559
+ const dispose = () => {
4560
+ if (disposed) return;
4561
+ disposed = true;
4562
+ clearTimeout(closeTimer);
4563
+ root.unmount();
4564
+ host.remove();
4565
+ resolveClose?.();
4566
+ action?.resolve();
4567
+ action = void 0;
4568
+ };
4569
+ const render = () => {
4570
+ if (disposed) return;
4571
+ reactDom.flushSync(
4572
+ () => root.render(
4573
+ /* @__PURE__ */ jsxRuntime.jsxs(
4574
+ reactComponents.ReactModal,
4575
+ {
4576
+ open,
4577
+ title: configuring ? "\u76F4\u63A5\u6253\u5370\u8BBE\u7F6E" : failed ? "\u6253\u5370\u5931\u8D25" : "\u6B63\u5728\u51C6\u5907\u6253\u5370",
4578
+ width: 440,
4579
+ centered: true,
4580
+ maskClosable: false,
4581
+ fullscreenable: false,
4582
+ getContainer: container,
4583
+ onCancel,
4584
+ afterClose: () => queueMicrotask(dispose),
4585
+ footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4586
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { onClick: onCancel, children: failed ? "\u5173\u95ED" : "\u53D6\u6D88\u6253\u5370" }),
4587
+ action && /* @__PURE__ */ jsxRuntime.jsx(
4588
+ reactComponents.ReactButton,
4589
+ {
4590
+ disabled: configuring && (!batchSize || !Number.isInteger(batchSize) || batchSize < 1),
4591
+ onClick: confirm,
4592
+ children: action.label
4593
+ }
4594
+ )
4595
+ ] }),
4596
+ children: [
4597
+ /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", "aria-live": "polite", children: message }),
4598
+ configuring ? /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
4599
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { whiteSpace: "nowrap", flexShrink: 0 }, children: "\u6BCF\u6B21\u6253\u5370\u9875\u6570" }),
4600
+ /* @__PURE__ */ jsxRuntime.jsx(
4601
+ reactComponents.ReactInputNumber,
4602
+ {
4603
+ "aria-label": "\u6BCF\u6B21\u6253\u5370\u9875\u6570",
4604
+ style: { flex: 1, minWidth: 0 },
4605
+ min: 1,
4606
+ precision: 0,
4607
+ value: batchSize,
4608
+ onChange: (value) => {
4609
+ batchSize = value;
4610
+ render();
4611
+ }
4612
+ }
4613
+ )
4614
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
4615
+ reactComponents.ReactProgress,
4616
+ {
4617
+ percent,
4618
+ label: "\u6253\u5370\u51C6\u5907\u8FDB\u5EA6",
4619
+ status: failed ? "exception" : "normal"
4620
+ }
4621
+ )
4622
+ ]
4623
+ }
4525
4624
  )
4526
4625
  )
4527
4626
  );
4528
- setSummaryPosition(config.summaryPosition ?? "last-page");
4529
- setShowPageNumbers(config.showPageNumbers ?? false);
4530
- setPageNumberPosition(config.pageNumberPosition ?? "right");
4531
- setShowPrintTime(config.showPrintTime ?? false);
4532
- setPrintTimePosition(config.printTimePosition ?? "left");
4533
- setPageMargins(
4534
- config.pageMargins ?? { top: 12, right: 12, bottom: 12, left: 12 }
4535
- );
4536
- setPaperSize(config.paperSize ?? "a4");
4537
- setOrientation(config.orientation ?? "portrait");
4538
- setUseCellBorders(config.useCellBorders ?? true);
4539
- setBorderColor(config.borderColor ?? "#000000");
4540
- setTextColor(config.textColor ?? "#000000");
4541
- setHeaderBackgroundColor(config.headerBackgroundColor ?? "#f2f5f8");
4542
- setSummaryBackgroundColor(config.summaryBackgroundColor ?? "#f2f5f8");
4543
- setShowSectionDividers(config.showSectionDividers ?? true);
4544
- setSectionDividerTopSpacing(config.sectionDividerTopSpacing ?? 4);
4545
- setSectionDividerBottomSpacing(config.sectionDividerBottomSpacing ?? 4);
4546
- setFormItemSpacing(config.formItemSpacing ?? 4);
4547
4627
  };
4548
- const previewPrintHtml = async () => {
4549
- if (!selectedKeys.length) {
4550
- setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
4551
- return;
4552
- }
4553
- if (!Number.isInteger(rowsPerPage) || rowsPerPage < 1) {
4554
- setError("\u6BCF\u9875\u884C\u6570\u5FC5\u987B\u662F\u6B63\u6574\u6570");
4555
- return;
4556
- }
4557
- if (!Number.isFinite(rowHeight) || rowHeight <= 0) {
4558
- setError("\u884C\u9AD8\u5FC5\u987B\u662F\u6B63\u6570");
4559
- return;
4560
- }
4561
- try {
4562
- const options = await createCurrentPrintOptions();
4563
- setPreviewHtml(print.createBrowserPrintPreviewHtml(options));
4564
- setPreviewMode("render");
4565
- setPreviewOpen(true);
4566
- setError("");
4567
- } catch (cause) {
4568
- setError(cause instanceof Error ? cause.message : "\u751F\u6210\u6253\u5370\u9884\u89C8\u5931\u8D25");
4569
- }
4570
- };
4571
- const confirm = async () => {
4572
- const selected = selectedKeys.map(String);
4573
- if (!selected.length) return setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
4574
- if (!Number.isInteger(rowsPerPage) || rowsPerPage < 1)
4575
- return setError("\u6BCF\u9875\u884C\u6570\u5FC5\u987B\u662F\u6B63\u6574\u6570");
4576
- if (!Number.isFinite(rowHeight) || rowHeight <= 0)
4577
- return setError("\u884C\u9AD8\u5FC5\u987B\u662F\u6B63\u6570");
4578
- if (Object.values(pageMargins).some(
4579
- (margin) => !Number.isFinite(margin) || margin < 0
4580
- )) {
4581
- return setError("\u6253\u5370\u8FB9\u8DDD\u5FC5\u987B\u662F\u975E\u8D1F\u6570");
4582
- }
4583
- if (columns.some(
4584
- (column) => !Number.isFinite(column.width) || column.width < 10
4585
- )) {
4586
- return setError("\u5217\u5BBD\u4E0D\u80FD\u5C0F\u4E8E 10 \u6BEB\u7C73");
4587
- }
4588
- const options = await createCurrentPrintOptions();
4589
- if (!print.printBrowserTable(options))
4590
- return setError("\u6D4F\u89C8\u5668\u963B\u6B62\u4E86\u6253\u5370\u7A97\u53E3\uFF0C\u8BF7\u5141\u8BB8\u6B64\u9875\u9762\u6253\u5F00\u5F39\u7A97");
4591
- if (cacheEnabled) {
4592
- writePrintSettings(props.storageKey, {
4593
- version: 2,
4594
- columns,
4595
- selectedKeys: selected,
4596
- rowsPerPage,
4597
- presetName: selectedPresetName || void 0,
4598
- rowHeight,
4599
- autoCalculateRowsPerPage: autoCalculateRows,
4600
- title,
4601
- subtitle,
4602
- titleFontSize,
4603
- subtitleFontSize,
4604
- includeSummary,
4605
- summaryPosition,
4606
- showPageNumbers,
4607
- pageNumberPosition,
4608
- showPrintTime,
4609
- printTimePosition,
4610
- pageMargins,
4611
- paperSize,
4612
- orientation,
4613
- useCellBorders,
4614
- borderColor,
4615
- textColor,
4616
- headerBackgroundColor,
4617
- summaryBackgroundColor,
4618
- showSectionDividers,
4619
- sectionDividerTopSpacing,
4620
- sectionDividerBottomSpacing,
4621
- formItemSpacing
4628
+ render();
4629
+ return {
4630
+ host,
4631
+ async configure(defaultPages) {
4632
+ configuring = true;
4633
+ batchSize = Number.isFinite(defaultPages) ? Math.max(1, Math.floor(defaultPages)) : 50;
4634
+ message = "\u6309\u6279\u6B21\u751F\u6210\u6253\u5370\u9875\u9762\uFF0C\u907F\u514D\u4E00\u6B21\u52A0\u8F7D\u8FC7\u591A\u5185\u5BB9\u3002";
4635
+ await new Promise((resolve) => {
4636
+ action = { label: "\u5F00\u59CB\u6253\u5370", resolve };
4637
+ render();
4622
4638
  });
4623
- }
4624
- props.onClose();
4625
- };
4626
- const tableColumns = [
4627
- listTable.ROW_SELECTION_COLUMN,
4628
- { key: "title", dataIndex: "title", title: "\u6253\u5370\u5217", width: 260 },
4629
- {
4630
- key: "width",
4631
- dataIndex: "width",
4632
- title: "\u5217\u5BBD\uFF08mm\uFF09",
4633
- width: 110,
4634
- editable: true,
4635
- formItemProps: { valueType: "number", clickCount: 1, min: 10 }
4639
+ return batchSize ?? 50;
4636
4640
  },
4637
- {
4638
- key: "align",
4639
- dataIndex: "align",
4640
- title: "\u5BF9\u9F50\u65B9\u5F0F",
4641
- width: 100,
4642
- editable: true,
4643
- formItemProps: {
4644
- valueType: "select",
4645
- clickCount: 1,
4646
- options: [
4647
- { value: "left", label: "\u5DE6\u5BF9\u9F50" },
4648
- { value: "center", label: "\u5C45\u4E2D" },
4649
- { value: "right", label: "\u53F3\u5BF9\u9F50" }
4650
- ]
4651
- },
4652
- render: (value) => value === "center" ? "\u5C45\u4E2D" : value === "right" ? "\u53F3\u5BF9\u9F50" : "\u5DE6\u5BF9\u9F50"
4641
+ async continueBatch(firstPage, lastPage) {
4642
+ message = `\u7B2C ${firstPage}\u2013${lastPage} \u9875\u7684\u6253\u5370\u7A97\u53E3\u5DF2\u5173\u95ED\uFF0C\u662F\u5426\u7EE7\u7EED\u4E0B\u4E00\u6279\uFF1F`;
4643
+ await new Promise((resolve) => {
4644
+ action = { label: "\u7EE7\u7EED\u4E0B\u4E00\u6279", resolve };
4645
+ render();
4646
+ });
4653
4647
  },
4654
- {
4655
- key: "overflow",
4656
- dataIndex: "overflow",
4657
- title: "\u8D85\u5BBD\u5904\u7406",
4658
- width: 105,
4659
- editable: true,
4660
- formItemProps: {
4661
- valueType: "select",
4662
- clickCount: 1,
4663
- options: [
4664
- { value: "ellipsis", label: "\u7701\u7565\u53F7" },
4665
- { value: "clip", label: "\u88C1\u5207" },
4666
- { value: "wrap", label: "\u6362\u884C" }
4667
- ]
4668
- },
4669
- render: (value) => value === "ellipsis" ? "\u7701\u7565\u53F7" : value === "clip" ? "\u88C1\u5207" : "\u6362\u884C"
4648
+ update(text, value) {
4649
+ if (percent === value && message === text) return;
4650
+ message = text;
4651
+ percent = value;
4652
+ render();
4670
4653
  },
4671
- ...includeSummary ? [
4672
- {
4673
- key: "summary-group",
4674
- dataIndex: "summaryType",
4675
- title: "\u6C47\u603B",
4676
- children: [
4677
- {
4678
- key: "summaryType",
4679
- dataIndex: "summaryType",
4680
- title: "\u6C47\u603B\u65B9\u5F0F",
4681
- width: 110,
4682
- editable: true,
4683
- formItemProps: {
4684
- valueType: "select",
4685
- clickCount: 1,
4686
- options: summaryOptions2.filter(
4687
- (option) => option.value !== "original" || props.source.summaryColumns?.some(
4688
- (column) => column.summary.type === "original"
4689
- )
4690
- )
4691
- },
4692
- render: (value) => summaryOptions2.find((option) => option.value === value)?.label ?? "\u65E0\u6C47\u603B"
4693
- },
4694
- {
4695
- key: "showTypePrefix",
4696
- dataIndex: "showTypePrefix",
4697
- title: "\u6C47\u603B\u524D\u7F00",
4698
- width: 90,
4699
- editable: true,
4700
- formItemProps: {
4701
- valueType: "select",
4702
- clickCount: 1,
4703
- options: booleanOptions2
4704
- },
4705
- render: (value) => value === "yes" ? "\u662F" : "\u5426"
4706
- },
4707
- {
4708
- key: "precision",
4709
- dataIndex: "precision",
4710
- title: "\u5C0F\u6570\u4F4D\u6570",
4711
- width: 90,
4712
- editable: true,
4713
- formItemProps: {
4714
- valueType: "number",
4715
- clickCount: 1,
4716
- min: 0,
4717
- max: 20
4718
- }
4719
- },
4720
- {
4721
- key: "roundingMode",
4722
- dataIndex: "roundingMode",
4723
- title: "\u53D6\u6574\u65B9\u5F0F",
4724
- width: 100,
4725
- editable: true,
4726
- formItemProps: {
4727
- valueType: "select",
4728
- clickCount: 1,
4729
- options: roundingOptions2
4730
- },
4731
- render: (value) => roundingOptions2.find((option) => option.value === value)?.label ?? "\u56DB\u820D\u4E94\u5165"
4732
- },
4733
- {
4734
- key: "preserveTrailingZeros",
4735
- dataIndex: "preserveTrailingZeros",
4736
- title: "\u4FDD\u7559\u65E0\u6548\u96F6",
4737
- width: 100,
4738
- editable: true,
4739
- formItemProps: {
4740
- valueType: "select",
4741
- clickCount: 1,
4742
- options: booleanOptions2
4743
- },
4744
- render: (value) => value === "yes" ? "\u662F" : "\u5426"
4745
- }
4746
- ]
4747
- }
4748
- ] : []
4749
- ];
4750
- const sectionDivider = showSectionDividers ? /* @__PURE__ */ jsxRuntime.jsx(
4751
- "div",
4752
- {
4753
- "aria-hidden": "true",
4754
- style: {
4755
- height: 1,
4756
- marginTop: sectionDividerTopSpacing,
4757
- marginBottom: sectionDividerBottomSpacing,
4758
- background: "#e2e8f0"
4654
+ error(text) {
4655
+ message = text;
4656
+ failed = true;
4657
+ render();
4658
+ },
4659
+ close(immediate = false) {
4660
+ if (disposed) return Promise.resolve();
4661
+ if (immediate) {
4662
+ dispose();
4663
+ return Promise.resolve();
4759
4664
  }
4760
- }
4761
- ) : null;
4762
- return /* @__PURE__ */ jsxRuntime.jsxs(
4763
- reactComponents.ReactModal,
4764
- {
4765
- open: true,
4766
- title: /* @__PURE__ */ jsxRuntime.jsxs(
4767
- "span",
4768
- {
4769
- style: {
4770
- display: "flex",
4771
- alignItems: "baseline",
4772
- gap: 12,
4773
- minWidth: 0
4774
- },
4775
- children: [
4776
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u6253\u5370\u8868\u683C\u914D\u7F6E" }),
4777
- printLayoutWarning ? /* @__PURE__ */ jsxRuntime.jsxs(
4778
- "span",
4779
- {
4780
- role: "status",
4781
- title: `${printLayoutWarning}\uFF0C\u4ECD\u53EF\u7EE7\u7EED\u6253\u5370\uFF1B\u6253\u5370\u7ED3\u679C\u53EF\u80FD\u88AB\u88C1\u5207\u6216\u5206\u9875\u5F02\u5E38\u3002`,
4782
- style: {
4783
- color: "#b45309",
4784
- fontSize: 12,
4785
- fontWeight: 400,
4786
- whiteSpace: "nowrap",
4787
- overflow: "hidden",
4788
- textOverflow: "ellipsis",
4789
- minWidth: 0
4790
- },
4791
- children: [
4792
- printLayoutWarning,
4793
- "\uFF0C\u4ECD\u53EF\u7EE7\u7EED\u6253\u5370"
4794
- ]
4795
- }
4796
- ) : null
4797
- ]
4798
- }
4799
- ),
4800
- width: "min(98vw, 1680px)",
4801
- fullscreenable: true,
4802
- fullscreen: printFullscreen,
4803
- onFullscreenChange: setPrintFullscreen,
4804
- bodyStyle: { display: "flex", minHeight: 0 },
4805
- okText: "\u6253\u5370",
4806
- cancelText: "\u53D6\u6D88",
4807
- onCancel: props.onClose,
4808
- footer: /* @__PURE__ */ jsxRuntime.jsxs(
4809
- "div",
4810
- {
4811
- style: {
4812
- display: "flex",
4813
- justifyContent: "flex-end",
4814
- alignItems: "center",
4815
- gap: 8,
4816
- width: "100%"
4665
+ return new Promise((resolve) => {
4666
+ resolveClose = resolve;
4667
+ closeTimer = setTimeout(
4668
+ () => {
4669
+ open = false;
4670
+ render();
4817
4671
  },
4818
- children: [
4819
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { type: "default", onClick: props.onClose, children: "\u53D6\u6D88" }),
4820
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { type: "default", onClick: previewPrintHtml, children: "\u6253\u5370\u9884\u89C8" }),
4821
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { type: "primary", onClick: confirm, children: "\u6253\u5370" })
4822
- ]
4672
+ Math.max(
4673
+ 0,
4674
+ PRINT_PROGRESS_MIN_DURATION - (performance.now() - startedAt)
4675
+ )
4676
+ );
4677
+ });
4678
+ }
4679
+ };
4680
+ }
4681
+ var PRINT_ROWS_WORKER_SOURCE = `
4682
+ self.onmessage = function(event) {
4683
+ try {
4684
+ const { keys, rows } = event.data;
4685
+ self.postMessage({ rows: rows.map(row => Object.fromEntries(keys.map((key, index) => [key, row[index] ?? ""]))) });
4686
+ } catch (error) {
4687
+ self.postMessage({ error: String(error) });
4688
+ }
4689
+ };`;
4690
+ async function preparePrintRows(source, options = {}) {
4691
+ const keys = source.columns.map((column) => column.key);
4692
+ let worker;
4693
+ let url;
4694
+ try {
4695
+ options.signal?.throwIfAborted();
4696
+ url = URL.createObjectURL(
4697
+ new Blob([PRINT_ROWS_WORKER_SOURCE], { type: "text/javascript" })
4698
+ );
4699
+ worker = new Worker(url);
4700
+ const result = new Array(source.rows.length);
4701
+ for (let offset = 0; offset < source.rows.length; offset += 2e3) {
4702
+ options.signal?.throwIfAborted();
4703
+ const rows = await new Promise(
4704
+ (resolve, reject) => {
4705
+ const cleanup = () => {
4706
+ clearTimeout(timeout);
4707
+ options.signal?.removeEventListener("abort", abort);
4708
+ };
4709
+ const fail = (error) => {
4710
+ cleanup();
4711
+ reject(error);
4712
+ };
4713
+ const abort = () => fail(options.signal?.reason);
4714
+ const timeout = setTimeout(
4715
+ () => fail(new Error("\u6253\u5370 Worker \u54CD\u5E94\u8D85\u65F6")),
4716
+ 15e3
4717
+ );
4718
+ options.signal?.addEventListener("abort", abort, { once: true });
4719
+ worker.onerror = () => fail(new Error("\u6253\u5370 Worker \u6267\u884C\u5931\u8D25"));
4720
+ worker.onmessageerror = () => fail(new Error("\u6253\u5370 Worker \u6570\u636E\u4F20\u8F93\u5931\u8D25"));
4721
+ worker.onmessage = (event) => {
4722
+ cleanup();
4723
+ if (event.data.error) reject(new Error(event.data.error));
4724
+ else resolve(event.data.rows);
4725
+ };
4726
+ try {
4727
+ worker.postMessage({
4728
+ keys,
4729
+ rows: source.rows.slice(offset, offset + 2e3)
4730
+ });
4731
+ } catch (error) {
4732
+ fail(error);
4733
+ }
4823
4734
  }
4735
+ );
4736
+ for (let index = 0; index < rows.length; index++)
4737
+ result[offset + index] = rows[index];
4738
+ options.onProgress?.(
4739
+ Math.min(offset + rows.length, source.rows.length),
4740
+ source.rows.length
4741
+ );
4742
+ }
4743
+ return result;
4744
+ } catch {
4745
+ worker?.terminate();
4746
+ worker = void 0;
4747
+ options.signal?.throwIfAborted();
4748
+ return await utils.mapInBatches(
4749
+ source.rows.length,
4750
+ (index) => Object.fromEntries(
4751
+ keys.map((key, column) => [key, source.rows[index][column] ?? ""])
4824
4752
  ),
4825
- children: [
4826
- /* @__PURE__ */ jsxRuntime.jsx(
4827
- "div",
4828
- {
4829
- style: {
4830
- display: "flex",
4831
- flex: "1 1 auto",
4832
- minHeight: 0,
4833
- flexDirection: "column"
4834
- },
4835
- children: /* @__PURE__ */ jsxRuntime.jsxs(
4836
- "div",
4837
- {
4838
- style: {
4839
- display: "grid",
4840
- flex: "1 1 auto",
4841
- minHeight: 0,
4842
- gridTemplateColumns: "minmax(340px, 380px) minmax(0, 1fr)",
4843
- gap: 20,
4844
- alignItems: "stretch"
4845
- },
4846
- children: [
4847
- /* @__PURE__ */ jsxRuntime.jsx(
4848
- "div",
4849
- {
4850
- style: {
4851
- display: "grid",
4852
- gap: 0,
4853
- padding: "4px 4px 0 0",
4854
- minHeight: 0,
4855
- overflowY: "auto"
4856
- },
4857
- children: /* @__PURE__ */ jsxRuntime.jsxs(
4858
- reactComponents.ReactForm,
4859
- {
4860
- layout: "horizontal",
4861
- noWrap: true,
4862
- itemSpacing: `${formItemSpacing}px`,
4863
- labelWidth: 88,
4864
- labelAlign: "left",
4865
- style: { display: "contents" },
4866
- children: [
4867
- props.printPresets?.length ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6253\u5370\u914D\u7F6E", children: /* @__PURE__ */ jsxRuntime.jsx(
4868
- reactComponents.ReactSelect,
4869
- {
4870
- value: selectedPresetName,
4871
- "aria-label": "\u6253\u5370\u914D\u7F6E\u9884\u8BBE",
4872
- options: [
4873
- { value: "", label: "\u9ED8\u8BA4\u914D\u7F6E" },
4874
- ...props.printPresets.map((preset) => ({
4875
- value: preset.name,
4876
- label: preset.name
4877
- }))
4878
- ],
4879
- onChange: (value) => applyPrintPreset(String(value ?? "")),
4880
- style: { width: "100%" }
4881
- }
4882
- ) }) : null,
4883
- props.storageKey ? /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7F13\u5B58\u5230\u672C\u5730", children: /* @__PURE__ */ jsxRuntime.jsx(
4884
- reactComponents.ReactCheckbox,
4885
- {
4886
- checked: cacheEnabled,
4887
- "aria-label": "\u7F13\u5B58\u6253\u5370\u914D\u7F6E\u5230\u672C\u5730",
4888
- onChange: (event) => {
4889
- setCacheEnabled(event.target.checked);
4890
- if (!event.target.checked)
4891
- writePrintSettings(props.storageKey, null);
4892
- }
4893
- }
4894
- ) }) : null,
4895
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u5206\u9694\u7EBF\u5360\u4F4D", children: /* @__PURE__ */ jsxRuntime.jsx(
4896
- reactComponents.ReactCheckbox,
4897
- {
4898
- checked: showSectionDividers,
4899
- "aria-label": "\u663E\u793A\u5206\u7EC4\u5206\u9694\u7EBF",
4900
- onChange: (event) => setShowSectionDividers(event.target.checked)
4901
- }
4902
- ) }),
4903
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u884C\u95F4\u8DDD\uFF08px\uFF09", children: /* @__PURE__ */ jsxRuntime.jsx(
4904
- reactComponents.ReactNumberInput,
4905
- {
4906
- min: 0,
4907
- max: 40,
4908
- step: 1,
4909
- value: formItemSpacing,
4910
- "aria-label": "\u8868\u5355\u884C\u95F4\u8DDD",
4911
- onChange: (value) => setFormItemSpacing(value ?? 0),
4912
- style: { width: "100%" }
4913
- }
4914
- ) }),
4915
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u5206\u9694\u7EBF\u4E0A\u4E0B\u95F4\u8DDD\uFF08px\uFF09", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4916
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u4E0A" }),
4917
- /* @__PURE__ */ jsxRuntime.jsx(
4918
- reactComponents.ReactNumberInput,
4919
- {
4920
- min: 0,
4921
- max: 40,
4922
- step: 1,
4923
- value: sectionDividerTopSpacing,
4924
- "aria-label": "\u5206\u9694\u7EBF\u4E0A\u95F4\u8DDD",
4925
- onChange: (value) => setSectionDividerTopSpacing(value ?? 0),
4926
- style: { width: 64 }
4927
- }
4928
- ),
4929
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u4E0B" }),
4930
- /* @__PURE__ */ jsxRuntime.jsx(
4931
- reactComponents.ReactNumberInput,
4932
- {
4933
- min: 0,
4934
- max: 40,
4935
- step: 1,
4936
- value: sectionDividerBottomSpacing,
4937
- "aria-label": "\u5206\u9694\u7EBF\u4E0B\u95F4\u8DDD",
4938
- onChange: (value) => setSectionDividerBottomSpacing(value ?? 0),
4939
- style: { width: 64 }
4940
- }
4941
- )
4942
- ] }) }),
4943
- sectionDivider,
4944
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6807\u9898", children: /* @__PURE__ */ jsxRuntime.jsx(
4945
- reactComponents.ReactInput,
4946
- {
4947
- value: title,
4948
- "aria-label": "\u6253\u5370\u6807\u9898",
4949
- allowClear: true,
4950
- onChange: (event) => setTitle(event.target.value),
4951
- style: { width: "100%", minWidth: 0 }
4952
- }
4953
- ) }),
4954
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u5B50\u6807\u9898", children: /* @__PURE__ */ jsxRuntime.jsx(
4955
- reactComponents.ReactInput,
4956
- {
4957
- value: subtitle,
4958
- "aria-label": "\u6253\u5370\u5B50\u6807\u9898",
4959
- allowClear: true,
4960
- onChange: (event) => setSubtitle(event.target.value),
4961
- style: { width: "100%", minWidth: 0 }
4962
- }
4963
- ) }),
4964
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6807\u9898\u5B57\u53F7", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, minWidth: 0 }, children: [
4965
- /* @__PURE__ */ jsxRuntime.jsx(
4966
- reactComponents.ReactNumberInput,
4967
- {
4968
- min: 1,
4969
- step: 1,
4970
- value: titleFontSize,
4971
- "aria-label": "\u6807\u9898\u5B57\u53F7",
4972
- onChange: (value) => setTitleFontSize(value ?? 18),
4973
- style: { flex: "1 1 0", minWidth: 0 }
4974
- }
4975
- ),
4976
- /* @__PURE__ */ jsxRuntime.jsx(
4977
- reactComponents.ReactNumberInput,
4978
- {
4979
- min: 1,
4980
- step: 1,
4981
- value: subtitleFontSize,
4982
- "aria-label": "\u5B50\u6807\u9898\u5B57\u53F7",
4983
- onChange: (value) => setSubtitleFontSize(value ?? 12),
4984
- style: { flex: "1 1 0", minWidth: 0 }
4985
- }
4986
- )
4987
- ] }) }),
4988
- sectionDivider,
4989
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u7EB8\u5F20", children: /* @__PURE__ */ jsxRuntime.jsx(
4990
- reactComponents.ReactSelect,
4991
- {
4992
- value: paperSize,
4993
- options: [
4994
- { value: "a0", label: "A0" },
4995
- { value: "a1", label: "A1" },
4996
- { value: "a2", label: "A2" },
4997
- { value: "a3", label: "A3" },
4998
- { value: "a4", label: "A4" },
4999
- { value: "a5", label: "A5" },
5000
- { value: "a6", label: "A6" },
5001
- { value: "b4", label: "B4" },
5002
- { value: "b5", label: "B5" },
5003
- { value: "letter", label: "Letter" },
5004
- { value: "legal", label: "Legal" },
5005
- { value: "tabloid", label: "Tabloid" },
5006
- { value: "executive", label: "Executive" },
5007
- { value: "folio", label: "Folio" }
5008
- ],
5009
- onChange: (value) => setPaperSize(value),
5010
- style: { width: "100%" }
5011
- }
5012
- ) }),
5013
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6253\u5370\u65B9\u5411", children: /* @__PURE__ */ jsxRuntime.jsxs(
5014
- reactComponents.ReactRadio.Group,
5015
- {
5016
- value: orientation,
5017
- "aria-label": "\u6253\u5370\u65B9\u5411",
5018
- onChange: (event) => setOrientation(event.target.value),
5019
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5020
- children: [
5021
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "portrait", children: "\u7EB5\u5411" }),
5022
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "landscape", children: "\u6A2A\u5411" })
5023
- ]
5024
- }
5025
- ) }),
5026
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6253\u5370\u8FB9\u8DDD\uFF08mm\uFF09", children: /* @__PURE__ */ jsxRuntime.jsx(
5027
- "div",
5028
- {
5029
- style: {
5030
- display: "grid",
5031
- gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
5032
- gap: 8
5033
- },
5034
- children: [
5035
- ["top", "\u4E0A"],
5036
- ["right", "\u53F3"],
5037
- ["bottom", "\u4E0B"],
5038
- ["left", "\u5DE6"]
5039
- ].map(([side, label]) => /* @__PURE__ */ jsxRuntime.jsxs(
5040
- "div",
5041
- {
5042
- style: {
5043
- display: "grid",
5044
- gridTemplateColumns: "20px minmax(0, 1fr)",
5045
- gap: 4,
5046
- alignItems: "center"
5047
- },
5048
- children: [
5049
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }),
5050
- /* @__PURE__ */ jsxRuntime.jsx(
5051
- reactComponents.ReactNumberInput,
5052
- {
5053
- min: 0,
5054
- step: 1,
5055
- value: pageMargins[side],
5056
- onChange: (value) => setPageMargins((current) => ({
5057
- ...current,
5058
- [side]: value ?? 0
5059
- })),
5060
- style: { width: "100%" }
5061
- }
5062
- )
5063
- ]
5064
- },
5065
- side
5066
- ))
5067
- }
5068
- ) }),
5069
- sectionDivider,
5070
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u5355\u5143\u683C\u8FB9\u6846", children: /* @__PURE__ */ jsxRuntime.jsx(
5071
- reactComponents.ReactCheckbox,
5072
- {
5073
- checked: useCellBorders,
5074
- "aria-label": "\u5355\u5143\u683C\u8FB9\u6846",
5075
- onChange: (event) => setUseCellBorders(event.target.checked)
5076
- }
5077
- ) }),
5078
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u8FB9\u6846\u989C\u8272", children: /* @__PURE__ */ jsxRuntime.jsx(
5079
- reactComponents.ReactColorPicker,
5080
- {
5081
- value: borderColor,
5082
- disabled: !useCellBorders,
5083
- onChange: setBorderColor,
5084
- style: { width: "100%" }
5085
- }
5086
- ) }),
5087
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6587\u5B57\u989C\u8272", children: /* @__PURE__ */ jsxRuntime.jsx(
5088
- reactComponents.ReactColorPicker,
5089
- {
5090
- value: textColor,
5091
- onChange: setTextColor,
5092
- style: { width: "100%" }
5093
- }
5094
- ) }),
5095
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u8868\u5934\u80CC\u666F\u8272", children: /* @__PURE__ */ jsxRuntime.jsx(
5096
- reactComponents.ReactColorPicker,
5097
- {
5098
- value: headerBackgroundColor,
5099
- onChange: setHeaderBackgroundColor,
5100
- style: { width: "100%" }
5101
- }
5102
- ) }),
5103
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6C47\u603B\u884C\u80CC\u666F\u8272", children: /* @__PURE__ */ jsxRuntime.jsx(
5104
- reactComponents.ReactColorPicker,
5105
- {
5106
- value: summaryBackgroundColor,
5107
- onChange: setSummaryBackgroundColor,
5108
- style: { width: "100%" }
5109
- }
5110
- ) }),
5111
- sectionDivider,
5112
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6253\u5370\u6C47\u603B\u884C", children: /* @__PURE__ */ jsxRuntime.jsx(
5113
- reactComponents.ReactCheckbox,
5114
- {
5115
- checked: includeSummary,
5116
- "aria-label": "\u6253\u5370\u6C47\u603B\u884C",
5117
- onChange: (event) => setIncludeSummary(event.target.checked)
5118
- }
5119
- ) }),
5120
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6C47\u603B\u4F4D\u7F6E", children: /* @__PURE__ */ jsxRuntime.jsxs(
5121
- reactComponents.ReactRadio.Group,
5122
- {
5123
- value: summaryPosition,
5124
- "aria-label": "\u6C47\u603B\u4F4D\u7F6E",
5125
- onChange: (event) => setSummaryPosition(
5126
- event.target.value
5127
- ),
5128
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5129
- children: [
5130
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "every-page", disabled: !includeSummary, children: "\u6BCF\u9875" }),
5131
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactRadio, { value: "last-page", disabled: !includeSummary, children: "\u6700\u540E\u4E00\u9875" })
5132
- ]
5133
- }
5134
- ) }),
5135
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6253\u5370\u65F6\u95F4", children: /* @__PURE__ */ jsxRuntime.jsxs(
5136
- "span",
5137
- {
5138
- style: {
5139
- display: "flex",
5140
- alignItems: "center",
5141
- gap: 8,
5142
- minWidth: 0,
5143
- whiteSpace: "nowrap"
5144
- },
5145
- children: [
5146
- /* @__PURE__ */ jsxRuntime.jsx(
5147
- reactComponents.ReactCheckbox,
5148
- {
5149
- checked: showPrintTime,
5150
- "aria-label": "\u663E\u793A\u6253\u5370\u65F6\u95F4",
5151
- onChange: (event) => {
5152
- const checked = event.target.checked;
5153
- setShowPrintTime(checked);
5154
- if (checked && showPageNumbers && pageNumberPosition === printTimePosition) {
5155
- setPrintTimePosition(
5156
- pageNumberPosition === "left" ? "center" : "left"
5157
- );
5158
- }
5159
- }
5160
- }
5161
- ),
5162
- "\u663E\u793A"
5163
- ]
5164
- }
5165
- ) }),
5166
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u65F6\u95F4\u4F4D\u7F6E", children: /* @__PURE__ */ jsxRuntime.jsxs(
5167
- reactComponents.ReactRadio.Group,
5168
- {
5169
- value: printTimePosition,
5170
- "aria-label": "\u6253\u5370\u65F6\u95F4\u4F4D\u7F6E",
5171
- onChange: (event) => {
5172
- const next = event.target.value;
5173
- if (showPageNumbers && next === pageNumberPosition) return;
5174
- setPrintTimePosition(next);
5175
- },
5176
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5177
- children: [
5178
- /* @__PURE__ */ jsxRuntime.jsx(
5179
- reactComponents.ReactRadio,
5180
- {
5181
- value: "left",
5182
- disabled: !showPrintTime || showPageNumbers && pageNumberPosition === "left",
5183
- children: "\u5DE6\u4FA7"
5184
- }
5185
- ),
5186
- /* @__PURE__ */ jsxRuntime.jsx(
5187
- reactComponents.ReactRadio,
5188
- {
5189
- value: "center",
5190
- disabled: !showPrintTime || showPageNumbers && pageNumberPosition === "center",
5191
- children: "\u4E2D\u95F4"
5192
- }
5193
- ),
5194
- /* @__PURE__ */ jsxRuntime.jsx(
5195
- reactComponents.ReactRadio,
5196
- {
5197
- value: "right",
5198
- disabled: !showPrintTime || showPageNumbers && pageNumberPosition === "right",
5199
- children: "\u53F3\u4FA7"
5200
- }
5201
- )
5202
- ]
5203
- }
5204
- ) }),
5205
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u5206\u9875\u4FE1\u606F", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5206
- /* @__PURE__ */ jsxRuntime.jsx(
5207
- reactComponents.ReactCheckbox,
5208
- {
5209
- checked: showPageNumbers,
5210
- "aria-label": "\u663E\u793A\u5206\u9875\u4FE1\u606F",
5211
- onChange: (event) => setShowPageNumbers(event.target.checked)
5212
- }
5213
- ),
5214
- "\u663E\u793A"
5215
- ] }) }),
5216
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u5206\u9875\u4F4D\u7F6E", children: /* @__PURE__ */ jsxRuntime.jsxs(
5217
- reactComponents.ReactRadio.Group,
5218
- {
5219
- value: pageNumberPosition,
5220
- "aria-label": "\u5206\u9875\u4FE1\u606F\u4F4D\u7F6E",
5221
- onChange: (event) => (() => {
5222
- const next = event.target.value;
5223
- setPageNumberPosition(next);
5224
- if (showPrintTime && next === printTimePosition) {
5225
- setPrintTimePosition(
5226
- next === "left" ? "center" : "left"
5227
- );
5228
- }
5229
- })(),
5230
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5231
- children: [
5232
- /* @__PURE__ */ jsxRuntime.jsx(
5233
- reactComponents.ReactRadio,
5234
- {
5235
- value: "left",
5236
- disabled: !showPageNumbers || showPrintTime && printTimePosition === "left",
5237
- children: "\u5DE6\u4FA7"
5238
- }
5239
- ),
5240
- /* @__PURE__ */ jsxRuntime.jsx(
5241
- reactComponents.ReactRadio,
5242
- {
5243
- value: "center",
5244
- disabled: !showPageNumbers || showPrintTime && printTimePosition === "center",
5245
- children: "\u4E2D\u95F4"
5246
- }
5247
- ),
5248
- /* @__PURE__ */ jsxRuntime.jsx(
5249
- reactComponents.ReactRadio,
5250
- {
5251
- value: "right",
5252
- disabled: !showPageNumbers || showPrintTime && printTimePosition === "right",
5253
- children: "\u53F3\u4FA7"
5254
- }
5255
- )
5256
- ]
5257
- }
5258
- ) }),
5259
- sectionDivider,
5260
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u884C\u9AD8\uFF08mm\uFF09", children: /* @__PURE__ */ jsxRuntime.jsx(
5261
- reactComponents.ReactNumberInput,
5262
- {
5263
- min: 1,
5264
- step: 1,
5265
- value: rowHeight,
5266
- onChange: (value) => {
5267
- setRowHeight(value ?? 0);
5268
- setError("");
5269
- },
5270
- style: { width: "100%" }
5271
- }
5272
- ) }),
5273
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactForm.Item, { label: "\u6BCF\u9875\u884C\u6570", children: /* @__PURE__ */ jsxRuntime.jsxs(
5274
- "span",
5275
- {
5276
- style: {
5277
- display: "flex",
5278
- alignItems: "center",
5279
- gap: 8,
5280
- whiteSpace: "nowrap"
5281
- },
5282
- children: [
5283
- /* @__PURE__ */ jsxRuntime.jsx(
5284
- reactComponents.ReactNumberInput,
5285
- {
5286
- min: 1,
5287
- step: 1,
5288
- value: rowsPerPage,
5289
- onChange: (value) => {
5290
- setRowsPerPage(value ?? 0);
5291
- setError("");
5292
- },
5293
- style: { flex: "1 1 auto", minWidth: 0 }
5294
- }
5295
- ),
5296
- /* @__PURE__ */ jsxRuntime.jsx(
5297
- reactComponents.ReactCheckbox,
5298
- {
5299
- checked: autoCalculateRows,
5300
- "aria-label": "\u81EA\u52A8\u8BA1\u7B97\u6BCF\u9875\u884C\u6570",
5301
- onChange: (event) => setAutoCalculateRows(event.target.checked)
5302
- }
5303
- ),
5304
- "\u81EA\u52A8\u8BA1\u7B97"
5305
- ]
5306
- }
5307
- ) })
5308
- ]
5309
- }
5310
- )
5311
- }
5312
- ),
5313
- /* @__PURE__ */ jsxRuntime.jsxs(
5314
- "div",
5315
- {
5316
- style: {
5317
- minWidth: 0,
5318
- minHeight: 0,
5319
- display: "flex",
5320
- flexDirection: "column"
5321
- },
5322
- children: [
5323
- /* @__PURE__ */ jsxRuntime.jsx(
5324
- "div",
5325
- {
5326
- style: {
5327
- display: "flex",
5328
- justifyContent: "flex-end",
5329
- marginBottom: 8
5330
- },
5331
- children: /* @__PURE__ */ jsxRuntime.jsx(
5332
- reactComponents.ReactButton,
5333
- {
5334
- type: "default",
5335
- onClick: autoCalculateColumnWidths,
5336
- disabled: selectedKeys.length === 0,
5337
- children: "\u81EA\u52A8\u8BA1\u7B97\u5217\u5BBD"
5338
- }
5339
- )
5340
- }
5341
- ),
5342
- /* @__PURE__ */ jsxRuntime.jsx(
5343
- "div",
5344
- {
5345
- style: {
5346
- flex: "1 1 auto",
5347
- minHeight: 280,
5348
- height: printFullscreen ? "100%" : "min(58vh, 560px)"
5349
- },
5350
- children: props.renderTable({
5351
- tableId,
5352
- columns: tableColumns,
5353
- dataSource: columns,
5354
- rowKey: "key",
5355
- rowHeight: 40,
5356
- headerRowHeight: 38,
5357
- toolbar: false,
5358
- contextMenu: false,
5359
- pagination: false,
5360
- draggable: true,
5361
- rowSelection: {
5362
- type: "checkbox",
5363
- selectedRowKeys: selectedKeys,
5364
- selectRowByClick: false,
5365
- onChange: (keys) => {
5366
- setSelectedKeys(keys);
5367
- setError("");
5368
- }
5369
- },
5370
- rowDrag: {
5371
- enabled: true,
5372
- droppable: true,
5373
- allowSelfDrop: true,
5374
- mode: "move",
5375
- onDrop: ({ rows: moved, insertIndex, source }) => {
5376
- if (source.tableId !== tableId || insertIndex == null)
5377
- return;
5378
- const keys = new Set(moved.map((row) => row.key));
5379
- setColumns((current) => {
5380
- const remaining = current.filter(
5381
- (row) => !keys.has(row.key)
5382
- );
5383
- const preceding = current.slice(0, insertIndex).filter((row) => !keys.has(row.key)).length;
5384
- remaining.splice(
5385
- preceding,
5386
- 0,
5387
- ...current.filter((row) => keys.has(row.key))
5388
- );
5389
- return remaining;
5390
- });
5391
- }
5392
- },
5393
- style: { width: "100%", height: "100%" }
5394
- })
5395
- }
5396
- )
5397
- ]
5398
- }
5399
- )
5400
- ]
5401
- }
5402
- )
5403
- }
5404
- ),
5405
- error ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", style: { color: "#c2410c", marginTop: 8 }, children: error }) : null,
5406
- /* @__PURE__ */ jsxRuntime.jsx(
5407
- reactComponents.ReactModal,
5408
- {
5409
- open: previewOpen,
5410
- title: "\u6253\u5370\u9884\u89C8",
5411
- width: "min(96vw, 1280px)",
5412
- fullscreenable: true,
5413
- fullscreen: previewFullscreen,
5414
- onFullscreenChange: setPreviewFullscreen,
5415
- bodyStyle: { display: "flex", minHeight: 0 },
5416
- footer: /* @__PURE__ */ jsxRuntime.jsxs(
5417
- "div",
5418
- {
5419
- style: {
5420
- display: "flex",
5421
- justifyContent: "flex-end",
5422
- alignItems: "center",
5423
- gap: 8,
5424
- width: "100%"
5425
- },
5426
- children: [
5427
- /* @__PURE__ */ jsxRuntime.jsx(
5428
- reactComponents.ReactButton,
5429
- {
5430
- type: previewMode === "render" ? "primary" : "default",
5431
- onClick: () => setPreviewMode("render"),
5432
- children: "\u6548\u679C"
5433
- }
5434
- ),
5435
- /* @__PURE__ */ jsxRuntime.jsx(
5436
- reactComponents.ReactButton,
5437
- {
5438
- type: previewMode === "source" ? "primary" : "default",
5439
- onClick: () => setPreviewMode("source"),
5440
- children: "HTML"
5441
- }
5442
- ),
5443
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { type: "default", onClick: previewPrintHtml, children: "\u5237\u65B0\u9884\u89C8" })
5444
- ]
5445
- }
5446
- ),
5447
- onCancel: () => setPreviewOpen(false),
5448
- children: /* @__PURE__ */ jsxRuntime.jsx(
5449
- "div",
5450
- {
5451
- style: {
5452
- display: "flex",
5453
- flex: 1,
5454
- minHeight: 0,
5455
- width: "100%",
5456
- justifyContent: "center"
5457
- },
5458
- children: previewMode === "render" ? /* @__PURE__ */ jsxRuntime.jsx(
5459
- reactComponents.ReactVirtualList,
5460
- {
5461
- items: previewPages,
5462
- height: previewListHeight,
5463
- itemHeight: previewItemHeight,
5464
- itemKey: (page) => page.index,
5465
- overscan: 1,
5466
- style: {
5467
- width: "100%",
5468
- maxWidth: previewListWidth,
5469
- overflowX: "hidden"
5470
- },
5471
- renderItem: (page, _index, meta) => /* @__PURE__ */ jsxRuntime.jsx(
5472
- "div",
5473
- {
5474
- style: {
5475
- ...meta.style,
5476
- display: "flex",
5477
- justifyContent: "center",
5478
- alignItems: "flex-start",
5479
- height: previewItemHeight,
5480
- padding: 12,
5481
- boxSizing: "border-box",
5482
- overflow: "hidden"
5483
- },
5484
- children: /* @__PURE__ */ jsxRuntime.jsx(
5485
- "div",
5486
- {
5487
- style: {
5488
- width: pageWidthPixels * previewScale,
5489
- height: pageHeightPixels * previewScale,
5490
- border: "1px solid #cbd5e1",
5491
- position: "relative",
5492
- overflow: "hidden",
5493
- background: "white"
5494
- },
5495
- children: /* @__PURE__ */ jsxRuntime.jsx(
5496
- "iframe",
5497
- {
5498
- title: `\u6253\u5370\u6548\u679C\u9884\u89C8\u7B2C ${page.index + 1} \u9875`,
5499
- srcDoc: page.srcDoc,
5500
- sandbox: "",
5501
- style: {
5502
- display: "block",
5503
- position: "absolute",
5504
- left: 0,
5505
- top: 0,
5506
- width: pageWidthPixels,
5507
- height: pageHeightPixels,
5508
- transform: `scale(${previewScale})`,
5509
- transformOrigin: "top left",
5510
- border: 0,
5511
- overflow: "hidden",
5512
- background: "white"
5513
- }
5514
- }
5515
- )
5516
- }
5517
- )
5518
- }
5519
- )
5520
- }
5521
- ) : /* @__PURE__ */ jsxRuntime.jsx(
5522
- "pre",
5523
- {
5524
- "aria-label": "\u751F\u6210\u7684\u6253\u5370 HTML",
5525
- style: {
5526
- boxSizing: "border-box",
5527
- width: "100%",
5528
- height: previewFullscreen ? "100%" : "min(72vh, 900px)",
5529
- minHeight: 0,
5530
- overflow: "auto",
5531
- margin: 0,
5532
- padding: 12,
5533
- border: "1px solid #cbd5e1",
5534
- background: "#f8fafc",
5535
- color: "#1f2937",
5536
- font: "12px/1.5 ui-monospace, SFMono-Regular, monospace",
5537
- whiteSpace: "pre-wrap",
5538
- overflowWrap: "anywhere"
5539
- },
5540
- children: previewHtml
5541
- }
5542
- )
5543
- }
5544
- )
5545
- }
4753
+ options
4754
+ );
4755
+ } finally {
4756
+ worker?.terminate();
4757
+ if (url) URL.revokeObjectURL(url);
4758
+ }
4759
+ }
4760
+
4761
+ // src/features/print/direct-print.ts
4762
+ async function runDirectPrint(container, loadSource, resolveTemplate = (source) => createTableDocument({ ...source, rows: [] }), validate, defaultPagesPerBatch = 50) {
4763
+ const controller = new AbortController();
4764
+ const { signal } = controller;
4765
+ const ownerDocument = container.ownerDocument;
4766
+ const previousFocus = ownerDocument.activeElement;
4767
+ let frame;
4768
+ const progress = createPrintProgress(container, () => {
4769
+ controller.abort();
4770
+ void cleanup(true);
4771
+ });
4772
+ const cleanup = async (immediate = false) => {
4773
+ frame?.remove();
4774
+ await progress.close(immediate);
4775
+ if (previousFocus?.isConnected)
4776
+ previousFocus.focus({ preventScroll: true });
4777
+ };
4778
+ const timer = setInterval(() => {
4779
+ if (!progress.host.isConnected) controller.abort();
4780
+ }, 250);
4781
+ let maximum = 0;
4782
+ const report = (text, value) => {
4783
+ signal.throwIfAborted();
4784
+ maximum = Math.max(maximum, Math.floor(value));
4785
+ progress.update(text, maximum);
4786
+ };
4787
+ try {
4788
+ const pagesPerBatch = await progress.configure(defaultPagesPerBatch);
4789
+ signal.throwIfAborted();
4790
+ report("\u6B63\u5728\u8BFB\u53D6\u6253\u5370\u6570\u636E", 0);
4791
+ await new Promise((resolve) => setTimeout(resolve, 0));
4792
+ const source = await loadSource({
4793
+ signal,
4794
+ onProgress: (done, total) => report(
4795
+ `\u6B63\u5728\u8BFB\u53D6\u6253\u5370\u6570\u636E ${done}/${total}`,
4796
+ total ? done / total * 30 : 30
4797
+ )
4798
+ });
4799
+ report("\u6B63\u5728\u8F6C\u6362\u6253\u5370\u6570\u636E", 30);
4800
+ const rows = await preparePrintRows(source, {
4801
+ signal,
4802
+ onProgress: (done, total) => report(
4803
+ `\u6B63\u5728\u8F6C\u6362\u6253\u5370\u6570\u636E ${done}/${total}`,
4804
+ 30 + (total ? done / total : 1) * 25
4805
+ )
4806
+ });
4807
+ const template = resolveTemplate(source);
4808
+ validate?.(source, template, createTableData(source, template, rows));
4809
+ report("\u6B63\u5728\u751F\u6210\u5206\u9875", 55);
4810
+ const prepared = await createTablePreviewSource(
4811
+ source,
4812
+ template,
4813
+ {
4814
+ signal,
4815
+ onProgress: (done, total) => report(
4816
+ `\u6B63\u5728\u751F\u6210\u5206\u9875 ${done}/${total}`,
4817
+ 55 + (total ? done / total : 1) * 15
5546
4818
  )
5547
- ]
4819
+ },
4820
+ rows
4821
+ );
4822
+ report("\u6B63\u5728\u751F\u6210\u6253\u5370\u9875\u9762", 70);
4823
+ for await (const batch of printDesign.transformPrintDesignToHtmlBatches(
4824
+ prepared.document,
4825
+ {
4826
+ pagesPerBatch,
4827
+ data: prepared.data,
4828
+ signal,
4829
+ onProgress: (value) => report("\u6B63\u5728\u751F\u6210\u6253\u5370\u9875\u9762", 70 + value * 29)
4830
+ }
4831
+ )) {
4832
+ report(`\u6B63\u5728\u6253\u5370\u7B2C ${batch.firstPage}\u2013${batch.lastPage} \u9875`, maximum);
4833
+ await new Promise((resolve) => setTimeout(resolve, 0));
4834
+ signal.throwIfAborted();
4835
+ frame = ownerDocument.createElement("iframe");
4836
+ frame.title = "\u8868\u683C\u6253\u5370";
4837
+ frame.setAttribute("aria-hidden", "true");
4838
+ frame.style.cssText = "position:fixed;left:-10000px;top:0;width:1px;height:1px;border:0";
4839
+ container.append(frame);
4840
+ const printWindow = frame.contentWindow;
4841
+ if (!printWindow) throw new Error("\u65E0\u6CD5\u521B\u5EFA\u6253\u5370\u9875\u9762");
4842
+ await new Promise((resolve, reject) => {
4843
+ const abort = () => {
4844
+ dispose();
4845
+ reject(signal.reason);
4846
+ };
4847
+ const dispose = () => {
4848
+ frame?.removeEventListener("load", loaded);
4849
+ signal.removeEventListener("abort", abort);
4850
+ };
4851
+ const loaded = () => {
4852
+ dispose();
4853
+ resolve();
4854
+ };
4855
+ frame.addEventListener("load", loaded, { once: true });
4856
+ signal.addEventListener("abort", abort, { once: true });
4857
+ printWindow.document.open();
4858
+ printWindow.document.write(batch.html);
4859
+ printWindow.document.close();
4860
+ });
4861
+ await Promise.all([
4862
+ ...Array.from(
4863
+ printWindow.document.images,
4864
+ (image) => image.decode?.().catch(() => void 0)
4865
+ ),
4866
+ printWindow.document.fonts?.ready
4867
+ ]);
4868
+ signal.throwIfAborted();
4869
+ await new Promise((resolve, reject) => {
4870
+ const dispose = () => {
4871
+ printWindow.removeEventListener("afterprint", finished);
4872
+ signal.removeEventListener("abort", aborted);
4873
+ };
4874
+ const finished = () => {
4875
+ dispose();
4876
+ resolve();
4877
+ };
4878
+ const aborted = () => {
4879
+ dispose();
4880
+ reject(signal.reason);
4881
+ };
4882
+ printWindow.addEventListener("afterprint", finished, { once: true });
4883
+ signal.addEventListener("abort", aborted, { once: true });
4884
+ try {
4885
+ printWindow.focus();
4886
+ printWindow.print();
4887
+ } catch (error) {
4888
+ dispose();
4889
+ reject(error);
4890
+ }
4891
+ });
4892
+ frame.remove();
4893
+ frame = void 0;
4894
+ if (batch.hasMore) {
4895
+ await progress.continueBatch(batch.firstPage, batch.lastPage);
4896
+ signal.throwIfAborted();
4897
+ report("\u6B63\u5728\u751F\u6210\u4E0B\u4E00\u6279\u6253\u5370\u9875\u9762", maximum);
4898
+ }
5548
4899
  }
5549
- );
4900
+ report("\u6253\u5370\u7A97\u53E3\u5DF2\u5173\u95ED", 100);
4901
+ await cleanup();
4902
+ } catch (error) {
4903
+ frame?.remove();
4904
+ if (!signal.aborted) {
4905
+ progress.error(
4906
+ `\u6253\u5370\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
4907
+ );
4908
+ } else await cleanup(true);
4909
+ } finally {
4910
+ clearInterval(timer);
4911
+ }
5550
4912
  }
5551
4913
 
5552
4914
  // src/features/editor/utils.ts
@@ -5589,12 +4951,13 @@ function getEditorInputStyle(request) {
5589
4951
  height,
5590
4952
  minHeight: height,
5591
4953
  color: request.theme.cellColor ?? request.theme.textColor,
4954
+ textAlign: request.theme.textAlign,
5592
4955
  fontFamily: request.theme.fontFamily,
5593
4956
  fontSize,
5594
4957
  // 用像素 token,确保 select/time/color 触发器与内部 Input 同步缩放。
5595
4958
  ["--canvas-react-control-height"]: `${height}px`,
5596
4959
  ["--canvas-react-font-size"]: fontSize != null ? `${fontSize}px` : void 0,
5597
- ["--canvas-react-control-padding-inline"]: `${paddingInline}px`,
4960
+ ["--canvas-react-control-padding-inline"]: `${Math.max(paddingInline - 1, 0)}px`,
5598
4961
  ["--canvas-react-control-padding-block"]: `${paddingBlock}px`,
5599
4962
  ["--canvas-react-content-zoom"]: String(contentZoom),
5600
4963
  ["--canvas-react-radius-sm"]: "0px",
@@ -5621,7 +4984,7 @@ function resolveEditorOverlayStyle(params) {
5621
4984
  boxSizing: "border-box",
5622
4985
  // 覆盖表单组件 token,使输入框高度/字号/内边距跟随表格缩放。
5623
4986
  ["--canvas-react-control-height"]: `${height}px`,
5624
- ["--canvas-react-control-padding-inline"]: `${resolvedPaddingInline}px`,
4987
+ ["--canvas-react-control-padding-inline"]: `${Math.max(resolvedPaddingInline - 1, 0)}px`,
5625
4988
  ["--canvas-react-control-padding-block"]: `${resolvedPaddingBlock}px`,
5626
4989
  ["--canvas-react-content-zoom"]: String(resolvedContentZoom),
5627
4990
  ["--canvas-react-radius-sm"]: "0px",
@@ -5635,6 +4998,16 @@ function resolveEditorOverlayStyle(params) {
5635
4998
  function ReactTableEditorOverlay(props) {
5636
4999
  const { request } = props;
5637
5000
  const editorHostRef = react.useRef(null);
5001
+ const wheelCommittedRef = react.useRef(false);
5002
+ const editorRequest = {
5003
+ ...request,
5004
+ onCommit: (options) => {
5005
+ if (!wheelCommittedRef.current) request.onCommit(options);
5006
+ }
5007
+ };
5008
+ react.useEffect(() => {
5009
+ wheelCommittedRef.current = false;
5010
+ }, [request.editorKey]);
5638
5011
  const style = resolveEditorOverlayStyle({
5639
5012
  rect: request.rect,
5640
5013
  hostRect: request.hostRect,
@@ -5651,7 +5024,26 @@ function ReactTableEditorOverlay(props) {
5651
5024
  }
5652
5025
  focusAndSelectEditorInput(input, request.selectOnFocus);
5653
5026
  }, [request]);
5654
- return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorHostRef, children: renderEditorByType(request, style) }, request.editorKey) });
5027
+ react.useEffect(() => {
5028
+ const host = editorHostRef.current;
5029
+ if (!host) return;
5030
+ const valueType = request.config.valueType ?? "text";
5031
+ if (valueType !== "text" && valueType !== "number" && valueType !== "input-range") {
5032
+ return;
5033
+ }
5034
+ const handleWheel = (event) => {
5035
+ event.preventDefault();
5036
+ event.stopPropagation();
5037
+ if (!wheelCommittedRef.current) {
5038
+ wheelCommittedRef.current = true;
5039
+ request.onCommit();
5040
+ }
5041
+ request.onWheel?.(event);
5042
+ };
5043
+ host.addEventListener("wheel", handleWheel, { passive: false });
5044
+ return () => host.removeEventListener("wheel", handleWheel);
5045
+ }, [request]);
5046
+ return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorHostRef, children: renderEditorByType(editorRequest, style) }, request.editorKey) });
5655
5047
  }
5656
5048
  function renderEditorByType(request, style) {
5657
5049
  switch (request.config.valueType ?? "text") {
@@ -5744,9 +5136,10 @@ function NumberEditor(props) {
5744
5136
  setValue(toNumberValue(request.value));
5745
5137
  }, [request.value]);
5746
5138
  return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: hostRef, style, children: /* @__PURE__ */ jsxRuntime.jsx(
5747
- reactComponents.ReactNumberInput,
5139
+ reactComponents.ReactInputNumber,
5748
5140
  {
5749
5141
  value,
5142
+ initialText: typeof request.value === "string" ? request.value : void 0,
5750
5143
  min: toNumericProp(request.config.min),
5751
5144
  max: toNumericProp(request.config.max),
5752
5145
  step: toNumericProp(request.config.step),
@@ -6624,47 +6017,6 @@ function ReactTableDangerConfirmView(props) {
6624
6017
  }
6625
6018
  );
6626
6019
  }
6627
- function ReactTableTooltipView(props) {
6628
- const { request } = props;
6629
- const tooltipRef = react.useRef(null);
6630
- react.useLayoutEffect(() => {
6631
- const tooltip = tooltipRef.current;
6632
- if (!tooltip || !request || typeof window === "undefined") return;
6633
- const width = tooltip.getBoundingClientRect().width;
6634
- const viewportWidth = window.innerWidth;
6635
- tooltip.style.left = `${Math.max(8, Math.min(request.x - width / 2, viewportWidth - width - 8))}px`;
6636
- }, [request]);
6637
- if (!request) {
6638
- return null;
6639
- }
6640
- const zoom = typeof request.contentZoom === "number" && Number.isFinite(request.contentZoom) && request.contentZoom > 0 ? request.contentZoom : 1;
6641
- const fontSize = 14 * zoom;
6642
- const paddingBlock = 6 * zoom;
6643
- const paddingInline = 10 * zoom;
6644
- const borderRadius = 6 * zoom;
6645
- const maxWidth = 320 * zoom;
6646
- const style = {
6647
- position: "fixed",
6648
- left: request.x,
6649
- top: request.y,
6650
- maxWidth: request.variant === "resize" ? "calc(100vw - 16px)" : `min(${maxWidth}px, calc(100vw - 16px))`,
6651
- padding: `${paddingBlock}px ${paddingInline}px`,
6652
- borderRadius,
6653
- background: request.variant === "error" ? "#ffffff" : "rgba(17, 24, 39, 0.92)",
6654
- color: request.variant === "error" ? "#ff4d4f" : "#fff",
6655
- fontSize,
6656
- lineHeight: 1.5,
6657
- boxShadow: request.variant === "error" ? "0 10px 30px rgba(255, 77, 79, 0.16)" : "0 10px 30px rgba(15, 23, 42, 0.18)",
6658
- border: request.variant === "error" ? "1px solid rgba(255, 77, 79, 0.2)" : "none",
6659
- pointerEvents: "none",
6660
- zIndex: 1200,
6661
- whiteSpace: request.variant === "resize" ? "nowrap" : "pre-wrap",
6662
- wordBreak: "break-word",
6663
- overflow: "hidden",
6664
- textOverflow: request.variant === "resize" ? "ellipsis" : void 0
6665
- };
6666
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: tooltipRef, style, children: request.content });
6667
- }
6668
6020
  function ToolbarIcon(props) {
6669
6021
  const { path, ...svgProps } = props;
6670
6022
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -6703,245 +6055,8 @@ function HolderOutlined() {
6703
6055
  return /* @__PURE__ */ jsxRuntime.jsx(ToolbarIcon, { path: "M300 276.5a56 56 0 1056-97 56 56 0 00-56 97zm0 284a56 56 0 1056-97 56 56 0 00-56 97zM640 228a56 56 0 10112 0 56 56 0 00-112 0zm0 284a56 56 0 10112 0 56 56 0 00-112 0zM300 844.5a56 56 0 1056-97 56 56 0 00-56 97zM640 796a56 56 0 10112 0 56 56 0 00-112 0z" });
6704
6056
  }
6705
6057
 
6706
- // src/components/fullscreen-portal.ts
6707
- function resolveFullscreenPortalContainer(host) {
6708
- const fullscreenElement = document.fullscreenElement;
6709
- return fullscreenElement instanceof HTMLElement && host && fullscreenElement.contains(host) ? fullscreenElement : document.body;
6710
- }
6711
- function SortableList(props) {
6712
- const { items, onOrderChange } = props;
6713
- const rootRef = react.useRef(null);
6714
- const dragRef = react.useRef(null);
6715
- const [dragState, setDragState] = react.useState(null);
6716
- react.useEffect(
6717
- () => () => {
6718
- document.body.classList.remove("react-list-table-sorting");
6719
- document.body.style.removeProperty("user-select");
6720
- },
6721
- []
6722
- );
6723
- react.useEffect(() => {
6724
- if (!dragState) return;
6725
- const scrollContainer = props.scrollContainerRef?.current;
6726
- let frameId = 0;
6727
- let lastTime = null;
6728
- const updateTarget = () => {
6729
- const current = dragRef.current;
6730
- if (!current) return;
6731
- const target = resolveClosestSortableItem({
6732
- items,
6733
- parentKey: current.source.parentKey,
6734
- layouts: current.layouts,
6735
- // 保留拖拽开始时的布局,补偿滚动位移,避免受行交换动画影响。
6736
- overlayCenterY: current.pointerY - current.offsetY + current.height / 2 + current.rootTop - (rootRef.current?.getBoundingClientRect().top ?? current.rootTop)
6737
- });
6738
- if (target) {
6739
- current.target = target;
6740
- }
6741
- setDragState({
6742
- sourceKey: current.source.key,
6743
- targetKey: current.target.key,
6744
- pointerY: current.pointerY
6745
- });
6746
- };
6747
- const handleMove = (event) => {
6748
- const current = dragRef.current;
6749
- if (!current || event.pointerId !== current.pointerId) return;
6750
- current.pointerY = event.clientY;
6751
- updateTarget();
6752
- };
6753
- const tick = (time) => {
6754
- const current = dragRef.current;
6755
- if (!current) return;
6756
- const elapsed = lastTime == null ? 0 : Math.min(time - lastTime, 50);
6757
- lastTime = time;
6758
- if (scrollContainer) {
6759
- const rect = scrollContainer.getBoundingClientRect();
6760
- const top = rect.top + scrollContainer.clientTop;
6761
- const height = scrollContainer.clientHeight;
6762
- const edge = Math.min(40, height / 2);
6763
- const bottom = top + height;
6764
- const direction = edge <= 0 ? 0 : current.pointerY < top + edge ? -Math.min(1, (top + edge - current.pointerY) / edge) : current.pointerY > bottom - edge ? Math.min(1, (current.pointerY - bottom + edge) / edge) : 0;
6765
- if (direction) {
6766
- scrollContainer.scrollTop = Math.max(
6767
- 0,
6768
- Math.min(
6769
- scrollContainer.scrollHeight - height,
6770
- scrollContainer.scrollTop + direction * elapsed * 0.5
6771
- )
6772
- );
6773
- updateTarget();
6774
- }
6775
- }
6776
- frameId = requestAnimationFrame(tick);
6777
- };
6778
- const finish = (commit) => {
6779
- const current = dragRef.current;
6780
- cancelAnimationFrame(frameId);
6781
- if (commit && current && current.source.key !== current.target.key) {
6782
- const siblings = items.filter(
6783
- (item) => item.parentKey === current.source.parentKey
6784
- );
6785
- const orderedKeys = resolveNextSortableOrder(
6786
- siblings.map((item) => item.key),
6787
- current.source.key,
6788
- current.target.key
6789
- );
6790
- if (orderedKeys) {
6791
- onOrderChange(current.source.parentKey, orderedKeys);
6792
- }
6793
- }
6794
- dragRef.current = null;
6795
- setDragState(null);
6796
- document.body.classList.remove("react-list-table-sorting");
6797
- document.body.style.removeProperty("user-select");
6798
- };
6799
- const handleEnd = (event) => {
6800
- if (event.pointerId !== dragRef.current?.pointerId) return;
6801
- handleMove(event);
6802
- finish(true);
6803
- };
6804
- const handleCancel = (event) => {
6805
- if (event.pointerId === dragRef.current?.pointerId) finish(false);
6806
- };
6807
- const handleBlur = () => finish(false);
6808
- frameId = requestAnimationFrame(tick);
6809
- scrollContainer?.addEventListener("scroll", updateTarget);
6810
- window.addEventListener("pointermove", handleMove);
6811
- window.addEventListener("pointerup", handleEnd);
6812
- window.addEventListener("pointercancel", handleCancel);
6813
- window.addEventListener("blur", handleBlur);
6814
- return () => {
6815
- cancelAnimationFrame(frameId);
6816
- scrollContainer?.removeEventListener("scroll", updateTarget);
6817
- window.removeEventListener("pointermove", handleMove);
6818
- window.removeEventListener("pointerup", handleEnd);
6819
- window.removeEventListener("pointercancel", handleCancel);
6820
- window.removeEventListener("blur", handleBlur);
6821
- };
6822
- }, [dragState != null, items, onOrderChange, props.scrollContainerRef]);
6823
- const sourceIndex = dragState ? items.findIndex((item) => item.key === dragState.sourceKey) : -1;
6824
- const targetIndex = dragState ? items.findIndex((item) => item.key === dragState.targetKey) : -1;
6825
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, children: [
6826
- items.map((item, index) => {
6827
- const style = resolveSortableTransform(
6828
- index,
6829
- sourceIndex,
6830
- targetIndex,
6831
- dragRef.current?.height ?? 0
6832
- );
6833
- return /* @__PURE__ */ jsxRuntime.jsx(
6834
- "div",
6835
- {
6836
- "data-sortable-key": item.key,
6837
- className: dragState?.sourceKey === item.key ? "dragging" : "",
6838
- style,
6839
- children: props.renderItem(item, {
6840
- onPointerDown: (event) => {
6841
- if (event.button !== 0 || dragRef.current) return;
6842
- const row = event.currentTarget.closest(
6843
- "[data-sortable-key]"
6844
- );
6845
- if (!row) return;
6846
- const rect = row.getBoundingClientRect();
6847
- dragRef.current = {
6848
- source: item,
6849
- target: item,
6850
- layouts: collectSortableItemLayouts(rootRef.current),
6851
- offsetY: event.clientY - rect.top,
6852
- width: rect.width,
6853
- left: rect.left,
6854
- height: rect.height,
6855
- pointerId: event.pointerId,
6856
- pointerY: event.clientY,
6857
- rootTop: rootRef.current?.getBoundingClientRect().top ?? 0
6858
- };
6859
- setDragState({
6860
- sourceKey: item.key,
6861
- targetKey: item.key,
6862
- pointerY: event.clientY
6863
- });
6864
- document.body.classList.add("react-list-table-sorting");
6865
- document.body.style.userSelect = "none";
6866
- event.preventDefault();
6867
- }
6868
- })
6869
- },
6870
- item.key
6871
- );
6872
- }),
6873
- dragState && dragRef.current ? reactDom.createPortal(
6874
- /* @__PURE__ */ jsxRuntime.jsx(
6875
- "div",
6876
- {
6877
- className: "react-list-table-sort-overlay",
6878
- style: {
6879
- left: dragRef.current.left,
6880
- top: dragState.pointerY - dragRef.current.offsetY,
6881
- width: dragRef.current.width,
6882
- height: dragRef.current.height
6883
- },
6884
- children: props.renderItem(dragRef.current.source, {
6885
- onPointerDown: (event) => event.preventDefault()
6886
- })
6887
- }
6888
- ),
6889
- resolveFullscreenPortalContainer(rootRef.current)
6890
- ) : null
6891
- ] });
6892
- }
6893
- function resolveNextSortableOrder(currentKeys, sourceKey, targetKey) {
6894
- const sourceIndex = currentKeys.indexOf(sourceKey);
6895
- const targetIndex = currentKeys.indexOf(targetKey);
6896
- if (sourceIndex < 0 || targetIndex < 0 || sourceIndex === targetIndex) {
6897
- return null;
6898
- }
6899
- const nextKeys = [...currentKeys];
6900
- const [source] = nextKeys.splice(sourceIndex, 1);
6901
- nextKeys.splice(targetIndex, 0, source);
6902
- return nextKeys;
6903
- }
6904
- function collectSortableItemLayouts(root) {
6905
- if (!root) return [];
6906
- return Array.from(
6907
- root.querySelectorAll("[data-sortable-key]")
6908
- ).map((element) => {
6909
- const rect = element.getBoundingClientRect();
6910
- return {
6911
- key: element.dataset.sortableKey ?? "",
6912
- centerY: rect.top + rect.height / 2
6913
- };
6914
- });
6915
- }
6916
- function resolveClosestSortableItem(params) {
6917
- let closestItem = null;
6918
- let closestDistance = Number.POSITIVE_INFINITY;
6919
- params.layouts.forEach((layout) => {
6920
- const item = params.items.find((candidate) => candidate.key === layout.key);
6921
- if (!item || item.parentKey !== params.parentKey) return;
6922
- const distance = Math.abs(params.overlayCenterY - layout.centerY);
6923
- if (distance < closestDistance) {
6924
- closestDistance = distance;
6925
- closestItem = item;
6926
- }
6927
- });
6928
- return closestItem;
6929
- }
6930
- function resolveSortableTransform(index, sourceIndex, targetIndex, height) {
6931
- let translateY = 0;
6932
- if (sourceIndex < targetIndex && index > sourceIndex && index <= targetIndex) {
6933
- translateY = -height;
6934
- } else if (sourceIndex > targetIndex && index >= targetIndex && index < sourceIndex) {
6935
- translateY = height;
6936
- }
6937
- return {
6938
- transform: translateY ? `translate3d(0, ${translateY}px, 0)` : void 0,
6939
- transition: sourceIndex >= 0 ? "transform 180ms ease" : void 0
6940
- };
6941
- }
6942
-
6943
6058
  // src/features/toolbar/style.css
6944
- styleInject(".react-list-table-shell {\n background: #fff;\n font-size: 14px;\n}\n.react-list-table-titlebar {\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0;\n box-sizing: border-box;\n background: #fff;\n}\n.react-list-table-shell-fullscreen {\n width: 100% !important;\n height: 100% !important;\n}\n.react-list-table-shell-fullscreen .canvas-list-table-root {\n height: 100% !important;\n}\n.react-list-table-title {\n min-width: 0;\n color: #1f2937;\n font-size: 14px;\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-tools {\n display: flex;\n align-items: center;\n gap: 14px;\n color: #475569;\n}\n.react-list-table-tool-wrap {\n position: relative;\n display: inline-flex;\n}\n.react-list-table-tool {\n width: 20px;\n height: 24px;\n padding: 0;\n border: 0;\n color: inherit;\n background: transparent;\n font: 16px/24px sans-serif;\n cursor: pointer;\n}\n.react-list-table-tool:hover {\n color: #1677ff;\n}\n.react-list-table-tool-menu,\n.react-list-table-column-setting {\n position: absolute;\n z-index: 120;\n top: 28px;\n right: 0;\n min-width: 112px;\n padding: 6px;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n background: #fff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.14);\n}\n.react-list-table-tool-menu button {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: #374151;\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n}\n.react-list-table-tool-menu {\n width: max-content;\n min-width: 0;\n padding: 8px;\n border-radius: 8px;\n}\n.react-list-table-tool-menu-check {\n width: 16px;\n flex: 0 0 16px;\n margin-right: 6px;\n text-align: center;\n}\n.react-list-table-tool-menu button:hover {\n background: #f3f4f6;\n}\n.react-list-table-column-setting {\n width: 328px;\n max-height: 360px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n.react-list-table-column-setting-head {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: 4px 6px 8px;\n border-bottom: 1px solid #f0f0f0;\n flex: 0 0 auto;\n}\n.react-list-table-column-setting-head button {\n border: 0;\n color: #1677ff;\n background: transparent;\n cursor: pointer;\n}\n.react-list-table-column-setting-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n.react-list-table-column-item {\n display: flex;\n align-items: center;\n gap: 8px;\n justify-content: space-between;\n padding: 7px 6px;\n box-sizing: border-box;\n cursor: pointer;\n}\n.react-list-table-column-position {\n flex: 0 0 28px;\n text-align: center;\n color: #64748b;\n font-variant-numeric: tabular-nums;\n}\n.react-list-table-column-main,\n.react-list-table-column-actions {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.react-list-table-column-main {\n min-width: 0;\n}\n.react-list-table-column-actions {\n flex: 0 0 auto;\n}\n.react-list-table-column-actions > .canvas-react-select-wrap {\n flex: 0 0 96px;\n width: 96px;\n height: 24px;\n}\n.react-list-table-column-label {\n min-width: 64px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-column-width-input {\n height: 22px;\n padding-inline: 5px;\n}\n.react-list-table-column-fixed-input {\n height: 22px;\n padding-inline: 6px;\n font-size: 14px;\n}\n.react-list-table-column-sort-input {\n height: 22px;\n padding-inline: 6px;\n font-size: 14px;\n}\n.react-list-table-column-setting label.dragging {\n opacity: 0.45;\n background: #e6f4ff;\n}\n.react-list-table-column-setting [data-sortable-key].dragging {\n opacity: 0.28;\n}\n.react-list-table-column-drag {\n touch-action: none;\n color: #94a3b8;\n display: inline-flex;\n font-size: 14px;\n cursor: grab;\n user-select: none;\n}\nbody.react-list-table-sorting,\nbody.react-list-table-sorting * {\n cursor: grabbing !important;\n}\n.react-list-table-sort-overlay {\n position: fixed;\n z-index: 1400;\n display: block;\n padding: 0;\n box-sizing: border-box;\n color: #334155;\n background: #fff;\n border: 1px solid #91caff;\n border-radius: 6px;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);\n pointer-events: none;\n}\n.react-list-table-sort-overlay .react-list-table-column-item {\n width: 100%;\n height: 100%;\n}\n");
6059
+ styleInject(".react-list-table-shell {\n background: #fff;\n font-size: 14px;\n}\n.react-list-table-titlebar {\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0;\n box-sizing: border-box;\n background: #fff;\n}\n.react-list-table-shell-fullscreen {\n width: 100% !important;\n height: 100% !important;\n}\n.react-list-table-shell-fullscreen .canvas-list-table-root {\n height: 100% !important;\n}\n.react-list-table-title {\n min-width: 0;\n color: #1f2937;\n font-size: 14px;\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-tools {\n display: flex;\n align-items: center;\n gap: 14px;\n color: #475569;\n}\n.react-list-table-tool-wrap {\n position: relative;\n display: inline-flex;\n}\n.react-list-table-tool {\n width: 20px;\n height: 24px;\n padding: 0;\n border: 0;\n color: inherit;\n background: transparent;\n font: 16px/24px sans-serif;\n cursor: pointer;\n}\n.react-list-table-tool:hover {\n color: #1677ff;\n}\n.react-list-table-tool-menu,\n.react-list-table-column-setting {\n position: absolute;\n z-index: 120;\n top: 28px;\n right: 0;\n min-width: 112px;\n padding: 6px;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n background: #fff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.14);\n}\n.react-list-table-tool-menu button {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: #374151;\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n}\n.react-list-table-tool-menu {\n width: max-content;\n min-width: 0;\n padding: 8px;\n border-radius: 8px;\n}\n.react-list-table-tool-menu-check {\n width: 16px;\n flex: 0 0 16px;\n margin-right: 6px;\n text-align: center;\n}\n.react-list-table-tool-menu button:hover {\n background: #f3f4f6;\n}\n.react-list-table-column-setting {\n width: 328px;\n max-height: 360px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n.react-list-table-column-setting-head {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: 4px 6px 8px;\n border-bottom: 1px solid #f0f0f0;\n flex: 0 0 auto;\n}\n.react-list-table-column-setting-head button {\n border: 0;\n color: #1677ff;\n background: transparent;\n cursor: pointer;\n}\n.react-list-table-column-setting-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n.react-list-table-column-item {\n display: flex;\n align-items: center;\n gap: 8px;\n justify-content: space-between;\n padding: 7px 6px;\n box-sizing: border-box;\n cursor: pointer;\n}\n.react-list-table-column-position {\n flex: 0 0 28px;\n text-align: center;\n color: #64748b;\n font-variant-numeric: tabular-nums;\n}\n.react-list-table-column-main,\n.react-list-table-column-actions {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.react-list-table-column-main {\n min-width: 0;\n}\n.react-list-table-column-actions {\n flex: 0 0 auto;\n}\n.react-list-table-column-actions > .canvas-react-select-wrap {\n flex: 0 0 96px;\n width: 96px;\n height: 24px;\n}\n.react-list-table-column-label {\n min-width: 64px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.react-list-table-column-width-input {\n height: 22px;\n padding-inline: 5px;\n}\n.react-list-table-column-fixed-input {\n height: 22px;\n padding-inline: 6px;\n font-size: 14px;\n}\n.react-list-table-column-sort-input {\n height: 22px;\n padding-inline: 6px;\n font-size: 14px;\n}\n.react-list-table-column-drag {\n touch-action: none;\n color: #94a3b8;\n display: inline-flex;\n font-size: 14px;\n cursor: grab;\n user-select: none;\n}\n.canvas-react-sort-overlay .react-list-table-column-item {\n width: 100%;\n height: 100%;\n}\n");
6945
6060
  function ReactTableToolbar(props) {
6946
6061
  const { toolbar, title } = props;
6947
6062
  const [densityOpen, setDensityOpen] = react.useState(false);
@@ -7072,18 +6187,17 @@ function ReactTableToolbar(props) {
7072
6187
  children: [
7073
6188
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-list-table-column-setting-head", children: [
7074
6189
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "\u5217\u8BBE\u7F6E" }),
7075
- /* @__PURE__ */ jsxRuntime.jsx(
6190
+ props.columnSettingsCacheAvailable ? /* @__PURE__ */ jsxRuntime.jsx(
7076
6191
  reactComponents.ReactCheckbox,
7077
6192
  {
7078
6193
  checked: props.cacheColumnSettings === true,
7079
- disabled: !props.columnSettingsCacheAvailable,
7080
- title: props.columnSettingsCacheAvailable ? "\u7F13\u5B58\u5217\u5BBD\u3001\u663E\u9690\u3001\u56FA\u5B9A\u548C\u987A\u5E8F" : "\u914D\u7F6E storageKey \u540E\u53EF\u7F13\u5B58\u5217\u8BBE\u7F6E",
6194
+ title: "\u7F13\u5B58\u5217\u5BBD\u3001\u663E\u9690\u3001\u56FA\u5B9A\u548C\u987A\u5E8F",
7081
6195
  onChange: (event) => props.onColumnSettingsCacheChange?.(
7082
6196
  event.target.checked
7083
6197
  ),
7084
6198
  children: "\u7F13\u5B58\u5230\u672C\u5730"
7085
6199
  }
7086
- ),
6200
+ ) : null,
7087
6201
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: "auto" }, children: config.columnSettingHeaderExtra }),
7088
6202
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: props.onResetColumns, children: "\u91CD\u7F6E" })
7089
6203
  ] }),
@@ -7093,13 +6207,15 @@ function ReactTableToolbar(props) {
7093
6207
  ref: columnSettingsBodyRef,
7094
6208
  className: "react-list-table-column-setting-body canvas-react-scrollbar",
7095
6209
  children: /* @__PURE__ */ jsxRuntime.jsx(
7096
- SortableList,
6210
+ reactComponents.ReactSortableList,
7097
6211
  {
7098
6212
  scrollContainerRef: columnSettingsBodyRef,
7099
- items: flattenColumns(props.columns).map((column, index) => ({
7100
- ...column,
7101
- position: index + 1
7102
- })),
6213
+ items: flattenColumns(props.columns).map(
6214
+ (column, index) => ({
6215
+ ...column,
6216
+ position: index + 1
6217
+ })
6218
+ ),
7103
6219
  onOrderChange: props.onColumnOrderChange,
7104
6220
  renderItem: (column, handleProps) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-list-table-column-item", children: [
7105
6221
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7147,13 +6263,12 @@ function ReactTableToolbar(props) {
7147
6263
  ),
7148
6264
  !column.isGroup ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "react-list-table-column-actions", children: [
7149
6265
  /* @__PURE__ */ jsxRuntime.jsx(
7150
- reactComponents.ReactNumberInput,
6266
+ reactComponents.ReactInputNumber,
7151
6267
  {
7152
6268
  className: "react-list-table-column-width-input",
7153
6269
  min: column.minWidth,
7154
6270
  max: column.maxWidth,
7155
6271
  value: column.width,
7156
- allowClear: false,
7157
6272
  "aria-label": `${column.label}\u5217\u5BBD`,
7158
6273
  style: { width: 80, height: 24 },
7159
6274
  onChange: (width) => {
@@ -7526,6 +6641,12 @@ function resolveReactListTableDebugOptions(debug, inheritedEnabled) {
7526
6641
  };
7527
6642
  }
7528
6643
 
6644
+ // src/components/fullscreen-portal.ts
6645
+ function resolveFullscreenPortalContainer(host) {
6646
+ const fullscreenElement = document.fullscreenElement;
6647
+ return fullscreenElement instanceof HTMLElement && host && fullscreenElement.contains(host) ? fullscreenElement : document.body;
6648
+ }
6649
+
7529
6650
  // src/components/column-manager-state.ts
7530
6651
  function applyColumnManagerState(columns, visibility, orders, config, parentKey = "root") {
7531
6652
  const order = orders.get(parentKey);
@@ -7899,13 +7020,61 @@ function ReactListTableInner(props, ref) {
7899
7020
  closeDangerConfirmRequest
7900
7021
  } = useReactListTableState(options);
7901
7022
  const hasPagination = paginationConfig != null;
7902
- const [printSource, setPrintSource] = react.useState(null);
7023
+ const [printRequest, setPrintRequest] = react.useState(null);
7024
+ const [savedPrintTemplates, setSavedPrintTemplates] = react.useState([]);
7025
+ const printStoreKey = storageKey ? `list:${storageKey}` : void 0;
7026
+ const printMenuOpen = Boolean(headerContextMenuRequest);
7027
+ react.useEffect(() => {
7028
+ if (!printMenuOpen || !printStoreKey) {
7029
+ setSavedPrintTemplates([]);
7030
+ return;
7031
+ }
7032
+ let disposed = false;
7033
+ void reactPrintDesign.readPrintDesignTemplates(printStoreKey).then((versions) => {
7034
+ if (!disposed) setSavedPrintTemplates(versions);
7035
+ }).catch(() => {
7036
+ if (!disposed) setSavedPrintTemplates([]);
7037
+ });
7038
+ return () => {
7039
+ disposed = true;
7040
+ };
7041
+ }, [printMenuOpen, printStoreKey]);
7042
+ const latestSavedTemplates = [
7043
+ ...new Set(savedPrintTemplates.map((item) => item.templateId))
7044
+ ].map((templateId) => {
7045
+ const versions = savedPrintTemplates.filter(
7046
+ (item) => item.templateId === templateId
7047
+ );
7048
+ return versions[versions.length - 1];
7049
+ });
7050
+ const printTemplateChoices = [
7051
+ { key: "base", label: "\u8868\u683C\u6253\u5370\u6A21\u677F" },
7052
+ ...props.printPresets?.map((item, index) => ({
7053
+ key: `preset:${index}`,
7054
+ label: item.name
7055
+ })) ?? [],
7056
+ ...props.printTemplates?.map((item, index) => ({
7057
+ key: `document:${index}`,
7058
+ label: item.name
7059
+ })) ?? [],
7060
+ ...latestSavedTemplates.map((item) => ({
7061
+ key: `saved:${item.id}`,
7062
+ label: `${item.document.name} (v${item.version})`
7063
+ }))
7064
+ ];
7065
+ const [cacheConfigOpen, setCacheConfigOpen] = react.useState(false);
7903
7066
  const paginationLayout = resolveReactListTablePaginationLayout(resolvedRowHeight);
7904
7067
  const portalContainer = resolveFullscreenPortalContainer(shellRef.current);
7905
7068
  react.useImperativeHandle(
7906
7069
  ref,
7907
7070
  () => ({
7908
7071
  validate: () => tableRef.current?.validate() ?? Promise.resolve([]),
7072
+ setValidationErrors: (errors) => {
7073
+ tableRef.current?.setValidationErrors(errors);
7074
+ },
7075
+ clearValidationErrors: (targets) => {
7076
+ tableRef.current?.clearValidationErrors(targets);
7077
+ },
7909
7078
  exportXlsx: (options2) => {
7910
7079
  tableRef.current?.exportXlsx(options2);
7911
7080
  },
@@ -8066,7 +7235,7 @@ function ReactListTableInner(props, ref) {
8066
7235
  }
8067
7236
  ),
8068
7237
  tooltipRequest ? reactDom.createPortal(
8069
- /* @__PURE__ */ jsxRuntime.jsx(ReactTableTooltipView, { request: tooltipRequest }),
7238
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactTooltip, { request: tooltipRequest }),
8070
7239
  portalContainer
8071
7240
  ) : null,
8072
7241
  filterPanelRequest ? reactDom.createPortal(
@@ -8081,29 +7250,58 @@ function ReactListTableInner(props, ref) {
8081
7250
  /* @__PURE__ */ jsxRuntime.jsx(
8082
7251
  ReactTableContextMenuView,
8083
7252
  {
7253
+ printTemplates: printTemplateChoices,
7254
+ onPrintTemplate: (key) => {
7255
+ const request = headerContextMenuRequest;
7256
+ if (!request?.onGetPrintData) return;
7257
+ request.onClose();
7258
+ void runDirectPrint(
7259
+ portalContainer,
7260
+ request.onGetPrintData,
7261
+ (source) => {
7262
+ const document2 = key.startsWith("saved:") ? savedPrintTemplates.find((item) => item.id === key.slice(6))?.document : key.startsWith("preset:") ? createTableDocument(
7263
+ { ...source, rows: [] },
7264
+ props.printPresets?.[Number(key.slice(7))]
7265
+ ) : key.startsWith("document:") ? props.printTemplates?.[Number(key.slice(9))] : createTableDocument({ ...source, rows: [] });
7266
+ if (!document2) throw new Error("\u627E\u4E0D\u5230\u6253\u5370\u6A21\u677F");
7267
+ return document2;
7268
+ },
7269
+ (source, document2, data) => {
7270
+ if (!reactPrintDesign.isPrintDesignDocumentCompatible(document2, data))
7271
+ throw new Error("\u6253\u5370\u6A21\u677F\u5DF2\u5931\u6548");
7272
+ if (key.startsWith("saved:") && reactPrintDesign.isPrintDesignTemplateInvalid(
7273
+ savedPrintTemplates.find(
7274
+ (item) => item.id === key.slice(6)
7275
+ ),
7276
+ getPrintSourceFormat(source),
7277
+ data
7278
+ ))
7279
+ throw new Error("\u6253\u5370\u6A21\u677F\u5DF2\u5931\u6548");
7280
+ },
7281
+ props.directPrintPagesPerBatch
7282
+ );
7283
+ },
7284
+ onViewCacheConfig: () => {
7285
+ headerContextMenuRequest?.onClose();
7286
+ setCacheConfigOpen(true);
7287
+ },
8084
7288
  onPrint: () => {
8085
7289
  const getPrintData = headerContextMenuRequest?.onGetPrintData;
8086
7290
  if (!getPrintData) return;
8087
- void Promise.resolve(getPrintData()).then(
8088
- (source) => setPrintSource(source)
8089
- );
7291
+ setPrintRequest({ loadSource: getPrintData });
8090
7292
  headerContextMenuRequest?.onClose();
8091
7293
  },
8092
7294
  onDirectPrint: () => {
8093
7295
  const request = headerContextMenuRequest;
8094
7296
  if (!request?.onGetPrintData) return;
8095
7297
  request.onClose();
8096
- void Promise.resolve(request.onGetPrintData()).then(
8097
- (source) => createCachedPrintTableOptions(
8098
- source,
8099
- storageKey ? `list:${storageKey}` : void 0,
8100
- props.printPresets
8101
- )
8102
- ).then((options2) => {
8103
- print.printBrowserTable(options2);
8104
- }).catch((error) => {
8105
- console.error("\u76F4\u63A5\u6253\u5370\u5931\u8D25", error);
8106
- });
7298
+ void runDirectPrint(
7299
+ portalContainer,
7300
+ request.onGetPrintData,
7301
+ void 0,
7302
+ void 0,
7303
+ props.directPrintPagesPerBatch
7304
+ );
8107
7305
  },
8108
7306
  request: headerContextMenuRequest ? {
8109
7307
  ...headerContextMenuRequest,
@@ -8125,14 +7323,25 @@ function ReactListTableInner(props, ref) {
8125
7323
  ),
8126
7324
  portalContainer
8127
7325
  ),
8128
- printSource ? reactDom.createPortal(
7326
+ printRequest ? reactDom.createPortal(
8129
7327
  /* @__PURE__ */ jsxRuntime.jsx(
8130
- ReactListTablePrintDialog,
7328
+ ReactListTablePrintDesignDialog,
8131
7329
  {
8132
- source: printSource,
7330
+ loadSource: printRequest.loadSource,
7331
+ storeKey: storageKey ? `list:${storageKey}` : void 0,
8133
7332
  printPresets: props.printPresets,
8134
- storageKey: storageKey ? `list:${storageKey}` : void 0,
8135
- onClose: () => setPrintSource(null),
7333
+ printTemplates: props.printTemplates,
7334
+ onClose: () => setPrintRequest(null)
7335
+ }
7336
+ ),
7337
+ portalContainer
7338
+ ) : null,
7339
+ cacheConfigOpen && storageKey ? reactDom.createPortal(
7340
+ /* @__PURE__ */ jsxRuntime.jsx(
7341
+ ReactListTableCacheConfigDialog,
7342
+ {
7343
+ storageKey,
7344
+ onClose: () => setCacheConfigOpen(false),
8136
7345
  renderTable: (tableProps) => /* @__PURE__ */ jsxRuntime.jsx(ReactListTable, { ...tableProps })
8137
7346
  }
8138
7347
  ),