arthub-table 0.2.0-beta.9 → 0.2.1

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.
Files changed (31) hide show
  1. package/dist/arthub-table.common.js +1 -1
  2. package/dist/arthub-table.common.js.map +1 -1
  3. package/dist/arthub-table.umd.js +1 -1
  4. package/dist/arthub-table.umd.js.map +1 -1
  5. package/dist/arthub-table.umd.min.js +1 -1
  6. package/dist/arthub-table.umd.min.js.map +1 -1
  7. package/dist/types/adapters/DataGridIntegration.d.ts +51 -0
  8. package/dist/types/adapters/columnAdapter.d.ts +7 -0
  9. package/dist/types/adapters/rowDataAdapter.d.ts +23 -0
  10. package/dist/types/core/ColumnHeader.d.ts +26 -0
  11. package/dist/types/core/DataGrid.d.ts +362 -4
  12. package/dist/types/core/Events.d.ts +0 -1
  13. package/dist/types/core/GroupRow.d.ts +46 -0
  14. package/dist/types/core/ImageManager.d.ts +21 -0
  15. package/dist/types/core/NestedGrid.d.ts +56 -1
  16. package/dist/types/core/StyleManager.d.ts +2 -0
  17. package/dist/types/core/constants.d.ts +1 -0
  18. package/dist/types/core/types.d.ts +14 -0
  19. package/dist/types/core/viewers/FileViewer.d.ts +3 -3
  20. package/dist/types/core/viewers/ImageViewer.d.ts +3 -3
  21. package/dist/types/core/viewers/ModuleViewer.d.ts +10 -9
  22. package/dist/types/core/viewers/PivotViewer.d.ts +42 -1
  23. package/dist/types/core/viewers/RelatedTaskViewer.d.ts +76 -0
  24. package/dist/types/core/viewers/TextViewerWithSwitcher.d.ts +22 -2
  25. package/dist/types/core/viewers/index.d.ts +3 -0
  26. package/dist/types/core/viewers/types.d.ts +115 -0
  27. package/dist/types/index.d.ts +1 -1
  28. package/dist/types/testing/TestHooks.d.ts +187 -24
  29. package/dist/types/testing/index.d.ts +1 -1
  30. package/dist/types/testing/installTestHooks.d.ts +4 -4
  31. package/package.json +5 -1
