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

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,14 @@
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 printDesign = require('@canvas-components/print-design');
13
+ var print = require('@canvas-components/print');
12
14
 
13
15
  // #style-inject:#style-inject
14
16
  function styleInject(css, { insertAt } = {}) {
@@ -33,7 +35,7 @@ function styleInject(css, { insertAt } = {}) {
33
35
  }
34
36
 
35
37
  // 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");
38
+ 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
39
  var conditionalOperators = {
38
40
  eq: "\u7B49\u4E8E",
39
41
  neq: "\u4E0D\u7B49\u4E8E",
@@ -949,11 +951,20 @@ function ReactTableContextMenuView(props) {
949
951
  }
950
952
  ),
951
953
  /* @__PURE__ */ jsxRuntime.jsx(ResetMenu, { request }),
952
- buildCacheMenuItems(request).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
954
+ request.columnSettingsCacheAvailable === true && buildCacheMenuItems(request).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
953
955
  MenuSubmenu,
954
956
  {
955
957
  label: "\u7F13\u5B58\u5230\u672C\u5730",
956
- items: buildCacheMenuItems(request)
958
+ items: [
959
+ ...buildCacheMenuItems(request),
960
+ {
961
+ key: "view-cache-config",
962
+ label: "\u67E5\u770B\u7F13\u5B58\u914D\u7F6E",
963
+ separatorBefore: true,
964
+ disabled: request.columnSettingsCacheAvailable !== true,
965
+ onClick: props.onViewCacheConfig
966
+ }
967
+ ]
957
968
  }
958
969
  ) : null
959
970
  ]
@@ -1050,22 +1061,41 @@ function ReactTableContextMenuView(props) {
1050
1061
  }
1051
1062
  ),
1052
1063
  /* @__PURE__ */ jsxRuntime.jsx(MenuAction, { label: "\u67E5\u627E", onClick: request.onOpenSearch }),
