276 lines
8.4 KiB
TypeScript
276 lines
8.4 KiB
TypeScript
import type { MetaFunction, LoaderFunctionArgs } from '@remix-run/node';
|
|
import { useLoaderData, useSearchParams, useNavigate } from '@remix-run/react';
|
|
import { useState } from 'react';
|
|
import { CompactSearchBox } from '~/components/contract-template/CompactSearchBox';
|
|
import { SearchResultHeader } from '~/components/contract-template/SearchResultHeader';
|
|
import { FilterTabs } from '~/components/contract-template/FilterTabs';
|
|
import { TemplateGrid } from '~/components/contract-template/TemplateGrid';
|
|
import { Pagination } from '~/components/ui/Pagination';
|
|
import styles from '~/styles/pages/contract-template.css?url';
|
|
|
|
export const links = () => [
|
|
{ rel: 'stylesheet', href: styles }
|
|
];
|
|
|
|
export const meta: MetaFunction = () => {
|
|
return [
|
|
{ title: '搜索结果 - AI智能合同模板搜索 - 智慧法务' },
|
|
{
|
|
name: 'description',
|
|
content: 'AI智能搜索合同模板结果,快速找到最适合的模板。'
|
|
}
|
|
];
|
|
};
|
|
|
|
// 面包屑导航配置
|
|
export const handle = {
|
|
breadcrumb: "搜索结果"
|
|
};
|
|
|
|
// 模拟数据 - 扩展搜索结果
|
|
const mockSearchResults = [
|
|
{
|
|
id: '1',
|
|
title: '烟草产品销售合同标准模板',
|
|
type: '销售合同',
|
|
description: '适用于烟草产品销售业务,包含完整的违约责任条款、付款方式、交付条件等核心要素,符合行业规范要求。',
|
|
updateTime: '2023-10-25',
|
|
useCount: 1248,
|
|
rating: 4.8,
|
|
category: '销售合同'
|
|
},
|
|
{
|
|
id: '2',
|
|
title: '零售商销售协议模板',
|
|
type: '销售合同',
|
|
description: '专为零售商设计的销售协议,详细规定了违约责任、退换货政策、结算方式等条款。',
|
|
updateTime: '2023-10-20',
|
|
useCount: 856,
|
|
rating: 4.6,
|
|
category: '销售合同'
|
|
},
|
|
{
|
|
id: '3',
|
|
title: '设备采购合同(含违约条款)',
|
|
type: '采购合同',
|
|
description: '设备采购专用合同模板,包含详细的违约责任条款、质量保证、验收标准等内容。',
|
|
updateTime: '2023-10-18',
|
|
useCount: 642,
|
|
rating: 4.7,
|
|
category: '采购合同'
|
|
},
|
|
{
|
|
id: '4',
|
|
title: '批发销售合同模板',
|
|
type: '销售合同',
|
|
description: '适用于大宗批发业务的销售合同,强化了违约责任条款和风险控制措施。',
|
|
updateTime: '2023-10-15',
|
|
useCount: 534,
|
|
rating: 4.5,
|
|
category: '销售合同'
|
|
},
|
|
{
|
|
id: '5',
|
|
title: '技术服务合同(标准版)',
|
|
type: '服务合同',
|
|
description: '技术服务类合同模板,包含服务标准、违约责任、知识产权保护等关键条款。',
|
|
updateTime: '2023-10-12',
|
|
useCount: 423,
|
|
rating: 4.4,
|
|
category: '服务合同'
|
|
},
|
|
{
|
|
id: '6',
|
|
title: '区域代理销售合同',
|
|
type: '销售合同',
|
|
description: '区域代理商专用销售合同,明确代理权限、销售目标、违约责任等核心条款。',
|
|
updateTime: '2023-10-10',
|
|
useCount: 312,
|
|
rating: 4.3,
|
|
category: '销售合同'
|
|
},
|
|
{
|
|
id: '7',
|
|
title: '物流运输服务合同',
|
|
type: '物流运输',
|
|
description: '专业的物流运输服务合同模板,涵盖运输责任、保险、违约赔偿等关键条款。',
|
|
updateTime: '2023-10-08',
|
|
useCount: 267,
|
|
rating: 4.2,
|
|
category: '物流运输'
|
|
},
|
|
{
|
|
id: '8',
|
|
title: '仓储管理服务协议',
|
|
type: '物流运输',
|
|
description: '仓储管理专用合同,包含货物保管、出入库管理、损失责任等详细条款。',
|
|
updateTime: '2023-10-05',
|
|
useCount: 189,
|
|
rating: 4.1,
|
|
category: '物流运输'
|
|
},
|
|
{
|
|
id: '9',
|
|
title: '劳务派遣合同模板',
|
|
type: '人事劳务',
|
|
description: '劳务派遣服务合同,明确派遣关系、工资福利、社保缴纳等人事管理条款。',
|
|
updateTime: '2023-10-03',
|
|
useCount: 345,
|
|
rating: 4.6,
|
|
category: '人事劳务'
|
|
},
|
|
{
|
|
id: '10',
|
|
title: '商业机密保护协议',
|
|
type: '保密协议',
|
|
description: '企业商业机密保护专用协议,涵盖信息范围、保密义务、违约责任等核心内容。',
|
|
updateTime: '2023-10-01',
|
|
useCount: 156,
|
|
rating: 4.5,
|
|
category: '保密协议'
|
|
},
|
|
{
|
|
id: '11',
|
|
title: '办公场地租赁合同',
|
|
type: '租赁合同',
|
|
description: '办公场地租赁标准合同,包含租金支付、物业管理、违约处理等全面条款。',
|
|
updateTime: '2023-09-28',
|
|
useCount: 278,
|
|
rating: 4.3,
|
|
category: '租赁合同'
|
|
},
|
|
{
|
|
id: '12',
|
|
title: '设备租赁协议(长期)',
|
|
type: '租赁合同',
|
|
description: '长期设备租赁专用协议,详细规定租赁期限、维护责任、续租条件等关键条款。',
|
|
updateTime: '2023-09-25',
|
|
useCount: 198,
|
|
rating: 4.4,
|
|
category: '租赁合同'
|
|
}
|
|
];
|
|
|
|
export async function loader({ request }: LoaderFunctionArgs) {
|
|
const url = new URL(request.url);
|
|
const query = url.searchParams.get('q') || '';
|
|
const category = url.searchParams.get('category') || '';
|
|
const page = parseInt(url.searchParams.get('page') || '1');
|
|
|
|
// 模拟搜索耗时
|
|
const startTime = Date.now();
|
|
|
|
// 这里应该是实际的搜索逻辑
|
|
// 目前返回模拟数据
|
|
let filteredResults = mockSearchResults;
|
|
|
|
// 如果有查询条件,进行筛选
|
|
if (query || category) {
|
|
filteredResults = mockSearchResults.filter(item => {
|
|
const matchesQuery = !query ||
|
|
item.title.toLowerCase().includes(query.toLowerCase()) ||
|
|
item.description.toLowerCase().includes(query.toLowerCase());
|
|
const matchesCategory = !category || item.category === category;
|
|
return matchesQuery && matchesCategory;
|
|
});
|
|
}
|
|
|
|
// 计算搜索耗时
|
|
const endTime = Date.now();
|
|
const searchTime = (endTime - startTime) / 1000;
|
|
const searchTimeText = `搜索用时 ${searchTime.toFixed(1)}秒`;
|
|
|
|
return {
|
|
results: filteredResults,
|
|
query,
|
|
category,
|
|
total: filteredResults.length,
|
|
page,
|
|
pageSize: 6,
|
|
searchTime: searchTimeText
|
|
};
|
|
}
|
|
|
|
export default function ContractTemplateSearchResults() {
|
|
const { results, query, total, page, pageSize, searchTime } = useLoaderData<typeof loader>();
|
|
const [searchParams] = useSearchParams();
|
|
const navigate = useNavigate();
|
|
const [activeFilter, setActiveFilter] = useState('全部');
|
|
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
|
|
const [sortBy, setSortBy] = useState('relevance');
|
|
|
|
const handleSearch = (newQuery: string) => {
|
|
if (newQuery.trim()) {
|
|
navigate(`/contract-template/search/results?q=${encodeURIComponent(newQuery)}`);
|
|
}
|
|
};
|
|
|
|
const handleTemplateClick = (templateId: string) => {
|
|
navigate(`/contract-template/detail/${templateId}`);
|
|
};
|
|
|
|
const handleFilterChange = (filter: string) => {
|
|
setActiveFilter(filter);
|
|
// 这里可以添加实际的筛选逻辑
|
|
};
|
|
|
|
const handlePageChange = (newPage: number) => {
|
|
const params = new URLSearchParams(searchParams);
|
|
params.set('page', newPage.toString());
|
|
navigate(`/contract-template/search/results?${params.toString()}`);
|
|
};
|
|
|
|
const filters = [
|
|
{ label: '全部', count: total },
|
|
{ label: '销售合同', count: results.filter(r => r.category === '销售合同').length },
|
|
{ label: '采购合同', count: results.filter(r => r.category === '采购合同').length },
|
|
{ label: '服务合同', count: results.filter(r => r.category === '服务合同').length }
|
|
];
|
|
|
|
const totalPages = Math.ceil(total / pageSize);
|
|
|
|
return (
|
|
<div className="contract-search-results">
|
|
{/* 紧凑搜索框 */}
|
|
<CompactSearchBox
|
|
initialQuery={query}
|
|
onSearch={handleSearch}
|
|
searchTime={searchTime}
|
|
/>
|
|
|
|
{/* 搜索结果头部 */}
|
|
<SearchResultHeader
|
|
total={total}
|
|
viewMode={viewMode}
|
|
onViewModeChange={setViewMode}
|
|
sortBy={sortBy}
|
|
onSortChange={setSortBy}
|
|
/>
|
|
|
|
{/* 筛选标签 */}
|
|
<FilterTabs
|
|
filters={filters}
|
|
activeFilter={activeFilter}
|
|
onFilterChange={handleFilterChange}
|
|
/>
|
|
|
|
{/* 模板网格 */}
|
|
<TemplateGrid
|
|
templates={results}
|
|
viewMode={viewMode}
|
|
onTemplateClick={handleTemplateClick}
|
|
/>
|
|
|
|
{/* 分页 */}
|
|
{totalPages > 1 && (
|
|
<Pagination
|
|
currentPage={page}
|
|
total={total}
|
|
pageSize={pageSize}
|
|
onChange={handlePageChange}
|
|
showPageSizeChanger={false}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|