import type { MetaFunction, LoaderFunctionArgs } from '@remix-run/node'; import { useLoaderData, useSearchParams, useNavigate } from '@remix-run/react'; import { useState, useEffect } from 'react'; import { FilterTabs } from '~/components/contract-template/FilterTabs'; import { TemplateGrid } from '~/components/contract-template/TemplateGrid'; import { Pagination } from '~/components/ui/Pagination'; import { getContractTemplates, getContractCategoriesWithCount } from '~/api/contract-template/templates'; import type { ContractTemplate, TemplateSearchParams, ContractCategoryWithCount } from '~/api/contract-template/templates'; import styles from '~/styles/pages/contract-template.css?url'; export const links = () => [ { rel: 'stylesheet', href: styles } ]; export const meta: MetaFunction = () => { return [ { title: '合同模板列表 - 智慧法务' }, { name: 'description', content: '浏览和管理所有合同模板,按分类查看各种类型的合同模板。' } ]; }; // 将数据库模板转换为前端显示格式 function transformTemplate(template: ContractTemplate) { // 模拟使用次数和评分(实际项目中可以从其他表获取) const mockUsageCount = Math.floor(Math.random() * 2000) + 100; const mockRating = (Math.random() * 1.5 + 3.5).toFixed(1); // 根据模板属性确定类型 let templateType = '标准版'; if (template.is_featured) { templateType = '推荐版'; } else if (template.description && template.description.includes('简化')) { templateType = '简化版'; } else if (template.description && (template.description.includes('专业') || template.description.includes('大客户'))) { templateType = '专业版'; } return { id: template.id.toString(), title: template.title, type: templateType, description: template.description || '', updateTime: new Date(template.updated_at).toLocaleDateString('zh-CN'), useCount: mockUsageCount, rating: parseFloat(mockRating), category: template.category?.name || '其他' }; } export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const category = url.searchParams.get('category') || ''; const category_id = url.searchParams.get('category_id') || ''; const type = url.searchParams.get('type') || ''; const page = parseInt(url.searchParams.get('page') || '1'); const pageSize = 6; try { // 构建搜索参数 const searchParams: TemplateSearchParams = { page, pageSize, sortBy: 'updated_at', sortOrder: 'desc' }; // 优先使用category_id,其次使用category名称 if (category_id) { searchParams.category_id = parseInt(category_id); } else if (category) { searchParams.category = category; } // 并行获取模板数据和分类数据 const [templatesResponse, categoriesResponse] = await Promise.all([ getContractTemplates(searchParams), getContractCategoriesWithCount() ]); // 处理模板数据 if (templatesResponse.error) { console.error('获取模板列表失败:', templatesResponse.error); return { templates: [], total: 0, page, pageSize, category, category_id, type, categories: [] }; } // 处理分类数据 const categories: ContractCategoryWithCount[] = categoriesResponse.error ? [] : categoriesResponse.data || []; // 转换模板数据格式 let transformedTemplates = templatesResponse.data?.templates.map(transformTemplate) || []; // 如果有类型筛选,在前端进行筛选(因为数据库中没有type字段) if (type) { transformedTemplates = transformedTemplates.filter(t => t.type === type); } // 获取当前分类信息(用于显示) let currentCategory = '全部'; if (category_id) { const cat = categories.find(c => c.id === parseInt(category_id)); currentCategory = cat?.name || '全部'; } else if (category) { currentCategory = category; } return { templates: transformedTemplates, total: templatesResponse.data?.total || 0, page, pageSize, category: currentCategory, category_id, type, categories }; } catch (error) { console.error('加载模板列表失败:', error); return { templates: [], total: 0, page, pageSize, category, category_id, type, categories: [] }; } } export default function ContractTemplateList() { const { templates, total, page, pageSize, category, category_id, categories } = useLoaderData(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); const [activeFilter, setActiveFilter] = useState(category || '全部'); const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); const [sortBy, setSortBy] = useState('newest'); // 监听category变化,同步更新activeFilter状态 useEffect(() => { setActiveFilter(category || '全部'); }, [category]); const handleTemplateClick = (templateId: string) => { navigate(`/contract-template/detail/${templateId}`); }; const handleFilterChange = (filter: string) => { setActiveFilter(filter); const params = new URLSearchParams(searchParams); if (filter === '全部') { params.delete('category'); params.delete('category_id'); } else { // 根据分类名称找到对应的ID const selectedCategory = categories.find(cat => cat.name === filter); if (selectedCategory) { params.set('category_id', selectedCategory.id.toString()); params.delete('category'); // 删除旧的category参数 } else { params.set('category', filter); params.delete('category_id'); } } params.delete('page'); // 重置页码 navigate(`/contract-template/list?${params.toString()}`); }; const handlePageChange = (newPage: number) => { const params = new URLSearchParams(searchParams); params.set('page', newPage.toString()); navigate(`/contract-template/list?${params.toString()}`); }; // 动态生成筛选选项 // 计算所有分类的总模板数量 const totalAllTemplates = categories.reduce((sum, cat) => sum + (cat.template_count || 0), 0); const filters = [ { label: '全部', count: totalAllTemplates }, ...categories.map(cat => ({ label: cat.name, count: cat.template_count || 0 })) ]; const totalPages = Math.ceil(total / pageSize); const currentCategory = category || '全部'; return (
{/* 页面头部 */}

{currentCategory === '全部' ? '合同模板库' : `${currentCategory}模板`}

{total} 个模板
{/* 视图切换 */}
{/* 排序选择 */}
{/* 筛选标签 */} {/* 模板网格 */} {/* 分页 */} {totalPages > 1 && ( )}
); } // 面包屑导航配置 export const handle = { breadcrumb: "合同列表" };