/**
 * Canvas-Table Viewer Type System
 * Data-driven cell viewer interfaces and types
 */
import type Paint from '../Paint';
import type DataGrid from '../DataGrid';
/**
 * Bounds of a cell for rendering
 */
export interface CellBounds {
    x: number;
    y: number;
    width: number;
    height: number;
}
/**
 * Render context passed to viewers
 */
export interface ViewerRenderContext {
    /** Canvas 2D rendering context */
    ctx: CanvasRenderingContext2D;
    /** Painter utility for drawing */
    painter: Paint;
    /** Parent grid reference */
    grid: DataGrid;
    /** Cell bounds */
    bounds: CellBounds;
    /** Row index */
    rowIndex: number;
    /** Column index */
    colIndex: number;
    /** Whether the cell is readonly */
    readonly: boolean;
    /** Whether the row is hovered */
    isHoverRow: boolean;
    /** Whether the cell is hovered */
    isHoverCell: boolean;
    /** Whether the cell is being edited */
    isEditing: boolean;
    /** Whether the row is checked/selected */
    isChecked: boolean;
    /** Cell background color */
    fillColor: string;
    /** Callback to request redraw */
    requestRedraw: () => void;
    /** 鼠标点击时的视口 clientX（仅在 onClick/onDblClick 调用链中可用） */
    clientX?: number;
    /** 鼠标点击时的视口 clientY（仅在 onClick/onDblClick 调用链中可用） */
    clientY?: number;
}
/**
 * Viewer interaction state for drag operations
 */
export interface ViewerDragState {
    /** Whether the viewer is currently being dragged */
    isDragging: boolean;
    /** Starting X position of the drag */
    startX: number;
    /** Starting Y position of the drag */
    startY: number;
    /** Original value before drag started */
    startValue: any;
    /** Current cell bounds */
    bounds: CellBounds;
    /** Current viewer data */
    data: CellViewerData;
    /** Row index */
    rowIndex: number;
    /** Column index */
    colIndex: number;
}
/**
 * Base cell viewer interface
 * All viewers must implement this interface
 */
export interface CellViewer<T extends CellViewerData = CellViewerData> {
    /** Viewer type identifier */
    readonly type: string;
    /**
     * Draw the cell content
     * @param context Render context
     * @param data Cell data
     */
    draw(context: ViewerRenderContext, data: T): void;
    /**
     * Optional: Handle click events on the cell
     * @param context Render context
     * @param data Cell data
     * @param localX Click X position relative to cell
     * @param localY Click Y position relative to cell
     * @returns true if the event was handled
     */
    onClick?(context: ViewerRenderContext, data: T, localX: number, localY: number): boolean;
    /**
     * Optional: Handle double click events on the cell
     * @param context Render context
     * @param data Cell data
     * @param localX Double click X position relative to cell
     * @param localY Double click Y position relative to cell
     * @returns true if the event was handled (prevents default edit behavior)
     */
    onDblClick?(context: ViewerRenderContext, data: T, localX: number, localY: number): boolean;
    /**
     * Optional: Query whether the given local coordinate hits an interactive hot area.
     * Pure side-effect-free lookup used at mousedown time to decide whether the cell
     * selection should skip horizontal auto-scroll (so a subsequent click can hit the
     * same hot area that would otherwise drift out from under the cursor).
     *
     * Contract:
     *   - MUST NOT draw, mutate data/context, or trigger any callback.
     *   - Return value semantics: true = clickable hot area hit; false = no hit.
     *   - Not implementing this method is equivalent to returning false (no effect on
     *     existing auto-scroll behavior for viewers that don't opt in).
     *
     * @param context Render context
     * @param data Cell data
     * @param localX Mouse X position relative to cell
     * @param localY Mouse Y position relative to cell
     * @returns true if the position hits an interactive/clickable hot area
     */
    hitTest?(context: ViewerRenderContext, data: T, localX: number, localY: number): boolean;
    /**
     * Optional: Get the preferred height for this cell
     * @param context Render context
     * @param data Cell data
     * @returns Preferred height in pixels
     */
    getPreferredHeight?(context: ViewerRenderContext, data: T): number;
    /**
     * Optional: Check if mouse is over an interactive area (e.g., drag handle)
     * @param context Render context
     * @param data Cell data
     * @param localX Mouse X position relative to cell
     * @param localY Mouse Y position relative to cell
     * @returns Cursor style if over interactive area, null otherwise
     */
    getInteractiveCursor?(context: ViewerRenderContext, data: T, localX: number, localY: number): string | null;
    /**
     * Optional: Handle mouse down for drag operations
     * @param context Render context
     * @param data Cell data
     * @param localX Mouse X position relative to cell
     * @param localY Mouse Y position relative to cell
     * @returns true if drag operation started
     */
    onDragStart?(context: ViewerRenderContext, data: T, localX: number, localY: number): boolean;
    /**
     * Optional: Handle drag move
     * @param context Render context
     * @param data Cell data
     * @param localX Current mouse X position relative to cell
     * @param localY Current mouse Y position relative to cell
     * @param startX Starting mouse X position
     * @param startY Starting mouse Y position
     * @returns New value if changed, undefined otherwise
     */
    onDragMove?(context: ViewerRenderContext, data: T, localX: number, localY: number, startX: number, startY: number): any;
    /**
     * Optional: Handle drag end
     * @param context Render context
     * @param data Cell data
     * @param newValue The final value after dragging
     */
    onDragEnd?(context: ViewerRenderContext, data: T, newValue: any, startValue?: any): void;
    /**
     * Optional: Get tooltip info when mouse hovers over a specific area (e.g., task icon, IOMC icon)
     * @param context Render context
     * @param data Cell data
     * @param localX Mouse X position relative to cell
     * @param localY Mouse Y position relative to cell
     * @returns Tooltip info object if hovering over a tooltip area, null otherwise.
     *   - text: the tooltip text to display
     *   - iconCenterX: the center X position of the icon (relative to cell) for precise popup positioning
     */
    getTooltip?(context: ViewerRenderContext, data: T, localX: number, localY: number): {
        text: string;
        iconCenterX: number;
    } | null;
    /**
     * Optional: Whether to hide the default edit icon on hover
     * When true, Cell will not draw the edit pencil icon when the cell is hovered.
     * Useful for viewers that manage their own hover icons (e.g., itfs-path shows disk icon instead).
     */
    hideEditIcon?: boolean;
}
/**
 * Base cell viewer data interface
 * All specific data types extend this interface
 */