@@ -79,6 +79,8 @@ declare class NestedGrid {
79
79
  parentRowBgColor: string | undefined;
80
80
  private redrawScheduled;
81
81
  private redrawTimer;
82
+ private _lastHoverViewerType;
83
+ private _lastHoverViewerData;
82
84
  selectionRange: SelectionRange | null;
83
85
  selectionAnchor: SelectionAnchor | null;
84
86
  selectionEnd: SelectionAnchor | null;
@@ -106,6 +108,15 @@ declare class NestedGrid {
106
108
  startValue: number;
107
109
  currentValue: number;
108
110
  };
111
+ rowDrag: {
112
+ pending: boolean;
113
+ isDragging: boolean;
114
+ fromRowIndex: number;
115
+ currentRowIndex: number;
116
+ position: 'front' | 'tail' | null;
117
+ mouseDownY: number;
118
+ ghostEl: HTMLDivElement | null;
119
+ };
109
120
  constructor(options: NestedGridOptions);
110
121
  getColumnWidth(index: number): number;
111
122
  getCellBounds(colIndex: number, rowIndex: number): {
@@ -125,12 +136,18 @@ declare class NestedGrid {
125
136
  row: number;
126
137
  } | null;
127
138
  handleMouseMove(mouseX: number, mouseY: number): boolean;
139
+ /**
140
+ * Reset the last hovered viewer's state (e.g. hide image popper).
141
+ * Called when mouse leaves the nested grid or moves to non-cell areas.
142
+ */
143
+ resetLastHoverViewer(): void;
128
144
  private isProgressCell;
129
145
  private isMouseOnProgressBar;
130
146
  handleMouseDown(mouseX: number, mouseY: number, e?: {
131
147
  ctrlKey?: boolean;
132
148
  metaKey?: boolean;
133
149
  shiftKey?: boolean;
150
+ altKey?: boolean;
134
151
  button?: number;
135
152
  }): boolean;
136
153
  private handleProgressDragMove;
@@ -139,7 +156,7 @@ declare class NestedGrid {
139
156
  col: number;
140
157
  row: number;
141
158
  }): boolean;
142
- isCellEditable(colIndex: number): boolean;
159
+ isCellEditable(colIndex: number, rowIndex?: number): boolean;
143
160
  getSelectLabel(colIndex: number, value: any): string;
144
161
  /**
145
162
  * 处理右键菜单事件,返回上下文信息
@@ -192,6 +209,31 @@ declare class NestedGrid {
192
209
  parentColKey: string;
193
210
  };
194
211
  } | null;
212
+ /**
213
+ * Handle double-click inside nested grid.
214
+ * Delegates to viewer.onDblClick (e.g. FileViewer opens file detail on dblclick).
215
+ * Returns true if the double-click was handled by a viewer.
216
+ */
217
+ handleDblClick(mouseX: number, mouseY: number): {
218
+ type: 'editIcon';
219
+ cell: {
220
+ row: number;
221
+ col: number;
222
+ };
223
+ editInfo: {
224
+ bounds: {
225
+ x: number;
226
+ y: number;
227
+ width: number;
228
+ height: number;
229
+ };
230
+ column: any;
231
+ value: any;
232
+ rowData: any;
233
+ parentRowData: any;
234
+ parentColKey: string;
235
+ };
236
+ } | null;
195
237
  /**
196
238
  * Check if mouse is on the boolean checkbox area within a cell
197
239
  */
@@ -230,6 +272,19 @@ declare class NestedGrid {
230
272
  * 以避免 autofill 手柄等突出 Cell 边界的元素被裁剪掉。
231
273
  */
232
274
  drawOverlays(): void;
275
+ /**
276
+ * 创建跟随鼠标的 DOM 浮层(Alt 子行拖动排序专用)。
277
+ * 样式与主表 DataGrid.createDragGhostEl 对齐,显示被拖子行的 name 字段值。
278
+ */
279
+ private createRowDragGhostEl;
280
+ /**
281
+ * 更新浮层位置,读取 DataGrid 缓存的最新鼠标 client 坐标(Events.ts handleMouseMove 中写入)。
282
+ */
283
+ private updateRowDragGhostPosition;
284
+ /**
285
+ * 从 DOM 中移除浮层元素。
286
+ */
287
+ private removeRowDragGhostEl;
233
288
  clearOtherNestedGridsSelection(): void;
234
289
  /**
235
290
  * 收集同列所有有选区的嵌套子表信息,触发 onNestedSelectionChange 回调
@@ -243,6 +243,8 @@ export interface ThemeTokens {
243
243
  iconExpand: string;
244
244
  /** 展开/折叠按钮激活色 */
245
245
  iconExpandActive: string;
246
+ /** 筛选激活色(筛选命中该列时,筛选图标常驻且使用此色) */
247
+ iconFilterActive: string;
246
248
  /** WfState 默认图标色 */
247
249
  iconWfStateDefault: string;
248
250
  /** 审核图标色 */
@@ -36,6 +36,7 @@ export declare const HEADER_ICON_PADDING = 4;
36
36
  export declare const HEADER_NESTED_SETTINGS_PADDING = 8;
37
37
  export declare const HEADER_ICON_RIGHT_MARGIN = 14;
38
38
  export declare const HEADER_ICON_GAP = 0;
39
+ export declare const SORT_ORDER_NUM_GAP = 9;
39
40
  export declare const HEADER_BUSINESS_ICON_SIZE = 14;
40
41
  export declare const HEADER_BUSINESS_ICON_GAP = 4;
41
42
  /** 引用字段 Link icon 常量 */
@@ -126,6 +126,10 @@ export interface ColumnConfig {
126
126
  nestedChildOffset?: number;
127
127
  color?: string;
128
128
  sortDisabled?: boolean;
129
+ /** Whether to show the filter icon on hover. When explicitly false, filter icon is suppressed (sort icons preserved). Default: true */
130
+ showFilterIcon?: boolean;
131
+ /** 筛选命中该列时为 true:筛选图标常驻显示且显示激活色 */
132
+ filterIconActive?: boolean;
129
133
  [key: string]: any;
130
134
  }
131
135
  export interface SelectorState {
@@ -272,6 +276,16 @@ export interface GroupRowData extends BaseGroupedRowData {
272
276
  hook_mark?: 'green' | 'blue';
273
277
  /** 图标容器背景色 */
274
278
  mark_bg_color?: 'purple';
279
+ /**
280
+ * 组头行是否被快捷搜索命中(searchMatchList 中存在 isGroupHeader: true 且 id 匹配的条目)。
281
+ * 由 rowDataAdapter.preprocessRow 在组头行上注入,供 GroupRow 渲染时查询。
282
+ */
283
+ _groupHeaderSearchMatched?: boolean;
284
+ /**
285
+ * 组头行是否是"当前高亮"命中项(命中条目中存在 highlight: true 的 field)。
286
+ * 当为 true 时 GroupRow 会绘制 2px 橙色 inset 边框。
287
+ */
288
+ _groupHeaderSearchCurrentHighlight?: boolean;
275
289
  }
276
290
  /**
277
291
  * Separate row data
@@ -110,9 +110,9 @@ declare class FileViewer implements CellViewer<FileViewerData> {
110
110
  */
111
111
  /**
112
112
  * 绘制交付物角标(右下角圆形图标)
113
- * 与 DOM .mark-icon 样式对齐:
114
- * - ah-icon_finish1: 白底 + 绿色 #00bd77 勾(已完成)
115
- * - ah-icon_help2: 白底 + 橙色 #ed954f 问号(待验收)
113
+ * 与 DOM .mark-icon iconfont 图标对齐:
114
+ * - ah-icon_finish1: 绿色 #00bd77 圆形背景 + 白色勾(已完成)
115
+ * - ah-icon_help2: 橙色 #ed954f 圆形背景 + 白色问号(待验收)
116
116
  */
117
117
  private drawMarkIcon;
118
118
  private drawIconByFileStatus;
@@ -62,9 +62,9 @@ declare class ImageViewer implements CellViewer<ImageViewerData> {
62
62
  private drawSinglePlaceholder;
63
63
  /**
64
64
  * 绘制交付物角标(右下角圆形图标)
65
- * 与 DOM .mark-icon 样式对齐:
66
- * - ah-icon_finish1: 白底 + 绿色 #00bd77 勾(已完成)
67
- * - ah-icon_help2: 白底 + 橙色 #ed954f 问号(待验收)
65
+ * 与 DOM .mark-icon iconfont 图标对齐:
66
+ * - ah-icon_finish1: 绿色 #00bd77 圆形背景 + 白色勾(已完成)
67
+ * - ah-icon_help2: 橙色 #ed954f 圆形背景 + 白色问号(待验收)
68
68
  */
69
69
  private drawMarkIcon;
70
70
  /**
@@ -30,17 +30,22 @@ declare class ModuleViewer implements CellViewer<ModuleViewerData> {
30
30
  */
31
31
  onClick(context: ViewerRenderContext, data: ModuleViewerData, localX: number, localY: number): boolean;
32
32
  /**
33
- * Draw colored module tags
33
+ * Draw colored module tags.
34
+ *
35
+ * 渲染规则(参考图片型实现):
36
+ * - 在单元格水平可绘制范围 [x+CELL_PADDING, x+width-CELL_PADDING] 内做矩形 clip 裁剪
37
+ * - 标签按顺序逐个绘制,能完整放下的完整画
38
+ * - 第一个放不下的标签:仍然绘制(背景 + 文字),由 clip 自动裁掉超出的部分;之后停止绘制
39
+ * - 不再使用 "..." 省略号,也不再展示 "+N" 概览
40
+ * - 极窄场景(剩余空间 1px 也要画,由 clip 处理截断)
41
+ *
42
+ * 注意:因为不再有 "+N" 点击区域,overflowBoundsMap 总是清空
34
43
  */
35
44
  private drawColoredTags;
36
45
  /**
37
46
  * Draw plain text mode (comma-separated module names)
38
47
  */
39
48
  private drawPlainText;
40
- /**
41
- * Draw the "+X" overflow indicator and cache its bounds for click detection
42
- */
43
- private drawOverflowIndicator;
44
49
  /**
45
50
  * Draw a rounded rectangle
46
51
  */
@@ -49,9 +54,5 @@ declare class ModuleViewer implements CellViewer<ModuleViewerData> {
49
54
  * Draw placeholder for empty state
50
55
  */
51
56
  private drawPlaceholder;
52
- /**
53
- * Truncate text to fit within maxWidth, adding "..." if needed
54
- */
55
- private truncateText;
56
57
  }
57
58
  export default ModuleViewer;
@@ -1,6 +1,12 @@
1
1
  /**
2
2
  * PivotViewer - 引用类型 Viewer
3
- * 在 canvas 单元格中渲染引用属性值,支持关联图标、悬停下划线和点击交互
3
+ * 在 canvas 单元格中渲染引用属性值,支持关联图标、悬停下划线和点击交互。
4
+ *
5
+ * 根据 pivotFieldViewer 委托给子 viewer 渲染:
6
+ * - 'person' → PersonViewer(人员头像 + 名称)
7
+ * - 'image' → ImageViewer(交付物缩略图)
8
+ * - 'wf-state' → WfStateViewer(工作流状态图标 + 名称)
9
+ * - 其他 / undefined → 默认文本渲染(当前逻辑)
4
10
  */
5
11
  import type { CellViewer, ViewerRenderContext, PivotViewerData } from './types';
6
12
  declare class PivotViewer implements CellViewer<PivotViewerData> {
@@ -11,18 +17,53 @@ declare class PivotViewer implements CellViewer<PivotViewerData> {
11
17
  * 解析 value,返回有效的显示文本或 null
12
18
  */
13
19
  private parseValue;
20
+ /**
21
+ * 判断是否应该委托给子 viewer 渲染
22
+ */
23
+ private shouldDelegate;
14
24
  /**
15
25
  * 绘制单元格内容
16
26
  */
17
27
  draw(context: ViewerRenderContext, data: PivotViewerData): void;
28
+ /**
29
+ * 委托给子 viewer 渲染
30
+ * 构造子 viewer 期望的 bounds(减去关联图标区域),然后调用子 viewer.draw()
31
+ */
32
+ private drawDelegated;
33
+ /**
34
+ * 默认文本模式渲染(原有逻辑)
35
+ */
36
+ private drawTextMode;
18
37
  /**
19
38
  * 处理点击事件
20
39
  */
21
40
  onClick(context: ViewerRenderContext, data: PivotViewerData, localX: number, localY: number): boolean;
41
+ /**
42
+ * 委托模式下的点击处理
43
+ */
44
+ private onClickDelegated;
45
+ /**
46
+ * 处理双击事件
47
+ * 对于 image 类型的 pivot 字段,双击图片打开文件详情页(与普通 file 列双击行为一致)。
48
+ * 实现方式:委托给 ImageViewer.onClick 检测点击位置,但用桥接回调将 onClickImage 转为 onFileGoToDetail。
49
+ */
50
+ onDblClick(context: ViewerRenderContext, data: PivotViewerData, localX: number, localY: number): boolean;
51
+ /**
52
+ * 构造子 viewer 的 data(公共逻辑提取)
53
+ */
54
+ private buildSubViewerData;
55
+ /**
56
+ * 构造子 viewer 的 context(公共逻辑提取)
57
+ */
58
+ private buildSubViewerContext;
22
59
  /**
23
60
  * 获取交互光标
24
61
  */
25
62
  getInteractiveCursor(context: ViewerRenderContext, data: PivotViewerData, localX: number, localY: number): string | null;
63
+ /**
64
+ * 委托模式下的光标处理
65
+ */
66
+ private getInteractiveCursorDelegated;
26
67
  /**
27
68
  * 绘制占位符文本
28
69
  */
@@ -0,0 +1,76 @@
1
+ /**
2
+ * RelatedTaskViewer - Related task cell renderer (Canvas implementation)
3
+ * Displays the first related task's configured display fields.
4
+ *
5
+ * Layout modes:
6
+ * - Single-line (default): task name | thumbnails | "label: value" pairs — all horizontal, vertically centered
7
+ * - Multi-line (when row is expanded by nested columns): one field per line, vertically stacked
8
+ */
9
+ import type { CellViewer, ViewerRenderContext, RelatedTaskViewerData } from './types';
10
+ declare class RelatedTaskViewer implements CellViewer<RelatedTaskViewerData> {
11
+ readonly type = "related-task";
12
+ private imageManager;
13
+ /** Track failed image URLs to avoid retrying */
14
+ private failedImages;
15
+ private _sm;
16
+ private get TEXT_COLOR();
17
+ private get LABEL_COLOR();
18
+ private get EMPTY_TEXT_COLOR();
19
+ private get DASHED_BORDER_COLOR();
20
+ constructor();
21
+ /**
22
+ * Calculate thumbnail height for single-line mode.
23
+ * Max height = cell height - top/bottom padding (4px each).
24
+ */
25
+ private getSingleLineThumbnailHeight;
26
+ /**
27
+ * Calculate thumbnail width for a given image, maintaining aspect ratio.
28
+ * If no image is cached yet, returns thumbHeight (square placeholder).
29
+ */
30
+ private getThumbnailWidth;
31
+ /**
32
+ * Draw an image within the given area according to the specified fit mode.
33
+ * Mirrors the logic in FileViewer.drawPreviewImage and ImageViewer.drawImageWithFit.
34
+ */
35
+ private drawImageWithFit;
36
+ /**
37
+ * Draw the related task cell content
38
+ */
39
+ draw(context: ViewerRenderContext, data: RelatedTaskViewerData): void;
40
+ private drawSingleLine;
41
+ /**
42
+ * Draw a single inline thumbnail at the given position (for single-line mode).
43
+ * @returns The X position after the thumbnail(s)
44
+ */
45
+ private drawInlineThumbnail;
46
+ private drawMultiLine;
47
+ /**
48
+ * Draw empty placeholder — consistent with other viewers
49
+ */
50
+ private drawEmptyPlaceholder;
51
+ /**
52
+ * Draw a file status/format icon when coverUrl is not available.
53
+ * Uses the same getIconByFileStatus logic as FileViewer for visual consistency.
54
+ */
55
+ private drawFileStatusIcon;
56
+ /**
57
+ * Draw a dashed rectangle placeholder for unloaded/missing images
58
+ */
59
+ private drawDashedPlaceholder;
60
+ /**
61
+ * Truncate text to fit within maxWidth, appending ellipsis if needed
62
+ */
63
+ private truncateText;
64
+ /**
65
+ * Handle click events on the cell.
66
+ * Detects clicks on file thumbnails and triggers onFileGoToDetail callback.
67
+ */
68
+ onClick(context: ViewerRenderContext, data: RelatedTaskViewerData, localX: number, localY: number): boolean;
69
+ /**
70
+ * Get cursor style for hover — show pointer on file thumbnails
71
+ */
72
+ getHitArea(context: ViewerRenderContext, data: RelatedTaskViewerData, localX: number, localY: number): string | null;
73
+ private calculateSingleLineThumbnailAreas;
74
+ private calculateMultiLineThumbnailAreas;
75
+ }
76
+ export default RelatedTaskViewer;
@@ -148,10 +148,30 @@ declare class TextViewerWithSwitcher implements CellViewer<TextViewerWithSwitche
148
148
  * Calculate layout bounds for a given data set (used by onClick/getInteractiveCursor)
149
149
  */
150
150
  private calcLayoutBounds;
151
+ /**
152
+ * Hit-test whether the given local coordinate lands on an interactive hot area.
153
+ * Pure query, no side effects. Used by Row.mouseDown to decide whether selectCell
154
+ * should skip horizontal auto-scroll (so the subsequent click event still hits
155
+ * the same hot area instead of drifting to a blank region after the scroll).
156
+ *
157
+ * Covered hot areas (MUST stay in sync with onClick):
158
+ * - expand area (tree expand/collapse)
159
+ * - task icon area (onClickIcon jump)
160
+ * - text area (精确到 actualTextWidth,与 onClick 一致)
161
+ * - totalNum area (child count badge)
162
+ */
163
+ hitTest(context: ViewerRenderContext, data: TextViewerWithSwitcherData, localX: number, localY: number): boolean;
164
+ /**
165
+ * 判断 localY 是否落在文字的垂直命中区域内。
166
+ * 文字以 textBaseline='middle' 绘制在单元格垂直中线 (height/2),
167
+ * 命中区为 [mid - fontSize/2 - buffer, mid + fontSize/2 + buffer],
168
+ * 避免点击文字上下空白区域时误触发文字点击回调。
169
+ */
170
+ private isInsideTextVerticalRange;
151
171
  /**
152
172
  * Handle click events on the cell
153
173
  */
154
- onClick(context: ViewerRenderContext, data: TextViewerWithSwitcherData, localX: number, _localY: number): boolean;
174
+ onClick(context: ViewerRenderContext, data: TextViewerWithSwitcherData, localX: number, localY: number): boolean;
155
175
  /**
156
176
  * Handle double-click: suppress editing when dblclick lands on the expand/collapse area.
157
177
  * Without this, rapidly toggling expand/collapse triggers a dblclick that enters edit mode.
@@ -160,7 +180,7 @@ declare class TextViewerWithSwitcher implements CellViewer<TextViewerWithSwitche
160
180
  /**
161
181
  * Get interactive cursor for hover areas
162
182
  */
163
- getInteractiveCursor(context: ViewerRenderContext, data: TextViewerWithSwitcherData, localX: number, _localY: number): string | null;
183
+ getInteractiveCursor(context: ViewerRenderContext, data: TextViewerWithSwitcherData, localX: number, localY: number): string | null;
164
184
  /**
165
185
  * Get tooltip text when mouse hovers over task icon or IOMC order state icon.
166
186
  * - Task icon: returns data.iconTooltip (pre-computed from iconFile by AssetMatrix)
@@ -40,6 +40,7 @@ export { default as ModuleColExpandViewer } from './ModuleColExpandViewer';
40
40
  export { default as ChildrenViewer } from './ChildrenViewer';
41
41
  export { default as OnlyShowErrorViewer } from './OnlyShowErrorViewer';
42
42
  export { default as PerspectiveViewer } from './PerspectiveViewer';
43
+ export { default as RelatedTaskViewer } from './RelatedTaskViewer';
43
44
  import TextViewer from './TextViewer';
44
45
  import DropdownViewer from './DropdownViewer';
45
46
  import ImageViewer from './ImageViewer';
@@ -76,6 +77,7 @@ import ModuleColExpandViewer from './ModuleColExpandViewer';
76
77
  import ChildrenViewer from './ChildrenViewer';
77
78
  import OnlyShowErrorViewer from './OnlyShowErrorViewer';
78
79
  import PerspectiveViewer from './PerspectiveViewer';
80
+ import RelatedTaskViewer from './RelatedTaskViewer';
79
81
  /**
80
82
  * Register all default viewers
81
83
  * Call this function once during application initialization
@@ -126,4 +128,5 @@ export declare const defaultViewers: {
126
128
  children: typeof ChildrenViewer;
127
129
  'only-show-error': typeof OnlyShowErrorViewer;
128
130
  perspective: typeof PerspectiveViewer;
131
+ 'related-task': typeof RelatedTaskViewer;
129
132
  };
@@ -100,6 +100,25 @@ export interface CellViewer<T extends CellViewerData = CellViewerData> {
100
100
  * @returns true if the event was handled (prevents default edit behavior)
101
101
  */
102
102
  onDblClick?(context: ViewerRenderContext, data: T, localX: number, localY: number): boolean;
103
+ /**
104
+ * Optional: Query whether the given local coordinate hits an interactive hot area.
105
+ * Pure side-effect-free lookup used at mousedown time to decide whether the cell
106
+ * selection should skip horizontal auto-scroll (so a subsequent click can hit the
107
+ * same hot area that would otherwise drift out from under the cursor).
108
+ *
109
+ * Contract:
110
+ * - MUST NOT draw, mutate data/context, or trigger any callback.
111
+ * - Return value semantics: true = clickable hot area hit; false = no hit.
112
+ * - Not implementing this method is equivalent to returning false (no effect on
113
+ * existing auto-scroll behavior for viewers that don't opt in).
114
+ *
115
+ * @param context Render context
116
+ * @param data Cell data
117
+ * @param localX Mouse X position relative to cell
118
+ * @param localY Mouse Y position relative to cell
119
+ * @returns true if the position hits an interactive/clickable hot area
120
+ */
121
+ hitTest?(context: ViewerRenderContext, data: T, localX: number, localY: number): boolean;
103
122
  /**
104
123
  * Optional: Get the preferred height for this cell
105
124
  * @param context Render context
@@ -659,6 +678,8 @@ export interface FileViewerData extends CellViewerData {
659
678
  key?: string;
660
679
  /** 是否可编辑 */
661
680
  canEdit?: boolean;
681
+ /** 隐藏右侧操作区域(编辑笔/查看图标),用于嵌套表格中由 NestedGrid 层统一绘制编辑笔 */
682
+ hideAfterArea?: boolean;
662
683
  /** 是否显示删除线 */
663
684
  showLineThrow?: boolean;
664
685
  /** 是否关联属性 */
@@ -977,6 +998,20 @@ export interface FileStorageSpecViewerData extends CellViewerData {
977
998
  /**
978
999
  * 引用类型 Viewer 数据接口
979
1000
  * 接收业务层将引用属性值格式化后传入的显示文本
1001
+ *
1002
+ * 支持根据 pivotFieldViewer 委托给子 viewer 渲染:
1003
+ * - 'person' → PersonViewer(人员头像 + 名称)
1004
+ * - 'image' → ImageViewer(交付物缩略图)
1005
+ * - 'wf-state' → WfStateViewer(工作流状态图标 + 名称)
1006
+ * - 其他 / undefined → 默认文本渲染
1007
+ *
1008
+ * 数据流:
1009
+ * 1. rowDataAdapter.transformPivotValue 将 PivotValueItem[] 转为结构化对象
1010
+ * (包含 pivotFieldViewer + 原始子字段值 pivotRawValue)
1011
+ * 2. cellValueTransformer(AssetMatrix 侧)根据 pivotFieldViewer 调用对应的
1012
+ * _transformPersonValue / _transformWfStateValue 等方法,将 pivotRawValue
1013
+ * 转为子 viewer 期望的格式,写入 pivotData
1014
+ * 3. PivotViewer.draw() 根据 pivotFieldViewer 委托给对应 viewer 实例绘制
980
1015
  */
981
1016
  export interface PivotViewerData extends CellViewerData {
982
1017
  /** 引用属性的格式化显示文本(由业务层将 pivotField 解析后传入) */
@@ -985,6 +1020,33 @@ export interface PivotViewerData extends CellViewerData {
985
1020
  placeholder?: string;
986
1021
  /** 是否为关联属性(为 true 时显示关联图标) */
987
1022
  isLink?: boolean;
1023
+ /**
1024
+ * pivotField 对应的 viewer 类型(Canvas 映射后的类型名,如 'person'、'image'、'wf-state')。
1025
+ * 由 transformPivotValue 从 pivotResolver 获取并注入。
1026
+ * 当此字段存在且非 'text' 时,PivotViewer 会委托给对应的子 viewer 渲染。
1027
+ */
1028
+ pivotFieldViewer?: string;
1029
+ /**
1030
+ * pivotField 的原始值(从 PivotValueItem[0][pivotField] 提取)。
1031
+ * 由 transformPivotValue 注入,供 cellValueTransformer 进一步转换。
1032
+ * 例如:person 类型为 accountName string,wf-state 类型为 state ID number。
1033
+ */
1034
+ pivotRawValue?: any;
1035
+ /**
1036
+ * 子 viewer 的已转换数据(由 cellValueTransformer 写入)。
1037
+ * 例如:person 类型为 PersonInfo[],wf-state 类型为 WfStateViewerData 对象。
1038
+ * PivotViewer.draw() 将此数据传给对应子 viewer 的 draw() 方法。
1039
+ */
1040
+ pivotData?: any;
1041
+ /**
1042
+ * 交付物图片的 assetId 列表(仅 pivotFieldViewer === 'image' 时有值)。
1043
+ * 由 transformPivotValue 从 deliverable 对象中提取,用于双击打开文件详情。
1044
+ */
1045
+ pivotAssetIds?: number[];
1046
+ /** 双击文件项回调(打开文件详情,由 DataGridIntegration 从 fileCallbacks 注入) */
1047
+ onFileGoToDetail?: (file: any, data: any) => void;
1048
+ /** 点击图片回调(打开图片预览,由 DataGridIntegration 从 imageCallbacks 注入) */
1049
+ onClickImage?: (imgUrls: string[], initIndex: number, assetIds: (number | string | undefined)[], data: any) => void;
988
1050
  }
989
1051
  /**
990
1052
  * 工作流 Viewer 数据接口
@@ -1262,3 +1324,56 @@ export interface RichTextViewerData extends CellViewerData {
1262
1324
  /** 占位符文本,默认 '-' */
1263
1325
  placeholder?: string;
1264
1326
  }
1327
+ /**
1328
+ * Related-task display field item
1329
+ */
1330
+ export interface RelatedTaskDisplayField {
1331
+ /** Field key (e.g. 'estimate_start_date') */
1332
+ key: string;
1333
+ /** Field display label (e.g. '预计开始时间') */
1334
+ label: string;
1335
+ /** Raw field value */
1336
+ value: any;
1337
+ /** Formatted display value (e.g. '2026/03/02') */
1338
+ displayValue: string;
1339
+ /** Whether this field is a file-type field */
1340
+ isFileType: boolean;
1341
+ /** File data for file-type fields (cover images, etc.) */
1342
+ fileData?: Array<{
1343
+ coverUrl: string;
1344
+ assetId?: number;
1345
+ status?: number;
1346
+ fileFormat?: string;
1347
+ }>;
1348
+ /** File meta key for file-type fields (e.g. 'deliverable') */
1349
+ fileMeta?: string;
1350
+ /** Node ID that owns this file (for opening asset detail) */
1351
+ nodeId?: number;
1352
+ }
1353
+ /**
1354
+ * Related-task Viewer data interface
1355
+ * Displays the first related task's configured display fields
1356
+ */
1357
+ export interface RelatedTaskViewerData extends CellViewerData {
1358
+ /** Structured value containing related task info */
1359
+ value: {
1360
+ /** First related task node ID */
1361
+ firstRelatedTaskId: number;
1362
+ /** First related task name */
1363
+ firstRelatedTaskName: string;
1364
+ /** Display label for the task name field (e.g. "名称") */
1365
+ firstRelatedTaskLabel?: string;
1366
+ /** All related node IDs (for future interactions) */
1367
+ allRelatedNodeIds: number[];
1368
+ /** Display fields with resolved values */
1369
+ displayFields: RelatedTaskDisplayField[];
1370
+ } | null;
1371
+ /** Thumbnail fit mode for file-type fields (synced from imageDisplayMode config) */
1372
+ thumbnailFit?: 'contain' | 'cover' | 'fill' | 'height-full' | 'width-full';
1373
+ /** Callback when user clicks a file thumbnail — opens asset detail page */
1374
+ onFileGoToDetail?: (file: {
1375
+ assetId: number;
1376
+ id: number;
1377
+ ids: number[];
1378
+ }, data: any) => void;
1379
+ }
@@ -41,7 +41,7 @@ export { CSS_PREFIX, HEADER_HEIGHT, ROW_INDEX_WIDTH, CHECK_BOX_WIDTH, CELL_HEIGH
41
41
  export { getFieldStatisticTypes } from './core/footer/utils';
42
42
  export { convertToDataGridColumns, } from './adapters/columnAdapter';
43
43
  export type { ITableHeader, } from './adapters/columnAdapter';
44
- export { convertToDataGridRows, isPerfLogEnabled, } from './adapters/rowDataAdapter';
44
+ export { convertToDataGridRows, isPerfLogEnabled, rebuildNestedColumnData, } from './adapters/rowDataAdapter';
45
45
  export type { PreprocessedRow, } from './adapters/rowDataAdapter';
46
46
  export { preprocessRowStyles, } from './adapters/styleAdapter';
47
47
  export type { RowStyleResult, } from './adapters/styleAdapter';