Refactor and enhance form recognition, mapping, and UI components (#18)

* 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运行时间和资源消耗

* refactor(qrcode): 重构二维码解析功能并提取为独立模块

* style(页面样式): 统一页面头部图标颜色并优化表单样式

更新各页面头部组件的图标颜色配置,移除冗余的表单标签属性,优化输入框样式和按钮悬停效果

* feat(formMapping): 添加表单映射功能

- 创建 FormMappingPage 页面组件
- 实现表单扫描器 scanner.ts
- 实现高亮器 highlighter.ts
- 更新路由配置 routes.ts
- 更新内容脚本 content.ts
- 更新类型定义 storage.d.ts
- 添加 formMappingPageStyles 样式配置

* feat(表单映射): 添加配置导出功能及状态提示

添加配置导出为JSON文件的功能,包含导出按钮和错误处理。新增Snackbar组件用于显示导出成功和错误状态。优化页面布局结构,将状态提示移至全局容器外。

* feat(表单填充): 新增智能表单填充功能

添加智能表单填充功能,包括:
1. 新增表单填充页面和路由配置
2. 实现模糊匹配引擎和智能注入引擎
3. 添加Mock数据生成器和视觉反馈渲染器
4. 扩展消息接口支持填充操作

* ci: 精简触发CI的工作流分支

移除对develop分支及其变体的触发,仅保留main分支的触发

* test: 更新路由测试以匹配新增的路由数量

* test: 将测试文件中的描述和断言翻译为中文

* test(PageHeader): 添加组件测试用例验证渲染逻辑和样式

* refactor(theme): 重构主题样式并优化仪表盘卡片组件

将页面样式配置集中管理,移除各页面中硬编码的背景色
新增 DashboardCard 组件封装通用卡片逻辑
添加 dashboardCards 配置文件统一管理卡片数据

* refactor(Button): 统一按钮样式并移除重复样式定义

将按钮样式统一封装到 Button 组件中,移除各页面重复的样式定义
更新组件文档说明,提供更清晰的用法示例

* docs: 更新 README 文件中的目录结构说明

添加新组件和配置文件的说明,保持文档与代码同步

* refactor: 优化代码类型声明和UI布局

修复类型声明从any改为never以提高类型安全性
调整TimestampPage页面布局间距
移除DashboardPage中不必要的实时时钟状态
更新ESLint配置以使用推荐配置
添加选项页面打开的错误处理

* refactor(消息通信): 使用 @webext-core/messaging 重构消息处理逻辑

将原有的 chrome.runtime.onMessage 和 chrome.tabs.sendMessage 替换为类型安全的 @webext-core/messaging 实现
添加 ProtocolMap 类型定义确保消息类型安全
更新相关页面和后台脚本使用新的消息通信方式

* fix: 修复依赖项缺失导致的潜在问题

修复 useStorageState 中缺少 defaultValue 依赖的问题
重构 RouterProvider 的初始化逻辑,使用 useCallback 优化性能

* refactor: 重构表单识别和消息处理逻辑

将表单映射UI逻辑提取到独立文件
将消息处理器提取到独立文件
将表单识别页面逻辑提取到自定义hook
优化代码结构和可维护性

* feat(侧边栏): 添加侧边栏状态变化通知功能

- 在消息类型中新增侧边栏状态变化枚举和字段
- 侧边栏打开和关闭时发送状态通知
- 替换轮询检查方式为消息监听机制

* refactor: 优化高亮组件渲染逻辑并添加防抖处理

重构高亮组件渲染逻辑,使用 requestAnimationFrame 进行节流优化
在 useStorageCleaner 中添加防抖处理以避免频繁加载

* refactor: 统一组件导出方式为默认导出

* refactor: 重构样式系统并迁移至 MUI 主题

删除冗余的 CSS 文件,统一使用 MUI 主题管理样式
新增 useActiveTabDomain 和 useSidePanelState 自定义 Hook
优化各入口点的主题集成和布局处理

* docs: 更新项目文档以反映新增功能和技术栈细节

更新 AGENTS.md 文档,详细描述新增的功能模块(存储管理、URL 管理、二维码生成、表单工具套件等)和更新的技术栈信息

* feat: 添加错误边界组件以捕获子组件错误

在 popup、sidepanel 和 options 入口点添加 ErrorBoundary 组件,用于捕获并处理子组件中的 JavaScript 错误。当错误发生时,显示友好的错误界面并提供刷新功能。

* refactor(ui): 使用全局 snackbar 替换本地通知组件

重构表单页面中的通知系统,移除本地 Snackbar 和 Alert 组件,改用全局 GlobalSnackbar 组件统一管理通知
标准化主题配置中的 CSS 属性命名,移除带前缀的样式属性

* refactor(snackbar): 重构全局消息提示为 SnackbarProvider 组件

将原本分散在各页面的 GlobalSnackbar 组件重构为集中管理的 SnackbarProvider,通过 Context 提供统一的消息提示功能。主要变更包括:

1. 创建新的 SnackbarProvider 组件作为全局消息提示容器
2. 提供 useSnackbar hook 供子组件调用
3. 移除各页面中独立的 GlobalSnackbar 实例
4. 在 App 根组件中统一集成 SnackbarProvider
5. 优化消息提示样式和交互行为

* refactor(Snackbar): 重构消息提示组件并优化样式

重构 Snackbar 组件,将状态管理逻辑提取到 GlobalSnackbar 中复用
优化消息提示样式,调整阴影效果和最小尺寸
统一各页面使用 Snackbar 的方式,移除冗余配置

* refactor: 重构路由和功能配置系统

- 将路由配置和仪表盘卡片配置合并为统一的 features 配置
- 重构 RouterProvider 增加数据校验和本地快照功能
- 优化表单字段识别和填充逻辑,提取公共方法
- 更新相关组件和文档以适配新的配置系统
- 删除废弃的 dashboardCards 和 routes 配置文件
This commit is contained in:
LingandRX
2026-05-01 18:00:06 +08:00
committed by GitHub
parent 60537f6e2e
commit 8d36f21f1b
64 changed files with 2901 additions and 2197 deletions
+200 -16
View File
@@ -1,47 +1,110 @@
import { useState } from 'react';
/**
* GlobalSnackbar - 全局 Snackbar 消息提示组件
*
* 提供可复用的 Toast 消息提示功能,支持两种使用方式:
* 1. 作为受控组件使用:通过 props 控制显示状态
* 2. 通过 useSnackbarState Hook 使用:自动管理状态
*
* @module GlobalSnackbar
* @version 1.0.0
*
* @example
* ```tsx
* // 方式一:受控组件
* <GlobalSnackbar
* message="操作成功"
* open={isOpen}
* onClose={() => setIsOpen(false)}
* severity="success"
* />
*
* // 方式二:Hook 方式
* const { snackbarProps, showMessage } = useSnackbarState();
* showMessage('Hello!', { severity: 'info' });
* ```
*/
import React, { JSX, useState } from 'react';
import { Snackbar, Alert, type SxProps, type Theme, alpha, Portal } from '@mui/material';
/**
* Snackbar 消息严重程度类型
* @description 决定 Alert 组件的颜色和图标
* - success: 绿色,成功提示
* - info: 蓝色,信息提示
* - warning: 橙色,警告提示
* - error: 红色,错误提示
*/
export type SnackbarSeverity = 'success' | 'info' | 'warning' | 'error';
/**
* 重新导出 SnackbarProvider 组件
* @description 提供 Context 方式的全局 Snackbar 功能
*/
export { SnackbarProvider } from './SnackbarProvider';
/**
* GlobalSnackbar 组件的属性接口
* @interface GlobalSnackbarProps
*/
export interface GlobalSnackbarProps {
/** 消息内容 */
/** 消息内容,要显示的提示文本 */
message: string;
/** 是否显示 */
/** 是否显示 Snackbar */
open: boolean;
/** 关闭回调 */
/** 关闭回调函数 */
onClose: () => void;
/** 消息级别影响颜色 */
/** 消息级别影响颜色和图标样式,默认 'info' */
severity?: SnackbarSeverity;
/** 自动隐藏时间毫秒0 不自动关闭 */
/** 自动隐藏时间毫秒),设为 0 不自动关闭,默认 2000 */
autoHideDuration?: number;
/** 弹出位置 */
/** Snackbar 弹出位置,默认 { vertical: 'bottom', horizontal: 'center' } */
anchorOrigin?: {
vertical: 'top' | 'bottom';
horizontal: 'left' | 'center' | 'right';
};
/** 是否使用 Alert 包裹false 则使用原生 Snackbar message */
/** 是否使用 Alert 组件包裹false 则使用原生 Snackbar message,默认 true */
showAlert?: boolean;
/** Alert 是否隐藏图标 */
/** 是否隐藏 Alert 图标,默认 false */
hideIcon?: boolean;
/** 自定义样式,透传给 Snackbar */
/** 自定义样式,透传给外层 Snackbar 组件 */
sx?: SxProps<Theme>;
/** 自定义样式,透传给 Alert(仅 showAlert=true 时生效) */
/** 自定义样式,透传给内层 Alert 组件(仅 showAlert=true 时生效) */
alertSx?: SxProps<Theme>;
}
/**
* showMessage 方法的选项配置
* @interface SnackbarOptions
*/
export interface SnackbarOptions {
/** 消息级别:success | info | warning | error */
severity?: SnackbarSeverity;
/** 自动隐藏时间(毫秒),设为 0 则不自动关闭 */
autoHideDuration?: number;
/** 是否隐藏 Alert 图标 */
hideIcon?: boolean;
/** 是否使用 Alert 组件包裹 */
showAlert?: boolean;
}
export interface UseSnackbarResult {
/**
* useSnackbarState Hook 的返回值类型
* @interface UseSnackbarStateResult
*/
export interface UseSnackbarStateResult {
/** 传递给 GlobalSnackbar 组件的属性对象 */
snackbarProps: GlobalSnackbarProps;
/** 显示消息的方法 */
showMessage: (message: string, options?: SnackbarOptions) => void;
/** 关闭消息的方法 */
closeMessage: () => void;
}
/**
* GlobalSnackbar 组件的默认属性配置
* @description 提供类型安全的默认值选择
*/
const defaultProps: Required<
Pick<
GlobalSnackbarProps,
@@ -55,6 +118,32 @@ const defaultProps: Required<
hideIcon: false,
};
/**
* GlobalSnackbar 组件
*
* 全局消息提示的展示组件,支持受控和非受控两种使用模式。
* 使用 MUI Snackbar 和 Alert 组件实现消息提示功能。
*
* @param {GlobalSnackbarProps} props - 组件属性
* @returns {JSX.Element}
*
* @remarks
* - 使用 Portal 组件将 Snackbar 渲染到 body 末尾,避免 z-index 问题
* - 默认位置在屏幕底部居中
* - 自动设置高 z-index 确保显示在其他内容之上
*
* @example
* ```tsx
* // 受控模式
* const [open, setOpen] = useState(false);
* <GlobalSnackbar
* message="保存成功"
* open={open}
* onClose={() => setOpen(false)}
* severity="success"
* />
* ```
*/
export function GlobalSnackbar({
message,
open,
@@ -63,8 +152,16 @@ export function GlobalSnackbar({
autoHideDuration = defaultProps.autoHideDuration,
showAlert = defaultProps.showAlert,
hideIcon = defaultProps.hideIcon,
}: GlobalSnackbarProps) {
// 使用 Portal 将 Snackbar 传送到 DOM 顶层 (body 标签下)
}: GlobalSnackbarProps): JSX.Element {
/**
* 使用 Portal 将 Snackbar 传送到 DOM 顶层 (body 标签下)
*
* @description
* Portal 的优势:
* - 避免父容器 overflow、z-index 等样式影响
* - 确保 Snackbar 始终显示在最顶层
* - 避免与其他组件的样式冲突
*/
return (
<Portal>
<Snackbar
@@ -75,8 +172,12 @@ export function GlobalSnackbar({
disableWindowBlurListener
sx={{
zIndex: 999999,
// 确保距离底部的间距
// 确保距离底部的间距,响应式设计适配不同屏幕
bottom: { xs: '24px', sm: '24px' },
// 固定宽度时使用 transform 实现真正的居中
left: '50%',
transform: 'translateX(-50%)',
minWidth: '140px',
}}
>
{showAlert ? (
@@ -85,19 +186,26 @@ export function GlobalSnackbar({
variant="filled"
icon={hideIcon ? false : undefined}
sx={{
// 胶囊形状,现代化的设计风格
borderRadius: '50px',
px: 2.5,
py: 0.2,
minWidth: '140px',
// 居中内容
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
// 粗体小字
fontWeight: 800,
fontSize: '0.75rem',
// 移除默认渐变背景
backgroundImage: 'none',
// 添加阴影效果,颜色根据 severity 自动匹配主题色
boxShadow: (theme: Theme) =>
`0 12px 32px ${alpha(theme.palette[severity].main, 0.35)}`,
// 图标样式:白色、稍大
'& .MuiAlert-icon': { mr: 0.5, fontSize: '1.1rem', color: '#fff' },
// 消息文字样式:白色、适当内边距
'& .MuiAlert-message': { color: '#fff', padding: '6px 0' },
}}
>
@@ -109,26 +217,98 @@ export function GlobalSnackbar({
);
}
export function useSnackbar(initialOptions?: SnackbarOptions): UseSnackbarResult {
/**
* useSnackbarState - 消息提示的 Hook 方式
*
* 提供状态管理的 Snackbar 功能,自动处理 open、message 等状态。
* 适合在组件内部使用,无需额外的状态管理代码。
*
* @param {SnackbarOptions} [initialOptions] - 初始配置选项
* @returns {UseSnackbarStateResult} 包含 snackbarProps 和操作方法的对象
*
* @description
* - 自动管理 Snackbar 的显示/隐藏状态
* - 支持链式调用 showMessage
* - 合并初始选项和调用时选项
*
* @example
* ```tsx
* function MyComponent() {
* const { snackbarProps, showMessage, closeMessage } = useSnackbarState({
* severity: 'info',
* autoHideDuration: 3000,
* });
*
* const handleSave = () => {
* // 业务逻辑...
* showMessage('保存成功!', { severity: 'success' });
* };
*
* return (
* <>
* <button onClick={handleSave}>保存</button>
* <GlobalSnackbar {...snackbarProps} />
* </>
* );
* }
* ```
*/
export function useSnackbarState(initialOptions?: SnackbarOptions): UseSnackbarStateResult {
// Snackbar 显示状态
const [open, setOpen] = useState(false);
// 当前显示的消息内容
const [message, setMessage] = useState('');
// 消息配置选项
const [options, setOptions] = useState<SnackbarOptions>(initialOptions || {});
/**
* 显示消息
*
* @param {string} newMessage - 要显示的消息文本
* @param {SnackbarOptions} [newOptions={}] - 新的配置选项
*
* @description
* - 合并初始选项和新的调用选项
* - 新选项会覆盖初始选项
*/
const showMessage = (newMessage: string, newOptions: SnackbarOptions = {}) => {
setMessage(newMessage);
setOptions({ ...initialOptions, ...newOptions });
setOpen(true);
};
/**
* 关闭消息
*
* @description
* - 直接将 open 状态设置为 false
*/
const closeMessage = () => {
setOpen(false);
};
/**
* 处理 Snackbar 关闭事件
*
* @param {React.SyntheticEvent | Event} [_event] - 关闭事件
* @param {string} [reason] - 关闭原因:timeout | clickaway | escapeKeyDown
*
* @description
* - 忽略 clickaway 原因(用户点击其他区域),防止误关闭
* - 其他情况调用 closeMessage 关闭
*/
const handleClose = (_event?: React.SyntheticEvent | Event, reason?: string) => {
if (reason === 'clickaway') return;
closeMessage();
};
/**
* 传递给 GlobalSnackbar 组件的属性
*
* @description
* - 组合当前状态和选项为完整的组件 props
* - onClose 使用 handleClose 包装后的版本
*/
const snackbarProps: GlobalSnackbarProps = {
message,
open,
@@ -145,4 +325,8 @@ export function useSnackbar(initialOptions?: SnackbarOptions): UseSnackbarResult
};
}
/**
* GlobalSnackbar 组件的默认导出
* @description 方便使用 `import GlobalSnackbar from './GlobalSnackbar'` 方式导入
*/
export default GlobalSnackbar;