export interface CellViewerData {
    /** Raw value stored in the cell */
    value: any;
    /** Display label (may differ from value) */
    label?: string;
    /** Options for select-type viewers */
    options?: ViewerOption[];
    /** Custom style overrides */
    style?: ViewerStyle;
    /** Extra data for specific viewers */
    extra?: Record<string, any>;
}
/**
 * Cell value transformer callback type.
 *
 * Called by Cell.drawWithViewer() before passing data to viewer.draw().
 * The transformer receives the raw cell value and column metadata, and returns
 * a transformed value suitable for the viewer. If no transformation is needed,
 * return the original value unchanged (or undefined to skip transformation).
 *
 * This decouples value transformation from the data preprocessing layer
 * (rowDataAdapter.transformCellValues) and moves it to the rendering layer,
 * aligning with the DOM table's approach where viewers (e.g. textViewer.ts
 * getDisplayValue / getTreeCustomInfo) handle value-to-display conversion.
 *
 * @param rawValue - The raw cell value from row data
 * @param columnKey - The column key (header key / property UUID)
 * @param viewerType - The viewer type identifier (e.g. 'text', 'person', 'wf-state')
 * @param rowData - The full row data object
 * @returns Transformed value to use for rendering, or undefined to keep original
 */
export type CellValueTransformer = (rawValue: any, columnKey: string, viewerType: string, rowData: Record<string, any>) => any | undefined;
/**
 * Option item for select-type viewers
 */
export interface ViewerOption {
    value: any;
    label: string;
    color?: string;
    backgroundColor?: string;
    icon?: string;
}
/**
 * Style configuration for viewers
 */
export interface ViewerStyle {
    color?: string;
    backgroundColor?: string;
    borderColor?: string;
    fontSize?: number;
    fontWeight?: 'normal' | 'bold';
    textAlign?: 'left' | 'center' | 'right';
    textBaseline?: 'top' | 'middle' | 'bottom';
    padding?: number;
}
/**
 * Text viewer data
 */
export interface TextViewerData extends CellViewerData {
    value: string | number | {
        value: string;
        bgColor: string;
        isOriginalColor?: boolean;
    }[] | null;
    /** Text alignment */
    textAlign?: 'left' | 'center' | 'right';
    /** Background color for label mode */
    backgroundColor?: string;
    /** Whether to render as a tag/badge */
    asTag?: boolean;
    /** Tag border radius */
    tagRadius?: number;
    /** Rich text HTML content */
    richText?: string;
    /** Placeholder for empty values */
    placeholder?: string;
}
/**
 * Dropdown viewer data (single/multi select)
 */
export interface DropdownViewerData extends CellViewerData {
    value: any | any[];
    /** Available options */
    options: ViewerOption[];
    /** Whether multiple selection is allowed */
    multiple?: boolean;
    /** Show dropdown arrow */
    showArrow?: boolean;
    /** Max tags to display (for multiple mode) */
    maxTags?: number;
}
/**
 * Image viewer data
 */
export interface ImageViewerData extends CellViewerData {
    value: string | string[] | null;
    /** 与 value 中的 URL 一一对应的 assetId 列表 */
    assetIds?: (number | string | undefined)[];
    /** 每个 assetId 对应的文件状态（转码中/失败等），用于加载失败时显示状态图标 */
    statuses?: Record<string | number, number | string | undefined>;
    /** 每个 assetId 对应的文件格式，用于加载失败时显示文件类型图标 */
    fileFormats?: Record<string | number, string | undefined>;
    /** 每个 assetId 对应的交付物角标标记（如 'ah-icon_finish1' / 'ah-icon_help2'） */
    marks?: Record<string | number, string | undefined>;
    /** Alternative text */
    alt?: string;
    /** Placeholder image URL */
    placeholder?: string;
    /** Image fit mode */
    fit?: 'contain' | 'cover' | 'fill' | 'height-full' | 'width-full';
    /** Border radius */
    borderRadius?: number;
    /** Whether the image is animated (GIF) */
    animated?: boolean;
    /** 点击图片回调（与 DOM multiImageViewer 的 onClickImage 签名一致） */
    onClickImage?: (imgUrls: string[], initIndex: number, assetIds: (number | string | undefined)[], data: any) => void;
    /** 鼠标移入图片回调（用于显示大图预览） */
    onImgMouseIn?: (url: string, virtualAnchor: any) => void;
    /** 鼠标移出图片回调（用于隐藏大图预览） */
    onImgMouseOut?: () => void;
    /**
     * 正在上传中的占位项（外部 OS 文件 drop 触发上传时由业务层 unshift 进来）。
     * - id：业务层生成的占位 id（如 `uploading-${rowId}-${ts}-${idx}`），用于进度回写匹配
     * - name：可选文件名（用于占位 hover 提示，目前 ImageViewer 不显示）
     * - previewUrl：可选 URL.createObjectURL 本地预览图（image 列）
     * - progress：0-100，由 EVENTHUB_TYPE.UpdateFileNodeProgress 回调写回
     * 渲染规则：在 value 数组前面追加占位 slot（占位灰底 + 居中 canvas 进度环），
     * 上传完成后业务层从 uploadingItems 移除并在 value 头部插入真实 URL。
     */
    uploadingItems?: Array<{
        id: string;
        name?: string;
        previewUrl?: string;
        progress?: number;
    }>;
}
/**
 * Person/User viewer data
 */
export interface PersonViewerData extends CellViewerData {
    value: PersonInfo | PersonInfo[] | string | null;
    /** Display mode */
    mode?: 'avatar' | 'name' | 'both';
    /** Avatar size */
    avatarSize?: number;
    /** Max persons to display */
    maxDisplay?: number;
    /** Placeholder text for empty */
    placeholder?: string;
    /** Name display type: chinese only, english only, or both */
    nameDisplayType?: 'chinese' | 'english' | 'chinese_and_english';
    /** Whether to show avatar image */
    showAvatar?: boolean;
    /** Avatar shape: circle or rounded rectangle */
    avatarShape?: 'circle' | 'rounded-rect';
    /** Whether to show name background tag */
    showNameBackground?: boolean;
}
/**
 * Person information
 */
