import { ChangeDetectorRef, ElementRef, EventEmitter, OnDestroy, OnInit, SimpleChange, TemplateRef } from "@angular/core"; import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from "ng-zorro-antd/core"; import { NzResizeEvent } from "ng-zorro-antd/resizable"; import { NzTableComponent } from "ng-zorro-antd/table"; import { Observable } from "rxjs"; import { TotalOption } from "../hd-detail-lines/hd-detail-lines.service"; import { Page } from "../model/common-type"; import { CommonSessionService } from "../service/common-session.service"; import { HdTableCellChange, HdTableColumn, OperateBtn, TableCacheOption, TreeGrid } from "./hd-table.service"; export declare class HdTableComponent implements OnInit, OnDestroy { private hostEl; private cdr; private commonSessionService; uuid: string; tableCols: Array; tableData: Page; showSelected: boolean; /** * 勾选列形态。checkbox:多选(默认);radio:单选,无表头全选,selectEvent 仍回传数组(0 或 1 条)。 */ selectType: "checkbox" | "radio"; showOperateColWarpButton: boolean; /** 是否展示列设置(齿轮),默认开启;弹窗等场景可传 false 关闭 */ showColSettings: boolean; virtualScroll: boolean; /** 手动指定行高;不传则在首屏渲染后自动测量 */ virtualItemSize: number; selectField: string; /** * 行勾选禁用字段名。定义后取当前行该字段: * 为 true 时禁用该行勾选(全选也会跳过)。 */ selectDisabledField: string; /** * 行失效字段名。定义后取当前行该字段: * 为 true 时整行背景色为 #F7F8FA。 */ rowInvalidField: string; showTableTotal: boolean; tableTotalOption: Array; /** * 合计列总数(含序号列,与 hd-detail-lines 一致); * 不传则按当前可见数据列数 + 1(序号)推算。 */ columnsNumber: number | string; sortEvent: EventEmitter<{}>; selectEvent: EventEmitter<{}>; tableSearchEvent: EventEmitter<{}>; /** 行内编辑变更(已写回行对象;previous* 供接口失败回滚) */ cellChange: EventEmitter; tableLoading: boolean; /** 是否显示分页;false 时一次展示 tableData.content 全部行 */ pagination: boolean; /** * 是否前端分页(对 content 全量切片)。 * true:翻页不触发 tableSearchEvent,适合详情全量数据; * false(默认):服务端分页,翻页触发查询(现有列表行为)。 * 与 pagination=false 同时用时以不分页为准。 */ frontPagination: boolean; tablePageIndex: number; tablePageSize: number; isFirstEntrySearch: boolean; isCrossPageSelect: boolean; tablePageIndexChange: EventEmitter; tablePageSizeChange: EventEmitter; tablePageSizeChangeEvent: EventEmitter; tableTotal: TemplateRef; tableLeftButton: TemplateRef; tableRightButton: TemplateRef; scroll: any; isAllDisplayDataChecked: boolean; isIndeterminate: boolean; listOfDisplayData: any[]; listOfAllData: any[]; listOfSelection: Array | TemplateRef; mapOfCheckedId: { [key: string]: boolean; }; mapOfCheckList: { [key: string]: any; }; tableTotalOptionList: any[]; tableCacheOption: TableCacheOption; userSession: any; tableColsCache: Array; showTable: boolean; selectColListNodes: Array; selectColListNodesCache: Array; showListNodes: boolean; isDropdownVisible: boolean; nowListNodes: Array; hideListNodes: Array; cancelNowListNodes: Array; cancelHideListNodes: Array; showDetail: boolean; localforage: any; localtionTmp: string; isFirstEntrySearchLocal: boolean; isCrossPageSelectLocal: boolean; /** 自动测量前的兜底行高,测量完成后会更新 */ measuredVirtualItemSize: number; /** 记录当前是否处于虚拟滚动模式,用于切换 pageSize 时重建表格 */ private virtualScrollActive; /** 实际渲染列宽合计(含勾选/序号 + 补宽),合计 footer 表宽用 */ tableColWidthTotal: number; /** 待按比例分给各业务列的总补宽;只影响展示,不写回 col.width(列宽缓存、拖拽仍用声明宽) */ fluidExtraWidth: number; /** 列少、靠补宽吃满容器:模板据此加 hd-table--fluid-x,隐藏 fixed-header 常驻的横滚槽 */ fluidHorizontal: boolean; /** 各业务列分到的补宽(按列对象取,applyHorizontalLayout 时整表重建) */ private fluidExtraByCol; /** 数据更新后待复位纵向滚动位置 */ private pendingResetScrollTop; /** 当前排序,表格重建后用于恢复表头排序态 */ private currentSortKey; private currentSortValue; nzTableComponent: NzTableComponent; private totalFooterScrollBoundBody; private totalFooterScrollHandler; private totalFooterSyncRetry; /** 表体有竖滚条时合计 footer 才预留右侧滚动条槽 */ totalFooterNeedYGutter: boolean; /** 视口/容器尺寸变化时重算 scroll.x 与合计对齐 */ private viewportResizeTimer; private boundOnViewportResize; private hostResizeObserver; /** select 展开 / 搜索防抖(对齐 form-lines) */ private selectOpenChangeSubject; private selectOpenChangeSubscription; private selectSearchSubject; private selectSearchSubscription; /** 异步回写 options 的订阅,避免连点搜索泄漏 */ private selectLoaderSubscription; constructor(hostEl: ElementRef, cdr: ChangeDetectorRef, commonSessionService: CommonSessionService); ngOnDestroy(): void; /** 供业务在自行写回 options 后触发 OnPush 刷新(优先 return Observable/Promise 由组件处理) */ markForCheck(): void; ngOnInit(): void; ngOnChanges(changes: SimpleChange): void; /** 是否走前端分页(对 content 切片,不请求后端) */ readonly useFrontPagination: boolean; deleteHideItem(): void; sort(sort: { key: string; value: string; }): void; getColSort(col: HdTableColumn): string | null; toggleShowDetail(): void; readonly effectiveVirtualItemSize: number; /** * 纵向可用高度扣减:按钮区/合计/分页等固定占位。 * 必须与 dealScroll / presetScrollBeforeRemount 使用同一套,否则会误判「能放下」而不设 scroll.y。 */ private getScrollYMaxOffset; /** * 当前视口实际展示的行数。 * 前端分页按 pageIndex/pageSize 切片估算,避免用全量 length 误判需要纵向滚动。 */ private getVisibleRowCount; /** 当前页内容高度是否超出视口(需要表内纵向滚动) */ readonly needsVerticalScroll: boolean; /** 当前页数据能完整展示时不启用虚拟滚动,避免少量数据也出现滚动条 */ readonly useVirtualScroll: boolean; getRightSticky(col: HdTableColumn): string | null; getLeftSticky(col: HdTableColumn): string | null; /** * 序号列固定宽(含 padding,可容纳 6 位如 199995)。 * 不锁死时表体会随位数变宽(1→~64px,199995→~67px),合计行对不齐。 */ readonly lineNumberColWidth = 72; /** 开启合计时序号列的 left(跟在勾选列后面) */ readonly lineNumberLeft: string; readonly lineNumberColWidthPx: string; /** * 无 scroll.x 时合计走 fluid(width:100%)。 * 列少时也会设 scroll.x(补宽吃满),合计走固定表宽。 */ readonly isTotalFooterFluid: boolean; private isColVisible; /** 业务列声明宽:未配置时按 fixColWidth */ private getColDeclaredWidth; /** 声明列宽合计:勾选列 + 序号列 + 可见业务列,不含补宽 */ private getDeclaredColWidthTotal; /** 模板里 th / td / 合计 col 用的列宽:声明宽 + 该列按比例分到的补宽 */ getColDisplayWidth(col: HdTableColumn): number; /** * 把 fluidExtra 按各可见业务列声明宽比例分配(最大余数法), * 勾选列 / 序号列不参与;保证各列补宽之和等于 fluidExtra。 */ private rebuildFluidExtraByCol; /** 把横向布局结果写回组件状态(dealScroll / syncHorizontalScroll 共用) */ private applyHorizontalLayout; /** fluid → 100%;固定 → scroll.x(与表体同一套横向宽度) */ readonly totalFooterTableWidth: string; /** 当前页行号(跨页连续,从 1 开始) */ getLineNumber(index: number): number; trackByRow: (index: number, data: any) => string; /** 虚拟滚动按数组下标追踪,避免业务主键 trackBy 导致 CDK 行复用错位 */ virtualTrackByRow: (index: number) => number; trackByCol: (_index: number, col: HdTableColumn) => string; getInitLocalforage(): void; initTable(): void; /** 虚拟/普通模式切换时重建表格,避免残留滚动容器 */ applyTableScrollMode(forceRemount?: boolean): void; /** 销毁并重建 nz-table:等 DOM 出来后再按真实容器宽重算一次横向布局 */ private remountTable; /** 重建前预设 scroll,保证 AfterViewInit 时 header/body 结构已正确 */ private presetScrollBeforeRemount; private afterTableRender; refreshVirtualScrollViewport(forceMeasure?: boolean): void; /** 数据刷新后将表体纵向滚动复位到顶部 */ private resetTableBodyScrollTop; /** * 数据更新后多次尝试复位。 * ng-zorro 8 + CDK 虚拟滚动会在数据刷新后异步改写 scrollTop,单次复位经常被覆盖。 */ private scheduleResetTableBodyScrollTop; private flushResetTableBodyScrollTop; /** 未手动传 virtualItemSize 时,从已渲染行测量真实高度 */ measureVirtualItemSize(force?: boolean): boolean; cancelDropdown(): void; confirmDropdown(): void; submitGrids(): void; setCols(): void; beforeDrop: (arg: NzFormatBeforeDropEvent) => Observable; moveElementNearby(arr: any, elementToMoveTitle: any, targetElementTitle: any, pos: any): any; checkAction(event: NzFormatEmitEvent): void; getHideListNodes(): Array; dealCols(): void; normalizeTableCacheOption(): void; private hasColsCache; saveTableCacheOption(): void; judgeRepeatCols(): boolean; onResize({ width }: NzResizeEvent, col: HdTableColumn): void; dealOperateBtn(): void; triggerEvent(fn: any, event: any): void; needShowConfirm(btn: OperateBtn, data: any): boolean; getBtnName(btn: OperateBtn, data: any): string; isDangerBtn(btn: OperateBtn, data: any): boolean; /** 虚拟滚动开启时使用视口最大高度 */ private getVirtualScrollY; /** * 按声明列宽合计 + 容器宽算出横向布局。 * 判断「是否超宽」用 offsetWidth(含竖滚条槽),避免只因竖滚条就误开横滚; * 补宽目标用 clientWidth 并向下取整,避免表宽多 1px 逼出横滚条。 */ private resolveHorizontalLayout; /** 表格渲染后按真实容器宽校正横向布局;只改 x,y 保持不变 */ private syncHorizontalScroll; /** 手动把表体横向滚动同步到表头 / 合计 footer(兜底 ng-zorro 监听丢失的情况) */ private syncHeaderBodyScrollLeft; /** 取表体横向滚动容器(虚拟滚动优先 viewport) */ private getTableBodyScrollEl; private getTotalFooterScrollEl; /** 表体是否出现纵向滚动条(含滚动条槽宽) */ private bodyHasVerticalScrollbar; /** * 合计 footer 与表体联动: * - fluid(列未撑满):不横滚、不测宽,表宽 100% 与表体同比例拉伸; * - fixed(有 scroll.x):同步 scrollLeft; * - 仅当表体有竖滚条时预留右侧槽,行少无竖滚时不占位。 */ private syncTotalFooterWithBody; private syncTotalFooterScrollLeft; private bindTotalFooterScrollSync; private unbindTotalFooterScrollSync; /** * 监听窗口 / 容器宽度变化:重新判定 scroll.x(fluid↔fixed)与合计右侧竖滚槽, * 避免拉宽/缩窄屏幕后合计行宽与表体错位。 */ private bindViewportResizeSync; private unbindViewportResizeSync; private scheduleViewportScrollSync; /** * 左/右冻结偏移按展示宽累计(fluid 比例补宽后各列变宽,不能再用声明宽)。 * 须在 applyHorizontalLayout 之后调用。 */ private refreshStickyOffsets; dealScroll(): void; currentPageDataChange($event: any): void; search(reset: boolean): void; /** * 底部合计:与 hd-detail-lines 相同,使用 TotalOption(insertIndex / insertValue)。 * 开启后强制展示序号列,「合计」落在序号列下; * insertIndex 从 1 起对应可见数据列;未传 insertValue 时按该列 name 对 content 求和。 */ calculateTableTotal(): void; private getTableTotalCellMeta; /** 合计单元格展示文案(对齐 detail-lines 小数规则) */ getTableTotalCellValue(col: HdTableColumn, colIndex: number): any; getTableTotalCellAlign(col: HdTableColumn, colIndex: number): string; /** 底部「共 n 条」:非分页/前端分页用 content.length,服务端分页用 totalElements */ getTableTotalCount(): number; resetStatus(): void; /** 单选:选中当前行并清掉其它行;忽略 radio 因切换而发出的 false */ onRadioSelect(checked: boolean, data: any): void; refreshStatus(event?: boolean, data?: any): void; checkAll(value: boolean): void; /** 当前行是否禁用勾选 */ isSelectDisabled(data: any): boolean; /** 当前行是否失效 */ isInvalidRow(data: any): boolean; /** * 列文字颜色:color 为函数时按行计算(用于某一行某一列标红),否则整列同色。 */ resolveCellColor(col: HdTableColumn, data: any): string; /** 可点击单元格颜色:空值固定灰,否则按列 color */ getLinkCellColor(col: HdTableColumn, data: any, isEmpty: boolean): string; /** 普通文本单元格颜色:失效行统一灰,否则用列配置 color */ getPlainCellColor(col: HdTableColumn, data: any): string; judgeColEmpty(str: any): any; getStateField(col: HdTableColumn): string; /** 字段值后是否展示竖线行号 */ hasRowNo(col: HdTableColumn): boolean; /** * 行号文案。rowNo 为字段名时取行数据;为 true 时按当前页序号(跨页连续,从 1 开始)。 */ getRowNoText(col: HdTableColumn, data: any, index: number): string; /** 表头「配送单号 | 行」拆成短竖线,避免字符 | 拉满行高 */ getTitleParts(col: HdTableColumn): Array; /** 是否显示编辑笔图标(有 editType 时走行内控件,不再显示笔) */ isEditable(col: HdTableColumn, data: any): boolean; /** 点击编辑笔,回调父组件传入的 edit */ onEditClick(event: Event, col: HdTableColumn, data: any): void; /** 列是否配置了可用的行内编辑(name 必须是 string) */ hasInlineEdit(col: HdTableColumn): boolean; isEditDisabled(col: HdTableColumn, data: any): boolean; getSelectList(col: HdTableColumn, data: any): Array; getSelectOptionLabel(col: HdTableColumn, item: any): string; getInputNumberProp(col: HdTableColumn, key: "min" | "max" | "step" | "precision", fallback: number): number; isDateShowTime(col: HdTableColumn): boolean; isDateShowToday(col: HdTableColumn): boolean; getDateFormat(col: HdTableColumn, isRange: boolean): string; getDisabledDate(col: HdTableColumn): (current: Date) => boolean; getRangePlaceholder(col: HdTableColumn): Array; /** Input / InputNumber / 日期变更:先记旧值再写回并通知父组件 */ onCellChange(col: HdTableColumn, data: any, value: any): void; /** * Select 展开:有 onOpenChangeEvent 时展开先清空选项再回调 (open, line);关闭不回调业务。 * 回调若 return 数组 / Promise / Observable,由组件写回 options 并 markForCheck。 */ onSelectOpenChange(col: HdTableColumn, data: any, open: boolean): void; /** * Select 搜索:有 onSearchEvent 时回调 (keyword, line),不清空 options。 * 回调若 return 数组 / Promise / Observable,由组件写回 options 并 markForCheck。 */ onSelectSearch(col: HdTableColumn, data: any, keyword: string): void; /** 展开时清空列 selectList 或行上 selectListName,由业务回调再写入 */ private clearSelectOptionsOnOpen; /** * 处理加载回调返回值:数组直接写回;Promise/Observable 完成后写回;void 仅 markForCheck。 * 优先写 selectListName,否则写列上 selectList。 */ private handleSelectLoaderResult; private applySelectOptions; /** Select 变更:双写 value + label,并带 previous* / option */ onSelectChange(col: HdTableColumn, data: any, value: any): void; }