1053
- /* @__PURE__ */ jsxRuntime.jsx(
1064
+ request.onPrint ? /* @__PURE__ */ jsxRuntime.jsx(
1065
+ MenuAction,
1066
+ {
1067
+ label: "\u6253\u5370",
1068
+ onClick: () => {
1069
+ setMenuOpen(false);
1070
+ request.onPrint?.();
1071
+ }
1072
+ }
1073
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1054
1074
  MenuSubmenu,
1055
1075
  {
1056
1076
  label: "\u6253\u5370",
1057
1077
  items: [
1058
- {
1059
- key: "print-direct",
1060
- label: "\u76F4\u63A5\u6253\u5370",
1061
- onClick: request.onGetPrintData ? () => {
1078
+ ...props.printTemplates && props.printTemplates.length > 1 ? props.printTemplates.map((template) => ({
1079
+ key: `print-template-${template.key}`,
1080
+ label: `\u76F4\u63A5\u6253\u5370 ${template.label}`,
1081
+ disabled: template.disabled,
1082
+ onClick: template.disabled ? void 0 : () => {
1062
1083
  setMenuOpen(false);
1063
- props.onDirectPrint?.();
1064
- } : void 0
1065
- },
1084
+ props.onPrintTemplate?.(template.key);
1085
+ }
1086
+ })) : [
1087
+ {
1088
+ key: "print-direct",
1089
+ label: "\u76F4\u63A5\u6253\u5370",
1090
+ onClick: request.onGetPrintData ? () => {
1091
+ setMenuOpen(false);
1092
+ props.onDirectPrint?.();
1093
+ } : void 0
1094
+ }
1095
+ ],
1066
1096
  {
1067
1097
  key: "print-configure",
1068
- label: "\u6253\u5370\u914D\u7F6E",
1098
+ label: "\u6253\u5370\u8BBE\u8BA1",
1069
1099
  onClick: request.onGetPrintData ? () => {
1070
1100
  setMenuOpen(false);
1071
1101
  props.onPrint?.();
@@ -1074,6 +1104,14 @@ function ReactTableContextMenuView(props) {
1074
1104
  ]
1075
1105
  }
1076
1106
  ),
1107
+ request.customItems?.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1108
+ CustomContextMenuItem,
1109
+ {
1110
+ item,
1111
+ onClose: () => setMenuOpen(false)
1112
+ },
1113
+ item.key
1114
+ )),
1077
1115
  /* @__PURE__ */ jsxRuntime.jsx(
1078
1116
  MenuAction,
1079
1117
  {
@@ -1348,13 +1386,21 @@ function ReactTableContextMenuView(props) {
1348
1386
  }
1349
1387
  ),
1350
1388
  /* @__PURE__ */ jsxRuntime.jsx(ZoomMenu, { value: request.zoom ?? 1, onChange: request.onChangeZoom }),
1351
- /* @__PURE__ */ jsxRuntime.jsx(
1389
+ request.columnSettingsCacheAvailable === true ? /* @__PURE__ */ jsxRuntime.jsx(
1352
1390
  MenuSubmenu,
1353
1391
  {
1354
1392
  label: "\u7F13\u5B58\u5230\u672C\u5730",
1355
- items: buildCacheMenuItems(request)
1393
+ items: [
1394
+ ...buildCacheMenuItems(request),
1395
+ {
1396
+ key: "view-cache-config",
1397
+ label: "\u67E5\u770B\u7F13\u5B58\u914D\u7F6E",
1398
+ separatorBefore: true,
1399
+ onClick: props.onViewCacheConfig
1400
+ }
1401
+ ]
1356
1402
  }
1357
- ),
1403
+ ) : null,
1358
1404
  request.columns && request.onToggleColumn ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1359
1405
  /* @__PURE__ */ jsxRuntime.jsx(MenuDivider, {}),
1360
1406
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1499,6 +1545,31 @@ function MenuAction(props) {
1499
1545
  }
1500
1546
  );
1501
1547
  }
1548
+ function CustomContextMenuItem(props) {
1549
+ const { item, onClose } = props;
1550
+ const children = item.children?.filter(Boolean) ?? [];
1551
+ if (children.length > 0) {
1552
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuSubmenu, { label: item.label, items: [], minWidth: 240, children: children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
1553
+ CustomContextMenuItem,
1554
+ {
1555
+ item: child,
1556
+ onClose
1557
+ },
1558
+ child.key
1559
+ )) });
1560
+ }
1561
+ return /* @__PURE__ */ jsxRuntime.jsx(
1562
+ MenuAction,
1563
+ {
1564
+ label: item.label,
1565
+ disabled: item.disabled,
1566
+ onClick: item.disabled ? void 0 : () => {
1567
+ onClose();
1568
+ item.onClick?.();
1569
+ }
1570
+ }
1571
+ );
1572
+ }
1502
1573
  function MenuSubmenu(props) {
1503
1574
  const { label, items, header, footer, children, minWidth = 220 } = props;
1504
1575
  const menuItems = items.filter((item) => item.onClick || item.disabled);
@@ -3458,6 +3529,107 @@ var moreFormatChoiceSelectedStyle = {
3458
3529
  background: "#f3f4f6",
3459
3530
  color: "#1677ff"
3460
3531
  };
3532
+ function ReactListTableCacheConfigDialog(props) {
3533
+ const [rows, setRows] = react.useState([]);
3534
+ const [config, setConfig] = react.useState(null);
3535
+ const [loading, setLoading] = react.useState(true);
3536
+ react.useEffect(() => {
3537
+ let active = true;
3538
+ setLoading(true);
3539
+ void listTable.getListTableStoredColumnConfig(props.storageKey).then((config2) => {
3540
+ if (!active) return;
3541
+ setConfig(config2 ?? null);
3542
+ setRows(
3543
+ config2 ? createCacheConfigRows(config2) : []
3544
+ );
3545
+ setLoading(false);
3546
+ });
3547
+ return () => {
3548
+ active = false;
3549
+ };
3550
+ }, [props.storageKey]);
3551
+ const removeRow = (key) => {
3552
+ if (!config) return;
3553
+ const next = removeCacheConfigKey(config, key);
3554
+ setConfig(next);
3555
+ setRows((current) => current.filter((row) => row.key !== key));
3556
+ void listTable.saveListTableStoredColumnConfig(props.storageKey, next);
3557
+ };
3558
+ return /* @__PURE__ */ jsxRuntime.jsx(
3559
+ reactComponents.ReactModal,
3560
+ {
3561
+ open: true,
3562
+ title: "\u7F13\u5B58\u914D\u7F6E",
3563
+ width: 1180,
3564
+ fullscreenable: true,
3565
+ onCancel: props.onClose,
3566
+ footer: false,
3567
+ 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({
3568
+ tableId: "list-table-cache-config",
3569
+ columns: [
3570
+ {
3571
+ key: "key",
3572
+ dataIndex: "key",
3573
+ title: "\u914D\u7F6E\u9879",
3574
+ width: 190,
3575
+ cellStyle: { verticalAlign: "top" }
3576
+ },
3577
+ {
3578
+ key: "value",
3579
+ dataIndex: "value",
3580
+ title: "\u7F13\u5B58\u503C",
3581
+ width: 850,
3582
+ cellType: "json",
3583
+ cellStyle: {
3584
+ verticalAlign: "top",
3585
+ fontFamily: "monospace",
3586
+ fontSize: 12
3587
+ }
3588
+ },
3589
+ {
3590
+ key: "operation",
3591
+ dataIndex: "key",
3592
+ title: "\u64CD\u4F5C",
3593
+ width: 90,
3594
+ render: (_value, row) => ({
3595
+ type: "button",
3596
+ text: "\u79FB\u9664",
3597
+ buttonType: "link",
3598
+ size: "small",
3599
+ danger: true,
3600
+ popconfirm: {
3601
+ title: "\u786E\u8BA4\u79FB\u9664\u7F13\u5B58\u914D\u7F6E\u5417\uFF1F",
3602
+ description: `\u5C06\u79FB\u9664\u201C${row.key}\u201D\u914D\u7F6E\u9879\u3002`,
3603
+ okText: "\u79FB\u9664",
3604
+ cancelText: "\u53D6\u6D88"
3605
+ },
3606
+ cursor: "pointer",
3607
+ onClick: () => removeRow(row.key)
3608
+ })
3609
+ }
3610
+ ],
3611
+ dataSource: rows,
3612
+ rowKey: "key",
3613
+ rowHeight: "auto",
3614
+ pagination: false,
3615
+ toolbar: false,
3616
+ contextMenu: false,
3617
+ style: { width: "100%", height: "min(68vh, 620px)" }
3618
+ })
3619
+ }
3620
+ );
3621
+ }
3622
+ function createCacheConfigRows(config) {
3623
+ return Object.entries(config).map(([key, value]) => ({
3624
+ key,
3625
+ value
3626
+ }));
3627
+ }
3628
+ function removeCacheConfigKey(config, key) {
3629
+ const next = { ...config };
3630
+ delete next[key];
3631
+ return next;
3632
+ }
3461
3633
  var SEARCH_MODAL_BODY_STYLE = {
3462
3634
  padding: 12
3463
3635
  };
@@ -3835,6 +4007,8 @@ function ReactListTableExportNameDialog({
3835
4007
  if (request.columns && !selectedKeys.length) return setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
3836
4008
  if (request.columns && cacheEnabled) {
3837
4009
  writeExportCache(storageKey, { version: 1, rows, selectedKeys: selectedKeys.map(String), includeSummary });
4010
+ } else if (request.columns) {
4011
+ writeExportCache(storageKey, null);
3838
4012
  }
3839
4013
  request.onConfirm(
3840
4014
  `${fileName.trim()}${extension}`,
@@ -3990,32 +4164,6 @@ function createPrintColumns(columns, summaryColumns = []) {
3990
4164
  };
3991
4165
  });
3992
4166
  }
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
4167
  function restorePrintColumns(columns, settings) {
4020
4168
  const current = new Map(columns.map((column) => [column.key, column]));
4021
4169
  const restored = [];
@@ -4028,1578 +4176,254 @@ function restorePrintColumns(columns, settings) {
4028
4176
  return [...restored, ...current.values()];
4029
4177
  }
4030
4178
  function resolvePrintSelectedKeys(sourceColumns, presetConfig, cached) {
4031
- const cachedColumnKeys = new Set(cached?.columns.map((column) => column.key));
4179
+ new Set(cached?.columns.map((column) => column.key));
4032
4180
  const presetKeys = presetConfig?.selectedKeys ? new Set(presetConfig.selectedKeys) : null;
4033
4181
  return sourceColumns.filter((column) => {
4034
- if (cached) {
4035
- return cachedColumnKeys.has(column.key) ? cached.selectedKeys.includes(column.key) : true;
4036
- }
4037
4182
  if (presetKeys) return presetKeys.has(column.key);
4038
4183
  return true;
4039
4184
  }).map((column) => column.key);
4040
4185
  }
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 };
4186
+ function createTableDocument(source, preset) {
4187
+ const config = preset?.config;
4188
+ const page = printDesign.createPrintDesignPage("\u8868\u683C\u6253\u5370");
4189
+ const [paperWidth, paperHeight] = print.BROWSER_PRINT_PAPER_SIZES[config?.paperSize ?? "a4"];
4190
+ page.width = config?.orientation === "landscape" ? paperHeight : paperWidth;
4191
+ page.height = config?.orientation === "landscape" ? paperWidth : paperHeight;
4192
+ page.orientation = config?.orientation ?? "portrait";
4193
+ page.margins = config?.pageMargins ?? page.margins;
4194
+ const selectedKeys = resolvePrintSelectedKeys(source.columns, config);
4050
4195
  const columns = restorePrintColumns(
4051
- restorePrintColumns(
4052
- createPrintColumns(source.columns, source.summaryColumns),
4053
- config?.columns ? { columns: config.columns } : null
4054
- ),
4055
- cached
4056
- );
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
- }
4196
+ createPrintColumns(source.columns, source.summaryColumns),
4197
+ config?.columns ? { columns: config.columns } : null
4198
+ ).filter((column) => selectedKeys.includes(column.key));
4199
+ const left = page.margins?.left ?? 10;
4200
+ const right = page.margins?.right ?? 10;
4201
+ const bottom = page.margins?.bottom ?? 10;
4202
+ const contentWidth = page.width - left - right;
4203
+ const widthSum = columns.reduce((sum, column) => sum + column.width, 0);
4204
+ const rowHeight = config?.rowHeight ?? 8;
4205
+ const footerY = page.height - bottom - 6;
4206
+ const tableY = 28;
4207
+ const tableHeight = footerY - tableY - 8;
4208
+ const rowsPerPage = Math.max(1, Math.floor((tableHeight - 9) / rowHeight));
4209
+ const pageCount = Math.max(1, Math.ceil(source.rows.length / rowsPerPage));
4210
+ const printedAt = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN");
4211
+ const pages = Array.from(
4212
+ { length: pageCount },
4213
+ (_, index) => ({
4214
+ ...page,
4215
+ id: index === 0 ? page.id : printDesign.createPrintDesignPage().id,
4216
+ name: `\u8868\u683C\u6253\u5370 ${index + 1}`,
4217
+ elements: [
4218
+ {
4219
+ id: `list-table-title-${index}`,
4220
+ type: "text",
4221
+ name: "\u6807\u9898",
4222
+ x: left,
4223
+ y: 12,
4224
+ width: contentWidth,
4225
+ height: 10,
4226
+ text: config?.title ?? "\u8868\u683C\u6253\u5370",
4227
+ fontSize: config?.titleFontSize ?? 18,
4228
+ fontWeight: "700",
4229
+ textAlign: "center"
4230
+ },
4231
+ {
4232
+ id: `list-table-data-${index}`,
4233
+ type: "table",
4234
+ name: "\u8868\u683C\u6570\u636E",
4235
+ x: left,
4236
+ y: tableY,
4237
+ width: contentWidth,
4238
+ height: tableHeight,
4239
+ dataMode: "binding",
4240
+ dataPath: `listTable.pages.${index}.rows`,
4241
+ dataSource: [],
4242
+ columns: columns.map((column) => ({
4243
+ key: column.key,
4244
+ title: column.title,
4245
+ dataIndex: column.key,
4246
+ width: widthSum > 0 ? Math.max(24, column.width / widthSum * 720) : 120,
4247
+ align: column.align
4248
+ })),
4249
+ rowHeight,
4250
+ headerRowHeight: 9,
4251
+ showHeader: true
4252
+ },
4253
+ {
4254
+ id: `list-table-print-time-${index}`,
4255
+ type: "text",
4256
+ name: "\u6253\u5370\u65F6\u95F4",
4257
+ x: left,
4258
+ y: footerY,
4259
+ width: contentWidth / 2,
4260
+ height: 6,
4261
+ text: `\u6253\u5370\u65F6\u95F4\uFF1A${printedAt}`,
4262
+ fontSize: 9,
4263
+ color: "#000000"
4264
+ },
4265
+ {
4266
+ id: `list-table-page-number-${index}`,
4267
+ type: "text",
4268
+ name: "\u5206\u9875\u4FE1\u606F",
4269
+ x: left + contentWidth / 2,
4270
+ y: footerY,
4271
+ width: contentWidth / 2,
4272
+ height: 6,
4273
+ text: `\u7B2C ${index + 1} \u9875 / \u5171 ${pageCount} \u9875`,
4274
+ textAlign: "right",
4275
+ fontSize: 9,
4276
+ color: "#000000"
4277
+ }
4278
+ ]
4279
+ })
4093
4280
  );