export interface PersonInfo {
    id: string | number;
    name: string;
    avatar?: string;
    email?: string;
    /** 企业微信别名（英文名） */
    qywxAlias?: string;
    /** 邮箱地址 */
    mail?: string;
}
/**
 * Progress viewer data
 */
export interface ProgressViewerData extends CellViewerData {
    value: number;
    /** Minimum value (default 0) */
    min?: number;
    /** Maximum value (default 100) */
    max?: number;
    /** Progress bar height */
    barHeight?: number;
    /** Show percentage text */
    showText?: boolean;
    /** Text position */
    textPosition?: 'inside' | 'outside' | 'right';
    /** Progress color (or auto based on value) */
    color?: string;
    /** Track/background color */
    trackColor?: string;
    /** Color thresholds for automatic coloring */
    colorThresholds?: Array<{
        value: number;
        color: string;
    }>;
    /** Whether the progress bar is draggable to change value */
    draggable?: boolean;
    /** 拖拽结束后的值变更回调（用于调用接口更新进度数据） */
    onProgressChange?: (newValue: number, oldValue: number, extra?: Record<string, any>) => void;
}
/**
 * Datetime viewer data
 */
export interface DatetimeViewerData extends CellViewerData {
    value: string | number | Date | null;
    /** Date format string */
    format?: string;
    /** Display type */
    displayType?: 'date' | 'time' | 'datetime' | 'month';
    /** Show icon */
    showIcon?: boolean;
    /** Placeholder for invalid/empty dates */
    placeholder?: string;
    /** 预格式化的显示文本（由业务层 dateFormatResolver 提供） */
    formattedText?: string;
    /** 文本颜色（如逾期提醒的红色） */
    textColor?: string;
    /** hover 时显示的 tooltip 文本（完整日期格式） */
    hoverText?: string;
    /** hover 时是否显示下划线（用于时间型字段变更提醒） */
    showUnderlineOnHover?: boolean;
}
/**
 * Boolean/Checkbox viewer data
 */
export interface BooleanViewerData extends CellViewerData {
    value: boolean | null;
    /** Display style */
    displayStyle?: 'checkbox' | 'switch' | 'text';
    /** Text for true value */
    trueText?: string;
    /** Text for false value */
    falseText?: string;
    /** Text for null/indeterminate value */
    nullText?: string;
    /** Check icon color */
    checkedColor?: string;
    /** Uncheck icon color */
    uncheckedColor?: string;
    /** 值变更回调（点击 checkbox/switch 切换布尔值后调用），用于通知业务层发起接口更新 */
    onValueChange?: (newValue: boolean, oldValue: boolean | null, extra?: Record<string, any>) => void;
}
/**
 * Status viewer data
 */
export interface StatusViewerData extends CellViewerData {
    value: string | number;
    /** Status configurations */
    options: StatusOption[];
    /** Show status icon */
    showIcon?: boolean;
    /** Show as tag/badge */
    asTag?: boolean;
}
/**
 * Status option configuration
 */
export interface StatusOption extends ViewerOption {
    /** Status icon */
    icon?: 'dot' | 'check' | 'cross' | 'warning' | 'info' | string;
    /** Status type for automatic styling */
    type?: 'success' | 'warning' | 'error' | 'info' | 'default';
}
/**
 * Group header viewer data
 */
export interface GroupHeaderViewerData extends CellViewerData {
    value: string;
    /** Group display label */
    label: string;
    /** Number of records in group */
    count?: number;
    /** Whether the group is expanded */
    expanded?: boolean;
    /** Nesting level (for multi-level groups) */
    level?: number;
    /** Group type */
    groupType?: 'text' | 'person' | 'status' | 'date';
    /** Group icon */
    icon?: string;
    /** Person info for person-type groups */
    person?: PersonInfo;
    /** Whether to show count badge */
    showCount?: boolean;
    /** Whether to show working hours icon */
    showUserWorkingHours?: boolean;
}
/**
 * Group name tag item (for module/dropdown/treeDropdown colored tags)
 */
export interface GroupNameTagItem {
    /** Display text */
    text: string;
    /** Tag background color */
    bgColor: string;
    /** Tag text color */
    textColor: string;
    /** Whether bgColor is an original color (not derived) */
    isOriginalColor?: boolean;
}
/**
 * Group name person item (for person-type group headers)
 */
export interface GroupNamePersonItem {
    /** Person display name */
    name: string;
    /** Person avatar URL */
    avatar?: string;
    /** Person account name (used for click-to-jump) */
    accountName?: string;
    /** Whether this is an empty/placeholder person */
    isEmpty?: boolean;
}
/**
 * Group name viewer data
 * Used by GroupNameViewer to render group header names with proper formatting.
 * The business layer (AssetMatrix) builds this data from formatSpecialGroupHeader logic,
 * and the viewer only handles rendering.
 */
export interface GroupNameViewerData extends CellViewerData {
    value: any;
    /** Render mode */
    renderType: 'text' | 'person' | 'tag' | 'boolean' | 'priority';
    /** Plain text display name (used for text/boolean/fallback rendering) */
    displayName?: string;
    /** Tag items for tag render mode (module/dropdown/treeDropdown) */
    tags?: GroupNameTagItem[];
    /** Person items for person render mode */
    persons?: GroupNamePersonItem[];
    /** Boolean value string ('true' or 'false') for boolean render mode */
    boolValue?: 'true' | 'false';
    /** Priority numeric value for priority render mode */
    priorityValue?: number | string;
    /** Callback when a person name is clicked (for user profile jump) */
    onPersonClick?: (accountName: string) => void;
}
/**
 * Separator row viewer data
 */
export interface SeparatorRowViewerData extends CellViewerData {
    value: null | undefined;
    /** Separator nesting level */
    separateLevel?: number;
    /** Group level context */
    groupLevel?: number;
    /** Whether this is the end level */
    isEndLevel?: boolean;
    /** Row height override */
    rowHeight?: number;
}
/**
 * Punch (打卡进度) viewer data
 */
