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