@kc-one/smart-fill-sdk 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,223 +1,542 @@
1
- # Smart Fill SDK
2
-
3
- 页面内智能录入 SDK,用于在业务页面嵌入「文本 / 图片识别 → 自动表单回填 → 结果反馈」能力。
4
-
5
- ## 快速开始
6
-
7
- ```bash
8
- npm install
9
- npm run dev
10
- ```
11
-
12
- 打开 Vite 示例页后,点击右上角「智能录入」悬浮按钮。
13
-
14
- ## 接入示例
15
-
16
- ```ts
17
- import { SmartFill } from '@kc-one/smart-fill-sdk'
18
- import '@kc-one/smart-fill-sdk/style.css'
19
-
20
- await SmartFill.setup({ apiKey: 'seKey_xxxxxxxxxxxxx' })
21
- // 网关地址在 src/config/defaults.ts 的 DEFAULT_BASE_URL 中配置
22
-
23
- const smartFill = SmartFill.create({
24
- formCode: 'apply-form',
25
- strictFormConfig: true,
26
- routeContainerSelector: '.page-container',
27
- // floatingContainer: '#smart-fill-host'
28
- })
29
-
30
- smartFill.registerFields([
31
- {
32
- fieldId: 'customerName',
33
- label: '客户姓名',
34
- type: 'text',
35
- element: '[data-smart-fill-key="customerName"]'
36
- },
37
- {
38
- fieldId: 'legalBankMobile',
39
- label: '法人手机号',
40
- type: 'text',
41
- localRuleMode: 'off', // 该字段不走本地规则,仅走后端识别
42
- element: '[data-smart-fill-key="legalBankMobile"]'
43
- }
44
- ])
45
-
46
- smartFill.mountFloatingButton()
47
- ```
48
-
49
- ### 悬浮挂载策略
50
-
51
- `mountFloatingButton()` 默认会自动识别当前 SPA 子路由页面容器;如果你的业务页面结构固定,推荐显式传入挂载策略,优先级如下:
52
-
53
- 1. `floatingContainer`: 直接指定悬浮面板挂载容器,支持 `HTMLElement` 或 CSS 选择器
54
- 2. `routeContainerSelector`: 指定当前子路由页面容器选择器
55
- 3. SDK 自动识别当前页面容器
56
- 4. 回退到 `document.body`
57
-
58
- ```ts
59
- const smartFill = SmartFill.create({
60
- formCode: 'apply-form',
61
- floatingContainer: '#smart-fill-host'
62
- // 或 routeContainerSelector: '.app-main > .page-container'
63
- })
64
- ```
65
-
66
- ## 核心流程
67
-
68
- ```text
69
- SmartFill.setup({ apiKey })
70
- 校验 apiKey / 创建会话 / 获取 accessToken
71
- SmartFill.create({ formCode })
72
- 创建页面实例,绑定网关客户端
73
- smartFill.registerFields([...]) // 可选:L3 高精度字段注册
74
- smartFill.mountFloatingButton() // 挂载悬浮入口 + 弹框 UI
75
- smartFill.open()
76
- → rescan() 扫描字段,生成 scanToken
77
- 用户输入文本 / 上传图片,点击「智能识别回填」
78
- → 本地规则预识别(可开关)
79
- → 后端识别网关补全
80
- 合并结果,自动回填高置信字段
81
- → 返回 applied / skipped / warnings / traceId
82
- ```
83
-
84
- ## 当前实现范围
85
-
86
- | 模块 | 能力 |
87
- | --- | --- |
88
- | `SmartFill.setup` | apiKey 校验、会话初始化(网关地址见 `config/defaults.ts`) |
89
- | `SmartFill.create` | 实例生命周期、单活 UI 管理、SSR mock 实例 |
90
- | `registerFields / rescan` | 优先注册字段,兜底 DOM 扫描 |
91
- | `LocalRuleEngine` | 手机号、身份证、邮箱、银行卡、金额、日期、角色化键值对识别 |
92
- | `FieldSchema.localRuleMode` | 字段级本地规则策略:`inherit / off / only` |
93
- | `SmartFillPanel` | Shadow DOM 面板、本地优先识别总开关、自动回填进度和结果反馈 |
94
- | `DomFiller` | 原生控件回填、scanToken / fingerprint 校验、浅蓝高亮反馈 |
95
- | `GatewayClient` | `/sdk/session`、`/sdk/forms/:code`、`/sdk/recognize` 网关调用 |
96
-
97
- ## 目录结构
98
-
99
- ```text
100
- smart-fill-sdk/
101
- ├─ package.json # 包配置,exports 指向 dist/
102
- ├─ vite.config.ts # Vite 库模式构建 + d.ts 生成
103
- ├─ tsconfig.json # TypeScript 编译配置
104
- ├─ README.md # 本文件
105
-
106
- ├─ examples/ # 接入示例
107
- │ └─ vanilla/
108
- │ ├─ index.html # 原生表单 demo 页面
109
- │ └─ main.ts # setup create registerFields → mountFloatingButton
110
-
111
- └─ src/ # SDK 源码
112
- ├─ index.ts # 包入口,统一导出对外 API 与类型
113
- ├─ style.css # 回填成功高亮样式(浅蓝背景)
114
- ├─ vite-env.d.ts # CSS 模块类型声明
115
-
116
- ├─ core/ # 生命周期与实例编排
117
- │ ├─ smart-fill.ts # 全局 setup / create 入口,管理会话状态
118
- │ ├─ smart-fill-instance.ts # 页面实例:扫描、识别、自动回填、事件分发
119
- │ ├─ instance-manager.ts # 多实例 UI 互斥,同一时刻仅一个面板激活
120
- │ └─ errors.ts # 统一错误对象、traceId 生成
121
-
122
- ├─ scanner/ # 字段扫描与稳定标识
123
- │ ├─ dom-scanner.ts # DOM 字段扫描、弹窗容器定位、scanToken 生成
124
- │ └─ fingerprint.ts # 字段 fingerprint 生成,过滤动态 ID
125
-
126
- ├─ rules/ # 浏览器端本地规则
127
- │ └─ local-rules.ts # 正则 + 键值对 + 角色语义识别引擎
128
-
129
- ├─ config/ # SDK 内置配置
130
- │ └─ defaults.ts # DEFAULT_BASE_URL 网关根地址(前期写死)
131
-
132
- ├─ client/ # 后端网关客户端
133
- │ └─ gateway-client.ts # session / formConfig / recognize 请求封装
134
-
135
- ├─ filler/ # 表单回填
136
- │ └─ dom-filler.ts # DOM 写入、适配器分发、scanToken 校验、高亮
137
-
138
- ├─ ui/ # 页面内 UI
139
- │ └─ panel.ts # Shadow DOM 弹框:输入、开关、识别、结果展示
140
-
141
- ├─ events/ # 事件系统
142
- │ └─ event-bus.ts # 轻量 pub/sub,驱动 ready / recognized / applied 等事件
143
-
144
- ├─ adapters/ # 组件库回填适配器
145
- │ └─ native.ts # 原生 input / textarea / select 适配器
146
-
147
- └─ types/ # 对外 TypeScript 类型
148
- └─ index.ts # FieldSchema、RecognizeResult、SmartFillEventMap 等
149
- ```
150
-
151
- ### 模块职责说明
152
-
153
- #### `core/` — 生命周期
154
-
155
- - **`smart-fill.ts`**:SDK 全局单例入口。`setup()` 负责 apiKey 校验和会话初始化;`create()` 在 ready 后创建页面实例。
156
- - **`config/defaults.ts`**:前期写死的网关 `DEFAULT_BASE_URL`,切换环境时改此文件即可。
157
- - **`smart-fill-instance.ts`**:单页面实例的核心编排器。串联扫描 → 本地规则 → 网关识别 → 自动回填,并通过 EventBus 向外派发事件。
158
- - **`instance-manager.ts`**:保证同一时刻只有一个实例的 UI 面板处于打开状态,避免多实例互相遮挡。
159
- - **`errors.ts`**:统一错误码封装(`SmartFillException`)和 `traceId` 生成,供审计和排障使用。
160
-
161
- #### `scanner/` — 字段扫描
162
-
163
- - **`dom-scanner.ts`**:扫描页面可见输入控件,支持注册字段优先、平台容器、最上层弹窗/抽屉定位。每次扫描生成唯一 `scanToken`。
164
- - **`fingerprint.ts`**:为每个字段生成稳定指纹,过滤 React/AntD 等框架的动态 ID,用于回填前校验字段是否变化。
165
-
166
- #### `rules/` 本地规则
167
-
168
- - **`local-rules.ts`**:浏览器端优先识别引擎。支持正则提取(手机号、身份证等)、键值对解析(`姓名:张三`)、角色语义(法人/紧急联系人/配偶)。匹配时优先角色字段,再退化到通用字段。
169
-
170
- #### `client/` 网关
171
-
172
- - **`gateway-client.ts`**:封装后端 `/sdk/session`、`/sdk/forms/:code`、`/sdk/recognize` 三个接口,统一请求 `DEFAULT_BASE_URL`。
173
-
174
- #### `filler/` — 回填
175
-
176
- - **`dom-filler.ts`**:执行字段写入。校验 `scanToken` `fingerprint` 防止误填;支持注册字段 `setValue`、适配器模式和原生 DOM 事件兜底;回填成功后添加浅蓝背景高亮,用户交互后自动消失。
177
-
178
- #### `ui/` — 界面
179
-
180
- - **`panel.ts`**:Shadow DOM 隔离的页面内弹框。包含文本输入、图片上传、本地优先识别开关、清空/识别按钮、识别结果列表和状态反馈。支持右上角悬浮 + 拖拽。
181
-
182
- #### `events/` — 事件
183
-
184
- - **`event-bus.ts`**:实例级和全局级事件总线,事件包括 `ready`、`scanCompleted`、`recognizing`、`recognized`、`applying`、`applied`、`error`。
185
-
186
- #### `adapters/` — 适配器
187
-
188
- - **`native.ts`**:原生 HTML 表单控件(input / textarea / select)的回填适配器,通过 dispatch `input/change` 事件触发框架响应。
189
-
190
- #### `types/` — 类型
191
-
192
- - **`index.ts`**:全部对外 TypeScript 类型定义,包括字段模型、识别结果、回填结果、事件映射、适配器接口等。
193
-
194
- ## 本地规则开关
195
-
196
- | 层级 | 配置 | 说明 |
197
- | --- | --- | --- |
198
- | 弹框总开关 | UI「启用本地优先识别」 | 一键开启/关闭本地规则,默认开启 |
199
- | 字段级 | `FieldSchema.localRuleMode` | `inherit` 跟随总开关;`off` 跳过本地规则;`only` 仅本地规则、不走后端 |
200
-
201
- ## 发布到 npm 公共仓库
202
-
203
- 包归属 [@kc-one](https://www.npmjs.com/settings/kc-one/packages) 组织,包名为 `@kc-one/smart-fill-sdk`。
204
-
205
- ```bash
206
- npm login # 使用已加入 kc-one 组织且开启 2FA 的账号
207
- npm run build
208
- npm publish --access public # publishConfig 已配置 public + registry.npmjs.org
209
- ```
210
-
211
- 安装:
212
-
213
- ```bash
214
- npm install @kc-one/smart-fill-sdk
215
- ```
216
-
217
- ## 构建
218
-
219
- ```bash
220
- npm run typecheck # 类型检查
221
- npm run build # 构建 dist/(ESM + UMD + d.ts)
222
- npm run preview # 预览构建产物
223
- ```
1
+ # Smart Fill SDK
2
+
3
+ 页面内智能录入 SDK,用于在业务页面嵌入「文本 / 图片识别 → 自动表单回填 → 结果反馈」能力。
4
+
5
+ - **包名**:`@kc-one/smart-fill-sdk`
6
+ - **当前版本**:`0.0.12`
7
+ - **浏览器**:Chrome ≥ 90、Edge ≥ 90、Firefox ≥ 88、Safari ≥ 14
8
+
9
+ ## 安装
10
+
11
+ ```bash
12
+ npm install @kc-one/smart-fill-sdk
13
+ ```
14
+
15
+ ## 快速开始
16
+
17
+ ### 本地开发
18
+
19
+ ```bash
20
+ npm install
21
+ npm run dev
22
+ ```
23
+
24
+ 打开 Vite 示例页(`examples/vanilla/index.html`),点击「智能录入」入口。
25
+
26
+ ### 业务接入
27
+
28
+ ```ts
29
+ import { SmartFill } from '@kc-one/smart-fill-sdk'
30
+ import '@kc-one/smart-fill-sdk/style.css'
31
+
32
+ await SmartFill.setup({ apiKey: 'seKey-xxxxxxxxxxxxx' })
33
+ // 网关根地址见 DEFAULT_BASE_URL(src/config/defaults.ts)
34
+
35
+ const smartFill = SmartFill.create({
36
+ formCode: 'apply-form',
37
+ routeContainerSelector: '.page-container'
38
+ })
39
+
40
+ smartFill.registerFields([
41
+ {
42
+ fieldId: 'customerName',
43
+ label: '客户姓名',
44
+ type: 'text',
45
+ element: '[data-smart-fill-key="customerName"]'
46
+ },
47
+ {
48
+ fieldId: 'legalBankMobile',
49
+ label: '法人手机号',
50
+ type: 'text',
51
+ localRuleMode: 'off', // 该字段不走本地规则,仅走后端识别
52
+ element: '[data-smart-fill-key="legalBankMobile"]'
53
+ }
54
+ ])
55
+
56
+ smartFill.mountFloatingButton()
57
+ // 或嵌入指定容器:smartFill.mount('#smart-fill-entry')
58
+ ```
59
+
60
+ ## 核心流程
61
+
62
+ ```text
63
+ SmartFill.setup({ apiKey })
64
+ → 校验 apiKey / 创建会话 / 获取 accessToken
65
+ SmartFill.create({ formCode, ... })
66
+ 创建页面实例,绑定网关客户端
67
+ smartFill.registerFields([...]) // 可选:L3 高精度字段注册
68
+ smartFill.mountFloatingButton() // 或 mount() 嵌入容器
69
+ smartFill.open() // 打开面板并 rescan
70
+ 用户输入文本 / 上传图片,点击「智能识别」
71
+ → rescan() 扫描字段,生成 scanToken
72
+ 本地规则预识别(可开关)
73
+ 后端识别网关补全
74
+ 合并结果,自动回填高置信字段(或 apiCallback 回调)
75
+ → 返回 applied / skipped / warnings / traceId
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 对外 API 总览
81
+
82
+ ### 类与常量
83
+
84
+ | 导出 | 说明 |
85
+ | --- | --- |
86
+ | `SmartFill` | 全局入口:`setup` / `create` / `on` |
87
+ | `SmartFillInstance` | 页面实例类(通常通过 `SmartFill.create()` 获取) |
88
+ | `DomScanner` | DOM 字段扫描器 |
89
+ | `DomFiller` | 表单回填执行器 |
90
+ | `LocalRuleEngine` | 浏览器端本地规则识别引擎 |
91
+ | `EventBus` | 轻量事件总线 |
92
+ | `NativeAdapter` | 原生 input / textarea / select 适配器 |
93
+ | `UiFrameworkAdapter` | Element / Ant Design Vue / Naive UI / Arco / Vant 等 UI 框架适配器 |
94
+ | `ElementAdapter` | `UiFrameworkAdapter` 的兼容别名 |
95
+ | `DEFAULT_BASE_URL` | 网关根地址常量 |
96
+ | `SmartFillException` | 结构化异常类 |
97
+ | `createError` | 创建标准 SDK 异常 |
98
+ | `toSmartFillError` | 将未知 error 归一化为 `SmartFillError` |
99
+ | `createTraceId` | 生成唯一追踪 ID |
100
+
101
+ ### 类型
102
+
103
+ | 类型 | 说明 |
104
+ | --- | --- |
105
+ | `SmartFillSetupConfig` | `setup()` 配置 |
106
+ | `SmartFillCreateConfig` | `create()` 配置 |
107
+ | `FieldSchema` | 业务注册字段 Schema |
108
+ | `FieldDescriptor` | 扫描后的运行时字段描述 |
109
+ | `FieldType` / `FieldOption` | 字段类型与选项 |
110
+ | `ScanResult` | 扫描结果(含 `scanToken` 与 `fields`) |
111
+ | `RecognizePayload` / `RecognizeResult` | 识别入参与返回 |
112
+ | `FieldSuggestion` | 单条识别建议 |
113
+ | `ApplyInput` / `ApplyResult` | 回填入参与结果 |
114
+ | `AutoApplyItem` / `AutoApplyState` | 自动回填候选状态 |
115
+ | `ApiRecognizeCallbackResult` / `ApiRecognizeField` | API 回调模式返回结构 |
116
+ | `SmartFillEventMap` / `SmartFillError` | 事件映射与错误结构 |
117
+ | `SmartFillAdapter` | 自定义组件库适配器接口 |
118
+ | `SessionResponse` | 会话初始化响应 |
119
+ | `FormConfigResponse` | 已弃用的远端表单配置 |
120
+
121
+ ---
122
+
123
+ ## SmartFill(全局入口)
124
+
125
+ ### `SmartFill.setup(config): Promise<SessionResponse>`
126
+
127
+ 初始化 SDK,校验 apiKey 并创建网关会话。
128
+
129
+ | 参数 | 类型 | 必填 | 说明 |
130
+ | --- | --- | --- | --- |
131
+ | `apiKey` | `string` | 是 | API 密钥,格式 `seKey-` 开头 |
132
+ | `requestTimeoutMs` | `number` | 否 | HTTP 超时,默认 `30000` |
133
+
134
+ 行为说明:
135
+
136
+ - 相同 `apiKey` 重复调用会复用已有 Promise
137
+ - `apiKey` 变更时会销毁所有存活实例并清空扫描缓存
138
+ - SSR 环境(无 `window`)返回 mock session,不发起网络请求
139
+
140
+ ### `SmartFill.create(config?): SmartFillInstance`
141
+
142
+ 创建页面实例。**必须在 `setup` 就绪后调用**,否则抛出 `SDK_NOT_READY`。
143
+
144
+ SSR 环境返回 noop 实例,所有方法安全空操作。
145
+
146
+ ### `SmartFill.on(event, handler): () => void`
147
+
148
+ 订阅全局事件,目前仅 `ready`。返回取消订阅函数。
149
+
150
+ ---
151
+
152
+ ## SmartFillInstance(页面实例)
153
+
154
+ 通过 `SmartFill.create()` 获取,负责扫描、识别、回填与 UI 生命周期。
155
+
156
+ ### 事件
157
+
158
+ #### `on(event, handler): () => void`
159
+
160
+ 订阅实例事件,返回取消订阅函数。
161
+
162
+ | 事件 | 载荷 | 触发时机 |
163
+ | --- | --- | --- |
164
+ | `ready` | `{ apiKey }` | 实例就绪(全局 setup 完成时由全局总线触发) |
165
+ | `scanCompleted` | `{ scanToken, fieldCount }` | `rescan()` 成功 |
166
+ | `recognizing` | `{ scanToken, traceId }` | 识别开始 |
167
+ | `recognized` | `RecognizeResult` | 识别完成 |
168
+ | `applying` | `{ scanToken, count }` | 回填开始 |
169
+ | `applied` | `ApplyResult` | 回填完成 |
170
+ | `error` | `SmartFillError` | 任意阶段出错 |
171
+
172
+ ### 字段注册
173
+
174
+ #### `registerFields(fields): this`
175
+
176
+ 显式注册字段映射(L3 模式)。注册后 `rescan` 仅解析这些字段,不再自动扫 DOM
177
+
178
+ - 支持链式调用
179
+ - `rowKey` 用于明细行等同 `fieldId` 多行场景,组合键 `{fieldId}:{rowKey}` 不可重复
180
+
181
+ #### `unregisterFields(fieldIds?): void`
182
+
183
+ 取消注册字段。不传 `fieldIds` 时清空全部注册。
184
+
185
+ ### UI 挂载
186
+
187
+ #### `mount(target): this`
188
+
189
+ 将面板嵌入指定容器(inline 模式)。`target` 支持 CSS 选择器或 `HTMLElement`。
190
+
191
+ #### `mountFloatingButton(): this`
192
+
193
+ 挂载右下角悬浮按钮 + 弹框(floating 模式)。挂载容器优先级见 [悬浮挂载策略](#悬浮挂载策略)。
194
+
195
+ #### `open(targetPanel?): Promise<void>`
196
+
197
+ 打开面板并触发 `rescan`(若尚无扫描结果)。同时激活当前实例,关闭其他实例面板。
198
+
199
+ #### `close(targetPanel?): void`
200
+
201
+ 关闭面板,不销毁实例。
202
+
203
+ ### 扫描 / 识别 / 回填
204
+
205
+ #### `rescan(): Promise<ScanResult>`
206
+
207
+ 扫描页面可回填字段。优先级:`registerFields` > DOM 自动扫描。
208
+
209
+ - 生成唯一 `scanToken`,贯穿识别与回填
210
+ - 无字段时抛出 `NO_FIELDS_FOUND`
211
+ - 成功时 emit `scanCompleted`
212
+
213
+ #### `recognize(input): Promise<RecognizeResult>`
214
+
215
+ 识别入口:文本和/或图片 → 本地规则 + 后端网关 → 合并 → 自动回填或 API 回调。
216
+
217
+ ```ts
218
+ await smartFill.recognize({
219
+ text: '姓名:张三 手机号:13800000000',
220
+ images: [file] // 可选,File[]
221
+ })
222
+ ```
223
+
224
+ 识别策略:
225
+
226
+ 1. 识别前先 `rescan()`,下拉选项在用户主动识别时动态展开
227
+ 2. `localRuleMode === 'off'` 跳过本地规则;`'only'` 跳过后端;`'inherit'` 跟随本地优先开关
228
+ 3. 后端成功时优先采用后端字段,本地规则仅补充后端未返回的字段
229
+ 4. 后端失败且存在本地结果时降级为本地识别
230
+ 5. `apiEnable: true` 时跳过自动回填,改为触发 `apiCallback`
231
+ 6. 置信度 ≥ 0.75 且无 `warnings` 的字段自动回填
232
+
233
+ #### `apply(input): Promise<ApplyResult>`
234
+
235
+ 手动回填指定字段,需传入与当前扫描一致的 `scanToken`。
236
+
237
+ ```ts
238
+ await smartFill.apply({
239
+ scanToken: result.scanToken,
240
+ values: [
241
+ { fieldId: 'customerName', value: '张三', source: 'ai' }
242
+ ]
243
+ })
244
+ ```
245
+
246
+ #### `useAdapter(adapter): this`
247
+
248
+ 注册组件库回填适配器,支持链式调用。实例默认已内置 `UiFrameworkAdapter`。
249
+
250
+ #### `destroy(): void`
251
+
252
+ 销毁实例:移除面板、清空事件、从实例管理器注销。销毁后调用其他方法抛出 `INSTANCE_DESTROYED`。
253
+
254
+ ---
255
+
256
+ ## SmartFill.create 配置项
257
+
258
+ | 字段 | 类型 | 默认 | 说明 |
259
+ | --- | --- | --- | --- |
260
+ | `formCode` | `string` | — | 表单编码,识别请求携带给后端 |
261
+ | `strictFormConfig` | `boolean` | — | **已弃用**,不再拉取远端 formConfig |
262
+ | `root` | `HTMLElement \| ShadowRoot` | `document` | 扫描根节点 |
263
+ | `maxFields` | `number` | `200` | DOM 自动扫描最大字段数 |
264
+ | `floatingContainer` | `HTMLElement \| string` | — | 悬浮面板挂载容器,优先级最高 |
265
+ | `routeContainerSelector` | `string` | — | 子路由页面容器选择器 |
266
+ | `locale` | `'zh-CN' \| 'en-US'` | — | 预留 |
267
+ | `messages` | `Record<string, string>` | — | 面板文案覆盖,key 见下表 |
268
+ | `apiEnable` | `boolean` | `false` | 为 `true` 时识别后不自动回填,改走 `apiCallback` |
269
+ | `apiCallback` | `(result) => void \| Promise<void>` | — | API 回调,仅在 `apiEnable: true` 时触发 |
270
+
271
+ ### 面板文案 key(`messages`)
272
+
273
+ | key | 默认文案 |
274
+ | --- | --- |
275
+ | `entry` | 智能录入 |
276
+ | `title` | 智能录入 |
277
+ | `expand` / `collapse` / `close` | 展开 / 收起 / 关闭 |
278
+ | `placeholder` | 粘贴文本,如:姓名:张三 手机号:13800000000 |
279
+ | `clear` | 清空 |
280
+ | `recognize` | 智能识别 |
281
+ | `uploadHint` | 点击、拖拽、Ctrl + V 粘贴图片至此 |
282
+ | `empty` | 暂无识别结果 |
283
+ | `emptyInput` | 请输入文本内容。 |
284
+ | `recognized` | 识别完成,正在自动回填... |
285
+ | `invalidImageError` | 请选择图片文件。 |
286
+ | `maxFilesError` | 最多上传 N 张图片 |
287
+ | `maxSingleFileSizeError` | 单张图片不能超过 10MB |
288
+ | `maxTotalFileSizeError` | 上传图片总大小不能超过 50MB |
289
+ | `imageReady` | 已选择 N 张图片,开始识别... |
290
+
291
+ ---
292
+
293
+ ## API 回调模式
294
+
295
+ 适用于业务方自行处理识别结果、不依赖 SDK 自动 DOM 回填的场景。
296
+
297
+ ```ts
298
+ const smartFill = SmartFill.create({
299
+ formCode: 'apply-form',
300
+ apiEnable: true,
301
+ apiCallback: async (result) => {
302
+ console.log(result.fields) // ApiRecognizeField[]
303
+ // 可选:自行调用 apply 回填
304
+ await smartFill.apply({
305
+ scanToken: result.scanToken,
306
+ values: result.fields.map((f) => ({ fieldId: f.fieldId, value: f.value }))
307
+ })
308
+ }
309
+ })
310
+ ```
311
+
312
+ `ApiRecognizeCallbackResult` 结构:
313
+
314
+ | 字段 | 说明 |
315
+ | --- | --- |
316
+ | `scanToken` | 当前扫描批次 token |
317
+ | `trace` | 追踪信息(traceId、usedOcr、usedAi、durationMs) |
318
+ | `fields` | 识别字段列表(含 value、confidence、currentValue 等) |
319
+ | `warnings` | 可选警告 |
320
+
321
+ ---
322
+
323
+ ## 扩展模块 API
324
+
325
+ ### DomScanner
326
+
327
+ ```ts
328
+ const scanner = new DomScanner(document)
329
+
330
+ // 同步扫描
331
+ const result = scanner.scan({
332
+ registered?: FieldSchema[],
333
+ scanContainer?: string,
334
+ maxFields?: number
335
+ })
336
+
337
+ // 异步扫描(展开下拉并补充动态选项)
338
+ const resultWithOptions = await scanner.scanWithDynamicOptions({ maxFields: 200 })
339
+ ```
340
+
341
+ 返回 `ScanResult`:`{ scanToken, fields: FieldDescriptor[] }`。
342
+
343
+ ### DomFiller
344
+
345
+ ```ts
346
+ const filler = new DomFiller(fields, schemas, adapters)
347
+ const result = await filler.apply({
348
+ scanToken: 'scan_xxx',
349
+ values: [{ fieldId: 'mobile', value: '13800000000' }]
350
+ })
351
+ ```
352
+
353
+ 回填前校验 `scanToken` 与 `fingerprint`,支持 `FieldSchema.setValue` / 适配器 / 原生 DOM 三种写入路径。
354
+
355
+ 跳过原因码:`FIELD_NOT_FOUND` | `SCAN_TOKEN_EXPIRED` | `VALIDATE_FAILED` | `SET_VALUE_FAILED`。
356
+
357
+ ### LocalRuleEngine
358
+
359
+ ```ts
360
+ const engine = new LocalRuleEngine()
361
+ const suggestions = engine.recognize(text, fields, scanToken)
362
+ ```
363
+
364
+ 当前支持的本地识别类型:手机号、身份证、邮箱、银行卡、金额、日期。
365
+
366
+ ### EventBus
367
+
368
+ ```ts
369
+ const bus = new EventBus()
370
+ const off = bus.on('recognized', (payload) => { ... })
371
+ bus.off('recognized', handler)
372
+ bus.emit('recognized', result)
373
+ bus.clear()
374
+ ```
375
+
376
+ ### SmartFillAdapter(自定义适配器)
377
+
378
+ ```ts
379
+ smartFill.useAdapter({
380
+ name: 'my-component',
381
+ match: (element, field) => element.classList.contains('my-input'),
382
+ getValue: (field) => { ... },
383
+ setValue: async (field, value) => { ... },
384
+ validateApplied: async (field, value) => true
385
+ })
386
+ ```
387
+
388
+ ---
389
+
390
+ ## FieldSchema 字段注册
391
+
392
+ | 字段 | 类型 | 说明 |
393
+ | --- | --- | --- |
394
+ | `fieldId` | `string` | 字段唯一标识 |
395
+ | `label` | `string` | 展示标签 |
396
+ | `type` | `FieldType` | `text` / `textarea` / `select` / `radio` / `checkbox` / `date` / `number` / `amount` / `cascader` |
397
+ | `element` | `HTMLElement \| string` | DOM 元素或 CSS 选择器 |
398
+ | `localRuleMode` | `'inherit' \| 'off' \| 'only'` | 本地规则策略 |
399
+ | `options` | `FieldOption[]` | 下拉/单选选项 |
400
+ | `getValue` | `() => unknown` | 自定义读值 |
401
+ | `setValue` | `(value) => void \| Promise<void>` | 自定义写值 |
402
+ | `transform` | `(aiValue) => unknown` | AI 返回值转换 |
403
+ | `validate` | `(value) => boolean \| string \| Promise<...>` | 写入前校验 |
404
+ | `rowKey` | `string \| number` | 明细行 key |
405
+ | `scope` | `'form' \| 'detail' \| 'dialog'` | 字段作用域 |
406
+ | `required` / `section` / `demoValue` | — | 其他元数据 |
407
+
408
+ ---
409
+
410
+ ## 本地规则
411
+
412
+ | 层级 | 配置 | 说明 |
413
+ | --- | --- | --- |
414
+ | 实例级 | `localPriorityEnabled`(localStorage 持久化) | 默认 **关闭**(优先后端识别);开启后 `inherit` 字段走本地规则 |
415
+ | 字段级 | `FieldSchema.localRuleMode` | `inherit` 跟随实例开关;`off` 跳过后端;`only` 仅本地、不走后端 |
416
+
417
+ ---
418
+
419
+ ## 悬浮挂载策略
420
+
421
+ `mountFloatingButton()` 挂载容器优先级:
422
+
423
+ 1. `floatingContainer`:显式指定容器(`HTMLElement` 或 CSS 选择器)
424
+ 2. `routeContainerSelector`:子路由页面容器
425
+ 3. SDK 自动识别(`#app` / `#root` / `main` / `.page-container` 等)
426
+ 4. 回退到 `document.body`
427
+
428
+ floating 模式下路由切换或挂载容器从 DOM 移除时,实例会自动 `destroy()`。
429
+
430
+ ---
431
+
432
+ ## 错误码
433
+
434
+ | code | stage | 说明 |
435
+ | --- | --- | --- |
436
+ | `SDK_NOT_READY` | setup | 未调用 setup 或 setup 未完成 |
437
+ | `API_KEY_INVALID` | setup | apiKey 格式不正确 |
438
+ | `NO_FIELDS_FOUND` | scan | 当前页面未找到可回填字段 |
439
+ | `UNSUPPORTED_PAGE` | scan / ui | 字段重复注册 / 挂载点未找到 |
440
+ | `SCAN_TOKEN_EXPIRED` | apply | 扫描已过期,需重新 rescan |
441
+ | `TOKEN_EXPIRED` | recognize | 会话过期,清空扫描缓存 |
442
+ | `INSTANCE_DESTROYED` | ui | 实例已销毁 |
443
+ | `RECOGNIZE_FAILED` | recognize | 识别失败 |
444
+ | `RECOGNIZE_TIMEOUT` | recognize | 识别超时(可重试) |
445
+
446
+ 捕获示例:
447
+
448
+ ```ts
449
+ import { SmartFillException } from '@kc-one/smart-fill-sdk'
450
+
451
+ try {
452
+ await smartFill.recognize({ text: '...' })
453
+ } catch (error) {
454
+ if (error instanceof SmartFillException) {
455
+ console.log(error.smartFillError.code, error.smartFillError.traceId)
456
+ }
457
+ }
458
+ ```
459
+
460
+ ---
461
+
462
+ ## 目录结构
463
+
464
+ ```text
465
+ smart-fill-sdk/
466
+ ├─ package.json
467
+ ├─ vite.config.ts
468
+ ├─ tsconfig.json
469
+ ├─ README.md
470
+
471
+ ├─ examples/vanilla/ # 原生表单接入示例
472
+ │ ├─ index.html
473
+ │ └─ main.ts
474
+
475
+ └─ src/
476
+ ├─ index.ts # 包入口,统一导出 API 与类型
477
+ ├─ style.css # 回填高亮样式
478
+
479
+ ├─ core/ # 生命周期与实例编排
480
+ │ ├─ smart-fill.ts # setup / create 全局入口
481
+ │ ├─ smart-fill-instance.ts
482
+ │ ├─ instance-manager.ts # 多实例 UI 互斥
483
+ │ └─ errors.ts # SmartFillException / createError
484
+
485
+ ├─ scanner/ # 字段扫描
486
+ │ ├─ dom-scanner.ts
487
+ │ ├─ fingerprint.ts
488
+ │ └─ ui-frameworks.ts # Element / AntD / Naive 等组件识别
489
+
490
+ ├─ select/ # 下拉 / 级联 / 地址选择回填
491
+ │ ├─ custom-select.ts
492
+ │ ├─ select-fill.ts
493
+ │ ├─ option-match.ts
494
+ │ └─ address-cascader.ts
495
+
496
+ ├─ rules/local-rules.ts # 本地规则引擎
497
+ ├─ config/defaults.ts # DEFAULT_BASE_URL
498
+ ├─ client/gateway-client.ts # 网关 HTTP 客户端
499
+ ├─ filler/ # DOM 回填与高亮
500
+ │ ├─ dom-filler.ts
501
+ │ └─ highlight-style.ts
502
+ ├─ ui/panel.ts # Shadow DOM 面板
503
+ ├─ events/event-bus.ts
504
+ ├─ adapters/ # 原生 + UI 框架适配器
505
+ │ ├─ native.ts
506
+ │ └─ ui-framework.ts
507
+ └─ types/index.ts # 全部对外 TypeScript 类型
508
+ ```
509
+
510
+ ---
511
+
512
+ ## 实现范围
513
+
514
+ | 模块 | 能力 |
515
+ | --- | --- |
516
+ | `SmartFill.setup` | apiKey 校验、会话初始化 |
517
+ | `SmartFill.create` | 实例生命周期、单活 UI 管理、SSR mock |
518
+ | `registerFields / rescan` | 优先注册字段,兜底 DOM 扫描 + 页面/会话级扫描缓存 |
519
+ | `LocalRuleEngine` | 手机号、身份证、邮箱、银行卡、金额、日期 |
520
+ | `FieldSchema.localRuleMode` | 字段级本地规则策略 |
521
+ | `SmartFillPanel` | Shadow DOM 面板、文本/图片输入、识别进度与结果反馈 |
522
+ | `DomFiller` | 原生 + UI 框架回填、scanToken / fingerprint 校验、浅蓝高亮 |
523
+ | `UiFrameworkAdapter` | Element / Ant Design Vue / Naive UI / Arco / Vant 等 |
524
+ | `GatewayClient` | session / OCR / smartEntry 识别网关 |
525
+
526
+ ---
527
+
528
+ ## 构建与发布
529
+
530
+ ```bash
531
+ npm run typecheck # 类型检查
532
+ npm run build # 构建 dist/(ESM + UMD + d.ts)
533
+ npm run preview # 预览构建产物
534
+ ```
535
+
536
+ 发布到 [@kc-one](https://www.npmjs.com/settings/kc-one/packages):
537
+
538
+ ```bash
539
+ npm login
540
+ npm run build
541
+ npm publish --access public
542
+ ```