export interface PunchViewerData extends CellViewerData {
    value: PunchValue | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 日期显示模式 */
    datePattern?: string;
    /** 是否关联属性 */
    isLink?: boolean;
    /** 关联 key */
    linkKey?: string;
    /** 是否有错误 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
    } | null;
    /** 点击打卡区域回调（打开打卡详情/新增打卡弹窗） */
    onPunchDialogVisibleTrigger?: (visible: boolean, type: 'add' | 'detail', params?: any) => void;
}
/**
 * 打卡值
 */
export interface PunchValue {
    /** 打卡记录 ID，> 0 表示已打卡 */
    punch_id?: number;
    /** 所属节点 ID */
    node_id?: number;
    /** 打卡日期时间戳 */
    created_date?: number;
    /** 进度 0~1 */
    progress?: number;
    /** 审批状态 */
    review_status?: number | string;
    /** 是否已读 */
    is_read?: boolean;
}
/**
 * Module information
 */
export interface ModuleInfo {
    /** Module unique identifier */
    id: string;
    /** Module display name */
    name: string;
    /** Module color for tag background (optional) */
    color?: string;
}
/**
 * Module viewer data
 */
export interface ModuleViewerData extends CellViewerData {
    /** Module(s) - ModuleInfo object(s), string ID(s) as fallback, or null */
    value: ModuleInfo | ModuleInfo[] | string | string[] | null;
    /** Whether to show colored tags (default true) */
    showColor?: boolean;
    /** Maximum number of modules to display (default 3) */
    maxDisplay?: number;
    /** Placeholder text for empty values (default '-') */
    placeholder?: string;
}
/**
 * Text viewer with switcher data (tree expand/collapse + task name)
 */
export interface TextViewerWithSwitcherData extends CellViewerData {
    value: string | number | null;
    /** Display label (overrides value when present) */
    label?: string;
    /** Custom text color (default '#333') */
    color?: string;
    /** Whether to apply TAPD sync highlight color (overrides color when true) */
    tapdHighlight?: boolean;
    /** Whether the node is expanded */
    expanded?: boolean;
    /** Whether the node has children */
    hasChildren?: boolean;
    /** Whether the node is loading children */
    loading?: boolean;
    /** Tree indentation level (0 = root) */
    tableTreeLevel?: number;
    /** Array indicating whether each ancestor is the last leaf at its level */
    isLastLeafArr?: boolean[];
    /** Task icon file URL (dynamically loaded from data source) */
    iconFile?: string;
    /** Child node count */
    count?: number;
    /** Whether the node has downstream nodes */
    hasDownstreamNode?: boolean;
    /** Rich text HTML content */
    richText?: string;
    /** Placeholder for empty values */
    placeholder?: string;
    /** Whether this is a linked task */
    isLinkTask?: boolean;
    /** Linked task icon file URL */
    linkIconFile?: string;
    /** Whether to show strikethrough on text */
    showLineThrough?: boolean;
    /** Whether to show weakened (dimmed) text */
    weakenWord?: boolean;
    /** Text alignment */
    textAlign?: 'left' | 'center' | 'right';
    /** Error/warning state */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
        is_warning?: boolean;
        is_level_1_error?: boolean;
    };
    /** IOMC 提单状态（1=已提单, 2=未提单, 3=已驳回） */
    iomcOrderState?: number | string;
    /** Task icon tooltip text (pre-computed from iconFile, e.g. '在外部协作页面') */
    iconTooltip?: string;
    /** 商业化单子数（仅商业化库 name 列，由 businessData[rowId] 注入） */
    businessOrderCount?: number;
    /** 点击任务图标回调（如跳转 TAPD 页面），与 DOM 版 onClickNameIcon + iconJumpUrl 对齐 */
    onClickIcon?: (rowData: Record<string, any>) => void;
    /** 平铺模式：不显示缩进线和展开箭头，内容起始位置与表头对齐 */
    isFlatMode?: boolean;
}
/**
 * 文件项信息
 */
export interface FileItem {
    /** 文件名 */
    name: string;
    /** 文件格式/后缀 */
    fileFormat?: string;
    /** 预览图片 URL */
    previewUrl?: string;
    /** 是否正在上传/处理中 */
    doing?: boolean;
    /** 文件资产 ID */
    assetId?: number;
    /** 文件状态 */
    status?: number;
    /** 交付物角标标记（如 'ah-icon_finish1' / 'ah-icon_help2'） */
    mark?: string;
    /**
     * 是否是外部 OS 文件 drop 触发的上传中占位项。
     * 为 true 时 viewer 会画占位 + canvas 进度环（不走真实 thumbnail / status 路径）。
     * 由 FileViewer.draw 在合并 uploadingItems → files 时打上，业务层一般不直接设置。
     */
    _uploading?: boolean;
    /** 上传进度 0-100（仅当 _uploading=true 时有意义） */
    progress?: number;
    /** 占位 id，用于外部进度事件回写匹配 */
    uploadingId?: string;
}
/**
 * 文件 Viewer 数据接口
 */
export interface FileViewerData extends CellViewerData {
    /** 文件列表 */
    value: FileItem[] | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 隐藏右侧操作区域（编辑笔/查看图标），用于嵌套表格中由 NestedGrid 层统一绘制编辑笔 */
    hideAfterArea?: boolean;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 是否关联属性 */
    isLink?: boolean;
    /** 关联 key */
    linkKey?: string;
    /** 关联数据行 ID */
    linkedId?: string | number;
    /** 文件元数据 key */
    fileMeta?: string;
    /** 是否有错误 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
    } | null;
    /** 是否仅显示缩略图（隐藏文件名） */
    isDisplayThumbnail?: boolean;
    /** 缩略图模式下的图片适配方式（与 ImageViewerData.fit 对齐） */
    thumbnailFit?: 'contain' | 'cover' | 'fill' | 'height-full' | 'width-full';
    /** 鼠标移入文件项回调（用于显示大图预览，与 ImageViewer 的 onImgMouseIn 签名一致） */
    onFileMouseIn?: (previewUrl: string, virtualAnchor: any) => void;
    /** 鼠标移出文件项回调（用于隐藏大图预览，与 ImageViewer 的 onImgMouseOut 签名一致） */
    onFileMouseOut?: () => void;
    /** 双击文件项回调（打开文件详情，与 DOM fileViewer-v2.ts 的 onFileGoToDetail 对齐） */
    onFileGoToDetail?: (file: FileItem & {
        id?: string | number;
        ids?: number[];
    }, data: FileViewerData) => void;
    /**
     * 正在上传中的占位项（外部 OS 文件 drop 触发上传时由业务层 unshift 进来）。
     * 渲染规则：在 value 数组前面追加占位 file 项（占位文件图标 + 文件名 + 居中 canvas 进度环），
     * 上传完成后业务层从 uploadingItems 移除并把真实数据 push 到 value。
     * 字段语义与 ImageViewerData.uploadingItems 一致，详见那里说明。
     */
    uploadingItems?: Array<{
        id: string;
        name?: string;
        fileFormat?: string;
        previewUrl?: string;
        progress?: number;
    }>;
}
/**
 * HyperLink text viewer data (超链接文本)
 */
