--- description: "检查并修正筛选表单指令" --- # 筛选表单检查与修复指南 ## 问题描述 在使用 React Hook Form 和状态管理进行筛选表单开发时,常见的同步问题包括: 1. **表单状态与查询参数不同步**:重置操作只清除查询参数,但表单字段值保持不变 2. **表单验证问题**:字段验证规则不完整或错误 3. **UI状态不一致**:筛选条件显示与实际查询条件不符 ## 检查步骤 ### 1. 检查表单重置功能 ```bash # 检查 handleReset 函数是否同时重置表单和查询参数 grep -n "handleReset" src/**/*.tsx ``` ### 2. 检查表单字段同步 ```bash # 检查表单字段是否与查询参数正确映射 grep -n "setSearchParams\|form.reset" src/**/*.tsx ``` ### 3. 验证表单字段定义 ```bash # 检查所有表单字段是否正确定义 grep -n "FormField\|control" src/**/*.tsx | head -10 ``` ## 常见问题及修复方案 ### 问题1: 重置功能不完整 **症状**:点击重置按钮后,查询参数被清除但表单字段值保持不变 **修复方案**: ```typescript // 错误示例 - 只重置查询参数 const handleReset = () => { setSearchParams({ status: undefined, keyword: undefined, // ...其他参数 }); }; // 正确示例 - 同时重置表单和查询参数 const handleReset = () => { // 重置表单字段值 form.reset({ status: undefined, keyword: undefined, dateRange: undefined, // ...所有表单字段 }); // 重置搜索参数 setSearchParams({ status: undefined, keyword: undefined, startDate: undefined, endDate: undefined, // ...对应查询参数 }); }; ``` ### 问题2: Select组件缺少"全部"选项 **症状**:筛选表单中的Select组件缺少"全部"选项,用户无法取消筛选 **修复方案**: ```typescript // 错误示例 - 缺少全部选项 {Object.values(StatusEnum).map(status => ( {StatusNameMap[status]} ))} // 正确示例 - 添加全部选项(使用特殊值"all"并转换为undefined) ``` **注意事项**: - Radix UI Select组件不允许使用空字符串作为SelectItem的value - 使用特殊值"all"来表示全部选项,在onChange时转换为undefined - 在value prop中使用 `field.value || "all"` 来确保选中状态正确显示 ### 问题2: 表单字段映射错误 **症状**:表单字段名称与查询参数名称不一致 **修复方案**: ```typescript // 确保表单字段名与查询参数名正确映射 const handleSearch = (values: any) => { setSearchParams({ status: values.status, // 表单字段名 -> 查询参数名 keyword: values.keyword, // 保持一致 startDate: values.dateRange?.[0]?.toISOString(), // 复杂映射 endDate: values.dateRange?.[1]?.toISOString(), }); }; ``` ### 问题3: 初始状态不一致 **症状**:组件挂载时表单初始值与查询参数不匹配 **修复方案**: ```typescript // 使用 useEffect 同步初始状态 useEffect(() => { const initialValues = { status: searchParams.status || undefined, keyword: searchParams.keyword || undefined, dateRange: searchParams.startDate && searchParams.endDate ? [new Date(searchParams.startDate), new Date(searchParams.endDate)] : undefined, }; form.reset(initialValues); }, []); ``` ## 通用CRUD filters参数使用指南 ### 问题4: 未使用通用CRUD的filters参数 **症状**:页面使用独立的查询参数而不是通用CRUD的标准filters参数 **修复方案**: ```typescript // 错误示例 - 使用独立参数 const res = await client.$get({ query: { page: 1, pageSize: 10, status: searchParams.status, problemType: searchParams.problemType, keyword: searchParams.keyword, startDate: searchParams.startDate, endDate: searchParams.endDate, } }); // 正确示例 - 使用通用CRUD filters参数 const filters: any = {}; if (searchParams.status) filters.status = searchParams.status; if (searchParams.problemType) filters.problemType = searchParams.problemType; if (searchParams.startDate && searchParams.endDate) { filters.createdAt = { between: [searchParams.startDate, searchParams.endDate] }; } const res = await client.$get({ query: { page: 1, pageSize: 10, keyword: searchParams.keyword, // 独立的关键词参数 filters: Object.keys(filters).length > 0 ? JSON.stringify(filters) : undefined, } }); ``` ### 问题5: 关联字段搜索与筛选不支持 **症状**:无法通过关联实体的字段进行搜索和筛选(如设备名称、用户名称等) **修复方案**: 1. **配置searchFields和relations**: ```typescript const routes = createCrudRoutes({ entity: YourEntity, searchFields: ['title', 'description', 'device.zichanInfo.assetName'], // 支持关联字段搜索(格式:relation.field 或 relation.nestedRelation.field) relations: ['device.zichanInfo'], // 确保关联数据被加载 // ...其他配置 }); ``` 2. **使用关联字段筛选**: ```typescript // 在filters参数中使用关联字段进行精确筛选 const filters = { 'device.zichanInfo.assetName': '服务器001', // 精确匹配 'device.zichanInfo.status': { gte: 1 }, // 范围查询 'device.zichanInfo.department.name': '%IT%' // 模糊匹配 }; const res = await client.$get({ query: { page: 1, pageSize: 10, filters: JSON.stringify(filters) } }); ``` **别名生成规则**: - 单级关联:`device.zichanInfo` → 别名:`device_zichanInfo` - 嵌套关联:`device.zichanInfo.department` → 别名:`device_zichanInfo_department` - 字段引用:`device_zichanInfo.assetName`, `device_zichanInfo_department.name` **支持的筛选操作**: - 精确匹配:`{ "relation.field": "value" }` - 模糊匹配:`{ "relation.field": "%value%" }` - 范围查询:`{ "relation.field": { "gte": min, "lte": max } }` - IN查询:`{ "relation.field": [value1, value2, ...] }` ## 完整代码示例 ### 修复后的筛选表单组件(使用通用CRUD filters) ```typescript import React from 'react'; import { useForm } from 'react-hook-form'; import { Form, FormField, FormItem, FormLabel, FormControl } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Button } from '@/components/ui/button'; import { workOrderClient } from '@/client/api'; export function FilterForm() { const [searchParams, setSearchParams] = useState({}); const form = useForm(); // 搜索处理 - 使用通用CRUD filters参数 const handleSearch = (values: any) => { // 构建filters对象 const filters: any = {}; if (values.status) filters.status = values.status; if (values.problemType) filters.problemType = values.problemType; if (values.dateRange?.[0] && values.dateRange?.[1]) { filters.createdAt = { between: [values.dateRange[0], values.dateRange[1]] }; } setSearchParams({ keyword: values.keyword, filters: Object.keys(filters).length > 0 ? JSON.stringify(filters) : undefined, }); }; // 重置处理 - 修复后的版本 const handleReset = () => { // 重置表单字段值 form.reset({ status: undefined, keyword: undefined, problemType: undefined, dateRange: undefined, }); // 重置搜索参数 setSearchParams({ keyword: undefined, filters: undefined, }); }; return (
( 状态 )} /> ( 关键字 )} />
); } ``` ## 最佳实践 1. **保持同步**:始终确保表单状态与查询参数同步 2. **完整重置**:重置操作应同时清除表单字段和查询参数 3. **类型安全**:为表单值和查询参数定义明确的 TypeScript 类型 4. **测试验证**:编写测试用例验证重置功能正常工作 5. **用户体验**:重置后应自动触发数据重新加载 ## 自动化检查脚本 ```bash #!/bin/bash # 检查筛选表单常见问题 echo "=== 筛选表单检查 ===" # 检查 handleReset 函数 echo "1. 检查 handleReset 函数:" grep -A 10 -B 2 "handleReset" src/**/*.tsx | grep -E "setSearchParams|form.reset" # 检查表单字段映射 echo "2. 检查表单字段映射:" grep -A 5 -B 5 "handleSearch" src/**/*.tsx # 检查初始状态同步 echo "3. 检查初始状态同步:" grep -A 10 -B 2 "useEffect.*searchParams" src/**/*.tsx # 检查通用CRUD filters参数使用 echo "4. 检查通用CRUD filters参数使用:" grep -A 5 -B 5 "filters.*JSON.stringify" src/**/*.tsx # 检查关联字段搜索配置 echo "5. 检查关联字段搜索配置:" grep -A 3 -B 3 "searchFields.*\." src/server/api/**/index.ts echo "=== 检查完成 ===" ``` ## 最佳实践更新 6. **标准接口**:优先使用通用CRUD的filters参数而不是独立参数 7. **关联搜索**:合理配置searchFields和relations支持关联字段搜索 8. **性能优化**:避免在filters中使用过多关联查询,必要时使用自定义服务方法 使用此指令可以快速识别和修复筛选表单中的常见同步问题,包括通用CRUD filters参数的使用和关联字段搜索功能。 使用此指令可以快速识别和修复筛选表单中的常见同步问题。