@canvas-components/react-list-table 0.3.44 → 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.js CHANGED
@@ -1,13 +1,15 @@
1
1
  import { createContext, memo, forwardRef, useMemo, useRef, useState, useEffect, useImperativeHandle, useLayoutEffect, useContext, useId, Fragment as Fragment$1 } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
- import { getSharedScrollbarSettings, subscribeSharedScrollbarSettings, setSharedScrollbarSettings, ReactImagePreview, ReactCheckbox, ReactNumberInput, ReactSelect, ReactPagination, ReactFilterPanel, ReactPopup, ReactScrollbarSettingsDialog, ReactScrollbarPositionDialog, ReactModal, ReactForm, ReactInput, ReactRadio, ReactColorPicker, ReactButton, ReactVirtualList, ReactPopconfirm, ReactContentScaleProvider, ReactInputNumber, resolveReactScrollbarMode, ReactAutoComplete, ReactTimeRangePicker, ReactDateTimeRangePicker, ReactDateTimePicker, ReactTimePicker, ReactDateRangePicker, ReactDatePicker, ReactMonthPicker, ReactQuarterPicker, ReactYearPicker, ReactInputRange, ReactCascader, ReactTreeSelect } from '@canvas-components/react-components';
4
- import { printBrowserTable, getBrowserPrintLayoutWarning, getBrowserPrintRowLayoutWarning, BROWSER_PRINT_PAPER_SIZES, calculateBrowserPrintRowsPerPage, calculateBrowserPrintColumnWidths, createBrowserPrintPreviewHtml } from '@canvas-components/print';
5
- import { EXPAND_COLUMN, SELECTION_COLUMN, ROW_SELECTION_COLUMN, resetListTableStoredColumnConfig, ListTable } from '@canvas-components/list-table';
3
+ import { getSharedScrollbarSettings, subscribeSharedScrollbarSettings, setSharedScrollbarSettings, ReactImagePreview, ReactCheckbox, ReactSortableList, ReactNumberInput, ReactSelect, ReactPagination, ReactFilterPanel, ReactPopup, ReactScrollbarSettingsDialog, ReactScrollbarPositionDialog, ReactModal, ReactInput, ReactPopconfirm, ReactContentScaleProvider, ReactButton, ReactColorPicker, ReactInputNumber, resolveReactScrollbarMode, ReactAutoComplete, ReactTimeRangePicker, ReactDateTimeRangePicker, ReactDateTimePicker, ReactTimePicker, ReactDateRangePicker, ReactDatePicker, ReactMonthPicker, ReactQuarterPicker, ReactYearPicker, ReactInputRange, ReactCascader, ReactTreeSelect } from '@canvas-components/react-components';
4
+ import { readPrintDesignTemplates, isPrintDesignDocumentCompatible, isPrintDesignTemplateInvalid, ReactPrintDesign } from '@canvas-components/react-print-design';
5
+ import { EXPAND_COLUMN, SELECTION_COLUMN, ROW_SELECTION_COLUMN, resetListTableStoredColumnConfig, ListTable, getListTableStoredColumnConfig, saveListTableStoredColumnConfig } from '@canvas-components/list-table';
6
6
  export { EXPAND_COLUMN, ROW_SELECTION_COLUMN, SELECTION_COLUMN, getListTableStoredPageSize } from '@canvas-components/list-table';
7
7
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
8
8
  import { CanvasChart } from '@canvas-components/chart';
9
9
  import { formatDateTimeValue, isDateTimeFormatPattern } from '@canvas-components/utils/date';
10
10
  import { formatNumberValue, formatPercentValue, formatScientificValue, formatCustomNumberPattern } from '@canvas-components/utils/number';
11
+ import { printPrintDesignHtml, transformPrintDesignToHtml, createPrintDesignPage, createPrintDesignDocument } from '@canvas-components/print-design';
12
+ import { BROWSER_PRINT_PAPER_SIZES } from '@canvas-components/print';
11
13
 
12
14
  // #style-inject:#style-inject
13
15
  function styleInject(css, { insertAt } = {}) {
@@ -32,7 +34,7 @@ function styleInject(css, { insertAt } = {}) {
32
34
  }
33
35
 
34
36
  // src/styles/table-overrides.css
35
- 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");
37
+ 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");
36
38
  var conditionalOperators = {
37
39
  eq: "\u7B49\u4E8E",
38
40
  neq: "\u4E0D\u7B49\u4E8E",
@@ -948,11 +950,20 @@ function ReactTableContextMenuView(props) {
948
950
  }
949
951
  ),
950
952
  /* @__PURE__ */ jsx(ResetMenu, { request }),
951
- buildCacheMenuItems(request).length > 0 ? /* @__PURE__ */ jsx(
953
+ request.columnSettingsCacheAvailable === true && buildCacheMenuItems(request).length > 0 ? /* @__PURE__ */ jsx(
952
954
  MenuSubmenu,
953
955
  {
954
956
  label: "\u7F13\u5B58\u5230\u672C\u5730",
955
- items: buildCacheMenuItems(request)
957
+ items: [
958
+ ...buildCacheMenuItems(request),
959
+ {
960
+ key: "view-cache-config",
961
+ label: "\u67E5\u770B\u7F13\u5B58\u914D\u7F6E",
962
+ separatorBefore: true,
963
+ disabled: request.columnSettingsCacheAvailable !== true,
964
+ onClick: props.onViewCacheConfig
965
+ }
966
+ ]
956
967
  }
957
968
  ) : null
958
969
  ]
@@ -1049,22 +1060,41 @@ function ReactTableContextMenuView(props) {
1049
1060
  }
1050
1061
  ),
1051
1062
  /* @__PURE__ */ jsx(MenuAction, { label: "\u67E5\u627E", onClick: request.onOpenSearch }),