export interface HyperlinkTextViewerData extends CellViewerData {
    /** 值格式：[显示文本, 链接URL] 或 null */
    value: [string, string] | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 是否关联属性 */
    isLink?: boolean;
    /** 关联 key */
    linkKey?: string;
    /** 是否有错误 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
    } | null;
}
/**
 * 工作流状态 Viewer 数据接口
 */
export interface WfStateViewerData extends CellViewerData {
    /** 工作流状态 ID，支持数字、包含 id 的对象、或 null */
    value: number | {
        id: number;
    } | null;
    /** 状态显示名称 */
    displayName?: string;
    /** 状态大类（如 'toStart' | 'inProgress' | 'complete' | 'rejected' | 'paused'） */
    stateType?: string;
    /** 图标颜色 */
    iconColor?: string;
    /** 文字颜色 */
    color?: string;
    /** 图标类型标识 */
    icon?: string;
    /** 额外信息，非空时显示角标 */
    extraInfo?: Record<string, any> | null;
    /** 空值时的占位文本 */
    placeholder?: string;
    /** 色块模式（tag）的背景色 */
    backgroundColor?: string;
    /** 色块模式（tag）的文字颜色 */
    textColor?: string;
    /** 渲染样式模式：'icon' 图标+文字（默认），'tag' 色块标签 */
    wfStateStyle?: 'icon' | 'tag';
    /** 点击工作流状态文字回调（打开工作流弹窗） */
    onShowWorkFlowPopover?: (nodeId: number, anchor: {
        getBoundingClientRect: () => DOMRect;
    }) => void;
}
/**
 * Module info for an upstream field item
 */
export interface IUpstreamModule {
    /** Module display name (e.g. '原画', '建模') */
    displayName: string;
    /** Module tag background color */
    bgColor: string;
}
/**
 * Reminder properties for an incomplete upstream field item
 */
export interface IUpstreamReminderProperties {
    /** Reminder display text (e.g. '等待上游', '已超期') */
    displayName: string;
    /** Optional background color for the reminder tag */
    bgColor?: string;
    /** Whether this is a first-edition completion time */
    isFirstEditionTime?: boolean;
    [key: string]: any;
}
/**
 * Sync property representing a single resource preview
 */
export interface IUpstreamSyncProperty {
    /** Resource asset ID */
    assetId: number;
    /** Resource display name (e.g. 'asset_001.png') */
    displayName: string;
    /** File format extension (e.g. 'png', 'psd', 'fbx') */
    fileFormat: string;
    /** Preview image URL (empty string if no preview available) */
    imageUrl: string;
}
/**
 * A single upstream field view item representing one upstream dependency
 */
export interface IUpstreamFieldViewItem {
    /** Unique node identifier */
    nodeId: number;
    /** Module info with display name and color */
    module: IUpstreamModule;
    /** Whether the upstream dependency is completed */
    isAvailable: boolean;
    /** Reminder properties (present when isAvailable is false) */
    reminderProperties?: IUpstreamReminderProperties;
    /** Sync resource previews (present when isAvailable is true) */
    syncProperties?: IUpstreamSyncProperty[];
}
/**
 * Upstream viewer data - displays upstream dependency status
 */
export interface UpstreamViewerData extends CellViewerData {
    /** Array of upstream field view items */
    value: IUpstreamFieldViewItem[];
}
/**
 * 任务节点项信息
 */
export interface TaskNodeItem {
    /** 任务节点 ID */
    id: number;
    /** 任务节点名称 */
    name: string;
    /** 任务图标文件名（可选，无时显示默认图标） */
    iconFile?: string;
    /** TAPD 单 URL（存在时点击图标会打开此 URL，不再走详情页跳转） */
    tapdUrl?: string;
}
/**
 * 任务节点 Viewer 数据接口
 */
export interface TaskNodeViewerData extends CellViewerData {
    /** 任务节点数据，支持数组、逗号分隔字符串、单个数字 */
    value: TaskNodeItem[] | string | number | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 是否为关联属性 */
    isLink?: boolean;
    /** 关联属性 key */
    linkKey?: string;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 错误信息 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
        is_warning?: boolean;
    } | null;
    /** 自定义任务节点信息映射 */
    customTaskNodeInfo?: Record<number, {
        name: string;
        iconFile?: string;
        tapdUrl?: string;
    }>;
    /** 节点详情解析回调（渲染时通过 graph.getNode 查询，与 DOM 版 findNeedFetchNodeAndFormatNode 对齐） */
    taskNodeResolver?: (nodeId: number) => {
        id: number;
        name: string;
        iconFile?: string;
        tapdUrl?: string;
    } | null;
    /** 点击任务节点回调（打开业务节点详情页） */
    onTaskGoToDetail?: (nodeId: number) => void;
    /** 点击节点图标回调：当节点项绑定了 tapdUrl 时，命中图标区域会触发此回调而不是 onTaskGoToDetail */
    onClickIcon?: (tapdUrl: string) => void;
}
/**
 * ITFS path viewer data
 */
