@sl-material/sl-table-sheet 1.0.0-beta0

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,2499 @@
1
+ var O = Object.defineProperty;
2
+ var L = (c, e, t) => e in c ? O(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
3
+ var u = (c, e, t) => L(c, typeof e != "symbol" ? e + "" : e, t);
4
+ import * as b from "xlsx";
5
+ import * as y from "@visactor/vtable-sheet";
6
+ import * as E from "@visactor/vtable-editors";
7
+ class k {
8
+ /**
9
+ * 检测表头行数
10
+ */
11
+ static detectHeaderRows(e, t) {
12
+ let n = 1;
13
+ t !== void 0 ? n = t : n = this.autoDetectHeaderRows(e);
14
+ const o = e.slice(0, n), s = this.filterTitleRows(o);
15
+ return {
16
+ headerRows: n,
17
+ dataStartRow: n,
18
+ effectiveHeaderRows: s
19
+ };
20
+ }
21
+ /**
22
+ * 自动检测表头行数
23
+ */
24
+ static autoDetectHeaderRows(e) {
25
+ const t = Math.min(5, e.length);
26
+ let n = 1;
27
+ const o = e[0] || [], s = e[1] || [], l = this.getNonEmptyCells(o), i = this.getNonEmptyCells(s), a = this.isTitleRow(l), d = this.isHeaderRow(i);
28
+ if (a && d)
29
+ return 2;
30
+ if (d && !a)
31
+ return 1;
32
+ for (let r = 0; r < t - 1; r++) {
33
+ const h = e[r] || [], p = this.getNonEmptyCells(h), f = this.isTitleRow(p), m = this.isHeaderRow(p), g = this.isDataRow(p);
34
+ if (f && m)
35
+ n = Math.max(n, r + 2);
36
+ else if (m && !g && r < t - 2) {
37
+ const v = e[r + 2] || [], w = this.getNonEmptyCells(v);
38
+ this.isDataRow(w) || (n = Math.max(n, r + 2));
39
+ }
40
+ }
41
+ return n;
42
+ }
43
+ /**
44
+ * 过滤标题行,只保留表头行
45
+ */
46
+ static filterTitleRows(e) {
47
+ for (let t = 0; t < e.length; t++) {
48
+ const n = e[t], o = this.getNonEmptyCells(n);
49
+ if (o.length === 1 && o[0].length > 20)
50
+ return e.slice(t + 1);
51
+ }
52
+ return e;
53
+ }
54
+ /**
55
+ * 获取非空单元格
56
+ */
57
+ static getNonEmptyCells(e) {
58
+ return e.filter((t) => String(t || "").trim() !== "");
59
+ }
60
+ /**
61
+ * 判断是否为标题行
62
+ */
63
+ static isTitleRow(e) {
64
+ return e.length === 1 && e[0].length > 20;
65
+ }
66
+ /**
67
+ * 判断是否为表头行
68
+ */
69
+ static isHeaderRow(e) {
70
+ return e.length > 3;
71
+ }
72
+ /**
73
+ * 判断是否为数据行
74
+ */
75
+ static isDataRow(e) {
76
+ return e.length > 0 && e.some((t) => {
77
+ const n = String(t || "").trim();
78
+ return /^\d+$/.test(n) || /^\d{4}-\d{1,2}-\d{1,2}/.test(n) || n.length <= 10;
79
+ });
80
+ }
81
+ /**
82
+ * 合并多层表头
83
+ */
84
+ static mergeHeaders(e, t) {
85
+ const n = [];
86
+ for (let o = 0; o < t; o++) {
87
+ const s = [];
88
+ let l = !1;
89
+ for (let i = e.length - 1; i >= 0; i--) {
90
+ const a = e[i][o], d = String(a || "").trim();
91
+ d !== "" ? l || s.unshift(d) : l = !0;
92
+ }
93
+ n.push(
94
+ s.length > 0 ? s.join(" - ") : `列${o + 1}`
95
+ );
96
+ }
97
+ return n;
98
+ }
99
+ }
100
+ function T(c) {
101
+ if (c) {
102
+ if (c.length === 8)
103
+ return "#" + c.substring(2);
104
+ if (c.length === 6)
105
+ return "#" + c;
106
+ }
107
+ }
108
+ function $(c, e) {
109
+ return {
110
+ 0: "#FFFFFF",
111
+ 1: "#000000",
112
+ 2: "#E7E6E6",
113
+ 3: "#44546A",
114
+ 4: "#4472C4",
115
+ 5: "#ED7D31",
116
+ 6: "#A5A5A5",
117
+ 7: "#FFC000",
118
+ 8: "#5B9BD5",
119
+ 9: "#70AD47"
120
+ }[c];
121
+ }
122
+ function x(c) {
123
+ if (c) {
124
+ if (c.rgb)
125
+ return T(c.rgb);
126
+ if (c.argb)
127
+ return T(c.argb);
128
+ if (c.theme !== void 0)
129
+ return $(c.theme, c.tint);
130
+ if (c.indexed !== void 0)
131
+ return {
132
+ 64: "#000000",
133
+ 65: "#FFFFFF",
134
+ 8: "#000000",
135
+ 9: "#FFFFFF",
136
+ 10: "#FF0000",
137
+ 11: "#00FF00",
138
+ 12: "#0000FF",
139
+ 13: "#FFFF00",
140
+ 14: "#FF00FF",
141
+ 15: "#00FFFF"
142
+ }[c.indexed];
143
+ }
144
+ }
145
+ class A {
146
+ /**
147
+ * 提取单元格样式
148
+ */
149
+ static extractStyles(e, t, n) {
150
+ const o = /* @__PURE__ */ new Map(), s = t.Styles;
151
+ if (!s)
152
+ return;
153
+ const l = s.Fonts || [], i = s.Fills || [], a = s.CellXf || [], d = b.utils.decode_range(e["!ref"] || "A1");
154
+ for (let r = n; r <= d.e.r; r++)
155
+ for (let h = d.s.c; h <= d.e.c; h++) {
156
+ const p = b.utils.encode_cell({ r, c: h }), f = e[p];
157
+ if ((f == null ? void 0 : f.s) !== void 0) {
158
+ const m = this.extractCellStyle(f, l, i, a);
159
+ if (m && this.hasNonDefaultStyle(m)) {
160
+ const g = r - n;
161
+ o.set(`${g}-${h}`, m);
162
+ }
163
+ }
164
+ }
165
+ return o.size > 0 ? o : void 0;
166
+ }
167
+ /**
168
+ * 提取单个单元格样式
169
+ */
170
+ static extractCellStyle(e, t, n, o) {
171
+ var d;
172
+ const s = {};
173
+ let l = null, i, a;
174
+ if (typeof e.s == "number")
175
+ l = o[e.s], i = (l == null ? void 0 : l.fontId) ?? (l == null ? void 0 : l.fontid), a = (l == null ? void 0 : l.fillId) ?? (l == null ? void 0 : l.fillid);
176
+ else if (typeof e.s == "object" && (l = e.s, i = l.fontId ?? l.fontid, a = l.fillId ?? l.fillid, l.patternType === "solid")) {
177
+ if (l.fgColor && Object.keys(l.fgColor).length > 0) {
178
+ const r = x(l.fgColor);
179
+ r && (s.bgColor = r);
180
+ }
181
+ if (!s.bgColor && ((d = l.bgColor) == null ? void 0 : d.indexed) !== void 0) {
182
+ const r = x(l.bgColor);
183
+ r && (s.bgColor = r);
184
+ }
185
+ }
186
+ return l && (this.extractFontStyle(s, i, t), this.extractFillStyle(s, a, n)), s;
187
+ }
188
+ /**
189
+ * 提取字体样式
190
+ */
191
+ static extractFontStyle(e, t, n) {
192
+ if (t !== void 0 && n[t]) {
193
+ const o = n[t];
194
+ if (o.color) {
195
+ const s = x(o.color);
196
+ s && s !== "#000000" && (e.fontColor = s);
197
+ }
198
+ o.bold && (e.bold = !0), o.italic && (e.italic = !0);
199
+ }
200
+ }
201
+ /**
202
+ * 提取填充样式
203
+ */
204
+ static extractFillStyle(e, t, n) {
205
+ if (t !== void 0 && n[t]) {
206
+ const o = n[t];
207
+ if (o.patternType === "solid" && o.fgColor) {
208
+ const s = x(o.fgColor);
209
+ s && (e.bgColor = s);
210
+ }
211
+ }
212
+ }
213
+ /**
214
+ * 检查是否有非默认样式
215
+ */
216
+ static hasNonDefaultStyle(e) {
217
+ return !!(e.fontColor || e.bgColor || e.bold || e.italic);
218
+ }
219
+ }
220
+ class B {
221
+ /**
222
+ * 提取批注数据
223
+ */
224
+ static extractComments(e, t) {
225
+ const n = /* @__PURE__ */ new Map();
226
+ return this.collectComments(e).forEach((s) => {
227
+ const l = b.utils.decode_cell(s.r), i = l.r - t, a = l.c;
228
+ if (i >= 0) {
229
+ const d = `${i}-${a}`, r = this.cleanCommentText(s.t, s.a);
230
+ n.set(d, {
231
+ text: r,
232
+ author: s.a
233
+ });
234
+ }
235
+ }), n.size > 0 ? n : void 0;
236
+ }
237
+ /**
238
+ * 收集所有批注
239
+ */
240
+ static collectComments(e) {
241
+ let t = [];
242
+ return e["!comments"] && (t = e["!comments"]), t.length === 0 && (t = this.extractCommentsFromCells(e)), t;
243
+ }
244
+ /**
245
+ * 从单元格中提取批注
246
+ */
247
+ static extractCommentsFromCells(e) {
248
+ const t = [];
249
+ return Object.keys(e).forEach((n) => {
250
+ if (!n.startsWith("!")) {
251
+ const o = e[n];
252
+ o != null && o.c && Array.isArray(o.c) && o.c.forEach((s) => {
253
+ const l = s.t || (s.r && typeof s.r == "string" ? s.r : "");
254
+ l && t.push({
255
+ r: n,
256
+ t: l,
257
+ a: s.a
258
+ });
259
+ });
260
+ }
261
+ }), t;
262
+ }
263
+ /**
264
+ * 清理批注文本
265
+ */
266
+ static cleanCommentText(e, t) {
267
+ let n = e;
268
+ return t && n.startsWith(t + ":") && (n = n.substring(t.length + 1).trim(), n.startsWith(`
269
+ `) && (n = n.substring(1))), n;
270
+ }
271
+ }
272
+ class V {
273
+ /**
274
+ * 解析 Excel ArrayBuffer
275
+ */
276
+ static parseBuffer(e, t = {}) {
277
+ const {
278
+ sheetIndex: n = 0,
279
+ headerRow: o = 0,
280
+ headerRows: s,
281
+ mergeHeaders: l = !0,
282
+ extractStyles: i = !0,
283
+ extractComments: a = !0
284
+ } = t, d = b.read(e, {
285
+ type: "array",
286
+ cellStyles: !0,
287
+ cellNF: !0
288
+ }), r = d.SheetNames;
289
+ if (n >= r.length)
290
+ throw new Error(
291
+ `Sheet index ${n} out of range. Available sheets: ${r.length}`
292
+ );
293
+ const h = d.Sheets[r[n]], p = b.utils.sheet_to_json(h, {
294
+ header: 1,
295
+ defval: ""
296
+ });
297
+ if (p.length === 0)
298
+ return { columns: [], records: [] };
299
+ const { headerRows: f, dataStartRow: m, effectiveHeaderRows: g } = k.detectHeaderRows(
300
+ p.slice(o),
301
+ s
302
+ ), v = this.buildColumns(
303
+ p,
304
+ o,
305
+ f,
306
+ g,
307
+ l
308
+ ), w = p.slice(o + m), I = i ? A.extractStyles(
309
+ h,
310
+ d,
311
+ o + m
312
+ ) : void 0, N = a ? B.extractComments(h, o + m) : void 0;
313
+ return { columns: v, records: w, cellStyles: I, cellComments: N };
314
+ }
315
+ /**
316
+ * 构建列配置
317
+ */
318
+ static buildColumns(e, t, n, o, s) {
319
+ if (s && n > 1) {
320
+ const i = e.slice(t, t + n), a = Math.max(...i.map((r) => r.length));
321
+ return k.mergeHeaders(o, a).map((r, h) => ({
322
+ key: `col_${h}`,
323
+ field: `col_${h}`,
324
+ title: r,
325
+ width: 120,
326
+ sort: !1,
327
+ filter: !1
328
+ }));
329
+ }
330
+ return (e[t] || []).map((i, a) => ({
331
+ key: `col_${a}`,
332
+ field: `col_${a}`,
333
+ title: String(i || `Column ${a + 1}`),
334
+ width: 120,
335
+ sort: !1,
336
+ filter: !1
337
+ }));
338
+ }
339
+ }
340
+ class D {
341
+ /**
342
+ * 导出为 Excel 流
343
+ */
344
+ static exportToStream(e, t, n) {
345
+ const { filterEmptyColumns: o = !0 } = n || {}, s = o ? this.filterEmptyColumns(e) : e, l = s.map((h) => h.title || h.field || ""), i = this.buildDataRows(t, e, s), a = [l, ...i], d = b.utils.aoa_to_sheet(a), r = b.utils.book_new();
346
+ return b.utils.book_append_sheet(r, d, "Sheet1"), b.write(r, { bookType: "xlsx", type: "array" });
347
+ }
348
+ /**
349
+ * 下载 Excel 文件
350
+ */
351
+ static download(e, t = "export") {
352
+ const n = new Blob([e], {
353
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
354
+ }), o = URL.createObjectURL(n), s = document.createElement("a");
355
+ s.href = o, s.download = `${t}.xlsx`, document.body.appendChild(s), s.click(), document.body.removeChild(s), URL.revokeObjectURL(o);
356
+ }
357
+ /**
358
+ * 过滤空列
359
+ */
360
+ static filterEmptyColumns(e) {
361
+ return e.filter((t) => {
362
+ const n = t.title || t.field || "";
363
+ return n && typeof n == "string" && n.trim() !== "";
364
+ });
365
+ }
366
+ /**
367
+ * 构建数据行
368
+ */
369
+ static buildDataRows(e, t, n) {
370
+ return e.map((o) => Array.isArray(o) ? n.map((s) => {
371
+ const l = t.indexOf(s);
372
+ if (l >= 0 && l < o.length) {
373
+ const i = o[l];
374
+ return this.extractCellValue(i);
375
+ }
376
+ return "";
377
+ }) : n.map((s) => {
378
+ const l = s.field || s.key, i = l ? o[l] : void 0;
379
+ return this.extractCellValue(i);
380
+ }));
381
+ }
382
+ /**
383
+ * 提取单元格值
384
+ */
385
+ static extractCellValue(e) {
386
+ return e && typeof e == "object" && "value" in e ? e.value : e;
387
+ }
388
+ }
389
+ async function j(c) {
390
+ const e = await fetch(c);
391
+ if (!e.ok)
392
+ throw new Error(`Failed to fetch Excel file: ${e.statusText}`);
393
+ return e.arrayBuffer();
394
+ }
395
+ function S(c, e = {}) {
396
+ return V.parseBuffer(c, e);
397
+ }
398
+ async function H(c, e = {}) {
399
+ const t = await j(c);
400
+ return S(t, e);
401
+ }
402
+ async function _(c, e = {}) {
403
+ const t = await K(c);
404
+ return S(t, e);
405
+ }
406
+ function P(c, e, t) {
407
+ return D.exportToStream(c, e, t);
408
+ }
409
+ function q(c, e = "export") {
410
+ D.download(c, e);
411
+ }
412
+ function K(c) {
413
+ return new Promise((e, t) => {
414
+ const n = new FileReader();
415
+ n.onload = (o) => {
416
+ var l;
417
+ const s = (l = o.target) == null ? void 0 : l.result;
418
+ e(s);
419
+ }, n.onerror = () => t(new Error("Failed to read file")), n.readAsArrayBuffer(c);
420
+ });
421
+ }
422
+ class U {
423
+ constructor(e, t) {
424
+ u(this, "customComponentContainers", /* @__PURE__ */ new Map());
425
+ u(this, "activeComponentKey", null);
426
+ u(this, "justCreatedComponent", !1);
427
+ u(this, "tableInstance", null);
428
+ u(this, "container", null);
429
+ /**
430
+ * 处理点击表格外部
431
+ */
432
+ u(this, "handleOutsideClick", (e) => {
433
+ if (this.justCreatedComponent || !this.activeComponentKey) return;
434
+ const t = this.customComponentContainers.get(
435
+ this.activeComponentKey
436
+ );
437
+ t && !t.contains(e.target) && this.closeActiveComponent();
438
+ });
439
+ this.tableInstance = e, this.container = t, this.bindOutsideClickHandler();
440
+ }
441
+ /**
442
+ * 显示自定义组件
443
+ */
444
+ showComponent(e, t, n) {
445
+ var m;
446
+ const { col: o, row: s } = n, l = this.tableInstance.getCellRect(o, s), i = this.tableInstance.getCellValue(o, s), a = (m = this.container) == null ? void 0 : m.getBoundingClientRect(), d = ((a == null ? void 0 : a.left) || 0) + l.left, r = ((a == null ? void 0 : a.top) || 0) + l.bottom, h = this.createComponentContainer(
447
+ d,
448
+ r,
449
+ t
450
+ ), p = {
451
+ table: this.tableInstance,
452
+ row: s,
453
+ col: o,
454
+ value: i,
455
+ dataValue: n.dataValue,
456
+ rect: l,
457
+ setValue: (g) => {
458
+ this.tableInstance.changeCellValue(o, s, g), this.closeActiveComponent();
459
+ },
460
+ close: () => {
461
+ this.closeActiveComponent();
462
+ }
463
+ };
464
+ try {
465
+ const g = t.render(p);
466
+ h.appendChild(g), document.body.appendChild(h);
467
+ } catch (g) {
468
+ console.error("❌ 渲染组件时出错:", g);
469
+ return;
470
+ }
471
+ const f = `${e}-${o}-${s}`;
472
+ this.customComponentContainers.set(f, h), this.activeComponentKey = f, t.onMount && t.onMount(h, p), h.addEventListener("click", (g) => {
473
+ g.stopPropagation();
474
+ }), this.justCreatedComponent = !0, setTimeout(() => {
475
+ this.justCreatedComponent = !1;
476
+ }, 100);
477
+ }
478
+ /**
479
+ * 创建组件容器
480
+ */
481
+ createComponentContainer(e, t, n) {
482
+ const o = document.createElement("div");
483
+ return o.className = "vtable-custom-component", o.style.position = "fixed", o.style.zIndex = "9999", o.style.left = `${e}px`, o.style.top = `${t}px`, o.style.backgroundColor = "white", o.style.borderRadius = "4px", o.style.boxShadow = "0 2px 12px rgba(0, 0, 0, 0.15)", n.containerStyle && Object.assign(o.style, n.containerStyle), o;
484
+ }
485
+ /**
486
+ * 关闭当前激活的组件
487
+ */
488
+ closeActiveComponent() {
489
+ if (!this.activeComponentKey) return;
490
+ const e = this.customComponentContainers.get(
491
+ this.activeComponentKey
492
+ );
493
+ e && (e.remove(), this.customComponentContainers.delete(this.activeComponentKey)), this.activeComponentKey = null;
494
+ }
495
+ /**
496
+ * 绑定外部点击处理
497
+ */
498
+ bindOutsideClickHandler() {
499
+ document.addEventListener("click", this.handleOutsideClick);
500
+ }
501
+ /**
502
+ * 销毁管理器
503
+ */
504
+ destroy() {
505
+ this.closeActiveComponent(), this.customComponentContainers.clear(), document.removeEventListener("click", this.handleOutsideClick);
506
+ }
507
+ }
508
+ class R {
509
+ constructor(e, t) {
510
+ u(this, "markedMap", null);
511
+ u(this, "tableInstance", null);
512
+ this.tableInstance = e, this.markedMap = t || null;
513
+ }
514
+ /**
515
+ * 处理单元格鼠标进入事件
516
+ */
517
+ handleCellMouseEnter(e) {
518
+ const { col: t, row: n } = e, o = this.tableInstance.columnHeaderLevelCount || 1, s = n - o, l = `${s}-${t}`;
519
+ this.markedMap && this.markedMap.has(l) && s >= 0 && this.showTooltip(t, n, l);
520
+ }
521
+ /**
522
+ * 显示 tooltip
523
+ */
524
+ showTooltip(e, t, n) {
525
+ const o = this.tableInstance.getVisibleCellRangeRelativeRect({
526
+ col: e,
527
+ row: t
528
+ }), s = this.markedMap.get(n), l = this.tableInstance.getCellValue(e, t);
529
+ let i = `${l}`;
530
+ if (s && typeof s == "object" && "comment" in s) {
531
+ const a = s.comment;
532
+ a && (i = `${l}: ${a}`);
533
+ }
534
+ this.tableInstance.showTooltip(e, t, {
535
+ content: i,
536
+ referencePosition: {
537
+ rect: o,
538
+ placement: "right"
539
+ },
540
+ className: "defineTooltip",
541
+ disappearDelay: 100,
542
+ style: {
543
+ bgColor: "black",
544
+ color: "white",
545
+ font: "normal bold normal 14px/1 STKaiti",
546
+ arrowMark: !0,
547
+ padding: [12]
548
+ }
549
+ });
550
+ }
551
+ /**
552
+ * 获取标记映射
553
+ */
554
+ getMarkedMap() {
555
+ return this.markedMap;
556
+ }
557
+ /**
558
+ * 设置标记映射
559
+ */
560
+ setMarkedMap(e) {
561
+ this.markedMap = e;
562
+ }
563
+ }
564
+ class W {
565
+ /**
566
+ * 注册编辑器
567
+ */
568
+ static registerEditors(e) {
569
+ if (e) {
570
+ if (e.dateEditor !== !1) {
571
+ const t = new E.DateInputEditor(
572
+ e.dateEditor || {}
573
+ );
574
+ y.VTable.register.editor("dateEditor", t);
575
+ }
576
+ if (e.listEditor) {
577
+ const t = new E.ListEditor(
578
+ e.listEditor || {
579
+ values: ["技术中心", "财务部"]
580
+ }
581
+ );
582
+ y.VTable.register.editor("listEditor", t);
583
+ }
584
+ e.customEditors && Object.entries(e.customEditors).forEach(([t, n]) => {
585
+ y.VTable.register.editor(t, n);
586
+ });
587
+ }
588
+ }
589
+ }
590
+ class X {
591
+ constructor(e, t, n) {
592
+ u(this, "tableInstance");
593
+ u(this, "config");
594
+ u(this, "customComponentManager", null);
595
+ u(this, "cellMarkManager", null);
596
+ this.config = e, this.tableInstance = e.tableInstance, this.customComponentManager = t, this.cellMarkManager = n;
597
+ }
598
+ /**
599
+ * 绑定所有事件
600
+ */
601
+ bindEvents() {
602
+ this.tableInstance && (this.tableInstance.on("click_cell", (e) => {
603
+ var t, n;
604
+ this.handleCellClick(e), (n = (t = this.config).onCellClick) == null || n.call(t, e);
605
+ }), this.config.onCellChange && this.tableInstance.on("change_cell_value", this.config.onCellChange), this.tableInstance.on("mouseenter_cell", (e) => {
606
+ var t;
607
+ (t = this.cellMarkManager) == null || t.handleCellMouseEnter(e);
608
+ }));
609
+ }
610
+ /**
611
+ * 处理单元格点击
612
+ */
613
+ handleCellClick(e) {
614
+ var i, a, d;
615
+ const { col: t } = e, o = (this.config.columns || [])[t];
616
+ if (!(o != null && o.customComponent)) return;
617
+ const s = o.customComponent, l = (i = this.config.customComponents) == null ? void 0 : i[s];
618
+ l != null && l.showOnClick && ((a = this.customComponentManager) == null || a.closeActiveComponent(), (d = this.customComponentManager) == null || d.showComponent(
619
+ s,
620
+ l,
621
+ e
622
+ ));
623
+ }
624
+ /**
625
+ * 监听事件
626
+ */
627
+ on(e, t) {
628
+ var n;
629
+ (n = this.tableInstance) == null || n.on(e, t);
630
+ }
631
+ /**
632
+ * 取消监听事件
633
+ */
634
+ off(e, t) {
635
+ var n;
636
+ (n = this.tableInstance) == null || n.off(e, t);
637
+ }
638
+ }
639
+ class M {
640
+ constructor(e, t) {
641
+ u(this, "sheetInstance", null);
642
+ u(this, "tableInstance", null);
643
+ u(this, "container", null);
644
+ u(this, "config");
645
+ u(this, "customComponentManager", null);
646
+ u(this, "cellMarkManager", null);
647
+ u(this, "eventManager", null);
648
+ this.config = e, this.cellMarkManager = new R(
649
+ null,
650
+ t || void 0
651
+ ), this.init();
652
+ }
653
+ /**
654
+ * 初始化表格
655
+ */
656
+ init() {
657
+ if (this.container = this.getContainer(this.config.container), !this.container)
658
+ throw new Error("Container not found");
659
+ W.registerEditors(this.config.editors), this.createSheet();
660
+ }
661
+ /**
662
+ * 获取容器元素
663
+ */
664
+ getContainer(e) {
665
+ return typeof e == "string" ? document.getElementById(e) || document.querySelector(e) : e;
666
+ }
667
+ /**
668
+ * 创建表格实例
669
+ */
670
+ createSheet() {
671
+ var i, a;
672
+ const {
673
+ columns: e = [],
674
+ records: t = [],
675
+ showFormulaBar: n = !0,
676
+ showSheetTab: o = !0,
677
+ sheets: s,
678
+ options: l
679
+ } = this.config;
680
+ this.sheetInstance = new y.VTableSheet(this.container, {
681
+ showFormulaBar: n,
682
+ showSheetTab: o,
683
+ sheets: s || [
684
+ {
685
+ sheetKey: "sheet1",
686
+ sheetTitle: "Sheet1",
687
+ dragOrder: {
688
+ dragHeaderMode: "all"
689
+ },
690
+ columns: e,
691
+ data: t
692
+ // 限制行数和列数,避免显示过多空白行列
693
+ // rowCount: records.length, // 只显示实际数据的行数
694
+ // columnCount: columns.length, // 尝试使用 columnCount
695
+ }
696
+ ],
697
+ tooltip: {
698
+ isShowOverflowTextTooltip: !0
699
+ },
700
+ ...l
701
+ }), this.tableInstance = (i = this.sheetInstance.getActiveSheet()) == null ? void 0 : i.tableInstance, this.customComponentManager = new U(
702
+ this.tableInstance,
703
+ this.container
704
+ ), this.cellMarkManager = new R(
705
+ this.tableInstance,
706
+ ((a = this.cellMarkManager) == null ? void 0 : a.getMarkedMap()) || void 0
707
+ ), this.eventManager = new X(
708
+ {
709
+ tableInstance: this.tableInstance,
710
+ columns: this.config.columns,
711
+ customComponents: this.config.customComponents,
712
+ onCellClick: this.config.onCellClick,
713
+ onCellChange: this.config.onCellChange
714
+ },
715
+ this.customComponentManager,
716
+ this.cellMarkManager
717
+ ), this.eventManager.bindEvents();
718
+ }
719
+ /**
720
+ * 修改单元格值
721
+ */
722
+ changeCellValue(e, t, n) {
723
+ this.tableInstance && this.tableInstance.changeCellValue(e, t, n);
724
+ }
725
+ /**
726
+ * 获取单元格值
727
+ */
728
+ getCellValue(e, t) {
729
+ var n;
730
+ return (n = this.tableInstance) == null ? void 0 : n.getCellValue(e, t);
731
+ }
732
+ /**
733
+ * 获取选中的单元格
734
+ */
735
+ getSelectedCells() {
736
+ var e;
737
+ return (e = this.tableInstance) == null ? void 0 : e.getSelectedCellInfos();
738
+ }
739
+ /**
740
+ * 更新数据
741
+ */
742
+ updateData(e) {
743
+ var n;
744
+ console.log("updateData 调用:", e.length, "条记录");
745
+ const t = (n = this.sheetInstance) == null ? void 0 : n.getActiveSheet();
746
+ if (t)
747
+ if (typeof t.updateRecords == "function")
748
+ console.log("使用 updateRecords 方法"), t.updateRecords(e);
749
+ else if (typeof t.setData == "function")
750
+ console.log("使用 setData 方法"), t.setData(e);
751
+ else if (this.tableInstance)
752
+ if (typeof this.tableInstance.updateOption == "function") {
753
+ console.log("使用 tableInstance.updateOption 方法");
754
+ const o = this.tableInstance.option || {};
755
+ this.tableInstance.updateOption({
756
+ ...o,
757
+ records: e
758
+ });
759
+ } else
760
+ console.warn("无法更新数据:找不到合适的方法");
761
+ else
762
+ console.warn("无法更新数据:找不到合适的方法");
763
+ else
764
+ console.warn("无法获取活动工作表");
765
+ }
766
+ /**
767
+ * 更新列配置
768
+ */
769
+ updateColumns(e) {
770
+ var n;
771
+ console.log("updateColumns 调用:", e.length, "列");
772
+ const t = (n = this.sheetInstance) == null ? void 0 : n.getActiveSheet();
773
+ if (t)
774
+ if (typeof t.updateColumns == "function")
775
+ console.log("使用 activeSheet.updateColumns 方法"), t.updateColumns(e);
776
+ else if (typeof t.setColumns == "function")
777
+ console.log("使用 setColumns 方法"), t.setColumns(e);
778
+ else if (this.tableInstance)
779
+ if (typeof this.tableInstance.updateOption == "function") {
780
+ console.log("使用 tableInstance.updateOption 方法更新列");
781
+ const o = this.tableInstance.option || {};
782
+ this.tableInstance.updateOption({
783
+ ...o,
784
+ columns: e
785
+ });
786
+ } else
787
+ console.warn("无法更新列配置:找不到合适的方法");
788
+ else
789
+ console.warn("无法更新列配置:找不到合适的方法");
790
+ else
791
+ console.warn("无法获取活动工作表");
792
+ }
793
+ /**
794
+ * 添加行
795
+ */
796
+ addRow(e, t) {
797
+ var o;
798
+ const n = (o = this.sheetInstance) == null ? void 0 : o.getActiveSheet();
799
+ n && n.addRecord(e, t);
800
+ }
801
+ /**
802
+ * 删除行
803
+ */
804
+ deleteRow(e) {
805
+ var n;
806
+ const t = (n = this.sheetInstance) == null ? void 0 : n.getActiveSheet();
807
+ t && t.deleteRecord(e);
808
+ }
809
+ /**
810
+ * 导出数据
811
+ */
812
+ exportData(e = "csv") {
813
+ var t, n;
814
+ return (n = (t = this.sheetInstance) == null ? void 0 : t.exportData) == null ? void 0 : n.call(t, e);
815
+ }
816
+ /**
817
+ * 切换工作表
818
+ */
819
+ switchSheet(e) {
820
+ var t, n;
821
+ (t = this.sheetInstance) == null || t.switchSheet(e), this.tableInstance = (n = this.sheetInstance.getActiveSheet()) == null ? void 0 : n.tableInstance;
822
+ }
823
+ /**
824
+ * 获取当前工作表
825
+ */
826
+ getActiveSheet() {
827
+ var e;
828
+ return (e = this.sheetInstance) == null ? void 0 : e.getActiveSheet();
829
+ }
830
+ /**
831
+ * 获取所有工作表
832
+ */
833
+ getAllSheets() {
834
+ var e;
835
+ return (e = this.sheetInstance) == null ? void 0 : e.getAllSheets();
836
+ }
837
+ /**
838
+ * 刷新表格
839
+ */
840
+ refresh() {
841
+ if (this.tableInstance && this.tableInstance.option)
842
+ try {
843
+ this.tableInstance.updateOption(this.tableInstance.option);
844
+ } catch (e) {
845
+ console.warn("刷新表格失败:", e);
846
+ const t = this.tableInstance.container;
847
+ t && (t.style.display = "none", setTimeout(() => {
848
+ t.style.display = "";
849
+ }, 0));
850
+ }
851
+ }
852
+ /**
853
+ * 获取原始实例
854
+ */
855
+ getSheetInstance() {
856
+ return this.sheetInstance;
857
+ }
858
+ getTableInstance() {
859
+ return this.tableInstance;
860
+ }
861
+ /**
862
+ * 为指定列设置自定义渲染函数
863
+ * @param field 列字段名
864
+ * @param customRender 自定义渲染函数
865
+ */
866
+ setColumnCustomRender(e, t) {
867
+ var o;
868
+ const n = (o = this.sheetInstance) == null ? void 0 : o.getActiveSheet();
869
+ if (n) {
870
+ const s = n.columns || [], l = s.find((i) => i.field === e);
871
+ l && (l.customRender = t, n.updateColumns(s));
872
+ }
873
+ }
874
+ /**
875
+ * 获取标记映射
876
+ */
877
+ getMarkedMap() {
878
+ var e;
879
+ return ((e = this.cellMarkManager) == null ? void 0 : e.getMarkedMap()) || null;
880
+ }
881
+ /**
882
+ * 监听事件
883
+ */
884
+ on(e, t) {
885
+ var n;
886
+ (n = this.eventManager) == null || n.on(e, t);
887
+ }
888
+ /**
889
+ * 取消监听事件
890
+ */
891
+ off(e, t) {
892
+ var n;
893
+ (n = this.eventManager) == null || n.off(e, t);
894
+ }
895
+ /**
896
+ * 销毁实例
897
+ */
898
+ destroy() {
899
+ var e, t, n;
900
+ (e = this.customComponentManager) == null || e.destroy(), this.customComponentManager = null, this.cellMarkManager = null, this.eventManager = null, this.sheetInstance && ((n = (t = this.sheetInstance).destroy) == null || n.call(t), this.sheetInstance = null, this.tableInstance = null);
901
+ }
902
+ }
903
+ class Y {
904
+ constructor(e = {}) {
905
+ // private container: HTMLElement | null = null;
906
+ u(this, "dialog", null);
907
+ u(this, "tableInstance", null);
908
+ // DOM 元素
909
+ u(this, "elements", {});
910
+ // 状态
911
+ u(this, "state", {
912
+ findText: "",
913
+ replaceText: "",
914
+ matches: [],
915
+ currentIndex: 0
916
+ });
917
+ // 配置
918
+ u(this, "options");
919
+ this.options = e, this.tableInstance = e.tableInstance, this.init();
920
+ }
921
+ /**
922
+ * 初始化弹窗
923
+ */
924
+ init() {
925
+ this.createDialog(), this.bindEvents(), this.injectStyles();
926
+ }
927
+ /**
928
+ * 创建弹窗 DOM
929
+ */
930
+ createDialog() {
931
+ this.dialog = document.createElement("div"), this.dialog.className = "find-replace-dialog", this.dialog.style.display = "none", this.dialog.innerHTML = `
932
+ <div class="find-replace-container">
933
+ <div class="find-replace-body">
934
+ <div class="find-replace-group">
935
+ <label class="find-replace-label">查找内容</label>
936
+ <div class="find-replace-input-wrapper">
937
+ <input
938
+ type="text"
939
+ class="find-replace-input find-input"
940
+ placeholder="请输入查找内容"
941
+ />
942
+ </div>
943
+ </div>
944
+
945
+ <div class="find-replace-group">
946
+ <label class="find-replace-label">替换为</label>
947
+ <input
948
+ type="text"
949
+ class="find-replace-input replace-input"
950
+ placeholder="请输入替换内容"
951
+ />
952
+ </div>
953
+
954
+ <div class="find-replace-result" style="display: none">
955
+ 已找到 <span class="total-matches">0</span> 个结果
956
+ <span class="current-position"></span>
957
+ </div>
958
+ </div>
959
+
960
+ <div class="find-replace-footer">
961
+ <button class="find-replace-btn cancel-btn">关闭</button>
962
+ <button class="find-replace-btn find-prev-btn">查找上一个</button>
963
+ <button class="find-replace-btn find-next-btn">查找下一个</button>
964
+ <button class="find-replace-btn replace-one-btn">替换</button>
965
+ <button class="find-replace-btn find-replace-btn-primary replace-all-btn">全部替换</button>
966
+ </div>
967
+ </div>
968
+ `, (this.resolveContainer(this.options.container) || document.body).appendChild(this.dialog), this.elements = {
969
+ findInput: this.dialog.querySelector(".find-input"),
970
+ replaceInput: this.dialog.querySelector(
971
+ ".replace-input"
972
+ ),
973
+ // resultCount: this.dialog.querySelector(
974
+ // ".find-replace-badge"
975
+ // ) as HTMLElement,
976
+ resultInfo: this.dialog.querySelector(
977
+ ".find-replace-result"
978
+ ),
979
+ totalMatches: this.dialog.querySelector(".total-matches"),
980
+ // currentPosition: this.dialog.querySelector(
981
+ // ".current-position"
982
+ // ) as HTMLElement,
983
+ selectedColumnsOnly: this.dialog.querySelector(
984
+ ".selected-columns-only"
985
+ )
986
+ };
987
+ }
988
+ /**
989
+ * 绑定事件
990
+ */
991
+ bindEvents() {
992
+ var t, n, o, s, l;
993
+ if (!this.dialog) return;
994
+ const e = this.dialog.querySelector(".cancel-btn");
995
+ e == null || e.addEventListener("click", () => this.close()), this.bindDragEvents(), (t = this.elements.findInput) == null || t.addEventListener("input", (i) => {
996
+ this.state.findText = i.target.value, this.state.findText || this.clearResults();
997
+ }), (n = this.dialog.querySelector(".find-next-btn")) == null || n.addEventListener("click", () => this.findNext()), (o = this.dialog.querySelector(".find-prev-btn")) == null || o.addEventListener("click", () => this.findPrevious()), (s = this.dialog.querySelector(".replace-one-btn")) == null || s.addEventListener("click", () => this.replaceOne()), (l = this.dialog.querySelector(".replace-all-btn")) == null || l.addEventListener("click", () => this.replaceAll());
998
+ }
999
+ /**
1000
+ * 绑定拖拽事件
1001
+ */
1002
+ bindDragEvents() {
1003
+ var r;
1004
+ const e = (r = this.dialog) == null ? void 0 : r.querySelector(
1005
+ ".find-replace-header"
1006
+ );
1007
+ if (!e || !this.dialog) return;
1008
+ let t = !1, n = 0, o = 0, s = 0, l = 0;
1009
+ const i = (h) => {
1010
+ t = !0, n = h.clientX, o = h.clientY;
1011
+ const p = this.dialog.getBoundingClientRect();
1012
+ s = p.left, l = p.top, this.dialog.style.left = `${s}px`, this.dialog.style.transform = "none", document.addEventListener("mousemove", a), document.addEventListener("mouseup", d);
1013
+ }, a = (h) => {
1014
+ if (!t || !this.dialog) return;
1015
+ const p = h.clientX - n, f = h.clientY - o, m = Math.max(0, s + p), g = Math.max(0, l + f);
1016
+ this.dialog.style.left = `${m}px`, this.dialog.style.top = `${g}px`;
1017
+ }, d = () => {
1018
+ t = !1, document.removeEventListener("mousemove", a), document.removeEventListener("mouseup", d);
1019
+ };
1020
+ e.addEventListener("mousedown", i);
1021
+ }
1022
+ /**
1023
+ * 注入样式
1024
+ */
1025
+ injectStyles() {
1026
+ if (document.getElementById("find-replace-styles")) return;
1027
+ const e = document.createElement("style");
1028
+ e.id = "find-replace-styles", e.textContent = `
1029
+ .find-replace-dialog {
1030
+ position: fixed;
1031
+ top: 80px;
1032
+ left: 50%;
1033
+ transform: translateX(-50%);
1034
+ z-index: 9999;
1035
+ font-size: 14px;
1036
+ color: #1D2129;
1037
+ pointer-events: auto;
1038
+ }
1039
+
1040
+ .find-replace-container {
1041
+ background: white;
1042
+ border-radius: 8px;
1043
+ width: 500px;
1044
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
1045
+ animation: slideIn 0.2s ease-out;
1046
+ }
1047
+
1048
+ @keyframes slideIn {
1049
+ from { opacity: 0; transform: translateX(20px); }
1050
+ to { opacity: 1; transform: translateX(0); }
1051
+ }
1052
+
1053
+
1054
+
1055
+ .find-replace-title {
1056
+ font-size: 16px;
1057
+ font-weight: 500;
1058
+ color: #303133;
1059
+ }
1060
+
1061
+
1062
+
1063
+ .find-replace-body {
1064
+ padding: 16px;
1065
+ }
1066
+
1067
+ .find-replace-group {
1068
+ margin-bottom: 16px;
1069
+ display: flex;
1070
+ align-items: center;
1071
+
1072
+ }
1073
+
1074
+ .find-replace-label {
1075
+ display: block;
1076
+ min-width: 56px;
1077
+ margin-right: 8px;
1078
+ }
1079
+
1080
+ .find-replace-checkbox {
1081
+
1082
+ display: none;
1083
+ align-items: center;
1084
+ font-weight: normal;
1085
+ min-width: auto;
1086
+ margin-right: 0;
1087
+ }
1088
+
1089
+ .find-replace-checkbox input {
1090
+ margin-right: 6px;
1091
+ }
1092
+
1093
+ .find-replace-input-wrapper {
1094
+ position: relative;
1095
+ display: flex;
1096
+ align-items: center;
1097
+ flex: 1;
1098
+ height: 32px;
1099
+ }
1100
+
1101
+ .find-replace-input {
1102
+ width: 100%;
1103
+ padding: 0px 12px;
1104
+ border: 1px solid #dcdfe6;
1105
+ border-radius: 4px;
1106
+ height:32px;
1107
+ }
1108
+
1109
+ .find-replace-input:focus {
1110
+ outline: none;
1111
+ border-color: #409eff;
1112
+ }
1113
+
1114
+ .current-position {
1115
+ margin-left: 10px;
1116
+ color: #409eff;
1117
+ font-weight: 500;
1118
+ }
1119
+
1120
+ .find-replace-footer {
1121
+ padding: 0px 16px 16px 16px;
1122
+ display: flex;
1123
+ justify-content: flex-end;
1124
+ gap: 8px;
1125
+ flex-wrap: wrap;
1126
+ }
1127
+
1128
+ .find-replace-btn {
1129
+ padding: 6px 16px;
1130
+ border-radius: 4px;
1131
+ height: 32px;
1132
+ cursor: pointer;
1133
+ background: var(--sl-color-white);
1134
+ border: 1px solid var(--sl-border-color);
1135
+ }
1136
+
1137
+ .find-replace-btn-primary {
1138
+ background-color: var(--sl-color-primary);
1139
+ color: white;
1140
+ }
1141
+
1142
+ .find-replace-btn-primary:hover {
1143
+ border-color: var(--sl-button-hover-border-color);
1144
+ background-color: var(--sl-button-hover-bg-color);
1145
+ }
1146
+
1147
+ .message-toast {
1148
+ height:40px;
1149
+ position: fixed;
1150
+ top: 20px;
1151
+ left: 50%;
1152
+ transform: translateX(-50%) translateY(-100px);
1153
+ padding: 11px 15px;
1154
+ color: white;
1155
+ border-radius: 4px;
1156
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
1157
+ z-index: 9999;
1158
+ opacity: 0;
1159
+ transition: all 0.3s ease-out;
1160
+ display: flex;
1161
+ align-items: center;
1162
+ }
1163
+ .message-toast--info {
1164
+ background-color: var(--sl-color-info-light-9);
1165
+ border: 1px solid var(--sl-color-info-light-8);
1166
+ color: var(--sl-color-info);
1167
+ }
1168
+ .message-toast--success {
1169
+ background-color: var(--sl-color-success-light-9);
1170
+ border: 1px solid var(--sl-color-success-light-8);
1171
+ color: var(--sl-color-success);
1172
+ }
1173
+ .message-toast--warning {
1174
+ background-color: var(--sl-color-warning-light-9);
1175
+ border: 1px solid var(--sl-color-warning-light-8);
1176
+ color: var(--sl-color-warning);
1177
+ }
1178
+ .message-toast--error {
1179
+ background-color: var(--sl-color-error-light-9);
1180
+ border: 1px solid var(--sl-color-error-light-8);
1181
+ color: var(--sl-color-error);
1182
+ }
1183
+
1184
+ .message-toast.show {
1185
+ transform: translateX(-50%) translateY(0);
1186
+ opacity: 1;
1187
+ }
1188
+ `, document.head.appendChild(e);
1189
+ }
1190
+ /**
1191
+ * 解析容器
1192
+ */
1193
+ resolveContainer(e) {
1194
+ return e ? typeof e == "string" ? document.getElementById(e) || document.querySelector(e) : e : null;
1195
+ }
1196
+ /**
1197
+ * 打开弹窗
1198
+ */
1199
+ open() {
1200
+ var e;
1201
+ this.dialog && (this.dialog.style.display = "block", (e = this.elements.findInput) == null || e.focus());
1202
+ }
1203
+ /**
1204
+ * 关闭弹窗
1205
+ */
1206
+ close() {
1207
+ this.dialog && (this.dialog.style.display = "none", this.resetState());
1208
+ }
1209
+ /**
1210
+ * 重置状态
1211
+ */
1212
+ resetState() {
1213
+ this.state = {
1214
+ findText: "",
1215
+ replaceText: "",
1216
+ matches: [],
1217
+ currentIndex: 0
1218
+ }, this.elements.findInput && (this.elements.findInput.value = ""), this.elements.replaceInput && (this.elements.replaceInput.value = ""), this.clearResults();
1219
+ }
1220
+ /**
1221
+ * 清除结果显示
1222
+ */
1223
+ clearResults() {
1224
+ this.elements.resultInfo && (this.elements.resultInfo.style.display = "none");
1225
+ }
1226
+ /**
1227
+ * 执行查找
1228
+ */
1229
+ performSearch() {
1230
+ var l, i, a, d, r;
1231
+ if (!this.state.findText)
1232
+ return this.showMessage("请输入查找内容", "warning"), !1;
1233
+ if (!this.tableInstance)
1234
+ return this.showMessage("未连接表格实例", "error"), !1;
1235
+ this.state.matches = [];
1236
+ const e = this.tableInstance.colCount || 0, t = this.tableInstance.rowCount || 0, n = this.tableInstance.columnHeaderLevelCount || 1, o = ((l = this.elements.selectedColumnsOnly) == null ? void 0 : l.checked) || !1;
1237
+ let s = [];
1238
+ if (o) {
1239
+ const h = ((a = (i = this.tableInstance).getSelectedCellInfos) == null ? void 0 : a.call(i)) || [];
1240
+ if (h.length === 0)
1241
+ return this.showMessage("请先选中要搜索的列", "warning"), !1;
1242
+ const p = /* @__PURE__ */ new Set();
1243
+ h.forEach((f) => {
1244
+ f.col !== void 0 && p.add(f.col);
1245
+ }), s = Array.from(p);
1246
+ } else
1247
+ s = Array.from({ length: e }, (h, p) => p);
1248
+ for (let h = n; h < t; h++)
1249
+ for (const p of s) {
1250
+ const f = this.tableInstance.getCellValue(p, h);
1251
+ f && String(f).toLowerCase().includes(this.state.findText.toLowerCase()) && this.state.matches.push({
1252
+ row: h,
1253
+ col: p,
1254
+ value: String(f)
1255
+ });
1256
+ }
1257
+ return this.state.matches.length > 0 ? (this.elements.totalMatches && (this.elements.totalMatches.textContent = String(
1258
+ this.state.matches.length
1259
+ )), this.elements.resultInfo && (this.elements.resultInfo.style.display = "block"), this.state.currentIndex = 0, this.highlightMatch(0), (r = (d = this.options).onSearch) == null || r.call(d, this.state.matches), !0) : (this.showMessage("未找到匹配内容", "warning"), this.clearResults(), !1);
1260
+ }
1261
+ /**
1262
+ * 高亮匹配项
1263
+ */
1264
+ highlightMatch(e) {
1265
+ var n, o, s;
1266
+ if (this.state.matches.length === 0) return;
1267
+ const t = this.state.matches[e];
1268
+ if ((n = this.tableInstance) != null && n.selectCell && this.tableInstance.selectCell(t.col, t.row), (o = this.tableInstance) != null && o.getVisibleCellRange && ((s = this.tableInstance) != null && s.scrollToCell)) {
1269
+ const l = this.tableInstance.getVisibleCellRange();
1270
+ if (l) {
1271
+ const { startRow: i, endRow: a, startCol: d, endCol: r } = l;
1272
+ t.row >= i && t.row <= a && t.col >= d && t.col <= r || this.tableInstance.scrollToCell({ col: t.col, row: t.row });
1273
+ }
1274
+ }
1275
+ }
1276
+ /**
1277
+ * 查找下一个
1278
+ */
1279
+ findNext() {
1280
+ this.state.matches.length === 0 && !this.performSearch() || (this.state.currentIndex = (this.state.currentIndex + 1) % this.state.matches.length, this.highlightMatch(this.state.currentIndex));
1281
+ }
1282
+ /**
1283
+ * 查找上一个
1284
+ */
1285
+ findPrevious() {
1286
+ this.state.matches.length === 0 && !this.performSearch() || (this.state.currentIndex = this.state.currentIndex === 0 ? this.state.matches.length - 1 : this.state.currentIndex - 1, this.highlightMatch(this.state.currentIndex));
1287
+ }
1288
+ /**
1289
+ * 替换一个
1290
+ */
1291
+ replaceOne() {
1292
+ var o, s, l, i;
1293
+ if (this.state.matches.length === 0 && !this.performSearch())
1294
+ return;
1295
+ this.state.replaceText = ((o = this.elements.replaceInput) == null ? void 0 : o.value) || "";
1296
+ const e = this.state.matches[this.state.currentIndex], n = e.value.replace(
1297
+ this.state.findText,
1298
+ this.state.replaceText
1299
+ );
1300
+ (s = this.tableInstance) != null && s.changeCellValue && (this.tableInstance.changeCellValue(e.col, e.row, n), (i = (l = this.options).onReplace) == null || i.call(l, e, n)), this.showMessage(
1301
+ `已替换第 ${this.state.currentIndex + 1} 个匹配项`,
1302
+ "success"
1303
+ ), setTimeout(() => {
1304
+ const a = this.state.currentIndex;
1305
+ this.performSearch(), this.state.matches.length > 0 && (this.state.currentIndex = Math.min(
1306
+ a,
1307
+ this.state.matches.length - 1
1308
+ ), this.highlightMatch(this.state.currentIndex));
1309
+ }, 100);
1310
+ }
1311
+ /**
1312
+ * 全部替换
1313
+ */
1314
+ replaceAll() {
1315
+ var t;
1316
+ if (this.state.matches.length === 0 && !this.performSearch())
1317
+ return;
1318
+ this.state.replaceText = ((t = this.elements.replaceInput) == null ? void 0 : t.value) || "";
1319
+ const e = this.state.matches.length;
1320
+ this.state.matches.forEach((n) => {
1321
+ var l, i, a;
1322
+ const s = n.value.replace(
1323
+ new RegExp(this.state.findText, "g"),
1324
+ this.state.replaceText
1325
+ );
1326
+ (l = this.tableInstance) != null && l.changeCellValue && (this.tableInstance.changeCellValue(n.col, n.row, s), (a = (i = this.options).onReplace) == null || a.call(i, n, s));
1327
+ }), this.showMessage(`已替换全部 ${e} 个匹配项`, "success");
1328
+ }
1329
+ /**
1330
+ * 显示消息
1331
+ */
1332
+ showMessage(e, t = "info") {
1333
+ const n = document.createElement("div");
1334
+ n.className = `message-toast message-toast--${t}`;
1335
+ const o = document.createElement("span");
1336
+ o.textContent = e, n.appendChild(o);
1337
+ const s = document.createElement("span");
1338
+ s.className = "message-close", s.innerHTML = "&times;", s.style.cssText = `
1339
+ margin-left: 12px;
1340
+ cursor: pointer;
1341
+ font-size: 22px;
1342
+ font-weight: 300;
1343
+ opacity: 0.8;
1344
+ transition: opacity 0.2s;
1345
+ `, s.onmouseenter = () => s.style.opacity = "1", s.onmouseleave = () => s.style.opacity = "0.8", n.appendChild(s), document.body.appendChild(n);
1346
+ let l;
1347
+ const i = () => {
1348
+ clearTimeout(l), n.classList.remove("show"), setTimeout(() => {
1349
+ n.parentNode && document.body.removeChild(n);
1350
+ }, 300);
1351
+ };
1352
+ s.onclick = i, setTimeout(() => n.classList.add("show"), 10), l = setTimeout(i, 3e3);
1353
+ }
1354
+ /**
1355
+ * 设置表格实例(用于表格重建后更新引用)
1356
+ */
1357
+ setTableInstance(e) {
1358
+ this.tableInstance = e, this.state.matches = [], this.state.currentIndex = 0, this.clearResults();
1359
+ }
1360
+ /**
1361
+ * 设置是否只搜索选中列
1362
+ */
1363
+ setSelectedColumnsOnly(e) {
1364
+ this.elements.selectedColumnsOnly && (this.elements.selectedColumnsOnly.checked = e);
1365
+ }
1366
+ /**
1367
+ * 获取是否只搜索选中列
1368
+ */
1369
+ getSelectedColumnsOnly() {
1370
+ var e;
1371
+ return ((e = this.elements.selectedColumnsOnly) == null ? void 0 : e.checked) || !1;
1372
+ }
1373
+ /**
1374
+ * 设置查找文本
1375
+ */
1376
+ setFindText(e) {
1377
+ this.state.findText = e, this.elements.findInput && (this.elements.findInput.value = e);
1378
+ }
1379
+ /**
1380
+ * 设置替换文本
1381
+ */
1382
+ setReplaceText(e) {
1383
+ this.state.replaceText = e, this.elements.replaceInput && (this.elements.replaceInput.value = e);
1384
+ }
1385
+ /**
1386
+ * 销毁弹窗
1387
+ */
1388
+ destroy() {
1389
+ this.dialog && (this.dialog.remove(), this.dialog = null);
1390
+ }
1391
+ }
1392
+ const G = {
1393
+ toolbar: {
1394
+ title: "制表错误",
1395
+ unit: "条",
1396
+ total: "共 {total} 个错误项",
1397
+ hint: "请在错误项里查询对应的数据或在数据里进行搜索",
1398
+ buttons: {
1399
+ search: "查找/替换",
1400
+ freeze: {
1401
+ label: "冻结前",
1402
+ suffix: "列"
1403
+ },
1404
+ list: "仅显示错误列"
1405
+ }
1406
+ },
1407
+ dialog: {
1408
+ find: {
1409
+ label: "查找内容",
1410
+ placeholder: "请输入查找内容"
1411
+ },
1412
+ replace: {
1413
+ label: "替换为",
1414
+ placeholder: "请输入替换内容"
1415
+ },
1416
+ checkbox: {
1417
+ selectedOnly: "只替换选中列"
1418
+ },
1419
+ buttons: {
1420
+ close: "关闭",
1421
+ findPrev: "查找上一个",
1422
+ findNext: "查找下一个",
1423
+ replaceOne: "替换",
1424
+ replaceAll: "全部替换"
1425
+ },
1426
+ messages: {
1427
+ pleaseInputFind: "请输入查找内容",
1428
+ notConnected: "未连接表格实例",
1429
+ pleaseSelectColumns: "请先选中要搜索的列",
1430
+ noMatchFound: "未找到匹配内容",
1431
+ nothingToReplace: "没有可替换的内容",
1432
+ replacedOne: "已替换第 {index} 个匹配项",
1433
+ replacedAll: "已替换全部 {count} 个匹配项"
1434
+ },
1435
+ result: {
1436
+ found: "已找到 {count} 个结果"
1437
+ }
1438
+ },
1439
+ sheet: {
1440
+ defaultTitle: "Sheet1"
1441
+ }
1442
+ }, J = {
1443
+ toolbar: {
1444
+ title: "製表錯誤",
1445
+ unit: "筆",
1446
+ total: "共 {total} 個錯誤項",
1447
+ hint: "請在錯誤項裡查詢對應的資料或在資料裡進行搜尋",
1448
+ buttons: {
1449
+ search: "尋找/取代",
1450
+ freeze: {
1451
+ label: "凍結前",
1452
+ suffix: "欄"
1453
+ },
1454
+ list: "僅顯示錯誤欄"
1455
+ }
1456
+ },
1457
+ dialog: {
1458
+ find: {
1459
+ label: "尋找內容",
1460
+ placeholder: "請輸入尋找內容"
1461
+ },
1462
+ replace: {
1463
+ label: "取代為",
1464
+ placeholder: "請輸入取代內容"
1465
+ },
1466
+ checkbox: {
1467
+ selectedOnly: "只取代選中欄"
1468
+ },
1469
+ buttons: {
1470
+ close: "關閉",
1471
+ findPrev: "尋找上一個",
1472
+ findNext: "尋找下一個",
1473
+ replaceOne: "取代",
1474
+ replaceAll: "全部取代"
1475
+ },
1476
+ messages: {
1477
+ pleaseInputFind: "請輸入尋找內容",
1478
+ notConnected: "未連接表格實例",
1479
+ pleaseSelectColumns: "請先選中要搜尋的欄",
1480
+ noMatchFound: "未找到符合內容",
1481
+ nothingToReplace: "沒有可取代的內容",
1482
+ replacedOne: "已取代第 {index} 個符合項",
1483
+ replacedAll: "已取代全部 {count} 個符合項"
1484
+ },
1485
+ result: {
1486
+ found: "已找到 {count} 個結果"
1487
+ }
1488
+ },
1489
+ sheet: {
1490
+ defaultTitle: "Sheet1"
1491
+ }
1492
+ }, Q = {
1493
+ toolbar: {
1494
+ title: "Table Errors",
1495
+ unit: "items",
1496
+ total: "Total {total} errors",
1497
+ hint: "Please search for the corresponding data in the error items or in the data",
1498
+ buttons: {
1499
+ search: "Find/Replace",
1500
+ freeze: {
1501
+ label: "Freeze first",
1502
+ suffix: "columns"
1503
+ },
1504
+ list: "Show error columns only"
1505
+ }
1506
+ },
1507
+ dialog: {
1508
+ find: {
1509
+ label: "Find content",
1510
+ placeholder: "Please enter content to find"
1511
+ },
1512
+ replace: {
1513
+ label: "Replace with",
1514
+ placeholder: "Please enter replacement content"
1515
+ },
1516
+ checkbox: {
1517
+ selectedOnly: "Replace selected columns only"
1518
+ },
1519
+ buttons: {
1520
+ close: "Close",
1521
+ findPrev: "Find Previous",
1522
+ findNext: "Find Next",
1523
+ replaceOne: "Replace",
1524
+ replaceAll: "Replace All"
1525
+ },
1526
+ messages: {
1527
+ pleaseInputFind: "Please enter content to find",
1528
+ notConnected: "Table instance not connected",
1529
+ pleaseSelectColumns: "Please select columns to search first",
1530
+ noMatchFound: "No matching content found",
1531
+ nothingToReplace: "Nothing to replace",
1532
+ replacedOne: "Replaced match #{index}",
1533
+ replacedAll: "Replaced all {count} matches"
1534
+ },
1535
+ result: {
1536
+ found: "Found {count} result(s)"
1537
+ }
1538
+ },
1539
+ sheet: {
1540
+ defaultTitle: "Sheet1"
1541
+ }
1542
+ }, Z = {
1543
+ "zh-CN": G,
1544
+ "en-US": Q,
1545
+ "zh-TW": J
1546
+ };
1547
+ let ee = "zh-CN";
1548
+ function te() {
1549
+ return Z[ee];
1550
+ }
1551
+ function ne(c, e = {}) {
1552
+ return c.replace(/\{(\w+)\}/g, (t, n) => e[n] !== void 0 ? String(e[n]) : `{${n}}`);
1553
+ }
1554
+ function C(c, e) {
1555
+ const t = te(), n = c.split(".");
1556
+ let o = t;
1557
+ for (const s of n)
1558
+ if (o && typeof o == "object" && s in o)
1559
+ o = o[s];
1560
+ else
1561
+ return console.warn(`I18n message not found: ${c}`), c;
1562
+ return typeof o == "string" ? ne(o, e || {}) : (console.warn(`I18n message is not a string: ${c}`), c);
1563
+ }
1564
+ class oe {
1565
+ constructor(e) {
1566
+ u(this, "container", null);
1567
+ u(this, "toolbarElement", null);
1568
+ u(this, "config");
1569
+ // DOM 元素缓存
1570
+ u(this, "elements", {});
1571
+ this.config = {
1572
+ title: C("toolbar.title"),
1573
+ count: 0,
1574
+ total: 0,
1575
+ hint: C("toolbar.hint"),
1576
+ freezeCount: 0,
1577
+ showErrorList: !1,
1578
+ buttons: {
1579
+ search: !0,
1580
+ freeze: !0,
1581
+ export: !0,
1582
+ refresh: !0,
1583
+ list: !0
1584
+ },
1585
+ ...e
1586
+ }, this.init();
1587
+ }
1588
+ /**
1589
+ * 初始化
1590
+ */
1591
+ init() {
1592
+ this.config.container && (this.container = this.getContainer(this.config.container)), this.createToolbar(), this.injectStyles();
1593
+ }
1594
+ /**
1595
+ * 获取容器
1596
+ */
1597
+ getContainer(e) {
1598
+ return typeof e == "string" ? document.getElementById(e) || document.querySelector(e) : e;
1599
+ }
1600
+ /**
1601
+ * 创建工具栏
1602
+ */
1603
+ createToolbar() {
1604
+ this.toolbarElement = document.createElement("div"), this.toolbarElement.className = "sl-toolbar";
1605
+ const e = this.createLeftSection(), t = this.createRightSection();
1606
+ this.toolbarElement.appendChild(e), this.toolbarElement.appendChild(t), this.container && this.container.appendChild(this.toolbarElement);
1607
+ }
1608
+ /**
1609
+ * 创建左侧区域(空容器,内容由调用者通过 leftSlot 插入)
1610
+ */
1611
+ createLeftSection() {
1612
+ const e = document.createElement("div");
1613
+ if (e.className = "sl-toolbar-left", this.config.leftSlot) {
1614
+ const t = typeof this.config.leftSlot == "function" ? this.config.leftSlot() : this.config.leftSlot;
1615
+ t && e.appendChild(t);
1616
+ }
1617
+ return e;
1618
+ }
1619
+ /**
1620
+ * 创建右侧区域
1621
+ */
1622
+ createRightSection() {
1623
+ const e = document.createElement("div");
1624
+ e.className = "sl-toolbar-right";
1625
+ const { buttons: t } = this.config;
1626
+ if ((t == null ? void 0 : t.search) !== !1) {
1627
+ const n = this.createButton({
1628
+ text: C("toolbar.buttons.search"),
1629
+ onClick: () => {
1630
+ var o, s;
1631
+ return (s = (o = this.config).onSearchClick) == null ? void 0 : s.call(o);
1632
+ }
1633
+ });
1634
+ e.appendChild(n);
1635
+ }
1636
+ if ((t == null ? void 0 : t.freeze) !== !1) {
1637
+ const n = this.createFreezeButton();
1638
+ e.appendChild(n);
1639
+ }
1640
+ return e;
1641
+ }
1642
+ /**
1643
+ * 创建按钮
1644
+ */
1645
+ createButton(e) {
1646
+ const t = document.createElement("button");
1647
+ return t.className = e.icon ? "sl-toolbar-btn sl-toolbar-btn-icon" : "sl-toolbar-btn", t.textContent = e.text, e.title && (t.title = e.title), e.onClick && (t.onclick = e.onClick), t;
1648
+ }
1649
+ /**
1650
+ * 创建冻结列选择器(标题 + 数字输入框 + 上下箭头)
1651
+ */
1652
+ createFreezeButton() {
1653
+ const e = document.createElement("div");
1654
+ e.className = "sl-freeze-selector";
1655
+ const t = document.createElement("span");
1656
+ t.className = "sl-freeze-label", t.textContent = C("toolbar.buttons.freeze.label");
1657
+ const n = document.createElement("div");
1658
+ n.className = "sl-freeze-input-wrapper";
1659
+ const o = document.createElement("input");
1660
+ o.type = "number", o.className = "sl-freeze-input", o.min = "0", o.max = "100", o.value = String(this.config.freezeCount || 0), this.elements.freezeSelect = o;
1661
+ const s = document.createElement("div");
1662
+ s.className = "sl-freeze-arrows";
1663
+ const l = document.createElement("button");
1664
+ l.className = "sl-freeze-arrow sl-freeze-arrow-up", l.innerHTML = "▲", l.type = "button";
1665
+ const i = document.createElement("button");
1666
+ i.className = "sl-freeze-arrow sl-freeze-arrow-down", i.innerHTML = "▼", i.type = "button", s.appendChild(l), s.appendChild(i);
1667
+ const a = document.createElement("span");
1668
+ a.className = "sl-freeze-suffix", a.textContent = C("toolbar.buttons.freeze.suffix");
1669
+ const d = (r) => {
1670
+ var h, p;
1671
+ r < 0 && (r = 0), r > 100 && (r = 100), o.value = String(r), this.config.freezeCount = r, (p = (h = this.config).onFreezeChange) == null || p.call(h, r);
1672
+ };
1673
+ return l.onclick = (r) => {
1674
+ r.preventDefault();
1675
+ const h = parseInt(o.value, 10) || 0;
1676
+ d(h + 1);
1677
+ }, i.onclick = (r) => {
1678
+ r.preventDefault();
1679
+ const h = parseInt(o.value, 10) || 0;
1680
+ d(h - 1);
1681
+ }, o.oninput = () => {
1682
+ let r = parseInt(o.value, 10);
1683
+ (isNaN(r) || r < 0) && (r = 0, o.value = "0"), r > 100 && (r = 100, o.value = "100"), this.config.freezeCount = r;
1684
+ }, o.onblur = () => {
1685
+ var h, p;
1686
+ const r = parseInt(o.value, 10) || 0;
1687
+ (p = (h = this.config).onFreezeChange) == null || p.call(h, r);
1688
+ }, o.onkeydown = (r) => {
1689
+ r.key === "Enter" && o.blur();
1690
+ }, n.appendChild(o), n.appendChild(s), e.appendChild(t), e.appendChild(n), e.appendChild(a), e;
1691
+ }
1692
+ /**
1693
+ * 格式化数字(添加千分位)
1694
+ */
1695
+ formatNumber(e) {
1696
+ return e.toLocaleString();
1697
+ }
1698
+ /**
1699
+ * 注入样式
1700
+ */
1701
+ injectStyles() {
1702
+ if (document.getElementById("sl-toolbar-styles")) return;
1703
+ const e = document.createElement("style");
1704
+ e.id = "sl-toolbar-styles", e.textContent = `
1705
+ .sl-toolbar {
1706
+ display: flex;
1707
+ justify-content: space-between;
1708
+ align-items: center;
1709
+ padding: 8px 16px;
1710
+ background: var(--sl-vtable-card-bg-color);
1711
+ font-size: 14px;
1712
+ color: var(--sl-vtable-content-color);
1713
+ flex-shrink: 0;
1714
+ heihgt:60px;
1715
+ border-radius: 4px;
1716
+ }
1717
+ .sl-toolbar-title {
1718
+ display: flex;
1719
+ align-items: baseline;
1720
+ gap: 4px;
1721
+ }
1722
+
1723
+ .sl-title-text {
1724
+ font-size: 14px;
1725
+ font-weight: 500;
1726
+ color: var(--sl-vtable-content-color);
1727
+ }
1728
+
1729
+ .sl-title-count {
1730
+ font-size: 16px;
1731
+ font-weight: 600;
1732
+ color: #F53F3F;
1733
+ }
1734
+
1735
+ .sl-title-unit {
1736
+ font-size: 14px;
1737
+ color: #1D2129;
1738
+ }
1739
+
1740
+ .sl-title-total {
1741
+ font-size: 12px;
1742
+ color: #86909C;
1743
+ margin-left: 4px;
1744
+ }
1745
+
1746
+ .sl-toolbar-hint {
1747
+ font-size: 12px;
1748
+ color: #86909C;
1749
+ }
1750
+
1751
+ .sl-toolbar-right {
1752
+ display: flex;
1753
+ align-items: center;
1754
+ gap: 24px;
1755
+ }
1756
+
1757
+ .sl-toolbar-btn {
1758
+ padding: 6px 14px;
1759
+ height: 32px;
1760
+ background: var(--sl-vtable-bg-color1);
1761
+ border: 1px solid var(--sl-vtable-bg-color1);
1762
+ border-radius: 8px;
1763
+ font-size: 14px;
1764
+ color: var(--sl-vtable-content-color);
1765
+ cursor: pointer;
1766
+ transition: all 0.2s;
1767
+ white-space: nowrap;
1768
+ }
1769
+
1770
+ .sl-toolbar-btn:hover {
1771
+ background: #E8E9EB;
1772
+ }
1773
+
1774
+ .sl-toolbar-btn-icon {
1775
+ padding: 6px 10px;
1776
+ font-size: 16px;
1777
+ min-width: 32px;
1778
+ }
1779
+
1780
+ .sl-toolbar-btn-complex {
1781
+ display: flex;
1782
+ align-items: center;
1783
+ gap: 4px;
1784
+ }
1785
+
1786
+ .sl-btn-icon {
1787
+ font-size: 14px;
1788
+ }
1789
+
1790
+ .sl-btn-text {
1791
+ font-size: 14px;
1792
+ }
1793
+
1794
+ .sl-btn-count {
1795
+ font-size: 14px;
1796
+ font-weight: 600;
1797
+ color: var(--sl-vtable-primary-color);
1798
+ }
1799
+
1800
+ .sl-btn-suffix {
1801
+ font-size: 14px;
1802
+ }
1803
+
1804
+ .sl-freeze-selector {
1805
+ display: flex;
1806
+ align-items: center;
1807
+ gap: 4px;
1808
+ }
1809
+
1810
+ .sl-freeze-label {
1811
+ font-size: 14px;
1812
+ color: var(--sl-vtable-content-color);
1813
+ white-space: nowrap;
1814
+ }
1815
+
1816
+ .sl-freeze-input-wrapper {
1817
+ position: relative;
1818
+ display: inline-flex;
1819
+ align-items: center;
1820
+ background: var(--sl-vtable-bg-color1);
1821
+ border: 1px solid var(--sl-vtable-bg-color1);
1822
+ border-radius: 8px;
1823
+ transition: all 0.2s;
1824
+ height: 32px;
1825
+ box-sizing: border-box;
1826
+ }
1827
+
1828
+ .sl-freeze-input-wrapper:hover {
1829
+ background: #E8E9EB;
1830
+ border-color: var(--sl-vtable-primary-color);
1831
+ }
1832
+
1833
+ .sl-freeze-input-wrapper:focus-within {
1834
+ border-color: var(--sl-vtable-primary-color);
1835
+ box-shadow: 0 0 0 2px rgba(40, 120, 255, 0.1);
1836
+ }
1837
+
1838
+ .sl-freeze-input {
1839
+ width: 30px;
1840
+ height: 30px;
1841
+ padding: 0px 2px;
1842
+ border-radius: 8px 0px 0px 8px;
1843
+ background: #fff;
1844
+ border: none;
1845
+ font-size: 14px;
1846
+ color: var(--sl-vtable-content-color);
1847
+ text-align: center;
1848
+ outline: none;
1849
+ -moz-appearance: textfield;
1850
+ }
1851
+
1852
+ .sl-freeze-input::-webkit-outer-spin-button,
1853
+ .sl-freeze-input::-webkit-inner-spin-button {
1854
+ -webkit-appearance: none;
1855
+ margin: 0;
1856
+ }
1857
+
1858
+ .sl-freeze-arrows {
1859
+ display: flex;
1860
+ flex-direction: column;
1861
+ border-left: 1px solid #E5E6EB;
1862
+ }
1863
+
1864
+ .sl-freeze-arrow {
1865
+ width: 20px;
1866
+ height: 16px;
1867
+ padding: 0;
1868
+ background: transparent;
1869
+ border: none;
1870
+ font-size: 8px;
1871
+ color: var(--sl-vtable-content-color);
1872
+ cursor: pointer;
1873
+ display: flex;
1874
+ align-items: center;
1875
+ justify-content: center;
1876
+ transition: all 0.2s;
1877
+ opacity: 0.6;
1878
+ }
1879
+
1880
+ .sl-freeze-arrow:hover {
1881
+ background: rgba(40, 120, 255, 0.1);
1882
+ opacity: 1;
1883
+ color: var(--sl-vtable-primary-color);
1884
+ }
1885
+
1886
+ .sl-freeze-arrow:active {
1887
+ background: rgba(40, 120, 255, 0.2);
1888
+ }
1889
+
1890
+ .sl-freeze-arrow-up {
1891
+ border-radius: 0 8px 0 0;
1892
+ }
1893
+
1894
+ .sl-freeze-arrow-down {
1895
+ border-radius: 0 0 8px 0;
1896
+ border-top: 1px solid #E5E6EB;
1897
+ }
1898
+
1899
+ .sl-freeze-suffix {
1900
+ font-size: 14px;
1901
+ color: var(--sl-vtable-content-color);
1902
+ }
1903
+
1904
+ .sl-error-list-checkbox {
1905
+ display: inline-flex;
1906
+ align-items: center;
1907
+ gap: 8px;
1908
+ cursor: pointer;
1909
+ user-select: none;
1910
+ }
1911
+
1912
+ .sl-checkbox-input {
1913
+ position: absolute;
1914
+ opacity: 0;
1915
+ width: 0;
1916
+ height: 0;
1917
+ }
1918
+
1919
+ .sl-checkbox-custom {
1920
+ position: relative;
1921
+ width: 16px;
1922
+ height: 16px;
1923
+ border: 2px solid #C9CDD4;
1924
+ border-radius: 4px;
1925
+ background: #fff;
1926
+ transition: all 0.2s;
1927
+ flex-shrink: 0;
1928
+ }
1929
+
1930
+ .sl-checkbox-input:checked + .sl-checkbox-custom {
1931
+ background: var(--sl-vtable-primary-color);
1932
+ border-color: var(--sl-vtable-primary-color);
1933
+ }
1934
+
1935
+ .sl-checkbox-input:checked + .sl-checkbox-custom::after {
1936
+ content: "";
1937
+ position: absolute;
1938
+ left: 4px;
1939
+ top: 1px;
1940
+ width: 4px;
1941
+ height: 8px;
1942
+ border: solid white;
1943
+ border-width: 0 2px 2px 0;
1944
+ transform: rotate(45deg);
1945
+ }
1946
+
1947
+ .sl-error-list-checkbox:hover .sl-checkbox-custom {
1948
+ border-color: var(--sl-vtable-primary-color);
1949
+ }
1950
+
1951
+ .sl-checkbox-label {
1952
+ font-size: 14px;
1953
+ color: var(--sl-vtable-content-color);
1954
+ }
1955
+
1956
+ /* 响应式设计 */
1957
+ @media (max-width: 768px) {
1958
+ .sl-toolbar {
1959
+ flex-direction: column;
1960
+ align-items: flex-start;
1961
+ gap: 12px;
1962
+ }
1963
+
1964
+ .sl-toolbar-left {
1965
+ flex-direction: column;
1966
+ align-items: flex-start;
1967
+ gap: 8px;
1968
+ }
1969
+
1970
+ .sl-toolbar-right {
1971
+ width: 100%;
1972
+ justify-content: flex-start;
1973
+ flex-wrap: wrap;
1974
+ }
1975
+ }
1976
+ `, document.head.appendChild(e);
1977
+ }
1978
+ /**
1979
+ * 更新标题
1980
+ */
1981
+ updateTitle(e) {
1982
+ this.elements.titleText && (this.elements.titleText.textContent = e);
1983
+ }
1984
+ /**
1985
+ * 更新统计数据
1986
+ */
1987
+ updateStats(e, t) {
1988
+ this.elements.titleCount && (this.elements.titleCount.textContent = this.formatNumber(e)), this.elements.titleTotal && (this.elements.titleTotal.textContent = `(共 ${this.formatNumber(
1989
+ t
1990
+ )} 个错误项)`);
1991
+ }
1992
+ /**
1993
+ * 更新提示信息
1994
+ */
1995
+ updateHint(e) {
1996
+ this.elements.hint && (this.elements.hint.textContent = e);
1997
+ }
1998
+ /**
1999
+ * 更新冻结列数
2000
+ */
2001
+ updateFreezeCount(e) {
2002
+ this.config.freezeCount = e, this.elements.freezeSelect && (this.elements.freezeSelect.value = String(e));
2003
+ }
2004
+ /**
2005
+ * 更新显示错误列状态
2006
+ */
2007
+ updateShowErrorList(e) {
2008
+ this.config.showErrorList = e, this.elements.errorListCheckbox && (this.elements.errorListCheckbox.checked = e);
2009
+ }
2010
+ /**
2011
+ * 显示工具栏
2012
+ */
2013
+ show() {
2014
+ this.toolbarElement && (this.toolbarElement.style.display = "flex");
2015
+ }
2016
+ /**
2017
+ * 隐藏工具栏
2018
+ */
2019
+ hide() {
2020
+ this.toolbarElement && (this.toolbarElement.style.display = "none");
2021
+ }
2022
+ /**
2023
+ * 获取工具栏元素
2024
+ */
2025
+ getElement() {
2026
+ return this.toolbarElement;
2027
+ }
2028
+ /**
2029
+ * 更新左侧插槽内容
2030
+ */
2031
+ setLeftSlot(e) {
2032
+ var n;
2033
+ const t = (n = this.toolbarElement) == null ? void 0 : n.querySelector(".sl-toolbar-left");
2034
+ if (t && (t.innerHTML = "", e)) {
2035
+ const o = typeof e == "function" ? e() : e;
2036
+ o && t.appendChild(o);
2037
+ }
2038
+ }
2039
+ /**
2040
+ * 获取左侧区域元素
2041
+ */
2042
+ getLeftSection() {
2043
+ var e;
2044
+ return ((e = this.toolbarElement) == null ? void 0 : e.querySelector(".sl-toolbar-left")) || null;
2045
+ }
2046
+ /**
2047
+ * 销毁工具栏
2048
+ */
2049
+ destroy() {
2050
+ this.toolbarElement && (this.toolbarElement.remove(), this.toolbarElement = null), this.elements = {};
2051
+ }
2052
+ }
2053
+ class F {
2054
+ /**
2055
+ * 预处理数据:将 {value, isMarked} 格式转换为二维数组格式,并构建标记索引
2056
+ */
2057
+ static processRecords(e, t) {
2058
+ const n = /* @__PURE__ */ new Map();
2059
+ return { displayRecords: e.map((s, l) => Array.isArray(s) ? this.processArrayRow(s, l, n) : this.processObjectRow(s, l, t, n)), markedMap: n };
2060
+ }
2061
+ /**
2062
+ * 处理数组格式的行
2063
+ */
2064
+ static processArrayRow(e, t, n) {
2065
+ return e.map((o, s) => o && typeof o == "object" && "value" in o ? (o.isMarked && n.set(`${t}-${s}`, {
2066
+ isMarked: !0,
2067
+ comment: o.comment || ""
2068
+ }), o.value) : o);
2069
+ }
2070
+ /**
2071
+ * 处理对象格式的行
2072
+ */
2073
+ static processObjectRow(e, t, n, o) {
2074
+ return n.map((s, l) => {
2075
+ const i = s.field || s.key, a = e[i];
2076
+ return a && typeof a == "object" && "value" in a ? (a.isMarked && o.set(`${t}-${l}`, {
2077
+ isMarked: !0,
2078
+ comment: a.comment || ""
2079
+ }), a.value) : a;
2080
+ });
2081
+ }
2082
+ }
2083
+ const se = (c, e) => ({
2084
+ bgColor: "#FFEBEB",
2085
+ // 浅紫色背景
2086
+ color: "#FF4D50",
2087
+ // borderLineWidth: [0, 0, 0, 4], // 上、右、下、左边框宽度
2088
+ // borderColor: ["transparent", "transparent", "transparent", "#7B1FA2"], // 左边框为紫色
2089
+ // 标记样式(右上角三角形)
2090
+ marked: {
2091
+ shape: "triangle",
2092
+ bgColor: "#FF4D50",
2093
+ size: 8
2094
+ }
2095
+ // 或者简单使用: marked: true,
2096
+ });
2097
+ class z {
2098
+ /**
2099
+ * 初始化列配置,根据 markedMap 添加高亮样式,并应用 Excel 单元格样式
2100
+ */
2101
+ static initColumns(e, t, n) {
2102
+ return e.map((o, s) => {
2103
+ const l = o.style, i = { ...o };
2104
+ return i.style = (a) => {
2105
+ const d = a.row;
2106
+ let r = l ? l(a) : void 0;
2107
+ if (r = this.applyExcelStyle(
2108
+ r,
2109
+ d,
2110
+ s,
2111
+ n
2112
+ ), t.has(`${d}-${s}`)) {
2113
+ const h = se();
2114
+ return {
2115
+ ...r,
2116
+ ...h,
2117
+ bgColor: h.bgColor,
2118
+ color: h.color
2119
+ };
2120
+ }
2121
+ return r;
2122
+ }, i;
2123
+ });
2124
+ }
2125
+ /**
2126
+ * 应用 Excel 单元格样式
2127
+ */
2128
+ static applyExcelStyle(e, t, n, o) {
2129
+ if (!o) return e;
2130
+ const s = o.get(`${t}-${n}`);
2131
+ if (!s) return e;
2132
+ const l = e || {};
2133
+ return s.fontColor && (l.color = s.fontColor), s.bgColor && (l.bgColor = s.bgColor), s.bold && (l.fontWeight = "bold"), s.italic && (l.fontStyle = "italic"), l;
2134
+ }
2135
+ }
2136
+ class ie {
2137
+ constructor(e) {
2138
+ u(this, "tableSheet", null);
2139
+ u(this, "findReplaceDialog", null);
2140
+ u(this, "toolbar", null);
2141
+ u(this, "container", null);
2142
+ u(this, "tableContainer", null);
2143
+ u(this, "toolbarContainer", null);
2144
+ u(this, "config");
2145
+ /** Excel 单元格样式映射 */
2146
+ u(this, "excelCellStyles", null);
2147
+ this.config = {
2148
+ showToolbar: !0,
2149
+ ...e
2150
+ }, this.init();
2151
+ }
2152
+ /**
2153
+ * 初始化
2154
+ */
2155
+ init() {
2156
+ if (this.container = this.getContainer(this.config.container), !this.container)
2157
+ throw new Error("Container not found");
2158
+ this.createLayout(), this.config.showToolbar && this.createToolbar(), this.createTable(), this.createFindReplaceDialog(), this.injectStyles();
2159
+ }
2160
+ /**
2161
+ * 获取容器
2162
+ */
2163
+ getContainer(e) {
2164
+ return typeof e == "string" ? document.getElementById(e) || document.querySelector(e) : e;
2165
+ }
2166
+ /**
2167
+ * 创建布局
2168
+ */
2169
+ createLayout() {
2170
+ this.container && (this.container.innerHTML = "", this.container.className = "sl-table-sheet-wrapper", this.config.showToolbar && (this.toolbarContainer = document.createElement("div"), this.container.appendChild(this.toolbarContainer)), this.tableContainer = document.createElement("div"), this.tableContainer.className = "sl-table-container", this.container.appendChild(this.tableContainer));
2171
+ }
2172
+ /**
2173
+ * 创建工具栏
2174
+ */
2175
+ createToolbar() {
2176
+ this.toolbarContainer && (this.toolbar = new oe({
2177
+ container: this.toolbarContainer,
2178
+ title: "制表错误7",
2179
+ count: 2993,
2180
+ total: 12393,
2181
+ hint: "请在错误项里查询对应的数据或在数据里进行搜索",
2182
+ buttons: {
2183
+ search: !0,
2184
+ freeze: !0,
2185
+ export: !0,
2186
+ refresh: !0,
2187
+ list: !0
2188
+ },
2189
+ onSearchClick: () => this.openFindReplace(),
2190
+ onFreezeChange: (e) => this.freezeColumns(e),
2191
+ onListChange: () => console.log("列表"),
2192
+ ...this.config.toolbar
2193
+ }));
2194
+ }
2195
+ /**
2196
+ * 创建表格
2197
+ */
2198
+ createTable() {
2199
+ if (!this.tableContainer) return;
2200
+ const e = this.config.columns || [], { displayRecords: t, markedMap: n } = F.processRecords(
2201
+ this.config.records || [],
2202
+ e
2203
+ ), o = z.initColumns(e, n);
2204
+ this.tableSheet = new M(
2205
+ {
2206
+ container: this.tableContainer,
2207
+ columns: o,
2208
+ records: t,
2209
+ showFormulaBar: this.config.showFormulaBar,
2210
+ showSheetTab: this.config.showSheetTab,
2211
+ sheets: this.config.sheets,
2212
+ editors: this.config.editors,
2213
+ customComponents: this.config.customComponents,
2214
+ options: this.config.options,
2215
+ onCellChange: this.config.onCellChange
2216
+ },
2217
+ n
2218
+ );
2219
+ }
2220
+ /**
2221
+ * 创建查找替换弹窗
2222
+ */
2223
+ createFindReplaceDialog() {
2224
+ var t;
2225
+ const e = (t = this.tableSheet) == null ? void 0 : t.getTableInstance();
2226
+ e && (this.findReplaceDialog = new Y({
2227
+ tableInstance: e,
2228
+ selectedColumnsOnly: !1,
2229
+ // 默认搜索所有列
2230
+ onSearch: (n) => {
2231
+ console.log(`找到 ${n.length} 个匹配项`);
2232
+ },
2233
+ onReplace: (n, o) => {
2234
+ console.log("替换成功:", n, "->", o);
2235
+ }
2236
+ }));
2237
+ }
2238
+ /**
2239
+ * 打开查找替换弹窗
2240
+ */
2241
+ openFindReplace() {
2242
+ var e;
2243
+ (e = this.findReplaceDialog) == null || e.open();
2244
+ }
2245
+ /**
2246
+ * 冻结列
2247
+ */
2248
+ freezeColumns(e) {
2249
+ console.log("冻结前列", e);
2250
+ }
2251
+ /**
2252
+ * 注入样式
2253
+ */
2254
+ injectStyles() {
2255
+ if (document.getElementById("sl-table-sheet-styles")) return;
2256
+ const e = document.createElement("style");
2257
+ e.id = "sl-table-sheet-styles", e.textContent = `
2258
+ .sl-table-sheet-wrapper {
2259
+ display: flex;
2260
+ flex-direction: column;
2261
+ height: 100%;
2262
+ background: #fff;
2263
+ }
2264
+ .sl-table-container {
2265
+ flex: 1;
2266
+ overflow: hidden;
2267
+ position: relative;
2268
+ margin-top:12px;
2269
+ }
2270
+ `, document.head.appendChild(e);
2271
+ }
2272
+ /**
2273
+ * 更新标题统计
2274
+ */
2275
+ updateTitleStats(e, t) {
2276
+ var n;
2277
+ (n = this.toolbar) == null || n.updateStats(e, t);
2278
+ }
2279
+ /**
2280
+ * 获取 TableSheet 实例
2281
+ */
2282
+ getTableSheet() {
2283
+ return this.tableSheet;
2284
+ }
2285
+ /**
2286
+ * 获取表格实例
2287
+ */
2288
+ getTableInstance() {
2289
+ var e;
2290
+ return (e = this.tableSheet) == null ? void 0 : e.getTableInstance();
2291
+ }
2292
+ /**
2293
+ * 获取查找替换弹窗实例
2294
+ */
2295
+ getFindReplaceDialog() {
2296
+ return this.findReplaceDialog;
2297
+ }
2298
+ /**
2299
+ * 设置查找替换是否只搜索选中列
2300
+ */
2301
+ setFindReplaceSelectedColumnsOnly(e) {
2302
+ this.findReplaceDialog && this.findReplaceDialog.setSelectedColumnsOnly(e);
2303
+ }
2304
+ /**
2305
+ * 更新数据
2306
+ */
2307
+ updateData(e) {
2308
+ var t;
2309
+ (t = this.tableSheet) == null || t.updateData(e);
2310
+ }
2311
+ /**
2312
+ * 更新列配置
2313
+ */
2314
+ updateColumns(e) {
2315
+ var t;
2316
+ (t = this.tableSheet) == null || t.updateColumns(e);
2317
+ }
2318
+ /**
2319
+ * 导出数据
2320
+ */
2321
+ exportData(e = "csv") {
2322
+ var t;
2323
+ return (t = this.tableSheet) == null ? void 0 : t.exportData(e);
2324
+ }
2325
+ /**
2326
+ * 导出数据为 Excel 流 (ArrayBuffer)
2327
+ * @param options 导出选项
2328
+ * @returns Excel 文件的 ArrayBuffer
2329
+ */
2330
+ exportToExcelStream(e) {
2331
+ const t = this.config.columns || [], n = this.config.records || [];
2332
+ return P(t, n, e);
2333
+ }
2334
+ /**
2335
+ * 下载 Excel 文件
2336
+ * @param filename 文件名(不含扩展名)
2337
+ */
2338
+ downloadExcel(e = "export") {
2339
+ const t = this.exportToExcelStream();
2340
+ q(t, e);
2341
+ }
2342
+ /**
2343
+ * 解析在线 Excel 文件并显示到表格
2344
+ * @param url Excel 文件的 URL 地址
2345
+ * @param options 解析选项
2346
+ * @returns 解析后的列配置和数据
2347
+ */
2348
+ async loadExcelFromUrl(e, t = {}) {
2349
+ const { autoDisplay: n = !0, ...o } = t, s = await H(e, o);
2350
+ return this.handleExcelImportResult(s, n), s;
2351
+ }
2352
+ /**
2353
+ * 解析 Excel ArrayBuffer 并显示到表格
2354
+ * @param buffer Excel 文件的 ArrayBuffer
2355
+ * @param options 解析选项
2356
+ * @returns 解析后的列配置和数据
2357
+ */
2358
+ parseExcelBuffer(e, t = {}) {
2359
+ const { autoDisplay: n = !0, ...o } = t, s = S(e, o);
2360
+ return this.handleExcelImportResult(s, n), s;
2361
+ }
2362
+ /**
2363
+ * 从 File 对象解析 Excel 文件
2364
+ * @param file File 对象
2365
+ * @param options 解析选项
2366
+ * @returns 解析后的列配置和数据
2367
+ */
2368
+ async parseExcelFile(e, t = {}) {
2369
+ const { autoDisplay: n = !0, ...o } = t, s = await _(e, o);
2370
+ return this.handleExcelImportResult(s, n), s;
2371
+ }
2372
+ /**
2373
+ * 处理 Excel 导入结果
2374
+ */
2375
+ handleExcelImportResult(e, t) {
2376
+ var s;
2377
+ console.log("handleExcelImportResult 调用:", {
2378
+ columns: e.columns.length,
2379
+ records: e.records.length,
2380
+ autoDisplay: t,
2381
+ hasTableSheet: !!this.tableSheet
2382
+ }), this.excelCellStyles = e.cellStyles || null;
2383
+ const n = z.initColumns(
2384
+ e.columns,
2385
+ /* @__PURE__ */ new Map(),
2386
+ this.excelCellStyles
2387
+ );
2388
+ this.config.columns = n;
2389
+ let o = e.records;
2390
+ if (e.cellComments && e.cellComments.size > 0 ? (console.log("处理 Excel 标注数据:", e.cellComments.size, "个标注"), console.log("所有标注数据:"), e.cellComments.forEach((l, i) => {
2391
+ console.log(` ${i}:`, l);
2392
+ }), o = e.records.map((l, i) => l.map((a, d) => {
2393
+ const r = `${i}-${d}`, h = e.cellComments.get(r);
2394
+ return h ? (console.log(`单元格 [${i},${d}] 有标注:`, h), {
2395
+ value: a,
2396
+ isMarked: !0,
2397
+ comment: h.text || ""
2398
+ }) : a;
2399
+ })), console.log("标注处理完成,第一条记录:", o[0])) : console.log("没有找到标注数据"), this.config.records = o, t && this.tableSheet)
2400
+ try {
2401
+ console.log("尝试更新现有表格..."), console.log("更新前表格状态:", {
2402
+ hasTableInstance: !!this.tableSheet,
2403
+ container: this.tableContainer,
2404
+ containerVisible: ((s = this.tableContainer) == null ? void 0 : s.offsetParent) !== null
2405
+ }), this.tableSheet.updateColumns(n), this.tableSheet.updateData(this.config.records), console.log("表格更新成功,更新后状态:", {
2406
+ recordsCount: this.config.records.length,
2407
+ columnsCount: n.length,
2408
+ firstRecord: this.config.records[0]
2409
+ }), console.log("强制重新创建表格以确保数据正确显示"), setTimeout(() => {
2410
+ this.recreateTable(n, this.config.records || []);
2411
+ }, 100);
2412
+ } catch (l) {
2413
+ console.warn("动态更新失败,尝试重新创建表格:", l), this.recreateTable(n, this.config.records || []);
2414
+ }
2415
+ else
2416
+ console.log("跳过自动显示:", {
2417
+ autoDisplay: t,
2418
+ hasTableSheet: !!this.tableSheet
2419
+ });
2420
+ this.config.onExcelImport && this.config.onExcelImport(e);
2421
+ }
2422
+ /**
2423
+ * 重新创建表格实例
2424
+ */
2425
+ recreateTable(e, t) {
2426
+ console.log("重新创建表格:", {
2427
+ columnCount: e.length,
2428
+ recordCount: t.length
2429
+ }), this.tableSheet && (this.tableSheet.destroy(), this.tableSheet = null);
2430
+ const { displayRecords: n, markedMap: o } = F.processRecords(
2431
+ t,
2432
+ e
2433
+ );
2434
+ this.tableSheet = new M(
2435
+ {
2436
+ container: this.tableContainer,
2437
+ columns: e,
2438
+ records: n,
2439
+ showFormulaBar: this.config.showFormulaBar,
2440
+ showSheetTab: this.config.showSheetTab,
2441
+ sheets: this.config.sheets,
2442
+ editors: this.config.editors,
2443
+ customComponents: this.config.customComponents,
2444
+ options: this.config.options,
2445
+ onCellChange: this.config.onCellChange
2446
+ },
2447
+ o
2448
+ ), this.updateFindReplaceTableInstance(), console.log("表格重新创建完成,标记单元格数:", o.size);
2449
+ }
2450
+ /**
2451
+ * 更新查找替换弹窗的表格实例引用
2452
+ */
2453
+ updateFindReplaceTableInstance() {
2454
+ var t;
2455
+ const e = (t = this.tableSheet) == null ? void 0 : t.getTableInstance();
2456
+ e && this.findReplaceDialog && this.findReplaceDialog.setTableInstance(e);
2457
+ }
2458
+ /**
2459
+ * 刷新表格
2460
+ */
2461
+ refresh() {
2462
+ var e;
2463
+ (e = this.tableSheet) == null || e.refresh();
2464
+ }
2465
+ /**
2466
+ * 监听事件
2467
+ */
2468
+ on(e, t) {
2469
+ var n;
2470
+ (n = this.tableSheet) == null || n.on(e, t);
2471
+ }
2472
+ /**
2473
+ * 取消监听事件
2474
+ */
2475
+ off(e, t) {
2476
+ var n;
2477
+ (n = this.tableSheet) == null || n.off(e, t);
2478
+ }
2479
+ /**
2480
+ * 获取工具栏实例
2481
+ */
2482
+ getToolbar() {
2483
+ return this.toolbar;
2484
+ }
2485
+ /**
2486
+ * 销毁实例
2487
+ */
2488
+ destroy() {
2489
+ var e, t, n;
2490
+ (e = this.toolbar) == null || e.destroy(), (t = this.findReplaceDialog) == null || t.destroy(), (n = this.tableSheet) == null || n.destroy(), this.container && (this.container.innerHTML = ""), this.toolbar = null, this.tableSheet = null, this.findReplaceDialog = null, this.container = null, this.tableContainer = null, this.toolbarContainer = null;
2491
+ }
2492
+ }
2493
+ export {
2494
+ ie as default,
2495
+ j as fetchExcelFromUrl,
2496
+ H as loadExcelFromUrl,
2497
+ S as parseExcelBuffer,
2498
+ _ as parseExcelFile
2499
+ };