@enableai-base/table 1.0.0

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.
@@ -0,0 +1,4465 @@
1
+ /**
2
+ * @enableai-base/table v1.0.0
3
+ * (c) 2024-present Enableai
4
+ * @license Proprietary
5
+ **/
6
+ 'use strict';
7
+
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+
10
+ var React = require('react');
11
+ var reactHooks = require('@enableai-sdk-common/react-hooks');
12
+ var core = require('@enableai-base/core');
13
+ var lodash = require('lodash');
14
+ var vrender = require('@visactor/vtable/es/vrender');
15
+ var color = require('@enableai-sdk-common/color');
16
+ var id = require('@enableai-sdk-common/id');
17
+ var store = require('@enableai-sdk-common/store');
18
+ var jotai = require('jotai');
19
+ var command = require('@enableai-sdk-common/command');
20
+ var fontIconEnableaiBase = require('@enableai-fonts/font-icon-enableai-base');
21
+ var dayjs = require('dayjs');
22
+ var customParseFormat = require('dayjs/plugin/customParseFormat');
23
+ var timezone = require('dayjs/plugin/timezone');
24
+ var utc = require('dayjs/plugin/utc');
25
+ var antd = require('antd');
26
+ var gridLayout = require('@enableai-base/grid-layout');
27
+ var icons = require('@ant-design/icons');
28
+ var ui = require('@enableai-base/ui');
29
+ var reactHotkeysHook = require('react-hotkeys-hook');
30
+ var core$1 = require('@enableai-sdk-common/core');
31
+ var VTable = require('@visactor/vtable');
32
+ var VTable_editors = require('@visactor/vtable-editors');
33
+
34
+ function _interopNamespaceDefault(e) {
35
+ var n = Object.create(null);
36
+ if (e) {
37
+ for (var k in e) {
38
+ n[k] = e[k];
39
+ }
40
+ }
41
+ n.default = e;
42
+ return Object.freeze(n);
43
+ }
44
+
45
+ var VTable__namespace = /*#__PURE__*/_interopNamespaceDefault(VTable);
46
+ var VTable_editors__namespace = /*#__PURE__*/_interopNamespaceDefault(VTable_editors);
47
+
48
+ const theme = {
49
+ selectionStyle: {
50
+ cellBorderColor: core.COLOR_BORDER_SELECTION,
51
+ cellBgColor: "rgba(255,255,255, 0.1)"
52
+ },
53
+ frameStyle: {
54
+ borderLineWidth: core.BORDER_LINE_WIDTH,
55
+ // 全局边框宽度
56
+ borderColor: core.BORDER_COLOR
57
+ // 全局边框颜色 最外面的方框
58
+ },
59
+ cellInnerBorder: true,
60
+ // 禁用内边框隐藏逻辑
61
+ defaultStyle: {
62
+ fontSize: core.DEFAULT_FONT_SIZE,
63
+ borderColor: core.BORDER_COLOR,
64
+ borderLineWidth: core.BORDER_LINE_WIDTH,
65
+ bgColor: core.COLOR_BG_CELL,
66
+ hover: {
67
+ // CustomCellStyle 设置的样式优先级更高
68
+ // TODO 感觉会变卡,后续优化,将样式设置属性放在 item 数据里面驱动控制
69
+ cellBgColor: ({ table, row, col }) => {
70
+ const cellStyle = table.getCellStyle(col, row);
71
+ const matched = core.CUSTOM_STYLE_LIST.filter((item) => lodash.isMatch(cellStyle, { bgColor: item.bgColor }));
72
+ if (matched.length) return cellStyle.bgColor;
73
+ return core.COLOR_BG_CELL_HOVER;
74
+ },
75
+ inlineRowBgColor: ({ table, row, col }) => {
76
+ const cellStyle = table.getCellStyle(col, row);
77
+ const matched = core.CUSTOM_STYLE_LIST.filter((item) => lodash.isMatch(cellStyle, { bgColor: item.bgColor }));
78
+ if (matched.length) return cellStyle.bgColor;
79
+ return core.COLOR_BG_CELL_HOVER;
80
+ }
81
+ }
82
+ },
83
+ headerStyle: {
84
+ fontSize: core.HEADER_FONT_SIZE
85
+ },
86
+ bodyStyle: {
87
+ fontSize: core.DEFAULT_FONT_SIZE
88
+ },
89
+ frozenColumnLine: {
90
+ shadow: {
91
+ width: 4,
92
+ startColor: "rgba(00, 24, 47, 0.05)",
93
+ endColor: "rgba(00, 24, 47, 0.03)",
94
+ visible: "always"
95
+ }
96
+ }
97
+ };
98
+
99
+ const { createUseContext, Provider: VTableProvider } = reactHooks.createContextWithProvider(
100
+ ({
101
+ id,
102
+ columns,
103
+ initialValues,
104
+ onChange,
105
+ ref,
106
+ theme: theme$1,
107
+ disabled = false,
108
+ debug = false,
109
+ cellMenus,
110
+ headerMenus,
111
+ moreMenus,
112
+ commandManager,
113
+ uploadFileFn,
114
+ innerColumnControl = {
115
+ checkbox: true,
116
+ main: true,
117
+ plus: true
118
+ },
119
+ ...rest
120
+ }) => {
121
+ const containerRef = React.useRef(null);
122
+ const editorRef = React.useRef(null);
123
+ React.useImperativeHandle(ref, () => {
124
+ return {
125
+ getEditor: () => editorRef.current
126
+ };
127
+ });
128
+ return {
129
+ id,
130
+ editorRef,
131
+ theme: theme$1 ?? theme,
132
+ columns,
133
+ records: initialValues,
134
+ containerRef,
135
+ disabled,
136
+ cellMenus,
137
+ headerMenus,
138
+ moreMenus,
139
+ onChange,
140
+ commandManager,
141
+ uploadFileFn,
142
+ innerColumnControl,
143
+ debug,
144
+ ...rest
145
+ };
146
+ }
147
+ );
148
+ const useComponentVTable = createUseContext();
149
+
150
+ const INNER_TABLE_COLUMN_KEY_PLUS = "INNER_TABLE_COLUMN_KEY_PLUS";
151
+ const INNER_TABLE_COLUMN_KEY_CHECKBOX = "INNER_TABLE_COLUMN_KEY_CHECKBOX";
152
+ const INNER_TABLE_COLUMN_KEY_LIST = [INNER_TABLE_COLUMN_KEY_PLUS, INNER_TABLE_COLUMN_KEY_CHECKBOX];
153
+ const INNER_TABLE_RECORD_ID_KEY = "INNER_PRESET_RECORD_ID";
154
+
155
+ const highlightMerge = (obj1, obj2) => {
156
+ return lodash.mergeWith({}, obj1, obj2, (objValue, srcValue) => {
157
+ if (Array.isArray(objValue)) {
158
+ return objValue.concat(srcValue);
159
+ }
160
+ });
161
+ };
162
+ const getColFromColIndex = (colIndex, innerColumnControl) => {
163
+ const hasCheckbox = innerColumnControl.checkbox;
164
+ return colIndex + (hasCheckbox ? 1 : 0);
165
+ };
166
+ const adaptedCellPosition = (col, row, innerColumnControl) => ({
167
+ col: getColFromColIndex(col, innerColumnControl),
168
+ row: getRowFromRowIndex(row)
169
+ });
170
+ const getRowFromRowIndex = (rowIndex) => rowIndex + 1;
171
+
172
+ function isValid(value) {
173
+ return value !== null && value !== void 0;
174
+ }
175
+ function getIconSizeFromFont(fontSize) {
176
+ return fontSize + 2;
177
+ }
178
+ function getFunctionalProp(name, cellStyle, col, row, _table) {
179
+ const prop = cellStyle && isValid(cellStyle[name]) ? cellStyle[name] : void 0;
180
+ if (typeof prop === "function") {
181
+ const arg = {
182
+ col,
183
+ row,
184
+ table: _table,
185
+ value: _table.getCellValue(col, row),
186
+ dataValue: _table.getCellOriginValue(col, row),
187
+ cellHeaderPaths: _table.getCellHeaderPaths(col, row)
188
+ };
189
+ return prop(arg);
190
+ }
191
+ return void 0;
192
+ }
193
+ function getProp(name, cellStyle, col, row, _table) {
194
+ const prop = cellStyle && isValid(cellStyle[name]) ? cellStyle[name] : void 0;
195
+ if (typeof prop === "function") {
196
+ const arg = {
197
+ col,
198
+ row,
199
+ table: _table,
200
+ value: _table.getCellValue(col, row),
201
+ dataValue: _table.getCellOriginValue(col, row),
202
+ cellHeaderPaths: _table.getCellHeaderPaths(col, row)
203
+ };
204
+ return prop(arg);
205
+ }
206
+ return prop ?? core.DEFAULT_FONT_SIZE;
207
+ }
208
+
209
+ const resolvePaddingLR = (padding) => {
210
+ if (typeof padding === "number") {
211
+ return [padding, padding];
212
+ } else {
213
+ if (padding.length === 2) {
214
+ return [padding[1], padding[1]];
215
+ } else if (padding.length === 4) {
216
+ return [padding[1], padding[3]];
217
+ }
218
+ }
219
+ throw new Error("padding \u683C\u5F0F\u9519\u8BEF");
220
+ };
221
+
222
+ function getAttribute(graphics) {
223
+ if ("attribute" in graphics) {
224
+ return graphics.attribute;
225
+ } else {
226
+ return graphics.props.attribute;
227
+ }
228
+ }
229
+ const createGraphicsWithLoading = (graphics, loading) => {
230
+ const attribute = getAttribute(graphics);
231
+ if (loading) {
232
+ const group = vrender.createGroup({
233
+ width: attribute.width,
234
+ height: attribute.height,
235
+ display: "flex",
236
+ alignItems: "center",
237
+ justifyContent: "center",
238
+ alignContent: "center"
239
+ });
240
+ const loadingImage = vrender.createImage({
241
+ width: 20,
242
+ height: 20,
243
+ image: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIGZpbGw9IiNjYWNhY2EiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIGZvY3VzYWJsZT0iZmFsc2UiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTk4OCA1NDhjLTE5LjkgMC0zNi0xNi4xLTM2LTM2IDAtNTkuNC0xMS42LTExNy0zNC42LTE3MS4zYTQ0MC40NSA0NDAuNDUgMCAwMC05NC4zLTEzOS45IDQzNy43MSA0MzcuNzEgMCAwMC0xMzkuOS05NC4zQzYyOSA4My42IDU3MS40IDcyIDUxMiA3MmMtMTkuOSAwLTM2LTE2LjEtMzYtMzZzMTYuMS0zNiAzNi0zNmM2OS4xIDAgMTM2LjIgMTMuNSAxOTkuMyA0MC4zQzc3Mi4zIDY2IDgyNyAxMDMgODc0IDE1MGM0NyA0NyA4My45IDEwMS44IDEwOS43IDE2Mi43IDI2LjcgNjMuMSA0MC4yIDEzMC4yIDQwLjIgMTk5LjMuMSAxOS45LTE2IDM2LTM1LjkgMzZ6IiAvPjwvc3ZnPg==",
244
+ anchor: [attribute.width / 2, attribute.height / 2],
245
+ cornerRadius: 10
246
+ });
247
+ loadingImage.animate().to(
248
+ {
249
+ angle: Math.PI * 2
250
+ },
251
+ 1e3,
252
+ "linear"
253
+ ).loop(Infinity);
254
+ group.add(loadingImage);
255
+ return group;
256
+ } else {
257
+ return graphics;
258
+ }
259
+ };
260
+
261
+ const createTextGraphics = (props) => {
262
+ const { table, row, col, rect } = props;
263
+ const { height, width } = rect ?? table.getCellRect(col, row);
264
+ const value = props.value?.value ?? "";
265
+ const loading = !!props.value?.loading;
266
+ const cellStyle = table._getCellStyle(col, row);
267
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
268
+ const functionalColor = getProp("color", cellStyle, col, row, table);
269
+ const parsedColor = props.color ?? functionalColor;
270
+ const padding = getProp("padding", cellStyle, col, row, table);
271
+ const paddingLR = resolvePaddingLR(padding);
272
+ const group = vrender.createGroup({
273
+ width,
274
+ height,
275
+ display: "flex",
276
+ flexWrap: "nowrap",
277
+ justifyContent: "space-around",
278
+ alignContent: "center",
279
+ alignItems: "center"
280
+ // 垂直居中
281
+ });
282
+ const text = vrender.createText({
283
+ fontSize: functionalFontSize,
284
+ fontFamily: "sans-serif",
285
+ text: value,
286
+ fill: parsedColor,
287
+ cursor: "pointer",
288
+ maxLineWidth: width - paddingLR[0] - paddingLR[1],
289
+ boundsPadding: padding
290
+ });
291
+ group.add(text);
292
+ return createGraphicsWithLoading(group, loading);
293
+ };
294
+
295
+ const createJsonGraphics = (props) => {
296
+ const value = props.value?.value ?? "";
297
+ let parsedValue = "";
298
+ try {
299
+ parsedValue = JSON.stringify(JSON.parse(value));
300
+ return createTextGraphics({
301
+ ...props,
302
+ value: {
303
+ ...props.value,
304
+ value: parsedValue
305
+ }
306
+ });
307
+ } catch {
308
+ return createTextGraphics({
309
+ ...props,
310
+ color: "red",
311
+ value: {
312
+ ...props.value,
313
+ value: "JSON Error"
314
+ }
315
+ });
316
+ }
317
+ };
318
+
319
+ const VTableEditorType = {
320
+ "TEXT_AREA": "textAreaEditor",
321
+ "INPUT": "inputEditor",
322
+ "DATE": "dateInputEditor",
323
+ "MULTI_SELECT": "multiSelectEditor",
324
+ "SINGLE_SELECT": "singleSelectEditor",
325
+ "LINK": "linkEditor",
326
+ "NUMBER": "numberEditor",
327
+ "TEXT": "textEditor",
328
+ "JSON": "jsonEditor"
329
+ };
330
+
331
+ const toolTypeToEditorMap = /* @__PURE__ */ new Map([
332
+ [29, "singleSelectEditor"],
333
+ [30, "multiSelectEditor"],
334
+ [36, "dateInputEditor"],
335
+ [33, "linkEditor"],
336
+ [34, "jsonEditor"],
337
+ [31, "numberEditor"],
338
+ [37, "numberEditor"],
339
+ // 多个 key 映射到同一个 value
340
+ [28, "textEditor"],
341
+ [35, "textEditor"]
342
+ ]);
343
+ const getEditorByToolType = (toolType) => {
344
+ return toolTypeToEditorMap.get(toolType) ?? void 0;
345
+ };
346
+
347
+ const baseCreator = (data, _innerColumnControl) => {
348
+ const { id, label, lock, width, type, options } = data;
349
+ const minWidth = 100;
350
+ const baseColumn = {
351
+ field: id,
352
+ title: label,
353
+ lock,
354
+ width: Math.max(minWidth, width ?? 0),
355
+ minWidth,
356
+ tool: type,
357
+ fmt: data.default?.format,
358
+ options,
359
+ request: data.request,
360
+ editor: getEditorByToolType(type),
361
+ // 默认表头渲染函数
362
+ headerCustomLayout: (args) => {
363
+ return {
364
+ rootContainer: createHeaderGraphics(type, args),
365
+ renderDefault: false
366
+ };
367
+ },
368
+ customLayout: (args) => {
369
+ return {
370
+ rootContainer: createTextGraphics(args),
371
+ renderDefault: false
372
+ };
373
+ }
374
+ };
375
+ return baseColumn;
376
+ };
377
+ const textColumnCreator = (data, innerColumnControl) => {
378
+ const baseColumn = baseCreator(data);
379
+ return {
380
+ ...baseColumn,
381
+ customLayout: (args) => {
382
+ return {
383
+ rootContainer: createTextGraphics(args),
384
+ renderDefault: false
385
+ };
386
+ }
387
+ };
388
+ };
389
+ const simpleSelectColumnCreator = (data, innerColumnControl) => {
390
+ const baseColumn = baseCreator(data);
391
+ return {
392
+ ...baseColumn,
393
+ editor: "singleSelectEditor",
394
+ customLayout: (args) => {
395
+ return {
396
+ rootContainer: createSingleSelectGraphic(args),
397
+ renderDefault: false
398
+ };
399
+ }
400
+ };
401
+ };
402
+ const multiSelectColumnCreator = (data, innerColumnControl) => {
403
+ const baseColumn = baseCreator(data);
404
+ return {
405
+ ...baseColumn,
406
+ editor: "multiSelectEditor",
407
+ customLayout: (args) => {
408
+ const { table, row, col, rect } = args;
409
+ const { height, width } = rect ?? table.getCellRect(col, row);
410
+ return {
411
+ rootContainer: createMultiSelectGraphic({ width, height, ...args }),
412
+ renderDefault: false
413
+ };
414
+ }
415
+ };
416
+ };
417
+ const numberColumnCreator = (data, innerColumnControl) => {
418
+ const baseColumn = baseCreator(data);
419
+ return {
420
+ ...baseColumn,
421
+ fmt: data.default?.format,
422
+ // editor: "numberEditor",
423
+ customLayout: (args) => {
424
+ return {
425
+ rootContainer: createNumberGraphics({
426
+ ...args,
427
+ textAlign: "right"
428
+ }),
429
+ renderDefault: false
430
+ };
431
+ }
432
+ };
433
+ };
434
+ const attachmentColumnCreator = (data, innerColumnControl) => {
435
+ const baseColumn = baseCreator(data);
436
+ return {
437
+ ...baseColumn,
438
+ customLayout: (args) => {
439
+ return {
440
+ rootContainer: createUploadDocumentGraphics(args),
441
+ renderDefault: false
442
+ };
443
+ }
444
+ };
445
+ };
446
+ const linkColumnCreator = (data, innerColumnControl) => {
447
+ const baseColumn = baseCreator(data);
448
+ return {
449
+ ...baseColumn,
450
+ customLayout: (args) => {
451
+ return {
452
+ rootContainer: createLinkGraphics(args),
453
+ renderDefault: false
454
+ };
455
+ }
456
+ };
457
+ };
458
+ const dateColumnCreator = (data, innerColumnControl) => {
459
+ const baseColumn = baseCreator(data);
460
+ return {
461
+ ...baseColumn,
462
+ fmt: data.default?.format,
463
+ customLayout: (args) => {
464
+ return {
465
+ rootContainer: createDateGraphics(args),
466
+ renderDefault: false
467
+ };
468
+ }
469
+ };
470
+ };
471
+ const timeLenColumnCreator = (data, innerColumnControl) => {
472
+ const baseColumn = baseCreator(data);
473
+ return {
474
+ ...baseColumn,
475
+ // NOTE: editor 为 number 输入整型
476
+ fmt: "integer",
477
+ customLayout: (args) => {
478
+ return {
479
+ rootContainer: createTimeLenGraphics(args),
480
+ renderDefault: false
481
+ };
482
+ }
483
+ };
484
+ };
485
+ const userColumnCreator = (data, innerColumnControl) => {
486
+ const baseColumn = baseCreator(data);
487
+ return {
488
+ ...baseColumn,
489
+ customLayout: (args) => {
490
+ return {
491
+ rootContainer: createPeopleGraphics(args),
492
+ renderDefault: false
493
+ };
494
+ }
495
+ };
496
+ };
497
+ const tagColumnCreator = (data, innerColumnControl) => {
498
+ const baseColumn = baseCreator(data);
499
+ return {
500
+ ...baseColumn,
501
+ customLayout: (args) => {
502
+ return {
503
+ rootContainer: createTagGraphic(args),
504
+ renderDefault: false
505
+ };
506
+ }
507
+ };
508
+ };
509
+ const jsonColumnCreator = (data, innerColumnControl) => {
510
+ const baseColumn = baseCreator(data);
511
+ return {
512
+ ...baseColumn,
513
+ customLayout: (args) => {
514
+ return {
515
+ rootContainer: createJsonGraphics(args),
516
+ renderDefault: false
517
+ };
518
+ }
519
+ };
520
+ };
521
+ const dropdownColumnCreator = (data, innerColumnControl) => {
522
+ const baseColumn = baseCreator(data);
523
+ return {
524
+ ...baseColumn,
525
+ dragHeader: false,
526
+ customLayout: (args) => {
527
+ return {
528
+ rootContainer: createMoreGraphics(args),
529
+ renderDefault: false
530
+ };
531
+ }
532
+ };
533
+ };
534
+ const checkboxColumnCreator = (data, innerColumnControl) => {
535
+ const baseColumn = baseCreator(data);
536
+ return {
537
+ ...baseColumn,
538
+ lock: true,
539
+ width: 40,
540
+ minWidth: 40,
541
+ headerType: "checkbox",
542
+ //指定表头单元格显示为复选框
543
+ cellType: "checkbox",
544
+ //指定body单元格显示为复选框
545
+ field: INNER_TABLE_COLUMN_KEY_CHECKBOX,
546
+ disable: false,
547
+ disableColumnResize: true,
548
+ disableSelect: true,
549
+ disableHeaderSelect: true,
550
+ dragHeader: false,
551
+ headerStyle: {
552
+ borderLineWidth: [1, 0, 1, 1],
553
+ // 上右下左的边框宽度
554
+ marked: false
555
+ },
556
+ style: {
557
+ borderLineWidth: [1, 0, 1, 1],
558
+ // 上右下左的边框宽度
559
+ marked: false
560
+ }
561
+ };
562
+ };
563
+ const plusColumnCreator = (data, innerColumnControl) => {
564
+ const baseColumn = baseCreator(data);
565
+ return {
566
+ ...baseColumn,
567
+ dragHeader: false,
568
+ field: INNER_TABLE_COLUMN_KEY_PLUS,
569
+ width: 50,
570
+ disable: true,
571
+ disableHover: true,
572
+ disableHeaderSelect: true,
573
+ disableColumnResize: true,
574
+ disableSelect: true,
575
+ headerCustomLayout: (args) => {
576
+ return {
577
+ rootContainer: createPlusHeaderGraphics(args),
578
+ renderDefault: false
579
+ };
580
+ },
581
+ style: {
582
+ borderLineWidth: ({ row, table }) => {
583
+ if (row === 1) return [1, 1, 0, 1];
584
+ if (row === table.rowCount - 1) return [0, 1, 1, 1];
585
+ return [0, 1, 0, 1];
586
+ }
587
+ }
588
+ };
589
+ };
590
+ const moreColumnCreator = (data, innerColumnControl) => {
591
+ const baseColumn = baseCreator(data);
592
+ return {
593
+ ...baseColumn,
594
+ field: "more",
595
+ title: "\u66F4\u591A",
596
+ dragHeader: false,
597
+ customLayout: (args) => {
598
+ return {
599
+ rootContainer: createMoreGraphics(args),
600
+ renderDefault: false
601
+ };
602
+ }
603
+ };
604
+ };
605
+ const mainColumnCreator = (data, innerColumnControl) => {
606
+ const baseColumn = baseCreator(data);
607
+ const mainKeyColumn = {
608
+ ...baseColumn,
609
+ tool: 28,
610
+ lock: true,
611
+ field: data.id,
612
+ dragHeader: false,
613
+ title: data.label,
614
+ width: 200,
615
+ headerStyle: {
616
+ borderLineWidth: [1, 1, 1, 0]
617
+ // 上右下左的边框宽度
618
+ },
619
+ style: {
620
+ borderLineWidth: [1, 1, 1, 0]
621
+ // 上右下左的边框宽度
622
+ },
623
+ headerCustomLayout: (args) => {
624
+ return {
625
+ rootContainer: createHeaderGraphics(28, args),
626
+ renderDefault: false
627
+ };
628
+ },
629
+ customLayout: (args) => {
630
+ return {
631
+ rootContainer: createMainColumnCellGraphics(args),
632
+ renderDefault: false
633
+ };
634
+ }
635
+ };
636
+ return mainKeyColumn;
637
+ };
638
+ const createColumns = (data, innerColumnControl) => {
639
+ const creator = creatorMap.get(data.type) ?? baseCreator;
640
+ return lodash.castArray(creator(data, innerColumnControl));
641
+ };
642
+ const creatorMap = /* @__PURE__ */ new Map([
643
+ [28, textColumnCreator],
644
+ [29, simpleSelectColumnCreator],
645
+ [30, multiSelectColumnCreator],
646
+ [31, numberColumnCreator],
647
+ [36, dateColumnCreator],
648
+ [33, linkColumnCreator],
649
+ [32, attachmentColumnCreator],
650
+ [37, timeLenColumnCreator],
651
+ [38, userColumnCreator],
652
+ [35, tagColumnCreator],
653
+ [34, jsonColumnCreator],
654
+ [39, dropdownColumnCreator],
655
+ /** 表格内置列 */
656
+ [-1, checkboxColumnCreator],
657
+ [-3, plusColumnCreator],
658
+ [-2, moreColumnCreator],
659
+ [-4, mainColumnCreator]
660
+ ]);
661
+
662
+ const adaptColumnStructure = (originalColumns, innerColumnControl) => {
663
+ const hasMainColumn = innerColumnControl.main;
664
+ const columnFeedbacksErrors = [];
665
+ const adaptedColumns = originalColumns.map((column, colIndex) => {
666
+ if (column.feedbacks && column.feedbacks.length > 0) {
667
+ columnFeedbacksErrors.push({
668
+ type: "column",
669
+ col: getColFromColIndex(colIndex, innerColumnControl),
670
+ info: column.feedbacks
671
+ });
672
+ }
673
+ return createColumns(
674
+ {
675
+ ...column,
676
+ // TODO: any
677
+ type: colIndex === 0 && hasMainColumn && [28, 31].includes(column.type) ? -4 : column.type
678
+ },
679
+ innerColumnControl
680
+ );
681
+ }).flat();
682
+ if (innerColumnControl.checkbox) {
683
+ adaptedColumns.unshift(
684
+ checkboxColumnCreator(
685
+ {
686
+ type: -1,
687
+ id: INNER_TABLE_COLUMN_KEY_CHECKBOX,
688
+ label: ""
689
+ })
690
+ );
691
+ }
692
+ if (innerColumnControl.plus)
693
+ adaptedColumns.push(
694
+ plusColumnCreator(
695
+ {
696
+ type: -3,
697
+ id: INNER_TABLE_COLUMN_KEY_PLUS,
698
+ label: ""
699
+ })
700
+ );
701
+ return {
702
+ columns: adaptedColumns,
703
+ feedbacksHighlight: {
704
+ [core.CUSTOM_CELL_STYLE_FEEDBACK_ERROR]: [...columnFeedbacksErrors]
705
+ }
706
+ };
707
+ };
708
+
709
+ const adaptRecordStructure = (record) => {
710
+ const { id, cells } = record;
711
+ const cellValues = Object.entries(cells).map(([columnId, data]) => {
712
+ const { id: id2, value, loading, feedbacks } = data ?? {};
713
+ const realId = !id2 ? columnId : id2;
714
+ return [columnId, { id: realId, value, loading, feedbacks }];
715
+ });
716
+ return {
717
+ [INNER_TABLE_RECORD_ID_KEY]: id,
718
+ ...Object.fromEntries(cellValues)
719
+ };
720
+ };
721
+ const revertRecordStructure = (tableRecord) => {
722
+ const { [INNER_TABLE_RECORD_ID_KEY]: recordId, ...cellsMap } = tableRecord;
723
+ const cells = Object.fromEntries(
724
+ Object.entries(cellsMap).map(([columnId, cellData]) => {
725
+ const { id, value, loading, feedbacks } = cellData ?? {};
726
+ const realId = !id ? columnId : id;
727
+ return [
728
+ columnId,
729
+ {
730
+ id: realId,
731
+ value,
732
+ loading,
733
+ feedbacks
734
+ }
735
+ ];
736
+ })
737
+ );
738
+ return {
739
+ id: recordId,
740
+ cells
741
+ };
742
+ };
743
+ const adaptRecordsStructure = (records, adapterColumns, innerColumnControl) => {
744
+ const fields = adapterColumns.map((column) => column.field);
745
+ const rowFeedbacksErrors = [];
746
+ const cellFeedbacksErrors = [];
747
+ const rows = records.map((record, rowIndex) => {
748
+ const { id, feedbacks, cells } = record;
749
+ const cellValues = Object.entries(cells).map(([columnId, { id: id2, value, loading, feedbacks: feedbacks2 }]) => {
750
+ if (feedbacks2 && feedbacks2.length) {
751
+ cellFeedbacksErrors.push({
752
+ type: "cell",
753
+ col: fields.indexOf(columnId),
754
+ row: getRowFromRowIndex(rowIndex),
755
+ info: feedbacks2 ?? []
756
+ });
757
+ }
758
+ const realId = !id2 ? columnId : id2;
759
+ return [columnId, { id: realId, value, loading, feedbacks: feedbacks2 }];
760
+ });
761
+ if (feedbacks && feedbacks.length) {
762
+ rowFeedbacksErrors.push({
763
+ type: "row",
764
+ col: getColFromColIndex(0, innerColumnControl),
765
+ row: getRowFromRowIndex(rowIndex),
766
+ info: feedbacks ?? []
767
+ });
768
+ }
769
+ return {
770
+ [INNER_TABLE_RECORD_ID_KEY]: id,
771
+ ...Object.fromEntries(cellValues)
772
+ };
773
+ });
774
+ return {
775
+ records: rows,
776
+ feedbacksHighlight: {
777
+ [core.CUSTOM_CELL_STYLE_FEEDBACK_ERROR]: [...cellFeedbacksErrors, ...rowFeedbacksErrors]
778
+ }
779
+ };
780
+ };
781
+
782
+ const { setDateEditorData, getDateEditorData, useDateEditorData } = store.createAtomStore(
783
+ "dateEditorData",
784
+ jotai.atom()
785
+ );
786
+ const { setDateEditorValue, getDateEditorValue, useDateEditorValue } = store.createAtomStore(
787
+ "dateEditorValue",
788
+ jotai.atom()
789
+ );
790
+ const initDateEditorTool = (value) => {
791
+ const { initialValue } = value;
792
+ setDateEditorData(value);
793
+ setDateEditorValue(initialValue);
794
+ };
795
+ const clearDateEditorTool = () => {
796
+ setDateEditorData(void 0);
797
+ setDateEditorValue(void 0);
798
+ };
799
+
800
+ const { getActiveEditorTable, setActiveEditorTable, useActiveEditorTable } = store.createAtomStore(
801
+ "activeEditorTable",
802
+ jotai.atom(
803
+ (get) => {
804
+ const map = get(editorTableStoreAtom);
805
+ const activeId = get(activeTableIdAtom);
806
+ if (!activeId) throw new Error("activeTableId is empty");
807
+ return map.get(activeId);
808
+ },
809
+ () => {
810
+ throw new Error("activeEditorTable is empty");
811
+ }
812
+ )
813
+ );
814
+ const { setActiveTableId, getActiveTableId, useActiveTableId, activeTableIdAtom } = store.createAtomStore(
815
+ "activeTableId",
816
+ jotai.atom()
817
+ );
818
+ const { setEditorTableStore, getEditorTableStore, useEditorTableStore, editorTableStoreAtom } = store.createAtomStore(
819
+ "editorTableStore",
820
+ jotai.atom(/* @__PURE__ */ new Map())
821
+ );
822
+
823
+ const dateProcess = (data, dateFormat) => {
824
+ const originalFullDayjs = dayjs(data.initialValue);
825
+ const isSpecialFormat = dateFormat === "MM-DD" || dateFormat.includes("MM") && dateFormat.includes("DD") && !dateFormat.includes("YYYY") || dateFormat === "MM/DD/YYYY" || dateFormat === "DD/MM/YYYY";
826
+ if (isSpecialFormat) {
827
+ return originalFullDayjs.isValid() ? originalFullDayjs : dayjs();
828
+ } else {
829
+ return dayjs(data.initialValue, dateFormat).isValid() ? dayjs(data.initialValue, dateFormat) : dayjs();
830
+ }
831
+ };
832
+
833
+ const DateSelect = () => {
834
+ const data = useDateEditorData();
835
+ if (!data) return null;
836
+ const tableEditor = getActiveEditorTable();
837
+ let dateFormat = "";
838
+ const column = tableEditor?.getColumnDefine(data?.cell?.col);
839
+ if (column.fmt) {
840
+ dateFormat = column.fmt || "YYYY/MM/DD HH:mm";
841
+ }
842
+ setDateEditorValue(data.initialValue);
843
+ const validDayjs = dateProcess(data, dateFormat);
844
+ const TZ_SUFFIX = " (GMT+8)";
845
+ const hasTimezone = dateFormat.endsWith(TZ_SUFFIX);
846
+ const pureFormat = hasTimezone ? dateFormat.replace(TZ_SUFFIX, "") : dateFormat;
847
+ const hasTime = /(HH|hh):mm(:ss)?/.test(pureFormat);
848
+ const formatDateDisplay = (date) => {
849
+ if (!date) return "";
850
+ const baseText = date.format(pureFormat);
851
+ return hasTimezone ? `${baseText} (GMT+8)` : baseText;
852
+ };
853
+ return /* @__PURE__ */ React.createElement(
854
+ antd.Popover,
855
+ {
856
+ trigger: "click",
857
+ className: "popoverDate",
858
+ arrow: false,
859
+ open: true,
860
+ align: {
861
+ points: ["tl", "bl"],
862
+ offset: [0, 10]
863
+ }
864
+ },
865
+ /* @__PURE__ */ React.createElement(
866
+ antd.DatePicker,
867
+ {
868
+ defaultValue: validDayjs,
869
+ format: formatDateDisplay,
870
+ defaultOpen: true,
871
+ showTime: hasTime ? { format: pureFormat } : false,
872
+ allowClear: false,
873
+ onChange: (value) => {
874
+ let targetDayjs;
875
+ if (Array.isArray(value)) {
876
+ targetDayjs = value[0] || null;
877
+ } else {
878
+ targetDayjs = value;
879
+ }
880
+ if (!targetDayjs) return;
881
+ const finalFormat = hasTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD";
882
+ const finalValue = targetDayjs.format(finalFormat);
883
+ if (!hasTime) {
884
+ if (data.initialValue?.value) {
885
+ const originalDayjs = dayjs(data.initialValue.value);
886
+ const hour = originalDayjs.hour();
887
+ const minute = originalDayjs.minute();
888
+ const second = originalDayjs.second();
889
+ const newDayjs = targetDayjs.hour(hour).minute(minute).second(second);
890
+ setDateEditorValue(newDayjs.format("YYYY-MM-DD HH:mm:ss"));
891
+ } else {
892
+ setDateEditorValue(targetDayjs.hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"));
893
+ }
894
+ } else {
895
+ setDateEditorValue(finalValue);
896
+ }
897
+ data.endEdit();
898
+ },
899
+ style: {
900
+ position: "absolute",
901
+ left: data.cell.position.x,
902
+ top: data.cell.position.y,
903
+ width: data.cell.width,
904
+ height: data.cell.height
905
+ }
906
+ }
907
+ )
908
+ );
909
+ };
910
+
911
+ const { setJsonEditorData, getJsonEditorData, useJsonEditorData } = store.createAtomStore(
912
+ "jsonEditorData",
913
+ jotai.atom()
914
+ );
915
+ const { setJsonEditorValue, getJsonEditorValue, useJsonEditorValue } = store.createAtomStore(
916
+ "jsonEditorValue",
917
+ jotai.atom()
918
+ );
919
+ const initJsonEditorTool = (value) => {
920
+ const { initialValue } = value;
921
+ setJsonEditorData(value);
922
+ setJsonEditorValue(initialValue);
923
+ };
924
+ const clearJsonEditorTool = () => {
925
+ setJsonEditorData(void 0);
926
+ setJsonEditorValue(void 0);
927
+ };
928
+
929
+ const TableJsonEditor = () => {
930
+ const jsonEditorData = useJsonEditorData();
931
+ const jsonEditorValue = useJsonEditorValue();
932
+ const clcHeight = React.useMemo(() => {
933
+ const lineCount = (jsonEditorValue ?? "").split("\n").length;
934
+ return lineCount * 20;
935
+ }, [jsonEditorValue]);
936
+ if (!jsonEditorData) return null;
937
+ const editor = getActiveEditorTable();
938
+ if (!editor) throw new Error("TableJsonEditor: editor is null");
939
+ const { cell, table } = jsonEditorData;
940
+ const { position, width } = cell;
941
+ const cellStyle = table._getCellStyle(cell.col, cell.row);
942
+ const fontSize = getProp("fontSize", cellStyle, cell.col, cell.row, table);
943
+ return /* @__PURE__ */ React.createElement(
944
+ "div",
945
+ {
946
+ className: "json-editor-modal-container",
947
+ style: {
948
+ fontSize,
949
+ width,
950
+ height: clcHeight,
951
+ minHeight: 100,
952
+ maxHeight: 300,
953
+ position: "absolute",
954
+ top: position.y,
955
+ left: position.x
956
+ }
957
+ },
958
+ /* @__PURE__ */ React.createElement(gridLayout.JsonEditor, { value: jsonEditorData.initialValue, onChange: (value) => setJsonEditorValue(value), dark: false })
959
+ );
960
+ };
961
+
962
+ const { setLinkEditorData, getLinkEditorData, useLinkEditorData } = store.createAtomStore(
963
+ "linkEditorData",
964
+ jotai.atom()
965
+ );
966
+ const { setLinkEditorValue, getLinkEditorValue, useLinkEditorValue } = store.createAtomStore(
967
+ "linkEditorValue",
968
+ jotai.atom()
969
+ );
970
+ const initLinkEditorTool = (value) => {
971
+ const { initialValue } = value;
972
+ setLinkEditorData(value);
973
+ setLinkEditorValue(initialValue);
974
+ };
975
+ const clearLinkEditorTool = () => {
976
+ setLinkEditorData(void 0);
977
+ setLinkEditorValue(void 0);
978
+ };
979
+
980
+ const LinkEditor = ({}) => {
981
+ const [popContentVisible, setPopContentVisible] = React.useState(false);
982
+ const data = useLinkEditorData();
983
+ const linkValue = useLinkEditorValue();
984
+ const cancel = React.useCallback(() => {
985
+ setLinkEditorValue({ ...data?.initialValue ?? {} });
986
+ data?.endEdit();
987
+ }, [data]);
988
+ const confirm = React.useCallback(() => data?.endEdit(), [data]);
989
+ if (!data) return null;
990
+ return /* @__PURE__ */ React.createElement(
991
+ antd.Popover,
992
+ {
993
+ open: popContentVisible,
994
+ content: /* @__PURE__ */ React.createElement(antd.Form, { className: "link-editor-form", layout: "vertical", style: { width: 300 } }, /* @__PURE__ */ React.createElement(antd.Form.Item, { label: "\u6587\u672C", className: "link-editor-form-item" }, /* @__PURE__ */ React.createElement(
995
+ antd.Input,
996
+ {
997
+ defaultValue: linkValue?.title ?? "",
998
+ onChange: (e) => setLinkEditorValue((v) => ({ ...v ?? {}, title: e.target.value }))
999
+ }
1000
+ )), /* @__PURE__ */ React.createElement(antd.Form.Item, { label: "\u8D85\u94FE\u63A5", className: "link-editor-form-item" }, /* @__PURE__ */ React.createElement(
1001
+ antd.Input,
1002
+ {
1003
+ defaultValue: linkValue?.url ?? "",
1004
+ onChange: (e) => setLinkEditorValue((v) => ({ ...v ?? {}, url: e.target.value }))
1005
+ }
1006
+ )), /* @__PURE__ */ React.createElement(antd.Flex, { justify: "flex-end" }, /* @__PURE__ */ React.createElement(antd.Space, null, /* @__PURE__ */ React.createElement(antd.Button, { onClick: cancel }, "\u53D6\u6D88"), /* @__PURE__ */ React.createElement(antd.Button, { type: "primary", onClick: confirm }, "\u786E\u5B9A")))),
1007
+ rootClassName: "link-editor-popover-root",
1008
+ className: "link-editor-popover",
1009
+ arrow: false,
1010
+ align: {
1011
+ points: ["tl", "bl"],
1012
+ // tl(top-left): 将【pop弹窗】左上角 与 Input bl(bottom-left) 左下角对齐
1013
+ offset: [0, 10]
1014
+ }
1015
+ },
1016
+ /* @__PURE__ */ React.createElement(
1017
+ antd.Flex,
1018
+ {
1019
+ style: {
1020
+ border: `2px solid ${core.COLOR_BORDER_SELECTION}`,
1021
+ backgroundColor: core.COLOR_BG_CELL,
1022
+ borderRadius: 0,
1023
+ position: "absolute",
1024
+ left: data.cell.position.x - 2,
1025
+ top: data.cell.position.y - 2,
1026
+ width: data.cell.width + 4,
1027
+ height: data.cell.height + 4
1028
+ },
1029
+ align: "center"
1030
+ },
1031
+ /* @__PURE__ */ React.createElement(
1032
+ antd.Input,
1033
+ {
1034
+ className: "link-editor-input",
1035
+ style: {
1036
+ color: core.COLOR_LINK,
1037
+ border: "unset",
1038
+ borderRadius: 0,
1039
+ height: data.cell.height - 2,
1040
+ boxSizing: "border-box"
1041
+ },
1042
+ defaultValue: linkValue?.title ?? "",
1043
+ onChange: (e) => setLinkEditorValue((v) => ({ ...v ?? {}, title: e.target.value })),
1044
+ onFocus: () => setPopContentVisible(false)
1045
+ }
1046
+ ),
1047
+ /* @__PURE__ */ React.createElement(
1048
+ antd.Button,
1049
+ {
1050
+ type: "text",
1051
+ icon: /* @__PURE__ */ React.createElement(icons.LinkOutlined, null),
1052
+ style: {
1053
+ border: "unset",
1054
+ borderRadius: 0,
1055
+ height: data.cell.height - 2,
1056
+ boxSizing: "border-box"
1057
+ },
1058
+ onClick: () => setPopContentVisible(!popContentVisible)
1059
+ }
1060
+ )
1061
+ )
1062
+ );
1063
+ };
1064
+
1065
+ const { setNumEditorValue, getNumEditorValue, useNumEditorValue } = store.createAtomStore(
1066
+ "numEditorValue",
1067
+ jotai.atom()
1068
+ );
1069
+ const { setNumEditorData, getNumEditorData, useNumEditorData } = store.createAtomStore(
1070
+ "numEditorData",
1071
+ jotai.atom()
1072
+ );
1073
+ const initNumEditorTool = (data) => {
1074
+ setNumEditorData(data);
1075
+ setNumEditorValue(data.initialValue);
1076
+ };
1077
+ const clearNumEditorTool = () => {
1078
+ setNumEditorData(void 0);
1079
+ setNumEditorValue(void 0);
1080
+ };
1081
+
1082
+ const NumEditor = () => {
1083
+ const numEditorData = useNumEditorData();
1084
+ if (!numEditorData) return null;
1085
+ const { cell, table } = numEditorData;
1086
+ const { position, width, height } = cell;
1087
+ const cellStyle = table._getCellStyle(cell.col, cell.row);
1088
+ const fontSize = getProp("fontSize", cellStyle, cell.col, cell.row, table);
1089
+ const bgColor = getProp("bgColor", cellStyle, cell.col, cell.row, table);
1090
+ return /* @__PURE__ */ React.createElement(
1091
+ antd.InputNumber,
1092
+ {
1093
+ defaultValue: numEditorData.initialValue,
1094
+ onChange: (value) => setNumEditorValue(value),
1095
+ controls: false,
1096
+ className: "num-editor-input",
1097
+ style: {
1098
+ position: "absolute",
1099
+ left: position.x - 2,
1100
+ top: position.y - 2,
1101
+ width: width + 4,
1102
+ minHeight: height + 4,
1103
+ background: bgColor,
1104
+ border: "2px solid #0404ff",
1105
+ borderRadius: 0,
1106
+ fontSize,
1107
+ scrollbarWidth: "none"
1108
+ }
1109
+ }
1110
+ );
1111
+ };
1112
+
1113
+ const { setSelectEditorData, getSelectEditorData, useSelectEditorData } = store.createAtomStore(
1114
+ "selectEditorData",
1115
+ jotai.atom(null)
1116
+ );
1117
+ const { setSelectEditorValue, getSelectEditorValue, useSelectEditorValue } = store.createAtomStore(
1118
+ "selectEditorValue",
1119
+ jotai.atom([])
1120
+ );
1121
+ const initSelectEditorTool = (value) => {
1122
+ const { initialValue } = value;
1123
+ setSelectEditorData(value);
1124
+ setSelectEditorValue(initialValue);
1125
+ };
1126
+ const clearSelectEditorTool = () => {
1127
+ setSelectEditorData(null);
1128
+ setSelectEditorValue([]);
1129
+ };
1130
+
1131
+ const TableChangeEvent = {
1132
+ "CELLS_UPDATE": "cells::update",
1133
+ "CELL_CLICK": "cell::click",
1134
+ "CELL_ATTACHMENT_PREVIEW": "cell::attachment::preview",
1135
+ "SELECT_OPTIONS_UPDATE": "select::options::update",
1136
+ "RECORD_OPEN_DETAIL_DRAWER": "record::open::detail::drawer",
1137
+ "RECORD_CHECKBOX_STATE_CHANGE": "record::checkbox::state::change",
1138
+ "COLUMN_WIDTH_UPDATE": "column::width::update",
1139
+ "COLUMN_DRAG_MOVE_END": "column::drag::move::end",
1140
+ "COLUMN_ADD_FROM_INNER_PLUS": "column::add::from::inner::plus"
1141
+ };
1142
+
1143
+ const EDIT_TABLE_CELL_DATA_COMMAND_ID = Symbol("EDIT_TABLE_CELL_DATA_COMMAND_ID");
1144
+ const EDIT_TABLE_CELL_DATA_COMMAND_LABEL = "\u7F16\u8F91\u8868\u683C\u5355\u5143\u683C\u6570\u636E\u901A\u7528\u547D\u4EE4";
1145
+ class EditTableCellDataCommand extends command.Command {
1146
+ constructor(editor, col, row, value, oldValue) {
1147
+ super();
1148
+ this.editor = editor;
1149
+ this.col = col;
1150
+ this.row = row;
1151
+ this.value = value;
1152
+ this.oldValue = oldValue;
1153
+ this.id = EDIT_TABLE_CELL_DATA_COMMAND_ID;
1154
+ this.label = EDIT_TABLE_CELL_DATA_COMMAND_LABEL;
1155
+ }
1156
+ get readonly() {
1157
+ const columnDefine = this.editor.getColumnDefine(this.col);
1158
+ return this.editor.lock || !!columnDefine?.lock;
1159
+ }
1160
+ execute(_props) {
1161
+ this.editor.updateCellData(this.col, this.row, this.value);
1162
+ const { columnId, recordId } = this.editor.getInteractiveCell(this.col, this.row);
1163
+ this.editor.dispatch("cells::update", {
1164
+ editor: this.editor,
1165
+ data: [
1166
+ {
1167
+ recordId,
1168
+ columnId,
1169
+ previous: this.oldValue,
1170
+ current: this.value
1171
+ }
1172
+ ]
1173
+ });
1174
+ }
1175
+ undo(_props) {
1176
+ this.editor.updateCellData(this.col, this.row, this.oldValue);
1177
+ const { columnId, recordId } = this.editor.getInteractiveCell(this.col, this.row);
1178
+ this.editor.dispatch("cells::update", {
1179
+ editor: this.editor,
1180
+ data: [
1181
+ {
1182
+ recordId,
1183
+ columnId,
1184
+ previous: this.value,
1185
+ current: this.oldValue
1186
+ }
1187
+ ]
1188
+ });
1189
+ }
1190
+ }
1191
+ const EDIT_TABLE_CELL_DATA_FUNCTIONAL_COMMAND_ID = Symbol("EDIT_TABLE_CELL_DATA_FUNCTIONAL_COMMAND_ID");
1192
+ const EDIT_TABLE_CELL_DATA_FUNCTIONAL_COMMAND_LABEL = "\u7F16\u8F91\u8868\u683C\u5355\u5143\u683C\u6570\u636E\u901A\u7528\u51FD\u6570\u5F0F\u547D\u4EE4";
1193
+ class EditTableCellDataFunctionalCommand extends command.Command {
1194
+ constructor(table, fn) {
1195
+ super();
1196
+ this.table = table;
1197
+ this.fn = fn;
1198
+ this.id = EDIT_TABLE_CELL_DATA_FUNCTIONAL_COMMAND_ID;
1199
+ this.label = EDIT_TABLE_CELL_DATA_FUNCTIONAL_COMMAND_LABEL;
1200
+ }
1201
+ get readonly() {
1202
+ return this.table.lock;
1203
+ }
1204
+ execute(_props) {
1205
+ const { restore } = this.fn();
1206
+ this._restore = restore;
1207
+ }
1208
+ undo(_props) {
1209
+ if (!this._restore) {
1210
+ throw new Error(`[EditTableCellCommand id: ${this.id.toString()} label: ${this.label}] \u672A\u6307\u5B9A\u6062\u590D\u51FD\u6570`);
1211
+ }
1212
+ this._restore();
1213
+ this._restore = void 0;
1214
+ }
1215
+ }
1216
+
1217
+ const updateSelectEditorCell = (col, row, value, oldValue) => {
1218
+ const commandManager = command.getCommandManager();
1219
+ const tableEditor = getActiveEditorTable();
1220
+ if (!commandManager) return;
1221
+ if (!tableEditor) return;
1222
+ command.startTransaction((command2) => command2 instanceof EditTableCellDataFunctionalCommand);
1223
+ const run = () => {
1224
+ const previous = tableEditor.getCellOriginValue(col, row);
1225
+ const current = { ...previous, value };
1226
+ tableEditor.updateCellData(col, row, current);
1227
+ const position = tableEditor.getInteractiveCell(col, row);
1228
+ tableEditor.dispatch("cells::update", {
1229
+ editor: tableEditor,
1230
+ data: [
1231
+ {
1232
+ previous,
1233
+ current,
1234
+ ...position
1235
+ }
1236
+ ]
1237
+ });
1238
+ const curData = getSelectEditorData();
1239
+ if (curData && curData.cell.col === col && curData.cell.row === row) {
1240
+ setSelectEditorValue(value);
1241
+ }
1242
+ return {
1243
+ restore: () => {
1244
+ const curData2 = getSelectEditorData();
1245
+ tableEditor.updateCellData(col, row, previous);
1246
+ tableEditor.dispatch("cells::update", {
1247
+ editor: tableEditor,
1248
+ data: [
1249
+ {
1250
+ previous: current,
1251
+ current: previous,
1252
+ ...position
1253
+ }
1254
+ ]
1255
+ });
1256
+ if (!curData2) return;
1257
+ if (curData2.cell.col !== col || curData2.cell.row !== row) return;
1258
+ setSelectEditorValue(oldValue);
1259
+ }
1260
+ };
1261
+ };
1262
+ const command$1 = new EditTableCellDataFunctionalCommand(tableEditor, run);
1263
+ commandManager.execute(command$1);
1264
+ command.stopTransaction();
1265
+ };
1266
+
1267
+ const SelectEditor = ({
1268
+ listHeight = 300,
1269
+ itemHeight = 32,
1270
+ emptyText = "\u6682\u65E0\u6570\u636E",
1271
+ multiple = true
1272
+ }) => {
1273
+ const data = useSelectEditorData();
1274
+ const table = useActiveEditorTable();
1275
+ if (!data) throw new Error("SelectEditorData is null in SelectEditor");
1276
+ if (!table) throw new Error("Table is null in SelectEditor");
1277
+ const editValue = useSelectEditorValue();
1278
+ const updateOption = (option) => {
1279
+ setSelectEditorData((prev) => {
1280
+ if (!prev) {
1281
+ return prev;
1282
+ }
1283
+ const newOptions = prev.options.map((opt) => {
1284
+ if (opt.value === option.value) {
1285
+ return { ...opt, label: option.label, color: option.color || opt.color };
1286
+ }
1287
+ return opt;
1288
+ });
1289
+ const col = data.cell.col;
1290
+ table.updateColumn(col, { options: newOptions });
1291
+ table.dispatch("select::options::update", {
1292
+ editor: table,
1293
+ columnId: String(table.getColumnDefine(data.cell.col)?.field || ""),
1294
+ options: newOptions
1295
+ });
1296
+ return { ...prev, options: newOptions };
1297
+ });
1298
+ setSelectEditorValue((prev) => {
1299
+ if (!prev) {
1300
+ return prev;
1301
+ }
1302
+ return prev.map((item) => item.value === option.value ? option : item);
1303
+ });
1304
+ };
1305
+ const createOption = async (option) => {
1306
+ const column = table.getColumnDefine(data.cell.col);
1307
+ if (!column) throw new Error("SelectEditor createOption column is null");
1308
+ if (column.request) option = await column.request(option).catch(() => option);
1309
+ setSelectEditorData((prev) => {
1310
+ if (!prev) return prev;
1311
+ const col = data.cell.col;
1312
+ table.updateColumn(col, { options: [...prev.options, option] });
1313
+ table.dispatch("select::options::update", {
1314
+ editor: table,
1315
+ columnId: String(table.getColumnDefine(data.cell.col)?.field || ""),
1316
+ options: [...prev.options, option]
1317
+ });
1318
+ return { ...prev, options: [...prev.options, option] };
1319
+ });
1320
+ return option;
1321
+ };
1322
+ const selectOption = (option) => {
1323
+ const newEditValue = editValue || [];
1324
+ if (multiple) {
1325
+ const newSelected = newEditValue.map((item) => item.value).includes(option.value) ? newEditValue : [...newEditValue, option];
1326
+ updateSelectEditorCell(data.cell.col, data.cell.row, newSelected, newEditValue);
1327
+ } else {
1328
+ updateSelectEditorCell(data.cell.col, data.cell.row, [option], newEditValue);
1329
+ }
1330
+ };
1331
+ const deselectOption = (option) => {
1332
+ const newEditValue = editValue || [];
1333
+ const filterValue = newEditValue.filter((item) => item.value !== option.value);
1334
+ updateSelectEditorCell(data.cell.col, data.cell.row, filterValue, newEditValue);
1335
+ };
1336
+ const handleChange = (value) => {
1337
+ setSelectEditorValue(value);
1338
+ };
1339
+ return /* @__PURE__ */ React.createElement(
1340
+ ui.Select,
1341
+ {
1342
+ listHeight,
1343
+ itemHeight,
1344
+ emptyText,
1345
+ multiple,
1346
+ options: data.options,
1347
+ value: editValue || [],
1348
+ onChange: handleChange,
1349
+ onOptionChange: updateOption,
1350
+ onOptionCreate: createOption,
1351
+ onSelect: selectOption,
1352
+ onDeselect: deselectOption,
1353
+ tagAreaStyle: {
1354
+ position: "absolute",
1355
+ left: data.cell.position.x - 2,
1356
+ top: data.cell.position.y - 2,
1357
+ width: data.cell.width + 4,
1358
+ minHeight: data.cell.height + 4,
1359
+ border: `2px solid ${core.COLOR_BORDER_SELECTION}`,
1360
+ backgroundColor: core.COLOR_BG_CELL
1361
+ },
1362
+ width: data.cell.width + 4,
1363
+ tagAreaHeight: data.cell.height,
1364
+ showDownIcon: true
1365
+ }
1366
+ );
1367
+ };
1368
+
1369
+ const TableSelectEditor = () => {
1370
+ const data = useSelectEditorData();
1371
+ if (!data) {
1372
+ return null;
1373
+ }
1374
+ return /* @__PURE__ */ React.createElement(SelectEditor, { multiple: data.isMultiple });
1375
+ };
1376
+
1377
+ const { setTextEditorValue, getTextEditorValue, useTextEditorValue } = store.createAtomStore(
1378
+ "textEditorValue",
1379
+ jotai.atom()
1380
+ );
1381
+ const { setTextEditorData, getTextEditorData, useTextEditorData } = store.createAtomStore(
1382
+ "textEditorData",
1383
+ jotai.atom()
1384
+ );
1385
+ const initTextEditorTool = (data) => {
1386
+ setTextEditorData(data);
1387
+ setTextEditorValue(data.initialValue);
1388
+ };
1389
+ const clearTextEditorTool = () => {
1390
+ setTextEditorData(void 0);
1391
+ setTextEditorValue(void 0);
1392
+ };
1393
+
1394
+ const TextEditor = () => {
1395
+ const textEditorData = useTextEditorData();
1396
+ if (!textEditorData) return null;
1397
+ const { cell, table } = textEditorData;
1398
+ const { position, width, height } = cell;
1399
+ const cellStyle = table._getCellStyle(cell.col, cell.row);
1400
+ const fontSize = getProp("fontSize", cellStyle, cell.col, cell.row, table);
1401
+ const bgColor = getProp("bgColor", cellStyle, cell.col, cell.row, table);
1402
+ return /* @__PURE__ */ React.createElement(
1403
+ antd.Input.TextArea,
1404
+ {
1405
+ defaultValue: textEditorData.initialValue,
1406
+ onChange: (e) => setTextEditorValue(e.target.value),
1407
+ autoSize: { minRows: 1 },
1408
+ style: {
1409
+ position: "absolute",
1410
+ left: position.x - 2,
1411
+ top: position.y - 2,
1412
+ width: width + 4,
1413
+ height: height + 4,
1414
+ padding: 5,
1415
+ background: bgColor,
1416
+ fontSize,
1417
+ border: "2px solid #0404ff",
1418
+ borderRadius: 0,
1419
+ scrollbarWidth: "none"
1420
+ }
1421
+ }
1422
+ );
1423
+ };
1424
+
1425
+ const { setUserShowId, getUserShowId, useUserShowId } = store.createAtomStore("userShowId", jotai.atom(null));
1426
+ const { setUserShowData, getUserShowData, useUserShowData } = store.createAtomStore(
1427
+ "userShowData",
1428
+ jotai.atom(null)
1429
+ );
1430
+ const initUserShowTool = (data) => {
1431
+ setUserShowData(data);
1432
+ setUserShowId(data.id);
1433
+ };
1434
+ const clearUserShowTool = () => {
1435
+ setUserShowData(null);
1436
+ setUserShowId(null);
1437
+ };
1438
+
1439
+ const UserShow = () => {
1440
+ const data = useUserShowData();
1441
+ const valueId = useUserShowId();
1442
+ const col = data?.cell?.col;
1443
+ const row = data?.cell?.row;
1444
+ const table = data?.table;
1445
+ let cellStyle, fontSize;
1446
+ if (table && typeof col === "number" && typeof row === "number") {
1447
+ cellStyle = table._getCellStyle(col, row);
1448
+ fontSize = getProp("fontSize", cellStyle, col, row, table);
1449
+ } else {
1450
+ cellStyle = void 0;
1451
+ fontSize = 14;
1452
+ }
1453
+ const [popoverKey, setPopoverKey] = React.useState(0);
1454
+ const [open, setOpen] = React.useState(false);
1455
+ React.useEffect(() => {
1456
+ if (data) {
1457
+ setPopoverKey((prev) => prev + 1);
1458
+ setOpen(true);
1459
+ }
1460
+ }, [data, valueId, col]);
1461
+ if (!data || valueId === "-2") return null;
1462
+ return /* @__PURE__ */ React.createElement(
1463
+ "div",
1464
+ {
1465
+ style: {
1466
+ position: "absolute",
1467
+ left: data.cell.position.x,
1468
+ top: data.cell.position.y - 8,
1469
+ zIndex: 9999,
1470
+ pointerEvents: "auto",
1471
+ transform: "translateX(-50%) translateY(-100%)"
1472
+ }
1473
+ },
1474
+ /* @__PURE__ */ React.createElement(
1475
+ antd.Popover,
1476
+ {
1477
+ key: popoverKey,
1478
+ content: /* @__PURE__ */ React.createElement(
1479
+ ui.AvatarPopoverContent,
1480
+ {
1481
+ id: valueId,
1482
+ column: getActiveEditorTable()?.getColumnDefine(col),
1483
+ fontSize
1484
+ }
1485
+ ),
1486
+ open,
1487
+ onOpenChange: setOpen,
1488
+ placement: "top",
1489
+ autoAdjustOverflow: false,
1490
+ mouseEnterDelay: 0.3,
1491
+ mouseLeaveDelay: 0.3,
1492
+ arrow: { pointAtCenter: true },
1493
+ getPopupContainer: () => document.body
1494
+ }
1495
+ )
1496
+ );
1497
+ };
1498
+
1499
+ const { setMenu, getMenu, useMenu } = store.createAtomStore("menu", jotai.atom(null));
1500
+
1501
+ const CellContextMenu = ({}) => {
1502
+ const menu = useMenu();
1503
+ const { cellMenus } = useComponentVTable();
1504
+ const tableEditor = useActiveEditorTable();
1505
+ if (!tableEditor) return null;
1506
+ if (!menu || menu.type !== "cell" || !cellMenus?.length) return null;
1507
+ return /* @__PURE__ */ React.createElement(
1508
+ CellContextMenuInner,
1509
+ {
1510
+ menu,
1511
+ cellMenus,
1512
+ tableEditor,
1513
+ offsetParent: tableEditor.container
1514
+ }
1515
+ );
1516
+ };
1517
+ const CellContextMenuInner = ({ menu, cellMenus, tableEditor, offsetParent = null }) => {
1518
+ const menuItems = React.useMemo(() => {
1519
+ if (!menu || menu.type !== "cell") return;
1520
+ return cellMenus?.map((item) => {
1521
+ const { onCellClick, ...rest } = item;
1522
+ return {
1523
+ ...rest,
1524
+ onClick: (info) => {
1525
+ onCellClick?.({
1526
+ menuInfo: info,
1527
+ tableEditor,
1528
+ cell: {
1529
+ col: menu.cell.col,
1530
+ row: menu.cell.row,
1531
+ recordId: menu.cell.recordId,
1532
+ columnId: menu.cell.columnId,
1533
+ rect: menu.cell.rect
1534
+ }
1535
+ });
1536
+ setMenu(null);
1537
+ }
1538
+ };
1539
+ });
1540
+ }, [cellMenus, menu, tableEditor]);
1541
+ return /* @__PURE__ */ React.createElement(
1542
+ gridLayout.TableMenuModal,
1543
+ {
1544
+ isOpen: menu?.open,
1545
+ offsetParent,
1546
+ position: menu.position,
1547
+ menuItems: menuItems ?? [],
1548
+ onPositionChange: (position) => setMenu(
1549
+ (prev) => prev ? { ...prev, position: typeof position === "function" ? position(prev.position) : position } : null
1550
+ )
1551
+ }
1552
+ );
1553
+ };
1554
+
1555
+ const HeaderContextMenu = ({}) => {
1556
+ const { headerMenus } = useComponentVTable();
1557
+ const menu = useMenu();
1558
+ const tableEditor = useActiveEditorTable();
1559
+ if (!tableEditor) return null;
1560
+ if (!menu || menu.type !== "header" || !headerMenus?.length) return null;
1561
+ return /* @__PURE__ */ React.createElement(
1562
+ HeaderContextMenuInner,
1563
+ {
1564
+ menu,
1565
+ headerMenus,
1566
+ tableEditor,
1567
+ offsetParent: tableEditor.container
1568
+ }
1569
+ );
1570
+ };
1571
+ const HeaderContextMenuInner = ({
1572
+ menu,
1573
+ headerMenus,
1574
+ tableEditor,
1575
+ offsetParent = null
1576
+ }) => {
1577
+ const menuItems = React.useMemo(() => {
1578
+ if (!menu || menu.type !== "header") return;
1579
+ return headerMenus?.map((item) => {
1580
+ const { onCellClick, ...rest } = item;
1581
+ return {
1582
+ ...rest,
1583
+ onClick: (info) => {
1584
+ onCellClick?.({
1585
+ menuInfo: info,
1586
+ tableEditor,
1587
+ cell: {
1588
+ col: menu.cell.col,
1589
+ row: menu.cell.row,
1590
+ recordId: menu.cell.recordId,
1591
+ columnId: menu.cell.columnId,
1592
+ rect: menu.cell.rect
1593
+ }
1594
+ });
1595
+ setMenu(null);
1596
+ }
1597
+ };
1598
+ });
1599
+ }, [headerMenus, menu, tableEditor]);
1600
+ return /* @__PURE__ */ React.createElement(
1601
+ gridLayout.TableMenuModal,
1602
+ {
1603
+ isOpen: menu?.open,
1604
+ width: 210,
1605
+ offsetParent,
1606
+ position: menu.position,
1607
+ menuItems: menuItems ?? [],
1608
+ onPositionChange: (position) => setMenu(
1609
+ (prev) => prev ? { ...prev, position: typeof position === "function" ? position(prev.position) : position } : null
1610
+ )
1611
+ }
1612
+ );
1613
+ };
1614
+
1615
+ const MoreContextMenu = () => {
1616
+ const menu = useMenu();
1617
+ const tableEditor = useActiveEditorTable();
1618
+ const { moreMenus } = useComponentVTable();
1619
+ if (!tableEditor) return null;
1620
+ if (!menu || menu.type !== "more") return null;
1621
+ return /* @__PURE__ */ React.createElement(MoreContextMenuInner, { menu, moreMenus, tableEditor });
1622
+ };
1623
+ const MoreContextMenuInner = ({ menu, moreMenus, tableEditor }) => {
1624
+ const menuItems = React.useMemo(() => {
1625
+ if (!menu || menu.type !== "more") return;
1626
+ return moreMenus?.map((item) => {
1627
+ const { onCellClick, ...rest } = item;
1628
+ return {
1629
+ ...rest,
1630
+ onClick: (info) => {
1631
+ onCellClick?.({
1632
+ menuInfo: info,
1633
+ tableEditor,
1634
+ cell: {
1635
+ col: menu.cell.col,
1636
+ row: menu.cell.row,
1637
+ recordId: menu.cell.recordId,
1638
+ columnId: menu.cell.columnId,
1639
+ rect: menu.cell.rect
1640
+ }
1641
+ });
1642
+ }
1643
+ };
1644
+ });
1645
+ }, [moreMenus, menu, tableEditor]);
1646
+ return /* @__PURE__ */ React.createElement(
1647
+ "div",
1648
+ {
1649
+ onMouseMove: () => setMenu({ ...menu }),
1650
+ onMouseLeave: () => setMenu(null),
1651
+ onMouseEnter: () => setMenu({ ...menu })
1652
+ },
1653
+ /* @__PURE__ */ React.createElement(
1654
+ antd.Dropdown,
1655
+ {
1656
+ menu: {
1657
+ items: menuItems ?? []
1658
+ },
1659
+ align: {
1660
+ offset: [0, -4]
1661
+ },
1662
+ placement: "bottom",
1663
+ arrow: false
1664
+ },
1665
+ /* @__PURE__ */ React.createElement(
1666
+ "div",
1667
+ {
1668
+ style: {
1669
+ left: menu.position.x,
1670
+ top: menu.position.y,
1671
+ position: "absolute",
1672
+ width: 16,
1673
+ height: 20,
1674
+ cursor: "pointer"
1675
+ }
1676
+ }
1677
+ )
1678
+ )
1679
+ );
1680
+ };
1681
+
1682
+ const Delete = () => {
1683
+ reactHotkeysHook.useHotkeys(
1684
+ ["backspace", "delete"],
1685
+ () => {
1686
+ const editor = getActiveEditorTable();
1687
+ if (!editor) return;
1688
+ const run = () => {
1689
+ const selectedCellGroup = editor.getSelectedCell() ?? [];
1690
+ const selectedCells = selectedCellGroup.flat().map((item) => ({
1691
+ col: item.col,
1692
+ row: item.row
1693
+ })).filter((item) => item.row !== 0);
1694
+ const payload = selectedCells.map((item) => {
1695
+ return {
1696
+ ...editor.getInteractiveCell(item.col, item.row),
1697
+ previous: editor.getCellOriginValue(item.col, item.row)
1698
+ };
1699
+ });
1700
+ const { recordsForRestore } = editor.removeSelectedCell();
1701
+ const selectedCellNewValues = selectedCells.map((item) => editor.getCellOriginValue(item.col, item.row));
1702
+ const data = payload.map((item, index) => {
1703
+ return {
1704
+ ...item,
1705
+ current: selectedCellNewValues[index]
1706
+ };
1707
+ });
1708
+ editor.dispatch("cells::update", {
1709
+ editor,
1710
+ data
1711
+ });
1712
+ return {
1713
+ restore() {
1714
+ const payload2 = selectedCells.map((item) => {
1715
+ return {
1716
+ ...editor.getInteractiveCell(item.col, item.row),
1717
+ previous: editor.getCellOriginValue(item.col, item.row)
1718
+ };
1719
+ });
1720
+ editor.updateRecordsData(recordsForRestore);
1721
+ const selectedCellNewValues2 = selectedCells.map((item) => editor.getCellOriginValue(item.col, item.row));
1722
+ const data2 = payload2.map((item, index) => {
1723
+ return {
1724
+ ...item,
1725
+ current: selectedCellNewValues2[index]
1726
+ };
1727
+ });
1728
+ editor.dispatch("cells::update", {
1729
+ editor,
1730
+ data: data2
1731
+ });
1732
+ }
1733
+ };
1734
+ };
1735
+ const command = new EditTableCellDataFunctionalCommand(editor, run);
1736
+ editor.commandManager.execute(command);
1737
+ },
1738
+ [],
1739
+ {
1740
+ enabled: true,
1741
+ enableOnContentEditable: false
1742
+ }
1743
+ );
1744
+ return null;
1745
+ };
1746
+
1747
+ const History = () => {
1748
+ const tableEditor = useActiveEditorTable();
1749
+ const commandManager = tableEditor?.commandManager;
1750
+ reactHotkeysHook.useHotkeys(
1751
+ "mod+z",
1752
+ () => {
1753
+ if (!commandManager) return;
1754
+ commandManager.undo();
1755
+ },
1756
+ [commandManager],
1757
+ {
1758
+ enabled: !!commandManager,
1759
+ enableOnContentEditable: false,
1760
+ enableOnFormTags: true
1761
+ }
1762
+ );
1763
+ reactHotkeysHook.useHotkeys(
1764
+ "mod+shift+z",
1765
+ () => {
1766
+ if (!commandManager) return;
1767
+ commandManager.redo();
1768
+ },
1769
+ [commandManager],
1770
+ {
1771
+ enabled: !!commandManager,
1772
+ enableOnContentEditable: false,
1773
+ enableOnFormTags: true
1774
+ }
1775
+ );
1776
+ return null;
1777
+ };
1778
+
1779
+ const Hotkeys = () => {
1780
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Delete, null), /* @__PURE__ */ React.createElement(History, null));
1781
+ };
1782
+
1783
+ class TableEditorEvent extends core$1.DestroyClass {
1784
+ constructor(editor, instance, container) {
1785
+ super();
1786
+ this.editor = editor;
1787
+ this.instance = instance;
1788
+ this.container = container;
1789
+ this.cancels.push(this.initEvent());
1790
+ }
1791
+ initEvent() {
1792
+ const handleContextMenuCell = (e) => {
1793
+ const event = e.event;
1794
+ const { recordId, columnId } = this.editor.getInteractiveCell(e.col, e.row);
1795
+ const columnDefine = this.instance.getBodyColumnDefine(e.col, e.row);
1796
+ if (columnDefine.disableSelect) {
1797
+ if (this.editor.debug) console.info("\u5F53\u524D\u5217\u7981\u7528\u9009\u4E2D\uFF0C\u65E0\u6CD5\u89E6\u53D1\u4E0A\u4E0B\u6587\u83DC\u5355", e, columnDefine);
1798
+ return;
1799
+ }
1800
+ const containerRect = this.instance.getContainer().getBoundingClientRect();
1801
+ const rect = this.instance.getCellRelativeRect(e.col, e.row);
1802
+ rect.left += containerRect.left;
1803
+ rect.top += containerRect.top;
1804
+ rect.right += containerRect.left;
1805
+ rect.bottom += containerRect.top;
1806
+ const isHeader = e.row === 0;
1807
+ const position = !isHeader ? { x: event.clientX, y: event.clientY } : { x: rect.left, y: rect.bottom + 1 };
1808
+ setMenu({
1809
+ open: true,
1810
+ type: isHeader ? "header" : "cell",
1811
+ position,
1812
+ cell: { col: e.col, row: e.row, recordId, columnId, rect }
1813
+ });
1814
+ };
1815
+ const hideMenu = (e) => {
1816
+ if (e.target.closest(".menu-container")) return;
1817
+ else setMenu(null);
1818
+ };
1819
+ const handleContextMenu = (e) => {
1820
+ e.preventDefault();
1821
+ e.stopPropagation();
1822
+ };
1823
+ const dbClickHandler = ({ col, row }) => {
1824
+ const columnDefine = this.instance.getBodyColumnDefine(col, row);
1825
+ const cellValue = this.instance.getCellValue(col, row);
1826
+ if (this.editor.debug) {
1827
+ console.group("\u53CC\u51FB\u5355\u5143\u683C\u4E8B\u4EF6");
1828
+ console.log("\u5F53\u524D\u5355\u5143\u683C\u9501\u5B9A&loading\u72B6\u6001:", {
1829
+ editor: this.editor.lock,
1830
+ column: columnDefine.lock,
1831
+ loading: cellValue?.loading
1832
+ });
1833
+ console.log("\u5F53\u524D\u5355\u5143\u683C\u5DF2\u9501\u5B9A\u6216\u6B63\u5728\u52A0\u8F7D\u4E2D\uFF0C\u65E0\u6CD5\u7F16\u8F91");
1834
+ console.groupEnd();
1835
+ }
1836
+ if (this.editor.lock || columnDefine?.lock || cellValue?.loading) return;
1837
+ this.instance.startEditCell(col, row);
1838
+ };
1839
+ const cellClickHandler = ({ col, row }) => {
1840
+ const columnDefine = this.instance.getBodyColumnDefine(col, row);
1841
+ const record = this.instance.getRecordByCell(col, row);
1842
+ const recordData = record ? revertRecordStructure(record) : void 0;
1843
+ const cellValue = this.instance.getCellValue(col, row);
1844
+ if (this.editor.debug) {
1845
+ console.group("\u5355\u51FB\u5355\u5143\u683C\u4E8B\u4EF6");
1846
+ console.log("\u5F53\u524D\u5217\u914D\u7F6E:", columnDefine);
1847
+ console.log("\u5355\u5143\u683C\u6570\u636E:", cellValue);
1848
+ console.log("\u5F53\u524D\u884C\u6570\u636E:", recordData);
1849
+ console.log("\u5F53\u524D\u5355\u5143\u683C\u9501\u5B9A\u72B6\u6001:", {
1850
+ editor: this.editor.lock,
1851
+ column: columnDefine.lock
1852
+ });
1853
+ console.log("\u5F53\u524D\u8868\u683C\u6570\u636E\u7BA1\u7406\u5668:", this.editor.recordsManager);
1854
+ console.groupEnd();
1855
+ }
1856
+ this.editor.dispatch("cell::click", {
1857
+ editor: this.editor,
1858
+ columnDefine,
1859
+ record,
1860
+ cellValue
1861
+ });
1862
+ };
1863
+ const changeHeaderPositionHandler = () => {
1864
+ this.editor.dispatch("column::drag::move::end", {
1865
+ editor: this.editor,
1866
+ columnIds: this.editor.columnIds.filter((item) => !INNER_TABLE_COLUMN_KEY_LIST.includes(item))
1867
+ });
1868
+ };
1869
+ const resizeColumnEndHandler = ({ col, colWidths }) => {
1870
+ const define = this.editor.getColumnDefine(col);
1871
+ if (INNER_TABLE_COLUMN_KEY_LIST.includes(define.field)) return;
1872
+ this.editor.dispatch("column::width::update", {
1873
+ editor: this.editor,
1874
+ columnId: define.field,
1875
+ width: colWidths[col]
1876
+ });
1877
+ };
1878
+ const checkboxStateChangeHandler = (event) => {
1879
+ const { field } = event;
1880
+ if (field != INNER_TABLE_COLUMN_KEY_CHECKBOX) return;
1881
+ const recordIds = this.editor.interactive.selectedRecords;
1882
+ this.editor.dispatch("record::checkbox::state::change", {
1883
+ editor: this.editor,
1884
+ selectedRecordIds: recordIds
1885
+ });
1886
+ };
1887
+ this.instance.on("contextmenu_cell", handleContextMenuCell);
1888
+ this.instance.on("dblclick_cell", dbClickHandler);
1889
+ this.instance.on("click_cell", cellClickHandler);
1890
+ this.instance.on("change_header_position", changeHeaderPositionHandler);
1891
+ this.instance.on("resize_column_end", resizeColumnEndHandler);
1892
+ this.instance.on("checkbox_state_change", checkboxStateChangeHandler);
1893
+ const parent = this.container.parentElement;
1894
+ parent.addEventListener("contextmenu", handleContextMenu);
1895
+ window.addEventListener("click", hideMenu);
1896
+ return () => {
1897
+ this.instance.off("contextmenu_cell", handleContextMenuCell);
1898
+ this.instance.off("dblclick_cell", dbClickHandler);
1899
+ this.instance.off("click_cell", cellClickHandler);
1900
+ this.instance.off("change_header_position", changeHeaderPositionHandler);
1901
+ this.instance.off("resize_column_end", resizeColumnEndHandler);
1902
+ this.instance.off("checkbox_state_change", checkboxStateChangeHandler);
1903
+ parent.removeEventListener("contextmenu", handleContextMenu);
1904
+ window.removeEventListener("click", hideMenu);
1905
+ this.instance.eventManager.release();
1906
+ };
1907
+ }
1908
+ destroy() {
1909
+ super.destroy();
1910
+ }
1911
+ }
1912
+
1913
+ class BaseTableInteractive {
1914
+ constructor(editor) {
1915
+ this.editor = editor;
1916
+ }
1917
+ get selectedRecords() {
1918
+ const records = this.editor.getSelectedRecord();
1919
+ return records.map((record) => record[INNER_TABLE_RECORD_ID_KEY]);
1920
+ }
1921
+ get selectedCells() {
1922
+ const selectedCells = this.editor.getSelectedCell() ?? [];
1923
+ const cellGroups = selectedCells.filter((group) => group[0].row !== 0);
1924
+ const cells = cellGroups.flat();
1925
+ return cells.map((item) => {
1926
+ const { col, row } = item;
1927
+ const { columnId, recordId } = this.editor.getInteractiveCell(col, row);
1928
+ return {
1929
+ cell: { columnId, recordId },
1930
+ data: item.value
1931
+ };
1932
+ });
1933
+ }
1934
+ getRecordsManagerStore() {
1935
+ return this.editor.recordsManager.store;
1936
+ }
1937
+ filters(recordIds) {
1938
+ this.editor.recordsManager.filters = recordIds;
1939
+ }
1940
+ selectCell(cell) {
1941
+ const { col, row } = this.editor.getInteractiveCellPosition(cell);
1942
+ this.editor.selectCell(col, row);
1943
+ }
1944
+ selectColumnByIndex(columnIndex) {
1945
+ const col = getColFromColIndex(columnIndex, this.editor.innerColumnControl);
1946
+ this.editor.instance.selectCol(col);
1947
+ }
1948
+ selectRowByIndex(recordIndex) {
1949
+ const row = getRowFromRowIndex(recordIndex);
1950
+ this.editor.instance.selectRow(row);
1951
+ }
1952
+ selectCellByIndex(cell) {
1953
+ const [recordIndex, colIndex] = cell;
1954
+ const col = getColFromColIndex(colIndex, this.editor.innerColumnControl);
1955
+ const row = getRowFromRowIndex(recordIndex);
1956
+ this.editor.selectCell(col, row);
1957
+ }
1958
+ clearSelect() {
1959
+ this.editor.instance.clearSelected();
1960
+ }
1961
+ setRecordsSelectState(records, state = true) {
1962
+ const columnIndex = 0;
1963
+ const columnDefine = this.editor.getColumnDefine(0);
1964
+ if (columnDefine.field !== INNER_TABLE_COLUMN_KEY_CHECKBOX) throw new Error("\u5F53\u524D\u8868\u683C\u7B2C\u4E00\u5217\u4E0D\u662F\u590D\u9009\u6846\u5217");
1965
+ if (records === "all") {
1966
+ const rowCount = this.editor.rowCount;
1967
+ for (let row = 0; row < rowCount; row++) {
1968
+ this.editor.setCheckboxState(columnIndex, row, state);
1969
+ }
1970
+ } else {
1971
+ const cellPositions = records.map(
1972
+ (item) => this.editor.getInteractiveCellPosition({ recordId: item, columnId: INNER_TABLE_COLUMN_KEY_CHECKBOX })
1973
+ );
1974
+ cellPositions.forEach((item) => this.editor.setCheckboxState(columnIndex, item.row, state));
1975
+ }
1976
+ }
1977
+ getRecord(recordId) {
1978
+ const { row } = this.editor.getInteractiveCellPosition({ recordId, columnId: INNER_TABLE_COLUMN_KEY_CHECKBOX });
1979
+ const data = this.editor.getRecordByCell(0, row);
1980
+ const record = data ? revertRecordStructure(data) : void 0;
1981
+ return record;
1982
+ }
1983
+ getRecords(recordIds) {
1984
+ const records = recordIds.map((item) => this.getRecord(item));
1985
+ return records;
1986
+ }
1987
+ updateRecords(records) {
1988
+ this.editor.recordsManager.updateRecords(records);
1989
+ }
1990
+ addRecords(_records) {
1991
+ this.editor.recordsManager.addRecords(_records);
1992
+ }
1993
+ removeRecords(_recordIds) {
1994
+ this.editor.recordsManager.removeRecords(_recordIds);
1995
+ }
1996
+ focus(cell) {
1997
+ const { col, row } = this.editor.getInteractiveCellPosition(cell);
1998
+ this.editor.focusCell(col, row);
1999
+ }
2000
+ focusByIndex(cell) {
2001
+ const [recordIndex, colIndex] = cell;
2002
+ const col = getColFromColIndex(colIndex, this.editor.innerColumnControl);
2003
+ const row = getRowFromRowIndex(recordIndex);
2004
+ this.editor.focusCell(col, row);
2005
+ }
2006
+ highlight(cells, _key = core.CUSTOM_CELL_STYLE_HIGHLIGHT_FOCUS) {
2007
+ const positions = cells.map((cell) => this.editor.getInteractiveCellPosition(cell));
2008
+ this.editor.highlightCells(_key, positions);
2009
+ }
2010
+ highlightByIndex(cells, _key = core.CUSTOM_CELL_STYLE_HIGHLIGHT_FOCUS) {
2011
+ const positions = cells.map(([recordIndex, colIndex]) => ({
2012
+ row: getRowFromRowIndex(recordIndex),
2013
+ col: getColFromColIndex(colIndex, this.editor.innerColumnControl)
2014
+ }));
2015
+ this.editor.highlightCells(_key, positions);
2016
+ }
2017
+ clearHighlight(key = core.CUSTOM_CELL_STYLE_HIGHLIGHT_FOCUS) {
2018
+ this.editor.clearHighlight(key);
2019
+ }
2020
+ // 冻结列的数量,此处count是用户可感知列的数量
2021
+ setFreezeCount(count) {
2022
+ const { checkbox } = this.editor.innerColumnControl;
2023
+ const realCount = count + (checkbox ? 1 : 0);
2024
+ this.editor.setFreezeCount(realCount);
2025
+ }
2026
+ }
2027
+
2028
+ class RecordsManager extends core$1.DestroyClass {
2029
+ constructor(editor) {
2030
+ super();
2031
+ this.editor = editor;
2032
+ this.recordsMap = jotai.atom(/* @__PURE__ */ new Map());
2033
+ this._filters = jotai.atom(void 0);
2034
+ /**
2035
+ * 当前表格records数量
2036
+ *
2037
+ * 如果filters不存在,直接返回 recordsMap 数量,
2038
+ *
2039
+ * 如果filters存在,则返回 filters 中存在的 records 数量
2040
+ */
2041
+ this.size = jotai.atom((get) => {
2042
+ const records = get(this.recordsMap);
2043
+ const filters = get(this._filters);
2044
+ let count = 0;
2045
+ if (lodash.isNil(filters)) count = records.size;
2046
+ else {
2047
+ count = filters.map((recordId) => records.get(recordId)).filter(Boolean).length;
2048
+ }
2049
+ return count;
2050
+ });
2051
+ }
2052
+ get filters() {
2053
+ return window.store.get(this._filters);
2054
+ }
2055
+ set filters(value) {
2056
+ window.store.set(this._filters, value);
2057
+ this.renderRecords();
2058
+ }
2059
+ initRecords(records) {
2060
+ const recordsMap = window.store.get(this.recordsMap);
2061
+ records.forEach((item) => recordsMap.set(item.INNER_PRESET_RECORD_ID, item));
2062
+ window.store.set(this.recordsMap, new Map(recordsMap));
2063
+ }
2064
+ renderRecords() {
2065
+ const recordsMap = window.store.get(this.recordsMap);
2066
+ const records = this.filters ? this.filters.map((filter) => recordsMap.get(filter)) : [...recordsMap.values()];
2067
+ const data = records.filter(Boolean);
2068
+ this.editor.setRecords(data);
2069
+ }
2070
+ updateRecords(records) {
2071
+ const recordsMap = window.store.get(this.recordsMap);
2072
+ records.forEach((item) => {
2073
+ const adaptedRecord = adaptRecordStructure(item);
2074
+ recordsMap.set(adaptedRecord[INNER_TABLE_RECORD_ID_KEY], adaptedRecord);
2075
+ });
2076
+ const ids = records.map((item) => item.id);
2077
+ const values = [...recordsMap.values()];
2078
+ const data = values.map((item, index) => {
2079
+ return ids.includes(item.INNER_PRESET_RECORD_ID) ? [item, index] : void 0;
2080
+ }).filter(Boolean);
2081
+ this.editor.instance.updateRecords(
2082
+ data.map(([record]) => record),
2083
+ data.map(([, rowIndex]) => rowIndex)
2084
+ );
2085
+ window.store.set(this.recordsMap, new Map(recordsMap));
2086
+ }
2087
+ addRecords(records) {
2088
+ const recordsMap = window.store.get(this.recordsMap);
2089
+ records.forEach((item) => {
2090
+ const adaptedRecord = adaptRecordStructure(item);
2091
+ if (recordsMap.has(adaptedRecord[INNER_TABLE_RECORD_ID_KEY])) {
2092
+ throw new Error("record id already exists " + adaptedRecord[INNER_TABLE_RECORD_ID_KEY]);
2093
+ }
2094
+ recordsMap.set(adaptedRecord[INNER_TABLE_RECORD_ID_KEY], adaptedRecord);
2095
+ });
2096
+ const recordsAdapted = records.map((item) => recordsMap.get(item.id)).filter(Boolean);
2097
+ this.editor.addRecords(recordsAdapted);
2098
+ window.store.set(this.recordsMap, new Map(recordsMap));
2099
+ }
2100
+ removeRecords(recordIds) {
2101
+ const recordsMap = window.store.get(this.recordsMap);
2102
+ recordIds.forEach((id) => recordsMap.delete(id));
2103
+ const indexes = recordIds.map((id) => this.editor.getInteractiveRecordIndex(id)).filter((i) => i !== -1);
2104
+ this.editor.deleteRecords(indexes);
2105
+ window.store.set(this.recordsMap, new Map(recordsMap));
2106
+ }
2107
+ get store() {
2108
+ return window.store.get(this.recordsMap);
2109
+ }
2110
+ get(recordId) {
2111
+ const recordsMap = window.store.get(this.recordsMap);
2112
+ return recordsMap.get(recordId);
2113
+ }
2114
+ set(recordId, record) {
2115
+ const recordsMap = window.store.get(this.recordsMap);
2116
+ recordsMap.set(recordId, record);
2117
+ window.store.set(this.recordsMap, new Map(recordsMap));
2118
+ }
2119
+ }
2120
+
2121
+ const createHeaderGraphics = (type, props) => {
2122
+ const { table, row, col, rect, value } = props;
2123
+ const headerStyle = table._getCellStyle(col, row);
2124
+ const columnDefine = table.getBodyColumnDefine(col, row);
2125
+ const lock = !!columnDefine.lock;
2126
+ const functionalFontSize = getProp("fontSize", headerStyle, col, row, table);
2127
+ const functionalColor = getProp("color", headerStyle, col, row, table);
2128
+ const { height, width } = rect ?? table.getCellRect(col, row);
2129
+ const headerIconSize = getIconSizeFromFont(functionalFontSize);
2130
+ const g = vrender.createGroup({
2131
+ width,
2132
+ height,
2133
+ display: "flex",
2134
+ flexWrap: "nowrap",
2135
+ justifyContent: "space-between",
2136
+ alignContent: "center",
2137
+ alignItems: "center"
2138
+ // 垂直居中
2139
+ });
2140
+ const lg = vrender.createGroup({
2141
+ width: width - 30,
2142
+ height,
2143
+ display: "flex",
2144
+ flexWrap: "nowrap",
2145
+ justifyContent: "flex-start",
2146
+ alignContent: "center",
2147
+ alignItems: "center"
2148
+ });
2149
+ const rg = vrender.createGroup({
2150
+ display: "flex",
2151
+ width: 30,
2152
+ height,
2153
+ alignContent: "center",
2154
+ alignItems: "center"
2155
+ });
2156
+ const arrowIcon = createIconGraphics("arrow_down", {
2157
+ size: headerIconSize,
2158
+ color: functionalColor,
2159
+ cursor: "pointer",
2160
+ hoverBg: true
2161
+ });
2162
+ rg.add(arrowIcon);
2163
+ const toolContainer = vrender.createGroup({
2164
+ display: "flex",
2165
+ width: 30,
2166
+ height,
2167
+ alignContent: "center",
2168
+ alignItems: "center"
2169
+ });
2170
+ const toolIcon = createIconGraphics(lock ? "lock" : core.TOOL_ICON[type], {
2171
+ size: headerIconSize,
2172
+ color: functionalColor
2173
+ });
2174
+ toolContainer.add(toolIcon);
2175
+ const titleContainer = vrender.createGroup({
2176
+ display: "flex",
2177
+ width: width - 60,
2178
+ height,
2179
+ alignContent: "center",
2180
+ alignItems: "center"
2181
+ });
2182
+ const title = vrender.createText({
2183
+ text: value,
2184
+ dy: -functionalFontSize / 2,
2185
+ fontSize: functionalFontSize,
2186
+ fill: functionalColor,
2187
+ lineHeight: height,
2188
+ maxLineWidth: width - 30,
2189
+ textAlign: "left",
2190
+ textBaseline: "middle"
2191
+ });
2192
+ titleContainer.add(title);
2193
+ lg.add(toolContainer);
2194
+ lg.add(titleContainer);
2195
+ g.add(lg);
2196
+ g.add(rg);
2197
+ arrowIcon.addEventListener("click", () => {
2198
+ });
2199
+ return g;
2200
+ };
2201
+
2202
+ const isColumnEditable = (table, col) => {
2203
+ const column = table.getBodyColumnDefine(col, 0);
2204
+ const lock = column.lock;
2205
+ return !lock;
2206
+ };
2207
+ const createDefaultColumnConfig = () => {
2208
+ return {
2209
+ field: id.getUUID(),
2210
+ title: "\u6587\u672C",
2211
+ tool: 28,
2212
+ // TODO: 改成自定义的文本输入组件
2213
+ editor: "textEditor",
2214
+ headerCustomLayout: (args) => {
2215
+ return {
2216
+ rootContainer: createHeaderGraphics(28, args),
2217
+ renderDefault: false
2218
+ };
2219
+ }
2220
+ };
2221
+ };
2222
+
2223
+ class TableEditor extends core$1.DestroyClass {
2224
+ constructor(id, container, onChange, config, commandManager, uploadFile, innerColumnControl) {
2225
+ super();
2226
+ this.id = id;
2227
+ this.container = container;
2228
+ this.commandManager = commandManager;
2229
+ this.uploadFile = uploadFile;
2230
+ this.innerColumnControl = innerColumnControl;
2231
+ this._lock = jotai.atom(false);
2232
+ this.customCellStyleArrangement = /* @__PURE__ */ new Map();
2233
+ this.recordsManager = new RecordsManager(this);
2234
+ /**
2235
+ * 当前是否处于debug状态,一般开发的时候为true,会打印一些需要调试的日志
2236
+ */
2237
+ this.debug = false;
2238
+ /**
2239
+ * 供外部调用的接口
2240
+ */
2241
+ this.interactive = new BaseTableInteractive(this);
2242
+ this.dispatch = onChange;
2243
+ const editorMap = getEditorTableStore();
2244
+ const editor = editorMap.get(this.id);
2245
+ if (editor) throw new Error("TableEditor \u5DF2\u5B58\u5728");
2246
+ this.instance = new VTable.ListTable(container, config);
2247
+ editorMap.set(id, this);
2248
+ setEditorTableStore(new Map([...editorMap]));
2249
+ this.event = new TableEditorEvent(this, this.instance, this.container);
2250
+ this.recordsManager.initRecords(this.instance.records);
2251
+ this.load();
2252
+ }
2253
+ get lock() {
2254
+ return window.store.get(this._lock);
2255
+ }
2256
+ set lock(value) {
2257
+ window.store.set(this._lock, value);
2258
+ }
2259
+ get colCount() {
2260
+ return this.instance.colCount;
2261
+ }
2262
+ get rowCount() {
2263
+ return this.instance.rowCount;
2264
+ }
2265
+ /**
2266
+ * 用于限定列的操作范围
2267
+ * 前两列 0 1 是关键主列,不进行任何操作,并且顺序永远在最前面
2268
+ * 最后两列 colCount - 1:Plus列, colCount - 2:more列 同样是固定列
2269
+ */
2270
+ get colActionLimit() {
2271
+ return {
2272
+ min: 2,
2273
+ max: this.instance.colCount - 2
2274
+ };
2275
+ }
2276
+ get columnIds() {
2277
+ return this.columns.map((item) => item.field);
2278
+ }
2279
+ get columns() {
2280
+ return this.instance.columns;
2281
+ }
2282
+ updateCellData(col, row, value) {
2283
+ const { field } = this.getColumnDefine(col);
2284
+ const record = this.instance.getRecordByCell(col, row);
2285
+ const recordId = record[INNER_TABLE_RECORD_ID_KEY];
2286
+ const recordData = this.recordsManager.get(recordId);
2287
+ if (!recordData) throw new Error(`[updateCellData] recordId ${recordId} \u4E0D\u5B58\u5728`);
2288
+ recordData[field] = value;
2289
+ this.updateCell(col, row, value);
2290
+ }
2291
+ getRecordByCell(col, row) {
2292
+ return this.instance.getRecordByCell(col, row);
2293
+ }
2294
+ getInteractiveCell(col, row) {
2295
+ const record = this.instance.getRecordByCell(col, row) ?? {};
2296
+ const columnDefine = this.instance.getBodyColumnDefine(col, row);
2297
+ const recordId = record[INNER_TABLE_RECORD_ID_KEY];
2298
+ const columnId = columnDefine.field;
2299
+ return { columnId, recordId };
2300
+ }
2301
+ getInteractiveRecordIndex(recordId) {
2302
+ return this.instance.records.findIndex((record) => record[INNER_TABLE_RECORD_ID_KEY] === recordId);
2303
+ }
2304
+ getInteractiveCellPosition(cell) {
2305
+ const { recordId, columnId } = cell;
2306
+ const fields = this.instance.columns.map((item) => item.field);
2307
+ const rowIndex = this.instance.records.findIndex((record) => record[INNER_TABLE_RECORD_ID_KEY] === recordId);
2308
+ const col = fields.findIndex((field) => field === columnId);
2309
+ return { col, row: getRowFromRowIndex(rowIndex) };
2310
+ }
2311
+ updateColumns(columns) {
2312
+ this.instance.updateColumns(columns);
2313
+ }
2314
+ getSelectedRecord() {
2315
+ const selected = this.instance.getCheckboxState(INNER_TABLE_COLUMN_KEY_CHECKBOX);
2316
+ return this.instance.records.filter((_, index) => selected[index]);
2317
+ }
2318
+ setCheckboxState(col, row, state) {
2319
+ this.instance.setCellCheckboxState(col, row, state);
2320
+ }
2321
+ getColumnDefine(col) {
2322
+ return this.instance.getBodyColumnDefine(col, 0);
2323
+ }
2324
+ getSelectedCell() {
2325
+ return this.instance.getSelectedCellInfos();
2326
+ }
2327
+ focusCell(col, row) {
2328
+ this.instance.scrollToCell({ col, row });
2329
+ }
2330
+ highlightCells(customCellStyleKey, cells) {
2331
+ this.clearHighlight(customCellStyleKey);
2332
+ cells.forEach((cell) => this.instance.arrangeCustomCellStyle(cell, customCellStyleKey));
2333
+ this.customCellStyleArrangement.set(customCellStyleKey, cells);
2334
+ }
2335
+ clearHighlight(customCellStyleKey) {
2336
+ if (!customCellStyleKey) {
2337
+ this.instance.arrangeCustomCellStyle(
2338
+ {
2339
+ range: {
2340
+ start: { col: 0, row: 0 },
2341
+ end: { col: this.instance.colCount - 1, row: this.instance.rowCount - 1 }
2342
+ }
2343
+ },
2344
+ "",
2345
+ true
2346
+ );
2347
+ this.customCellStyleArrangement.clear();
2348
+ } else {
2349
+ const cells = this.customCellStyleArrangement.get(customCellStyleKey) || [];
2350
+ cells.forEach((cell) => this.instance.arrangeCustomCellStyle(cell, ""));
2351
+ this.customCellStyleArrangement.delete(customCellStyleKey);
2352
+ }
2353
+ }
2354
+ updateColumn(col, options) {
2355
+ const newColumns = [...this.instance.columns];
2356
+ newColumns[col] = {
2357
+ ...newColumns[col],
2358
+ ...options
2359
+ };
2360
+ this.instance.updateColumns(newColumns);
2361
+ }
2362
+ setRecords(_records) {
2363
+ this.instance.setRecords(_records, { sortState: null });
2364
+ }
2365
+ addRecords(_records) {
2366
+ this.instance.addRecords(_records);
2367
+ }
2368
+ selectCell(col, row) {
2369
+ this.instance.selectCell(col, row);
2370
+ }
2371
+ /**
2372
+ * 删除选中单元格
2373
+ * 1. 过滤表头行
2374
+ * 2. 只修改没有被锁定的列内容
2375
+ */
2376
+ removeSelectedCell() {
2377
+ const selectedCells = this.getSelectedCell() ?? [];
2378
+ const cellGroups = selectedCells.filter((group) => group[0].row !== 0);
2379
+ const rows = cellGroups.map((cells) => this.instance.getRecordShowIndexByCell(cells[0].col, cells[0].row));
2380
+ const row1 = cellGroups[0];
2381
+ const cols = row1.map((cell) => cell.col).filter((col) => isColumnEditable(this.instance, col));
2382
+ const fields = cols.map((col) => this.instance.columns[col].field).filter(Boolean);
2383
+ const recordsForRestore = rows.map((row) => [
2384
+ structuredClone(this.instance.records[row]),
2385
+ row
2386
+ ]);
2387
+ const records = rows.map((row) => {
2388
+ const record = structuredClone(this.instance.records[row]);
2389
+ fields.forEach((field) => record[field].value = void 0);
2390
+ return [record, row];
2391
+ });
2392
+ this.instance.updateRecords(
2393
+ records.map(([record]) => record),
2394
+ records.map(([, row]) => row)
2395
+ );
2396
+ return {
2397
+ records,
2398
+ recordsForRestore
2399
+ };
2400
+ }
2401
+ /**
2402
+ * 添加数据 支持多条数据
2403
+ * @param records 多条数据
2404
+ * @param recordIndex 向数据源中要插入的位置,从0开始。不设置recordIndex的话 默认追加到最后。
2405
+ * 如果设置了排序规则recordIndex无效,会自动适应排序逻辑确定插入顺序。
2406
+ * recordIndex 可以通过接口getRecordShowIndexByCell获取
2407
+ */
2408
+ createRows(count, recordBodyIndex) {
2409
+ const index = recordBodyIndex ?? this.instance.recordsCount;
2410
+ const columns = this.instance.columns.map((item) => [item.field, item.defaultValue ?? void 0]);
2411
+ const defaultRecord = Object.fromEntries(columns);
2412
+ const newRecords = Array.from({ length: count }).map(() => lodash.clone(defaultRecord));
2413
+ this.instance.addRecords([...newRecords], index);
2414
+ const indexes = [];
2415
+ for (let i = 0; i < count; i++) {
2416
+ indexes.push(index + i);
2417
+ }
2418
+ return {
2419
+ newRecords,
2420
+ newRecordIndexes: indexes
2421
+ };
2422
+ }
2423
+ deleteRecords(recordIndexes) {
2424
+ this.instance.deleteRecords(recordIndexes);
2425
+ }
2426
+ /**
2427
+ * 删除行
2428
+ */
2429
+ removeRow(count, recordBodyIndex) {
2430
+ if (this.lock) throw new Error("\u9501\u5B9A\u8868\u683C\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664\u884C");
2431
+ const index = recordBodyIndex;
2432
+ const indexes = [];
2433
+ for (let i = 0; i < count; i++) {
2434
+ indexes.push(index + i);
2435
+ }
2436
+ const records = structuredClone(indexes.map((index2) => this.instance.records[index2]));
2437
+ this.instance.deleteRecords(lodash.clone(indexes));
2438
+ return {
2439
+ oldRecords: records,
2440
+ oldRecordIndexes: indexes
2441
+ };
2442
+ }
2443
+ /**
2444
+ * 新增默认列
2445
+ * @param count 新增列数
2446
+ * @param insertIndex 新增列索引,默认在最后一列前新增
2447
+ */
2448
+ createColumn(count, insertIndex) {
2449
+ if (this.lock) throw new Error("\u9501\u5B9A\u8868\u683C\uFF0C\u4E0D\u5141\u8BB8\u65B0\u589E\u5217");
2450
+ const columns = [...this.instance.columns];
2451
+ const newColumns = [...this.instance.columns];
2452
+ const index = lodash.clamp(insertIndex, this.colActionLimit.min, this.colActionLimit.max);
2453
+ const createdColumns = Array.from({ length: count }).map(() => createDefaultColumnConfig());
2454
+ newColumns.splice(index, 0, ...createdColumns);
2455
+ this.instance.updateColumns(newColumns);
2456
+ return {
2457
+ oldColumns: columns,
2458
+ newColumns
2459
+ };
2460
+ }
2461
+ /**
2462
+ * 删除列
2463
+ */
2464
+ removeColumn(count, startIndex) {
2465
+ if (this.lock) throw new Error("\u9501\u5B9A\u8868\u683C\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664\u5217");
2466
+ const oldColumns = [...this.instance.columns];
2467
+ const newColumns = [...this.instance.columns];
2468
+ const min = this.colActionLimit.min;
2469
+ const max = this.colActionLimit.max;
2470
+ const plannedIndexes = Array.from({ length: count }, (_, i) => startIndex + i);
2471
+ const inRangeIndexes = plannedIndexes.filter((i) => i >= min && i <= max);
2472
+ if (inRangeIndexes.length === 0) {
2473
+ console.warn(
2474
+ `[removeColumn] \u6CA1\u6709\u4EFB\u4F55\u5217\u843D\u5728\u53EF\u64CD\u4F5C\u8303\u56F4\u5185\u3002startIndex=${startIndex}, count=${count}, \u8303\u56F4=[${min}, ${max}]`
2475
+ );
2476
+ return;
2477
+ }
2478
+ const removableIndexes = inRangeIndexes.filter((i) => isColumnEditable(this.instance, i));
2479
+ const notEditableIndexes = inRangeIndexes.filter((i) => !isColumnEditable(this.instance, i));
2480
+ if (notEditableIndexes.length > 0) {
2481
+ console.warn(`[removeColumn] \u4EE5\u4E0B\u5217\u88AB\u9501\u5B9A\uFF0C\u4E0D\u53C2\u4E0E\u5220\u9664: ${notEditableIndexes.join(", ")}`);
2482
+ }
2483
+ if (removableIndexes.length === 0) {
2484
+ console.warn(`[removeColumn] \u53EF\u64CD\u4F5C\u8303\u56F4\u5185\u7684\u5217\u5747\u4E0D\u53EF\u5220\u9664\u3002startIndex=${startIndex}, count=${count}`);
2485
+ return;
2486
+ }
2487
+ removableIndexes.sort((a, b) => b - a);
2488
+ removableIndexes.forEach((index) => {
2489
+ newColumns.splice(index, 1);
2490
+ });
2491
+ this.instance.updateColumns(newColumns);
2492
+ return {
2493
+ oldColumns,
2494
+ newColumns
2495
+ };
2496
+ }
2497
+ /**
2498
+ * 复制列
2499
+ * @param sourceIndex 要复制的列索引
2500
+ * @param insertIndex 插入位置,默认在源列之后
2501
+ */
2502
+ copyColumn(sourceIndex, insertIndex = sourceIndex + 1) {
2503
+ if (this.lock) throw new Error("\u9501\u5B9A\u8868\u683C\uFF0C\u4E0D\u5141\u8BB8\u590D\u5236\u5217");
2504
+ const oldColumns = [...this.instance.columns];
2505
+ const newColumns = [...this.instance.columns];
2506
+ const sourceColumn = oldColumns[sourceIndex];
2507
+ const newColumn = lodash.clone(sourceColumn);
2508
+ newColumn.field = id.getUUID();
2509
+ newColumn.title = `${newColumn.title} \u590D\u5236`;
2510
+ newColumns.splice(insertIndex, 0, newColumn);
2511
+ this.instance.updateColumns(newColumns);
2512
+ return {
2513
+ oldColumns,
2514
+ newColumns
2515
+ };
2516
+ }
2517
+ /**
2518
+ * 冻结列
2519
+ * @param count 要冻结的列数
2520
+ * 注意:count >= 2,否则会将关键主列于checkbox拆分
2521
+ */
2522
+ setFreezeCount(count) {
2523
+ if (this.lock) throw new Error("\u9501\u5B9A\u8868\u683C\uFF0C\u4E0D\u5141\u8BB8\u51BB\u7ED3\u5217");
2524
+ const oldFrozenColCount = this.instance.frozenColCount;
2525
+ const newFrozenColCount = count;
2526
+ this.instance.setFrozenColCount(count);
2527
+ return {
2528
+ oldValue: oldFrozenColCount,
2529
+ newValue: newFrozenColCount
2530
+ };
2531
+ }
2532
+ getCellOriginValue(col, row) {
2533
+ return this.instance.getCellOriginValue(col, row);
2534
+ }
2535
+ updateCell(col, row, value) {
2536
+ if (this.lock) throw new Error("\u9501\u5B9A\u8868\u683C\uFF0C\u4E0D\u5141\u8BB8\u4FEE\u6539\u5355\u5143\u683C\u6570\u636E");
2537
+ if (!isColumnEditable(this.instance, col)) throw new Error(`\u9501\u5B9A\u5217\uFF0C\u4E0D\u5141\u8BB8\u4FEE\u6539 column: ${col}`);
2538
+ const rowIndex = this.instance.getRecordShowIndexByCell(col, row);
2539
+ const oldValue = this.instance.getCellValue(col, row);
2540
+ const field = this.instance.columns[col].field;
2541
+ const record = this.instance.records[rowIndex];
2542
+ this.instance.updateRecords([{ ...record, [field]: value }], [rowIndex]);
2543
+ return {
2544
+ record,
2545
+ rowIndex,
2546
+ oldValue,
2547
+ newValue: value
2548
+ };
2549
+ }
2550
+ updateRecordsData(records) {
2551
+ records.forEach(([item]) => {
2552
+ const recordId = item[INNER_TABLE_RECORD_ID_KEY];
2553
+ this.recordsManager.set(recordId, item);
2554
+ });
2555
+ this.instance.updateRecords(
2556
+ records.map(([record]) => record),
2557
+ records.map(([, rowIndex]) => rowIndex)
2558
+ );
2559
+ }
2560
+ getCellStyle(col, row) {
2561
+ return this.instance.getCellStyle(col, row);
2562
+ }
2563
+ load() {
2564
+ this.cancels.push(
2565
+ ...[
2566
+ () => this.event.destroy(),
2567
+ () => this.instance.release(),
2568
+ () => {
2569
+ const editorMap = getEditorTableStore();
2570
+ editorMap.delete(this.id);
2571
+ setEditorTableStore(new Map([...editorMap]));
2572
+ }
2573
+ ]
2574
+ );
2575
+ }
2576
+ unload() {
2577
+ this.cancels.forEach((cancel) => cancel());
2578
+ }
2579
+ destroy() {
2580
+ super.destroy();
2581
+ this.unload();
2582
+ }
2583
+ }
2584
+ const createBaseTableEditor = (config) => {
2585
+ const {
2586
+ id,
2587
+ onChange,
2588
+ columns,
2589
+ records,
2590
+ theme,
2591
+ commandManager,
2592
+ container,
2593
+ uploadFileFn,
2594
+ innerColumnControl,
2595
+ ...rest
2596
+ } = config;
2597
+ const defaultChangeHandler = (e, payload) => {
2598
+ console.info("\u9ED8\u8BA4\u53D8\u66F4\u5904\u7406\u51FD\u6570", e, payload);
2599
+ };
2600
+ const dispatch = onChange ?? defaultChangeHandler;
2601
+ const frozenColCount = [innerColumnControl.checkbox, innerColumnControl.main].filter(Boolean).length;
2602
+ const options = {
2603
+ columns,
2604
+ records,
2605
+ theme,
2606
+ hover: {
2607
+ highlightMode: "cross"
2608
+ },
2609
+ customCellStyle: [core.CUSTOM_CELL_STYLE, core.CUSTOM_CELL_FOCUS_STYLE, core.CUSTOM_CELL_FEEDBACK_ERROR_STYLE],
2610
+ dragOrder: {
2611
+ dragHeaderMode: "column",
2612
+ // 仅启用列表头拖拽换位
2613
+ validateDragOrderOnEnd: (source, target) => {
2614
+ const tableEditor = getActiveEditorTable();
2615
+ if (!tableEditor) throw new Error("\u672A\u6FC0\u6D3B\u7684\u8868\u683C\u7F16\u8F91\u5668");
2616
+ if (source.col <= 1) return false;
2617
+ if (target.col <= 1) return false;
2618
+ if (target.col >= tableEditor.colCount - 2) return false;
2619
+ return true;
2620
+ }
2621
+ },
2622
+ // 如果有checkbox,前两列默认固定 一列checkbox 一列题目名称
2623
+ // 如果没有checkbox,第一列默认固定
2624
+ frozenColCount,
2625
+ defaultColWidth: 150,
2626
+ defaultRowHeight: core.TABLE_DEFAULT_ROW_HEIGHT,
2627
+ enableLineBreak: true,
2628
+ heightMode: "standard",
2629
+ editCellTrigger: "api",
2630
+ showHeader: true,
2631
+ ...rest
2632
+ };
2633
+ const editor = new TableEditor(id, container, dispatch, options, commandManager, uploadFileFn, innerColumnControl);
2634
+ return editor;
2635
+ };
2636
+
2637
+ const TableView = ({}) => {
2638
+ const {
2639
+ id,
2640
+ editorRef,
2641
+ containerRef,
2642
+ records,
2643
+ columns,
2644
+ theme,
2645
+ commandManager,
2646
+ onChange,
2647
+ uploadFileFn,
2648
+ innerColumnControl,
2649
+ disabled,
2650
+ maxHeight,
2651
+ debug,
2652
+ ...rest
2653
+ } = useComponentVTable();
2654
+ const [recordsState] = React.useState(records);
2655
+ const innerColumnControlState = React.useMemo(() => {
2656
+ return {
2657
+ main: innerColumnControl.main,
2658
+ plus: innerColumnControl.plus,
2659
+ checkbox: innerColumnControl.checkbox
2660
+ };
2661
+ }, [innerColumnControl.checkbox, innerColumnControl.main, innerColumnControl.plus]);
2662
+ React.useEffect(() => {
2663
+ if (!editorRef.current) return;
2664
+ editorRef.current.lock = disabled;
2665
+ editorRef.current.debug = debug;
2666
+ }, [disabled, editorRef, debug]);
2667
+ const adaptedData = React.useMemo(() => {
2668
+ const adaptedColumns = adaptColumnStructure(columns, innerColumnControlState);
2669
+ const adaptedRecords = adaptRecordsStructure(recordsState, adaptedColumns.columns, innerColumnControlState);
2670
+ return {
2671
+ columns: adaptedColumns.columns,
2672
+ records: adaptedRecords.records,
2673
+ highlight: highlightMerge(adaptedRecords.feedbacksHighlight, adaptedColumns.feedbacksHighlight)
2674
+ };
2675
+ }, [columns, innerColumnControlState, recordsState]);
2676
+ React.useEffect(() => {
2677
+ if (!containerRef.current) return;
2678
+ if (editorRef.current) {
2679
+ editorRef.current.updateColumns(adaptedData.columns);
2680
+ editorRef.current.innerColumnControl = innerColumnControl;
2681
+ return;
2682
+ }
2683
+ editorRef.current = createBaseTableEditor({
2684
+ id,
2685
+ onChange,
2686
+ container: containerRef.current,
2687
+ columns: adaptedData.columns,
2688
+ records: adaptedData.records,
2689
+ theme,
2690
+ commandManager,
2691
+ uploadFileFn,
2692
+ innerColumnControl,
2693
+ ...rest
2694
+ });
2695
+ editorRef.current.lock = disabled;
2696
+ editorRef.current.debug = debug;
2697
+ return () => {
2698
+ editorRef.current?.destroy();
2699
+ editorRef.current = null;
2700
+ };
2701
+ }, []);
2702
+ React.useEffect(() => {
2703
+ if (!editorRef.current) return;
2704
+ editorRef.current.updateColumns(adaptedData.columns);
2705
+ }, [adaptedData.columns, editorRef]);
2706
+ React.useEffect(() => {
2707
+ if (!editorRef.current) return;
2708
+ const highlight = adaptedData.highlight;
2709
+ const highlightCellsGroup = Object.entries(highlight).map(([styleKey, cells]) => {
2710
+ return {
2711
+ styleKey,
2712
+ cells
2713
+ };
2714
+ });
2715
+ highlightCellsGroup.forEach((group) => {
2716
+ if (!editorRef.current) return;
2717
+ const cells = group.cells.map((cell) => {
2718
+ if (cell.type === "cell") return { row: cell.row, col: cell.col };
2719
+ else if (cell.type === "row") {
2720
+ return {
2721
+ range: {
2722
+ start: { col: 0 + 1, row: cell.row + 1 },
2723
+ end: { col: editorRef.current.colCount, row: cell.row }
2724
+ }
2725
+ };
2726
+ } else if (cell.type === "column") {
2727
+ return {
2728
+ range: {
2729
+ start: { col: cell.col, row: 0 },
2730
+ end: { col: cell.col, row: editorRef.current.rowCount }
2731
+ }
2732
+ };
2733
+ } else throw new Error(`Unknown cell type ${cell.type}`);
2734
+ });
2735
+ editorRef.current.highlightCells(group.styleKey, cells);
2736
+ });
2737
+ editorRef.current.innerColumnControl = innerColumnControlState;
2738
+ editorRef.current.updateColumns(adaptedData.columns);
2739
+ }, [editorRef, adaptedData.highlight, innerColumnControlState, adaptedData.columns]);
2740
+ const [recordCount, setRecordCount] = React.useState(adaptedData.records.length);
2741
+ React.useEffect(() => {
2742
+ if (!editorRef.current) {
2743
+ setRecordCount(0);
2744
+ return;
2745
+ }
2746
+ const sizeUpdate = () => {
2747
+ if (!editorRef.current) setRecordCount(0);
2748
+ else setRecordCount(window.store.get(editorRef.current.recordsManager.size));
2749
+ };
2750
+ const cancel = window.store.sub(editorRef.current.recordsManager.size, sizeUpdate);
2751
+ return () => cancel();
2752
+ }, [editorRef, adaptedData.records, recordCount]);
2753
+ const calcHeight = React.useMemo(() => {
2754
+ if (!maxHeight) return "100%";
2755
+ const calHeight = recordCount * core.TABLE_DEFAULT_ROW_HEIGHT + core.TABLE_DEFAULT_ROW_HEIGHT + 2;
2756
+ const height = lodash.max([lodash.min([calHeight, maxHeight]), core.TABLE_DEFAULT_ROW_HEIGHT]);
2757
+ return height;
2758
+ }, [recordCount, maxHeight]);
2759
+ return /* @__PURE__ */ React.createElement(
2760
+ "div",
2761
+ {
2762
+ contentEditable: false,
2763
+ className: `table-wrapper`,
2764
+ style: { width: "100%", height: calcHeight, position: "relative" }
2765
+ },
2766
+ /* @__PURE__ */ React.createElement("div", { className: "table-container", ref: containerRef, style: { width: "100%", height: "100%" } }),
2767
+ /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(TableSelectEditor, null), /* @__PURE__ */ React.createElement(LinkEditor, null), /* @__PURE__ */ React.createElement(UserShow, null), /* @__PURE__ */ React.createElement(DateSelect, null), /* @__PURE__ */ React.createElement(TextEditor, null), /* @__PURE__ */ React.createElement(NumEditor, null), /* @__PURE__ */ React.createElement(TableJsonEditor, null)),
2768
+ /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(CellContextMenu, null), /* @__PURE__ */ React.createElement(HeaderContextMenu, null), /* @__PURE__ */ React.createElement(MoreContextMenu, null))
2769
+ );
2770
+ };
2771
+ const TableLayout = () => {
2772
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(TableView, null), /* @__PURE__ */ React.createElement(Hotkeys, null));
2773
+ };
2774
+ const Table = (props) => {
2775
+ return /* @__PURE__ */ React.createElement(VTableProvider, { ...props }, /* @__PURE__ */ React.createElement(TableLayout, null));
2776
+ };
2777
+
2778
+ const MenuItemInputLabel = ({ icon, direction, type, onCellClick, disabled }) => {
2779
+ const menu = useMenu();
2780
+ const tableEditor = useActiveEditorTable();
2781
+ if (!menu) throw new Error("menu \u5FC5\u987B\u5B58\u5728");
2782
+ if (!tableEditor) throw new Error("tableEditor \u5FC5\u987B\u5B58\u5728");
2783
+ const [inputValue, setInputValue] = React.useState(1);
2784
+ const directionLabel = React.useMemo(() => {
2785
+ if (direction === "left") return "\u5DE6";
2786
+ if (direction === "right") return "\u53F3";
2787
+ if (direction === "up") return "\u4E0A";
2788
+ if (direction === "down") return "\u4E0B";
2789
+ }, [direction]);
2790
+ const onClick = (e) => {
2791
+ onCellClick?.({ cell: menu.cell, tableEditor, e }, inputValue);
2792
+ };
2793
+ return /* @__PURE__ */ React.createElement(antd.Flex, { align: "center", onClick, gap: 10 }, icon, /* @__PURE__ */ React.createElement(antd.Flex, { gap: 10, style: { width: "100%" }, align: "center" }, /* @__PURE__ */ React.createElement("span", null, "\u5411", directionLabel, "\u63D2\u5165"), /* @__PURE__ */ React.createElement(
2794
+ antd.InputNumber,
2795
+ {
2796
+ defaultValue: 1,
2797
+ disabled,
2798
+ rootClassName: "menu-item-label-input",
2799
+ onClick: (e) => {
2800
+ e.stopPropagation();
2801
+ },
2802
+ style: { width: 40 },
2803
+ value: inputValue,
2804
+ onChange: (value) => setInputValue(value || 1),
2805
+ controls: false
2806
+ }
2807
+ ), /* @__PURE__ */ React.createElement("span", null, type === "row" ? "\u884C" : "\u5217")));
2808
+ };
2809
+
2810
+ function initEditorTool(type, value) {
2811
+ switch (type) {
2812
+ case 30:
2813
+ case 29:
2814
+ initSelectEditorTool(value);
2815
+ break;
2816
+ case 33:
2817
+ initLinkEditorTool(value);
2818
+ break;
2819
+ case 36:
2820
+ initDateEditorTool(value);
2821
+ break;
2822
+ case 31:
2823
+ initNumEditorTool(value);
2824
+ break;
2825
+ case 28:
2826
+ initTextEditorTool(value);
2827
+ break;
2828
+ case 34:
2829
+ initJsonEditorTool(value);
2830
+ break;
2831
+ case 38:
2832
+ break;
2833
+ default:
2834
+ throw new Error(`[initEditorTool] \u4E0D\u652F\u6301\u7684\u5DE5\u5177\u7C7B\u578B ${type}`);
2835
+ }
2836
+ }
2837
+ const clearEditorTool = () => {
2838
+ clearSelectEditorTool();
2839
+ clearLinkEditorTool();
2840
+ clearDateEditorTool();
2841
+ clearTextEditorTool();
2842
+ clearNumEditorTool();
2843
+ clearJsonEditorTool();
2844
+ };
2845
+
2846
+ class DateSelectEditorTool {
2847
+ onStart(props) {
2848
+ const { col, row, table, value, endEdit } = props;
2849
+ this.row = row;
2850
+ this.col = col;
2851
+ this.table = table;
2852
+ this.oldValue = value;
2853
+ const rect = table.getCellRelativeRect?.(col, row);
2854
+ if (!rect) throw new Error("[DateSelectEditorTool::onStart] rect is Nil");
2855
+ initEditorTool(36, {
2856
+ cell: {
2857
+ col,
2858
+ row,
2859
+ position: { x: rect.left, y: rect.top },
2860
+ width: rect.width,
2861
+ height: rect.height
2862
+ },
2863
+ endEdit,
2864
+ table,
2865
+ initialValue: value?.value
2866
+ });
2867
+ }
2868
+ //校验
2869
+ validateValue(newValue, oldValue) {
2870
+ this.newValue = newValue;
2871
+ this.oldValue = oldValue;
2872
+ return VTable_editors.ValidateEnum.invalidateExit;
2873
+ }
2874
+ setValue() {
2875
+ }
2876
+ // 结束编辑时触发,返回编辑后的值
2877
+ getValue() {
2878
+ return { ...this.oldValue, value: getDateEditorValue() };
2879
+ }
2880
+ // 退出编辑状态
2881
+ onEnd() {
2882
+ const tableEditor = getActiveEditorTable();
2883
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) return;
2884
+ if (!tableEditor) {
2885
+ throw new Error("[DateSelectEditorTool::onEnd] tableEditor is Nil");
2886
+ }
2887
+ const command = new EditTableCellDataCommand(tableEditor, this.col, this.row, this.newValue, this.oldValue);
2888
+ tableEditor.commandManager.execute(command);
2889
+ clearEditorTool();
2890
+ }
2891
+ isEditorElement(target) {
2892
+ return !!target.closest(".ant-picker-dropdown");
2893
+ }
2894
+ }
2895
+
2896
+ class JsonEditorTool {
2897
+ // 双击单元格触发,进入编辑状态
2898
+ onStart(props) {
2899
+ const { col, row, table, value, endEdit } = props;
2900
+ this.row = row;
2901
+ this.col = col;
2902
+ this.table = table;
2903
+ this.oldValue = value;
2904
+ const rect = table.getCellRelativeRect(col, row);
2905
+ if (!rect) throw new Error("[LinkEditor::onStart] rect is Nil");
2906
+ initEditorTool(34, {
2907
+ cell: {
2908
+ col,
2909
+ row,
2910
+ position: { x: rect.left, y: rect.top },
2911
+ width: rect.width,
2912
+ height: rect.height
2913
+ },
2914
+ endEdit,
2915
+ table,
2916
+ initialValue: value?.value
2917
+ });
2918
+ }
2919
+ validateValue(newValue, oldValue) {
2920
+ this.newValue = newValue;
2921
+ this.oldValue = oldValue;
2922
+ return VTable_editors.ValidateEnum.invalidateExit;
2923
+ }
2924
+ // 不可删除,否则会报错
2925
+ setValue() {
2926
+ }
2927
+ // 结束编辑时触发,返回编辑后的值
2928
+ getValue() {
2929
+ return { ...this.oldValue, value: getJsonEditorValue() };
2930
+ }
2931
+ // 退出编辑状态
2932
+ onEnd() {
2933
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) return;
2934
+ const tableEditor = getActiveEditorTable();
2935
+ if (!tableEditor) throw new Error("[JsonEditor::onEnd] tableEditor is Nil");
2936
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) throw new Error("[JsonEditor::onEnd] col or row is Nil");
2937
+ const command = new EditTableCellDataCommand(tableEditor, this.col, this.row, this.newValue, this.oldValue);
2938
+ tableEditor.commandManager.execute(command);
2939
+ clearEditorTool();
2940
+ }
2941
+ /**
2942
+ * 如果提供了此函数,VTable 将会在用户点击其他地方时调用此函数。
2943
+ * 如果此函数返回了一个假值,VTable 将会调用 `onEnd` 并退出编辑状态。
2944
+ * 如果未定义此函数或此函数返回了一个真值, VTable 将不会做任何事。
2945
+ * 这意味着,你需要手动调用 `onStart` 中提供的 `endEdit` 来结束编辑模式。
2946
+ */
2947
+ isEditorElement(target) {
2948
+ return !!target.closest(".json-editor-modal-container");
2949
+ }
2950
+ }
2951
+
2952
+ class LinkEditorTool {
2953
+ // 双击单元格触发,进入编辑状态
2954
+ onStart(props) {
2955
+ const { col, row, table, value, endEdit } = props;
2956
+ this.row = row;
2957
+ this.col = col;
2958
+ this.table = table;
2959
+ this.oldValue = value;
2960
+ const rect = table.getCellRelativeRect(col, row);
2961
+ if (!rect) throw new Error("[LinkEditor::onStart] rect is Nil");
2962
+ initEditorTool(33, {
2963
+ cell: {
2964
+ col,
2965
+ row,
2966
+ position: { x: rect.left, y: rect.top },
2967
+ width: rect.width,
2968
+ height: rect.height
2969
+ },
2970
+ endEdit,
2971
+ table,
2972
+ initialValue: value?.value
2973
+ });
2974
+ }
2975
+ validateValue(newValue, oldValue) {
2976
+ this.newValue = newValue;
2977
+ this.oldValue = oldValue;
2978
+ return VTable_editors.ValidateEnum.invalidateExit;
2979
+ }
2980
+ // 不可删除,否则会报错
2981
+ setValue() {
2982
+ }
2983
+ // 结束编辑时触发,返回编辑后的值
2984
+ getValue() {
2985
+ return { ...this.oldValue, value: getLinkEditorValue() };
2986
+ }
2987
+ // 退出编辑状态
2988
+ onEnd() {
2989
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) return;
2990
+ const tableEditor = getActiveEditorTable();
2991
+ if (!tableEditor) throw new Error("[LinkEditor::onEnd] tableEditor is Nil");
2992
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) throw new Error("[LinkEditor::onEnd] col or row is Nil");
2993
+ const command = new EditTableCellDataCommand(tableEditor, this.col, this.row, this.newValue, this.oldValue);
2994
+ tableEditor.commandManager.execute(command);
2995
+ clearEditorTool();
2996
+ }
2997
+ /**
2998
+ * 如果提供了此函数,VTable 将会在用户点击其他地方时调用此函数。
2999
+ * 如果此函数返回了一个假值,VTable 将会调用 `onEnd` 并退出编辑状态。
3000
+ * 如果未定义此函数或此函数返回了一个真值, VTable 将不会做任何事。
3001
+ * 这意味着,你需要手动调用 `onStart` 中提供的 `endEdit` 来结束编辑模式。
3002
+ */
3003
+ isEditorElement(target) {
3004
+ return !!target.closest(".link-editor-popover-root") || !!target.closest(".link-editor-popover");
3005
+ }
3006
+ }
3007
+
3008
+ class NumEditorTool {
3009
+ // 双击单元格触发,进入编辑状态
3010
+ onStart(props) {
3011
+ const { col, row, table, value, endEdit } = props;
3012
+ this.row = row;
3013
+ this.col = col;
3014
+ this.oldValue = value;
3015
+ const rect = table.getCellRelativeRect(col, row);
3016
+ if (!rect) throw new Error("[NumEditor::onStart] rect is Nil");
3017
+ initEditorTool(31, {
3018
+ endEdit,
3019
+ initialValue: value?.value,
3020
+ table,
3021
+ cell: {
3022
+ col,
3023
+ row,
3024
+ position: { x: rect.left, y: rect.top },
3025
+ width: rect.width,
3026
+ height: rect.height
3027
+ }
3028
+ });
3029
+ }
3030
+ validateValue(newValue, oldValue) {
3031
+ this.newValue = newValue;
3032
+ this.oldValue = oldValue;
3033
+ return VTable_editors.ValidateEnum.invalidateExit;
3034
+ }
3035
+ setValue() {
3036
+ }
3037
+ // 结束编辑时触发,返回编辑后的值
3038
+ getValue() {
3039
+ return { ...this.oldValue, value: getNumEditorValue() };
3040
+ }
3041
+ // 退出编辑状态
3042
+ onEnd() {
3043
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) return;
3044
+ const tableEditor = getActiveEditorTable();
3045
+ if (!tableEditor) throw new Error("[NumEditor::onEnd] tableEditor is Nil");
3046
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) throw new Error("[NumEditor::onEnd] col or row is Nil");
3047
+ const command = new EditTableCellDataCommand(tableEditor, this.col, this.row, this.newValue, this.oldValue);
3048
+ tableEditor.commandManager.execute(command);
3049
+ clearEditorTool();
3050
+ }
3051
+ isEditorElement(target) {
3052
+ return target.className.includes("ant-input-number");
3053
+ }
3054
+ }
3055
+
3056
+ class MultiSelectEditorTool {
3057
+ // 双击单元格触发,进入编辑状态
3058
+ onStart(props) {
3059
+ const { col, row, table, value, endEdit } = props;
3060
+ this.table = table;
3061
+ this.col = col;
3062
+ this.row = row;
3063
+ this.oldValue = value;
3064
+ const rect = table.getCellRelativeRect(col, row);
3065
+ if (!rect) throw new Error("[MultiSelectEditor::onStart] rect is Nil");
3066
+ const options = table.getBodyColumnDefine(col, 0)?.options || [];
3067
+ initEditorTool(30, {
3068
+ initialValue: value?.value ?? [],
3069
+ endEdit,
3070
+ options,
3071
+ table,
3072
+ cell: {
3073
+ col,
3074
+ row,
3075
+ position: { x: rect.left, y: rect.top },
3076
+ width: rect.width,
3077
+ height: rect.height
3078
+ },
3079
+ isMultiple: true
3080
+ });
3081
+ }
3082
+ validateValue(newValue, oldValue) {
3083
+ this.newValue = newValue;
3084
+ this.oldValue = oldValue;
3085
+ return VTable_editors.ValidateEnum.invalidateExit;
3086
+ }
3087
+ setValue() {
3088
+ }
3089
+ // 结束编辑时触发,返回编辑后的值
3090
+ getValue() {
3091
+ return { ...this.oldValue, value: getSelectEditorValue() };
3092
+ }
3093
+ // 退出编辑状态
3094
+ onEnd() {
3095
+ clearEditorTool();
3096
+ }
3097
+ /**
3098
+ * 如果提供了此函数,VTable 将会在用户点击其他地方时调用此函数。
3099
+ * 如果此函数返回了一个假值,VTable 将会调用 `onEnd` 并退出编辑状态。
3100
+ * 如果未定义此函数或此函数返回了一个真值, VTable 将不会做任何事。
3101
+ * 这意味着,你需要手动调用 `onStart` 中提供的 `endEdit` 来结束编辑模式。
3102
+ */
3103
+ isEditorElement(target) {
3104
+ return !!target.closest(".multi-select-editor-popover-root") || !!target.closest(".multi-select-editor-popover") || !!target.closest(".selector-color-picker") || !!target.closest(".option-item-modal");
3105
+ }
3106
+ }
3107
+
3108
+ class SingleSelectEditorTool {
3109
+ // 双击单元格触发,进入编辑状态
3110
+ onStart(props) {
3111
+ const { col, row, table, value, endEdit } = props;
3112
+ this.table = table;
3113
+ this.col = col;
3114
+ this.row = row;
3115
+ this.oldValue = value;
3116
+ const rect = table.getCellRelativeRect(col, row);
3117
+ if (!rect) throw new Error("[SingleSelectEditor::onStart] rect is Nil");
3118
+ const options = table.getBodyColumnDefine(col, 0)?.options || [];
3119
+ initEditorTool(29, {
3120
+ initialValue: value?.value ?? [],
3121
+ endEdit,
3122
+ options,
3123
+ table,
3124
+ cell: {
3125
+ col,
3126
+ row,
3127
+ position: { x: rect.left, y: rect.top },
3128
+ width: rect.width,
3129
+ height: rect.height
3130
+ },
3131
+ isMultiple: false
3132
+ });
3133
+ }
3134
+ validateValue(newValue, oldValue) {
3135
+ this.newValue = newValue;
3136
+ this.oldValue = oldValue;
3137
+ return VTable_editors.ValidateEnum.invalidateExit;
3138
+ }
3139
+ setValue() {
3140
+ }
3141
+ // 结束编辑时触发,返回编辑后的值
3142
+ getValue() {
3143
+ return { ...this.oldValue, value: getSelectEditorValue() };
3144
+ }
3145
+ // 退出编辑状态
3146
+ onEnd() {
3147
+ clearEditorTool();
3148
+ }
3149
+ /**
3150
+ * 如果提供了此函数,VTable 将会在用户点击其他地方时调用此函数。
3151
+ * 如果此函数返回了一个假值,VTable 将会调用 `onEnd` 并退出编辑状态。
3152
+ * 如果未定义此函数或此函数返回了一个真值, VTable 将不会做任何事。
3153
+ * 这意味着,你需要手动调用 `onStart` 中提供的 `endEdit` 来结束编辑模式。
3154
+ */
3155
+ isEditorElement(target) {
3156
+ return !!target.closest(".multi-select-editor-popover-root") || !!target.closest(".multi-select-editor-popover") || !!target.closest(".selector-color-picker") || !!target.closest(".option-item-modal");
3157
+ }
3158
+ }
3159
+
3160
+ class TextEditorTool {
3161
+ // 双击单元格触发,进入编辑状态
3162
+ onStart(props) {
3163
+ const { col, row, table, value, endEdit } = props;
3164
+ this.row = row;
3165
+ this.col = col;
3166
+ this.oldValue = value;
3167
+ const rect = table.getCellRelativeRect(col, row);
3168
+ if (!rect) throw new Error("[TextEditor::onStart] rect is Nil");
3169
+ initEditorTool(28, {
3170
+ endEdit,
3171
+ initialValue: value?.value ?? "",
3172
+ table,
3173
+ cell: {
3174
+ col,
3175
+ row,
3176
+ position: { x: rect.left, y: rect.top },
3177
+ width: rect.width,
3178
+ height: rect.height
3179
+ }
3180
+ });
3181
+ }
3182
+ validateValue(newValue, oldValue) {
3183
+ this.newValue = newValue;
3184
+ this.oldValue = oldValue;
3185
+ return VTable_editors.ValidateEnum.invalidateExit;
3186
+ }
3187
+ setValue() {
3188
+ }
3189
+ // 结束编辑时触发,返回编辑后的值
3190
+ getValue() {
3191
+ return { ...this.oldValue, value: getTextEditorValue() };
3192
+ }
3193
+ // 退出编辑状态
3194
+ onEnd() {
3195
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) return;
3196
+ const tableEditor = getActiveEditorTable();
3197
+ if (!tableEditor) throw new Error("[TextEditor::onEnd] tableEditor is Nil");
3198
+ if (lodash.isNil(this.col) || lodash.isNil(this.row)) throw new Error("[TextEditor::onEnd] col or row is Nil");
3199
+ const command = new EditTableCellDataCommand(tableEditor, this.col, this.row, this.newValue, this.oldValue);
3200
+ tableEditor.commandManager.execute(command);
3201
+ clearEditorTool();
3202
+ }
3203
+ isEditorElement(target) {
3204
+ return target.className.includes("ant-input");
3205
+ }
3206
+ }
3207
+
3208
+ const inputEditor = new VTable_editors__namespace.InputEditor();
3209
+ const dateInputEditor = new VTable_editors__namespace.DateInputEditor();
3210
+ const textAreaEditor = new VTable_editors__namespace.TextAreaEditor({ readonly: false });
3211
+ const linkEditor = new LinkEditorTool();
3212
+ const dateRangeEditor = new DateSelectEditorTool();
3213
+ const textEditor = new TextEditorTool();
3214
+ const numberEditor = new NumEditorTool();
3215
+ const multiSelectEditor = new MultiSelectEditorTool();
3216
+ const singleSelectEditor = new SingleSelectEditorTool();
3217
+ const jsonEditor = new JsonEditorTool();
3218
+ const editorRegistry = () => {
3219
+ VTable__namespace.register.editor("inputEditor", inputEditor);
3220
+ VTable__namespace.register.editor("dateInputEditor", dateInputEditor);
3221
+ VTable__namespace.register.editor("textAreaEditor", textAreaEditor);
3222
+ VTable__namespace.register.editor("multiSelectEditor", multiSelectEditor);
3223
+ VTable__namespace.register.editor("linkEditor", linkEditor);
3224
+ VTable__namespace.register.editor("dateInputEditor", dateRangeEditor);
3225
+ VTable__namespace.register.editor("textEditor", textEditor);
3226
+ VTable__namespace.register.editor("numberEditor", numberEditor);
3227
+ VTable__namespace.register.editor("singleSelectEditor", singleSelectEditor);
3228
+ VTable__namespace.register.editor("jsonEditor", jsonEditor);
3229
+ };
3230
+
3231
+ const padding = 4;
3232
+ const createIconGraphics = (name, props) => {
3233
+ const { disabled, cursor, x = 0, y = 0, size = 20, color = core.COLOR_ICON, hoverBg, onClick } = props ?? {};
3234
+ const u = fontIconEnableaiBase.EnableAIBaseFontIcon.get(name, "unicode");
3235
+ const group = vrender.createGroup({
3236
+ display: "flex",
3237
+ x,
3238
+ y,
3239
+ width: size + padding,
3240
+ height: size + padding,
3241
+ cornerRadius: 4,
3242
+ cursor: disabled ? void 0 : cursor,
3243
+ alignContent: "center",
3244
+ alignItems: "center",
3245
+ justifyContent: "center"
3246
+ });
3247
+ const text = vrender.createText({
3248
+ text: u,
3249
+ fontSize: size,
3250
+ fontFamily: fontIconEnableaiBase.EnableAIBaseFontIcon.fontFamily,
3251
+ fill: color,
3252
+ cursor: disabled ? void 0 : cursor,
3253
+ textBaseline: "alphabetic"
3254
+ });
3255
+ if (hoverBg && !disabled) {
3256
+ group.addEventListener("mouseover", () => {
3257
+ group.setAttribute("background", "#f0f0f0");
3258
+ group.stage?.renderNextFrame();
3259
+ });
3260
+ group.addEventListener("mouseleave", () => {
3261
+ group.setAttribute("background", "");
3262
+ group.stage?.renderNextFrame();
3263
+ });
3264
+ if (onClick) group.addEventListener("click", onClick);
3265
+ }
3266
+ group.add(text);
3267
+ return group;
3268
+ };
3269
+
3270
+ const createPlusHeaderGraphics = (props) => {
3271
+ const { table, row, col, rect } = props;
3272
+ const { height, width } = rect ?? table.getCellRect(col, row);
3273
+ const group = vrender.createGroup({
3274
+ display: "flex",
3275
+ alignContent: "center",
3276
+ alignItems: "center",
3277
+ justifyContent: "center",
3278
+ width,
3279
+ height,
3280
+ cursor: "pointer"
3281
+ });
3282
+ const icon = createIconGraphics("plus", {
3283
+ cursor: "pointer"
3284
+ });
3285
+ group.add(icon);
3286
+ group.addEventListener("click", () => {
3287
+ const editor = getActiveEditorTable();
3288
+ if (!editor) throw new Error("[createPlusHeaderGraphics::onClick]editor is not found");
3289
+ editor.dispatch("column::add::from::inner::plus", {
3290
+ editor
3291
+ });
3292
+ });
3293
+ return group;
3294
+ };
3295
+
3296
+ dayjs.extend(utc);
3297
+ dayjs.extend(timezone);
3298
+ dayjs.extend(customParseFormat);
3299
+ const FIXED_TIMEZONE_LABEL = "(GMT+8)";
3300
+ const createDateGraphics = (props) => {
3301
+ const { table, row, col, rect } = props;
3302
+ const { height, width } = rect ?? table.getCellRect(col, row);
3303
+ const loading = !!props.value?.loading;
3304
+ const columnDefine = table.getBodyColumnDefine(col, row);
3305
+ const type = columnDefine.fmt;
3306
+ const cellStyle = table._getCellStyle(col, row);
3307
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
3308
+ const functionalColor = getProp("color", cellStyle, col, row, table);
3309
+ const headerIconSize = getIconSizeFromFont(functionalFontSize);
3310
+ const padding = [5, 10];
3311
+ const group = vrender.createGroup({
3312
+ width,
3313
+ height,
3314
+ display: "flex",
3315
+ flexWrap: "nowrap",
3316
+ justifyContent: "flex-start",
3317
+ alignContent: "center",
3318
+ alignItems: "center"
3319
+ });
3320
+ const value = props.value?.value ?? "";
3321
+ const getPureDateFormat = (format) => {
3322
+ return format.replace(/\s*\(GMT\+8\)$/i, "").replace(/\s*\(G1T\+8\)$/i, "").replace(/\s*\(G10T\+8\)$/i, "").replace(/G1T\+8/gi, "").replace(/G10T\+8/gi, "").trim();
3323
+ };
3324
+ const formattedValue1 = (() => {
3325
+ const cleanedValue = value && value?.replace(/\s*\([^)]+\)$/gi, "").replace(/:/g, ":").replace(/\s+/g, " ").replace(/(|)/g, "").replace(/[\u200B-\u200D\uFEFF]/g, "").replace(/[^0-9\/\-\s:]/g, "");
3326
+ const pureDateTimeMatch = cleanedValue.match(/(\d{4}[-\/]\d{2}[-\/]\d{2}(?:\s+\d{2}:\d{2})?)/);
3327
+ const pureDateTime = pureDateTimeMatch?.[1]?.trim() || "";
3328
+ if (!pureDateTime) return "";
3329
+ const pureDateFormat = getPureDateFormat(type);
3330
+ if (!pureDateFormat) return "";
3331
+ const parseFormats = [pureDateFormat, "YYYY/MM/DD HH:mm", "YYYY-MM-DD HH:mm", "YYYY/MM/DD", "YYYY-MM-DD"];
3332
+ let finalParsedDate = dayjs(pureDateTime, parseFormats[0], true);
3333
+ for (const format of parseFormats.slice(1)) {
3334
+ if (!finalParsedDate.isValid()) {
3335
+ finalParsedDate = dayjs(pureDateTime, format, true);
3336
+ } else break;
3337
+ }
3338
+ if (!finalParsedDate.isValid()) return "";
3339
+ const pureFormattedDate = finalParsedDate.format(pureDateFormat);
3340
+ return type.includes("GMT+8") || type.includes("G1T+8") || type.includes("G10T+8") ? pureFormattedDate + " " + FIXED_TIMEZONE_LABEL : pureFormattedDate;
3341
+ })();
3342
+ const text = vrender.createText({
3343
+ fontSize: headerIconSize,
3344
+ fontFamily: "sans-serif",
3345
+ text: formattedValue1,
3346
+ fill: functionalColor,
3347
+ maxLineWidth: width - padding[1] * 2,
3348
+ boundsPadding: [5, 12, 5, 10]
3349
+ });
3350
+ group.add(text);
3351
+ return createGraphicsWithLoading(group, loading);
3352
+ };
3353
+
3354
+ const createLinkGraphics = (props) => {
3355
+ const { value, table, rect, col, row } = props;
3356
+ const { title, url } = value?.value ?? {};
3357
+ const loading = value?.loading ?? false;
3358
+ const padding = [5, 10];
3359
+ const { height, width } = rect ?? table.getCellRect(col, row);
3360
+ const group = vrender.createGroup({
3361
+ width,
3362
+ height,
3363
+ display: "flex",
3364
+ flexWrap: "nowrap",
3365
+ justifyContent: "space-around",
3366
+ alignContent: "center",
3367
+ alignItems: "center"
3368
+ // 垂直居中
3369
+ });
3370
+ const text = vrender.createText({
3371
+ fontSize: 12,
3372
+ fontFamily: "sans-serif",
3373
+ text: title,
3374
+ fill: core.COLOR_LINK,
3375
+ cursor: "pointer",
3376
+ maxLineWidth: width - padding[1] * 2,
3377
+ boundsPadding: [5, 12, 5, 10]
3378
+ });
3379
+ text.addEventListener("click", () => window.open(url));
3380
+ text.addEventListener("mouseover", () => {
3381
+ text.setAttribute("underline", 1);
3382
+ text.stage?.renderNextFrame();
3383
+ });
3384
+ text.addEventListener("mouseleave", () => {
3385
+ text.setAttribute("underline", 0);
3386
+ text.stage?.renderNextFrame();
3387
+ });
3388
+ group.add(text);
3389
+ return createGraphicsWithLoading(group, loading);
3390
+ };
3391
+
3392
+ const createMainColumnCellGraphics = (props) => {
3393
+ const { row, col, rect, table } = props;
3394
+ const { height, width } = rect ?? table.getCellRect(col, row);
3395
+ const loading = !!props.value?.loading;
3396
+ const cellStyle = table._getCellStyle(col, row);
3397
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
3398
+ const group = vrender.createGroup({
3399
+ width,
3400
+ height,
3401
+ display: "flex",
3402
+ alignItems: "center",
3403
+ justifyContent: "space-between"
3404
+ });
3405
+ const text = vrender.createText({
3406
+ fontSize: functionalFontSize,
3407
+ text: props.value?.value ?? "",
3408
+ fill: getProp("color", cellStyle, col, row, table),
3409
+ cursor: "pointer",
3410
+ maxLineWidth: width - 30
3411
+ });
3412
+ group.add(text);
3413
+ const ig = vrender.createGroup({
3414
+ width: 30,
3415
+ height,
3416
+ display: "flex",
3417
+ alignItems: "center",
3418
+ justifyContent: "center"
3419
+ });
3420
+ const detailIcon = createIconGraphics("drawer", {
3421
+ hoverBg: true,
3422
+ cursor: "pointer",
3423
+ size: functionalFontSize,
3424
+ onClick: () => {
3425
+ const editor = getActiveEditorTable();
3426
+ if (!editor) throw new Error("createMainColumnCellGraphics::detailIcon onclick \u672A\u83B7\u53D6\u5230activeEditorTable");
3427
+ const { recordId } = editor.getInteractiveCell(col, row);
3428
+ editor.dispatch("record::open::detail::drawer", { editor, recordId });
3429
+ }
3430
+ });
3431
+ ig.add(detailIcon);
3432
+ ig.removeChild(detailIcon);
3433
+ group.addEventListener("mouseover", () => {
3434
+ ig.setAttribute("visible", true);
3435
+ ig.add(detailIcon);
3436
+ group.stage?.renderNextFrame();
3437
+ });
3438
+ group.addEventListener("mouseleave", () => {
3439
+ ig.setAttribute("visible", false);
3440
+ ig.removeChild(detailIcon);
3441
+ group.stage?.renderNextFrame();
3442
+ });
3443
+ group.add(ig);
3444
+ return createGraphicsWithLoading(group, loading);
3445
+ };
3446
+
3447
+ const createMoreGraphics = (props) => {
3448
+ const { onClick, onCancel, record, row, col, table, rect, value } = props;
3449
+ const loading = !!value?.loading;
3450
+ const cellStyle = table._getCellStyle(col, row);
3451
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
3452
+ const functionalColor = getProp("color", cellStyle, col, row, table);
3453
+ const { height, width } = rect ?? table.getCellRect(col, row);
3454
+ const group = vrender.createGroup({
3455
+ width,
3456
+ height,
3457
+ display: "flex",
3458
+ cursor: "pointer",
3459
+ justifyContent: "center",
3460
+ alignItems: "center"
3461
+ });
3462
+ const icon = createIconGraphics("more", {
3463
+ size: getIconSizeFromFont(functionalFontSize),
3464
+ color: functionalColor,
3465
+ x: (width - 16) / 2,
3466
+ y: (height - 16) / 2,
3467
+ cursor: "pointer"
3468
+ });
3469
+ const handleEvent = (evt) => {
3470
+ evt.stopPropagation();
3471
+ const x = evt.clientX || evt.x || 0;
3472
+ const y = evt.clientY || evt.y || 0;
3473
+ onClick?.({ row, col, record, x, y });
3474
+ const rect2 = table.getCellRelativeRect(col, row);
3475
+ const tableEditor = getActiveEditorTable();
3476
+ if (!tableEditor) throw new Error("tableEditor \u4E0D\u5B58\u5728");
3477
+ const { recordId, columnId } = tableEditor.getInteractiveCell(row, col);
3478
+ setMenu({
3479
+ open: true,
3480
+ position: { x: rect2.left + width / 2 - 8, y: rect2.top + height / 2 - 8 },
3481
+ type: "more",
3482
+ cell: { col, row, recordId, columnId, rect: rect2 }
3483
+ });
3484
+ };
3485
+ const handleCancel = (evt) => {
3486
+ evt.stopPropagation();
3487
+ onCancel?.();
3488
+ setMenu(null);
3489
+ };
3490
+ group.addEventListener("pointerenter", handleEvent);
3491
+ group.addEventListener("pointermove", handleEvent);
3492
+ group.addEventListener("click", handleEvent);
3493
+ group.addEventListener("pointerleave", handleCancel);
3494
+ group.add(icon);
3495
+ return createGraphicsWithLoading(group, loading);
3496
+ };
3497
+
3498
+ const formatTagItem = (value, options, tableInstance) => {
3499
+ const {
3500
+ blankWidth = 16,
3501
+ fontWeight = 400,
3502
+ fontSize,
3503
+ fontColor = "black",
3504
+ fontFamily = "PingFang SC",
3505
+ basePadding = 16 * 2,
3506
+ tagMinWidth = 48,
3507
+ cellWidth
3508
+ } = options;
3509
+ const tagMaxWidth = Math.max(cellWidth - basePadding, tagMinWidth);
3510
+ const item = {
3511
+ label: value.label,
3512
+ value: value.value
3513
+ };
3514
+ const label = (item.label || "").replace(/[\u200B\u2060]/g, "");
3515
+ const { width } = tableInstance.measureText(label, {
3516
+ fontSize,
3517
+ fontWeight,
3518
+ fontFamily
3519
+ });
3520
+ const textLength = Math.ceil(width) + blankWidth;
3521
+ const tagWidth = Math.min(Math.max(textLength, tagMinWidth), tagMaxWidth);
3522
+ if (!item.tagProps) {
3523
+ item.tagProps = {
3524
+ fontColor,
3525
+ backgroundColor: value.color,
3526
+ width: 0
3527
+ };
3528
+ }
3529
+ item.tagProps.width = tagWidth;
3530
+ return {
3531
+ textLength,
3532
+ tagWidth,
3533
+ tagMaxWidth,
3534
+ tagMinWidth,
3535
+ item
3536
+ };
3537
+ };
3538
+
3539
+ const TAG_HEIGHT$2 = 18;
3540
+ const TAG_GAP = 8;
3541
+ const NUMBER_WIDTH = 25;
3542
+ const TAG_MIN_WIDTH$2 = TAG_GAP + NUMBER_WIDTH;
3543
+ const getTagsRowMap = (tags, options, tableInstance) => {
3544
+ const res = calcCellTags(
3545
+ tags,
3546
+ {
3547
+ cellWidth: options.cellWidth,
3548
+ fontSize: options.fontSize,
3549
+ blankWidth: options.blankWidth,
3550
+ tagMinWidth: TAG_MIN_WIDTH$2
3551
+ },
3552
+ tableInstance
3553
+ );
3554
+ return res.filterTagsRowMap;
3555
+ };
3556
+ const calcCellTags = (tags = [], options, tableInstance) => {
3557
+ if (!tags.length) return { filterTags: [], filterTagsRowMap: {} };
3558
+ const data = lodash.cloneDeep(tags);
3559
+ const filterTags = [];
3560
+ const filterTagsRowMap = {};
3561
+ const numberTagWidth = TAG_GAP + NUMBER_WIDTH;
3562
+ const len = data.length;
3563
+ let totalWidth = 0;
3564
+ const currentRow = 1;
3565
+ const addTags = (item) => {
3566
+ filterTags.push(item);
3567
+ if (!filterTagsRowMap[currentRow]) {
3568
+ filterTagsRowMap[currentRow] = [];
3569
+ }
3570
+ filterTagsRowMap[currentRow].push(item);
3571
+ };
3572
+ if (len === 1) {
3573
+ const { item } = formatTagItem(data[0], options, tableInstance);
3574
+ addTags(item);
3575
+ } else if (len > 1) {
3576
+ for (let i = 0; i < len; i += 1) {
3577
+ const { item, tagMaxWidth, tagMinWidth, tagWidth } = formatTagItem(data[i], options, tableInstance);
3578
+ const handlePushItem = (item2) => {
3579
+ const calcWidth = totalWidth + tagMinWidth + (i === len - 1 ? 0 : numberTagWidth);
3580
+ if (tagMaxWidth >= calcWidth) {
3581
+ const realTextWidth = Math.min(tagWidth, tagMaxWidth - totalWidth - (i === len - 1 ? 0 : numberTagWidth));
3582
+ item2.tagProps.width = realTextWidth;
3583
+ totalWidth = totalWidth + realTextWidth + TAG_GAP;
3584
+ addTags(item2);
3585
+ return false;
3586
+ } else if (tagMaxWidth < calcWidth) {
3587
+ if (tagMaxWidth < totalWidth + tagMinWidth + numberTagWidth) {
3588
+ addTags({
3589
+ label: "+" + (len - filterTags.length),
3590
+ value: -1,
3591
+ tagProps: {
3592
+ fontColor: "#404A59",
3593
+ backgroundColor: "#eff0f1",
3594
+ width: TAG_MIN_WIDTH$2
3595
+ }
3596
+ });
3597
+ return true;
3598
+ }
3599
+ if (i === len - 1) {
3600
+ item2.tagProps.width = Math.min(tagWidth, tagMaxWidth - totalWidth);
3601
+ addTags(item2);
3602
+ } else {
3603
+ item2.tagProps.width = Math.min(tagWidth, tagMaxWidth - totalWidth - numberTagWidth);
3604
+ addTags(item2);
3605
+ addTags({
3606
+ label: "+" + (len - filterTags.length),
3607
+ value: -1,
3608
+ tagProps: {
3609
+ fontColor: "#404A59",
3610
+ backgroundColor: "#eff0f1",
3611
+ width: NUMBER_WIDTH
3612
+ }
3613
+ });
3614
+ }
3615
+ return true;
3616
+ }
3617
+ };
3618
+ if (handlePushItem(item)) break;
3619
+ }
3620
+ }
3621
+ return { filterTags, filterTagsRowMap };
3622
+ };
3623
+ const createMultiSelectGraphic = (props) => {
3624
+ const { width, height, table, col, row } = props;
3625
+ const value = props.value?.value ?? [];
3626
+ const loading = !!props.value?.loading;
3627
+ const styles = table._getCellStyle(col, row);
3628
+ const options = table.getBodyColumnDefine(col, 0).options || [];
3629
+ const newValue = value.map((item) => {
3630
+ return options.find((option) => option.value === item.value);
3631
+ }).filter(Boolean);
3632
+ const fontSize = getProp("fontSize", styles, col, row, table);
3633
+ const tagsMap = getTagsRowMap(newValue, { cellWidth: width, blankWidth: 16, fontSize }, table) || {};
3634
+ const container = /* @__PURE__ */ React.createElement(
3635
+ vrender.VGroup,
3636
+ {
3637
+ attribute: {
3638
+ width: width - 32,
3639
+ height,
3640
+ display: "flex",
3641
+ alignItems: "center",
3642
+ alignContent: "center",
3643
+ dx: 16
3644
+ }
3645
+ },
3646
+ Object.keys(tagsMap).map((key) => {
3647
+ const tag = tagsMap[Number(key)];
3648
+ return /* @__PURE__ */ React.createElement(
3649
+ vrender.VGroup,
3650
+ {
3651
+ key,
3652
+ attribute: {
3653
+ width: width - 32,
3654
+ height: TAG_HEIGHT$2,
3655
+ display: "flex",
3656
+ alignItems: "center",
3657
+ flexWrap: "nowrap",
3658
+ overflow: "hidden",
3659
+ boundsPadding: [4, 0, 4, 0]
3660
+ }
3661
+ },
3662
+ tag.map((item, subIndex) => {
3663
+ return /* @__PURE__ */ React.createElement(
3664
+ vrender.VGroup,
3665
+ {
3666
+ key: item.value,
3667
+ attribute: {
3668
+ width: item.tagProps.width,
3669
+ height: TAG_HEIGHT$2,
3670
+ display: "flex",
3671
+ alignItems: "center",
3672
+ justifyContent: "center",
3673
+ overflow: "hidden",
3674
+ cornerRadius: TAG_HEIGHT$2 / 2,
3675
+ fill: item.tagProps.backgroundColor,
3676
+ boundsPadding: subIndex > 0 ? [0, 0, 0, 8] : 0
3677
+ }
3678
+ },
3679
+ /* @__PURE__ */ React.createElement(
3680
+ vrender.VText,
3681
+ {
3682
+ attribute: {
3683
+ text: item.label,
3684
+ fontSize,
3685
+ fill: color.getTextColorForBackground(item.tagProps.backgroundColor || "#000000"),
3686
+ textAlign: "left",
3687
+ textBaseline: "top",
3688
+ maxLineWidth: item.tagProps.width - 16
3689
+ }
3690
+ }
3691
+ )
3692
+ );
3693
+ })
3694
+ );
3695
+ })
3696
+ );
3697
+ return createGraphicsWithLoading(container, loading);
3698
+ };
3699
+
3700
+ const createNumberGraphics = (props) => {
3701
+ const { row, col, table, rect, textAlign = "right" } = props;
3702
+ const columnDefine = table.getBodyColumnDefine(col, row);
3703
+ const fmt = columnDefine.fmt ?? "integer";
3704
+ const value = props.value?.value;
3705
+ const loading = !!props.value?.loading;
3706
+ const cellStyle = table._getCellStyle(col, row);
3707
+ const fontSize = getProp("fontSize", cellStyle, col, row, table);
3708
+ const functionalColor = getProp("color", cellStyle, col, row, table);
3709
+ const { height, width } = rect ?? table.getCellRect(col, row);
3710
+ const textValue = core.formatValue(value, fmt);
3711
+ const padding = 10;
3712
+ const group = vrender.createGroup({
3713
+ width,
3714
+ height
3715
+ });
3716
+ const text = vrender.createText({
3717
+ text: textValue,
3718
+ fill: functionalColor,
3719
+ fontFamily: "sans-serif",
3720
+ fontSize,
3721
+ textBaseline: "middle",
3722
+ y: height / 2,
3723
+ maxLineWidth: width - padding * 2
3724
+ });
3725
+ if (textAlign === "left") {
3726
+ text.setAttribute("x", padding);
3727
+ text.setAttribute("textAlign", "left");
3728
+ } else if (textAlign === "center") {
3729
+ text.setAttribute("x", width / 2);
3730
+ text.setAttribute("textAlign", "center");
3731
+ } else {
3732
+ text.setAttribute("x", width - padding);
3733
+ text.setAttribute("textAlign", "right");
3734
+ }
3735
+ group.add(text);
3736
+ return createGraphicsWithLoading(group, loading);
3737
+ };
3738
+
3739
+ const getTextWidth = (text, fontSize) => {
3740
+ const textElement = vrender.createText({
3741
+ text,
3742
+ fontSize
3743
+ });
3744
+ const bounds = textElement.AABBBounds;
3745
+ return bounds.width();
3746
+ };
3747
+
3748
+ const AVATAR_SIZE = 20;
3749
+ const GAP = 4;
3750
+ const ITEM_GAP = 8;
3751
+ const ELLIPSIS = "...";
3752
+ const ELLIPSIS_WIDTH = 8;
3753
+ const PADDING_LEFT = 15;
3754
+ const getName = (id, value) => {
3755
+ if (id == -1) {
3756
+ return "\u7CFB\u7EDF";
3757
+ } else if (id == -2) {
3758
+ return "\u65E0";
3759
+ }
3760
+ return value;
3761
+ };
3762
+ const createPeopleGraphics = (props) => {
3763
+ const { row, col, rect, table } = props;
3764
+ const cellStyle = table?._getCellStyle(col, row);
3765
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
3766
+ const functionalColor = getProp("color", cellStyle, col, row, table);
3767
+ const { height, width } = rect ?? table.getCellRect(col, row);
3768
+ const group = vrender.createGroup({ width, height, x: 15, y: 0 });
3769
+ const value = props.value?.value ?? [];
3770
+ const loading = props.value?.loading ?? false;
3771
+ const items = [];
3772
+ let cursor = 0;
3773
+ for (let i = 0; i < value.length; i++) {
3774
+ const person = value[i];
3775
+ const nameWidth = getTextWidth(getName(person.id, person.name), functionalFontSize);
3776
+ const fullWidth = AVATAR_SIZE + GAP + nameWidth;
3777
+ const remaining = width - cursor - PADDING_LEFT;
3778
+ if (fullWidth <= remaining) {
3779
+ items.push({ person, mode: "full" });
3780
+ cursor += fullWidth + ITEM_GAP;
3781
+ continue;
3782
+ }
3783
+ const minWidth = AVATAR_SIZE + GAP + ELLIPSIS_WIDTH;
3784
+ if (remaining >= minWidth) {
3785
+ const availableNameWidth = remaining - AVATAR_SIZE - GAP;
3786
+ items.push({
3787
+ person,
3788
+ mode: "truncate",
3789
+ availableNameWidth
3790
+ });
3791
+ }
3792
+ break;
3793
+ }
3794
+ const hasMore = items.length < value.length;
3795
+ let x = 0;
3796
+ items.forEach((item) => {
3797
+ const personGroup = renderPersonItem(item, x, height, functionalFontSize, functionalColor, table, {
3798
+ row,
3799
+ col,
3800
+ width,
3801
+ height
3802
+ });
3803
+ group.add(personGroup);
3804
+ const nameW = item.mode === "full" ? getTextWidth(getName(item.person.id, item.person?.name ?? ""), functionalFontSize) : item.availableNameWidth ?? 0;
3805
+ x += AVATAR_SIZE + GAP + nameW + ITEM_GAP;
3806
+ });
3807
+ if (hasMore) {
3808
+ group.add(
3809
+ vrender.createText({
3810
+ x,
3811
+ y: height / 2,
3812
+ text: ELLIPSIS,
3813
+ textBaseline: "middle",
3814
+ fill: functionalColor || "#666",
3815
+ fontSize: functionalFontSize
3816
+ })
3817
+ );
3818
+ }
3819
+ return createGraphicsWithLoading(group, loading);
3820
+ };
3821
+ function renderPersonItem(item, x, containerHeight, functionalFontSize, functionalColor, table, cell) {
3822
+ const { person, mode, availableNameWidth } = item;
3823
+ const y = (containerHeight - AVATAR_SIZE) / 2;
3824
+ const g = vrender.createGroup({ x, y, height: AVATAR_SIZE });
3825
+ if (person.id == -1 || person.id == -2) {
3826
+ const avatarBg = vrender.createRect({
3827
+ width: AVATAR_SIZE,
3828
+ height: AVATAR_SIZE,
3829
+ cornerRadius: AVATAR_SIZE / 2,
3830
+ fill: person.id == -1 ? "#52c41a" : "#999"
3831
+ });
3832
+ g.add(avatarBg);
3833
+ const avatarText = vrender.createText({
3834
+ x: AVATAR_SIZE / 2,
3835
+ y: AVATAR_SIZE / 2,
3836
+ text: person.id == -1 ? "\u7CFB\u7EDF" : "\u65E0",
3837
+ textBaseline: "middle",
3838
+ textAlign: "center",
3839
+ fill: "#fff",
3840
+ fontSize: 8
3841
+ });
3842
+ g.add(avatarText);
3843
+ } else if (person.avatar) {
3844
+ const imageGraphics = vrender.createImage({
3845
+ width: AVATAR_SIZE,
3846
+ height: AVATAR_SIZE,
3847
+ image: person.avatar,
3848
+ cornerRadius: AVATAR_SIZE / 2
3849
+ });
3850
+ g.add(imageGraphics);
3851
+ } else {
3852
+ const avatarBg = vrender.createRect({
3853
+ width: AVATAR_SIZE,
3854
+ height: AVATAR_SIZE,
3855
+ cornerRadius: AVATAR_SIZE / 2,
3856
+ fill: core.getColorByStr(person.name?.slice(-2))
3857
+ });
3858
+ g.add(avatarBg);
3859
+ const avatarText = vrender.createText({
3860
+ x: AVATAR_SIZE / 2,
3861
+ y: AVATAR_SIZE / 2,
3862
+ text: (person.name?.length ?? 0) >= 2 ? person.name?.slice(-2) : person.name?.[0] ?? "?",
3863
+ textBaseline: "middle",
3864
+ textAlign: "center",
3865
+ fill: "#fff",
3866
+ fontSize: 8
3867
+ });
3868
+ g.add(avatarText);
3869
+ }
3870
+ if (table && cell && person.id !== -1 && person.id !== -2) {
3871
+ g.on("mouseenter", () => {
3872
+ const cellRect = table.getCellRelativeRect(cell.col, cell.row);
3873
+ const avatarCenterX = cellRect.left + PADDING_LEFT + x + AVATAR_SIZE / 2;
3874
+ const avatarCenterY = cellRect.top + y + AVATAR_SIZE / 2;
3875
+ initUserShowTool({
3876
+ cell: {
3877
+ row: cell.row,
3878
+ col: cell.col,
3879
+ position: { x: avatarCenterX, y: avatarCenterY },
3880
+ width: cell.width,
3881
+ height: cell.height
3882
+ },
3883
+ table,
3884
+ endEdit: () => {
3885
+ },
3886
+ id: person.id
3887
+ });
3888
+ });
3889
+ g.on("mouseleave", () => {
3890
+ clearUserShowTool();
3891
+ });
3892
+ }
3893
+ let text = getName(person.id, person.name ?? "");
3894
+ if (mode === "truncate" && availableNameWidth !== void 0 && person.id !== -1 && person.id !== -2) {
3895
+ let left = 0;
3896
+ let right = person.name?.length || 0;
3897
+ let bestLength = 0;
3898
+ while (left <= right) {
3899
+ const mid = Math.floor((left + right) / 2);
3900
+ const testText = person.name?.slice(0, mid) + ELLIPSIS;
3901
+ const testWidth = getTextWidth(testText, functionalFontSize);
3902
+ if (testWidth <= availableNameWidth) {
3903
+ bestLength = mid;
3904
+ left = mid + 1;
3905
+ } else {
3906
+ right = mid - 1;
3907
+ }
3908
+ }
3909
+ text = bestLength > 0 ? person.name?.slice(0, bestLength) + ELLIPSIS : ELLIPSIS;
3910
+ }
3911
+ g.add(
3912
+ vrender.createText({
3913
+ x: AVATAR_SIZE + GAP,
3914
+ y: AVATAR_SIZE / 2,
3915
+ text,
3916
+ textBaseline: "middle",
3917
+ fill: functionalColor,
3918
+ fontSize: functionalFontSize
3919
+ })
3920
+ );
3921
+ return g;
3922
+ }
3923
+
3924
+ const TAG_HEIGHT$1 = 18;
3925
+ const CELL_PADDING$1 = 16;
3926
+ const TAG_PADDING$1 = 8;
3927
+ const TAG_MIN_WIDTH$1 = 35;
3928
+ const createSingleSelectGraphic = (props) => {
3929
+ const { table, col, row, rect } = props;
3930
+ const { height, width } = rect ?? table.getCellRect(col, row);
3931
+ const value = props.value?.value ?? [];
3932
+ const loading = !!props.value?.loading;
3933
+ const options = table.getBodyColumnDefine(col, 0).options || [];
3934
+ const valueItem = options.find((option) => option.value === value[0]?.value);
3935
+ if (!valueItem) {
3936
+ return null;
3937
+ }
3938
+ const styles = table._getCellStyle(col, row);
3939
+ const fontSize = getProp("fontSize", styles, col, row, table);
3940
+ const { item } = formatTagItem(
3941
+ valueItem,
3942
+ {
3943
+ cellWidth: width,
3944
+ blankWidth: 16,
3945
+ basePadding: CELL_PADDING$1 * 2,
3946
+ tagMinWidth: TAG_MIN_WIDTH$1,
3947
+ fontSize
3948
+ },
3949
+ table
3950
+ );
3951
+ const container = /* @__PURE__ */ React.createElement(
3952
+ vrender.VGroup,
3953
+ {
3954
+ attribute: {
3955
+ width: width - 32,
3956
+ height,
3957
+ display: "flex",
3958
+ alignItems: "center",
3959
+ alignContent: "center",
3960
+ dx: 16
3961
+ }
3962
+ },
3963
+ /* @__PURE__ */ React.createElement(
3964
+ vrender.VGroup,
3965
+ {
3966
+ key: item.value,
3967
+ attribute: {
3968
+ width: item.tagProps.width,
3969
+ height: TAG_HEIGHT$1,
3970
+ display: "flex",
3971
+ alignItems: "center",
3972
+ justifyContent: "center",
3973
+ overflow: "hidden",
3974
+ cornerRadius: TAG_HEIGHT$1 / 2 - 1,
3975
+ fill: item.tagProps.backgroundColor
3976
+ }
3977
+ },
3978
+ /* @__PURE__ */ React.createElement(
3979
+ vrender.VText,
3980
+ {
3981
+ attribute: {
3982
+ text: item.label,
3983
+ fontSize,
3984
+ fill: color.getTextColorForBackground(item.tagProps.backgroundColor || "#000000"),
3985
+ textAlign: "left",
3986
+ textBaseline: "top",
3987
+ maxLineWidth: item.tagProps.width - TAG_PADDING$1 * 2
3988
+ }
3989
+ }
3990
+ )
3991
+ )
3992
+ );
3993
+ return createGraphicsWithLoading(container, loading);
3994
+ };
3995
+
3996
+ const TAG_HEIGHT = 18;
3997
+ const CELL_PADDING = 16;
3998
+ const TAG_PADDING = 8;
3999
+ const TAG_MIN_WIDTH = 40;
4000
+ const TAG_BACKGROUND_COLOR = "#FAFAFA";
4001
+ const createTagGraphic = (props) => {
4002
+ const { table, row, col, rect } = props;
4003
+ const { height, width } = rect ?? table.getCellRect(col, row);
4004
+ const value = props.value?.value ?? "";
4005
+ const loading = !!props.value?.loading;
4006
+ const styles = table._getCellStyle(col, row);
4007
+ const fontSize = getProp("fontSize", styles, col, row, table);
4008
+ const { item } = formatTagItem(
4009
+ { label: value, value, color: TAG_BACKGROUND_COLOR },
4010
+ {
4011
+ cellWidth: width,
4012
+ blankWidth: 16,
4013
+ basePadding: CELL_PADDING * 2,
4014
+ tagMinWidth: TAG_MIN_WIDTH,
4015
+ fontSize
4016
+ },
4017
+ table
4018
+ );
4019
+ const container = /* @__PURE__ */ React.createElement(
4020
+ vrender.VGroup,
4021
+ {
4022
+ attribute: {
4023
+ width: width - 32,
4024
+ height,
4025
+ display: "flex",
4026
+ alignItems: "center",
4027
+ alignContent: "center",
4028
+ dx: 16
4029
+ }
4030
+ },
4031
+ !lodash.isNil(props.value?.value) && /* @__PURE__ */ React.createElement(
4032
+ vrender.VGroup,
4033
+ {
4034
+ key: item.value,
4035
+ attribute: {
4036
+ width: item.tagProps.width,
4037
+ height: TAG_HEIGHT,
4038
+ display: "flex",
4039
+ alignItems: "center",
4040
+ justifyContent: "center",
4041
+ overflow: "hidden",
4042
+ cornerRadius: 4,
4043
+ stroke: "#D9D9D9",
4044
+ fill: item.tagProps.backgroundColor
4045
+ }
4046
+ },
4047
+ /* @__PURE__ */ React.createElement(
4048
+ vrender.VText,
4049
+ {
4050
+ attribute: {
4051
+ text: item.label,
4052
+ fontSize,
4053
+ zIndex: 1e3,
4054
+ textAlign: "left",
4055
+ textBaseline: "top",
4056
+ fill: item.tagProps.fontColor,
4057
+ maxLineWidth: item.tagProps.width - TAG_PADDING * 2
4058
+ }
4059
+ }
4060
+ )
4061
+ )
4062
+ );
4063
+ return createGraphicsWithLoading(container, loading);
4064
+ };
4065
+
4066
+ const createTimeLenGraphics = (props) => {
4067
+ const { table, row, col, rect } = props;
4068
+ const { height, width } = rect ?? table.getCellRect(col, row);
4069
+ const padding = [5, 10];
4070
+ const loading = props.value?.loading;
4071
+ const value = props.value?.value;
4072
+ const cellStyle = table._getCellStyle(col, row);
4073
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
4074
+ const functionalColor = getProp("color", cellStyle, col, row, table);
4075
+ const time = !lodash.isNil(value) ? core.formatDuration(value) : "";
4076
+ const group = vrender.createGroup({
4077
+ width,
4078
+ height,
4079
+ display: "flex",
4080
+ flexWrap: "nowrap",
4081
+ justifyContent: "space-around",
4082
+ alignContent: "center",
4083
+ alignItems: "center"
4084
+ // 垂直居中
4085
+ });
4086
+ const text = vrender.createText({
4087
+ fontSize: functionalFontSize,
4088
+ fontFamily: "sans-serif",
4089
+ text: time,
4090
+ maxLineWidth: width - padding[1] * 2,
4091
+ boundsPadding: [5, 12, 5, 10],
4092
+ fill: functionalColor
4093
+ });
4094
+ group.add(text);
4095
+ return createGraphicsWithLoading(group, !!loading);
4096
+ };
4097
+
4098
+ const suffixToIconName = {
4099
+ // 图片类型
4100
+ png: "image-file",
4101
+ jpg: "image-file",
4102
+ jpeg: "image-file",
4103
+ bmp: "image-file",
4104
+ tif: "image-file",
4105
+ tiff: "image-file",
4106
+ heic: "image-file",
4107
+ pdf: "pdf",
4108
+ doc: "doc",
4109
+ docs: "docs",
4110
+ // 若枚举中没有 "docs",改为 "doc"
4111
+ ppt: "ppt",
4112
+ mp4: "video-file",
4113
+ mp3: "mp3",
4114
+ csv: "csv"
4115
+ };
4116
+ const createUploadDocumentGraphics = (props) => {
4117
+ const { table, row, col, rect } = props;
4118
+ const { height, width } = rect ?? table.getCellRect(col, row);
4119
+ const cellStyle = table._getCellStyle(col, row);
4120
+ const functionalFontSize = getProp("fontSize", cellStyle, col, row, table);
4121
+ const functionalColor = getProp("color", cellStyle, col, row, table);
4122
+ const headerIconSize = getIconSizeFromFont(functionalFontSize);
4123
+ const padding = [5, 10, 20];
4124
+ const value = props.value?.value ?? [];
4125
+ const loading = !!props.value?.loading;
4126
+ const getFileIconName = () => {
4127
+ if (value.length < 1) {
4128
+ return "text";
4129
+ }
4130
+ const fileNameOnly = value[0]?.name.split("/").pop() || "";
4131
+ const suffix = fileNameOnly.split(".").pop()?.toLowerCase() || "";
4132
+ return suffixToIconName[suffix] || "text";
4133
+ };
4134
+ const group = vrender.createGroup({
4135
+ width,
4136
+ height,
4137
+ display: "flex",
4138
+ flexWrap: "nowrap",
4139
+ justifyContent: "center",
4140
+ alignContent: "center",
4141
+ alignItems: "center"
4142
+ // 垂直居中
4143
+ // x: 15,
4144
+ });
4145
+ const uploadIcon = createIconGraphics("upload", { x: 0, y: 0, size: 14, color: functionalColor });
4146
+ const text = vrender.createText({
4147
+ fontSize: headerIconSize,
4148
+ fontFamily: "sans-serif",
4149
+ text: "\u70B9\u51FB\u4E0A\u4F20",
4150
+ fill: functionalColor,
4151
+ cursor: "pointer",
4152
+ // TODO padding maxLineWidth 计算优化
4153
+ maxLineWidth: width - padding[2] * 2 - uploadIcon.AABBBounds.width() - 12 - 5,
4154
+ boundsPadding: [4, 12, 5, 5],
4155
+ overflow: "hidden",
4156
+ textBaseline: "middle"
4157
+ });
4158
+ const borderGroup = vrender.createGroup({
4159
+ width: width - 30,
4160
+ height: height - 8,
4161
+ display: "flex",
4162
+ alignItems: "center",
4163
+ justifyContent: "center",
4164
+ stroke: "#D9D9D9",
4165
+ cursor: "pointer"
4166
+ });
4167
+ borderGroup.add(uploadIcon);
4168
+ borderGroup.add(text);
4169
+ borderGroup.addEventListener("click", () => {
4170
+ const columnDefine = table.getBodyColumnDefine(col, row);
4171
+ const lock = columnDefine.lock;
4172
+ const editor = getActiveEditorTable();
4173
+ if (lock || editor?.lock) return;
4174
+ const fileInput = document.createElement("input");
4175
+ fileInput.type = "file";
4176
+ fileInput.style.display = "none";
4177
+ fileInput.addEventListener("change", (e) => {
4178
+ const target = e.target;
4179
+ const files = target.files;
4180
+ if (files && files.length > 0) {
4181
+ const selectedFile = files[0];
4182
+ console.log("\u7528\u6237\u9009\u62E9\u7684\u6587\u4EF6\uFF1A", selectedFile);
4183
+ uploadFileToServer(selectedFile, col, row, props.value);
4184
+ }
4185
+ fileInput.value = "";
4186
+ });
4187
+ document.body.appendChild(fileInput);
4188
+ fileInput.click();
4189
+ setTimeout(() => {
4190
+ document.body.removeChild(fileInput);
4191
+ }, 100);
4192
+ });
4193
+ group.add(borderGroup);
4194
+ const groupname = vrender.createGroup({
4195
+ width,
4196
+ height,
4197
+ display: "flex",
4198
+ flexWrap: "nowrap",
4199
+ justifyContent: "flex-start",
4200
+ // alignContent: 'center',
4201
+ alignItems: "center",
4202
+ // 垂直居中
4203
+ x: 15
4204
+ });
4205
+ const uploadIconName = createIconGraphics(getFileIconName(), { x: 0, y: 0, size: 14, color: functionalColor });
4206
+ const textname = vrender.createText({
4207
+ fontSize: headerIconSize,
4208
+ fontFamily: "sans-serif",
4209
+ text: value.length > 0 ? value[0].name : "",
4210
+ fill: functionalColor,
4211
+ cursor: "pointer",
4212
+ maxLineWidth: width - padding[2] * 2,
4213
+ // marginLeft: 5,
4214
+ boundsPadding: [4, 12, 5, 5]
4215
+ });
4216
+ groupname.add(uploadIconName);
4217
+ groupname.add(textname);
4218
+ groupname.addEventListener("click", () => {
4219
+ const editor = getActiveEditorTable();
4220
+ if (!editor) throw new Error("\u672A\u83B7\u53D6\u5230\u8868\u683C\u7F16\u8F91\u5668\u5B9E\u4F8B");
4221
+ editor.dispatch("cell::attachment::preview", {
4222
+ editor,
4223
+ cellValue: props.value
4224
+ });
4225
+ });
4226
+ if (value.length > 0) {
4227
+ return createGraphicsWithLoading(groupname, loading);
4228
+ } else {
4229
+ return createGraphicsWithLoading(group, loading);
4230
+ }
4231
+ };
4232
+ const uploadFileToServer = async (file, col, row, originValue) => {
4233
+ const name = file.name;
4234
+ const suffix = name.split(".").pop();
4235
+ const column = getActiveEditorTable()?.getColumnDefine(col);
4236
+ let getField;
4237
+ if (column.field) {
4238
+ getField = column.field;
4239
+ }
4240
+ try {
4241
+ const editor = getActiveEditorTable();
4242
+ if (!editor) {
4243
+ throw new Error("\u672A\u83B7\u53D6\u5230\u8868\u683C\u7F16\u8F91\u5668\u5B9E\u4F8B");
4244
+ }
4245
+ const path = `dataset/base/table/upload/${getField}/${id.getUUID()}.${suffix}`;
4246
+ editor.updateCellData(col, row, {
4247
+ loading: true
4248
+ });
4249
+ editor.uploadFile(
4250
+ {
4251
+ file,
4252
+ // 注意:需确保 formData 是后端/编辑器要求的文件类型(如 Blob、File、FormData 等)
4253
+ type: file.type
4254
+ // 类型标识,根据业务传如 'image'/'video'/'file' 等
4255
+ },
4256
+ path
4257
+ ).then(() => {
4258
+ console.log("\u4E0A\u4F20\u6210\u529F\uFF01\uFF01");
4259
+ const tableEditor = getActiveEditorTable();
4260
+ if (!tableEditor) throw new Error("[createUploadFileGraphics::onEnd] tableEditor is Nil");
4261
+ const run = () => {
4262
+ const oldData = { ...originValue, loading: false };
4263
+ const { columnId, recordId } = tableEditor.getInteractiveCell(col, row);
4264
+ const data = {
4265
+ ...oldData,
4266
+ loading: false,
4267
+ value: [{ name, path }]
4268
+ };
4269
+ tableEditor.updateCellData(col, row, data);
4270
+ tableEditor.dispatch("cells::update", {
4271
+ editor: tableEditor,
4272
+ data: [
4273
+ {
4274
+ current: data,
4275
+ previous: oldData,
4276
+ recordId,
4277
+ columnId
4278
+ }
4279
+ ]
4280
+ });
4281
+ return {
4282
+ restore: () => {
4283
+ tableEditor.updateCellData(col, row, oldData);
4284
+ tableEditor.dispatch("cells::update", {
4285
+ editor: tableEditor,
4286
+ data: [
4287
+ {
4288
+ current: oldData,
4289
+ previous: data,
4290
+ recordId,
4291
+ columnId
4292
+ }
4293
+ ]
4294
+ });
4295
+ }
4296
+ };
4297
+ };
4298
+ const command = new EditTableCellDataFunctionalCommand(tableEditor, run);
4299
+ tableEditor.commandManager.execute(command);
4300
+ }).catch((e) => {
4301
+ console.log(e);
4302
+ });
4303
+ } catch (error) {
4304
+ console.error("\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF1A", error);
4305
+ }
4306
+ };
4307
+
4308
+ exports.BaseTableInteractive = BaseTableInteractive;
4309
+ exports.CellContextMenu = CellContextMenu;
4310
+ exports.DateSelect = DateSelect;
4311
+ exports.DateSelectEditorTool = DateSelectEditorTool;
4312
+ exports.EditTableCellDataCommand = EditTableCellDataCommand;
4313
+ exports.EditTableCellDataFunctionalCommand = EditTableCellDataFunctionalCommand;
4314
+ exports.HeaderContextMenu = HeaderContextMenu;
4315
+ exports.INNER_TABLE_COLUMN_KEY_CHECKBOX = INNER_TABLE_COLUMN_KEY_CHECKBOX;
4316
+ exports.INNER_TABLE_COLUMN_KEY_LIST = INNER_TABLE_COLUMN_KEY_LIST;
4317
+ exports.INNER_TABLE_COLUMN_KEY_PLUS = INNER_TABLE_COLUMN_KEY_PLUS;
4318
+ exports.INNER_TABLE_RECORD_ID_KEY = INNER_TABLE_RECORD_ID_KEY;
4319
+ exports.JsonEditorTool = JsonEditorTool;
4320
+ exports.LinkEditor = LinkEditor;
4321
+ exports.LinkEditorTool = LinkEditorTool;
4322
+ exports.MenuItemInputLabel = MenuItemInputLabel;
4323
+ exports.MoreContextMenu = MoreContextMenu;
4324
+ exports.MultiSelectEditorTool = MultiSelectEditorTool;
4325
+ exports.NumEditor = NumEditor;
4326
+ exports.NumEditorTool = NumEditorTool;
4327
+ exports.RecordsManager = RecordsManager;
4328
+ exports.SelectEditor = SelectEditor;
4329
+ exports.SingleSelectEditorTool = SingleSelectEditorTool;
4330
+ exports.Table = Table;
4331
+ exports.TableChangeEvent = TableChangeEvent;
4332
+ exports.TableEditor = TableEditor;
4333
+ exports.TableEditorEvent = TableEditorEvent;
4334
+ exports.TableJsonEditor = TableJsonEditor;
4335
+ exports.TableLayout = TableLayout;
4336
+ exports.TableSelectEditor = TableSelectEditor;
4337
+ exports.TableView = TableView;
4338
+ exports.TextEditor = TextEditor;
4339
+ exports.TextEditorTool = TextEditorTool;
4340
+ exports.UserShow = UserShow;
4341
+ exports.VTableEditorType = VTableEditorType;
4342
+ exports.activeTableIdAtom = activeTableIdAtom;
4343
+ exports.adaptColumnStructure = adaptColumnStructure;
4344
+ exports.adaptRecordStructure = adaptRecordStructure;
4345
+ exports.adaptRecordsStructure = adaptRecordsStructure;
4346
+ exports.adaptedCellPosition = adaptedCellPosition;
4347
+ exports.attachmentColumnCreator = attachmentColumnCreator;
4348
+ exports.checkboxColumnCreator = checkboxColumnCreator;
4349
+ exports.clearDateEditorTool = clearDateEditorTool;
4350
+ exports.clearEditorTool = clearEditorTool;
4351
+ exports.clearJsonEditorTool = clearJsonEditorTool;
4352
+ exports.clearLinkEditorTool = clearLinkEditorTool;
4353
+ exports.clearNumEditorTool = clearNumEditorTool;
4354
+ exports.clearSelectEditorTool = clearSelectEditorTool;
4355
+ exports.clearTextEditorTool = clearTextEditorTool;
4356
+ exports.clearUserShowTool = clearUserShowTool;
4357
+ exports.createBaseTableEditor = createBaseTableEditor;
4358
+ exports.createColumns = createColumns;
4359
+ exports.createDateGraphics = createDateGraphics;
4360
+ exports.createDefaultColumnConfig = createDefaultColumnConfig;
4361
+ exports.createGraphicsWithLoading = createGraphicsWithLoading;
4362
+ exports.createHeaderGraphics = createHeaderGraphics;
4363
+ exports.createIconGraphics = createIconGraphics;
4364
+ exports.createJsonGraphics = createJsonGraphics;
4365
+ exports.createLinkGraphics = createLinkGraphics;
4366
+ exports.createMainColumnCellGraphics = createMainColumnCellGraphics;
4367
+ exports.createMoreGraphics = createMoreGraphics;
4368
+ exports.createMultiSelectGraphic = createMultiSelectGraphic;
4369
+ exports.createNumberGraphics = createNumberGraphics;
4370
+ exports.createPeopleGraphics = createPeopleGraphics;
4371
+ exports.createPlusHeaderGraphics = createPlusHeaderGraphics;
4372
+ exports.createSingleSelectGraphic = createSingleSelectGraphic;
4373
+ exports.createTagGraphic = createTagGraphic;
4374
+ exports.createTextGraphics = createTextGraphics;
4375
+ exports.createTimeLenGraphics = createTimeLenGraphics;
4376
+ exports.createUploadDocumentGraphics = createUploadDocumentGraphics;
4377
+ exports.dateColumnCreator = dateColumnCreator;
4378
+ exports.dateProcess = dateProcess;
4379
+ exports.dropdownColumnCreator = dropdownColumnCreator;
4380
+ exports.editorRegistry = editorRegistry;
4381
+ exports.editorTableStoreAtom = editorTableStoreAtom;
4382
+ exports.getActiveEditorTable = getActiveEditorTable;
4383
+ exports.getActiveTableId = getActiveTableId;
4384
+ exports.getColFromColIndex = getColFromColIndex;
4385
+ exports.getDateEditorData = getDateEditorData;
4386
+ exports.getDateEditorValue = getDateEditorValue;
4387
+ exports.getEditorByToolType = getEditorByToolType;
4388
+ exports.getEditorTableStore = getEditorTableStore;
4389
+ exports.getFunctionalProp = getFunctionalProp;
4390
+ exports.getIconSizeFromFont = getIconSizeFromFont;
4391
+ exports.getJsonEditorData = getJsonEditorData;
4392
+ exports.getJsonEditorValue = getJsonEditorValue;
4393
+ exports.getLinkEditorData = getLinkEditorData;
4394
+ exports.getLinkEditorValue = getLinkEditorValue;
4395
+ exports.getMenu = getMenu;
4396
+ exports.getNumEditorData = getNumEditorData;
4397
+ exports.getNumEditorValue = getNumEditorValue;
4398
+ exports.getProp = getProp;
4399
+ exports.getRowFromRowIndex = getRowFromRowIndex;
4400
+ exports.getSelectEditorData = getSelectEditorData;
4401
+ exports.getSelectEditorValue = getSelectEditorValue;
4402
+ exports.getTextEditorData = getTextEditorData;
4403
+ exports.getTextEditorValue = getTextEditorValue;
4404
+ exports.getTextWidth = getTextWidth;
4405
+ exports.getUserShowData = getUserShowData;
4406
+ exports.getUserShowId = getUserShowId;
4407
+ exports.highlightMerge = highlightMerge;
4408
+ exports.initDateEditorTool = initDateEditorTool;
4409
+ exports.initEditorTool = initEditorTool;
4410
+ exports.initJsonEditorTool = initJsonEditorTool;
4411
+ exports.initLinkEditorTool = initLinkEditorTool;
4412
+ exports.initNumEditorTool = initNumEditorTool;
4413
+ exports.initSelectEditorTool = initSelectEditorTool;
4414
+ exports.initTextEditorTool = initTextEditorTool;
4415
+ exports.initUserShowTool = initUserShowTool;
4416
+ exports.isColumnEditable = isColumnEditable;
4417
+ exports.jsonColumnCreator = jsonColumnCreator;
4418
+ exports.linkColumnCreator = linkColumnCreator;
4419
+ exports.moreColumnCreator = moreColumnCreator;
4420
+ exports.multiSelectColumnCreator = multiSelectColumnCreator;
4421
+ exports.numberColumnCreator = numberColumnCreator;
4422
+ exports.plusColumnCreator = plusColumnCreator;
4423
+ exports.revertRecordStructure = revertRecordStructure;
4424
+ exports.setActiveEditorTable = setActiveEditorTable;
4425
+ exports.setActiveTableId = setActiveTableId;
4426
+ exports.setDateEditorData = setDateEditorData;
4427
+ exports.setDateEditorValue = setDateEditorValue;
4428
+ exports.setEditorTableStore = setEditorTableStore;
4429
+ exports.setJsonEditorData = setJsonEditorData;
4430
+ exports.setJsonEditorValue = setJsonEditorValue;
4431
+ exports.setLinkEditorData = setLinkEditorData;
4432
+ exports.setLinkEditorValue = setLinkEditorValue;
4433
+ exports.setMenu = setMenu;
4434
+ exports.setNumEditorData = setNumEditorData;
4435
+ exports.setNumEditorValue = setNumEditorValue;
4436
+ exports.setSelectEditorData = setSelectEditorData;
4437
+ exports.setSelectEditorValue = setSelectEditorValue;
4438
+ exports.setTextEditorData = setTextEditorData;
4439
+ exports.setTextEditorValue = setTextEditorValue;
4440
+ exports.setUserShowData = setUserShowData;
4441
+ exports.setUserShowId = setUserShowId;
4442
+ exports.tagColumnCreator = tagColumnCreator;
4443
+ exports.theme = theme;
4444
+ exports.timeLenColumnCreator = timeLenColumnCreator;
4445
+ exports.updateSelectEditorCell = updateSelectEditorCell;
4446
+ exports.useActiveEditorTable = useActiveEditorTable;
4447
+ exports.useActiveTableId = useActiveTableId;
4448
+ exports.useComponentVTable = useComponentVTable;
4449
+ exports.useDateEditorData = useDateEditorData;
4450
+ exports.useDateEditorValue = useDateEditorValue;
4451
+ exports.useEditorTableStore = useEditorTableStore;
4452
+ exports.useJsonEditorData = useJsonEditorData;
4453
+ exports.useJsonEditorValue = useJsonEditorValue;
4454
+ exports.useLinkEditorData = useLinkEditorData;
4455
+ exports.useLinkEditorValue = useLinkEditorValue;
4456
+ exports.useMenu = useMenu;
4457
+ exports.useNumEditorData = useNumEditorData;
4458
+ exports.useNumEditorValue = useNumEditorValue;
4459
+ exports.useSelectEditorData = useSelectEditorData;
4460
+ exports.useSelectEditorValue = useSelectEditorValue;
4461
+ exports.useTextEditorData = useTextEditorData;
4462
+ exports.useTextEditorValue = useTextEditorValue;
4463
+ exports.useUserShowData = useUserShowData;
4464
+ exports.useUserShowId = useUserShowId;
4465
+ exports.userColumnCreator = userColumnCreator;