export interface ItfsPathViewerData extends CellViewerData {
    value: string | Record<string, any> | null;
    /** Path text color (default: #268bfb) */
    pathColor?: string;
    /** Icon color (default: #8e8e8e) */
    iconColor?: string;
    /** Whether to show netdisc icon (default: true) */
    showIcon?: boolean;
    /** Placeholder for empty values */
    placeholder?: string;
    /** 点击图标回调（弹出 ITFS 操作列表弹窗），anchor 为虚拟锚点用于弹窗定位 */
    onClickIcon?: (anchor: {
        getBoundingClientRect: () => DOMRect;
    }, payload: any) => void;
    /** 点击路径文本回调（触发名称点击逻辑） */
    onClickPath?: (payload: any) => void;
}
/**
 * Nested grid viewer data
 */
export interface NestedGridViewerData extends CellViewerData {
    value: any[];
    /** Nested grid columns */
    columns: NestedColumnConfig[];
    /** Whether to show expand all button */
    showExpandAll?: boolean;
    /** Default display rows when collapsed */
    displayRows?: number;
    /** Whether currently expanded */
    expanded?: boolean;
}
/**
 * Nested column configuration
 */
export interface NestedColumnConfig {
    key: string;
    title: string;
    width?: number;
    type?: string;
    align?: 'left' | 'center' | 'right';
    [key: string]: any;
}
/**
 * Viewer class constructor type
 */
export type ViewerConstructor<T extends CellViewerData = CellViewerData> = new () => CellViewer<T>;
/**
 * Viewer factory function type
 */
export type ViewerFactory<T extends CellViewerData = CellViewerData> = () => CellViewer<T>;
/**
 * Viewer type mapping
 */
export interface ViewerTypeMap {
    text: TextViewerData;
    select: DropdownViewerData;
    image: ImageViewerData;
    person: PersonViewerData;
    progress: ProgressViewerData;
    datetime: DatetimeViewerData;
    date: DatetimeViewerData;
    time: DatetimeViewerData;
    month: DatetimeViewerData;
    boolean: BooleanViewerData;
    checkbox: BooleanViewerData;
    status: StatusViewerData;
    'group-header': GroupHeaderViewerData;
    'group-name': GroupNameViewerData;
    'separator-row': SeparatorRowViewerData;
    nested: NestedGridViewerData;
    punch: PunchViewerData;
    'punch-timing': PunchTimingViewerData;
    hyperlink: HyperlinkTextViewerData;
    file: FileViewerData;
    'task-node': TaskNodeViewerData;
    'wf-state': WfStateViewerData;
    workflow: WorkflowViewerData;
    'file-storage-spec': FileStorageSpecViewerData;
    pivot: PivotViewerData;
    module: ModuleViewerData;
    'text-with-switcher': TextViewerWithSwitcherData;
    upstream: UpstreamViewerData;
    'table-action-button': TableActionButtonViewerData;
    'priority-text': PriorityTextViewerData;
    'status-text': StatusTextViewerData;
    theme: ThemeViewerData;
    'itfs-path': ItfsPathViewerData;
    'deliverable-review': DeliverableReviewViewerData;
    'rich-text': RichTextViewerData;
    'cp-person': CpPersonViewerData;
}
/**
 * All supported viewer types
 */
export type ViewerType = keyof ViewerTypeMap;
/**
 * Cell data with viewer type
 */
export interface TypedCellData<T extends ViewerType = ViewerType> {
    viewerType: T;
    data: ViewerTypeMap[T];
}
/**
 * Type guard for viewer data
 */
export declare function isTextViewerData(data: CellViewerData): data is TextViewerData;
export declare function isDropdownViewerData(data: CellViewerData): data is DropdownViewerData;
export declare function isPersonViewerData(data: CellViewerData): data is PersonViewerData;
export declare function isProgressViewerData(data: CellViewerData): data is ProgressViewerData;
export declare function isNestedGridViewerData(data: CellViewerData): data is NestedGridViewerData;
/**
 * 交付地址 Viewer 数据接口
 * 接收业务层已处理好的地址字符串（URL 格式转换和权限脱敏由业务层完成）
 */
export interface FileStorageSpecViewerData extends CellViewerData {
    /** 交付地址显示文本（业务层将原始 URL 经过格式转换和权限脱敏后传入） */
    value: string | null;
    /** 空值时的占位文本（默认 '-'） */
    placeholder?: string;
    /** 点击文字区域后的回调（用于打开存储地址弹窗） */
    onTextClick?: (ids: number[], rawValue: any) => void;
}
/**
 * 引用类型 Viewer 数据接口
 * 接收业务层将引用属性值格式化后传入的显示文本
 *
 * 支持根据 pivotFieldViewer 委托给子 viewer 渲染：
 * - 'person' → PersonViewer（人员头像 + 名称）
 * - 'image' → ImageViewer（交付物缩略图）
 * - 'wf-state' → WfStateViewer（工作流状态图标 + 名称）
 * - 其他 / undefined → 默认文本渲染
 *
 * 数据流：
 * 1. rowDataAdapter.transformPivotValue 将 PivotValueItem[] 转为结构化对象
 *    （包含 pivotFieldViewer + 原始子字段值 pivotRawValue）
 * 2. cellValueTransformer（AssetMatrix 侧）根据 pivotFieldViewer 调用对应的
 *    _transformPersonValue / _transformWfStateValue 等方法，将 pivotRawValue
 *    转为子 viewer 期望的格式，写入 pivotData
 * 3. PivotViewer.draw() 根据 pivotFieldViewer 委托给对应 viewer 实例绘制
 */
