zmdms-webui 2.6.1 → 2.6.3

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,192 @@
1
+ import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, SCROLLBAR_SIZE } from '../../utils/constants.js';
2
+ import { drawCheckbox, truncateText } from '../../utils/canvasDrawHelpers.js';
3
+ import { formatCellValue } from '../../utils/formatHelpers.js';
4
+ import '../../../_virtual/_tslib.js';
5
+ import { setTextAlign, calculateTextX } from '../../utils/renderHelpers.js';
6
+
7
+ /**
8
+ * 固定行渲染器
9
+ * 负责渲染固定的顶部行、底部行和合计行
10
+ */
11
+ var FixedRowRenderer = /** @class */ (function () {
12
+ function FixedRowRenderer() {
13
+ this.context = null;
14
+ }
15
+ FixedRowRenderer.prototype.setContext = function (context) {
16
+ this.context = context;
17
+ };
18
+ /**
19
+ * 渲染固定顶部�?
20
+ */
21
+ FixedRowRenderer.prototype.renderFixedTopRows = function (onlyFixed) {
22
+ var _this = this;
23
+ if (onlyFixed === void 0) { onlyFixed = false; }
24
+ if (!this.context) {
25
+ throw new Error("FixedRowRenderer: Context not set");
26
+ }
27
+ var _a = this.context, fixedRowsCount = _a.fixedRowsCount, fixedRowsConfig = _a.fixedRowsConfig;
28
+ var fixedTopCount = fixedRowsCount || (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.topCount) || 0;
29
+ for (var i = 0; i < fixedTopCount; i++) {
30
+ this.renderFixedRow(i, "top", function (idx) { return _this.context.headerHeight + idx * _this.context.rowHeight; }, onlyFixed);
31
+ }
32
+ };
33
+ /**
34
+ * 渲染固定底部�?
35
+ */
36
+ FixedRowRenderer.prototype.renderFixedBottomRows = function (onlyFixed) {
37
+ if (onlyFixed === void 0) { onlyFixed = false; }
38
+ if (!this.context) {
39
+ throw new Error("FixedRowRenderer: Context not set");
40
+ }
41
+ var _a = this.context, processedDataSource = _a.processedDataSource, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, rowHeight = _a.rowHeight, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, fixedRowsConfig = _a.fixedRowsConfig;
42
+ var fixedBottomCount = (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.bottomCount) || 0;
43
+ if (fixedBottomCount === 0)
44
+ return;
45
+ var bottomRowsStartIndex = processedDataSource.length -
46
+ fixedBottomCount -
47
+ (summaryFixed && hasSummaryRow ? 1 : 0);
48
+ var _loop_1 = function (i) {
49
+ var rowIndex = bottomRowsStartIndex + i;
50
+ this_1.renderFixedRow(rowIndex, "bottom", function () {
51
+ var fixedSummaryHeight = summaryFixed && hasSummaryRow ? rowHeight : 0;
52
+ return (displayHeight -
53
+ (needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
54
+ fixedSummaryHeight -
55
+ fixedBottomCount * rowHeight +
56
+ i * rowHeight);
57
+ }, onlyFixed);
58
+ };
59
+ var this_1 = this;
60
+ for (var i = 0; i < fixedBottomCount; i++) {
61
+ _loop_1(i);
62
+ }
63
+ };
64
+ /**
65
+ * 渲染固定合计�?
66
+ */
67
+ FixedRowRenderer.prototype.renderFixedSummaryRow = function (onlyFixed) {
68
+ if (onlyFixed === void 0) { onlyFixed = false; }
69
+ if (!this.context) {
70
+ throw new Error("FixedRowRenderer: Context not set");
71
+ }
72
+ var _a = this.context, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, processedDataSource = _a.processedDataSource, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, rowHeight = _a.rowHeight;
73
+ if (!summaryFixed || !hasSummaryRow)
74
+ return;
75
+ var summaryRowIndex = processedDataSource.length - 1;
76
+ var summaryRowY = displayHeight -
77
+ (needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
78
+ rowHeight;
79
+ this.renderFixedRow(summaryRowIndex, "summary", function () { return summaryRowY; }, onlyFixed);
80
+ };
81
+ /**
82
+ * 通用的固定行渲染函数
83
+ */
84
+ FixedRowRenderer.prototype.renderFixedRow = function (rowIndex, position, yCalculator, onlyFixed) {
85
+ if (onlyFixed === void 0) { onlyFixed = false; }
86
+ if (!this.context)
87
+ return;
88
+ var _a = this.context, ctx = _a.ctx, processedDataSource = _a.processedDataSource, columnRenderInfos = _a.columnRenderInfos, rowHeight = _a.rowHeight, scrollState = _a.scrollState, state = _a.state, getRowKey = _a.getRowKey, displayWidth = _a.displayWidth, fixedRowsConfig = _a.fixedRowsConfig, striped = _a.striped, getColumnWidth = _a.getColumnWidth;
89
+ var record = processedDataSource[rowIndex];
90
+ if (!record)
91
+ return;
92
+ var fixedY = yCalculator(rowIndex);
93
+ ctx.save();
94
+ var recordKey = getRowKey(record, rowIndex);
95
+ var isSelected = state.selectedRowKeys.includes(recordKey);
96
+ var isHover = state.hoverRowIndex === rowIndex;
97
+ columnRenderInfos.forEach(function (info, colIndex) {
98
+ var _a;
99
+ var column = info.column, x = info.x, width = info.width, fixed = info.fixed, fixedLeft = info.fixedLeft;
100
+ // 根据 onlyFixed 参数过滤
101
+ if (onlyFixed && !fixed)
102
+ return;
103
+ if (!onlyFixed && fixed)
104
+ return;
105
+ var actualWidth = getColumnWidth ? getColumnWidth(colIndex) : width;
106
+ var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
107
+ // 跳过不可见的�?
108
+ if (!fixed && (drawX + actualWidth < 0 || drawX > displayWidth)) {
109
+ return;
110
+ }
111
+ // 绘制背景
112
+ var bgColor = COLORS.white;
113
+ if ((_a = fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.style) === null || _a === void 0 ? void 0 : _a.backgroundColor) {
114
+ bgColor = fixedRowsConfig.style.backgroundColor;
115
+ }
116
+ else {
117
+ if (isSelected) {
118
+ bgColor = COLORS.selectedBg;
119
+ }
120
+ else if (isHover) {
121
+ bgColor = COLORS.hoverBg;
122
+ }
123
+ else if (striped && rowIndex % 2 === 1) {
124
+ bgColor = COLORS.stripedBg;
125
+ }
126
+ }
127
+ ctx.fillStyle = bgColor;
128
+ ctx.fillRect(drawX, fixedY, actualWidth, rowHeight);
129
+ // 处理序号�?
130
+ if (column.key === "__index__") {
131
+ if (position !== "summary") {
132
+ var indexText = String(rowIndex + 1);
133
+ ctx.fillStyle = COLORS.text;
134
+ ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
135
+ ctx.textBaseline = "middle";
136
+ setTextAlign(ctx, "center");
137
+ var textX = drawX + actualWidth / 2;
138
+ var textY = fixedY + rowHeight / 2;
139
+ ctx.fillText(indexText, textX, textY);
140
+ return;
141
+ }
142
+ }
143
+ // 处理选择框列
144
+ if (column.key === "__selection__") {
145
+ if (position !== "summary") {
146
+ var checkboxX = drawX + actualWidth / 2;
147
+ var textY = fixedY + rowHeight / 2;
148
+ drawCheckbox(ctx, checkboxX, textY, isSelected, false, false);
149
+ return;
150
+ }
151
+ }
152
+ // 获取单元格�?
153
+ var dataIndex = column.dataIndex || column.key;
154
+ var cellValue = record[dataIndex];
155
+ // 渲染单元格内�?
156
+ var cellText = formatCellValue(cellValue, column);
157
+ // 检查是否有render函数且返回自定义ReactNode
158
+ var shouldRenderInCanvas = true;
159
+ var isSummaryRowFixed = position === "summary";
160
+ if (column.render && !isSummaryRowFixed) {
161
+ var rendered = column.render(cellValue, record, rowIndex);
162
+ if (typeof rendered !== "string" &&
163
+ typeof rendered !== "number" &&
164
+ rendered !== null &&
165
+ rendered !== undefined) {
166
+ shouldRenderInCanvas = false;
167
+ }
168
+ }
169
+ // 只有在需要在Canvas中渲染时才绘制文�?
170
+ if (cellText && shouldRenderInCanvas) {
171
+ ctx.fillStyle = COLORS.text;
172
+ ctx.font =
173
+ position === "summary"
174
+ ? "bold ".concat(FONT_SIZE, "px ").concat(FONT_FAMILY)
175
+ : "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
176
+ ctx.textBaseline = "middle";
177
+ var align = column.align || "left";
178
+ setTextAlign(ctx, align);
179
+ var padding = 5;
180
+ var maxWidth = actualWidth - padding * 2;
181
+ var textY = fixedY + rowHeight / 2;
182
+ var textX = calculateTextX(drawX, actualWidth, align, padding);
183
+ var truncatedText = truncateText(ctx, cellText, maxWidth);
184
+ ctx.fillText(truncatedText, textX, textY);
185
+ }
186
+ });
187
+ ctx.restore();
188
+ };
189
+ return FixedRowRenderer;
190
+ }());
191
+
192
+ export { FixedRowRenderer };
@@ -0,0 +1,395 @@
1
+ import { isValidElement } from 'react';
2
+ import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, TEXT_PADDING } from '../../utils/constants.js';
3
+ import { drawCheckbox, wrapText, truncateText, drawFilterIcon, drawSortIcon } from '../../utils/canvasDrawHelpers.js';
4
+ import { getMaxDepth, flattenHeaders, calculateLayerHeights, getLeafColumns } from '../../utils/multiHeaderHelpers.js';
5
+ import 'zmdms-utils';
6
+ import 'dayjs';
7
+ import { calculateSelectionState, calculateIconArea } from '../../utils/interactionHelpers.js';
8
+ import '../../../_virtual/_tslib.js';
9
+
10
+ /**
11
+ * 表头渲染�?
12
+ * 负责渲染单层和多层表�?
13
+ */
14
+ var HeaderRenderer = /** @class */ (function () {
15
+ function HeaderRenderer() {
16
+ this.context = null;
17
+ this.isMultiHeader = false;
18
+ this.flattenedHeaderRows = [];
19
+ this.layerHeights = [];
20
+ this.layerStartY = [];
21
+ }
22
+ HeaderRenderer.prototype.setContext = function (context) {
23
+ this.context = context;
24
+ // 判断是否是多级表�?
25
+ var maxDepth = getMaxDepth(context.columns);
26
+ this.isMultiHeader = maxDepth > 1;
27
+ // 扁平化多级表头(如果需要)
28
+ if (this.isMultiHeader) {
29
+ this.flattenedHeaderRows = flattenHeaders(context.columns);
30
+ }
31
+ // 计算多级表头每一层的高度
32
+ var _a = calculateLayerHeights(context.columns, context.baseHeaderHeight ||
33
+ (maxDepth > 1
34
+ ? Math.floor(context.headerHeight / maxDepth)
35
+ : context.headerHeight), context.columnRenderInfos), layerHeights = _a.layerHeights, layerStartY = _a.layerStartY;
36
+ this.layerHeights = layerHeights;
37
+ this.layerStartY = layerStartY;
38
+ };
39
+ /**
40
+ * 渲染表头主入�?
41
+ */
42
+ HeaderRenderer.prototype.render = function () {
43
+ if (!this.context) {
44
+ throw new Error("HeaderRenderer: Context not set");
45
+ }
46
+ var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, headerHeight = _a.headerHeight;
47
+ // 表头背景
48
+ ctx.fillStyle = COLORS.headerBg;
49
+ ctx.fillRect(0, 0, displayWidth, headerHeight);
50
+ if (this.isMultiHeader) {
51
+ this.renderMultiHeader();
52
+ }
53
+ else {
54
+ this.renderSingleHeader();
55
+ }
56
+ };
57
+ /**
58
+ * 渲染单层表头
59
+ */
60
+ HeaderRenderer.prototype.renderSingleHeader = function () {
61
+ var _this = this;
62
+ if (!this.context)
63
+ return;
64
+ var _a = this.context, columnRenderInfos = _a.columnRenderInfos, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight;
65
+ // 先绘制非fixed�?
66
+ columnRenderInfos.forEach(function (info, index) {
67
+ if (!info.fixed) {
68
+ _this.renderHeaderCell(info, index, displayWidth, displayHeight, false);
69
+ }
70
+ });
71
+ // 再绘制fixed列(覆盖在非fixed列之上)
72
+ columnRenderInfos.forEach(function (info, index) {
73
+ if (info.fixed) {
74
+ _this.renderHeaderCell(info, index, displayWidth, displayHeight, false);
75
+ }
76
+ });
77
+ };
78
+ /**
79
+ * 渲染多层表头
80
+ */
81
+ HeaderRenderer.prototype.renderMultiHeader = function () {
82
+ var _this = this;
83
+ if (!this.context)
84
+ return;
85
+ var displayWidth = this.context.displayWidth;
86
+ // 先绘制非fixed�?
87
+ this.flattenedHeaderRows.forEach(function (headerRow, rowIndex) {
88
+ var y = _this.layerStartY[rowIndex];
89
+ headerRow.forEach(function (headerCell) {
90
+ // 计算单元格的总高度(如果跨越多层�?
91
+ var totalCellHeight = 0;
92
+ for (var i = rowIndex; i < rowIndex + headerCell.rowSpan; i++) {
93
+ totalCellHeight += _this.layerHeights[i];
94
+ }
95
+ _this.renderMultiHeaderCell(headerCell, y, displayWidth, rowIndex, totalCellHeight, false);
96
+ });
97
+ });
98
+ // 再绘制fixed列(覆盖在非fixed列之上)
99
+ this.flattenedHeaderRows.forEach(function (headerRow, rowIndex) {
100
+ var y = _this.layerStartY[rowIndex];
101
+ headerRow.forEach(function (headerCell) {
102
+ // 计算单元格的总高度(如果跨越多层�?
103
+ var totalCellHeight = 0;
104
+ for (var i = rowIndex; i < rowIndex + headerCell.rowSpan; i++) {
105
+ totalCellHeight += _this.layerHeights[i];
106
+ }
107
+ _this.renderMultiHeaderCell(headerCell, y, displayWidth, rowIndex, totalCellHeight, true);
108
+ });
109
+ });
110
+ };
111
+ /**
112
+ * 渲染单个表头单元格(单层表头�?
113
+ */
114
+ HeaderRenderer.prototype.renderHeaderCell = function (info, index, displayWidth, displayHeight, onlyFixed) {
115
+ if (!this.context)
116
+ return;
117
+ var _a = this.context, ctx = _a.ctx, scrollState = _a.scrollState, headerHeight = _a.headerHeight, bordered = _a.bordered, state = _a.state, processedDataSource = _a.processedDataSource, getRowKey = _a.getRowKey, rowSelection = _a.rowSelection, resizeState = _a.resizeState, getColumnWidth = _a.getColumnWidth, _b = _a.RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_WIDTH = _b === void 0 ? 8 : _b, headerAlign = _a.headerAlign;
118
+ var column = info.column, x = info.x, fixed = info.fixed, fixedLeft = info.fixedLeft;
119
+ var width = getColumnWidth ? getColumnWidth(index) : info.width;
120
+ var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
121
+ // 跳过不在可视区域的列
122
+ if (!fixed && (drawX + width < 0 || drawX > displayWidth)) {
123
+ return;
124
+ }
125
+ // 绘制表头单元�?
126
+ ctx.save();
127
+ ctx.beginPath();
128
+ ctx.rect(drawX, 0, width, headerHeight);
129
+ ctx.clip();
130
+ // 绘制单元格背�?
131
+ ctx.fillStyle = COLORS.headerBg;
132
+ ctx.fillRect(drawX, 0, width, headerHeight);
133
+ // 表头文本
134
+ ctx.fillStyle = COLORS.text;
135
+ ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
136
+ ctx.textBaseline = "middle";
137
+ var textY = headerHeight / 2;
138
+ // 绘制选择�?
139
+ if (column.key === "__selection__") {
140
+ var selectionState = calculateSelectionState(processedDataSource, state.selectedRowKeys, getRowKey, rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.getCheckboxProps);
141
+ var checkboxX = drawX + width / 2;
142
+ drawCheckbox(ctx, checkboxX, textY, selectionState.isAllSelected, false, selectionState.isIndeterminate);
143
+ }
144
+ else {
145
+ // 计算图标占用的宽�?
146
+ var iconArea = calculateIconArea(column, width);
147
+ // 确定表头对齐方式
148
+ var columnHeaderAlign = column.headerAlign || headerAlign;
149
+ // 绘制文本
150
+ if (!isValidElement(column.title)) {
151
+ var titleText = String(column.title || "");
152
+ var textX_1;
153
+ var textMaxWidth = void 0;
154
+ if (iconArea.iconsWidth > 0) {
155
+ if (columnHeaderAlign === "right") {
156
+ ctx.textAlign = "right";
157
+ textX_1 = drawX + width - TEXT_PADDING - iconArea.iconsWidth;
158
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
159
+ }
160
+ else if (columnHeaderAlign === "center") {
161
+ ctx.textAlign = "center";
162
+ textX_1 = drawX + (width - iconArea.iconsWidth) / 2;
163
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
164
+ }
165
+ else {
166
+ ctx.textAlign = "left";
167
+ textX_1 = drawX + TEXT_PADDING;
168
+ textMaxWidth = width - TEXT_PADDING - iconArea.iconsWidth;
169
+ }
170
+ }
171
+ else {
172
+ if (columnHeaderAlign === "left") {
173
+ ctx.textAlign = "left";
174
+ textX_1 = drawX + TEXT_PADDING;
175
+ textMaxWidth = width - TEXT_PADDING * 2;
176
+ }
177
+ else if (columnHeaderAlign === "right") {
178
+ ctx.textAlign = "right";
179
+ textX_1 = drawX + width - TEXT_PADDING;
180
+ textMaxWidth = width - TEXT_PADDING * 2;
181
+ }
182
+ else {
183
+ ctx.textAlign = "center";
184
+ textX_1 = drawX + width / 2;
185
+ textMaxWidth = width - TEXT_PADDING * 2;
186
+ }
187
+ }
188
+ if (column.wrap) {
189
+ var lines = wrapText(ctx, titleText, textMaxWidth);
190
+ var lineHeight_1 = FONT_SIZE + 5;
191
+ var startY_1 = textY - ((lines.length - 1) * lineHeight_1) / 2;
192
+ lines.forEach(function (line, idx) {
193
+ var lineY = startY_1 + idx * lineHeight_1;
194
+ ctx.fillText(line, textX_1, lineY);
195
+ });
196
+ }
197
+ else {
198
+ var truncatedText = truncateText(ctx, titleText, textMaxWidth);
199
+ ctx.fillText(truncatedText, textX_1, textY);
200
+ }
201
+ }
202
+ // 绘制筛选图�?
203
+ if (iconArea.hasFilter) {
204
+ var iconX = drawX + width - 10;
205
+ var hasFilterValue = state.filters[column.key] && state.filters[column.key].length > 0;
206
+ drawFilterIcon(ctx, iconX, textY, hasFilterValue);
207
+ }
208
+ // 绘制排序图标
209
+ if (iconArea.hasOrder) {
210
+ var iconX = drawX + width - (iconArea.hasFilter ? 24 : 10);
211
+ drawSortIcon(ctx, iconX, textY, column.key === state.sortField ? state.sortOrder : null);
212
+ }
213
+ }
214
+ ctx.textAlign = "left";
215
+ ctx.restore();
216
+ // 绘制表头列之间的边框
217
+ if (bordered) {
218
+ ctx.strokeStyle = COLORS.border;
219
+ ctx.lineWidth = 2;
220
+ ctx.beginPath();
221
+ ctx.moveTo(drawX + width, 0);
222
+ ctx.lineTo(drawX + width, headerHeight);
223
+ ctx.stroke();
224
+ }
225
+ // 绘制列宽调整手柄
226
+ if (column.key !== "__selection__" && resizeState) {
227
+ var isHover = resizeState.hoverResizeColumnIndex === index;
228
+ var isResizing = resizeState.resizingColumnIndex === index;
229
+ if (isHover || isResizing) {
230
+ var handleX = drawX + width - RESIZE_HANDLE_WIDTH / 2;
231
+ ctx.fillStyle = isResizing ? "#1890ff" : "rgba(24, 144, 255, 0.3)";
232
+ ctx.fillRect(handleX, 0, RESIZE_HANDLE_WIDTH, headerHeight);
233
+ if (isResizing) {
234
+ ctx.strokeStyle = "#1890ff";
235
+ ctx.lineWidth = 1;
236
+ ctx.setLineDash([4, 4]);
237
+ ctx.beginPath();
238
+ ctx.moveTo(drawX + width, 0);
239
+ ctx.lineTo(drawX + width, displayHeight);
240
+ ctx.stroke();
241
+ ctx.setLineDash([]);
242
+ }
243
+ }
244
+ }
245
+ };
246
+ /**
247
+ * 渲染多层表头单元�?
248
+ */
249
+ HeaderRenderer.prototype.renderMultiHeaderCell = function (headerCell, y, displayWidth, currentDepth, totalCellHeight, onlyFixed) {
250
+ if (onlyFixed === void 0) { onlyFixed = false; }
251
+ if (!this.context)
252
+ return;
253
+ var _a = this.context, ctx = _a.ctx, scrollState = _a.scrollState, bordered = _a.bordered, state = _a.state, processedDataSource = _a.processedDataSource, getRowKey = _a.getRowKey, rowSelection = _a.rowSelection, columnRenderInfos = _a.columnRenderInfos, columns = _a.columns, getColumnWidth = _a.getColumnWidth, headerAlign = _a.headerAlign;
254
+ var column = headerCell.column, colSpan = headerCell.colSpan, rowSpan = headerCell.rowSpan, colIndex = headerCell.colIndex;
255
+ // 计算x位置和宽�?
256
+ var x = 0;
257
+ var width = 0;
258
+ var isFixed = false;
259
+ var fixedLeft = 0;
260
+ var leafColumns = getLeafColumns(columns);
261
+ for (var i = 0; i < leafColumns.length; i++) {
262
+ var leafInfo = columnRenderInfos[i];
263
+ if (i < colIndex) {
264
+ x += getColumnWidth ? getColumnWidth(i) : leafInfo.width;
265
+ }
266
+ else if (i < colIndex + colSpan) {
267
+ width += getColumnWidth ? getColumnWidth(i) : leafInfo.width;
268
+ if (leafInfo.fixed) {
269
+ isFixed = true;
270
+ if (i === colIndex) {
271
+ fixedLeft = leafInfo.fixedLeft;
272
+ }
273
+ }
274
+ }
275
+ }
276
+ // 根据 onlyFixed 参数过滤
277
+ if (onlyFixed && !isFixed)
278
+ return;
279
+ if (!onlyFixed && isFixed)
280
+ return;
281
+ var drawX = isFixed ? fixedLeft : x - scrollState.scrollLeft;
282
+ // 跳过不在可视区域的列
283
+ if (!isFixed && (drawX + width < 0 || drawX > displayWidth)) {
284
+ return;
285
+ }
286
+ // 绘制单元格背�?
287
+ ctx.fillStyle = COLORS.headerBg;
288
+ ctx.fillRect(drawX, y, width, totalCellHeight);
289
+ // 绘制边框
290
+ if (bordered) {
291
+ ctx.strokeStyle = COLORS.border;
292
+ ctx.lineWidth = 1;
293
+ ctx.strokeRect(drawX, y, width, totalCellHeight);
294
+ }
295
+ var maxDepth = getMaxDepth(columns);
296
+ var isLastLevel = currentDepth + rowSpan === maxDepth;
297
+ var isSpecialColumn = column.key === "__selection__" || column.key === "__index__";
298
+ var textY = y + totalCellHeight / 2;
299
+ // 绘制选择�?
300
+ if (column.key === "__selection__" && currentDepth === 0) {
301
+ var selectionState = calculateSelectionState(processedDataSource, state.selectedRowKeys, getRowKey, rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.getCheckboxProps);
302
+ var checkboxX = drawX + width / 2;
303
+ drawCheckbox(ctx, checkboxX, textY, selectionState.isAllSelected, false, selectionState.isIndeterminate);
304
+ }
305
+ else {
306
+ // 绘制文本
307
+ ctx.fillStyle = COLORS.text;
308
+ ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
309
+ ctx.textBaseline = "middle";
310
+ if (!isValidElement(column.title)) {
311
+ var titleText = String(column.title || "");
312
+ var shouldShowIcons = isLastLevel && !isSpecialColumn;
313
+ var iconArea = shouldShowIcons
314
+ ? calculateIconArea(column, width)
315
+ : { hasOrder: false, hasFilter: false, iconsWidth: 0 };
316
+ var columnHeaderAlign = column.headerAlign || headerAlign;
317
+ if (isLastLevel && iconArea.iconsWidth > 0) {
318
+ var textX_2;
319
+ var textMaxWidth = void 0;
320
+ if (columnHeaderAlign === "right") {
321
+ ctx.textAlign = "right";
322
+ textX_2 = drawX + width - TEXT_PADDING - iconArea.iconsWidth;
323
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
324
+ }
325
+ else if (columnHeaderAlign === "center") {
326
+ ctx.textAlign = "center";
327
+ textX_2 = drawX + (width - iconArea.iconsWidth) / 2;
328
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
329
+ }
330
+ else {
331
+ ctx.textAlign = "left";
332
+ textX_2 = drawX + TEXT_PADDING;
333
+ textMaxWidth = width - TEXT_PADDING - iconArea.iconsWidth;
334
+ }
335
+ if (column.wrap) {
336
+ var lines = wrapText(ctx, titleText, textMaxWidth);
337
+ var lineHeight_2 = FONT_SIZE + 5;
338
+ var startY_2 = textY - ((lines.length - 1) * lineHeight_2) / 2;
339
+ lines.forEach(function (line, idx) {
340
+ var lineY = startY_2 + idx * lineHeight_2;
341
+ ctx.fillText(line, textX_2, lineY);
342
+ });
343
+ }
344
+ else {
345
+ var truncated = truncateText(ctx, titleText, textMaxWidth);
346
+ ctx.fillText(truncated, textX_2, textY);
347
+ }
348
+ }
349
+ else {
350
+ var textX_3;
351
+ if (columnHeaderAlign === "left") {
352
+ ctx.textAlign = "left";
353
+ textX_3 = drawX + TEXT_PADDING;
354
+ }
355
+ else if (columnHeaderAlign === "right") {
356
+ ctx.textAlign = "right";
357
+ textX_3 = drawX + width - TEXT_PADDING;
358
+ }
359
+ else {
360
+ ctx.textAlign = "center";
361
+ textX_3 = drawX + width / 2;
362
+ }
363
+ if (column.wrap) {
364
+ var lines = wrapText(ctx, titleText, width - TEXT_PADDING * 2);
365
+ var lineHeight_3 = FONT_SIZE + 5;
366
+ var startY_3 = textY - ((lines.length - 1) * lineHeight_3) / 2;
367
+ lines.forEach(function (line, idx) {
368
+ var lineY = startY_3 + idx * lineHeight_3;
369
+ ctx.fillText(line, textX_3, lineY);
370
+ });
371
+ }
372
+ else {
373
+ var truncated = truncateText(ctx, titleText, width - TEXT_PADDING * 2);
374
+ ctx.fillText(truncated, textX_3, textY);
375
+ }
376
+ }
377
+ // 绘制筛选图�?
378
+ if (iconArea.hasFilter) {
379
+ var iconX = drawX + width - 10;
380
+ var hasFilterValue = state.filters[column.key] && state.filters[column.key].length > 0;
381
+ drawFilterIcon(ctx, iconX, textY, hasFilterValue);
382
+ }
383
+ // 绘制排序图标
384
+ if (iconArea.hasOrder) {
385
+ var iconX = drawX + width - (iconArea.hasFilter ? 24 : 10);
386
+ drawSortIcon(ctx, iconX, textY, column.key === state.sortField ? state.sortOrder : null);
387
+ }
388
+ }
389
+ }
390
+ ctx.textAlign = "left";
391
+ };
392
+ return HeaderRenderer;
393
+ }());
394
+
395
+ export { HeaderRenderer };
@@ -0,0 +1,85 @@
1
+ import { COLORS, SCROLLBAR_SIZE, SCROLLBAR_PADDING } from '../../utils/constants.js';
2
+ import 'zmdms-utils';
3
+ import 'dayjs';
4
+ import '../../../_virtual/_tslib.js';
5
+
6
+ /**
7
+ * 滚动条渲染器
8
+ * 负责渲染垂直和水平滚动条
9
+ */
10
+ var ScrollbarRenderer = /** @class */ (function () {
11
+ function ScrollbarRenderer() {
12
+ this.context = null;
13
+ }
14
+ ScrollbarRenderer.prototype.setContext = function (context) {
15
+ this.context = context;
16
+ };
17
+ /**
18
+ * 渲染滚动�?
19
+ */
20
+ ScrollbarRenderer.prototype.render = function () {
21
+ if (!this.context) {
22
+ throw new Error("ScrollbarRenderer: Context not set");
23
+ }
24
+ this.renderVerticalScrollbar();
25
+ this.renderHorizontalScrollbar();
26
+ this.renderScrollbarCorner();
27
+ };
28
+ /**
29
+ * 渲染垂直滚动�?
30
+ */
31
+ ScrollbarRenderer.prototype.renderVerticalScrollbar = function () {
32
+ if (!this.context || !this.context.needVerticalScrollbar)
33
+ return;
34
+ var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, headerHeight = _a.headerHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, scrollState = _a.scrollState, verticalScrollbarTop = _a.verticalScrollbarTop, verticalScrollbarHeight = _a.verticalScrollbarHeight;
35
+ var scrollbarX = displayWidth - SCROLLBAR_SIZE;
36
+ var scrollbarY = headerHeight;
37
+ var scrollbarHeight = needHorizontalScrollbar
38
+ ? displayHeight - SCROLLBAR_SIZE - headerHeight
39
+ : displayHeight - headerHeight;
40
+ // 滚动条轨�?
41
+ ctx.fillStyle = COLORS.scrollbarTrack;
42
+ ctx.fillRect(scrollbarX, scrollbarY, SCROLLBAR_SIZE, scrollbarHeight);
43
+ // 滚动条滑�?
44
+ ctx.fillStyle = scrollState.isDraggingVertical
45
+ ? COLORS.scrollbarThumbActive
46
+ : COLORS.scrollbarThumb;
47
+ ctx.fillRect(scrollbarX + SCROLLBAR_PADDING, verticalScrollbarTop + headerHeight + SCROLLBAR_PADDING, SCROLLBAR_SIZE - SCROLLBAR_PADDING * 2, verticalScrollbarHeight - SCROLLBAR_PADDING * 2);
48
+ };
49
+ /**
50
+ * 渲染水平滚动�?
51
+ */
52
+ ScrollbarRenderer.prototype.renderHorizontalScrollbar = function () {
53
+ if (!this.context || !this.context.needHorizontalScrollbar)
54
+ return;
55
+ var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, needVerticalScrollbar = _a.needVerticalScrollbar, scrollState = _a.scrollState, horizontalScrollbarLeft = _a.horizontalScrollbarLeft, horizontalScrollbarWidth = _a.horizontalScrollbarWidth;
56
+ var scrollbarX = 0;
57
+ var scrollbarY = displayHeight - SCROLLBAR_SIZE;
58
+ var scrollbarWidth = needVerticalScrollbar
59
+ ? displayWidth - SCROLLBAR_SIZE
60
+ : displayWidth;
61
+ // 滚动条轨�?
62
+ ctx.fillStyle = COLORS.scrollbarTrack;
63
+ ctx.fillRect(scrollbarX, scrollbarY, scrollbarWidth, SCROLLBAR_SIZE);
64
+ // 滚动条滑�?
65
+ ctx.fillStyle = scrollState.isDraggingHorizontal
66
+ ? COLORS.scrollbarThumbActive
67
+ : COLORS.scrollbarThumb;
68
+ ctx.fillRect(horizontalScrollbarLeft + SCROLLBAR_PADDING, scrollbarY + SCROLLBAR_PADDING, horizontalScrollbarWidth - SCROLLBAR_PADDING * 2, SCROLLBAR_SIZE - SCROLLBAR_PADDING * 2);
69
+ };
70
+ /**
71
+ * 渲染滚动条交叉处
72
+ */
73
+ ScrollbarRenderer.prototype.renderScrollbarCorner = function () {
74
+ if (!this.context)
75
+ return;
76
+ var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, needVerticalScrollbar = _a.needVerticalScrollbar, needHorizontalScrollbar = _a.needHorizontalScrollbar;
77
+ if (needVerticalScrollbar && needHorizontalScrollbar) {
78
+ ctx.fillStyle = COLORS.scrollbarTrack;
79
+ ctx.fillRect(displayWidth - SCROLLBAR_SIZE, displayHeight - SCROLLBAR_SIZE, SCROLLBAR_SIZE, SCROLLBAR_SIZE);
80
+ }
81
+ };
82
+ return ScrollbarRenderer;
83
+ }());
84
+
85
+ export { ScrollbarRenderer };