[TOC]

# Fantasy-Ngzorro

基于 **Angular 8** + **ng-zorro-antd 8.5.x** 的业务组件库，封装按钮、表格、表单、详情页等常用 UI 模式。

## 组件一览

| 序号 | 选择器 | 说明 |
| ---- | ------ | ---- |
| 1 | `hd-button` | 按钮 |
| 2 | `hd-button-group` | 按钮组（左右布局） |
| 3 | `hd-space` | 间隔占位 |
| 4 | `hd-tip` | 小标题 |
| 5 | `hd-status` | 状态标签 |
| 6 | `hd-popconfirm` | 气泡确认框 |
| 7 | `hd-filter` | 筛选器 |
| 8 | `hd-current-table` | 通用表格（自定义列模板） |
| 9 | `hd-table` | 增强表格（列配置、排序、列缓存） |
| 10 | `hd-form` | 表单 |
| 11 | `hd-form-lines` | 明细表单（可编辑表格） |
| 12 | `hd-detail-tip` | 详情头 |
| 13 | `hd-detail-form` | 详情单头 |
| 14 | `hd-detail-lines` | 详情明细（前端分页 / 搜索） |
| 15 | `hd-detail-lines-page` | 详情明细（服务端分页） |
| 16 | `hd-log` | 操作日志 |
| 17 | `hd-accessory-list` | 附件列表（分组标签 + 可下载文件行） |