export interface PivotViewerData extends CellViewerData {
    /** 引用属性的格式化显示文本（由业务层将 pivotField 解析后传入） */
    value: string | null;
    /** 空值时的占位文本（默认 '-'） */
    placeholder?: string;
    /** 是否为关联属性（为 true 时显示关联图标） */
    isLink?: boolean;
    /**
     * pivotField 对应的 viewer 类型（Canvas 映射后的类型名，如 'person'、'image'、'wf-state'）。
     * 由 transformPivotValue 从 pivotResolver 获取并注入。
     * 当此字段存在且非 'text' 时，PivotViewer 会委托给对应的子 viewer 渲染。
     */
    pivotFieldViewer?: string;
    /**
     * pivotField 的原始值（从 PivotValueItem[0][pivotField] 提取）。
     * 由 transformPivotValue 注入，供 cellValueTransformer 进一步转换。
     * 例如：person 类型为 accountName string，wf-state 类型为 state ID number。
     */
    pivotRawValue?: any;
    /**
     * 子 viewer 的已转换数据（由 cellValueTransformer 写入）。
     * 例如：person 类型为 PersonInfo[]，wf-state 类型为 WfStateViewerData 对象。
     * PivotViewer.draw() 将此数据传给对应子 viewer 的 draw() 方法。
     */
    pivotData?: any;
    /**
     * 交付物图片的 assetId 列表（仅 pivotFieldViewer === 'image' 时有值）。
     * 由 transformPivotValue 从 deliverable 对象中提取，用于双击打开文件详情。
     */
    pivotAssetIds?: number[];
    /** 双击文件项回调（打开文件详情，由 DataGridIntegration 从 fileCallbacks 注入） */
    onFileGoToDetail?: (file: any, data: any) => void;
    /** 点击图片回调（打开图片预览，由 DataGridIntegration 从 imageCallbacks 注入） */
    onClickImage?: (imgUrls: string[], initIndex: number, assetIds: (number | string | undefined)[], data: any) => void;
}
/**
 * 工作流 Viewer 数据接口
 * 接收业务层已转换好的工作流显示名称数组
 */
export interface WorkflowViewerData extends CellViewerData {
    /** 工作流显示名称数组（由业务层将工作流 ID 通过 wfStateManager 转换后传入） */
    value: string[];
    /** 空值时的占位文本（默认 '-'） */
    placeholder?: string;
    /** 点击工作流文字回调（打开工作流弹窗） */
    onShowWorkFlowPopover?: (nodeId: number, anchor: {
        getBoundingClientRect: () => DOMRect;
    }) => void;
}
/**
 * Single button option for table action button viewer
 */
export interface TableActionButtonOption {
    /** Button unique identifier */
    name: string;
    /** Button display text */
    displayName: string;
    /** Whether this is a super admin button (orange style) */
    isSuperBtn?: boolean;
    /** Whether this is an operation button (blue style) */
    isOperationBtn?: boolean;
    /** Custom background color */
    backgroundColor?: string;
    /** Custom text color */
    color?: string;
}
/**
 * Table action button viewer data
 */
export interface TableActionButtonViewerData extends CellViewerData {
    /** Array of button options */
    value: TableActionButtonOption[] | null;
    /** Data row ID */
    id?: string | number;
    /** Property key */
    key?: string;
    /** Whether the buttons are editable/clickable */
    canEdit?: boolean;
    /** Whether this is a linked task (shows link icon, no buttons) */
    isLinkTask?: boolean;
    /** Whether to show link icon */
    isLink?: boolean;
    /** Link key */
    linkKey?: string;
    /** Button click callback */
    onButtonClick?: (event: MouseEvent, payload: {
        id: string | number;
        operation: TableActionButtonOption;
    }) => void;
    /** Operation button click callback */
    onOperationBtnClick?: (event: MouseEvent, payload: {
        id: string | number;
        data: TableActionButtonViewerData;
    }) => void;
    /** "More" button click callback */
    onAfterClick?: (event: MouseEvent, payload: {
        data: TableActionButtonViewerData;
        position: {
            x: number;
            y: number;
        };
    }) => void;
}
/**
 * 打卡时间查看器数据接口
 * 用于显示打卡的时间信息，如00:00:00格式的时间显示
 */
export interface PunchTimingViewerData extends CellViewerData {
    /** 时间值，支持字符串格式如'00:00:00'或时间戳 */
    value: string | number | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 是否关联属性 */
    isLink?: boolean;
    /** 关联 key */
    linkKey?: string;
    /** 是否有错误 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
    } | null;
    /** 时间格式，默认'HH:mm:ss' */
    timeFormat?: string;
    /** 是否显示为24小时制 */
    is24Hour?: boolean;
    /** 是否显示毫秒 */
    showMilliseconds?: boolean;
    /** 占位符文本，默认'-' */
    placeholder?: string;
    /** 文本对齐方式 */
    textAlign?: 'left' | 'center' | 'right';
    /** 字体大小 */
    fontSize?: number;
    /** 字体颜色 */
    color?: string;
    /** 背景颜色 */
    backgroundColor?: string;
    /** 计时器状态 */
    timerState?: {
        /** 计时器ID */
        timerId: number | null;
        /** 开始时间戳 */
        startTime: number | null;
        /** 当前显示时间 */
        currentTime: string;
        /** 计时器状态 */
        status: 'start' | 'pause';
        /** 是否正在计时 */
        isTiming: boolean;
    };
    /** 点击暂停按钮的回调（用于打开今日打卡弹窗） */
    onPauseTimer?: (nodeId: number, startTime: number | null) => void;
    /** 点击开始按钮的回调（前置校验 + API 调用），返回 true 表示可以开始计时 */
    onStartTimer?: (nodeId: number) => Promise<boolean>;
}
/**
 * 优先级文本 viewer 数据
 * 用于展示优先级标签（P0-P4+），带有对应的颜色和背景色
 */
export interface PriorityTextViewerData extends CellViewerData {
    /** 优先级值，支持数字或字符串（如 0, 1, 2, '0', '1'） */
    value: string | number | null;
    /** 文本对齐方式，默认 'center' */
    textAlign?: 'left' | 'center' | 'right';
    /** 标签圆角半径，默认 2 */
    tagRadius?: number;
    /** 占位符文本，默认 '-' */
    placeholder?: string;
}
/**
 * 状态枚举项
 */
export interface StatusTextEnum {
    /** 状态值标识（如 'toStart', 'inProgress', 'complete'） */
    value: string;
    /** 状态显示名称（如 '未开始', '进行中', '已完成'） */
    name: string;
    /** 文字颜色 */
    color: string;
    /** 图标类型（'circle' | 'pause' | 'progress' | 'check' 或自定义字符串） */
    icon: string;
    /** 图标颜色 */
    iconColor: string;
}
/**
 * 状态文本 viewer 数据
 * 用于展示状态标签（图标 + 状态名称），如 [●] 进行中
 */
