import React, { useState, useEffect, useMemo } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@/components/ui/table'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { DataTablePagination } from '@/components/ui/pagination'; import { Loader2, Search, Eye, Trash2, Download, Folder, Activity, Clock, CheckCircle2, FileCheck, Database } from 'lucide-react'; import { getFormDataList, deleteFormData, exportFormData } from './service'; import { getEnabledCategories } from '../Category/service'; import type { FormDataResponse, FormDataStatus, FormDataBusinessType } from './types'; import type { FormCategoryResponse } from '../Category/types'; import type { Page } from '@/types/base'; import { DEFAULT_PAGE_SIZE, DEFAULT_CURRENT } from '@/utils/page'; import dayjs from 'dayjs'; /** * 表单数据列表页 */ const FormDataList: React.FC = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const [loading, setLoading] = useState(false); const [data, setData] = useState | null>(null); const [categories, setCategories] = useState([]); const [query, setQuery] = useState({ pageNum: DEFAULT_CURRENT - 1, pageSize: DEFAULT_PAGE_SIZE, formDefinitionId: searchParams.get('formDefinitionId') ? Number(searchParams.get('formDefinitionId')) : undefined, businessKey: '', categoryId: undefined as number | undefined, status: undefined as FormDataStatus | undefined, businessType: undefined as FormDataBusinessType | undefined, }); // 加载分类列表 const loadCategories = async () => { try { const result = await getEnabledCategories(); setCategories(result || []); } catch (error) { console.error('加载分类失败:', error); } }; // 加载数据 const loadData = async () => { setLoading(true); try { const result = await getFormDataList(query); setData(result); } catch (error) { console.error('加载表单数据失败:', error); } finally { setLoading(false); } }; useEffect(() => { loadCategories(); }, []); useEffect(() => { loadData(); }, [query]); // 搜索 const handleSearch = () => { setQuery(prev => ({ ...prev, pageNum: 0, })); }; // 重置搜索 const handleReset = () => { setQuery({ pageNum: 0, pageSize: DEFAULT_PAGE_SIZE, formDefinitionId: undefined, businessKey: '', categoryId: undefined, status: undefined, businessType: undefined, }); }; // 根据分类 ID 获取分类信息 const getCategoryInfo = (categoryId?: number) => { return categories.find(cat => cat.id === categoryId); }; // 查看详情 const handleView = (record: FormDataResponse) => { navigate(`/form/data/${record.id}`); }; // 删除 const handleDelete = async (record: FormDataResponse) => { if (!confirm('确定要删除该数据吗?')) return; try { await deleteFormData(record.id); loadData(); } catch (error) { console.error('删除数据失败:', error); } }; // 导出 const handleExport = async () => { try { await exportFormData(query); } catch (error) { console.error('导出数据失败:', error); } }; // 状态徽章 const getStatusBadge = (status: FormDataStatus) => { const statusMap: Record = { DRAFT: { variant: 'outline', text: '草稿', icon: Clock }, SUBMITTED: { variant: 'success', text: '已提交', icon: CheckCircle2 }, COMPLETED: { variant: 'default', text: '已完成', icon: FileCheck }, }; const statusInfo = statusMap[status]; const Icon = statusInfo.icon; return ( {statusInfo.text} ); }; // 业务类型徽章 const getBusinessTypeBadge = (type: FormDataBusinessType) => { const typeMap: Record = { STANDALONE: { variant: 'outline', text: '独立' }, WORKFLOW: { variant: 'default', text: '工作流' }, ORDER: { variant: 'secondary', text: '订单' }, }; const typeInfo = typeMap[type]; return {typeInfo.text}; }; // 统计数据 const stats = useMemo(() => { const total = data?.totalElements || 0; const draftCount = data?.content?.filter(d => d.status === 'DRAFT').length || 0; const submittedCount = data?.content?.filter(d => d.status === 'SUBMITTED').length || 0; const completedCount = data?.content?.filter(d => d.status === 'COMPLETED').length || 0; return { total, draftCount, submittedCount, completedCount }; }, [data]); const pageCount = data?.totalElements ? Math.ceil(data.totalElements / query.pageSize) : 0; return (

表单数据管理

查看和管理用户提交的表单数据,支持按分类、状态、业务类型筛选。

{/* 统计卡片 */}
总数据量
{stats.total}

全部表单数据

草稿
{stats.draftCount}

暂存的数据

已提交
{stats.submittedCount}

待处理的数据

已完成
{stats.completedCount}

已处理完成

数据列表 {/* 搜索栏 */}
setQuery(prev => ({ ...prev, businessKey: e.target.value }))} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} className="h-9" />
{/* 表格 */}
表单标识 分类 业务类型 业务标识 提交人 提交时间 状态 操作 {loading ? (
加载中...
) : data?.content && data.content.length > 0 ? ( data.content.map((record) => { const categoryInfo = getCategoryInfo(record.categoryId); return ( {record.formKey} {categoryInfo ? ( {categoryInfo.icon && } {categoryInfo.name} ) : ( 未分类 )} {getBusinessTypeBadge(record.businessType)} {record.businessKey || '-'} {record.submitter || '匿名'} {record.submitTime ? dayjs(record.submitTime).format('YYYY-MM-DD HH:mm:ss') : '-'} {getStatusBadge(record.status)}
); }) ) : (
暂无表单数据
用户提交的表单数据将在此显示。
)}
{/* 分页 */} {pageCount > 1 && ( setQuery(prev => ({ ...prev, pageNum: page - 1 }))} /> )}
); }; export default FormDataList;