# 自定义页面组件技术规范 ## 概述 本文档定义了DrPlayer中用于渲染T4 Action交互功能的自定义页面组件技术规范。这些组件将根据后端返回的Action JSON配置动态生成相应的UI界面,实现灵活的用户交互体验。 ## 架构设计 ### 1. 组件层次结构 ``` ActionRenderer (主渲染器) ├── ActionDialog (弹窗容器) │ ├── InputAction (单项输入组件) │ ├── EditAction (多行编辑组件) │ ├── MultiInputAction (多项输入组件) │ ├── MenuAction (单选菜单组件) │ ├── SelectAction (多选菜单组件) │ ├── MsgBoxAction (消息弹窗组件) │ ├── WebViewAction (网页视图组件) │ └── HelpAction (帮助页面组件) ├── ActionButton (动作按钮组件) └── ActionToast (提示消息组件) ``` ### 2. 数据流 ``` Action JSON → ActionRenderer → 具体Action组件 → 用户交互 → 回调处理 → API调用 ``` ## 核心组件规范 ### 1. ActionRenderer (主渲染器) **职责:** - 解析Action JSON配置 - 根据type字段路由到对应的组件 - 管理组件的生命周期 - 处理专项动作 **Props接口:** ```typescript interface ActionRendererProps { actionData: string | ActionConfig; // Action JSON字符串或对象 onAction: (action: string, value: any) => Promise; // 动作回调 onClose?: () => void; // 关闭回调 } interface ActionConfig { actionId: string; type: ActionType; [key: string]: any; } type ActionType = 'input' | 'edit' | 'multiInput' | 'multiInputX' | 'menu' | 'select' | 'msgbox' | 'webview' | 'help'; ``` **核心方法:** ```typescript class ActionRenderer { // 解析Action配置 parseActionConfig(data: string | ActionConfig): ActionConfig; // 渲染对应组件 renderActionComponent(config: ActionConfig): React.ReactNode; // 处理专项动作 handleSpecialAction(actionId: string, config: ActionConfig): void; // 执行动作回调 executeAction(action: string, value: any): Promise; } ``` ### 2. ActionDialog (弹窗容器) **职责:** - 提供统一的弹窗容器 - 处理弹窗的显示/隐藏逻辑 - 管理弹窗的尺寸和位置 - 处理背景遮罩和点击外部关闭 **Props接口:** ```typescript interface ActionDialogProps { visible: boolean; title?: string; width?: number; height?: number; bottom?: number; canceledOnTouchOutside?: boolean; dimAmount?: number; onClose: () => void; children: React.ReactNode; } ``` **样式规范:** ```css .action-dialog { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); z-index: 1000; } .action-dialog-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 999; } ``` ### 3. InputAction (单项输入组件) **职责:** - 渲染单项输入界面 - 处理输入验证 - 支持快速选择选项 - 显示图片和二维码 - 处理图片点击坐标 **Props接口:** ```typescript interface InputActionProps { config: InputActionConfig; onSubmit: (value: any) => void; onCancel?: () => void; } interface InputActionConfig { actionId: string; id: string; title: string; tip: string; value?: string; msg?: string; width?: number; button?: number; selectData?: string; imageUrl?: string; imageHeight?: number; imageClickCoord?: boolean; qrcode?: string; qrcodeSize?: string; timeout?: number; keep?: boolean; help?: string; } ``` **核心功能:** ```typescript class InputAction { // 解析快速选择数据 parseSelectData(selectData: string): SelectOption[]; // 处理图片点击坐标 handleImageClick(event: MouseEvent): void; // 生成二维码 generateQRCode(url: string, size: string): string; // 验证输入值 validateInput(value: string): boolean; // 处理超时 handleTimeout(timeout: number): void; } ``` ### 4. MultiInputAction (多项输入组件) **职责:** - 渲染多项输入界面 - 支持不同类型的输入控件 - 处理文件选择、日期选择等特殊输入 - 验证所有输入项 **Props接口:** ```typescript interface MultiInputActionProps { config: MultiInputActionConfig; onSubmit: (values: Record) => void; onCancel?: () => void; } interface MultiInputActionConfig { actionId: string; type: 'multiInput' | 'multiInputX'; title: string; width?: number; height?: number; msg?: string; button?: number; input: InputItem[]; } interface InputItem { id: string; name: string; tip: string; value?: string; selectData?: string; inputType?: number; multiLine?: number; validation?: string; help?: string; quickSelect?: boolean; onlyQuickSelect?: boolean; multiSelect?: boolean; selectWidth?: number; selectColumn?: number; } ``` **特殊输入类型处理:** ```typescript class MultiInputAction { // 文件夹选择 handleFolderSelect(itemId: string): void; // 文件选择 handleFileSelect(itemId: string): void; // 日期选择 handleDateSelect(itemId: string): void; // 图像选择并转换为Base64 handleImageSelect(itemId: string): void; // 多选处理 handleMultiSelect(itemId: string, options: string[]): void; // 输入验证 validateItem(item: InputItem, value: string): boolean; } ``` ### 5. MenuAction (单选菜单组件) **职责:** - 渲染单选菜单界面 - 支持多列布局 - 处理选项选择 **Props接口:** ```typescript interface MenuActionProps { config: MenuActionConfig; onSelect: (action: string) => void; onCancel?: () => void; } interface MenuActionConfig { actionId: string; title: string; width?: number; column?: number; option: MenuOption[]; selectedIndex?: number; } interface MenuOption { name: string; action: string; } ``` ### 6. SelectAction (多选菜单组件) **职责:** - 渲染多选菜单界面 - 管理选中状态 - 支持全选/反选功能 **Props接口:** ```typescript interface SelectActionProps { config: SelectActionConfig; onSubmit: (selectedActions: string[]) => void; onCancel?: () => void; } interface SelectActionConfig { actionId: string; title: string; width?: number; column?: number; option: SelectOption[]; } interface SelectOption { name: string; action: string; selected?: boolean; } ``` ### 7. MsgBoxAction (消息弹窗组件) **职责:** - 显示消息内容 - 支持HTML格式消息 - 显示图片 **Props接口:** ```typescript interface MsgBoxActionProps { config: MsgBoxActionConfig; onClose: () => void; } interface MsgBoxActionConfig { actionId: string; title: string; msg?: string; htmlMsg?: string; imageUrl?: string; } ``` ### 8. WebViewAction (网页视图组件) **职责:** - 嵌入网页内容 - 处理网页交互 - 管理缩放和滚动 **Props接口:** ```typescript interface WebViewActionProps { config: WebViewActionConfig; onClose: () => void; } interface WebViewActionConfig { actionId: string; url: string; height?: number; textZoom?: number; } ``` ## 状态管理 ### 1. Action状态 ```typescript interface ActionState { currentAction: ActionConfig | null; isVisible: boolean; isLoading: boolean; error: string | null; history: ActionConfig[]; // 动作历史,支持返回 } ``` ### 2. 状态管理器 ```typescript class ActionStateManager { private state: ActionState; private listeners: ((state: ActionState) => void)[]; // 显示动作 showAction(config: ActionConfig): void; // 隐藏动作 hideAction(): void; // 执行动作 executeAction(action: string, value: any): Promise; // 返回上一个动作 goBack(): void; // 清空历史 clearHistory(): void; // 订阅状态变化 subscribe(listener: (state: ActionState) => void): () => void; } ``` ## 样式规范 ### 1. 设计系统 ```css :root { /* 颜色 */ --action-primary: #1890ff; --action-success: #52c41a; --action-warning: #faad14; --action-error: #f5222d; --action-text: #262626; --action-text-secondary: #8c8c8c; --action-border: #d9d9d9; --action-background: #ffffff; --action-background-light: #fafafa; /* 尺寸 */ --action-border-radius: 6px; --action-padding: 16px; --action-margin: 8px; /* 阴影 */ --action-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); --action-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.15); } ``` ### 2. 组件样式 ```css /* 输入框 */ .action-input { width: 100%; padding: 8px 12px; border: 1px solid var(--action-border); border-radius: var(--action-border-radius); font-size: 14px; transition: border-color 0.3s; } .action-input:focus { border-color: var(--action-primary); outline: none; box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); } /* 按钮 */ .action-button { padding: 8px 16px; border: 1px solid var(--action-border); border-radius: var(--action-border-radius); background: var(--action-background); cursor: pointer; transition: all 0.3s; } .action-button-primary { background: var(--action-primary); border-color: var(--action-primary); color: white; } .action-button:hover { box-shadow: var(--action-shadow-hover); } /* 选项 */ .action-option { padding: 12px; border: 1px solid var(--action-border); border-radius: var(--action-border-radius); cursor: pointer; transition: all 0.3s; } .action-option:hover { background: var(--action-background-light); border-color: var(--action-primary); } .action-option-selected { background: var(--action-primary); border-color: var(--action-primary); color: white; } ``` ## API接口规范 ### 1. Action执行接口 ```typescript interface ActionAPI { // 执行动作 executeAction(action: string, value: any): Promise; } interface ActionResponse { success: boolean; data?: any; action?: ActionConfig; // 新的动作配置 toast?: string; // 提示消息 error?: string; } ``` ### 2. 文件操作接口 ```typescript interface FileAPI { // 选择文件夹 selectFolder(): Promise; // 选择文件 selectFile(accept?: string): Promise; // 选择图片并转换为Base64 selectImageAsBase64(): Promise; } ``` ## 错误处理 ### 1. 错误类型 ```typescript enum ActionErrorType { PARSE_ERROR = 'PARSE_ERROR', VALIDATION_ERROR = 'VALIDATION_ERROR', NETWORK_ERROR = 'NETWORK_ERROR', TIMEOUT_ERROR = 'TIMEOUT_ERROR', USER_CANCEL = 'USER_CANCEL' } interface ActionError { type: ActionErrorType; message: string; details?: any; } ``` ### 2. 错误处理策略 ```typescript class ActionErrorHandler { // 处理解析错误 handleParseError(error: Error): void; // 处理验证错误 handleValidationError(field: string, message: string): void; // 处理网络错误 handleNetworkError(error: Error): void; // 处理超时错误 handleTimeoutError(): void; // 显示错误提示 showError(error: ActionError): void; } ``` ## 性能优化 ### 1. 组件懒加载 ```typescript // 动态导入组件 const InputAction = lazy(() => import('./InputAction')); const MultiInputAction = lazy(() => import('./MultiInputAction')); // ... // 使用Suspense包装 }> ``` ### 2. 虚拟滚动 对于大量选项的菜单组件,使用虚拟滚动优化性能: ```typescript import { FixedSizeList as List } from 'react-window'; const VirtualMenuAction = ({ options, onSelect }) => { const Row = ({ index, style }) => (
onSelect(options[index])}> {options[index].name}
); return ( {Row} ); }; ``` ### 3. 防抖处理 对于输入组件,使用防抖优化性能: ```typescript import { debounce } from 'lodash'; const debouncedValidation = debounce((value: string) => { validateInput(value); }, 300); ``` ## 测试规范 ### 1. 单元测试 ```typescript describe('ActionRenderer', () => { test('should parse action config correctly', () => { const config = '{"actionId":"test","type":"input"}'; const result = ActionRenderer.parseActionConfig(config); expect(result.actionId).toBe('test'); expect(result.type).toBe('input'); }); test('should handle invalid JSON gracefully', () => { const config = 'invalid json'; expect(() => ActionRenderer.parseActionConfig(config)).toThrow(); }); }); ``` ### 2. 集成测试 ```typescript describe('Action Integration', () => { test('should complete input action flow', async () => { const mockOnAction = jest.fn().mockResolvedValue('success'); const { getByTestId } = render( ); const input = getByTestId('action-input'); fireEvent.change(input, { target: { value: 'test value' } }); const submitButton = getByTestId('action-submit'); fireEvent.click(submitButton); await waitFor(() => { expect(mockOnAction).toHaveBeenCalledWith('test', { test: 'test value' }); }); }); }); ``` ## 部署和构建 ### 1. 构建配置 ```javascript // vite.config.js export default { build: { rollupOptions: { output: { manualChunks: { 'action-components': [ './src/components/actions/InputAction', './src/components/actions/MultiInputAction', // ... ] } } } } }; ``` ### 2. 代码分割 ```typescript // 路由级别的代码分割 const ActionPage = lazy(() => import('./pages/ActionPage')); // 组件级别的代码分割 const ActionRenderer = lazy(() => import('./components/ActionRenderer')); ``` 通过以上技术规范,开发团队可以构建出功能完整、性能优良、用户体验良好的Action交互组件系统。