export interface StatusTextViewerData extends CellViewerData {
    /** 状态名称（匹配 statusList 中的 name 字段） */
    value: string | null;
    /** 自定义状态枚举列表，不传则使用默认状态列表 */
    statusList?: StatusTextEnum[];
    /** 是否显示图标，默认 true */
    showIcon?: boolean;
    /** 图标大小，默认 14 */
    iconSize?: number;
    /** 是否显示角标指示器，默认 false */
    showCorner?: boolean;
    /** 额外信息（当存在时且 showCorner 为 true 显示角标） */
    extraInfo?: Record<string, any>;
    /** 占位符文本，默认 '-' */
    placeholder?: string;
}
/**
 * 主题项信息
 */
export interface ThemeItem {
    /** 主题唯一标识 */
    id: string;
    /** 主题显示标题 */
    title: string;
}
/**
 * 主题文本 viewer 数据
 * 用于展示主题标签（图标 + 主题名称 + 后缀），如 [🎨] 主题A 等2个
 */
export interface ThemeViewerData extends CellViewerData {
    /** 主题列表，支持 ThemeItem[] 或 string[] */
    value: ThemeItem[] | string[] | null;
    /** 是否显示图标，默认 true */
    showIcon?: boolean;
    /** 图标大小，默认 14 */
    iconSize?: number;
    /** 图标颜色，默认 '#8c8c8c' */
    iconColor?: string;
    /** 后缀文字颜色，默认 '#999' */
    suffixColor?: string;
    /** 占位符文本，默认 '-' */
    placeholder?: string;
}
/**
 * 交付物审核文件项
 */
export interface DeliverableReviewItem {
    /** 文件名 */
    name: string;
    /** 文件格式/后缀 */
    file_format?: string;
    /** 预览图片 URL */
    preview_url?: string;
    /** 资产 ID */
    asset_id?: number;
    /** 审核 ID（> 0 表示为审核类型文件） */
    review_id?: number;
    /** 是否为审核类型 */
    isReview?: boolean;
}
/**
 * 交付物审核 viewer 数据
 * 用于展示交付物审核文件列表（审核图标 + 文件名）
 */
export interface DeliverableReviewViewerData extends CellViewerData {
    /** 审核文件列表 */
    value: DeliverableReviewItem[] | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 是否关联属性 */
    isLink?: boolean;
    /** 关联 key */
    linkKey?: string;
    /** 文件元数据 key */
    fileMeta?: string;
    /** 是否有错误 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
    } | null;
    /** 占位符文本，默认 '-' */
    placeholder?: string;
}
/**
 * 富文本 viewer 数据
 * 用于展示富文本内容，去除 HTML 标签后渲染纯文本
 * <img> 标签显示为 [图片]，<video> 标签显示为 [视频]
 */
export interface RichTextViewerData extends CellViewerData {
    /** HTML 富文本内容或纯文本 */
    value: string | null;
    /** 数据行 ID */
    id?: string | number;
    /** 属性 key */
    key?: string;
    /** 是否可编辑 */
    canEdit?: boolean;
    /** 是否显示删除线 */
    showLineThrow?: boolean;
    /** 是否关联属性 */
    isLink?: boolean;
    /** 关联 key */
    linkKey?: string;
    /** 是否有错误 */
    error?: {
        errorProperty?: string;
        errorMessage?: string;
    } | null;
    /** 占位符文本，默认 '-' */
    placeholder?: string;
}
/**
 * Related-task display field item
 */
export interface RelatedTaskDisplayField {
    /** Field key (e.g. 'estimate_start_date') */
    key: string;
    /** Field display label (e.g. '预计开始时间') */
    label: string;
    /** Raw field value */
    value: any;
    /** Formatted display value (e.g. '2026/03/02') */
    displayValue: string;
    /** Whether this field is a file-type field */
    isFileType: boolean;
    /** File data for file-type fields (cover images, etc.) */
    fileData?: Array<{
        coverUrl: string;
        assetId?: number;
        status?: number;
        fileFormat?: string;
        mark?: string;
    }>;
    /** File meta key for file-type fields (e.g. 'deliverable') */
    fileMeta?: string;
    /** Node ID that owns this file (for opening asset detail) */
    nodeId?: number;
}
/**
 * Related-task Viewer data interface
 * Displays the first related task's configured display fields
 */
export interface RelatedTaskViewerData extends CellViewerData {
    /** Structured value containing related task info */
    value: {
        /** First related task node ID */
        firstRelatedTaskId: number;
        /** First related task name */
        firstRelatedTaskName: string;
        /** Display label for the task name field (e.g. "名称") */
        firstRelatedTaskLabel?: string;
        /** All related node IDs (for future interactions) */
        allRelatedNodeIds: number[];
        /** Display fields with resolved values */
        displayFields: RelatedTaskDisplayField[];
    } | null;
    /** Thumbnail fit mode for file-type fields (synced from imageDisplayMode config) */
    thumbnailFit?: 'contain' | 'cover' | 'fill' | 'height-full' | 'width-full';
    /** Callback when user clicks a file thumbnail — opens asset detail page */
    onFileGoToDetail?: (file: {
        assetId: number;
        id: number;
        ids: number[];
    }, data: any) => void;
}
/**
 * CP 人员信息（由 cpUserResolver 返回）
 */
export interface CpPersonInfo {
    id: string;
    /** 显示名称，格式如 "公司名/基地/昵称" */
    showName: string;
}
/**
 * CP 人员 Viewer 数据接口
 * 用于展示外包人员（CP User）信息
 * 对齐 DOM 版 cpPersonViewer.ts 的渲染逻辑
 */
export interface CpPersonViewerData extends CellViewerData {
    /** CP 用户 ID 数组或单个 ID 字符串 */
    value: string[] | string | null;
    /** 头像大小，默认 16 */
    avatarSize?: number;
    /** 最大显示人数，默认 3 */
    maxDisplay?: number;
    /** 空值占位符，默认 '-' */
    placeholder?: string;
    /**
     * CP 用户解析回调
     * 同步返回已缓存的用户信息，对未缓存的 ID 触发异步加载后调用 requestRedraw
     * @param ids CP 用户 ID 数组
     * @param requestRedraw 重绘回调，异步加载完成后调用
     * @returns 已解析的用户信息数组（未解析的以 ID 作为 showName）
     */
    cpUserResolver?: (ids: string[], requestRedraw: () => void) => CpPersonInfo[];
}