4281
+ return printDesign.createPrintDesignDocument({
4282
+ name: preset?.name ?? "\u8868\u683C\u6253\u5370\u6A21\u677F",
4283
+ pages
4284
+ });
4094
4285
  }
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])
4286
+ function mapPrintSourceRows(source) {
4287
+ return source.rows.map(
4288
+ (row) => Object.fromEntries(
4289
+ source.columns.map((column, index) => [column.key, row[index] ?? ""])
4290
+ )
4100
4291
  );
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
- ])
4292
+ }
4293
+ function createTableData(source, document2, rows = mapPrintSourceRows(source)) {
4294
+ const firstTable = document2.pages[0]?.elements.find(
4295
+ (item) => item.type === "table"
4112
4296
  );
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;
4297
+ const rowsPerPage = firstTable?.type === "table" ? Math.max(
4298
+ 1,
4299
+ Math.floor(
4300
+ (firstTable.height - (firstTable.showHeader === false ? 0 : firstTable.headerRowHeight ?? 9)) / (firstTable.rowHeight ?? 8)
4301
+ )
4302
+ ) : Math.max(1, Math.ceil(rows.length / document2.pages.length));
4121
4303
  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"
4304
+ listTable: {
4305
+ rows,
4306
+ columns: source.columns.map((column) => ({ key: column.key })),
4307
+ pages: document2.pages.map((_, index) => ({
4308
+ rows: rows.slice(index * rowsPerPage, (index + 1) * rowsPerPage)
4309
+ }))
4310
+ }
4163
4311
  };