1052
- /* @__PURE__ */ jsx(
1063
+ request.onPrint ? /* @__PURE__ */ jsx(
1064
+ MenuAction,
1065
+ {
1066
+ label: "\u6253\u5370",
1067
+ onClick: () => {
1068
+ setMenuOpen(false);
1069
+ request.onPrint?.();
1070
+ }
1071
+ }
1072
+ ) : /* @__PURE__ */ jsx(
1053
1073
  MenuSubmenu,
1054
1074
  {
1055
1075
  label: "\u6253\u5370",
1056
1076
  items: [
1057
- {
1058
- key: "print-direct",
1059
- label: "\u76F4\u63A5\u6253\u5370",
1060
- onClick: request.onGetPrintData ? () => {
1077
+ ...props.printTemplates && props.printTemplates.length > 1 ? props.printTemplates.map((template) => ({
1078
+ key: `print-template-${template.key}`,
1079
+ label: `\u76F4\u63A5\u6253\u5370 ${template.label}`,
1080
+ disabled: template.disabled,
1081
+ onClick: template.disabled ? void 0 : () => {
1061
1082
  setMenuOpen(false);
1062
- props.onDirectPrint?.();
1063
- } : void 0
1064
- },
1083
+ props.onPrintTemplate?.(template.key);
1084
+ }
1085
+ })) : [
1086
+ {
1087
+ key: "print-direct",
1088
+ label: "\u76F4\u63A5\u6253\u5370",
1089
+ onClick: request.onGetPrintData ? () => {
1090
+ setMenuOpen(false);
1091
+ props.onDirectPrint?.();
1092
+ } : void 0
1093
+ }
1094
+ ],
1065
1095
  {
1066
1096
  key: "print-configure",
1067
- label: "\u6253\u5370\u914D\u7F6E",
1097
+ label: "\u6253\u5370\u8BBE\u8BA1",
1068
1098
  onClick: request.onGetPrintData ? () => {
1069
1099
  setMenuOpen(false);
1070
1100
  props.onPrint?.();
@@ -1073,6 +1103,14 @@ function ReactTableContextMenuView(props) {
1073
1103
  ]
1074
1104
  }
1075
1105
  ),
1106
+ request.customItems?.map((item) => /* @__PURE__ */ jsx(
1107
+ CustomContextMenuItem,
1108
+ {
1109
+ item,
1110
+ onClose: () => setMenuOpen(false)
1111
+ },
1112
+ item.key
1113
+ )),
1076
1114
  /* @__PURE__ */ jsx(
1077
1115
  MenuAction,
1078
1116
  {
@@ -1347,13 +1385,21 @@ function ReactTableContextMenuView(props) {
1347
1385
  }
1348
1386
  ),
1349
1387
  /* @__PURE__ */ jsx(ZoomMenu, { value: request.zoom ?? 1, onChange: request.onChangeZoom }),
1350
- /* @__PURE__ */ jsx(
1388
+ request.columnSettingsCacheAvailable === true ? /* @__PURE__ */ jsx(
1351
1389
  MenuSubmenu,
1352
1390
  {
1353
1391
  label: "\u7F13\u5B58\u5230\u672C\u5730",
1354
- items: buildCacheMenuItems(request)
1392
+ items: [
1393
+ ...buildCacheMenuItems(request),
1394
+ {
1395
+ key: "view-cache-config",
1396
+ label: "\u67E5\u770B\u7F13\u5B58\u914D\u7F6E",
1397
+ separatorBefore: true,
1398
+ onClick: props.onViewCacheConfig
1399
+ }
1400
+ ]
1355
1401
  }
1356
- ),
1402
+ ) : null,
1357
1403
  request.columns && request.onToggleColumn ? /* @__PURE__ */ jsxs(Fragment, { children: [
1358
1404
  /* @__PURE__ */ jsx(MenuDivider, {}),
1359
1405
  /* @__PURE__ */ jsx(
@@ -1498,6 +1544,31 @@ function MenuAction(props) {
1498
1544
  }
1499
1545
  );
1500
1546
  }
1547
+ function CustomContextMenuItem(props) {
1548
+ const { item, onClose } = props;
1549
+ const children = item.children?.filter(Boolean) ?? [];
1550
+ if (children.length > 0) {
1551
+ return /* @__PURE__ */ jsx(MenuSubmenu, { label: item.label, items: [], minWidth: 240, children: children.map((child) => /* @__PURE__ */ jsx(
1552
+ CustomContextMenuItem,
1553
+ {
1554
+ item: child,
1555
+ onClose
1556
+ },
1557
+ child.key
1558
+ )) });
1559
+ }
1560
+ return /* @__PURE__ */ jsx(
1561
+ MenuAction,
1562
+ {
1563
+ label: item.label,
1564
+ disabled: item.disabled,
1565
+ onClick: item.disabled ? void 0 : () => {
1566
+ onClose();
1567
+ item.onClick?.();
1568
+ }
1569
+ }
1570
+ );
1571
+ }
1501
1572
  function MenuSubmenu(props) {
1502
1573
  const { label, items, header, footer, children, minWidth = 220 } = props;
1503
1574
  const menuItems = items.filter((item) => item.onClick || item.disabled);
@@ -3457,6 +3528,107 @@ var moreFormatChoiceSelectedStyle = {
3457
3528
  background: "#f3f4f6",
3458
3529
  color: "#1677ff"
3459
3530
  };
3531
+ function ReactListTableCacheConfigDialog(props) {
3532
+ const [rows, setRows] = useState([]);
3533
+ const [config, setConfig] = useState(null);
3534
+ const [loading, setLoading] = useState(true);
3535
+ useEffect(() => {
3536
+ let active = true;
3537
+ setLoading(true);
3538
+ void getListTableStoredColumnConfig(props.storageKey).then((config2) => {
3539
+ if (!active) return;
3540
+ setConfig(config2 ?? null);
3541
+ setRows(
3542
+ config2 ? createCacheConfigRows(config2) : []
3543
+ );
3544
+ setLoading(false);
3545
+ });
3546
+ return () => {
3547
+ active = false;
3548
+ };
3549
+ }, [props.storageKey]);
3550
+ const removeRow = (key) => {
3551
+ if (!config) return;
3552
+ const next = removeCacheConfigKey(config, key);
3553
+ setConfig(next);
3554
+ setRows((current) => current.filter((row) => row.key !== key));
3555
+ void saveListTableStoredColumnConfig(props.storageKey, next);
3556
+ };
3557
+ return /* @__PURE__ */ jsx(
3558
+ ReactModal,
3559
+ {
3560
+ open: true,
3561
+ title: "\u7F13\u5B58\u914D\u7F6E",
3562
+ width: 1180,
3563
+ fullscreenable: true,
3564
+ onCancel: props.onClose,
3565
+ footer: false,
3566
+ children: loading ? /* @__PURE__ */ jsx("div", { style: { padding: 24, textAlign: "center", color: "#64748b" }, children: "\u6B63\u5728\u8BFB\u53D6\u7F13\u5B58\u914D\u7F6E\u2026" }) : rows.length === 0 ? /* @__PURE__ */ jsx("div", { style: { padding: 24, textAlign: "center", color: "#64748b" }, children: "\u5F53\u524D\u6CA1\u6709\u7F13\u5B58\u914D\u7F6E" }) : props.renderTable({
3567
+ tableId: "list-table-cache-config",
3568
+ columns: [
3569
+ {
3570
+ key: "key",
3571
+ dataIndex: "key",
3572
+ title: "\u914D\u7F6E\u9879",
3573
+ width: 190,
3574
+ cellStyle: { verticalAlign: "top" }
3575
+ },
3576
+ {
3577
+ key: "value",
3578
+ dataIndex: "value",
3579
+ title: "\u7F13\u5B58\u503C",
3580
+ width: 850,
3581
+ cellType: "json",
3582
+ cellStyle: {
3583
+ verticalAlign: "top",
3584
+ fontFamily: "monospace",
3585
+ fontSize: 12
3586
+ }
3587
+ },
3588
+ {
3589
+ key: "operation",
3590
+ dataIndex: "key",
3591
+ title: "\u64CD\u4F5C",
3592
+ width: 90,
3593
+ render: (_value, row) => ({
3594
+ type: "button",
3595
+ text: "\u79FB\u9664",
3596
+ buttonType: "link",
3597
+ size: "small",
3598
+ danger: true,
3599
+ popconfirm: {
3600
+ title: "\u786E\u8BA4\u79FB\u9664\u7F13\u5B58\u914D\u7F6E\u5417\uFF1F",
3601
+ description: `\u5C06\u79FB\u9664\u201C${row.key}\u201D\u914D\u7F6E\u9879\u3002`,
3602
+ okText: "\u79FB\u9664",
3603
+ cancelText: "\u53D6\u6D88"
3604
+ },
3605
+ cursor: "pointer",
3606
+ onClick: () => removeRow(row.key)
3607
+ })
3608
+ }
3609
+ ],
3610
+ dataSource: rows,
3611
+ rowKey: "key",
3612
+ rowHeight: "auto",
3613
+ pagination: false,
3614
+ toolbar: false,
3615
+ contextMenu: false,
3616
+ style: { width: "100%", height: "min(68vh, 620px)" }
3617
+ })
3618
+ }
3619
+ );
3620
+ }
3621
+ function createCacheConfigRows(config) {
3622
+ return Object.entries(config).map(([key, value]) => ({
3623
+ key,
3624
+ value
3625
+ }));
3626
+ }
3627
+ function removeCacheConfigKey(config, key) {
3628
+ const next = { ...config };
3629
+ delete next[key];
3630
+ return next;
3631
+ }
3460
3632
  var SEARCH_MODAL_BODY_STYLE = {
3461
3633
  padding: 12
3462
3634
  };
@@ -3834,6 +4006,8 @@ function ReactListTableExportNameDialog({
3834
4006
  if (request.columns && !selectedKeys.length) return setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
3835
4007
  if (request.columns && cacheEnabled) {
3836
4008
  writeExportCache(storageKey, { version: 1, rows, selectedKeys: selectedKeys.map(String), includeSummary });
4009
+ } else if (request.columns) {
4010
+ writeExportCache(storageKey, null);
3837
4011
  }
3838
4012
  request.onConfirm(
3839
4013
  `${fileName.trim()}${extension}`,
@@ -3989,32 +4163,6 @@ function createPrintColumns(columns, summaryColumns = []) {
3989
4163
  };
3990
4164
  });
3991
4165
  }
3992
- function readPrintSettings(storageKey) {
3993
- if (!storageKey) return null;
3994
- try {
3995
- const value = JSON.parse(
3996
- localStorage.getItem(`canvas-table-print:${storageKey}`) ?? "null"
3997
- );
3998
- if (!value || typeof value !== "object") return null;
3999
- const settings = value;
4000
- if (settings.version !== 2 || settings.presetName !== void 0 && typeof settings.presetName !== "string" || !Array.isArray(settings.columns) || !settings.columns.every(
4001
- (column) => column && typeof column.key === "string" && Number.isFinite(column.width) && column.width >= 10
4002
- ) || !Array.isArray(settings.selectedKeys) || !settings.selectedKeys.every((key) => typeof key === "string") || !Number.isInteger(settings.rowsPerPage) || settings.rowsPerPage < 1)
4003
- return null;
4004
- return settings;
4005
- } catch {
4006
- return null;
4007
- }
4008
- }
4009
- function writePrintSettings(storageKey, settings) {
4010
- if (!storageKey) return;
4011
- try {
4012
- const key = `canvas-table-print:${storageKey}`;
4013
- if (settings) localStorage.setItem(key, JSON.stringify(settings));
4014
- else localStorage.removeItem(key);
4015
- } catch {
4016
- }
4017
- }
4018
4166
  function restorePrintColumns(columns, settings) {
4019
4167
  const current = new Map(columns.map((column) => [column.key, column]));
4020
4168
  const restored = [];
@@ -4027,1577 +4175,254 @@ function restorePrintColumns(columns, settings) {
4027
4175
  return [...restored, ...current.values()];
4028
4176
  }
4029
4177
  function resolvePrintSelectedKeys(sourceColumns, presetConfig, cached) {
4030
- const cachedColumnKeys = new Set(cached?.columns.map((column) => column.key));
4178
+ new Set(cached?.columns.map((column) => column.key));
4031
4179
  const presetKeys = presetConfig?.selectedKeys ? new Set(presetConfig.selectedKeys) : null;
4032
4180
  return sourceColumns.filter((column) => {
4033
- if (cached) {
4034
- return cachedColumnKeys.has(column.key) ? cached.selectedKeys.includes(column.key) : true;
4035
- }
4036
4181
  if (presetKeys) return presetKeys.has(column.key);
4037
4182
  return true;
4038
4183
  }).map((column) => column.key);
4039
4184
  }
4040
- function createCachedPrintTableOptions(source, storageKey, printPresets = []) {
4041
- const cached = readPrintSettings(storageKey);
4042
- const selectedPreset = cached?.presetName ? printPresets.find((preset) => preset.name === cached.presetName) : cached ? void 0 : printPresets[0];
4043
- const config = selectedPreset?.config;
4044
- const settings = { ...config, ...cached };
4185
+ function createTableDocument(source, preset) {
4186
+ const config = preset?.config;
4187
+ const page = createPrintDesignPage("\u8868\u683C\u6253\u5370");
4188
+ const [paperWidth, paperHeight] = BROWSER_PRINT_PAPER_SIZES[config?.paperSize ?? "a4"];
4189
+ page.width = config?.orientation === "landscape" ? paperHeight : paperWidth;
4190
+ page.height = config?.orientation === "landscape" ? paperWidth : paperHeight;
4191
+ page.orientation = config?.orientation ?? "portrait";
4192
+ page.margins = config?.pageMargins ?? page.margins;
4193
+ const selectedKeys = resolvePrintSelectedKeys(source.columns, config);
4045
4194
  const columns = restorePrintColumns(
4046
- restorePrintColumns(
4047
- createPrintColumns(source.columns, source.summaryColumns),
4048
- config?.columns ? { columns: config.columns } : null
4049
- ),
4050
- cached
4051
- );
4052
- const selectedKeys = resolvePrintSelectedKeys(source.columns, config, cached);
4053
- return configurePrintTable(
4054
- source,
4055
- columns,
4056
- selectedKeys,
4057
- settings.rowsPerPage ?? 30,
4058
- {
4059
- includeSummary: settings.includeSummary ?? Boolean(
4060
- source.summaryRow || source.summaryColumns?.some(
4061
- (column) => column.summary.type !== "none"
4062
- )
4063
- ),
4064
- rowHeight: settings.rowHeight ?? 8,
4065
- title: settings.title ?? "\u8868\u683C\u6253\u5370",
4066
- subtitle: settings.subtitle ?? "",
4067
- titleFontSize: settings.titleFontSize ?? 18,
4068
- subtitleFontSize: settings.subtitleFontSize ?? 12,
4069
- summaryPosition: settings.summaryPosition ?? "last-page",
4070
- showPageNumbers: settings.showPageNumbers ?? false,
4071
- pageNumberPosition: settings.pageNumberPosition ?? "right",
4072
- showPrintTime: settings.showPrintTime ?? false,
4073
- printTimePosition: settings.printTimePosition ?? "left",
4074
- pageMargins: settings.pageMargins ?? {
4075
- top: 12,
4076
- right: 12,
4077
- bottom: 12,
4078
- left: 12
4079
- },
4080
- paperSize: settings.paperSize ?? "a4",
4081
- orientation: settings.orientation ?? "portrait",
4082
- useCellBorders: settings.useCellBorders ?? true,
4083
- borderColor: settings.borderColor ?? "#000000",
4084
- textColor: settings.textColor ?? "#000000",
4085
- headerBackgroundColor: settings.headerBackgroundColor ?? "#f2f5f8",
4086
- summaryBackgroundColor: settings.summaryBackgroundColor ?? "#f2f5f8"
4087
- }
4195
+ createPrintColumns(source.columns, source.summaryColumns),
4196
+ config?.columns ? { columns: config.columns } : null
4197
+ ).filter((column) => selectedKeys.includes(column.key));
4198
+ const left = page.margins?.left ?? 10;
4199
+ const right = page.margins?.right ?? 10;
4200
+ const bottom = page.margins?.bottom ?? 10;
4201
+ const contentWidth = page.width - left - right;
4202
+ const widthSum = columns.reduce((sum, column) => sum + column.width, 0);
4203
+ const rowHeight = config?.rowHeight ?? 8;
4204
+ const footerY = page.height - bottom - 6;
4205
+ const tableY = 28;
4206
+ const tableHeight = footerY - tableY - 8;
4207
+ const rowsPerPage = Math.max(1, Math.floor((tableHeight - 9) / rowHeight));
4208
+ const pageCount = Math.max(1, Math.ceil(source.rows.length / rowsPerPage));
4209
+ const printedAt = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN");
4210
+ const pages = Array.from(
4211
+ { length: pageCount },
4212
+ (_, index) => ({
4213
+ ...page,
4214
+ id: index === 0 ? page.id : createPrintDesignPage().id,
4215
+ name: `\u8868\u683C\u6253\u5370 ${index + 1}`,
4216
+ elements: [
4217
+ {
4218
+ id: `list-table-title-${index}`,
4219
+ type: "text",
4220
+ name: "\u6807\u9898",
4221
+ x: left,
4222
+ y: 12,
4223
+ width: contentWidth,
4224
+ height: 10,
4225
+ text: config?.title ?? "\u8868\u683C\u6253\u5370",
4226
+ fontSize: config?.titleFontSize ?? 18,
4227
+ fontWeight: "700",
4228
+ textAlign: "center"
4229
+ },
4230
+ {
4231
+ id: `list-table-data-${index}`,
4232
+ type: "table",
4233
+ name: "\u8868\u683C\u6570\u636E",
4234
+ x: left,
4235
+ y: tableY,
4236
+ width: contentWidth,
4237
+ height: tableHeight,
4238
+ dataMode: "binding",
4239
+ dataPath: `listTable.pages.${index}.rows`,
4240
+ dataSource: [],
4241
+ columns: columns.map((column) => ({
4242
+ key: column.key,
4243
+ title: column.title,
4244
+ dataIndex: column.key,
4245
+ width: widthSum > 0 ? Math.max(24, column.width / widthSum * 720) : 120,
4246
+ align: column.align
4247
+ })),
4248
+ rowHeight,
4249
+ headerRowHeight: 9,
4250
+ showHeader: true
4251
+ },
4252
+ {
4253
+ id: `list-table-print-time-${index}`,
4254
+ type: "text",
4255
+ name: "\u6253\u5370\u65F6\u95F4",
4256
+ x: left,
4257
+ y: footerY,
4258
+ width: contentWidth / 2,
4259
+ height: 6,
4260
+ text: `\u6253\u5370\u65F6\u95F4\uFF1A${printedAt}`,
4261
+ fontSize: 9,
4262
+ color: "#000000"
4263
+ },
4264
+ {
4265
+ id: `list-table-page-number-${index}`,
4266
+ type: "text",
4267
+ name: "\u5206\u9875\u4FE1\u606F",
4268
+ x: left + contentWidth / 2,
4269
+ y: footerY,
4270
+ width: contentWidth / 2,
4271
+ height: 6,
4272
+ text: `\u7B2C ${index + 1} \u9875 / \u5171 ${pageCount} \u9875`,
4273
+ textAlign: "right",
4274
+ fontSize: 9,
4275
+ color: "#000000"
4276
+ }
4277
+ ]
4278
+ })
4088
4279
  );
4280
+ return createPrintDesignDocument({
4281
+ name: preset?.name ?? "\u8868\u683C\u6253\u5370\u6A21\u677F",
4282
+ pages
4283
+ });
4089
4284
  }
4090
- async function configurePrintTable(source, columns, selectedKeys, rowsPerPage, settings = {}) {
4091
- const selected = new Set(selectedKeys);
4092
- const activeColumns = columns.filter((column) => selected.has(column.key));
4093
- const sourceIndexes = new Map(
4094
- source.columns.map((column, index) => [column.key, index])
4285
+ function mapPrintSourceRows(source) {
4286
+ return source.rows.map(
4287
+ (row) => Object.fromEntries(
4288
+ source.columns.map((column, index) => [column.key, row[index] ?? ""])
4289
+ )
4095
4290
  );
4096
- const summaries = Object.fromEntries(
4097
- activeColumns.map((column) => [
4098
- column.key,
4099
- {
4100
- type: column.summaryType ?? "none",
4101
- showTypePrefix: column.showTypePrefix === "yes",
4102
- precision: column.precision,
4103
- roundingMode: column.roundingMode ?? "round",
4104
- preserveTrailingZeros: column.preserveTrailingZeros === "yes"
4105
- }
4106
- ])
4291
+ }
4292
+ function createTableData(source, document2, rows = mapPrintSourceRows(source)) {
4293
+ const firstTable = document2.pages[0]?.elements.find(
4294
+ (item) => item.type === "table"
4107
4295
  );
4108
- const summaryRow = settings.includeSummary ? source.getSummaryRow ? await source.getSummaryRow({
4109
- columnKeys: activeColumns.map((column) => column.key),
4110
- sortState: [],
4111
- summaries,
4112
- includeSummary: true
4113
- }) : source.summaryRow ? activeColumns.map(
4114
- (column) => source.summaryRow?.[sourceIndexes.get(column.key) ?? -1] ?? ""
4115
- ) : void 0 : void 0;
4296
+ const rowsPerPage = firstTable?.type === "table" ? Math.max(
4297
+ 1,
4298
+ Math.floor(
4299
+ (firstTable.height - (firstTable.showHeader === false ? 0 : firstTable.headerRowHeight ?? 9)) / (firstTable.rowHeight ?? 8)
4300
+ )
4301
+ ) : Math.max(1, Math.ceil(rows.length / document2.pages.length));
4116
4302
  return {
4117
- title: settings.title ?? "\u8868\u683C\u6253\u5370",
4118
- ...settings.subtitle ? { subtitle: settings.subtitle } : {},
4119
- titleFontSize: settings.titleFontSize ?? 18,
4120
- subtitleFontSize: settings.subtitleFontSize ?? 12,
4121
- columns: activeColumns.map(({ key, title, width, align, overflow }) => ({
4122
- key,
4123
- title,
4124
- width,
4125
- ...align ? { align } : {},
4126
- ...overflow ? { overflow } : {}
4127
- })),
4128
- rows: source.rows.map(
4129
- (row) => activeColumns.map(
4130
- (column) => row[sourceIndexes.get(column.key) ?? -1] ?? ""
4131
- )
4132
- ),
4133
- rowsPerPage,
4134
- rowHeight: settings.rowHeight ?? 8,
4135
- ...settings.includeSummary && summaryRow ? {
4136
- summaryRow: activeColumns.map(
4137
- (_column, index) => summaryRow[index] ?? ""
4138
- ),
4139
- summaryPosition: settings.summaryPosition ?? "last-page"
4140
- } : {},
4141
- showPageNumbers: settings.showPageNumbers ?? false,
4142
- pageNumberPosition: settings.pageNumberPosition ?? "right",
4143
- showPrintTime: settings.showPrintTime ?? false,
4144
- printTimePosition: settings.printTimePosition ?? "left",
4145
- pageMargins: settings.pageMargins ?? {
4146
- top: 12,
4147
- right: 12,
4148
- bottom: 12,
4149
- left: 12
4150
- },
4151
- paperSize: settings.paperSize ?? "a4",
4152
- orientation: settings.orientation ?? "portrait",
4153
- useCellBorders: settings.useCellBorders ?? true,
4154
- borderColor: settings.borderColor ?? "#000000",
4155
- textColor: settings.textColor ?? "#000000",
4156
- headerBackgroundColor: settings.headerBackgroundColor ?? "#f2f5f8",
4157
- summaryBackgroundColor: settings.summaryBackgroundColor ?? "#f2f5f8"
4303
+ listTable: {
4304
+ rows,
4305
+ columns: source.columns.map((column) => ({ key: column.key })),
4306
+ pages: document2.pages.map((_, index) => ({
4307
+ rows: rows.slice(index * rowsPerPage, (index + 1) * rowsPerPage)
4308
+ }))
4309
+ }
4158
4310
  };
4159
4311
  }
4160
- var summaryOptions2 = [
4161
- { value: "original", label: "\u539F\u6C47\u603B" },
4162
- { value: "none", label: "\u65E0\u6C47\u603B" },
4163
- { value: "title", label: "\u6807\u9898" },
4164
- { value: "sum", label: "\u6C42\u548C" },
4165
- { value: "avg", label: "\u5E73\u5747\u503C" },
4166
- { value: "count", label: "\u8BA1\u6570" },
4167
- { value: "unionCount", label: "\u53BB\u91CD\u8BA1\u6570" },
4168
- { value: "rowCount", label: "\u884C\u6570" },
4169
- { value: "mergedRowCount", label: "\u5408\u5E76\u884C\u6570" },
4170
- { value: "min", label: "\u6700\u5C0F\u503C" },
4171
- { value: "max", label: "\u6700\u5927\u503C" }
4172
- ];
4173
- var roundingOptions2 = [
4174
- { value: "round", label: "\u56DB\u820D\u4E94\u5165" },
4175
- { value: "floor", label: "\u5411\u4E0B\u53D6\u6574" },
4176
- { value: "ceil", label: "\u5411\u4E0A\u53D6\u6574" },
4177
- { value: "truncate", label: "\u622A\u65AD" }
4178
- ];
4179
- var booleanOptions2 = [
4180
- { value: "yes", label: "\u662F" },
4181
- { value: "no", label: "\u5426" }
4182
- ];
4183
- function ReactListTablePrintDialog(props) {
4184
- const tableId = useId();
4185
- const [cached] = useState(() => readPrintSettings(props.storageKey));
4186
- const initialPreset = cached?.presetName ? props.printPresets?.find((preset) => preset.name === cached.presetName) : cached ? void 0 : props.printPresets?.[0];
4187
- const initialConfig = initialPreset?.config;
4188
- const [columns, setColumns] = useState(
4189
- () => restorePrintColumns(
4190
- restorePrintColumns(
4191
- createPrintColumns(props.source.columns, props.source.summaryColumns),
4192
- initialConfig?.columns ? { columns: initialConfig.columns } : null
4193
- ),
4194
- cached
4195
- )
4196
- );
4197
- const [selectedKeys, setSelectedKeys] = useState(
4198
- () => resolvePrintSelectedKeys(props.source.columns, initialConfig, cached)
4199
- );
4200
- const [rowsPerPage, setRowsPerPage] = useState(
4201
- cached?.rowsPerPage ?? initialConfig?.rowsPerPage ?? 30
4202
- );
4203
- const [rowHeight, setRowHeight] = useState(
4204
- cached?.rowHeight ?? initialConfig?.rowHeight ?? 8
4205
- );
4206
- const [autoCalculateRows, setAutoCalculateRows] = useState(
4207
- cached?.autoCalculateRowsPerPage ?? initialConfig?.autoCalculateRowsPerPage ?? false
4208
- );
4209
- const [title, setTitle] = useState(
4210
- cached?.title ?? initialConfig?.title ?? "\u8868\u683C\u6253\u5370"
4312
+ function getPrintSourceFormat(source) {
4313
+ return JSON.stringify(
4314
+ source.columns.map((column) => String(column.key)).sort()
4211
4315
  );
4212
- const [subtitle, setSubtitle] = useState(
4213
- cached?.subtitle ?? initialConfig?.subtitle ?? ""
4316
+ }
4317
+ function printTableTemplate(source, popup, document2 = createTableDocument(source)) {
4318
+ const data = createTableData(source, document2);
4319
+ printPrintDesignHtml(popup, transformPrintDesignToHtml(document2, { data }));
4320
+ return true;
4321
+ }
4322
+ function ReactListTablePrintDesignDialog(props) {
4323
+ const [fullscreen, setFullscreen] = useState(true);
4324
+ const document2 = useMemo(
4325
+ () => createTableDocument(props.source),
4326
+ [props.source]
4214
4327
  );
4215
- const [titleFontSize, setTitleFontSize] = useState(
4216
- cached?.titleFontSize ?? initialConfig?.titleFontSize ?? 18
4328
+ const [boundDocument, setBoundDocument] = useState(document2);
4329
+ const rows = useMemo(() => mapPrintSourceRows(props.source), [props.source]);
4330
+ const defaultTemplates = useMemo(
4331
+ () => [
4332
+ document2,
4333
+ ...props.printPresets?.map(
4334
+ (preset) => createTableDocument(props.source, preset)
4335
+ ) ?? [],
4336
+ ...props.printTemplates ?? []
4337
+ ],
4338
+ [document2, props.printPresets, props.printTemplates, props.source]
4217
4339
  );
4218
- const [subtitleFontSize, setSubtitleFontSize] = useState(
4219
- cached?.subtitleFontSize ?? initialConfig?.subtitleFontSize ?? 12
4340
+ const data = useMemo(
4341
+ () => createTableData(props.source, boundDocument, rows),
4342
+ [props.source, boundDocument, rows]
4220
4343
  );
4221
- const [includeSummary, setIncludeSummary] = useState(
4222
- () => cached?.includeSummary ?? initialConfig?.includeSummary ?? Boolean(
4223
- props.source.summaryRow || props.source.summaryColumns?.some(
4224
- (column) => column.summary.type !== "none"
4344
+ return /* @__PURE__ */ jsx(
4345
+ ReactModal,
4346
+ {
4347
+ open: true,
4348
+ fullscreen,
4349
+ closable: false,
4350
+ fullscreenable: false,
4351
+ footer: false,
4352
+ width: "min(96vw, 1440px)",
4353
+ style: { height: fullscreen ? "100%" : "min(88vh, 900px)" },
4354
+ bodyStyle: { padding: 0, overflow: "hidden", display: "flex" },
4355
+ onCancel: props.onClose,
4356
+ children: /* @__PURE__ */ jsx(
4357
+ ReactPrintDesign,
4358
+ {
4359
+ document: document2,
4360
+ defaultTemplates,
4361
+ data,
4362
+ dataFormatKey: getPrintSourceFormat(props.source),
4363
+ onChange: setBoundDocument,
4364
+ storeKey: props.storeKey,
4365
+ fullscreen,
4366
+ onFullscreenChange: setFullscreen,
4367
+ onClose: props.onClose,
4368
+ style: { flex: 1 }
4369
+ }
4225
4370
  )
4226
- )
4227
- );
4228
- const [summaryPosition, setSummaryPosition] = useState(cached?.summaryPosition ?? initialConfig?.summaryPosition ?? "last-page");
4229
- const [showPageNumbers, setShowPageNumbers] = useState(
4230
- cached?.showPageNumbers ?? initialConfig?.showPageNumbers ?? false
4231
- );
4232
- const [pageNumberPosition, setPageNumberPosition] = useState(cached?.pageNumberPosition ?? initialConfig?.pageNumberPosition ?? "right");
4233
- const [showPrintTime, setShowPrintTime] = useState(
4234
- cached?.showPrintTime ?? initialConfig?.showPrintTime ?? false
4235
- );
4236
- const [printTimePosition, setPrintTimePosition] = useState(cached?.printTimePosition ?? initialConfig?.printTimePosition ?? "left");
4237
- const [pageMargins, setPageMargins] = useState(
4238
- cached?.pageMargins ?? initialConfig?.pageMargins ?? {
4239
- top: 12,
4240
- right: 12,
4241
- bottom: 12,
4242
- left: 12
4243
4371
  }
4244
4372
  );
4245
- const [paperSize, setPaperSize] = useState(cached?.paperSize ?? initialConfig?.paperSize ?? "a4");
4246
- const [orientation, setOrientation] = useState(
4247
- cached?.orientation ?? initialConfig?.orientation ?? "portrait"
4248
- );
4249
- const [useCellBorders, setUseCellBorders] = useState(
4250
- cached?.useCellBorders ?? initialConfig?.useCellBorders ?? true
4251
- );
4252
- const [borderColor, setBorderColor] = useState(
4253
- cached?.borderColor ?? initialConfig?.borderColor ?? "#000000"
4254
- );
4255
- const [textColor, setTextColor] = useState(
4256
- cached?.textColor ?? initialConfig?.textColor ?? "#000000"
4257
- );
4258
- const [headerBackgroundColor, setHeaderBackgroundColor] = useState(
4259
- cached?.headerBackgroundColor ?? initialConfig?.headerBackgroundColor ?? "#f2f5f8"
4260
- );
4261
- const [summaryBackgroundColor, setSummaryBackgroundColor] = useState(
4262
- cached?.summaryBackgroundColor ?? initialConfig?.summaryBackgroundColor ?? "#f2f5f8"
4263
- );
4264
- const [selectedPresetName, setSelectedPresetName] = useState(
4265
- initialPreset?.name ?? ""
4266
- );
4267
- const [showSectionDividers, setShowSectionDividers] = useState(
4268
- cached?.showSectionDividers ?? initialConfig?.showSectionDividers ?? true
4269
- );
4270
- const [sectionDividerTopSpacing, setSectionDividerTopSpacing] = useState(
4271
- cached?.sectionDividerTopSpacing ?? initialConfig?.sectionDividerTopSpacing ?? 4
4272
- );
4273
- const [sectionDividerBottomSpacing, setSectionDividerBottomSpacing] = useState(
4274
- cached?.sectionDividerBottomSpacing ?? initialConfig?.sectionDividerBottomSpacing ?? 4
4275
- );
4276
- const [formItemSpacing, setFormItemSpacing] = useState(
4277
- cached?.formItemSpacing ?? initialConfig?.formItemSpacing ?? 4
4278
- );
4279
- const [cacheEnabled, setCacheEnabled] = useState(Boolean(props.storageKey));
4280
- const [error, setError] = useState("");
4281
- const [previewHtml, setPreviewHtml] = useState("");
4282
- const [previewOpen, setPreviewOpen] = useState(false);
4283
- const [printFullscreen, setPrintFullscreen] = useState(false);
4284
- const [previewFullscreen, setPreviewFullscreen] = useState(false);
4285
- const [previewMode, setPreviewMode] = useState("render");
4286
- const [previewViewport, setPreviewViewport] = useState(() => ({
4287
- width: typeof window === "undefined" ? 1280 : window.innerWidth,
4288
- height: typeof window === "undefined" ? 900 : window.innerHeight
4289
- }));
4290
- const selectedColumnKeys = new Set(selectedKeys.map(String));
4291
- const layoutWarning = getBrowserPrintLayoutWarning({
4292
- columns: columns.filter((column) => selectedColumnKeys.has(column.key)),
4293
- pageMargins,
4294
- paperSize,
4295
- orientation
4296
- });
4297
- const rowLayoutWarning = getBrowserPrintRowLayoutWarning({
4298
- pageMargins,
4299
- paperSize,
4300
- orientation,
4301
- rowsPerPage,
4302
- rowHeight,
4303
- includeSummary,
4304
- summaryPosition,
4305
- showPageNumbers,
4306
- showPrintTime,
4307
- titleFontSize,
4308
- subtitleFontSize,
4309
- subtitle
4310
- });
4311
- const printLayoutWarning = [layoutWarning, rowLayoutWarning].filter(Boolean).join("\uFF1B");
4312
- const [paperWidth, paperHeight] = BROWSER_PRINT_PAPER_SIZES[paperSize];
4313
- const previewPaperWidth = orientation === "portrait" ? paperWidth : paperHeight;
4314
- const previewPaperHeight = orientation === "portrait" ? paperHeight : paperWidth;
4315
- const previewListHeight = Math.max(
4316
- 240,
4317
- previewFullscreen ? previewViewport.height - 168 : Math.min(previewViewport.height - 260, 900)
4318
- );
4319
- const previewListWidth = Math.max(
4320
- 320,
4321
- (previewFullscreen ? previewViewport.width : Math.min(previewViewport.width * 0.96, 1280)) - 48
4322
- );
4323
- const pageWidthPixels = previewPaperWidth * 96 / 25.4;
4324
- const pageHeightPixels = previewPaperHeight * 96 / 25.4;
4325
- const previewScale = Math.min(
4326
- 1,
4327
- (previewListWidth - 24) / pageWidthPixels,
4328
- (previewListHeight - 24) / pageHeightPixels
4329
- );
4330
- const previewItemHeight = Math.ceil(pageHeightPixels * previewScale + 24);
4331
- const previewPages = useMemo(() => {
4332
- if (!previewHtml || typeof DOMParser === "undefined") return [];
4333
- const parsed = new DOMParser().parseFromString(previewHtml, "text/html");
4334
- const styles = Array.from(parsed.head.querySelectorAll("style")).map((style) => style.outerHTML).join("");
4335
- const pages = Array.from(parsed.body.children).filter(
4336
- (element) => element.classList.contains("page")
4337
- );
4338
- 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>`;
4339
- return pages.map((page, index) => ({
4340
- index,
4341
- srcDoc: `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">${styles}${pageStyles}</head><body>${page.outerHTML}</body></html>`
4342
- }));
4343
- }, [
4344
- pageHeightPixels,
4345
- pageWidthPixels,
4346
- previewHtml,
4347
- previewPaperHeight,
4348
- previewPaperWidth
4349
- ]);
4350
- useEffect(() => {
4351
- const updateViewport = () => {
4352
- setPreviewViewport({
4353
- width: window.innerWidth,
4354
- height: window.innerHeight
4355
- });
4356
- };
4357
- window.addEventListener("resize", updateViewport);
4358
- return () => window.removeEventListener("resize", updateViewport);
4359
- }, []);
4360
- const autoCalculateColumnWidths = () => {
4361
- const selectedColumnSet = new Set(selectedKeys.map(String));
4362
- const selectedColumns = columns.filter(
4363
- (column) => selectedColumnSet.has(column.key)
4364
- );
4365
- const calculated = calculateBrowserPrintColumnWidths(selectedColumns, {
4366
- pageMargins,
4367
- paperSize,
4368
- orientation
4369
- });
4370
- if (!calculated) {
4371
- setError("\u5F53\u524D\u7EB8\u5F20\u53EF\u7528\u5BBD\u5EA6\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u6240\u9009\u5217\uFF08\u6BCF\u5217\u81F3\u5C11 10mm\uFF09");
4372
- return;
4373
- }
4374
- const widths = new Map(calculated.map(({ key, width }) => [key, width]));
4375
- setColumns(
4376
- (current) => current.map(
4377
- (column) => widths.has(column.key) ? { ...column, width: widths.get(column.key) } : column
4378
- )
4379
- );
4380
- setError("");
4381
- };
4382
- const autoCalculateRowsPerPage = () => {
4383
- const calculated = calculateBrowserPrintRowsPerPage({
4384
- pageMargins,
4385
- paperSize,
4386
- orientation,
4387
- rowHeight,
4388
- includeSummary,
4389
- summaryPosition,
4390
- showPageNumbers,
4391
- showPrintTime,
4392
- titleFontSize,
4393
- subtitleFontSize,
4394
- subtitle
4395
- });
4396
- if (!calculated) {
4397
- setError("\u5F53\u524D\u7EB8\u5F20\u53EF\u7528\u9AD8\u5EA6\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u4E00\u884C");
4398
- return;
4399
- }
4400
- setRowsPerPage(calculated);
4401
- setError("");
4402
- };
4403
- useEffect(() => {
4404
- if (autoCalculateRows) autoCalculateRowsPerPage();
4405
- }, [
4406
- autoCalculateRows,
4407
- rowHeight,
4408
- includeSummary,
4409
- summaryPosition,
4410
- showPageNumbers,
4411
- showPrintTime,
4412
- titleFontSize,
4413
- subtitleFontSize,
4414
- subtitle,
4415
- paperSize,
4416
- orientation,
4417
- pageMargins
4418
- ]);
4419
- useEffect(() => {
4420
- if (showPageNumbers && showPrintTime && pageNumberPosition === printTimePosition) {
4421
- setPrintTimePosition(pageNumberPosition === "left" ? "center" : "left");
4422
- }
4423
- }, [showPageNumbers, showPrintTime, pageNumberPosition, printTimePosition]);
4424
- const createCurrentPrintOptions = () => configurePrintTable(
4425
- props.source,
4426
- columns,
4427
- selectedKeys.map(String),
4428
- rowsPerPage,
4429
- {
4430
- includeSummary,
4431
- rowHeight,
4432
- title,
4433
- subtitle,
4434
- titleFontSize,
4435
- subtitleFontSize,
4436
- summaryPosition,
4437
- showPageNumbers,
4438
- pageNumberPosition,
4439
- showPrintTime,
4440
- printTimePosition,
4441
- pageMargins,
4442
- paperSize,
4443
- orientation,
4444
- useCellBorders,
4445
- borderColor,
4446
- textColor,
4447
- headerBackgroundColor,
4448
- summaryBackgroundColor
4449
- }
4450
- );
4451
- const applyPrintPreset = (name) => {
4452
- setSelectedPresetName(name);
4453
- setError("");
4454
- if (!name) {
4455
- const defaultColumns = createPrintColumns(
4456
- props.source.columns,
4457
- props.source.summaryColumns
4458
- );
4459
- setColumns(defaultColumns);
4460
- setSelectedKeys(
4461
- resolvePrintSelectedKeys(props.source.columns, void 0, null)
4462
- );
4463
- setRowsPerPage(30);
4464
- setRowHeight(8);
4465
- setAutoCalculateRows(false);
4466
- setTitle("\u8868\u683C\u6253\u5370");
4467
- setSubtitle("");
4468
- setTitleFontSize(18);
4469
- setSubtitleFontSize(12);
4470
- setIncludeSummary(
4471
- Boolean(
4472
- props.source.summaryRow || props.source.summaryColumns?.some(
4473
- (column) => column.summary.type !== "none"
4474
- )
4475
- )
4476
- );
4477
- setSummaryPosition("last-page");
4478
- setShowPageNumbers(false);
4479
- setPageNumberPosition("right");
4480
- setShowPrintTime(false);
4481
- setPrintTimePosition("left");
4482
- setPageMargins({ top: 12, right: 12, bottom: 12, left: 12 });
4483
- setPaperSize("a4");
4484
- setOrientation("portrait");
4485
- setUseCellBorders(true);
4486
- setBorderColor("#000000");
4487
- setTextColor("#000000");
4488
- setHeaderBackgroundColor("#f2f5f8");
4489
- setSummaryBackgroundColor("#f2f5f8");
4490
- setShowSectionDividers(true);
4491
- setSectionDividerTopSpacing(4);
4492
- setSectionDividerBottomSpacing(4);
4493
- setFormItemSpacing(4);
4494
- return;
4495
- }
4496
- const preset = props.printPresets?.find((item) => item.name === name);
4497
- if (!preset) return;
4498
- const config = preset.config;
4499
- const baseColumns = createPrintColumns(
4500
- props.source.columns,
4501
- props.source.summaryColumns
4502
- );
4503
- setColumns(
4504
- restorePrintColumns(
4505
- baseColumns,
4506
- config.columns ? { columns: config.columns } : null
4507
- )
4508
- );
4509
- setSelectedKeys(
4510
- resolvePrintSelectedKeys(props.source.columns, config, null)
4511
- );
4512
- setRowsPerPage(config.rowsPerPage ?? 30);
4513
- setRowHeight(config.rowHeight ?? 8);
4514
- setAutoCalculateRows(config.autoCalculateRowsPerPage ?? false);
4515
- setTitle(config.title ?? "\u8868\u683C\u6253\u5370");
4516
- setSubtitle(config.subtitle ?? "");
4517
- setTitleFontSize(config.titleFontSize ?? 18);
4518
- setSubtitleFontSize(config.subtitleFontSize ?? 12);
4519
- setIncludeSummary(
4520
- config.includeSummary ?? Boolean(
4521
- props.source.summaryRow || props.source.summaryColumns?.some(
4522
- (column) => column.summary.type !== "none"
4523
- )
4524
- )
4525
- );
4526
- setSummaryPosition(config.summaryPosition ?? "last-page");
4527
- setShowPageNumbers(config.showPageNumbers ?? false);
4528
- setPageNumberPosition(config.pageNumberPosition ?? "right");
4529
- setShowPrintTime(config.showPrintTime ?? false);
4530
- setPrintTimePosition(config.printTimePosition ?? "left");
4531
- setPageMargins(
4532
- config.pageMargins ?? { top: 12, right: 12, bottom: 12, left: 12 }
4533
- );
4534
- setPaperSize(config.paperSize ?? "a4");
4535
- setOrientation(config.orientation ?? "portrait");
4536
- setUseCellBorders(config.useCellBorders ?? true);
4537
- setBorderColor(config.borderColor ?? "#000000");
4538
- setTextColor(config.textColor ?? "#000000");
4539
- setHeaderBackgroundColor(config.headerBackgroundColor ?? "#f2f5f8");
4540
- setSummaryBackgroundColor(config.summaryBackgroundColor ?? "#f2f5f8");
4541
- setShowSectionDividers(config.showSectionDividers ?? true);
4542
- setSectionDividerTopSpacing(config.sectionDividerTopSpacing ?? 4);
4543
- setSectionDividerBottomSpacing(config.sectionDividerBottomSpacing ?? 4);
4544
- setFormItemSpacing(config.formItemSpacing ?? 4);
4545
- };
4546
- const previewPrintHtml = async () => {
4547
- if (!selectedKeys.length) {
4548
- setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
4549
- return;
4550
- }
4551
- if (!Number.isInteger(rowsPerPage) || rowsPerPage < 1) {
4552
- setError("\u6BCF\u9875\u884C\u6570\u5FC5\u987B\u662F\u6B63\u6574\u6570");
4553
- return;
4554
- }
4555
- if (!Number.isFinite(rowHeight) || rowHeight <= 0) {
4556
- setError("\u884C\u9AD8\u5FC5\u987B\u662F\u6B63\u6570");
4557
- return;
4558
- }
4559
- try {
4560
- const options = await createCurrentPrintOptions();
4561
- setPreviewHtml(createBrowserPrintPreviewHtml(options));
4562
- setPreviewMode("render");
4563
- setPreviewOpen(true);
4564
- setError("");
4565
- } catch (cause) {
4566
- setError(cause instanceof Error ? cause.message : "\u751F\u6210\u6253\u5370\u9884\u89C8\u5931\u8D25");
4567
- }
4568
- };
4569
- const confirm = async () => {
4570
- const selected = selectedKeys.map(String);
4571
- if (!selected.length) return setError("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217");
4572
- if (!Number.isInteger(rowsPerPage) || rowsPerPage < 1)
4573
- return setError("\u6BCF\u9875\u884C\u6570\u5FC5\u987B\u662F\u6B63\u6574\u6570");
4574
- if (!Number.isFinite(rowHeight) || rowHeight <= 0)
4575
- return setError("\u884C\u9AD8\u5FC5\u987B\u662F\u6B63\u6570");
4576
- if (Object.values(pageMargins).some(
4577
- (margin) => !Number.isFinite(margin) || margin < 0
4578
- )) {
4579
- return setError("\u6253\u5370\u8FB9\u8DDD\u5FC5\u987B\u662F\u975E\u8D1F\u6570");
4580
- }
4581
- if (columns.some(
4582
- (column) => !Number.isFinite(column.width) || column.width < 10
4583
- )) {
4584
- return setError("\u5217\u5BBD\u4E0D\u80FD\u5C0F\u4E8E 10 \u6BEB\u7C73");
4585
- }
4586
- const options = await createCurrentPrintOptions();
4587
- if (!printBrowserTable(options))
4588
- return setError("\u6D4F\u89C8\u5668\u963B\u6B62\u4E86\u6253\u5370\u7A97\u53E3\uFF0C\u8BF7\u5141\u8BB8\u6B64\u9875\u9762\u6253\u5F00\u5F39\u7A97");
4589
- if (cacheEnabled) {
4590
- writePrintSettings(props.storageKey, {
4591
- version: 2,
4592
- columns,
4593
- selectedKeys: selected,
4594
- rowsPerPage,
4595
- presetName: selectedPresetName || void 0,
4596
- rowHeight,
4597
- autoCalculateRowsPerPage: autoCalculateRows,
4598
- title,
4599
- subtitle,
4600
- titleFontSize,
4601
- subtitleFontSize,
4602
- includeSummary,
4603
- summaryPosition,
4604
- showPageNumbers,
4605
- pageNumberPosition,
4606
- showPrintTime,
4607
- printTimePosition,
4608
- pageMargins,
4609
- paperSize,
4610
- orientation,
4611
- useCellBorders,
4612
- borderColor,
4613
- textColor,
4614
- headerBackgroundColor,
4615
- summaryBackgroundColor,
4616
- showSectionDividers,
4617
- sectionDividerTopSpacing,
4618
- sectionDividerBottomSpacing,
4619
- formItemSpacing
4620
- });
4621
- }
4622
- props.onClose();
4623
- };
4624
- const tableColumns = [
4625
- ROW_SELECTION_COLUMN,
4626
- { key: "title", dataIndex: "title", title: "\u6253\u5370\u5217", width: 260 },
4627
- {
4628
- key: "width",
4629
- dataIndex: "width",
4630
- title: "\u5217\u5BBD\uFF08mm\uFF09",
4631
- width: 110,
4632
- editable: true,
4633
- formItemProps: { valueType: "number", clickCount: 1, min: 10 }
4634
- },
4635
- {
4636
- key: "align",
4637
- dataIndex: "align",
4638
- title: "\u5BF9\u9F50\u65B9\u5F0F",
4639
- width: 100,
4640
- editable: true,
4641
- formItemProps: {
4642
- valueType: "select",
4643
- clickCount: 1,
4644
- options: [
4645
- { value: "left", label: "\u5DE6\u5BF9\u9F50" },
4646
- { value: "center", label: "\u5C45\u4E2D" },
4647
- { value: "right", label: "\u53F3\u5BF9\u9F50" }
4648
- ]
4649
- },
4650
- render: (value) => value === "center" ? "\u5C45\u4E2D" : value === "right" ? "\u53F3\u5BF9\u9F50" : "\u5DE6\u5BF9\u9F50"
4651
- },
4652
- {
4653
- key: "overflow",
4654
- dataIndex: "overflow",
4655
- title: "\u8D85\u5BBD\u5904\u7406",
4656
- width: 105,
4657
- editable: true,
4658
- formItemProps: {
4659
- valueType: "select",
4660
- clickCount: 1,
4661
- options: [
4662
- { value: "ellipsis", label: "\u7701\u7565\u53F7" },
4663
- { value: "clip", label: "\u88C1\u5207" },
4664
- { value: "wrap", label: "\u6362\u884C" }
4665
- ]
4666
- },
4667
- render: (value) => value === "ellipsis" ? "\u7701\u7565\u53F7" : value === "clip" ? "\u88C1\u5207" : "\u6362\u884C"
4668
- },
4669
- ...includeSummary ? [
4670
- {
4671
- key: "summary-group",
4672
- dataIndex: "summaryType",
4673
- title: "\u6C47\u603B",
4674
- children: [
4675
- {
4676
- key: "summaryType",
4677
- dataIndex: "summaryType",
4678
- title: "\u6C47\u603B\u65B9\u5F0F",
4679
- width: 110,
4680
- editable: true,
4681
- formItemProps: {
4682
- valueType: "select",
4683
- clickCount: 1,
4684
- options: summaryOptions2.filter(
4685
- (option) => option.value !== "original" || props.source.summaryColumns?.some(
4686
- (column) => column.summary.type === "original"
4687
- )
4688
- )
4689
- },
4690
- render: (value) => summaryOptions2.find((option) => option.value === value)?.label ?? "\u65E0\u6C47\u603B"
4691
- },
4692
- {
4693
- key: "showTypePrefix",
4694
- dataIndex: "showTypePrefix",
4695
- title: "\u6C47\u603B\u524D\u7F00",
4696
- width: 90,
4697
- editable: true,
4698
- formItemProps: {
4699
- valueType: "select",
4700
- clickCount: 1,
4701
- options: booleanOptions2
4702
- },
4703
- render: (value) => value === "yes" ? "\u662F" : "\u5426"
4704
- },
4705
- {
4706
- key: "precision",
4707
- dataIndex: "precision",
4708
- title: "\u5C0F\u6570\u4F4D\u6570",
4709
- width: 90,
4710
- editable: true,
4711
- formItemProps: {
4712
- valueType: "number",
4713
- clickCount: 1,
4714
- min: 0,
4715
- max: 20
4716
- }
4717
- },
4718
- {
4719
- key: "roundingMode",
4720
- dataIndex: "roundingMode",
4721
- title: "\u53D6\u6574\u65B9\u5F0F",
4722
- width: 100,
4723
- editable: true,
4724
- formItemProps: {
4725
- valueType: "select",
4726
- clickCount: 1,
4727
- options: roundingOptions2
4728
- },
4729
- render: (value) => roundingOptions2.find((option) => option.value === value)?.label ?? "\u56DB\u820D\u4E94\u5165"
4730
- },
4731
- {
4732
- key: "preserveTrailingZeros",
4733
- dataIndex: "preserveTrailingZeros",
4734
- title: "\u4FDD\u7559\u65E0\u6548\u96F6",
4735
- width: 100,
4736
- editable: true,
4737
- formItemProps: {
4738
- valueType: "select",
4739
- clickCount: 1,
4740
- options: booleanOptions2
4741
- },
4742
- render: (value) => value === "yes" ? "\u662F" : "\u5426"
4743
- }
4744
- ]
4745
- }
4746
- ] : []
4747
- ];
4748
- const sectionDivider = showSectionDividers ? /* @__PURE__ */ jsx(
4749
- "div",
4750
- {
4751
- "aria-hidden": "true",
4752
- style: {
4753
- height: 1,
4754
- marginTop: sectionDividerTopSpacing,
4755
- marginBottom: sectionDividerBottomSpacing,
4756
- background: "#e2e8f0"
4757
- }
4758
- }
4759
- ) : null;
4760
- return /* @__PURE__ */ jsxs(
4761
- ReactModal,
4762
- {
4763
- open: true,
4764
- title: /* @__PURE__ */ jsxs(
4765
- "span",
4766
- {
4767
- style: {
4768
- display: "flex",
4769
- alignItems: "baseline",
4770
- gap: 12,
4771
- minWidth: 0
4772
- },
4773
- children: [
4774
- /* @__PURE__ */ jsx("span", { children: "\u6253\u5370\u8868\u683C\u914D\u7F6E" }),
4775
- printLayoutWarning ? /* @__PURE__ */ jsxs(
4776
- "span",
4777
- {
4778
- role: "status",
4779
- 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`,
4780
- style: {
4781
- color: "#b45309",
4782
- fontSize: 12,
4783
- fontWeight: 400,
4784
- whiteSpace: "nowrap",
4785
- overflow: "hidden",
4786
- textOverflow: "ellipsis",
4787
- minWidth: 0
4788
- },
4789
- children: [
4790
- printLayoutWarning,
4791
- "\uFF0C\u4ECD\u53EF\u7EE7\u7EED\u6253\u5370"
4792
- ]
4793
- }
4794
- ) : null
4795
- ]
4796
- }
4797
- ),
4798
- width: "min(98vw, 1680px)",
4799
- fullscreenable: true,
4800
- fullscreen: printFullscreen,
4801
- onFullscreenChange: setPrintFullscreen,
4802
- bodyStyle: { display: "flex", minHeight: 0 },
4803
- okText: "\u6253\u5370",
4804
- cancelText: "\u53D6\u6D88",
4805
- onCancel: props.onClose,
4806
- footer: /* @__PURE__ */ jsxs(
4807
- "div",
4808
- {
4809
- style: {
4810
- display: "flex",
4811
- justifyContent: "flex-end",
4812
- alignItems: "center",
4813
- gap: 8,
4814
- width: "100%"
4815
- },
4816
- children: [
4817
- /* @__PURE__ */ jsx(ReactButton, { type: "default", onClick: props.onClose, children: "\u53D6\u6D88" }),
4818
- /* @__PURE__ */ jsx(ReactButton, { type: "default", onClick: previewPrintHtml, children: "\u6253\u5370\u9884\u89C8" }),
4819
- /* @__PURE__ */ jsx(ReactButton, { type: "primary", onClick: confirm, children: "\u6253\u5370" })
4820
- ]
4821
- }
4822
- ),
4823
- children: [
4824
- /* @__PURE__ */ jsx(
4825
- "div",
4826
- {
4827
- style: {
4828
- display: "flex",
4829
- flex: "1 1 auto",
4830
- minHeight: 0,
4831
- flexDirection: "column"
4832
- },
4833
- children: /* @__PURE__ */ jsxs(
4834
- "div",
4835
- {
4836
- style: {
4837
- display: "grid",
4838
- flex: "1 1 auto",
4839
- minHeight: 0,
4840
- gridTemplateColumns: "minmax(340px, 380px) minmax(0, 1fr)",
4841
- gap: 20,
4842
- alignItems: "stretch"
4843
- },
4844
- children: [
4845
- /* @__PURE__ */ jsx(
4846
- "div",
4847
- {
4848
- style: {
4849
- display: "grid",
4850
- gap: 0,
4851
- padding: "4px 4px 0 0",
4852
- minHeight: 0,
4853
- overflowY: "auto"
4854
- },
4855
- children: /* @__PURE__ */ jsxs(
4856
- ReactForm,
4857
- {
4858
- layout: "horizontal",
4859
- noWrap: true,
4860
- itemSpacing: `${formItemSpacing}px`,
4861
- labelWidth: 88,
4862
- labelAlign: "left",
4863
- style: { display: "contents" },
4864
- children: [
4865
- props.printPresets?.length ? /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6253\u5370\u914D\u7F6E", children: /* @__PURE__ */ jsx(
4866
- ReactSelect,
4867
- {
4868
- value: selectedPresetName,
4869
- "aria-label": "\u6253\u5370\u914D\u7F6E\u9884\u8BBE",
4870
- options: [
4871
- { value: "", label: "\u9ED8\u8BA4\u914D\u7F6E" },
4872
- ...props.printPresets.map((preset) => ({
4873
- value: preset.name,
4874
- label: preset.name
4875
- }))
4876
- ],
4877
- onChange: (value) => applyPrintPreset(String(value ?? "")),
4878
- style: { width: "100%" }
4879
- }
4880
- ) }) : null,
4881
- props.storageKey ? /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u7F13\u5B58\u5230\u672C\u5730", children: /* @__PURE__ */ jsx(
4882
- ReactCheckbox,
4883
- {
4884
- checked: cacheEnabled,
4885
- "aria-label": "\u7F13\u5B58\u6253\u5370\u914D\u7F6E\u5230\u672C\u5730",
4886
- onChange: (event) => {
4887
- setCacheEnabled(event.target.checked);
4888
- if (!event.target.checked)
4889
- writePrintSettings(props.storageKey, null);
4890
- }
4891
- }
4892
- ) }) : null,
4893
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u5206\u9694\u7EBF\u5360\u4F4D", children: /* @__PURE__ */ jsx(
4894
- ReactCheckbox,
4895
- {
4896
- checked: showSectionDividers,
4897
- "aria-label": "\u663E\u793A\u5206\u7EC4\u5206\u9694\u7EBF",
4898
- onChange: (event) => setShowSectionDividers(event.target.checked)
4899
- }
4900
- ) }),
4901
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u884C\u95F4\u8DDD\uFF08px\uFF09", children: /* @__PURE__ */ jsx(
4902
- ReactNumberInput,
4903
- {
4904
- min: 0,
4905
- max: 40,
4906
- step: 1,
4907
- value: formItemSpacing,
4908
- "aria-label": "\u8868\u5355\u884C\u95F4\u8DDD",
4909
- onChange: (value) => setFormItemSpacing(value ?? 0),
4910
- style: { width: "100%" }
4911
- }
4912
- ) }),
4913
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u5206\u9694\u7EBF\u4E0A\u4E0B\u95F4\u8DDD\uFF08px\uFF09", children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4914
- /* @__PURE__ */ jsx("span", { children: "\u4E0A" }),
4915
- /* @__PURE__ */ jsx(
4916
- ReactNumberInput,
4917
- {
4918
- min: 0,
4919
- max: 40,
4920
- step: 1,
4921
- value: sectionDividerTopSpacing,
4922
- "aria-label": "\u5206\u9694\u7EBF\u4E0A\u95F4\u8DDD",
4923
- onChange: (value) => setSectionDividerTopSpacing(value ?? 0),
4924
- style: { width: 64 }
4925
- }
4926
- ),
4927
- /* @__PURE__ */ jsx("span", { children: "\u4E0B" }),
4928
- /* @__PURE__ */ jsx(
4929
- ReactNumberInput,
4930
- {
4931
- min: 0,
4932
- max: 40,
4933
- step: 1,
4934
- value: sectionDividerBottomSpacing,
4935
- "aria-label": "\u5206\u9694\u7EBF\u4E0B\u95F4\u8DDD",
4936
- onChange: (value) => setSectionDividerBottomSpacing(value ?? 0),
4937
- style: { width: 64 }
4938
- }
4939
- )
4940
- ] }) }),
4941
- sectionDivider,
4942
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6807\u9898", children: /* @__PURE__ */ jsx(
4943
- ReactInput,
4944
- {
4945
- value: title,
4946
- "aria-label": "\u6253\u5370\u6807\u9898",
4947
- allowClear: true,
4948
- onChange: (event) => setTitle(event.target.value),
4949
- style: { width: "100%", minWidth: 0 }
4950
- }
4951
- ) }),
4952
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u5B50\u6807\u9898", children: /* @__PURE__ */ jsx(
4953
- ReactInput,
4954
- {
4955
- value: subtitle,
4956
- "aria-label": "\u6253\u5370\u5B50\u6807\u9898",
4957
- allowClear: true,
4958
- onChange: (event) => setSubtitle(event.target.value),
4959
- style: { width: "100%", minWidth: 0 }
4960
- }
4961
- ) }),
4962
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6807\u9898\u5B57\u53F7", children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, minWidth: 0 }, children: [
4963
- /* @__PURE__ */ jsx(
4964
- ReactNumberInput,
4965
- {
4966
- min: 1,
4967
- step: 1,
4968
- value: titleFontSize,
4969
- "aria-label": "\u6807\u9898\u5B57\u53F7",
4970
- onChange: (value) => setTitleFontSize(value ?? 18),
4971
- style: { flex: "1 1 0", minWidth: 0 }
4972
- }
4973
- ),
4974
- /* @__PURE__ */ jsx(
4975
- ReactNumberInput,
4976
- {
4977
- min: 1,
4978
- step: 1,
4979
- value: subtitleFontSize,
4980
- "aria-label": "\u5B50\u6807\u9898\u5B57\u53F7",
4981
- onChange: (value) => setSubtitleFontSize(value ?? 12),
4982
- style: { flex: "1 1 0", minWidth: 0 }
4983
- }
4984
- )
4985
- ] }) }),
4986
- sectionDivider,
4987
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u7EB8\u5F20", children: /* @__PURE__ */ jsx(
4988
- ReactSelect,
4989
- {
4990
- value: paperSize,
4991
- options: [
4992
- { value: "a0", label: "A0" },
4993
- { value: "a1", label: "A1" },
4994
- { value: "a2", label: "A2" },
4995
- { value: "a3", label: "A3" },
4996
- { value: "a4", label: "A4" },
4997
- { value: "a5", label: "A5" },
4998
- { value: "a6", label: "A6" },
4999
- { value: "b4", label: "B4" },
5000
- { value: "b5", label: "B5" },
5001
- { value: "letter", label: "Letter" },
5002
- { value: "legal", label: "Legal" },
5003
- { value: "tabloid", label: "Tabloid" },
5004
- { value: "executive", label: "Executive" },
5005
- { value: "folio", label: "Folio" }
5006
- ],
5007
- onChange: (value) => setPaperSize(value),
5008
- style: { width: "100%" }
5009
- }
5010
- ) }),
5011
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6253\u5370\u65B9\u5411", children: /* @__PURE__ */ jsxs(
5012
- ReactRadio.Group,
5013
- {
5014
- value: orientation,
5015
- "aria-label": "\u6253\u5370\u65B9\u5411",
5016
- onChange: (event) => setOrientation(event.target.value),
5017
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5018
- children: [
5019
- /* @__PURE__ */ jsx(ReactRadio, { value: "portrait", children: "\u7EB5\u5411" }),
5020
- /* @__PURE__ */ jsx(ReactRadio, { value: "landscape", children: "\u6A2A\u5411" })
5021
- ]
5022
- }
5023
- ) }),
5024
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6253\u5370\u8FB9\u8DDD\uFF08mm\uFF09", children: /* @__PURE__ */ jsx(
5025
- "div",
5026
- {
5027
- style: {
5028
- display: "grid",
5029
- gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
5030
- gap: 8
5031
- },
5032
- children: [
5033
- ["top", "\u4E0A"],
5034
- ["right", "\u53F3"],
5035
- ["bottom", "\u4E0B"],
5036
- ["left", "\u5DE6"]
5037
- ].map(([side, label]) => /* @__PURE__ */ jsxs(
5038
- "div",
5039
- {
5040
- style: {
5041
- display: "grid",
5042
- gridTemplateColumns: "20px minmax(0, 1fr)",
5043
- gap: 4,
5044
- alignItems: "center"
5045
- },
5046
- children: [
5047
- /* @__PURE__ */ jsx("span", { children: label }),
5048
- /* @__PURE__ */ jsx(
5049
- ReactNumberInput,
5050
- {
5051
- min: 0,
5052
- step: 1,
5053
- value: pageMargins[side],
5054
- onChange: (value) => setPageMargins((current) => ({
5055
- ...current,
5056
- [side]: value ?? 0
5057
- })),
5058
- style: { width: "100%" }
5059
- }
5060
- )
5061
- ]
5062
- },
5063
- side
5064
- ))
5065
- }
5066
- ) }),
5067
- sectionDivider,
5068
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u5355\u5143\u683C\u8FB9\u6846", children: /* @__PURE__ */ jsx(
5069
- ReactCheckbox,
5070
- {
5071
- checked: useCellBorders,
5072
- "aria-label": "\u5355\u5143\u683C\u8FB9\u6846",
5073
- onChange: (event) => setUseCellBorders(event.target.checked)
5074
- }
5075
- ) }),
5076
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u8FB9\u6846\u989C\u8272", children: /* @__PURE__ */ jsx(
5077
- ReactColorPicker,
5078
- {
5079
- value: borderColor,
5080
- disabled: !useCellBorders,
5081
- onChange: setBorderColor,
5082
- style: { width: "100%" }
5083
- }
5084
- ) }),
5085
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6587\u5B57\u989C\u8272", children: /* @__PURE__ */ jsx(
5086
- ReactColorPicker,
5087
- {
5088
- value: textColor,
5089
- onChange: setTextColor,
5090
- style: { width: "100%" }
5091
- }
5092
- ) }),
5093
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u8868\u5934\u80CC\u666F\u8272", children: /* @__PURE__ */ jsx(
5094
- ReactColorPicker,
5095
- {
5096
- value: headerBackgroundColor,
5097
- onChange: setHeaderBackgroundColor,
5098
- style: { width: "100%" }
5099
- }
5100
- ) }),
5101
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6C47\u603B\u884C\u80CC\u666F\u8272", children: /* @__PURE__ */ jsx(
5102
- ReactColorPicker,
5103
- {
5104
- value: summaryBackgroundColor,
5105
- onChange: setSummaryBackgroundColor,
5106
- style: { width: "100%" }
5107
- }
5108
- ) }),
5109
- sectionDivider,
5110
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6253\u5370\u6C47\u603B\u884C", children: /* @__PURE__ */ jsx(
5111
- ReactCheckbox,
5112
- {
5113
- checked: includeSummary,
5114
- "aria-label": "\u6253\u5370\u6C47\u603B\u884C",
5115
- onChange: (event) => setIncludeSummary(event.target.checked)
5116
- }
5117
- ) }),
5118
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6C47\u603B\u4F4D\u7F6E", children: /* @__PURE__ */ jsxs(
5119
- ReactRadio.Group,
5120
- {
5121
- value: summaryPosition,
5122
- "aria-label": "\u6C47\u603B\u4F4D\u7F6E",
5123
- onChange: (event) => setSummaryPosition(
5124
- event.target.value
5125
- ),
5126
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5127
- children: [
5128
- /* @__PURE__ */ jsx(ReactRadio, { value: "every-page", disabled: !includeSummary, children: "\u6BCF\u9875" }),
5129
- /* @__PURE__ */ jsx(ReactRadio, { value: "last-page", disabled: !includeSummary, children: "\u6700\u540E\u4E00\u9875" })
5130
- ]
5131
- }
5132
- ) }),
5133
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6253\u5370\u65F6\u95F4", children: /* @__PURE__ */ jsxs(
5134
- "span",
5135
- {
5136
- style: {
5137
- display: "flex",
5138
- alignItems: "center",
5139
- gap: 8,
5140
- minWidth: 0,
5141
- whiteSpace: "nowrap"
5142
- },
5143
- children: [
5144
- /* @__PURE__ */ jsx(
5145
- ReactCheckbox,
5146
- {
5147
- checked: showPrintTime,
5148
- "aria-label": "\u663E\u793A\u6253\u5370\u65F6\u95F4",
5149
- onChange: (event) => {
5150
- const checked = event.target.checked;
5151
- setShowPrintTime(checked);
5152
- if (checked && showPageNumbers && pageNumberPosition === printTimePosition) {
5153
- setPrintTimePosition(
5154
- pageNumberPosition === "left" ? "center" : "left"
5155
- );
5156
- }
5157
- }
5158
- }
5159
- ),
5160
- "\u663E\u793A"
5161
- ]
5162
- }
5163
- ) }),
5164
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u65F6\u95F4\u4F4D\u7F6E", children: /* @__PURE__ */ jsxs(
5165
- ReactRadio.Group,
5166
- {
5167
- value: printTimePosition,
5168
- "aria-label": "\u6253\u5370\u65F6\u95F4\u4F4D\u7F6E",
5169
- onChange: (event) => {
5170
- const next = event.target.value;
5171
- if (showPageNumbers && next === pageNumberPosition) return;
5172
- setPrintTimePosition(next);
5173
- },
5174
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5175
- children: [
5176
- /* @__PURE__ */ jsx(
5177
- ReactRadio,
5178
- {
5179
- value: "left",
5180
- disabled: !showPrintTime || showPageNumbers && pageNumberPosition === "left",
5181
- children: "\u5DE6\u4FA7"
5182
- }
5183
- ),
5184
- /* @__PURE__ */ jsx(
5185
- ReactRadio,
5186
- {
5187
- value: "center",
5188
- disabled: !showPrintTime || showPageNumbers && pageNumberPosition === "center",
5189
- children: "\u4E2D\u95F4"
5190
- }
5191
- ),
5192
- /* @__PURE__ */ jsx(
5193
- ReactRadio,
5194
- {
5195
- value: "right",
5196
- disabled: !showPrintTime || showPageNumbers && pageNumberPosition === "right",
5197
- children: "\u53F3\u4FA7"
5198
- }
5199
- )
5200
- ]
5201
- }
5202
- ) }),
5203
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u5206\u9875\u4FE1\u606F", children: /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5204
- /* @__PURE__ */ jsx(
5205
- ReactCheckbox,
5206
- {
5207
- checked: showPageNumbers,
5208
- "aria-label": "\u663E\u793A\u5206\u9875\u4FE1\u606F",
5209
- onChange: (event) => setShowPageNumbers(event.target.checked)
5210
- }
5211
- ),
5212
- "\u663E\u793A"
5213
- ] }) }),
5214
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u5206\u9875\u4F4D\u7F6E", children: /* @__PURE__ */ jsxs(
5215
- ReactRadio.Group,
5216
- {
5217
- value: pageNumberPosition,
5218
- "aria-label": "\u5206\u9875\u4FE1\u606F\u4F4D\u7F6E",
5219
- onChange: (event) => (() => {
5220
- const next = event.target.value;
5221
- setPageNumberPosition(next);
5222
- if (showPrintTime && next === printTimePosition) {
5223
- setPrintTimePosition(
5224
- next === "left" ? "center" : "left"
5225
- );
5226
- }
5227
- })(),
5228
- style: { display: "flex", gap: 10, flexWrap: "nowrap" },
5229
- children: [
5230
- /* @__PURE__ */ jsx(
5231
- ReactRadio,
5232
- {
5233
- value: "left",
5234
- disabled: !showPageNumbers || showPrintTime && printTimePosition === "left",
5235
- children: "\u5DE6\u4FA7"
5236
- }
5237
- ),
5238
- /* @__PURE__ */ jsx(
5239
- ReactRadio,
5240
- {
5241
- value: "center",
5242
- disabled: !showPageNumbers || showPrintTime && printTimePosition === "center",
5243
- children: "\u4E2D\u95F4"
5244
- }
5245
- ),
5246
- /* @__PURE__ */ jsx(
5247
- ReactRadio,
5248
- {
5249
- value: "right",
5250
- disabled: !showPageNumbers || showPrintTime && printTimePosition === "right",
5251
- children: "\u53F3\u4FA7"
5252
- }
5253
- )
5254
- ]
5255
- }
5256
- ) }),
5257
- sectionDivider,
5258
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u884C\u9AD8\uFF08mm\uFF09", children: /* @__PURE__ */ jsx(
5259
- ReactNumberInput,
5260
- {
5261
- min: 1,
5262
- step: 1,
5263
- value: rowHeight,
5264
- onChange: (value) => {
5265
- setRowHeight(value ?? 0);
5266
- setError("");
5267
- },
5268
- style: { width: "100%" }
5269
- }
5270
- ) }),
5271
- /* @__PURE__ */ jsx(ReactForm.Item, { label: "\u6BCF\u9875\u884C\u6570", children: /* @__PURE__ */ jsxs(
5272
- "span",
5273
- {
5274
- style: {
5275
- display: "flex",
5276
- alignItems: "center",
5277
- gap: 8,
5278
- whiteSpace: "nowrap"
5279
- },
5280
- children: [
5281
- /* @__PURE__ */ jsx(
5282
- ReactNumberInput,
5283
- {
5284
- min: 1,
5285
- step: 1,
5286
- value: rowsPerPage,
5287
- onChange: (value) => {
5288
- setRowsPerPage(value ?? 0);
5289
- setError("");
5290
- },
5291
- style: { flex: "1 1 auto", minWidth: 0 }
5292
- }
5293
- ),
5294
- /* @__PURE__ */ jsx(
5295
- ReactCheckbox,
5296
- {
5297
- checked: autoCalculateRows,
5298
- "aria-label": "\u81EA\u52A8\u8BA1\u7B97\u6BCF\u9875\u884C\u6570",
5299
- onChange: (event) => setAutoCalculateRows(event.target.checked)
5300
- }
5301
- ),
5302
- "\u81EA\u52A8\u8BA1\u7B97"
5303
- ]
5304
- }
5305
- ) })
5306
- ]
5307
- }
5308
- )
5309
- }
5310
- ),
5311
- /* @__PURE__ */ jsxs(
5312
- "div",
5313
- {
5314
- style: {
5315
- minWidth: 0,
5316
- minHeight: 0,
5317
- display: "flex",
5318
- flexDirection: "column"
5319
- },
5320
- children: [
5321
- /* @__PURE__ */ jsx(
5322
- "div",
5323
- {
5324
- style: {
5325
- display: "flex",
5326
- justifyContent: "flex-end",
5327
- marginBottom: 8
5328
- },
5329
- children: /* @__PURE__ */ jsx(
5330
- ReactButton,
5331
- {
5332
- type: "default",
5333
- onClick: autoCalculateColumnWidths,
5334
- disabled: selectedKeys.length === 0,
5335
- children: "\u81EA\u52A8\u8BA1\u7B97\u5217\u5BBD"
5336
- }
5337
- )
5338
- }
5339
- ),
5340
- /* @__PURE__ */ jsx(
5341
- "div",
5342
- {
5343
- style: {
5344
- flex: "1 1 auto",
5345
- minHeight: 280,
5346
- height: printFullscreen ? "100%" : "min(58vh, 560px)"
5347
- },
5348
- children: props.renderTable({
5349
- tableId,
5350
- columns: tableColumns,
5351
- dataSource: columns,
5352
- rowKey: "key",
5353
- rowHeight: 40,
5354
- headerRowHeight: 38,
5355
- toolbar: false,
5356
- contextMenu: false,
5357
- pagination: false,
5358
- draggable: true,
5359
- rowSelection: {
5360
- type: "checkbox",
5361
- selectedRowKeys: selectedKeys,
5362
- selectRowByClick: false,
5363
- onChange: (keys) => {
5364
- setSelectedKeys(keys);
5365
- setError("");
5366
- }
5367
- },
5368
- rowDrag: {
5369
- enabled: true,
5370
- droppable: true,
5371
- allowSelfDrop: true,
5372
- mode: "move",
5373
- onDrop: ({ rows: moved, insertIndex, source }) => {
5374
- if (source.tableId !== tableId || insertIndex == null)
5375
- return;
5376
- const keys = new Set(moved.map((row) => row.key));
5377
- setColumns((current) => {
5378
- const remaining = current.filter(
5379
- (row) => !keys.has(row.key)
5380
- );
5381
- const preceding = current.slice(0, insertIndex).filter((row) => !keys.has(row.key)).length;
5382
- remaining.splice(
5383
- preceding,
5384
- 0,
5385
- ...current.filter((row) => keys.has(row.key))
5386
- );
5387
- return remaining;
5388
- });
5389
- }
5390
- },
5391
- style: { width: "100%", height: "100%" }
5392
- })
5393
- }
5394
- )
5395
- ]
5396
- }
5397
- )
5398
- ]
5399
- }
5400
- )
5401
- }
5402
- ),
5403
- error ? /* @__PURE__ */ jsx("div", { role: "alert", style: { color: "#c2410c", marginTop: 8 }, children: error }) : null,
5404
- /* @__PURE__ */ jsx(
5405
- ReactModal,
5406
- {
5407
- open: previewOpen,
5408
- title: "\u6253\u5370\u9884\u89C8",
5409
- width: "min(96vw, 1280px)",
5410
- fullscreenable: true,
5411
- fullscreen: previewFullscreen,
5412
- onFullscreenChange: setPreviewFullscreen,
5413
- bodyStyle: { display: "flex", minHeight: 0 },
5414
- footer: /* @__PURE__ */ jsxs(
5415
- "div",
5416
- {
5417
- style: {
5418
- display: "flex",
5419
- justifyContent: "flex-end",
5420
- alignItems: "center",
5421
- gap: 8,
5422
- width: "100%"
5423
- },
5424
- children: [
5425
- /* @__PURE__ */ jsx(
5426
- ReactButton,
5427
- {
5428
- type: previewMode === "render" ? "primary" : "default",
5429
- onClick: () => setPreviewMode("render"),
5430
- children: "\u6548\u679C"
5431
- }
5432
- ),
5433
- /* @__PURE__ */ jsx(
5434
- ReactButton,
5435
- {
5436
- type: previewMode === "source" ? "primary" : "default",
5437
- onClick: () => setPreviewMode("source"),
5438
- children: "HTML"
5439
- }
5440
- ),
5441
- /* @__PURE__ */ jsx(ReactButton, { type: "default", onClick: previewPrintHtml, children: "\u5237\u65B0\u9884\u89C8" })
5442
- ]
5443
- }
5444
- ),
5445
- onCancel: () => setPreviewOpen(false),
5446
- children: /* @__PURE__ */ jsx(
5447
- "div",
5448
- {
5449
- style: {
5450
- display: "flex",
5451
- flex: 1,
5452
- minHeight: 0,
5453
- width: "100%",
5454
- justifyContent: "center"
5455
- },
5456
- children: previewMode === "render" ? /* @__PURE__ */ jsx(
5457
- ReactVirtualList,
5458
- {
5459
- items: previewPages,
5460
- height: previewListHeight,
5461
- itemHeight: previewItemHeight,
5462
- itemKey: (page) => page.index,
5463
- overscan: 1,
5464
- style: {
5465
- width: "100%",
5466
- maxWidth: previewListWidth,
5467
- overflowX: "hidden"
5468
- },
5469
- renderItem: (page, _index, meta) => /* @__PURE__ */ jsx(
5470
- "div",
5471
- {
5472
- style: {
5473
- ...meta.style,
5474
- display: "flex",
5475
- justifyContent: "center",
5476
- alignItems: "flex-start",
5477
- height: previewItemHeight,
5478
- padding: 12,
5479
- boxSizing: "border-box",
5480
- overflow: "hidden"
5481
- },
5482
- children: /* @__PURE__ */ jsx(
5483
- "div",
5484
- {
5485
- style: {
5486
- width: pageWidthPixels * previewScale,
5487
- height: pageHeightPixels * previewScale,
5488
- border: "1px solid #cbd5e1",
5489
- position: "relative",
5490
- overflow: "hidden",
5491
- background: "white"
5492
- },
5493
- children: /* @__PURE__ */ jsx(
5494
- "iframe",
5495
- {
5496
- title: `\u6253\u5370\u6548\u679C\u9884\u89C8\u7B2C ${page.index + 1} \u9875`,
5497
- srcDoc: page.srcDoc,
5498
- sandbox: "",
5499
- style: {
5500
- display: "block",
5501
- position: "absolute",
5502
- left: 0,
5503
- top: 0,
5504
- width: pageWidthPixels,
5505
- height: pageHeightPixels,
5506
- transform: `scale(${previewScale})`,
5507
- transformOrigin: "top left",
5508
- border: 0,
5509
- overflow: "hidden",
5510
- background: "white"
5511
- }
5512
- }
5513
- )
5514
- }
5515
- )
5516
- }
5517
- )
5518
- }
5519
- ) : /* @__PURE__ */ jsx(
5520
- "pre",
5521
- {
5522
- "aria-label": "\u751F\u6210\u7684\u6253\u5370 HTML",
5523
- style: {
5524
- boxSizing: "border-box",
5525
- width: "100%",
5526
- height: previewFullscreen ? "100%" : "min(72vh, 900px)",
5527
- minHeight: 0,
5528
- overflow: "auto",
5529
- margin: 0,
5530
- padding: 12,
5531
- border: "1px solid #cbd5e1",
5532
- background: "#f8fafc",
5533
- color: "#1f2937",
5534
- font: "12px/1.5 ui-monospace, SFMono-Regular, monospace",
5535
- whiteSpace: "pre-wrap",
5536
- overflowWrap: "anywhere"
5537
- },
5538
- children: previewHtml
5539
- }
5540
- )
5541
- }
5542
- )
5543
- }
5544
- )
5545
- ]
5546
- }
5547
- );
5548
- }
5549
-
5550
- // src/features/editor/utils.ts
5551
- function toNumberValue(value) {
5552
- if (typeof value === "number" && Number.isFinite(value)) {
5553
- return value;
5554
- }
5555
- if (typeof value === "string" && value.trim().length > 0) {
5556
- const nextValue = Number(value);
5557
- return Number.isFinite(nextValue) ? nextValue : null;
5558
- }
5559
- return null;
5560
- }
5561
- function toNumericProp(value) {
5562
- if (typeof value === "number") {
5563
- return value;
5564
- }
5565
- if (typeof value === "string" && value.trim().length > 0) {
5566
- const nextValue = Number(value);
5567
- return Number.isFinite(nextValue) ? nextValue : void 0;
5568
- }
5569
- return void 0;
5570
- }
5571
- function resolvePadding(value, fallback = 0) {
5572
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
5573
- }
5574
- function resolveEditorControlSize(request) {
5575
- const targetRect = request.hostRect ?? request.rect;
5576
- const height = Math.max(targetRect.height - 2, 1);
5577
- const fontSize = typeof request.theme.fontSize === "number" && Number.isFinite(request.theme.fontSize) && request.theme.fontSize > 0 ? request.theme.fontSize : void 0;
5578
- const paddingInline = resolvePadding(request.theme.paddingInline);
5579
- const paddingBlock = resolvePadding(request.theme.paddingBlock);
5580
- const contentZoom = typeof request.theme.contentZoom === "number" && Number.isFinite(request.theme.contentZoom) && request.theme.contentZoom > 0 ? request.theme.contentZoom : 1;
5581
- return { height, fontSize, paddingInline, paddingBlock, contentZoom };
5582
- }
5583
- function getEditorInputStyle(request) {
5584
- const { height, fontSize, paddingInline, paddingBlock, contentZoom } = resolveEditorControlSize(request);
5585
- return {
5586
- width: "100%",
5587
- height,
5588
- minHeight: height,
5589
- color: request.theme.cellColor ?? request.theme.textColor,
5590
- fontFamily: request.theme.fontFamily,
5591
- fontSize,
5592
- // 用像素 token,确保 select/time/color 触发器与内部 Input 同步缩放。
5593
- ["--canvas-react-control-height"]: `${height}px`,
5594
- ["--canvas-react-font-size"]: fontSize != null ? `${fontSize}px` : void 0,
5595
- ["--canvas-react-control-padding-inline"]: `${paddingInline}px`,
5596
- ["--canvas-react-control-padding-block"]: `${paddingBlock}px`,
5597
- ["--canvas-react-content-zoom"]: String(contentZoom),
5598
- ["--canvas-react-radius-sm"]: "0px",
5599
- borderRadius: 0,
5600
- boxSizing: "border-box"
4373
+ }
4374
+
4375
+ // src/features/editor/utils.ts
4376
+ function toNumberValue(value) {
4377
+ if (typeof value === "number" && Number.isFinite(value)) {
4378
+ return value;
4379
+ }
4380
+ if (typeof value === "string" && value.trim().length > 0) {
4381
+ const nextValue = Number(value);
4382
+ return Number.isFinite(nextValue) ? nextValue : null;
4383
+ }
4384
+ return null;
4385
+ }
4386
+ function toNumericProp(value) {
4387
+ if (typeof value === "number") {
4388
+ return value;
4389
+ }
4390
+ if (typeof value === "string" && value.trim().length > 0) {
4391
+ const nextValue = Number(value);
4392
+ return Number.isFinite(nextValue) ? nextValue : void 0;
4393
+ }
4394
+ return void 0;
4395
+ }
4396
+ function resolvePadding(value, fallback = 0) {
4397
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
4398
+ }
4399
+ function resolveEditorControlSize(request) {
4400
+ const targetRect = request.hostRect ?? request.rect;
4401
+ const height = Math.max(targetRect.height - 2, 1);
4402
+ const fontSize = typeof request.theme.fontSize === "number" && Number.isFinite(request.theme.fontSize) && request.theme.fontSize > 0 ? request.theme.fontSize : void 0;
4403
+ const paddingInline = resolvePadding(request.theme.paddingInline);
4404
+ const paddingBlock = resolvePadding(request.theme.paddingBlock);
4405
+ const contentZoom = typeof request.theme.contentZoom === "number" && Number.isFinite(request.theme.contentZoom) && request.theme.contentZoom > 0 ? request.theme.contentZoom : 1;
4406
+ return { height, fontSize, paddingInline, paddingBlock, contentZoom };
4407
+ }
4408
+ function getEditorInputStyle(request) {
4409
+ const { height, fontSize, paddingInline, paddingBlock, contentZoom } = resolveEditorControlSize(request);
4410
+ return {
4411
+ width: "100%",
4412
+ height,
4413
+ minHeight: height,
4414
+ color: request.theme.cellColor ?? request.theme.textColor,
4415
+ fontFamily: request.theme.fontFamily,
4416
+ fontSize,
4417
+ // 用像素 token,确保 select/time/color 触发器与内部 Input 同步缩放。
4418
+ ["--canvas-react-control-height"]: `${height}px`,
4419
+ ["--canvas-react-font-size"]: fontSize != null ? `${fontSize}px` : void 0,
4420
+ ["--canvas-react-control-padding-inline"]: `${paddingInline}px`,
4421
+ ["--canvas-react-control-padding-block"]: `${paddingBlock}px`,
4422
+ ["--canvas-react-content-zoom"]: String(contentZoom),
4423
+ ["--canvas-react-radius-sm"]: "0px",
4424
+ borderRadius: 0,
4425
+ boxSizing: "border-box"
5601
4426
  };
5602
4427
  }
5603
4428
  function resolveEditorOverlayStyle(params) {
@@ -5633,6 +4458,16 @@ function resolveEditorOverlayStyle(params) {
5633
4458
  function ReactTableEditorOverlay(props) {
5634
4459
  const { request } = props;
5635
4460
  const editorHostRef = useRef(null);
4461
+ const wheelCommittedRef = useRef(false);
4462
+ const editorRequest = {
4463
+ ...request,
4464
+ onCommit: (options) => {
4465
+ if (!wheelCommittedRef.current) request.onCommit(options);
4466
+ }
4467
+ };
4468
+ useEffect(() => {
4469
+ wheelCommittedRef.current = false;
4470
+ }, [request.editorKey]);
5636
4471
  const style = resolveEditorOverlayStyle({
5637
4472
  rect: request.rect,
5638
4473
  hostRect: request.hostRect,
@@ -5649,7 +4484,26 @@ function ReactTableEditorOverlay(props) {
5649
4484
  }
5650
4485
  focusAndSelectEditorInput(input, request.selectOnFocus);
5651
4486
  }, [request]);
5652
- return /* @__PURE__ */ jsx(ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsx("div", { ref: editorHostRef, children: renderEditorByType(request, style) }, request.editorKey) });
4487
+ useEffect(() => {
4488
+ const host = editorHostRef.current;
4489
+ if (!host) return;
4490
+ const valueType = request.config.valueType ?? "text";
4491
+ if (valueType !== "text" && valueType !== "number" && valueType !== "input-range") {
4492
+ return;
4493
+ }
4494
+ const handleWheel = (event) => {
4495
+ event.preventDefault();
4496
+ event.stopPropagation();
4497
+ if (!wheelCommittedRef.current) {
4498
+ wheelCommittedRef.current = true;
4499
+ request.onCommit();
4500
+ }
4501
+ request.onWheel?.(event);
4502
+ };
4503
+ host.addEventListener("wheel", handleWheel, { passive: false });
4504
+ return () => host.removeEventListener("wheel", handleWheel);
4505
+ }, [request]);
4506
+ return /* @__PURE__ */ jsx(ReactContentScaleProvider, { scale: contentZoom, children: /* @__PURE__ */ jsx("div", { ref: editorHostRef, children: renderEditorByType(editorRequest, style) }, request.editorKey) });
5653
4507
  }
5654
4508
  function renderEditorByType(request, style) {
5655
4509
  switch (request.config.valueType ?? "text") {
@@ -6701,245 +5555,8 @@ function HolderOutlined() {
6701
5555
  return /* @__PURE__ */ 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" });
6702
5556
  }
6703
5557
 
6704
- // src/components/fullscreen-portal.ts
6705
- function resolveFullscreenPortalContainer(host) {
6706
- const fullscreenElement = document.fullscreenElement;
6707
- return fullscreenElement instanceof HTMLElement && host && fullscreenElement.contains(host) ? fullscreenElement : document.body;
6708
- }
6709
- function SortableList(props) {
6710
- const { items, onOrderChange } = props;
6711
- const rootRef = useRef(null);
6712
- const dragRef = useRef(null);
6713
- const [dragState, setDragState] = useState(null);
6714
- useEffect(
6715
- () => () => {
6716
- document.body.classList.remove("react-list-table-sorting");
6717
- document.body.style.removeProperty("user-select");
6718
- },
6719
- []
6720
- );
6721
- useEffect(() => {
6722
- if (!dragState) return;
6723
- const scrollContainer = props.scrollContainerRef?.current;
6724
- let frameId = 0;
6725
- let lastTime = null;
6726
- const updateTarget = () => {
6727
- const current = dragRef.current;
6728
- if (!current) return;
6729
- const target = resolveClosestSortableItem({
6730
- items,
6731
- parentKey: current.source.parentKey,
6732
- layouts: current.layouts,
6733
- // 保留拖拽开始时的布局,补偿滚动位移,避免受行交换动画影响。
6734
- overlayCenterY: current.pointerY - current.offsetY + current.height / 2 + current.rootTop - (rootRef.current?.getBoundingClientRect().top ?? current.rootTop)
6735
- });
6736
- if (target) {
6737
- current.target = target;
6738
- }
6739
- setDragState({
6740
- sourceKey: current.source.key,
6741
- targetKey: current.target.key,
6742
- pointerY: current.pointerY
6743
- });
6744
- };
6745
- const handleMove = (event) => {
6746
- const current = dragRef.current;
6747
- if (!current || event.pointerId !== current.pointerId) return;
6748
- current.pointerY = event.clientY;
6749
- updateTarget();
6750
- };
6751
- const tick = (time) => {
6752
- const current = dragRef.current;
6753
- if (!current) return;
6754
- const elapsed = lastTime == null ? 0 : Math.min(time - lastTime, 50);
6755
- lastTime = time;
6756
- if (scrollContainer) {
6757
- const rect = scrollContainer.getBoundingClientRect();
6758
- const top = rect.top + scrollContainer.clientTop;
6759
- const height = scrollContainer.clientHeight;
6760
- const edge = Math.min(40, height / 2);
6761
- const bottom = top + height;
6762
- 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;
6763
- if (direction) {
6764
- scrollContainer.scrollTop = Math.max(
6765
- 0,
6766
- Math.min(
6767
- scrollContainer.scrollHeight - height,
6768
- scrollContainer.scrollTop + direction * elapsed * 0.5
6769
- )
6770
- );
6771
- updateTarget();
6772
- }
6773
- }
6774
- frameId = requestAnimationFrame(tick);
6775
- };
6776
- const finish = (commit) => {
6777
- const current = dragRef.current;
6778
- cancelAnimationFrame(frameId);
6779
- if (commit && current && current.source.key !== current.target.key) {
6780
- const siblings = items.filter(
6781
- (item) => item.parentKey === current.source.parentKey
6782
- );
6783
- const orderedKeys = resolveNextSortableOrder(
6784
- siblings.map((item) => item.key),
6785
- current.source.key,
6786
- current.target.key
6787
- );
6788
- if (orderedKeys) {
6789
- onOrderChange(current.source.parentKey, orderedKeys);
6790
- }
6791
- }
6792
- dragRef.current = null;
6793
- setDragState(null);
6794
- document.body.classList.remove("react-list-table-sorting");
6795
- document.body.style.removeProperty("user-select");
6796
- };
6797
- const handleEnd = (event) => {
6798
- if (event.pointerId !== dragRef.current?.pointerId) return;
6799
- handleMove(event);
6800
- finish(true);
6801
- };
6802
- const handleCancel = (event) => {
6803
- if (event.pointerId === dragRef.current?.pointerId) finish(false);
6804
- };
6805
- const handleBlur = () => finish(false);
6806
- frameId = requestAnimationFrame(tick);
6807
- scrollContainer?.addEventListener("scroll", updateTarget);
6808
- window.addEventListener("pointermove", handleMove);
6809
- window.addEventListener("pointerup", handleEnd);
6810
- window.addEventListener("pointercancel", handleCancel);
6811
- window.addEventListener("blur", handleBlur);
6812
- return () => {
6813
- cancelAnimationFrame(frameId);
6814
- scrollContainer?.removeEventListener("scroll", updateTarget);
6815
- window.removeEventListener("pointermove", handleMove);
6816
- window.removeEventListener("pointerup", handleEnd);
6817
- window.removeEventListener("pointercancel", handleCancel);
6818
- window.removeEventListener("blur", handleBlur);
6819
- };
6820
- }, [dragState != null, items, onOrderChange, props.scrollContainerRef]);
6821
- const sourceIndex = dragState ? items.findIndex((item) => item.key === dragState.sourceKey) : -1;
6822
- const targetIndex = dragState ? items.findIndex((item) => item.key === dragState.targetKey) : -1;
6823
- return /* @__PURE__ */ jsxs("div", { ref: rootRef, children: [
6824
- items.map((item, index) => {
6825
- const style = resolveSortableTransform(
6826
- index,
6827
- sourceIndex,
6828
- targetIndex,
6829
- dragRef.current?.height ?? 0
6830
- );
6831
- return /* @__PURE__ */ jsx(
6832
- "div",
6833
- {
6834
- "data-sortable-key": item.key,
6835
- className: dragState?.sourceKey === item.key ? "dragging" : "",
6836
- style,
6837
- children: props.renderItem(item, {
6838
- onPointerDown: (event) => {
6839
- if (event.button !== 0 || dragRef.current) return;
6840
- const row = event.currentTarget.closest(
6841
- "[data-sortable-key]"
6842
- );
6843
- if (!row) return;
6844
- const rect = row.getBoundingClientRect();
6845
- dragRef.current = {
6846
- source: item,
6847
- target: item,
6848
- layouts: collectSortableItemLayouts(rootRef.current),
6849
- offsetY: event.clientY - rect.top,
6850
- width: rect.width,
6851
- left: rect.left,
6852
- height: rect.height,
6853
- pointerId: event.pointerId,
6854
- pointerY: event.clientY,
6855
- rootTop: rootRef.current?.getBoundingClientRect().top ?? 0
6856
- };
6857
- setDragState({
6858
- sourceKey: item.key,
6859
- targetKey: item.key,
6860
- pointerY: event.clientY
6861
- });
6862
- document.body.classList.add("react-list-table-sorting");
6863
- document.body.style.userSelect = "none";
6864
- event.preventDefault();
6865
- }
6866
- })
6867
- },
6868
- item.key
6869
- );
6870
- }),
6871
- dragState && dragRef.current ? createPortal(
6872
- /* @__PURE__ */ jsx(
6873
- "div",
6874
- {
6875
- className: "react-list-table-sort-overlay",
6876
- style: {
6877
- left: dragRef.current.left,
6878
- top: dragState.pointerY - dragRef.current.offsetY,
6879
- width: dragRef.current.width,
6880
- height: dragRef.current.height
6881
- },
6882
- children: props.renderItem(dragRef.current.source, {
6883
- onPointerDown: (event) => event.preventDefault()
6884
- })
6885
- }
6886
- ),
6887
- resolveFullscreenPortalContainer(rootRef.current)
6888
- ) : null
6889
- ] });
6890
- }
6891
- function resolveNextSortableOrder(currentKeys, sourceKey, targetKey) {
6892
- const sourceIndex = currentKeys.indexOf(sourceKey);
6893
- const targetIndex = currentKeys.indexOf(targetKey);
6894
- if (sourceIndex < 0 || targetIndex < 0 || sourceIndex === targetIndex) {
6895
- return null;
6896
- }
6897
- const nextKeys = [...currentKeys];
6898
- const [source] = nextKeys.splice(sourceIndex, 1);
6899
- nextKeys.splice(targetIndex, 0, source);
6900
- return nextKeys;
6901
- }
6902
- function collectSortableItemLayouts(root) {
6903
- if (!root) return [];
6904
- return Array.from(
6905
- root.querySelectorAll("[data-sortable-key]")
6906
- ).map((element) => {
6907
- const rect = element.getBoundingClientRect();
6908
- return {
6909
- key: element.dataset.sortableKey ?? "",
6910
- centerY: rect.top + rect.height / 2
6911
- };
6912
- });
6913
- }
6914
- function resolveClosestSortableItem(params) {
6915
- let closestItem = null;
6916
- let closestDistance = Number.POSITIVE_INFINITY;
6917
- params.layouts.forEach((layout) => {
6918
- const item = params.items.find((candidate) => candidate.key === layout.key);
6919
- if (!item || item.parentKey !== params.parentKey) return;
6920
- const distance = Math.abs(params.overlayCenterY - layout.centerY);
6921
- if (distance < closestDistance) {
6922
- closestDistance = distance;
6923
- closestItem = item;
6924
- }
6925
- });
6926
- return closestItem;
6927
- }
6928
- function resolveSortableTransform(index, sourceIndex, targetIndex, height) {
6929
- let translateY = 0;
6930
- if (sourceIndex < targetIndex && index > sourceIndex && index <= targetIndex) {
6931
- translateY = -height;
6932
- } else if (sourceIndex > targetIndex && index >= targetIndex && index < sourceIndex) {
6933
- translateY = height;
6934
- }
6935
- return {
6936
- transform: translateY ? `translate3d(0, ${translateY}px, 0)` : void 0,
6937
- transition: sourceIndex >= 0 ? "transform 180ms ease" : void 0
6938
- };
6939
- }
6940
-
6941
5558
  // src/features/toolbar/style.css
6942
- 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");
5559
+ 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");
6943
5560
  function ReactTableToolbar(props) {
6944
5561
  const { toolbar, title } = props;
6945
5562
  const [densityOpen, setDensityOpen] = useState(false);
@@ -7070,18 +5687,17 @@ function ReactTableToolbar(props) {
7070
5687
  children: [
7071
5688
  /* @__PURE__ */ jsxs("div", { className: "react-list-table-column-setting-head", children: [
7072
5689
  /* @__PURE__ */ jsx("strong", { children: "\u5217\u8BBE\u7F6E" }),
7073
- /* @__PURE__ */ jsx(
5690
+ props.columnSettingsCacheAvailable ? /* @__PURE__ */ jsx(
7074
5691
  ReactCheckbox,
7075
5692
  {
7076
5693
  checked: props.cacheColumnSettings === true,
7077
- disabled: !props.columnSettingsCacheAvailable,
7078
- 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",
5694
+ title: "\u7F13\u5B58\u5217\u5BBD\u3001\u663E\u9690\u3001\u56FA\u5B9A\u548C\u987A\u5E8F",
7079
5695
  onChange: (event) => props.onColumnSettingsCacheChange?.(
7080
5696
  event.target.checked
7081
5697
  ),
7082
5698
  children: "\u7F13\u5B58\u5230\u672C\u5730"
7083
5699
  }
7084
- ),
5700
+ ) : null,
7085
5701
  /* @__PURE__ */ jsx("span", { style: { marginLeft: "auto" }, children: config.columnSettingHeaderExtra }),
7086
5702
  /* @__PURE__ */ jsx("button", { type: "button", onClick: props.onResetColumns, children: "\u91CD\u7F6E" })
7087
5703
  ] }),
@@ -7091,13 +5707,15 @@ function ReactTableToolbar(props) {
7091
5707
  ref: columnSettingsBodyRef,
7092
5708
  className: "react-list-table-column-setting-body canvas-react-scrollbar",
7093
5709
  children: /* @__PURE__ */ jsx(
7094
- SortableList,
5710
+ ReactSortableList,
7095
5711
  {
7096
5712
  scrollContainerRef: columnSettingsBodyRef,
7097
- items: flattenColumns(props.columns).map((column, index) => ({
7098
- ...column,
7099
- position: index + 1
7100
- })),
5713
+ items: flattenColumns(props.columns).map(
5714
+ (column, index) => ({
5715
+ ...column,
5716
+ position: index + 1
5717
+ })
5718
+ ),
7101
5719
  onOrderChange: props.onColumnOrderChange,
7102
5720
  renderItem: (column, handleProps) => /* @__PURE__ */ jsxs("div", { className: "react-list-table-column-item", children: [
7103
5721
  /* @__PURE__ */ jsx(
@@ -7524,6 +6142,12 @@ function resolveReactListTableDebugOptions(debug, inheritedEnabled) {
7524
6142
  };
7525
6143
  }
7526
6144
 
6145
+ // src/components/fullscreen-portal.ts
6146
+ function resolveFullscreenPortalContainer(host) {
6147
+ const fullscreenElement = document.fullscreenElement;
6148
+ return fullscreenElement instanceof HTMLElement && host && fullscreenElement.contains(host) ? fullscreenElement : document.body;
6149
+ }
6150
+
7527
6151
  // src/components/column-manager-state.ts
7528
6152
  function applyColumnManagerState(columns, visibility, orders, config, parentKey = "root") {
7529
6153
  const order = orders.get(parentKey);
@@ -7898,12 +6522,102 @@ function ReactListTableInner(props, ref) {
7898
6522
  } = useReactListTableState(options);
7899
6523
  const hasPagination = paginationConfig != null;
7900
6524
  const [printSource, setPrintSource] = useState(null);
6525
+ const [savedPrintTemplates, setSavedPrintTemplates] = useState([]);
6526
+ const [printMenuSource, setPrintMenuSource] = useState(null);
6527
+ const printStoreKey = storageKey ? `list:${storageKey}` : void 0;
6528
+ const printMenuOpen = Boolean(headerContextMenuRequest);
6529
+ useEffect(() => {
6530
+ if (!printMenuOpen || !printStoreKey) {
6531
+ setSavedPrintTemplates([]);
6532
+ return;
6533
+ }
6534
+ let disposed = false;
6535
+ void readPrintDesignTemplates(printStoreKey).then((versions) => {
6536
+ if (!disposed) setSavedPrintTemplates(versions);
6537
+ }).catch(() => {
6538
+ if (!disposed) setSavedPrintTemplates([]);
6539
+ });
6540
+ return () => {
6541
+ disposed = true;
6542
+ };
6543
+ }, [printMenuOpen, printStoreKey]);
6544
+ useEffect(() => {
6545
+ if (!printMenuOpen) {
6546
+ setPrintMenuSource(null);
6547
+ return;
6548
+ }
6549
+ const getPrintData = headerContextMenuRequest?.onGetPrintData;
6550
+ if (!getPrintData) return;
6551
+ let disposed = false;
6552
+ void Promise.resolve(getPrintData()).then((source) => {
6553
+ if (!disposed) setPrintMenuSource(source);
6554
+ }).catch(() => {
6555
+ if (!disposed) setPrintMenuSource(null);
6556
+ });
6557
+ return () => {
6558
+ disposed = true;
6559
+ };
6560
+ }, [printMenuOpen]);
6561
+ const printDataFormat = printMenuSource ? getPrintSourceFormat(printMenuSource) : void 0;
6562
+ const printMenuRows = useMemo(
6563
+ () => printMenuSource ? mapPrintSourceRows(printMenuSource) : [],
6564
+ [printMenuSource]
6565
+ );
6566
+ const latestSavedTemplates = [
6567
+ ...new Set(savedPrintTemplates.map((item) => item.templateId))
6568
+ ].map((templateId) => {
6569
+ const versions = savedPrintTemplates.filter(
6570
+ (item) => item.templateId === templateId
6571
+ );
6572
+ return versions[versions.length - 1];
6573
+ });
6574
+ const printTemplateChoices = [
6575
+ { key: "base", label: "\u8868\u683C\u6253\u5370\u6A21\u677F" },
6576
+ ...props.printPresets?.map((item, index) => ({
6577
+ key: `preset:${index}`,
6578
+ label: item.name
6579
+ })) ?? [],
6580
+ ...props.printTemplates?.map((item, index) => {
6581
+ const invalid = Boolean(
6582
+ printMenuSource && !isPrintDesignDocumentCompatible(
6583
+ item,
6584
+ createTableData(printMenuSource, item, printMenuRows)
6585
+ )
6586
+ );
6587
+ return {
6588
+ key: `document:${index}`,
6589
+ label: `${item.name}${invalid ? "\uFF08\u5DF2\u5931\u6548\uFF09" : ""}`,
6590
+ disabled: invalid
6591
+ };
6592
+ }) ?? [],
6593
+ ...latestSavedTemplates.map((item) => {
6594
+ const invalid = Boolean(
6595
+ printMenuSource && isPrintDesignTemplateInvalid(
6596
+ item,
6597
+ printDataFormat,
6598
+ createTableData(printMenuSource, item.document, printMenuRows)
6599
+ )
6600
+ );
6601
+ return {
6602
+ key: `saved:${item.id}`,
6603
+ label: `${item.document.name} (v${item.version})${invalid ? "\uFF08\u5DF2\u5931\u6548\uFF09" : ""}`,
6604
+ disabled: invalid
6605
+ };
6606
+ })
6607
+ ];
6608
+ const [cacheConfigOpen, setCacheConfigOpen] = useState(false);
7901
6609
  const paginationLayout = resolveReactListTablePaginationLayout(resolvedRowHeight);
7902
6610
  const portalContainer = resolveFullscreenPortalContainer(shellRef.current);
7903
6611
  useImperativeHandle(
7904
6612
  ref,
7905
6613
  () => ({
7906
6614
  validate: () => tableRef.current?.validate() ?? Promise.resolve([]),
6615
+ setValidationErrors: (errors) => {
6616
+ tableRef.current?.setValidationErrors(errors);
6617
+ },
6618
+ clearValidationErrors: (targets) => {
6619
+ tableRef.current?.clearValidationErrors(targets);
6620
+ },
7907
6621
  exportXlsx: (options2) => {
7908
6622
  tableRef.current?.exportXlsx(options2);
7909
6623
  },
@@ -8079,27 +6793,56 @@ function ReactListTableInner(props, ref) {
8079
6793
  /* @__PURE__ */ jsx(
8080
6794
  ReactTableContextMenuView,
8081
6795
  {
6796
+ printTemplates: printTemplateChoices,
6797
+ onPrintTemplate: (key) => {
6798
+ const request = headerContextMenuRequest;
6799
+ if (!request?.onGetPrintData) return;
6800
+ request.onClose();
6801
+ const popup = window.open("", "_blank");
6802
+ if (!popup) return;
6803
+ void Promise.resolve(request.onGetPrintData()).then((source) => {
6804
+ const document2 = key.startsWith("saved:") ? savedPrintTemplates.find((item) => item.id === key.slice(6))?.document : key.startsWith("preset:") ? createTableDocument(
6805
+ source,
6806
+ props.printPresets?.[Number(key.slice(7))]
6807
+ ) : key.startsWith("document:") ? props.printTemplates?.[Number(key.slice(9))] : createTableDocument(source);
6808
+ if (!document2) throw new Error("\u627E\u4E0D\u5230\u6253\u5370\u6A21\u677F");
6809
+ const data = createTableData(source, document2);
6810
+ if (!isPrintDesignDocumentCompatible(document2, data))
6811
+ throw new Error("\u6253\u5370\u6A21\u677F\u5DF2\u5931\u6548");
6812
+ if (key.startsWith("saved:") && isPrintDesignTemplateInvalid(
6813
+ savedPrintTemplates.find(
6814
+ (item) => item.id === key.slice(6)
6815
+ ),
6816
+ getPrintSourceFormat(source),
6817
+ data
6818
+ ))
6819
+ throw new Error("\u6253\u5370\u6A21\u677F\u5DF2\u5931\u6548");
6820
+ printTableTemplate(source, popup, document2);
6821
+ }).catch((error) => {
6822
+ popup.close();
6823
+ console.error("\u76F4\u63A5\u6253\u5370\u5931\u8D25", error);
6824
+ });
6825
+ },
6826
+ onViewCacheConfig: () => {
6827
+ headerContextMenuRequest?.onClose();
6828
+ setCacheConfigOpen(true);
6829
+ },
8082
6830
  onPrint: () => {
8083
6831
  const getPrintData = headerContextMenuRequest?.onGetPrintData;
8084
6832
  if (!getPrintData) return;
8085
- void Promise.resolve(getPrintData()).then(
8086
- (source) => setPrintSource(source)
8087
- );
6833
+ void Promise.resolve(getPrintData()).then(setPrintSource);
8088
6834
  headerContextMenuRequest?.onClose();
8089
6835
  },
8090
6836
  onDirectPrint: () => {
8091
6837
  const request = headerContextMenuRequest;
8092
6838
  if (!request?.onGetPrintData) return;
8093
6839
  request.onClose();
8094
- void Promise.resolve(request.onGetPrintData()).then(
8095
- (source) => createCachedPrintTableOptions(
8096
- source,
8097
- storageKey ? `list:${storageKey}` : void 0,
8098
- props.printPresets
8099
- )
8100
- ).then((options2) => {
8101
- printBrowserTable(options2);
6840
+ const popup = window.open("", "_blank");
6841
+ if (!popup) return;
6842
+ void Promise.resolve(request.onGetPrintData()).then((source) => {
6843
+ printTableTemplate(source, popup);
8102
6844
  }).catch((error) => {
6845
+ popup.close();
8103
6846
  console.error("\u76F4\u63A5\u6253\u5370\u5931\u8D25", error);
8104
6847
  });
8105
6848
  },
@@ -8125,12 +6868,23 @@ function ReactListTableInner(props, ref) {
8125
6868
  ),
8126
6869
  printSource ? createPortal(
8127
6870
  /* @__PURE__ */ jsx(
8128
- ReactListTablePrintDialog,
6871
+ ReactListTablePrintDesignDialog,
8129
6872
  {
8130
6873
  source: printSource,
6874
+ storeKey: storageKey ? `list:${storageKey}` : void 0,
8131
6875
  printPresets: props.printPresets,
8132
- storageKey: storageKey ? `list:${storageKey}` : void 0,
8133
- onClose: () => setPrintSource(null),
6876
+ printTemplates: props.printTemplates,
6877
+ onClose: () => setPrintSource(null)
6878
+ }
6879
+ ),
6880
+ portalContainer
6881
+ ) : null,
6882
+ cacheConfigOpen && storageKey ? createPortal(
6883
+ /* @__PURE__ */ jsx(
6884
+ ReactListTableCacheConfigDialog,
6885
+ {
6886
+ storageKey,
6887
+ onClose: () => setCacheConfigOpen(false),
8134
6888
  renderTable: (tableProps) => /* @__PURE__ */ jsx(ReactListTable, { ...tableProps })
8135
6889
  }
8136
6890
  ),