id-scanner-lib 1.3.2 → 1.5.0
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 +55 -460
- package/dist/id-scanner-lib.esm.js +4641 -0
- package/dist/id-scanner-lib.esm.js.map +1 -0
- package/dist/id-scanner-lib.js +14755 -0
- package/dist/id-scanner-lib.js.map +1 -0
- package/dist/types/core/base-module.d.ts +44 -0
- package/dist/types/core/camera-manager.d.ts +258 -0
- package/dist/types/core/config.d.ts +88 -0
- package/dist/types/core/errors.d.ts +111 -0
- package/dist/types/core/event-emitter.d.ts +55 -0
- package/dist/types/core/logger.d.ts +277 -0
- package/dist/types/core/module-manager.d.ts +78 -0
- package/dist/types/core/plugin-manager.d.ts +158 -0
- package/dist/types/core/resource-manager.d.ts +246 -0
- package/dist/types/core/result.d.ts +83 -0
- package/dist/types/core/scanner-factory.d.ts +93 -0
- package/dist/types/index.bundle.d.ts +1303 -0
- package/dist/types/index.d.ts +86 -0
- package/dist/types/interfaces/external-types.d.ts +174 -0
- package/dist/types/interfaces/face-detection.d.ts +293 -0
- package/dist/types/interfaces/scanner-module.d.ts +280 -0
- package/dist/types/modules/face/face-detector.d.ts +170 -0
- package/dist/types/modules/face/index.d.ts +56 -0
- package/dist/types/modules/face/liveness-detector.d.ts +177 -0
- package/dist/types/modules/face/types.d.ts +136 -0
- package/dist/types/modules/id-card/anti-fake-detector.d.ts +170 -0
- package/dist/types/modules/id-card/id-card-detector.d.ts +131 -0
- package/dist/types/modules/id-card/index.d.ts +89 -0
- package/dist/types/modules/id-card/ocr-processor.d.ts +110 -0
- package/dist/types/modules/id-card/ocr-worker.d.ts +31 -0
- package/dist/types/modules/id-card/types.d.ts +181 -0
- package/dist/types/modules/qrcode/index.d.ts +51 -0
- package/dist/types/modules/qrcode/qr-code-scanner.d.ts +64 -0
- package/dist/types/modules/qrcode/types.d.ts +67 -0
- package/dist/types/utils/camera.d.ts +81 -0
- package/dist/types/utils/image-processing.d.ts +176 -0
- package/dist/types/utils/index.d.ts +175 -0
- package/dist/types/utils/performance.d.ts +81 -0
- package/dist/types/utils/resource-manager.d.ts +53 -0
- package/dist/types/utils/types.d.ts +166 -0
- package/dist/types/utils/worker.d.ts +52 -0
- package/dist/types/version.d.ts +7 -0
- package/package.json +76 -77
- package/src/core/base-module.ts +78 -0
- package/src/core/camera-manager.ts +798 -0
- package/src/core/config.ts +268 -0
- package/src/core/errors.ts +174 -0
- package/src/core/event-emitter.ts +110 -0
- package/src/core/logger.ts +549 -0
- package/src/core/module-manager.ts +165 -0
- package/src/core/plugin-manager.ts +429 -0
- package/src/core/resource-manager.ts +762 -0
- package/src/core/result.ts +163 -0
- package/src/core/scanner-factory.ts +237 -0
- package/src/index.ts +113 -936
- package/src/interfaces/external-types.ts +200 -0
- package/src/interfaces/face-detection.ts +309 -0
- package/src/interfaces/scanner-module.ts +384 -0
- package/src/modules/face/face-detector.ts +931 -0
- package/src/modules/face/index.ts +208 -0
- package/src/modules/face/liveness-detector.ts +908 -0
- package/src/modules/face/types.ts +133 -0
- package/src/modules/id-card/anti-fake-detector.ts +732 -0
- package/src/modules/id-card/id-card-detector.ts +474 -0
- package/src/modules/id-card/index.ts +425 -0
- package/src/modules/id-card/ocr-processor.ts +538 -0
- package/src/modules/id-card/ocr-worker.ts +259 -0
- package/src/modules/id-card/types.ts +178 -0
- package/src/modules/qrcode/index.ts +175 -0
- package/src/modules/qrcode/qr-code-scanner.ts +230 -0
- package/src/modules/qrcode/types.ts +65 -0
- package/src/types/browser-image-compression.d.ts +19 -0
- package/src/types/tesseract.d.ts +280 -0
- package/src/utils/image-processing.ts +432 -49
- package/src/utils/index.ts +426 -0
- package/src/utils/performance.ts +168 -131
- package/src/utils/resource-manager.ts +65 -146
- package/src/utils/types.ts +90 -2
- package/src/utils/worker.ts +123 -84
- package/src/version.ts +11 -0
- package/tools/scaffold.js +543 -0
- package/dist/id-scanner-core.esm.js +0 -11076
- package/dist/id-scanner-core.esm.js.map +0 -1
- package/dist/id-scanner-core.js +0 -11088
- package/dist/id-scanner-core.js.map +0 -1
- package/dist/id-scanner-core.min.js +0 -1
- package/dist/id-scanner-core.min.js.map +0 -1
- package/dist/id-scanner-ocr.esm.js +0 -1802
- package/dist/id-scanner-ocr.esm.js.map +0 -1
- package/dist/id-scanner-ocr.js +0 -1811
- package/dist/id-scanner-ocr.js.map +0 -1
- package/dist/id-scanner-ocr.min.js +0 -1
- package/dist/id-scanner-ocr.min.js.map +0 -1
- package/dist/id-scanner-qr.esm.js +0 -1023
- package/dist/id-scanner-qr.esm.js.map +0 -1
- package/dist/id-scanner-qr.js +0 -1032
- package/dist/id-scanner-qr.js.map +0 -1
- package/dist/id-scanner-qr.min.js +0 -1
- package/dist/id-scanner-qr.min.js.map +0 -1
- package/dist/id-scanner.js +0 -3740
- package/dist/id-scanner.js.map +0 -1
- package/dist/id-scanner.min.js +0 -1
- package/dist/id-scanner.min.js.map +0 -1
- package/src/core.ts +0 -138
- package/src/demo/demo.ts +0 -204
- package/src/id-recognition/anti-fake-detector.ts +0 -317
- package/src/id-recognition/data-extractor.ts +0 -262
- package/src/id-recognition/id-detector.ts +0 -363
- package/src/id-recognition/ocr-processor.ts +0 -334
- package/src/id-recognition/ocr-worker.ts +0 -156
- package/src/index-umd.ts +0 -477
- package/src/ocr-module.ts +0 -187
- package/src/qr-module.ts +0 -179
- package/src/scanner/barcode-scanner.ts +0 -251
- package/src/scanner/qr-scanner.ts +0 -167
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 配置管理器
|
|
3
|
+
* @description 提供全局配置管理功能
|
|
4
|
+
* @module core/config
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 配置管理器
|
|
9
|
+
* 负责存储和管理应用程序的配置
|
|
10
|
+
*/
|
|
11
|
+
export class ConfigManager {
|
|
12
|
+
/** 单例实例 */
|
|
13
|
+
private static instance: ConfigManager;
|
|
14
|
+
|
|
15
|
+
/** 配置存储 */
|
|
16
|
+
private config: Record<string, any> = {};
|
|
17
|
+
|
|
18
|
+
/** 配置变更回调 */
|
|
19
|
+
private changeCallbacks: Map<string, Array<(value: any, oldValue: any) => void>> = new Map();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 私有构造函数
|
|
23
|
+
*/
|
|
24
|
+
private constructor() {
|
|
25
|
+
// 设置默认配置
|
|
26
|
+
this.config = {
|
|
27
|
+
debug: false,
|
|
28
|
+
logLevel: 'info',
|
|
29
|
+
camera: {
|
|
30
|
+
resolution: {
|
|
31
|
+
width: 1280,
|
|
32
|
+
height: 720
|
|
33
|
+
},
|
|
34
|
+
frameRate: 30,
|
|
35
|
+
facingMode: 'environment'
|
|
36
|
+
},
|
|
37
|
+
performance: {
|
|
38
|
+
useCache: true
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 获取单例实例
|
|
45
|
+
*/
|
|
46
|
+
public static getInstance(): ConfigManager {
|
|
47
|
+
if (!ConfigManager.instance) {
|
|
48
|
+
ConfigManager.instance = new ConfigManager();
|
|
49
|
+
}
|
|
50
|
+
return ConfigManager.instance;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 获取配置值
|
|
55
|
+
* @param key 配置键,支持点号分隔的路径
|
|
56
|
+
* @param defaultValue 默认值
|
|
57
|
+
*/
|
|
58
|
+
get<T = any>(key: string, defaultValue?: T): T {
|
|
59
|
+
const value = this.getNestedValue(this.config, key);
|
|
60
|
+
return (value !== undefined) ? value : (defaultValue as T);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 设置配置值
|
|
65
|
+
* @param key 配置键,支持点号分隔的路径
|
|
66
|
+
* @param value 配置值
|
|
67
|
+
*/
|
|
68
|
+
set<T = any>(key: string, value: T): void {
|
|
69
|
+
const oldValue = this.get(key);
|
|
70
|
+
|
|
71
|
+
// 如果值相同,不做任何事
|
|
72
|
+
if (oldValue === value) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.setNestedValue(this.config, key, value);
|
|
77
|
+
|
|
78
|
+
// 触发变更回调
|
|
79
|
+
this.triggerChangeCallbacks(key, value, oldValue);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 批量更新配置
|
|
84
|
+
* @param config 配置对象
|
|
85
|
+
*/
|
|
86
|
+
updateConfig(config: Record<string, any>): void {
|
|
87
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
88
|
+
this.set(key, value);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 重置为默认配置
|
|
94
|
+
*/
|
|
95
|
+
reset(): void {
|
|
96
|
+
const oldConfig = { ...this.config };
|
|
97
|
+
|
|
98
|
+
// 重新创建默认配置
|
|
99
|
+
this.config = {
|
|
100
|
+
debug: false,
|
|
101
|
+
logLevel: 'info',
|
|
102
|
+
camera: {
|
|
103
|
+
resolution: {
|
|
104
|
+
width: 1280,
|
|
105
|
+
height: 720
|
|
106
|
+
},
|
|
107
|
+
frameRate: 30,
|
|
108
|
+
facingMode: 'environment'
|
|
109
|
+
},
|
|
110
|
+
performance: {
|
|
111
|
+
useCache: true
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// 触发所有回调
|
|
116
|
+
Object.keys(oldConfig).forEach(key => {
|
|
117
|
+
this.triggerChangeCallbacks(key, this.get(key), oldConfig[key]);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 注册配置变更回调
|
|
123
|
+
* @param key 配置键
|
|
124
|
+
* @param callback 回调函数
|
|
125
|
+
*/
|
|
126
|
+
onConfigChange<T = any>(key: string, callback: (value: T, oldValue: T) => void): void {
|
|
127
|
+
if (!this.changeCallbacks.has(key)) {
|
|
128
|
+
this.changeCallbacks.set(key, []);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.changeCallbacks.get(key)!.push(callback);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 移除配置变更回调
|
|
136
|
+
* @param key 配置键
|
|
137
|
+
* @param callback 特定回调函数,如不提供则移除所有
|
|
138
|
+
*/
|
|
139
|
+
offConfigChange<T = any>(key: string, callback?: (value: T, oldValue: T) => void): void {
|
|
140
|
+
if (!this.changeCallbacks.has(key)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (callback) {
|
|
145
|
+
// 移除特定回调
|
|
146
|
+
const callbacks = this.changeCallbacks.get(key)!;
|
|
147
|
+
const index = callbacks.indexOf(callback as any);
|
|
148
|
+
if (index !== -1) {
|
|
149
|
+
callbacks.splice(index, 1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 如果没有回调,删除键
|
|
153
|
+
if (callbacks.length === 0) {
|
|
154
|
+
this.changeCallbacks.delete(key);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
// 移除所有回调
|
|
158
|
+
this.changeCallbacks.delete(key);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 获取嵌套值
|
|
164
|
+
* @param obj 对象
|
|
165
|
+
* @param path 路径
|
|
166
|
+
*/
|
|
167
|
+
private getNestedValue(obj: Record<string, any>, path: string): any {
|
|
168
|
+
// 处理根路径
|
|
169
|
+
if (!path) {
|
|
170
|
+
return obj;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 处理嵌套路径
|
|
174
|
+
const parts = path.split('.');
|
|
175
|
+
let current = obj;
|
|
176
|
+
|
|
177
|
+
for (const part of parts) {
|
|
178
|
+
if (current === undefined || current === null) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
current = current[part];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return current;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 设置嵌套值
|
|
190
|
+
* @param obj 对象
|
|
191
|
+
* @param path 路径
|
|
192
|
+
* @param value 值
|
|
193
|
+
*/
|
|
194
|
+
private setNestedValue(obj: Record<string, any>, path: string, value: any): void {
|
|
195
|
+
// 处理根路径
|
|
196
|
+
if (!path) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 处理嵌套路径
|
|
201
|
+
const parts = path.split('.');
|
|
202
|
+
let current = obj;
|
|
203
|
+
|
|
204
|
+
// 遍历路径,直到倒数第二部分
|
|
205
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
206
|
+
const part = parts[i];
|
|
207
|
+
|
|
208
|
+
// 如果不存在,创建新对象
|
|
209
|
+
if (current[part] === undefined || current[part] === null || typeof current[part] !== 'object') {
|
|
210
|
+
current[part] = {};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
current = current[part];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 设置最终值
|
|
217
|
+
current[parts[parts.length - 1]] = value;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 触发变更回调
|
|
222
|
+
* @param key 配置键
|
|
223
|
+
* @param value 新值
|
|
224
|
+
* @param oldValue 旧值
|
|
225
|
+
*/
|
|
226
|
+
private triggerChangeCallbacks(key: string, value: any, oldValue: any): void {
|
|
227
|
+
// 触发特定键的回调
|
|
228
|
+
if (this.changeCallbacks.has(key)) {
|
|
229
|
+
const callbacks = this.changeCallbacks.get(key)!;
|
|
230
|
+
callbacks.forEach(callback => {
|
|
231
|
+
try {
|
|
232
|
+
callback(value, oldValue);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error(`Error in config change callback for key ${key}:`, error);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// 触发父路径的回调
|
|
240
|
+
const parts = key.split('.');
|
|
241
|
+
while (parts.length > 1) {
|
|
242
|
+
parts.pop();
|
|
243
|
+
const parentKey = parts.join('.');
|
|
244
|
+
|
|
245
|
+
if (this.changeCallbacks.has(parentKey)) {
|
|
246
|
+
const parentValue = this.get(parentKey);
|
|
247
|
+
this.changeCallbacks.get(parentKey)!.forEach(callback => {
|
|
248
|
+
try {
|
|
249
|
+
callback(parentValue, parentValue);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
console.error(`Error in config change callback for parent key ${parentKey}:`, error);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* 模块配置接口
|
|
261
|
+
* 定义所有模块共享的基础配置属性
|
|
262
|
+
*/
|
|
263
|
+
export interface ModuleConfig {
|
|
264
|
+
/** 是否启用该模块 */
|
|
265
|
+
enabled: boolean;
|
|
266
|
+
/** 其他模块特定配置 */
|
|
267
|
+
[key: string]: any;
|
|
268
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 错误处理模块
|
|
3
|
+
* @description 定义ID-Scanner-Lib的错误类层次结构
|
|
4
|
+
* @module core/errors
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ID-Scanner-Lib 基础错误类
|
|
9
|
+
* 所有库特定错误的基类
|
|
10
|
+
*/
|
|
11
|
+
export class IDScannerError extends Error {
|
|
12
|
+
/** 错误代码 */
|
|
13
|
+
public code: string;
|
|
14
|
+
/** 错误原因 */
|
|
15
|
+
public cause?: Error;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 构造函数
|
|
19
|
+
* @param message 错误消息
|
|
20
|
+
* @param options 错误选项
|
|
21
|
+
*/
|
|
22
|
+
constructor(message: string, options?: { code?: string; cause?: Error }) {
|
|
23
|
+
super(message);
|
|
24
|
+
|
|
25
|
+
// 设置错误名称
|
|
26
|
+
this.name = this.constructor.name;
|
|
27
|
+
|
|
28
|
+
// 设置错误代码
|
|
29
|
+
this.code = options?.code || 'UNKNOWN_ERROR';
|
|
30
|
+
|
|
31
|
+
// 设置错误原因
|
|
32
|
+
this.cause = options?.cause;
|
|
33
|
+
|
|
34
|
+
// 捕获堆栈
|
|
35
|
+
if (Error.captureStackTrace) {
|
|
36
|
+
Error.captureStackTrace(this, this.constructor);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 初始化错误
|
|
43
|
+
* 当库初始化失败时抛出
|
|
44
|
+
*/
|
|
45
|
+
export class InitializationError extends IDScannerError {
|
|
46
|
+
constructor(message: string, details?: string) {
|
|
47
|
+
super(`初始化失败: ${message}${details ? ` (${details})` : ''}`, { code: 'INIT_FAILED' });
|
|
48
|
+
this.name = 'InitializationError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 设备错误
|
|
54
|
+
* 当访问硬件设备(如摄像头)失败时抛出
|
|
55
|
+
*/
|
|
56
|
+
export class DeviceError extends IDScannerError {
|
|
57
|
+
constructor(message: string) {
|
|
58
|
+
super(`设备错误: ${message}`, { code: 'DEVICE_ERROR' });
|
|
59
|
+
this.name = 'DeviceError';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 摄像头访问错误
|
|
65
|
+
* 当无法访问或启动摄像头时抛出
|
|
66
|
+
*/
|
|
67
|
+
export class CameraAccessError extends IDScannerError {
|
|
68
|
+
constructor(message: string, options?: { code?: string; cause?: Error }) {
|
|
69
|
+
super(`摄像头访问失败: ${message}`, {
|
|
70
|
+
code: options?.code || 'CAMERA_ACCESS_FAILED',
|
|
71
|
+
cause: options?.cause
|
|
72
|
+
});
|
|
73
|
+
this.name = 'CameraAccessError';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 人脸检测错误
|
|
79
|
+
* 当人脸检测过程失败时抛出
|
|
80
|
+
*/
|
|
81
|
+
export class FaceDetectionError extends IDScannerError {
|
|
82
|
+
constructor(message: string) {
|
|
83
|
+
super(`人脸检测失败: ${message}`, { code: 'FACE_DETECTION_FAILED' });
|
|
84
|
+
this.name = 'FaceDetectionError';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 人脸比对错误
|
|
90
|
+
* 当人脸比对过程失败时抛出
|
|
91
|
+
*/
|
|
92
|
+
export class FaceComparisonError extends IDScannerError {
|
|
93
|
+
constructor(message: string) {
|
|
94
|
+
super(`人脸比对失败: ${message}`, { code: 'FACE_COMPARISON_FAILED' });
|
|
95
|
+
this.name = 'FaceComparisonError';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 活体检测错误
|
|
101
|
+
* 当活体检测过程失败时抛出
|
|
102
|
+
*/
|
|
103
|
+
export class LivenessDetectionError extends IDScannerError {
|
|
104
|
+
constructor(message: string) {
|
|
105
|
+
super(`活体检测失败: ${message}`, { code: 'LIVENESS_DETECTION_FAILED' });
|
|
106
|
+
this.name = 'LivenessDetectionError';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* OCR识别错误
|
|
112
|
+
* 当OCR文字识别失败时抛出
|
|
113
|
+
*/
|
|
114
|
+
export class OCRProcessingError extends IDScannerError {
|
|
115
|
+
constructor(message: string) {
|
|
116
|
+
super(`OCR处理失败: ${message}`, { code: 'OCR_PROCESSING_FAILED' });
|
|
117
|
+
this.name = 'OCRProcessingError';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 二维码扫描错误
|
|
123
|
+
* 当二维码扫描失败时抛出
|
|
124
|
+
*/
|
|
125
|
+
export class QRScanError extends IDScannerError {
|
|
126
|
+
constructor(message: string) {
|
|
127
|
+
super(`二维码扫描失败: ${message}`, { code: 'QR_SCAN_FAILED' });
|
|
128
|
+
this.name = 'QRScanError';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 身份证检测错误
|
|
134
|
+
* 当身份证检测失败时抛出
|
|
135
|
+
*/
|
|
136
|
+
export class IDCardDetectionError extends IDScannerError {
|
|
137
|
+
constructor(message: string) {
|
|
138
|
+
super(`身份证检测失败: ${message}`, { code: 'ID_CARD_DETECTION_FAILED' });
|
|
139
|
+
this.name = 'IDCardDetectionError';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 资源加载错误
|
|
145
|
+
* 当无法加载必要资源(如模型)时抛出
|
|
146
|
+
*/
|
|
147
|
+
export class ResourceLoadError extends IDScannerError {
|
|
148
|
+
constructor(resource: string, reason: string) {
|
|
149
|
+
super(`无法加载资源 ${resource}: ${reason}`, { code: 'RESOURCE_LOAD_FAILED' });
|
|
150
|
+
this.name = 'ResourceLoadError';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 参数错误
|
|
156
|
+
* 当提供的参数无效时抛出
|
|
157
|
+
*/
|
|
158
|
+
export class InvalidArgumentError extends IDScannerError {
|
|
159
|
+
constructor(paramName: string, reason: string) {
|
|
160
|
+
super(`无效的参数 ${paramName}: ${reason}`, { code: 'INVALID_ARGUMENT' });
|
|
161
|
+
this.name = 'InvalidArgumentError';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 不支持错误
|
|
167
|
+
* 当尝试使用不支持的功能或当前环境无法使用的功能时抛出
|
|
168
|
+
*/
|
|
169
|
+
export class NotSupportedError extends IDScannerError {
|
|
170
|
+
constructor(feature: string) {
|
|
171
|
+
super(`不支持的功能: ${feature}`, { code: 'NOT_SUPPORTED' });
|
|
172
|
+
this.name = 'NotSupportedError';
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 事件发射器
|
|
3
|
+
* @description 提供基础的事件发射和订阅功能
|
|
4
|
+
* @module core/event-emitter
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 事件处理器类型
|
|
9
|
+
*/
|
|
10
|
+
type EventHandler = (data?: any) => void;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 事件发射器基类
|
|
14
|
+
* 提供基础的事件发射和订阅功能
|
|
15
|
+
*/
|
|
16
|
+
export class EventEmitter {
|
|
17
|
+
/** 事件处理器映射 */
|
|
18
|
+
private eventHandlers: Map<string, Set<EventHandler>> = new Map();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 订阅事件
|
|
22
|
+
* @param eventName 事件名称
|
|
23
|
+
* @param handler 事件处理器
|
|
24
|
+
*/
|
|
25
|
+
on(eventName: string, handler: EventHandler): void {
|
|
26
|
+
if (!this.eventHandlers.has(eventName)) {
|
|
27
|
+
this.eventHandlers.set(eventName, new Set());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.eventHandlers.get(eventName)!.add(handler);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 取消订阅事件
|
|
35
|
+
* @param eventName 事件名称
|
|
36
|
+
* @param handler 事件处理器,如果不提供则移除该事件的所有处理器
|
|
37
|
+
*/
|
|
38
|
+
off(eventName: string, handler?: EventHandler): void {
|
|
39
|
+
if (!this.eventHandlers.has(eventName)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (handler) {
|
|
44
|
+
this.eventHandlers.get(eventName)!.delete(handler);
|
|
45
|
+
|
|
46
|
+
// 如果没有处理器了,删除这个事件
|
|
47
|
+
if (this.eventHandlers.get(eventName)!.size === 0) {
|
|
48
|
+
this.eventHandlers.delete(eventName);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
// 移除该事件的所有处理器
|
|
52
|
+
this.eventHandlers.delete(eventName);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 订阅事件,但只触发一次
|
|
58
|
+
* @param eventName 事件名称
|
|
59
|
+
* @param handler 事件处理器
|
|
60
|
+
*/
|
|
61
|
+
once(eventName: string, handler: EventHandler): void {
|
|
62
|
+
const onceHandler = (data?: any) => {
|
|
63
|
+
handler(data);
|
|
64
|
+
this.off(eventName, onceHandler);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
this.on(eventName, onceHandler);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 发射事件
|
|
72
|
+
* @param eventName 事件名称
|
|
73
|
+
* @param data 事件数据
|
|
74
|
+
*/
|
|
75
|
+
emit(eventName: string, data?: any): void {
|
|
76
|
+
if (!this.eventHandlers.has(eventName)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const handler of this.eventHandlers.get(eventName)!) {
|
|
81
|
+
try {
|
|
82
|
+
handler(data);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error(`Error in event handler for "${eventName}":`, error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 获取某个事件的处理器数量
|
|
91
|
+
* @param eventName 事件名称
|
|
92
|
+
*/
|
|
93
|
+
listenerCount(eventName: string): number {
|
|
94
|
+
return this.eventHandlers.has(eventName) ? this.eventHandlers.get(eventName)!.size : 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 移除所有事件处理器
|
|
99
|
+
*/
|
|
100
|
+
removeAllListeners(): void {
|
|
101
|
+
this.eventHandlers.clear();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 获取所有事件名称
|
|
106
|
+
*/
|
|
107
|
+
eventNames(): string[] {
|
|
108
|
+
return Array.from(this.eventHandlers.keys());
|
|
109
|
+
}
|
|
110
|
+
}
|