4164
4312
  }
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"
4313
+ function getPrintSourceFormat(source) {
4314
+ return JSON.stringify(
4315
+ source.columns.map((column) => String(column.key)).sort()
4216
4316
  );
4217
- const [subtitle, setSubtitle] = react.useState(
4218
- cached?.subtitle ?? initialConfig?.subtitle ?? ""
4317
+ }
4318
+ function printTableTemplate(source, popup, document2 = createTableDocument(source)) {
4319
+ const data = createTableData(source, document2);
4320
+ printDesign.printPrintDesignHtml(popup, printDesign.transformPrintDesignToHtml(document2, { data }));
4321
+ return true;
4322
+ }
4323
+ function ReactListTablePrintDesignDialog(props) {
4324
+ const [fullscreen, setFullscreen] = react.useState(true);
4325
+ const document2 = react.useMemo(
4326
+ () => createTableDocument(props.source),
4327
+ [props.source]
4219
4328
  );
4220
- const [titleFontSize, setTitleFontSize] = react.useState(
4221
- cached?.titleFontSize ?? initialConfig?.titleFontSize ?? 18
4329
+ const [boundDocument, setBoundDocument] = react.useState(document2);
4330
+ const rows = react.useMemo(() => mapPrintSourceRows(props.source), [props.source]);
4331
+ const defaultTemplates = react.useMemo(
4332
+ () => [
4333
+ document2,
4334
+ ...props.printPresets?.map(
4335
+ (preset) => createTableDocument(props.source, preset)
4336
+ ) ?? [],
4337
+ ...props.printTemplates ?? []
4338
+ ],
4339
+ [document2, props.printPresets, props.printTemplates, props.source]
4222
4340
  );
4223
- const [subtitleFontSize, setSubtitleFontSize] = react.useState(
4224
- cached?.subtitleFontSize ?? initialConfig?.subtitleFontSize ?? 12
4341
+ const data = react.useMemo(
4342
+ () => createTableData(props.source, boundDocument, rows),
4343
+ [props.source, boundDocument, rows]
4225
4344
  );
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"
4345
+ return /* @__PURE__ */ jsxRuntime.jsx(
4346
+ reactComponents.ReactModal,
4347
+ {
4348
+ open: true,
4349
+ fullscreen,
4350
+ closable: false,
4351
+ fullscreenable: false,
4352
+ footer: false,
4353
+ width: "min(96vw, 1440px)",
4354
+ style: { height: fullscreen ? "100%" : "min(88vh, 900px)" },
4355
+ bodyStyle: { padding: 0, overflow: "hidden", display: "flex" },
4356
+ onCancel: props.onClose,
4357
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4358
+ reactPrintDesign.ReactPrintDesign,
4359
+ {
4360
+ document: document2,
4361
+ defaultTemplates,
4362
+ data,
4363
+ dataFormatKey: getPrintSourceFormat(props.source),
4364
+ onChange: setBoundDocument,
4365
+ storeKey: props.storeKey,
4366
+ fullscreen,
4367
+ onFullscreenChange: setFullscreen,
4368
+ onClose: props.onClose,
4369
+ style: { flex: 1 }
4370
+ }
4230
4371
  )
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
4240
- );
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
4248
4372
  }
4249
4373
  );
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
4280
- );
4281
- const [formItemSpacing, setFormItemSpacing] = react.useState(
4282
- cached?.formItemSpacing ?? initialConfig?.formItemSpacing ?? 4
4283
- );
4284
- const [cacheEnabled, setCacheEnabled] = react.useState(Boolean(props.storageKey));
4285
- 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)
4323
- );
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
- react.useEffect(() => {
4356
- const updateViewport = () => {
4357
- setPreviewViewport({
4358
- width: window.innerWidth,
4359
- height: window.innerHeight
4360
- });
4361
- };
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");
4424
- }
4425
- }, [showPageNumbers, showPrintTime, pageNumberPosition, printTimePosition]);
4426
- const createCurrentPrintOptions = () => configurePrintTable(
4427
- props.source,
4428
- columns,
4429
- selectedKeys.map(String),
4430
- rowsPerPage,
4431
- {
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
4451
- }
4452
- );
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"
4525
- )
4526
- )
4527
- );
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
- };
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
4622
- });
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 }
4636
- },
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"
4653
- },
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"
4670
- },
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"
4759
- }
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%"
4817
- },
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
- ]
4823
- }
4824
- ),
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
- }
5546
- )
5547
- ]
5548
- }
5549
- );
5550
- }
5551
-
5552
- // src/features/editor/utils.ts
5553
- function toNumberValue(value) {
5554
- if (typeof value === "number" && Number.isFinite(value)) {
5555
- return value;
5556
- }
5557
- if (typeof value === "string" && value.trim().length > 0) {
5558
- const nextValue = Number(value);
5559
- return Number.isFinite(nextValue) ? nextValue : null;
5560
- }
5561
- return null;
5562
- }
5563
- function toNumericProp(value) {
5564
- if (typeof value === "number") {
5565
- return value;
5566
- }
5567
- if (typeof value === "string" && value.trim().length > 0) {
5568
- const nextValue = Number(value);
5569
- return Number.isFinite(nextValue) ? nextValue : void 0;
5570
- }
5571
- return void 0;
5572
- }
5573
- function resolvePadding(value, fallback = 0) {
5574
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
5575
- }
5576
- function resolveEditorControlSize(request) {
5577
- const targetRect = request.hostRect ?? request.rect;
5578
- const height = Math.max(targetRect.height - 2, 1);
5579
- const fontSize = typeof request.theme.fontSize === "number" && Number.isFinite(request.theme.fontSize) && request.theme.fontSize > 0 ? request.theme.fontSize : void 0;
5580
- const paddingInline = resolvePadding(request.theme.paddingInline);
5581
- const paddingBlock = resolvePadding(request.theme.paddingBlock);
5582
- const contentZoom = typeof request.theme.contentZoom === "number" && Number.isFinite(request.theme.contentZoom) && request.theme.contentZoom > 0 ? request.theme.contentZoom : 1;
5583
- return { height, fontSize, paddingInline, paddingBlock, contentZoom };
5584
- }
5585
- function getEditorInputStyle(request) {
5586
- const { height, fontSize, paddingInline, paddingBlock, contentZoom } = resolveEditorControlSize(request);
5587
- return {
5588
- width: "100%",
5589
- height,
5590
- minHeight: height,
5591
- color: request.theme.cellColor ?? request.theme.textColor,
5592
- fontFamily: request.theme.fontFamily,
5593
- fontSize,
5594
- // 用像素 token,确保 select/time/color 触发器与内部 Input 同步缩放。
5595
- ["--canvas-react-control-height"]: `${height}px`,
5596
- ["--canvas-react-font-size"]: fontSize != null ? `${fontSize}px` : void 0,
5597
- ["--canvas-react-control-padding-inline"]: `${paddingInline}px`,
5598
- ["--canvas-react-control-padding-block"]: `${paddingBlock}px`,
5599
- ["--canvas-react-content-zoom"]: String(contentZoom),
5600
- ["--canvas-react-radius-sm"]: "0px",
5601
- borderRadius: 0,
5602
- boxSizing: "border-box"
4374
+ }
4375
+
4376
+ // src/features/editor/utils.ts
4377
+ function toNumberValue(value) {
4378
+ if (typeof value === "number" && Number.isFinite(value)) {
4379
+ return value;
4380
+ }
4381
+ if (typeof value === "string" && value.trim().length > 0) {
4382
+ const nextValue = Number(value);
4383
+ return Number.isFinite(nextValue) ? nextValue : null;
4384
+ }
4385
+ return null;
4386
+ }
4387
+ function toNumericProp(value) {
4388
+ if (typeof value === "number") {
4389
+ return value;
4390
+ }
4391
+ if (typeof value === "string" && value.trim().length > 0) {
4392
+ const nextValue = Number(value);
4393
+ return Number.isFinite(nextValue) ? nextValue : void 0;
4394
+ }
4395
+ return void 0;
4396
+ }
4397
+ function resolvePadding(value, fallback = 0) {
4398
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
4399
+ }
4400
+ function resolveEditorControlSize(request) {
4401
+ const targetRect = request.hostRect ?? request.rect;
4402
+ const height = Math.max(targetRect.height - 2, 1);
4403
+ const fontSize = typeof request.theme.fontSize === "number" && Number.isFinite(request.theme.fontSize) && request.theme.fontSize > 0 ? request.theme.fontSize : void 0;
4404
+ const paddingInline = resolvePadding(request.theme.paddingInline);
4405
+ const paddingBlock = resolvePadding(request.theme.paddingBlock);
4406
+ const contentZoom = typeof request.theme.contentZoom === "number" && Number.isFinite(request.theme.contentZoom) && request.theme.contentZoom > 0 ? request.theme.contentZoom : 1;
4407
+ return { height, fontSize, paddingInline, paddingBlock, contentZoom };
4408
+ }
4409
+ function getEditorInputStyle(request) {
4410
+ const { height, fontSize, paddingInline, paddingBlock, contentZoom } = resolveEditorControlSize(request);
4411
+ return {
4412
+ width: "100%",
4413
+ height,
4414
+ minHeight: height,
4415
+ color: request.theme.cellColor ?? request.theme.textColor,
4416
+ fontFamily: request.theme.fontFamily,
4417
+ fontSize,
4418
+ // 用像素 token,确保 select/time/color 触发器与内部 Input 同步缩放。
4419
+ ["--canvas-react-control-height"]: `${height}px`,
4420
+ ["--canvas-react-font-size"]: fontSize != null ? `${fontSize}px` : void 0,
4421
+ ["--canvas-react-control-padding-inline"]: `${paddingInline}px`,
4422
+ ["--canvas-react-control-padding-block"]: `${paddingBlock}px`,
4423
+ ["--canvas-react-content-zoom"]: String(contentZoom),
4424
+ ["--canvas-react-radius-sm"]: "0px",
4425
+ borderRadius: 0,
4426
+ boxSizing: "border-box"
5603
4427
  };
5604
4428
  }
5605
4429
  function resolveEditorOverlayStyle(params) {
@@ -5635,6 +4459,16 @@ function resolveEditorOverlayStyle(params) {
5635
4459
  function ReactTableEditorOverlay(props) {
5636
4460
  const { request } = props;
5637
4461
  const editorHostRef = react.useRef(null);
4462
+ const wheelCommittedRef = react.useRef(false);
4463
+ const editorRequest = {
4464
+ ...request,
4465
+ onCommit: (options) => {
4466
+ if (!wheelCommittedRef.current) request.onCommit(options);
4467
+ }
4468
+ };
4469
+ react.useEffect(() => {
4470
+ wheelCommittedRef.current = false;
4471
+ }, [request.editorKey]);
5638
4472
  const style = resolveEditorOverlayStyle({
5639
4473
  rect: request.rect,
5640
4474
  hostRect: request.hostRect,
@@ -5651,7 +4485,26 @@ function ReactTableEditorOverlay(props) {
5651
4485
  }
5652
4486
  focusAndSelectEditorInput(input, request.selectOnFocus);
5653
4487
  }, [request]);
5654
- return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorHostRef, children: renderEditorByType(request, style) }, request.editorKey) });
4488
+ react.useEffect(() => {
4489
+ const host = editorHostRef.current;
4490
+ if (!host) return;
4491
+ const valueType = request.config.valueType ?? "text";
4492
+ if (valueType !== "text" && valueType !== "number" && valueType !== "input-range") {
4493
+ return;
4494
+ }
4495
+ const handleWheel = (event) => {
4496
+ event.preventDefault();
4497
+ event.stopPropagation();
4498
+ if (!wheelCommittedRef.current) {
4499
+ wheelCommittedRef.current = true;
4500
+ request.onCommit();
4501
+ }
4502
+ request.onWheel?.(event);
4503
+ };
4504
+ host.addEventListener("wheel", handleWheel, { passive: false });
4505
+ return () => host.removeEventListener("wheel", handleWheel);
4506
+ }, [request]);
4507
+ return /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorHostRef, children: renderEditorByType(editorRequest, style) }, request.editorKey) });
5655
4508
  }