> 配置类型（SelectOption、FormItem、HdTableColumn 等）见 [附录：公共配置类型](#附录公共配置类型)。

## 更新记录

| 更新人 | 更新时间 | 更新内容 |
| ------ | -------- | -------- |
| MC | 2023-2-10 | Readme 创建；按钮、按钮组、通用表格、筛选器、状态、详情头、详情单头、详情明细文档 |
| MC | 2023-2-13 | 表单、明细表单、间隔、小标题文档；组件字段增加必填说明 |
| — | 2026-5-20 | 补充 hd-table、hd-detail-lines-page 等组件；完善公共子类型（SelectOption、FormItem 等）文档 |
| — | 2026-9-18 | `hd-form-lines` 选中回显（nzHide）认 `showLabelAndValue`，与下拉 `[value]label` 一致（对齐 `hd-form`） |
| — | 2026-9-18 | `hd-detail-lines-page` 对齐 `hd-table` 支持虚拟滚动（`virtualScroll` / `virtualItemSize`）；千行勾选时减少 DOM 卡顿 |
| — | 2026-9-21 | hd-table 列支持 `rowNo`：字段值后竖线展示行号，前面字段仍可超链接 |
| — | 2026-9-22 | `hd-form-lines` 支持列设置（`showColSettings` 默认开）：仅非 hide 的 ViewDom 可显隐，禁止调序；可选 `uuid` 缓存 |
| — | 2026-9-22 | `hd-tip` 支持右侧展开/收起（`showCollapse` / `[(expanded)]`），暴露 `expand` / `collapse` / `toggle` 供父组件控制其它区块 |
| — | 2026-9-22 | `hd-form-lines` 勾选提示改为 `tableTotal` 插槽（同 hd-table），组件内不再默认渲染已选中块 |
| — | 2026-9-22 | `hd-table` / `hd-detail-form` 字段值后支持编辑笔图标（`editable` + `edit` 回调，图标对齐 Figma） |
| — | 2026-9-28 | `hd-detail-lines` / `hd-detail-lines-page`：CSS 纵滚场景下提高冻结列表头 z-index，修复横滚盖住冻结列名 |
| — | 2026-9-28 | `hd-detail-lines` / `hd-detail-lines-page`：仅有 `scroll.x` 时用 CSS `max-height` 做表内纵滚（不补 `nzScroll.y`），修复无列宽多行平铺无法纵滚，同时避免拆表头错位 |
| — | 2026-9-28 | `hd-filter`：可选筛选组（`enableFilterScheme` / `filterSchemeKey` + `HD_FILTER_SCHEME_STORE`），支持切换/保存为当前/另存为/删除 |
| — | 2026-9-29 | `hd-filter` 筛选组：弹窗标题「保存筛选组」；操作下拉「删除」红色；操作无左右 padding；选择/另存为改 `hd-form`；长名称省略；按钮顺序与间距对齐稿面 |
| — | 2026-9-30 | `hd-filter` 筛选组：选择/保存弹窗宽度 560px；筛选组名称 maxLength 50 |
| — | 2026-9-30 | `hd-filter`：筛选组弹窗未打开时不渲染空 `hd-form`；`hd-form` 空 formList 时初始化空 FormGroup，修复列表页 formGroup 报错（2.2.7） |
| — | 2026-9-24 | `hd-detail-lines` / `hd-detail-lines-page`：恢复历史默认 `scroll={x:'1px'}`；**不再自动补 scroll.y**（仅父组件显式传 y，或 page 虚拟滚动才设 y）；去掉 `table-layout:fixed`。对齐 2.1.64 前无列宽自适应 |
| — | 2026-9-24 | `hd-detail-lines` / `hd-detail-lines-page`：横滚时加固表头/表体 `scrollLeft` 同步与 `table-layout: fixed`，修复列名与列值不对齐 |
| — | 2026-9-24 | `hd-detail-lines`：补 `scroll.y` 后重建表格并同步表头横滚，修复列头不跟随左右滚动 |
| — | 2026-9-24 | `hd-detail-lines` / `hd-detail-lines-page`：自动或仅传 `scroll.x` 时补 `scroll.y`，修复窄屏下无法纵向滚动 |
| — | 2026-9-22 | `hd-table` 支持 `pagination` / `frontPagination`：全量 `content` 可「不分页展示」或「前端切片分页」，列表默认仍为服务端分页 |
| — | 2026-9-21 | hd-table 列 `color` 支持函数，按行给某一个字段标红 |
| — | 2026-9-20 | hd-detail-form 附件图片：最多展示 4 张，超出末张蒙版 `+n`；弹窗预览支持左右翻页 |
| — | 2026-9-20 | hd-detail-form 附件图片点击弹窗预览大图（不再 `window.open`） |
| — | 2026-9-20 | hd-detail-form 支持附件图片字段（`HdDetailFormFieldType.Accessory`，Figma 48×48 缩略图横排，不复用 hd-accessory-list） |
| — | 2026-9-17 | hd-table / hd-detail-lines / hd-detail-lines-page 支持 `selectDisabledField` / `rowInvalidField`：按行字段控制勾选禁用、失效行样式 |
| — | 2026-9-14 | 新增 `hd-accessory-list` 附件列表组件（分组 name + accessoryList，点击下载/查看） |
| — | 2026-6-23 | hd-table 状态列支持 `stateField` 自定义取值字段、`isState` 按列名取值；hd-form Input 支持 `prefix` / `prefixIcon`；hd-detail-lines-page 支持 `isCrossPageSelect` 跨页勾选开关 |
| — | 2026-7-6 | hd-form 支持 `FormListType.Checkbox`（单个复选框 / 复选框组）及 `CheckboxOption` 配置 |
| — | 2026-9-8 | hd-form 支持 `FormListType.RegionAddress`（省市区级联 + 详细地址，双 FormControl，固定占 2 列） |
| — | 2026-9-9 | hd-detail-form 默认固定一行 4 列；`HdOption.width` 支持占列（默认 1，最大 4） |
| — | 2026-8-6 | hd-form-lines：`allowEmpty` + 仅删除按钮时初始化不补空行、可删至 0 行；分页页码删空校正；ViewDom 字号 14px |
| — | 2026-8-26 | `hd-table` 默认开启虚拟滚动（`virtualScroll` / `virtualItemSize`）；文档补齐 |
| — | 2026-8-25 | hd-status：`statusToColor` 按 sunan-server 业务状态枚举全量去重补充（排除银行 / AGV / HTTP StatusCode） |
| — | 2026-8-21 | 分页选项统一增加 500 / 1000；`hd-table` / `hd-detail-lines` / `hd-detail-lines-page` 默认 `tablePageSize` 改为 100 |
| — | 2026-9-14 | TotalOption 增加 `preserveNumber`（合计小数位数，不传默认 2）；用于 `hd-detail-lines` / `hd-detail-lines-page` / `hd-form-lines` |
| — | 2026-9-14 | hd-table：普通列支持文案后挂 `btnList` 操作按钮；`OperateBtn.name` 支持按行动态文案 |

## 前言

> 1. 文档中的「插槽」对应 Angular 的模板 `#template`（`ng-template` + `@ContentChild`）。
> 2. 事件回调建议使用 `bind(this)`，示例：`onChangeEvent: this.formInputChange.bind(this)`。
> 3. 本地运行 `npm start`，访问 `http://localhost:13000` 查看 Demo 交互。
> 4. 业务模块引入：`import { FantasyNgzorroModule } from 'fantasy-ngzorro'`。

### 公共导出

| 模块 | 说明 |
| ---- | ---- |
| `FantasyNgzorroModule` | 根模块，业务侧统一引入 |
| `ColWidth` | 列宽常量 |
| `Page<T>` | 分页数据结构 |
| `Utils` | 精度计算工具 |
| `HdOverlayCleanupService` | 清理残留 tooltip/overlay（引入模块后自动生效） |
| `HdTableColumn` / `FormLine` / `Filter` 等 | 各组件配置类型，详见 [附录：公共配置类型](#附录公共配置类型) |

---

## 1、按钮（hd-button）

### 示例

```html
<hd-button type="primary" (clickAction)="search()">查询</hd-button>
<hd-button type="default" [loading]="loading" (clickAction)="save()">保存</hd-button>
```

### 参数

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| type | string | default | primary \| dashed \| danger \| default \| link \| reset \| add |
| size | string | normal | 按钮尺寸 |
| loading | boolean | false | 加载中（与 loading 配合时必须用 clickAction / nzOnConfirm） |
| disabled | boolean | false | 是否禁用；loading 时也会禁用 |
| clickAction | EventEmitter | — | 点击事件 |
| nzOnConfirm | EventEmitter | — | 确认类点击事件（与 clickAction 二选一亦可） |

### 注意点

- **禁止**使用 `type="submit"`，请用普通按钮 + `clickAction` 触发表单提交。
- 设置了 `loading` 的按钮必须用 `(clickAction)` 或 `(nzOnConfirm)`，不能用 `(click)`。

---

## 2、按钮组（hd-button-group）

### 示例

```html
<hd-button-group>
  <ng-template #buttonGroupLeft>
    <hd-button type="add">新增</hd-button>
  </ng-template>
  <ng-template #buttonGroupRight>
    <hd-button type="default">导出</hd-button>
  </ng-template>
</hd-button-group>
```

### 插槽

| 插槽 | 说明 |
| ---- | ---- |
| buttonGroupLeft | 左侧按钮区 |
| buttonGroupRight | 右侧按钮区 |

按钮间距自动 12px。

---

## 3、间隔（hd-space）

### 示例

```html
<hd-space background="#fff" type="row" size="12"></hd-space>
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| background | string | inherit | 背景色 |
| type | string | row | row \| column |
| size | number | — | 高度或宽度（px） |

---

## 4、小标题（hd-tip）

### 示例

```html
<hd-tip title="基本信息" [fontSize]="14"></hd-tip>
<hd-tip title="新增" [showIcon]="false" [fontSize]="16"></hd-tip>

<!-- 右侧展开/收起：父组件控制其它区块显隐 -->
<hd-tip #basicTip title="基本信息" showCollapse [(expanded)]="showBasicBlock"></hd-tip>
<div *ngIf="showBasicBlock">…其它内容…</div>

<!-- 或 ViewChild 调用 -->
<!-- this.basicTip.expand() / collapse() / toggle() -->
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| title | string | — | 标题文案 |
| showIcon | boolean | true | 是否显示左侧竖线 |
| fontSize | number | — | 字体大小 |
| showCollapse | boolean | false | 是否在右侧显示展开/收起 |
| expanded | boolean | true | 当前是否展开；可 `[(expanded)]` 双向绑定 |
| expandedChange | EventEmitter\<boolean\> | — | 展开状态变化 |

#### 暴露方法（ViewChild）

| 方法 | 说明 |
| ---- | ---- |
| expand() | 展开，并触发 `expandedChange` |
| collapse() | 收起，并触发 `expandedChange` |
| toggle() | 切换，并触发 `expandedChange` |

`hd-tip` 本身不包裹内容块，由父组件根据 `expanded` / 方法结果自行控制其它区域的 `*ngIf` 等显隐。

---

## 5、状态（hd-status）

### 示例

```html
<hd-status status="initial">未审核</hd-status>
<hd-status status="audited">已审核</hd-status>
<hd-status status="received">已收货</hd-status>
```

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| status | string | 状态值，匹配 `hd-status.service.ts` 中 `statusToColor` 配置 |

匹配时**不区分大小写**。未命中时圆点默认为灰色 `#9FA4A2`。新增状态请在 `statusToColor` 中配置颜色。

#### statusToColor 颜色语义

| 颜色 | 含义 | 常见状态码示例 |
| ---- | ---- | -------------- |
| `#FAB13B` 黄 | 过程中 / 中间态 | committed、picking、receiving、待生效 |
| `#9FA4A2` 灰 | 初始 / 未开始 / 线下停用 | initial、saved、未审核、已保存、OFF_LINE |
| `#F5222D` 红 | 作废 / 拒绝 / 失效 / 禁用 | aborted、rejected、INVALID、已作废 |
| `#3B77E3` 蓝 | 审核流转 / 处理中 | audited、submitted、处理中、已初审 |
| `#20B95D` 绿 | 完成 / 启用 / 生效 | finished、published、EFFECTIVE、已完成 |
| `#F05B24` 橙 | 部分完成 / 预警 | partPublished、部分核销、willExpired |

状态码已按 sunan-server 业务 `*State` / `*Status` 枚举全量去重补齐（排除银行支付 / AGV / HTTP StatusCode）。同时支持英文码、`SCREAMING_SNAKE` 与中文枚举名。

---

## 6、气泡确认（hd-popconfirm）

### 示例

```html
<hd-popconfirm message="确认删除该记录吗？" (confirmOption)="onConfirm()" (cancelOption)="onCancel()">
</hd-popconfirm>
```

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| message | string | 提示文案 |
| confirmOption | EventEmitter | 点击确认 |
| cancelOption | EventEmitter | 点击取消 |

---

## 7、筛选器（hd-filter）

### 示例

```html
<hd-filter [filterList]="filterList" (searchEvent)="filterChange($event)" (resetEvent)="resetFilterChange($event)">
</hd-filter>
```

筛选组（可选，默认关闭；需业务仓 `provide HD_FILTER_SCHEME_STORE`）：

```html
<hd-filter
  [filterList]="filterList"
  [enableFilterScheme]="true"
  [filterSchemeKey]="'erp.offerPlan.list'"
  (searchEvent)="filterChange($event)">
</hd-filter>
```

本地 Demo（`npm start`）在「筛选器 · 筛选组」区块有可操作示例，使用内存 `DemoFilterSchemeService`。

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| filterList | Array\<Filter\> | 筛选项配置 |
| enableFilterScheme | boolean | 是否启用筛选组，默认 `false` |
| filterSchemeKey | string | 筛选器标识；开启筛选组时必传 |
| searchEvent | EventEmitter | 查询，带回筛选数据 |
| resetEvent | EventEmitter | 重置 |

#### Filter 配置

筛选项使用 [Filter](#filter筛选项) 类型，下拉/数字/级联等子配置见 [SelectOption](#selectoption下拉选项配置)、[InputNumber](#inputnumber数字输入配置)、[CascaderOption](#cascaderoption级联选择配置)。

---

## 8、通用表格（hd-current-table）(已废弃、禁用)

适用于**完全自定义**表头、表体模板的列表页。

### 示例

```html
<hd-current-table #hdCurrentTable [(tablePageIndex)]="pageIndex" [(tablePageSize)]="pageSize"
  [scroll]="{x: '600px'}" [tableData]="page" [tableLoading]="loading"
  (tableSearchEvent)="search($event)" showSelected selectField="billNumber"
  (selectEvent)="selectResult($event)">
  <ng-template #tableTotal>...</ng-template>
  <ng-template #tableHead>
    <th>配送单号</th>
    <th>状态</th>
  </ng-template>
  <ng-template #tableBody let-data>
    <td>{{ data.billNumber }}</td>
    <td><hd-status [status]="data.state">{{ data.stateText }}</hd-status></td>
  </ng-template>
</hd-current-table>
```

```typescript
page: Page<any> = new Page();
pageIndex = 1;
pageSize = 10;
loading = false;

search(reset = false) {
  if (reset) { this.pageIndex = 1; }
  this.queryFilter.pageNumber = this.pageIndex - 1;
  this.queryFilter.pageSize = this.pageSize;
  this.loading = true;
  this.service.query(this.queryFilter).subscribe(
    result => { this.loading = false; this.page = result; },
    () => { this.loading = false; }
  );
}
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| tableData | Page\<any\> | — | 分页数据；非分页时 `content` 放全量，`totalElements` 建议等于 `content.length` |
| pagination | boolean | true | 是否显示分页；`false` 时一次展示全部 `content` |
| frontPagination | boolean | false | 前端分页：对 `content` 全量切片，翻页不触发 `tableSearchEvent`。详情全量数据时与 `pagination` 搭配：`pagination=false` 全展示，`pagination=true` + `frontPagination` 前端分页。列表服务端分页保持默认即可（`frontPagination` 不传） |
| tablePageIndex | number | 1 | 当前页（双向绑定）；`pagination=false` 时无意义 |
| tablePageSize | number | 10 | 每页条数（双向绑定） |
| tableLoading | boolean | false | 加载状态 |
| tableSearchEvent | EventEmitter | — | 翻页 / 改 pageSize 触发，参数 reset 表示是否重置到第一页 |
| scroll | object | { x: '1px' } | 横向滚动 |
| showSelected | boolean | false | 是否显示勾选列 |
| selectField | string | billNumber | 勾选主键字段 |
| selectEvent | EventEmitter | — | 勾选变化 |
| showTableTotal | boolean | false | 底部合计行 |
| tableTotalOption | TableTotalOption[] | — | 合计配置（已弃用类型） |
| tableHead / tableBody / tableTotal | TemplateRef | — | 表头 / 表体 / 顶部合计插槽 |

分页可选条数：`10 / 50 / 100 / 200 / 500 / 1000`。

---

## 9、增强表格（hd-table）

在通用表格基础上支持**列配置渲染**、**排序**、**列宽/顺序/pageSize 本地缓存**、**设置列**等能力。列表页**优先推荐使用**。

### 示例

```html
<hd-table #hdTable [(tablePageIndex)]="pageIndex" [(tablePageSize)]="pageSize"
  [tableCols]="tableCols" [tableData]="page" [tableLoading]="loading"
  (tableSearchEvent)="search($event)" showSelected showOperateColWarpButton
  selectField="billNumber" (selectEvent)="selectResult($event)"
  uuid="74907b48-1b17-4e51-9fa9-81fd0ac94051"
  (sortEvent)="sortEvent($event)" (tablePageSizeChangeEvent)="search(true)">
  <ng-template #tableLeftButton>
    <hd-button type="default" (clickAction)="search()">刷新</hd-button>
  </ng-template>
  <ng-template #tableRightButton>
    <hd-button type="default">导出</hd-button>
  </ng-template>
  <ng-template #tableTotal>...</ng-template>
</hd-table>
```

```typescript
tableCols: HdTableColumn[] = [{
  title: '配送单号',
  name: 'billNumber',
  fixed: 'left',
  click: (line) => { /* 点击行 */ },
  // 按行控制是否显示为超链接（例如仅有网址时才可点）
  // canClick: (line) => !!line.url
}, {
  title: '状态',
  name: 'state',
  width: ColWidth.enumColWidth,
  // stateField: 'orderStatus', // 可选，自定义状态取值字段，默认取 data.state
  render: (line) => line.state === 'received' ? '已收货' : '未收货'
}, {
  title: '订单状态',
  name: 'orderStatus',
  isState: true, // 按 hd-status 渲染，取值字段为 name（orderStatus）
  width: ColWidth.enumColWidth,
  render: (line) => line.orderStatusText
}, {
  title: '业务数据自动上报',
  name: 'autoReport',
  width: 140,
  render: (line) => (line.autoReport ? '是' : '否'),
  // 普通列挂 btnList：文案后跟操作按钮（见 Figma 操作列单元格）
  btnList: [{
    name: (line) => (line.autoReport ? '解除' : '设置'),
    click: (line) => { line.autoReport = !line.autoReport; }
  }]
}, {
  title: '操作',
  name: 'operate',
  width: ColWidth.operateColWidth,
  btnList: [{ name: '删除', showConfirm: true, click: (line) => this.remove(line) }]
  // showConfirm 也可传函数，按行属性决定是否二次确认
  // btnList: [{ name: '删除', showConfirm: (line) => line.state !== 'draft', click: (line) => this.remove(line) }]
}];
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| tableCols | HdTableColumn[] | [] | 列配置 |
| tableData | Page\<any\> | — | 数据；服务端分页时为当前页；全量场景 `content` 放全部行 |
| pagination | boolean | true | 是否显示分页；`false` 一次展示全部 `content` |
| frontPagination | boolean | false | 前端分页：对 `content` 切片，翻页不触发 `tableSearchEvent`。详情全量数据：`[pagination]="x" frontPagination`，切 `x` 即可在「全展示 / 前端分页」间切换。列表保持默认（不传）即为服务端分页 |
| tablePageIndex | number | 1 | 当前页（双向绑定）；`pagination=false` 时可忽略 |
| tablePageSize | number | 100 | 每页条数（双向绑定）；外面传入会覆盖默认值；非分页时可忽略 |
| tableLoading | boolean | false | 加载状态 |
| tableSearchEvent | EventEmitter | — | 翻页查询 |
| tablePageSizeChange | EventEmitter | — | pageSize 双向绑定同步 |
| tablePageSizeChangeEvent | EventEmitter | — | pageSize 变化（含缓存恢复），常用于重新查询 |
| sortEvent | EventEmitter | — | 排序 |
| selectEvent | EventEmitter | — | 勾选变化 |
| showSelected | boolean | false | 勾选列 |
| selectField | string | billNumber | 勾选主键字段 |
| selectDisabledField | string | — | 行勾选禁用字段名；行数据该字段为 `true` 时禁用勾选（全选也会跳过） |
| rowInvalidField | string | — | 行失效字段名；为 `true` 时整行背景 `#F7F8FA`、普通文字 `#868A9C`（操作按钮/超链接颜色不变） |
| showOperateColWarpButton | boolean | false | 展开/缩略显示换行列 |
| virtualScroll | boolean | true | 行数多自动虚拟滚动；横向滚动条按**列总宽是否超出容器**决定 |
| virtualItemSize | number | — | 虚拟滚动行高（px）；**不传则首屏自动测量** |
| showTableTotal | boolean | false | 底部合计行 |
| tableTotalOption | HdTableTotalOption[] | — | 合计配置 |
| isFirstEntrySearch | boolean | — | 首次进入是否自动查询 |
| isCrossPageSelect | boolean | — | 跨页勾选 |
| uuid | string | — | 列缓存唯一标识（必填，用于 IndexedDB 缓存） |
| tableLeftButton / tableRightButton / tableTotal | TemplateRef | — | 工具栏插槽 |

分页可选条数：`10 / 50 / 100 / 200 / 500 / 1000`。若本地缓存过该表 `pageSize` 且 `> 10`，初始化会优先使用缓存值并回写父组件（仅 `pagination=true`）。

非分页示例：

```html
<!-- 不分页：一次展示全部 -->
<hd-table [pagination]="false" frontPagination
  [tableCols]="cols" [tableData]="linesPage" uuid="detail-lines-uuid"></hd-table>

<!-- 前端分页：对全量 content 切片 -->
<hd-table [pagination]="true" frontPagination [tablePageSize]="10"
  [tableCols]="cols" [tableData]="linesPage" uuid="detail-lines-uuid"></hd-table>
```

```typescript
// content 放全量；totalElements 建议与 content.length 一致
linesPage = { content: lines, totalElements: lines.length };
```

#### HdTableColumn 配置

列定义见 [HdTableColumn](#hdtablecolumn表格列)、[OperateBtn](#operatebtn操作列按钮)、[HdTableTotalOption](#hdtabletotaloptionhd-table-底部合计)。

当 `name` 为 `state` 或 `isState` 为 `true` 时，列内容使用 `hd-status` 渲染。取值规则：`isState` 时取 `data[name]`；否则可通过 `stateField` 指定字段，未配置时默认取 `state`。

---

## 10、表单（hd-form）

### 示例

```html
<hd-form [formList]="formInput" (changeEvent)="formChangeEvent($event)"></hd-form>
```

```typescript
formInput: FormItem[] = [{
  type: FormListType.Input,
  label: '配送单号',
  name: 'billNumber',
  require: true,
  width: 2,
  onChangeEvent: this.formInputChange.bind(this)
}, {
  type: FormListType.Select,
  label: '是否启用',
  name: 'enabled',
  width: 1,
  selectOption: { value: 'value', label: 'label', selectList: [...] }
}, {
  type: FormListType.Input,
  label: '金额',
  name: 'amount',
  prefix: '¥' // 前缀文字，对应 nz-input-group nzPrefix
}, {
  type: FormListType.Input,
  label: '手机号',
  name: 'mobile',
  prefixIcon: 'phone' // 前缀图标，对应 nz-icon nzType
}, {
  type: FormListType.InputNumber,
  label: '数量',
  name: 'qty',
  inputNumber: { min: 0, max: 9999, step: 1, precision: 2 }
}, {
  type: FormListType.Checkbox,
  label: '是否启用',
  name: 'enabled',
  value: false // 单个复选框，值为 boolean
}, {
  type: FormListType.Checkbox,
  label: '权限',
  name: 'permissions',
  value: ['read'],
  checkboxOption: {
    label: 'name',
    value: 'code',
    optionList: [
      { code: 'read', name: '查看' },
      { code: 'edit', name: '编辑' }
    ]
  }
}, {
  type: FormListType.RegionAddress,
  label: '场所地址',
  name: 'region',                 // 省市区 string[]
  addressName: 'addressDetail',   // 详细地址 string
  require: true,                  // 两边同时必填；固定占 2 列
  cascaderOption: { options: cityOptions },
  addressPlaceholder: '请输入详细地址'
}];

// 编辑回填（两个平级字段）
// this.hdForm.validateHdForm.patchValue({
//   region: ['上海', '上海市', '浦东新区'],
//   addressDetail: '张江路 88 号',
// });

formChangeEvent(validateForm: FormGroup) {
  this.validateHdForm = validateForm;
}
```

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| formList | FormItem[] | 表单项配置 |
| changeEvent | EventEmitter | 表单值变化，返回 FormGroup |

#### FormItem 配置

表单项使用 [FormItem](#formitem表单项) 类型，下拉/数字等子配置见 [SelectOption](#selectoption下拉选项配置)、[InputNumber](#inputnumber数字输入配置)、[RadioOption](#radiooption单选配置)、[CheckboxOption](#checkboxoption复选框配置)。

---

## 11、明细表单（hd-form-lines）

可编辑的明细行表格，支持键盘导航、行内搜索、勾选批量填充、合计等。

### 示例

```html
<hd-form-lines #hdFormLines showSearch showCheckbox showKeyboardOperateTip
  uuid="demo-form-lines-col-settings"
  [formLines]="formLines" [formLinesData]="formLinesData"
  [operateButtons]="['add', 'copy', 'delete']" [allowEmpty]="false"
  (changeEvent)="formLinesChangeEvent($event)"
  (selectionChange)="formLinesSelectionChange($event)"
  (deleteLastLineEvent)="deleteEvent()">
  <ng-template #formLinesLeftButton>
    <hd-button type="primary" (clickAction)="batchFill()">批量填充</hd-button>
  </ng-template>
  <ng-template #formLinesRightButton>
    <hd-button type="default">右侧操作</hd-button>
  </ng-template>
  <!-- 勾选提示等同 hd-table 的 tableTotal，放在表格上方 -->
  <ng-template #tableTotal>
    <nz-alert *ngIf="hdFormLines.getSelectedCount() > 0" nzType="info"
      [nzMessage]="formLinesAlertTpl" nzShowIcon></nz-alert>
    <ng-template #formLinesAlertTpl>
      <span>已选择{{ hdFormLines.getSelectedCount() }}条数据</span>&nbsp;&nbsp;
      <span class="common-btn-group">
        <a (click)="hdFormLines.clearSelection()">清空</a>
      </span>
    </ng-template>
  </ng-template>
  <ng-template #ViewDomRightTemplate let-formItem="formItem" let-formLine="formLine">
    <!-- ViewDom 列右侧自定义内容 -->
  </ng-template>
</hd-form-lines>
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| formLines | FormLine[] | — | 列定义 |
| formLinesData | any[] | — | 行数据；空数组视为新增 |
| operateButtons | string[] | ['add','delete'] | 操作按钮：`add` / `copy` / `delete` |
| showDeleteConfirm | boolean | false | 删除前确认 |
| showSearch | boolean | false | 行内搜索 |
| showCheckbox | boolean | false | 行勾选列（用于批量操作） |
| showColSettings | boolean | true | 是否展示列设置（齿轮，位置同 hd-table）；仅 **非 hide 的 ViewDom** 可配置显示/隐藏，**不可拖拽调序** |
| uuid | string | — | 列设置缓存标识；有值时按用户+路由持久化到 IndexedDB |
| showKeyboardOperateTip | boolean | false | 键盘操作提示 |
| showLineNumber | boolean | true | 序号列 |
| tableLoading | boolean | false | 加载状态 |
| allowEmpty | boolean | true | 是否允许空表（见下方说明） |
| showTotal | boolean | false | 合计行 |
| totalOption / columnsNumber | — | — | 合计配置 |
| scroll | object | { x: '1px' } | 横向滚动 |
| changeEvent | EventEmitter | — | 表单变化 |
| selectionChange | EventEmitter\<FormGroup[]\> | — | 勾选变化 |
| deleteLastLineEvent | EventEmitter | — | `allowEmpty=false` 时删除最后一行 |
| deleteLineEvent | EventEmitter | — | 删除行事件 |

### 插槽

| 插槽 | 说明 |
| ---- | ---- |
| formLinesLeftButton | 工具栏左侧自定义按钮（同 hd-table 的 tableLeftButton） |
| formLinesRightButton | 工具栏右侧自定义按钮 |
| tableTotal | 表格上方自定义区域（同 hd-table）；勾选提示等由业务自行放入，组件内不再默认渲染 |
| ViewDomRightTemplate | ViewDom 列右侧自定义模板，上下文：`formItem`、`formLine` |

### allowEmpty 行为

| 场景 | 行为 |
| ---- | ---- |
| `allowEmpty=false` | 不能删掉最后一行，触发 `deleteLastLineEvent` |
| `allowEmpty=true` 且操作列含 add/copy | 删空后会自动补一行空行 |
| `allowEmpty=true` 且操作列**仅有** `delete` | 初始化空数据不补空行；可删至 0 行；外部可通过 `addFormLine()` 新增 |

### FormLine 配置

明细列使用 [FormLine](#formline明细表单项) 类型，含 [ColorOption](#coloroption)、[ExplainOption](#explainoption) 及表格型 [SelectOption](#selectoption下拉选项配置)。

开启 `showKeyboardOperateTip` 后支持 `[↑][↓][←][→]`、`Enter` 在单元格间跳转；InputNumber 上下键用于跳转，不触发 step 增减。

表格分页可选条数：`10 / 50 / 100 / 200 / 500 / 1000`。

#### 暴露方法

```typescript
this.hdFormLines.getValid();              // 整表校验状态
this.hdFormLines.getLines();              // 获取行 FormArray
this.hdFormLines.addFormLine();           // 末尾新增空行（也可传当前行在其后插入）
this.hdFormLines.resetForm();             // 重置表单
this.hdFormLines.getSelectedLines();      // 当前勾选行 FormGroup[]
this.hdFormLines.getSelectedLinesData();  // 勾选行数据（含跨页）
this.hdFormLines.getSelectedCount();      // 勾选数量
this.hdFormLines.clearSelection();        // 清空勾选
this.hdFormLines.batchFillSelected({ remark: '批量备注' }); // 批量填充勾选行字段
```

---

## 12、详情头（hd-detail-tip）

### 示例

```html
<hd-detail-tip state="shipped" stateText="配送中" billNumber="202111030001"></hd-detail-tip>
```

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| state | string | 状态值 |
| stateText | string | 状态文案 |
| billNumber | string | 单号 |
| tip | string | 前缀文案，默认「详情」 |

---

## 13、详情单头（hd-detail-form）

### 示例

```html
<hd-detail-form [formCols]="formCols" (imageClick)="onDetailFormImageClick($event)"></hd-detail-form>
```

```typescript
import { HdDetailFormFieldType, HdOption } from 'fantasy-ngzorro';

formCols: HdOption[] = [
  { label: '收货单号', value: '202111030001' },
  { label: '地址', value: '江苏/南京市/玄武区 某某路', width: 2 },
  { label: '备注', value: '...' },
  // 附件图片：label + 图片地址列表（Figma 48×48 缩略图横排）
  {
    label: '食品经营许可证',
    type: HdDetailFormFieldType.Accessory,
    width: 2,
    value: [
      { name: '正面', path: 'https://oss.xxx.com/a.png' },
      { name: '背面', path: 'https://oss.xxx.com/b.png' },
      'https://oss.xxx.com/c.png', // 也支持纯地址字符串
    ],
  },
];
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| formCols | HdOption[] | — | 展示字段，见 [HdOption](#hdoption键值展示项) |
| nzColumn | number \| object | `4` | 一行列数，默认固定 4 列 |
| imageClick | EventEmitter | — | 附件图片点击回调 `{ image, path, index }`（`type=accessory` 时） |

附件字段 `type: HdDetailFormFieldType.Accessory`（或 `'accessory'`）：

- 对齐 Figma `items/description-cell`「图片」：标签 + **48×48** 缩略图横排（间距 6px，边框 `#E5E6EB`，圆角 4px）；标签与首图顶对齐
- `value` 支持：图片地址 `string` / `string[]`，或 `{ name?, path?/url? }[]`
- 最多直接展示 **4** 张；超出时第 4 张蒙版显示 `+n`（n 为剩余张数）
- 点击缩略图弹窗预览大图（支持左右翻页），并触发 `imageClick`
- 无图时展示 `<空>`
- **不使用** `hd-accessory-list`（文件列表样式请用独立附件列表组件）

---

## 14、详情明细（hd-detail-lines）

详情页只读/轻编辑明细表格，支持**前端分页**和**行内搜索**。

### 示例

```html
<!-- 带搜索 + 前端分页 -->
<hd-detail-lines showSearch [lines]="lines" [scroll]="{x: '1150px'}">
  <ng-template #detailLineHead>...</ng-template>
  <ng-template #detailLineBody let-data let-index="index">...</ng-template>
</hd-detail-lines>

<!-- 勾选 + 合计 + 前端分页 -->
<hd-detail-lines [lines]="lines" showSelected selectField="uuid"
  hdFrontPagination showTotal columnsNumber="4" [totalOption]="detailLinesTotalOption"
  (selectEvent)="selectResultLines($event)">
  ...
</hd-detail-lines>
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| lines | any[] | — | 明细数据 |
| scroll | object | { x: '1px' } | 横向滚动。默认 `{ x: '1px' }`（开启横滚、列宽自适应）；传 `null` 则按列宽自动测算。**不要默认补 `scroll.y`**（会拆表头导致无列宽错位）；仅有 `x` 时由组件 CSS 限制表体高度实现纵滚。需要分体固定表头时再显式传 `y` |
| showSearch | boolean | false | 行内搜索 |
| searchFields | string[] | [] | 搜索字段，空则搜全部字段 |
| hdFrontPagination | boolean | false | 前端分页 |
| tablePageSize | number | 100 | 每页条数（开启前端分页时生效） |
| showSelected | boolean | false | 勾选 |
| selectField | string | billNumber | 勾选主键 |
| selectDisabledField | string | — | 行勾选禁用字段名；行数据该字段为 `true` 时禁用勾选（全选也会跳过） |
| rowInvalidField | string | — | 行失效字段名；为 `true` 时整行背景 `#F7F8FA`、普通文字 `#868A9C`（操作按钮/超链接颜色不变） |
| selectedField | string | — | 初始勾选标记字段 |
| selectEvent | EventEmitter | — | 勾选变化 |
| allowDrop | boolean | false | 拖拽排序 |
| showTotal | boolean | false | 合计行 |
| columnsNumber | number | — | 总列数（含合计） |
| totalOption | TotalOption[] | — | 合计配置，见 [TotalOption](#totaloption明细合计行) |
| detailLineHead / detailLineBody | TemplateRef | — | 表头 / 表体插槽 |

分页可选条数：`10 / 50 / 100 / 200 / 500 / 1000`。

---

## 15、详情明细-服务端分页（hd-detail-lines-page）

与 `hd-detail-lines` 模板用法相同，但**不做内部分页和搜索**，分页由父组件控制（对齐 `hd-table`）。

### 示例

```html
<hd-detail-lines-page [scroll]="{x: '1150px'}"
  [lines]="detailLinesPageData.content"
  [tableData]="detailLinesPageData"
  [tableLoading]="detailLinesPageLoading"
  [tablePageIndex]="detailLinesPageIndex"
  [tablePageSize]="detailLinesPageSize"
  (tablePageIndexChange)="onDetailLinesPageIndexChange($event)"
  (tablePageSizeChange)="onDetailLinesPageSizeChange($event)">
  <ng-template #detailLineHead>
    <th style="width: 40px">序号</th>
    <th style="width: 150px">商品编码</th>
    <th>商品名称</th>
  </ng-template>
  <ng-template #detailLineBody let-data let-index="index">
    <td>{{ index + 1 }}</td>
    <td>{{ data.productCode }}</td>
    <td>{{ data.productName }}</td>
  </ng-template>
</hd-detail-lines-page>
```

```typescript
detailLinesPageData: Page<any> = new Page();
detailLinesPageIndex = 1;
detailLinesPageSize = 100;
detailLinesPageLoading = false;

loadDetailLinesPage(reset = false) {
  if (reset) { this.detailLinesPageIndex = 1; }
  this.detailLinesPageLoading = true;
  this.service.queryLines({
    pageNumber: this.detailLinesPageIndex - 1,
    pageSize: this.detailLinesPageSize
  }).subscribe(result => {
    this.detailLinesPageData = result;
    this.detailLinesPageLoading = false;
  });
}

onDetailLinesPageIndexChange(pageIndex: number) {
  this.detailLinesPageIndex = pageIndex;
  this.loadDetailLinesPage();
}

onDetailLinesPageSizeChange(pageSize: number) {
  this.detailLinesPageSize = pageSize;
  this.loadDetailLinesPage(true);
}
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| lines | any[] | [] | 当前页数据（也可用 tableData.content） |
| tableData | Page\<any\> | — | 分页对象，提供 totalElements |
| tablePageIndex | number | 1 | 当前页 |
| tablePageSize | number | 100 | 每页条数 |
| tableLoading | boolean | false | 加载状态 |
| tablePageIndexChange | EventEmitter | — | 页码变化 |
| tablePageSizeChange | EventEmitter | — | 每页条数变化（组件内会重置到第 1 页） |
| pageChange | EventEmitter | — | 任意分页变化 |
| showSelected / allowDrop / showTotal / selectDisabledField / rowInvalidField 等 | — | — | 同 hd-detail-lines；`allowDrop` 开启时虚拟滚动自动关闭 |
| virtualScroll | boolean | true | 与 hd-table 一致：当前页行数多（或已设 `scroll.y`）时自动虚拟滚动，减轻千行勾选卡顿 |
| virtualItemSize | number | — | 虚拟滚动行高；不传则默认/自动测量 |
| isCrossPageSelect | boolean | — | 跨页勾选 |

分页可选条数：`10 / 50 / 100 / 200 / 500 / 1000`。模板中 `index` 为**全局序号**：`(pageIndex - 1) * pageSize + 行号`。

### 与 hd-detail-lines 选型

| 场景 | 推荐组件 |
| ---- | -------- |
| 数据量小、前端筛选/分页 | hd-detail-lines |
| 接口分页、数据量大 | hd-detail-lines-page |

---

## 16、操作日志（hd-log）

基于 `hd-detail-lines` 封装的日志展示，内置列：时间、操作人、事件、描述。

### 示例

```html
<hd-log [logs]="logs"></hd-log>
```

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| logs | any[] | 日志列表，字段：`createInfo.operateTime`、`createInfo.operatorName`、`event`、`describe` |

也可作为 Modal 内容组件使用（`entryComponents: HdLogComponent`）。

---

## 17、附件列表（hd-accessory-list）

只读附件分组列表：上方标签（如「营业执照扫描件：」），下方灰色文件行；每行最多 4 个，超出自动换行；点击文件名下载/查看。对齐 Figma「文件列表」样式。

### 示例

```html
<hd-accessory-list
  [groups]="accessoryGroups"
  (fileClick)="onAccessoryFileClick($event)">
</hd-accessory-list>
```

```typescript
import { HdAccessoryGroup } from 'fantasy-ngzorro';

accessoryGroups: HdAccessoryGroup[] = [
  {
    name: '营业执照扫描件',
    accessoryList: [
      { name: '文件名称.doc', path: 'https://oss.xxx.com/files/license.doc', size: 12 * 1024 * 1024 },
      { name: '副本.pdf', path: 'https://oss.xxx.com/a.pdf' }, // size 可缺省
    ],
  },
];

onAccessoryFileClick(e: { group: HdAccessoryGroup; file: any; path: string }) {
  console.log('下载', e.path);
}
```

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| groups | HdAccessoryGroup[] | [] | 分组数组，每项含 `name` + `accessoryList` |
| labelColon | boolean | true | 标签后自动补「：」 |
| autoOpen | boolean | true | 点击后默认 `window.open` 打开 |
| fileClick | EventEmitter | — | 点击附件回调 `{ group, file, path }` |

#### HdAccessoryGroup

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| name | string | 分组标签 |
| accessoryList | HdAccessoryFile[] | 附件列表 |

#### HdAccessoryFile

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| name | string | 展示文件名 |
| path | string | 完整下载/查看地址（由父组件直接传入） |
| size | number \| string | 可缺省；有值才展示。数字按字节格式化为 B/KB/MB，字符串原样展示 |

---

## 附录：公共配置类型

以下类型在 `hd-filter`、`hd-form`、`hd-form-lines`、`hd-table` 等组件中复用。

### SelectOption（下拉选项配置）

用于 `Filter.selectOption`、`FormItem.selectOption`、`FormLine.selectOption`。

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| label | string | — | selectList 中作为显示文案的字段名 |
| value | string | — | selectList 中作为绑定值的字段名 |
| selectList | any[] | — | 静态选项列表 |
| selectListName | string | — | 选项来自行数据某字段时使用（配合 hide 字段） |
| showLabelAndValue | boolean | false | 选项与已选回显均为 `[value]label`（`hd-form` / `hd-form-lines`） |
| hdDropdownMatchSelectWidth | boolean | false | 下拉宽度是否与控件一致 |
| hdServerSearch | boolean | false | 是否远程搜索 |
| hdShowSearch | boolean | true | 是否可搜索 |
| hdAllowClear | boolean | true | 是否允许清空 |
| hdShowItemCode | boolean | false | 已选展示是否带 `[value]` 前缀 |
| tableColumns | SelectOptionTableColumn[] | — | 表格型下拉列配置（商品选择器等） |

```typescript
selectOption: {
  value: 'productCode',
  label: 'productName',
  showLabelAndValue: true,
  hdServerSearch: true,
  selectList: [],
  tableColumns: [
    { width: ColWidth.codeNameColWidth, label: '商品', name: 'product',
      render: (line) => `[${line.productCode}] ${line.productName}` },
    { width: ColWidth.enumColWidth, label: '规格', name: 'specification' }
  ]
}
```

### SelectOptionTableColumn（表格型下拉列）

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| width | number | 列宽（px），参考 `ColWidth` |
| label | string | 表头文案 |
| name | string | selectList item 字段名 |
| render | (line) => string | 自定义渲染，优先级高于 name |
| icons | SelectOptionTableColumnIcon[] | 图标列（如推荐、协采标签） |

### SelectOptionTableColumnIcon（表格型下拉图标列）

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| iconName | string | `hd-select-close`（禁用）、`hd-select-purchase`（协）、`hd-recommend-star`、`hd-img-star` |
| fieldName | string | selectList item 中控制显示的布尔字段 |

### InputNumber（数字输入配置）

用于 `Filter.inputNumber`、`FormItem.inputNumber`、`FormLine.inputNumber`。

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| min | number | 0 | 最小值 |
| max | number | 99999999 | 最大值 |
| step | number | 1 | 步进值 |
| precision | number | 4 | 小数精度 |
| nzFormatter | Function | — | 展示格式化 |
| nzParser | Function | — | 输入解析 |

### CascaderOption（级联选择配置）

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| options | any[] | 级联数据源（ng-zorro cascader 格式） |
| showSearch | boolean \| CascaderShowSearchOptions | 是否开启搜索，默认 true；支持拼音字段匹配 |
| pinyinField | string | 拼音字段名，默认 `pinyin` |
| menuClassName | string | 下拉菜单额外 class |
| menuStyle | object | 下拉菜单样式（对应 `nzMenuStyle`） |
| dropdownMinWidth | number \| string | 搜索结果下拉最小宽度；**不传则不强制**，按文案自适应（上限 560px） |

### RadioOption（单选配置）

用于 `FormItem.radioOption`（`FormListType.Radio`）。

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| label | string | — | optionList 中作为显示文案的字段名 |
| value | string | — | optionList 中作为绑定值的字段名 |
| optionList | any[] | — | 选项列表 |
| showLabelAndValue | boolean | false | 选项展示为 `[value]label` |

### CheckboxOption（复选框配置）

用于 `FormItem.checkboxOption`（`FormListType.Checkbox` 多选组）。未配置 `checkboxOption` 时渲染单个复选框，值为 `boolean`，默认 `false`；配置后为复选框组，值为选中项 `value` 组成的数组，默认 `[]`。

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| label | string | — | optionList 中作为显示文案的字段名 |
| value | string | — | optionList 中作为绑定值的字段名 |
| optionList | any[] | — | 选项列表 |
| showLabelAndValue | boolean | false | 选项展示为 `[value]label` |

### HdOption（键值展示项）

用于 `hd-detail-form` 的 `formCols`。

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| label | string | 标签 |
| value | any | 值；附件类型时为图片地址 `string` / `string[]` 或 `{ name?, path?/url? }[]` |
| type | string / HdDetailFormFieldType | 字段类型，默认文本；`accessory` 为附件图片缩略图 |
| width | number | 占据列数，默认 1，最大 4；未传按 1 |
| color | string | 文字颜色 |
| hide | boolean | 是否隐藏 |
| clickText | string | 可点击文案 |
| click | (value) => void | 点击回调 |
| editable | boolean | 值后显示编辑笔图标（Figma 14px） |
| edit | (col) => void | 点击编辑笔回调，供父组件处理 |

### Filter（筛选项）

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| type | FilterListType | — | 控件类型 |
| label | string | — | 标签 |
| name | string | — | 字段名（提交给后端的 key） |
| value | any | null | 初始值 |
| placeholder | string | — | 占位符 |
| require | boolean | false | 是否必填 |
| show | boolean | — | 是否显示 |
| hdAllowClear | boolean | true | 是否允许清空；不传默认 true。Select 未配此项时可回退 `selectOption.hdAllowClear` |
| selectOption | SelectOption | — | Select / MultipleSelect 配置 |
| inputNumber | InputNumber | — | InputNumber 配置 |
| cascaderOption | CascaderOption | — | Cascader 配置 |
| showTime | boolean | false | Date 是否含时间 |
| hdDisabledDate | Function | — | 不可选日期 `(date) => boolean` |
| onChangeEvent | Function | — | 值变化 |
| onSearchEvent | Function | — | 下拉搜索 |
| onBlurEvent | Function | — | 失焦 |
| onChangeEventDebounceTime | number | — | change 防抖（ms） |
| onSearchEventEventDebounceTime | number | — | search 防抖（ms） |

#### FilterListType 枚举

`Input` \| `Select` \| `MultipleSelect` \| `Date` \| `DateRange` \| `Cascader` \| `Month` \| `InputNumber`

### FormItem（表单项）

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| type | FormListType | — | 控件类型 |
| label / name | string | — | 标签 / 字段名 |
| require | boolean | false | 是否必填 |
| width | number | 1 | 占据列数（总宽 4 列） |
| hide | boolean | false | 隐藏字段 |
| hdAllowClear | boolean | true | 是否允许清空；不传默认 true。Select 未配此项时可回退 `selectOption.hdAllowClear` |
| value | any | null | 初始值 |
| placeholder | string | — | 占位符 |
| disabled | boolean | — | 是否禁用 |
| color / labelColor | string | — | 控件 / 标签颜色 |
| maxLength | number | — | Input 最大长度 |
| prefix | string | — | Input 前缀文字（`nzPrefix`） |
| prefixIcon | string | — | Input 前缀图标（`nz-icon` 的 `nzType`） |
| textAreaRows | number | — | TextArea 行数 |
| explain | string | — | label 下方说明 |
| showTime | boolean | false | Date 含时间 |
| format | string | — | 时间格式化 |
| selectOption | SelectOption | — | 下拉配置 |
| radioOption | RadioOption | — | 单选配置 |
| checkboxOption | CheckboxOption | — | 复选框组配置；不传则为单个复选框 |
| inputNumber | InputNumber | — | 数字框配置 |
| cascaderOption | CascaderOption | — | 级联配置 |
| addressName | string | — | RegionAddress：详细地址字段名（必填） |
| addressValue | string | — | RegionAddress：详细地址初始值 |
| addressPlaceholder | string | 请输入详细地址 | RegionAddress：详细地址占位符 |
| addressMaxLength | number | — | RegionAddress：详细地址最大长度 |
| defaultLabel | string \| string[] | — | Select 默认展示文案 |
| hdDisabledDate | Function | — | 不可选日期 |
| validatorKeys | ValidatorKey[] | — | 校验键 |
| validator | ValidatorFn | — | 自定义校验 |
| onChangeEvent / onSearchEvent | Function | — | 值变化 / 下拉搜索 |
| onChangeEventDebounceTime | number | — | change 防抖（ms） |
| onSearchEventEventDebounceTime | number | — | search 防抖（ms） |

#### FormListType 枚举

`Input` \| `Select` \| `MultipleSelect` \| `Date` \| `DateRange` \| `TextArea` \| `InputNumber` \| `ViewDom` \| `Switch` \| `Time` \| `Cascader` \| `Radio` \| `Checkbox` \| `RegionAddress`

#### ValidatorKey

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| key | string | 校验规则 key |
| label | string | 校验失败提示 |

### FormLine（明细表单项）

在 FormItem 基础上用于行内编辑，额外字段：

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| type | FormLineType | — | 控件类型 |
| align | string | — | 列对齐 left \| right \| center |
| hideViewDomValue | boolean | false | ViewDom 隐藏 value（如只显示图片） |
| isShow | boolean | true | 列设置可见性（仅非 hide 的 ViewDom 可由设置列切换） |
| isSelect | boolean | — | 聚焦后全选内容 |
| preserveNumber | number | — | ViewDom 小数位 |
| maxLength | number | — | Input 最大长度 |
| disabled | boolean | — | 是否禁用 |
| showTime | boolean | false | Date 是否含时间 |
| hdShowToday | boolean | true | Date 是否显示「今天」按钮 |
| hdDisabledDate | Function | — | 不可选日期 |
| style | object | — | 列样式 |
| canSearch | boolean | false | hide 字段参与搜索 |
| defaultLabel | any | — | Select 未初始化时的默认展示文案 |
| explainOption / explainOptionRight | ExplainOption | — | 说明文字（左 / 右） |
| colorOption | ColorOption | — | 动态颜色 |
| selectOption | SelectOption | — | 含 tableColumns 表格下拉 |
| inputNumber | InputNumber | — | 数字框配置 |
| onChangeEvent | Function | — | 值变化，签名见下 |
| onSearchEvent | Function | — | 下拉搜索 |
| onOpenChangeEvent | Function | — | 下拉展开/收起，回调 `(open, line)`，可按行请求 selectList；**展开时组件会先清空当前 `selectList` / 行内 `selectListName`，再回调**，避免条件变化后请求返回前仍显示旧选项 |
| onChangeEventDebounceTime | number | — | change 防抖（ms），未配置或 0 为同步 |
| onSearchEventEventDebounceTime | number | — | search 防抖（ms） |
| onOpenChangeEventDebounceTime | number | — | openChange 防抖（ms） |

#### FormLineType 枚举

`Input` \| `Select` \| `Date` \| `DateRange` \| `TextArea` \| `InputNumber` \| `MultipleSelect` \| `ViewDom` \| `Switch` \| `Time`

#### ColorOption / ExplainOption

| ColorOption | ExplainOption |
| ----------- | ------------- |
| name：hide 字段名存颜色 | show：是否显示 |
| color：默认颜色 | name：hide 字段名存文案 |
| | color：文字颜色 |

#### FormLine 事件签名

```typescript
onChangeEvent: (value, line: FormGroup) => void
onSearchEvent: (keyword, line?: FormGroup) => void
onOpenChangeEvent: (open: boolean, line: FormGroup) => void
```

### HdTableColumn（表格列）

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| title / name | string | — | 列标题 / 字段名 |
| width / minWidth | number | — | 列宽 / 最小列宽 |
| align | string | left | 对齐方式 |
| color | string \| (line) => string | — | 文字颜色。字符串为整列同色；函数按行返回颜色，标红可返回 `#F5222D`，不标色返回空 |
| fixed / fixedWidth | — | — | 固定列 |
| isShow | boolean | true | 设置列可见性 |
| canSort / canWarp | boolean | false | 排序 / 换行 |
| isState | boolean | false | 是否按状态列渲染，取值字段为 `name` |
| stateField | string | — | 状态列取值字段（`name` 为 `state` 且未设置 `isState` 时生效，默认 `state`） |
| render / click | Function | — | 渲染 / 点击 |
| canClick | (line) => boolean | — | 按行控制是否可点 |
| rowNo | boolean \| string | — | 字段值后竖线 + 行号。`true` 为分页连续序号（从 1 起）；字符串为行数据字段名。前面的字段仍可用 `click` 做成超链接，行号不可点 |
| editable | boolean \| (line) => boolean | — | 值后显示编辑笔图标（Figma 14px）；函数按行控制 |
| edit | (line) => void | — | 点击编辑笔回调，供父组件处理（如弹窗改值） |
| btnList | OperateBtn[] | — | `title` 为「操作」时整列按钮；其他列时显示在单元格文案后的操作按钮 |

#### OperateBtn（操作列按钮）

| 参数 | 类型 | 默认值 | 说明 |
| ---- | ---- | ------ | ---- |
| name | string \| (line) => string | — | 按钮文案；支持按行动态（如 `是/否` 旁的「解除/设置」） |
| showConfirm | boolean \| (line) => boolean | false | 是否 popconfirm 确认；传函数时按行数据判断 |
| isRepeat | boolean | false | 与其他按钮互斥显示 |
| click | (line) => void | — | 点击回调 |
| permission | (line) => boolean | — | 是否显示 |

#### HdTableTotalOption（hd-table 底部合计）

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| columnNumber | number | 总列数 |
| insertIndex | number | 插入列下标 |
| insertName | string | 合计字段名 |

#### TotalOption（明细合计行）

用于 `hd-detail-lines`、`hd-detail-lines-page`、`hd-form-lines`。

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| insertIndex | number | 插入列下标（从 1 开始） |
| insertValue | any | 合计值 |
| align | string | 对齐方式 |
| showDecimal | boolean | 始终显示小数 |
| preserveNumber | number | 保留小数位数，不传默认 2 |
| isHide | boolean | 隐藏该合计列 |

#### TableTotalOption（hd-current-table 合计，已弃用）

| 参数 | 类型 | 说明 |
| ---- | ---- | ---- |
| columnNumber | number | 总列数 |
| insertIndex | number | 插入列下标 |
| insertName | string | 合计字段名 |

---

## 附录：ColWidth 列宽常量

发布后的 `.d.ts` 带字面量类型（`as const`），业务仓 IDE 悬停 `ColWidth.xxx` 可直接看到数值与说明。

```typescript
import { ColWidth } from 'fantasy-ngzorro';

ColWidth.tableImageColWidth    // 25   表格单图标
ColWidth.tableTwoImageColWidth  // 40   表格双图标（Select 表格下拉）
ColWidth.billNumberColWidth    // 150  单号
ColWidth.nameColWidth          // 150  名称
ColWidth.codeColWidth          // 100  代码
ColWidth.codeNameColWidth      // 200  [code]name
ColWidth.enumColWidth          // 100  枚举
ColWidth.dateColWidth          // 100  日期
ColWidth.dateTimeColWidth      // 150  日期时间
ColWidth.dateRangeWidth        // 200  日期范围
ColWidth.operateColWidth       // 150  操作列
ColWidth.numberColWidth        // 100  数字
ColWidth.remarkColWidth        // 250  备注
ColWidth.fixColWidth           // 150  通用固定宽
ColWidth.maxColWidth           // 350  超长省略展开
```

## 附录：Page 分页结构

```typescript
class Page<T> {
  totalPages: number;
  totalElements: number;
  pageNumber: number;   // 从 0 开始
  pageSize: number;
  hasContent: boolean;
  hasNext: boolean;
  content: T[];
}
```
