* docs: 添加组件文档注释和类型导入

refactor: 统一使用 SnackbarOptions 类型
style: 优化导入语句顺序和格式

* refactor: 简化假数据生成器中的faker导入和使用

Co-authored-by: Copilot <copilot@github.com>

* feat(form-recognizer): 增强表单识别功能并优化UI交互

- 新增字段类型偏好设置功能,支持按域名保存字段类型
- 重构FieldList组件,改进字段选择和类型修改体验
- 添加字段定位闪烁功能,便于在页面上快速找到对应字段
- 优化表单填充逻辑,支持单个字段覆盖默认填充模式
- 移除独立的侧边栏页面,统一使用主页面组件
- 改进useStorageState钩子,增加加载状态管理和防抖处理

* refactor: 移除未使用的组件文件

* refactor(页面头部): 提取通用 PageHeader 组件并替换各页面头部实现

重构各页面头部为统一的 PageHeader 组件,提高代码复用性和维护性

* style(组件): 调整自动刷新开关和存储选项网格的样式

优化自动刷新开关的文本内边距,重构存储选项网格的布局结构,调整间距和边框样式

* style(ui): 调整时间戳页面和结果视图的样式

- 为时区选择器添加圆角
- 优化结果视图的布局和对齐方式
- 调整结果项的内边距和文本样式

* ci(workflow): 移除Firefox测试以简化CI流程

仅保留Chrome浏览器的构建步骤,减少CI运行时间和资源消耗
This commit is contained in:
LingandRX
2026-04-28 08:56:47 +08:00
committed by GitHub
parent fb5f98dd3b
commit c039475119
29 changed files with 908 additions and 1317 deletions
+57 -16
View File
@@ -1,4 +1,4 @@
import { faker, fakerZH_CN } from '@faker-js/faker';
import { fakerZH_CN as faker } from '@faker-js/faker';
/**
* 表单字段信息接口
@@ -34,7 +34,7 @@ export class DummyDataGenerator {
* 生成随机中文姓名
*/
static generateChineseName(): string {
return fakerZH_CN.person.fullName();
return faker.person.fullName();
}
/**
@@ -45,17 +45,20 @@ export class DummyDataGenerator {
}
/**
* 生成随机手机号
* 生成随机手机号(中国格式)
*/
static generatePhoneNumber(): string {
return fakerZH_CN.phone.number();
const prefix =
'1' + faker.string.numeric({ length: 1, allowLeadingZeros: false, exclude: ['0', '1', '2'] });
const suffix = faker.string.numeric({ length: 9, allowLeadingZeros: true });
return prefix + suffix;
}
/**
* 生成有效邮箱
*/
static generateValidEmail(): string {
return fakerZH_CN.internet.email();
return faker.internet.email();
}
/**
@@ -77,14 +80,14 @@ export class DummyDataGenerator {
* 生成短文本
*/
static generateShortText(): string {
return fakerZH_CN.lorem.sentence({ min: 3, max: 6 });
return faker.lorem.sentence({ min: 3, max: 6 });
}
/**
* 生成长文本
*/
static generateLongText(): string {
return fakerZH_CN.lorem.paragraphs(5);
return faker.lorem.paragraphs(5);
}
/**
@@ -106,42 +109,42 @@ export class DummyDataGenerator {
* 生成随机数字
*/
static generateNumber(): number {
return fakerZH_CN.number.int(10000);
return faker.number.int(10000);
}
/**
* 生成随机浮点数
*/
static generateFloat(): number {
return fakerZH_CN.number.float({ max: 10000 });
return faker.number.float({ max: 10000 });
}
/**
* 生成随机负数
*/
static generateNegativeNumber(): number {
return -fakerZH_CN.number.int(10000);
return -faker.number.int(10000);
}
/**
* 生成随机日期
*/
static generateDate(): string {
return fakerZH_CN.date.recent({ days: 365 }).toISOString().split('T')[0];
return faker.date.recent({ days: 365 }).toISOString().split('T')[0];
}
/**
* 生成过去的日期
*/
static generatePastDate(): string {
return fakerZH_CN.date.past({ years: 1 }).toISOString().split('T')[0];
return faker.date.past({ years: 1 }).toISOString().split('T')[0];
}
/**
* 生成未来的日期
*/
static generateFutureDate(): string {
return fakerZH_CN.date.future({ years: 1 }).toISOString().split('T')[0];
return faker.date.future({ years: 1 }).toISOString().split('T')[0];
}
/**
@@ -779,14 +782,23 @@ export function fillFieldWithInjector(
}
/**
* 批量填充选中的字段
* 批量填充选中的字段(支持单字段模式覆盖)
*/
export function fillSelectedFields(fields: FormFieldInfo[], mode: FillMode): number {
export function fillSelectedFields(
fields: Array<FormFieldInfo & { useInvalidData?: boolean }>,
defaultMode: FillMode,
): number {
let filledCount = 0;
fields.forEach((field) => {
if (field.isSelected) {
const value = field.generatedValue || generateValueByFieldType(field.fieldType, mode);
const mode = field.useInvalidData
? FillMode.INVALID
: field.useInvalidData === false
? FillMode.VALID
: defaultMode;
// 始终根据当前 fieldType 重新生成值,确保类型变更生效
const value = generateValueByFieldType(field.fieldType, mode);
fillFieldWithInjector(field.element, value);
filledCount++;
}
@@ -795,6 +807,35 @@ export function fillSelectedFields(fields: FormFieldInfo[], mode: FillMode): num
return filledCount;
}
/**
* 闪烁字段(用于定位)
*/
export function flashField(element: HTMLElement): void {
let flashCount = 0;
const maxFlashes = 4;
const originalStyle =
element.getAttribute('data-original-style') || element.getAttribute('style') || '';
element.setAttribute('data-original-style', originalStyle);
const flash = () => {
if (flashCount >= maxFlashes) {
unhighlightField(element);
return;
}
if (flashCount % 2 === 0) {
element.style.outline = '3px solid #4caf50';
element.style.outlineOffset = '2px';
element.style.transition = 'outline 0.3s ease-in-out';
} else {
element.style.outline = '';
}
flashCount++;
setTimeout(flash, 300);
};
flash();
}
/**
* 高亮指定字段
*/