5656
4509
  function renderEditorByType(request, style) {
5657
4510
  switch (request.config.valueType ?? "text") {
@@ -6703,245 +5556,8 @@ function HolderOutlined() {
6703
5556
  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
5557
  }
6705
5558
 
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
5559
  // 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");
5560
+ 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
5561
  function ReactTableToolbar(props) {
6946
5562
  const { toolbar, title } = props;
6947
5563
  const [densityOpen, setDensityOpen] = react.useState(false);
@@ -7072,18 +5688,17 @@ function ReactTableToolbar(props) {
7072
5688
  children: [
7073
5689
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-list-table-column-setting-head", children: [
7074
5690
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "\u5217\u8BBE\u7F6E" }),
7075
- /* @__PURE__ */ jsxRuntime.jsx(
5691
+ props.columnSettingsCacheAvailable ? /* @__PURE__ */ jsxRuntime.jsx(
7076
5692
  reactComponents.ReactCheckbox,
7077
5693
  {
7078
5694
  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",
5695
+ title: "\u7F13\u5B58\u5217\u5BBD\u3001\u663E\u9690\u3001\u56FA\u5B9A\u548C\u987A\u5E8F",
7081
5696
  onChange: (event) => props.onColumnSettingsCacheChange?.(
7082
5697
  event.target.checked
7083
5698
  ),
7084
5699
  children: "\u7F13\u5B58\u5230\u672C\u5730"
7085
5700
  }
7086
- ),
5701
+ ) : null,
7087
5702
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: "auto" }, children: config.columnSettingHeaderExtra }),
7088
5703
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: props.onResetColumns, children: "\u91CD\u7F6E" })
7089
5704
  ] }),
@@ -7093,13 +5708,15 @@ function ReactTableToolbar(props) {
7093
5708
  ref: columnSettingsBodyRef,
7094
5709
  className: "react-list-table-column-setting-body canvas-react-scrollbar",
7095
5710
  children: /* @__PURE__ */ jsxRuntime.jsx(
7096
- SortableList,
5711
+ reactComponents.ReactSortableList,
7097
5712
  {
7098
5713
  scrollContainerRef: columnSettingsBodyRef,
7099
- items: flattenColumns(props.columns).map((column, index) => ({
7100
- ...column,
7101
- position: index + 1
7102
- })),
5714
+ items: flattenColumns(props.columns).map(
5715
+ (column, index) => ({
5716
+ ...column,
5717
+ position: index + 1
5718
+ })
5719
+ ),
7103
5720
  onOrderChange: props.onColumnOrderChange,
7104
5721
  renderItem: (column, handleProps) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-list-table-column-item", children: [
7105
5722
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7526,6 +6143,12 @@ function resolveReactListTableDebugOptions(debug, inheritedEnabled) {
7526
6143
  };
7527
6144
  }
7528
6145
 
6146
+ // src/components/fullscreen-portal.ts
6147
+ function resolveFullscreenPortalContainer(host) {
6148
+ const fullscreenElement = document.fullscreenElement;
6149
+ return fullscreenElement instanceof HTMLElement && host && fullscreenElement.contains(host) ? fullscreenElement : document.body;
6150
+ }
6151
+
7529
6152
  // src/components/column-manager-state.ts
7530
6153
  function applyColumnManagerState(columns, visibility, orders, config, parentKey = "root") {
7531
6154
  const order = orders.get(parentKey);
@@ -7900,12 +6523,102 @@ function ReactListTableInner(props, ref) {
7900
6523
  } = useReactListTableState(options);
7901
6524
  const hasPagination = paginationConfig != null;
7902
6525
  const [printSource, setPrintSource] = react.useState(null);
6526
+ const [savedPrintTemplates, setSavedPrintTemplates] = react.useState([]);
6527
+ const [printMenuSource, setPrintMenuSource] = react.useState(null);
6528
+ const printStoreKey = storageKey ? `list:${storageKey}` : void 0;
6529
+ const printMenuOpen = Boolean(headerContextMenuRequest);
6530
+ react.useEffect(() => {
6531
+ if (!printMenuOpen || !printStoreKey) {
6532
+ setSavedPrintTemplates([]);
6533
+ return;
6534
+ }
6535
+ let disposed = false;
6536
+ void reactPrintDesign.readPrintDesignTemplates(printStoreKey).then((versions) => {
6537
+ if (!disposed) setSavedPrintTemplates(versions);
6538
+ }).catch(() => {
6539
+ if (!disposed) setSavedPrintTemplates([]);
6540
+ });
6541
+ return () => {
6542
+ disposed = true;
6543
+ };
6544
+ }, [printMenuOpen, printStoreKey]);
6545
+ react.useEffect(() => {
6546
+ if (!printMenuOpen) {
6547
+ setPrintMenuSource(null);
6548
+ return;
6549
+ }
6550
+ const getPrintData = headerContextMenuRequest?.onGetPrintData;
6551
+ if (!getPrintData) return;
6552
+ let disposed = false;
6553
+ void Promise.resolve(getPrintData()).then((source) => {
6554
+ if (!disposed) setPrintMenuSource(source);
6555
+ }).catch(() => {
6556
+ if (!disposed) setPrintMenuSource(null);
6557
+ });
6558
+ return () => {
6559
+ disposed = true;
6560
+ };
6561
+ }, [printMenuOpen]);
6562
+ const printDataFormat = printMenuSource ? getPrintSourceFormat(printMenuSource) : void 0;
6563
+ const printMenuRows = react.useMemo(
6564
+ () => printMenuSource ? mapPrintSourceRows(printMenuSource) : [],
6565
+ [printMenuSource]
6566
+ );
6567
+ const latestSavedTemplates = [
6568
+ ...new Set(savedPrintTemplates.map((item) => item.templateId))
6569
+ ].map((templateId) => {
6570
+ const versions = savedPrintTemplates.filter(
6571
+ (item) => item.templateId === templateId
6572
+ );
6573
+ return versions[versions.length - 1];
6574
+ });
6575
+ const printTemplateChoices = [
6576
+ { key: "base", label: "\u8868\u683C\u6253\u5370\u6A21\u677F" },
6577
+ ...props.printPresets?.map((item, index) => ({
6578
+ key: `preset:${index}`,
6579
+ label: item.name
6580
+ })) ?? [],
6581
+ ...props.printTemplates?.map((item, index) => {
6582
+ const invalid = Boolean(
6583
+ printMenuSource && !reactPrintDesign.isPrintDesignDocumentCompatible(
6584
+ item,
6585
+ createTableData(printMenuSource, item, printMenuRows)
6586
+ )
6587
+ );
6588
+ return {
6589
+ key: `document:${index}`,
6590
+ label: `${item.name}${invalid ? "\uFF08\u5DF2\u5931\u6548\uFF09" : ""}`,
6591
+ disabled: invalid
6592
+ };
6593
+ }) ?? [],
6594
+ ...latestSavedTemplates.map((item) => {
6595
+ const invalid = Boolean(
6596
+ printMenuSource && reactPrintDesign.isPrintDesignTemplateInvalid(
6597
+ item,
6598
+ printDataFormat,
6599
+ createTableData(printMenuSource, item.document, printMenuRows)
6600
+ )
6601
+ );
6602
+ return {
6603
+ key: `saved:${item.id}`,
6604
+ label: `${item.document.name} (v${item.version})${invalid ? "\uFF08\u5DF2\u5931\u6548\uFF09" : ""}`,
6605
+ disabled: invalid
6606
+ };
6607
+ })
6608
+ ];
6609
+ const [cacheConfigOpen, setCacheConfigOpen] = react.useState(false);
7903
6610
  const paginationLayout = resolveReactListTablePaginationLayout(resolvedRowHeight);
7904
6611
  const portalContainer = resolveFullscreenPortalContainer(shellRef.current);
7905
6612
  react.useImperativeHandle(
7906
6613
  ref,
7907
6614
  () => ({
7908
6615
  validate: () => tableRef.current?.validate() ?? Promise.resolve([]),
6616
+ setValidationErrors: (errors) => {
6617
+ tableRef.current?.setValidationErrors(errors);
6618
+ },
6619
+ clearValidationErrors: (targets) => {
6620
+ tableRef.current?.clearValidationErrors(targets);
6621
+ },
7909
6622
  exportXlsx: (options2) => {
7910
6623
  tableRef.current?.exportXlsx(options2);
7911
6624
  },
@@ -8081,27 +6794,56 @@ function ReactListTableInner(props, ref) {
8081
6794
  /* @__PURE__ */ jsxRuntime.jsx(
8082
6795
  ReactTableContextMenuView,
8083
6796
  {
6797
+ printTemplates: printTemplateChoices,
6798
+ onPrintTemplate: (key) => {
6799
+ const request = headerContextMenuRequest;
6800
+ if (!request?.onGetPrintData) return;
6801
+ request.onClose();
6802
+ const popup = window.open("", "_blank");
6803
+ if (!popup) return;
6804
+ void Promise.resolve(request.onGetPrintData()).then((source) => {
6805
+ const document2 = key.startsWith("saved:") ? savedPrintTemplates.find((item) => item.id === key.slice(6))?.document : key.startsWith("preset:") ? createTableDocument(
6806
+ source,
6807
+ props.printPresets?.[Number(key.slice(7))]
6808
+ ) : key.startsWith("document:") ? props.printTemplates?.[Number(key.slice(9))] : createTableDocument(source);
6809
+ if (!document2) throw new Error("\u627E\u4E0D\u5230\u6253\u5370\u6A21\u677F");
6810
+ const data = createTableData(source, document2);
6811
+ if (!reactPrintDesign.isPrintDesignDocumentCompatible(document2, data))
6812
+ throw new Error("\u6253\u5370\u6A21\u677F\u5DF2\u5931\u6548");
6813
+ if (key.startsWith("saved:") && reactPrintDesign.isPrintDesignTemplateInvalid(
6814
+ savedPrintTemplates.find(
6815
+ (item) => item.id === key.slice(6)
6816
+ ),
6817
+ getPrintSourceFormat(source),
6818
+ data
6819
+ ))
6820
+ throw new Error("\u6253\u5370\u6A21\u677F\u5DF2\u5931\u6548");
6821
+ printTableTemplate(source, popup, document2);
6822
+ }).catch((error) => {
6823
+ popup.close();
6824
+ console.error("\u76F4\u63A5\u6253\u5370\u5931\u8D25", error);
6825
+ });
6826
+ },
6827
+ onViewCacheConfig: () => {
6828
+ headerContextMenuRequest?.onClose();
6829
+ setCacheConfigOpen(true);
6830
+ },
8084
6831
  onPrint: () => {
8085
6832
  const getPrintData = headerContextMenuRequest?.onGetPrintData;
8086
6833
  if (!getPrintData) return;
8087
- void Promise.resolve(getPrintData()).then(
8088
- (source) => setPrintSource(source)
8089
- );
6834
+ void Promise.resolve(getPrintData()).then(setPrintSource);
8090
6835
  headerContextMenuRequest?.onClose();
8091
6836
  },
8092
6837
  onDirectPrint: () => {
8093
6838
  const request = headerContextMenuRequest;
8094
6839
  if (!request?.onGetPrintData) return;
8095
6840
  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);
6841
+ const popup = window.open("", "_blank");
6842
+ if (!popup) return;
6843
+ void Promise.resolve(request.onGetPrintData()).then((source) => {
6844
+ printTableTemplate(source, popup);
8104
6845
  }).catch((error) => {
6846
+ popup.close();
8105
6847
  console.error("\u76F4\u63A5\u6253\u5370\u5931\u8D25", error);
8106
6848
  });
8107
6849
  },
@@ -8127,12 +6869,23 @@ function ReactListTableInner(props, ref) {
8127
6869
  ),
8128
6870
  printSource ? reactDom.createPortal(
8129
6871
  /* @__PURE__ */ jsxRuntime.jsx(
8130
- ReactListTablePrintDialog,
6872
+ ReactListTablePrintDesignDialog,
8131
6873
  {
8132
6874
  source: printSource,
6875
+ storeKey: storageKey ? `list:${storageKey}` : void 0,
8133
6876
  printPresets: props.printPresets,
8134
- storageKey: storageKey ? `list:${storageKey}` : void 0,
8135
- onClose: () => setPrintSource(null),
6877
+ printTemplates: props.printTemplates,
6878
+ onClose: () => setPrintSource(null)
6879
+ }
6880
+ ),
6881
+ portalContainer
6882
+ ) : null,
6883
+ cacheConfigOpen && storageKey ? reactDom.createPortal(
6884
+ /* @__PURE__ */ jsxRuntime.jsx(
6885
+ ReactListTableCacheConfigDialog,
6886
+ {
6887
+ storageKey,
6888
+ onClose: () => setCacheConfigOpen(false),
8136
6889
  renderTable: (tableProps) => /* @__PURE__ */ jsxRuntime.jsx(ReactListTable, { ...tableProps })
8137
6890
  }
8138
6891
  ),