From 6989ae389b60f7690c07821b539c0bfd7a42b484 Mon Sep 17 00:00:00 2001 From: awen Date: Fri, 30 May 2025 19:07:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E6=97=A0=E7=94=A8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E6=9A=82=E6=97=B6=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/contract-template/templates.ts | 6 +- .../contract-template/TemplateCard.tsx | 5 - app/routes/contract-template.detail.$id.tsx | 343 +++++++++--------- app/routes/contract-template.list._index.tsx | 19 - 4 files changed, 180 insertions(+), 193 deletions(-) diff --git a/app/api/contract-template/templates.ts b/app/api/contract-template/templates.ts index de3ab55..7fe38ce 100644 --- a/app/api/contract-template/templates.ts +++ b/app/api/contract-template/templates.ts @@ -177,7 +177,7 @@ export async function getContractTemplates(searchParams: TemplateSearchParams = // 构建查询参数 const params: PostgrestParams = { - select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,contract_categories(id,name,icon,description)', + select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,category:contract_categories(id,name,icon,description)', limit: pageSize, offset: (page - 1) * pageSize, order: `${sortBy}.${sortOrder}` @@ -271,7 +271,7 @@ export async function getContractTemplates(searchParams: TemplateSearchParams = export async function getContractTemplate(id: string | number) { try { const params: PostgrestParams = { - select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,contract_categories(id,name,icon,description)', + select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,category:contract_categories(id,name,icon,description)', filter: { 'id': `eq.${id}` } }; @@ -303,7 +303,7 @@ export async function getContractTemplate(id: string | number) { export async function getFeaturedTemplates(limit: number = 6) { try { const params: PostgrestParams = { - select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,contract_categories(id,name,icon,description)', + select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,category:contract_categories(id,name,icon,description)', filter: { 'is_featured': 'eq.true' }, order: 'updated_at.desc', limit diff --git a/app/components/contract-template/TemplateCard.tsx b/app/components/contract-template/TemplateCard.tsx index 745de50..12fa098 100644 --- a/app/components/contract-template/TemplateCard.tsx +++ b/app/components/contract-template/TemplateCard.tsx @@ -72,11 +72,6 @@ export function TemplateCard({ template, onClick }: TemplateCardProps) { switch (action) { case '立即下载': - // 添加调试信息 - console.log('模板数据:', template); - console.log('文件路径:', template.file_path); - console.log('文件格式:', template.file_format); - if (template.file_path) { // 构建文件名,使用模板标题和文件格式 const fileExtension = template.file_format || 'docx'; diff --git a/app/routes/contract-template.detail.$id.tsx b/app/routes/contract-template.detail.$id.tsx index fdaac27..558faab 100644 --- a/app/routes/contract-template.detail.$id.tsx +++ b/app/routes/contract-template.detail.$id.tsx @@ -1,6 +1,7 @@ import type { MetaFunction, LoaderFunctionArgs } from '@remix-run/node'; import { useLoaderData, useNavigate } from '@remix-run/react'; -import { useState } from 'react'; +import { getContractTemplate } from '~/api/contract-template/templates'; +import type { ContractTemplate } from '~/api/contract-template/templates'; import styles from '~/styles/pages/contract-template.css?url'; // 导入FilePreview组件 @@ -112,123 +113,108 @@ export const handle = { } }; -// 模拟详细数据 -const getTemplateDetail = (id: string) => { - const templates = { - '1': { - id: '1', - title: '烟草产品销售合同(2023版)', - type: '销售合同 · 标准版', - description: '本模板是专为烟草行业设计的标准销售合同,严格遵循《烟草专卖法》等相关法律法规,涵盖了烟草产品销售过程中的各个关键环节。', - updateTime: '2023年10月25日', - useCount: 2156, - rating: 4.9, - fileSize: '245KB', - scope: '烟草产品销售', - legalBasis: '《合同法》《烟草专卖法》', - templateCode: 'XS-2023-001', - reviews: [ - { - user: '李经理', - rating: 5, - comment: '模板非常专业,条款完整,符合行业规范。我们公司一直在使用这个模板,效果很好。', - date: '2023-10-20' - }, - { - user: '王总', - rating: 4, - comment: '模板结构清晰,易于理解和使用。特别是违约责任条款写得很详细,对我们很有帮助。', - date: '2023-10-18' - } - ], - features: [ - { title: '法律合规', description: '严格遵循烟草行业法律法规,确保合同条款合法有效', icon: 'ri-shield-check-line', color: 'green' }, - { title: '条款完整', description: '涵盖销售全流程,条款结构完整,逻辑清晰', icon: 'ri-settings-3-line', color: 'blue' }, - { title: '易于定制', description: '模板化设计,可根据具体业务需求灵活调整', icon: 'ri-edit-line', color: 'purple' }, - { title: '行业标准', description: '符合烟草行业标准,被广泛使用和认可', icon: 'ri-award-line', color: 'orange' } - ], - structure: [ - { step: 1, title: '合同主体', description: '甲乙双方基本信息、资质证明' }, - { step: 2, title: '标的物条款', description: '产品名称、规格、数量、质量标准' }, - { step: 3, title: '价格与付款', description: '价格条款、付款方式、结算周期' }, - { step: 4, title: '交付与验收', description: '交付时间、地点、方式、验收标准' }, - { step: 5, title: '违约责任', description: '违约情形、责任承担、损失赔偿' }, - { step: 6, title: '争议解决', description: '争议处理方式、管辖法院' } - ], - preview: ` -中文合同预览内容... - - 烟草产品销售合同 - 合同编号:_______________ - -甲方(销售方):_________________________ -地址:_____________________________________ -法定代表人:_______________ 联系电话:_______________ -烟草专卖许可证号:_________________________ - -乙方(采购方):_________________________ -地址:_____________________________________ -法定代表人:_______________ 联系电话:_______________ -烟草专卖零售许可证号:_____________________ - -根据《中华人民共和国合同法》、《中华人民共和国烟草专卖法》等相关法律法规, -甲乙双方在平等、自愿、公平、诚信的基础上,就烟草产品销售事宜达成如下协议: - -第一条 标的物 -1.1 产品名称:_________________________ -1.2 产品规格:_________________________ -1.3 产品数量:_________________________ -1.4 产品单价:_________________________ -1.5 合同总金额:_______________________ - -... 更多条款内容请下载完整模板查看 ... - ` - } - }; - - return templates[id as keyof typeof templates] || null; -}; - export async function loader({ params }: LoaderFunctionArgs) { - const template = getTemplateDetail(params.id!); + const templateId = params.id!; - if (!template) { + try { + const response = await getContractTemplate(templateId); + + if (response.error) { + throw new Response(response.error, { status: response.status || 404 }); + } + + if (!response.data) { + throw new Response('模板未找到', { status: 404 }); + } + + // 添加调试信息 + console.log('模板详情数据:', response.data); + console.log('分类信息:', response.data.category); + + return { template: response.data }; + } catch (error) { + console.error('加载模板详情失败:', error); throw new Response('模板未找到', { status: 404 }); } - - return { template }; } export default function ContractTemplateDetail() { - const { template } = useLoaderData(); + const { template }: { template: ContractTemplate } = useLoaderData(); const navigate = useNavigate(); - const [isFavorited, setIsFavorited] = useState(false); + // 注释掉收藏功能 + // const [isFavorited, setIsFavorited] = useState(false); const handleBack = () => { navigate(-1); }; + // MinIO下载URL构建函数 + const buildDownloadUrl = (filePath: string): string => { + const minioHost = 'http://nas.7bm.co:9000'; + const bucketName = 'docauditai'; + + const cleanPath = filePath.startsWith('/') ? filePath.substring(1) : filePath; + return `${minioHost}/${bucketName}/${cleanPath}`; + }; + + // 下载文件函数 + const downloadFile = async (filePath: string, fileName: string) => { + try { + const downloadUrl = buildDownloadUrl(filePath); + + const cleanFileName = fileName.replace(/[<>:"/\\|?*]/g, '_'); + + const link = document.createElement('a'); + link.href = downloadUrl; + link.download = cleanFileName; + link.target = '_blank'; + + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + console.log('开始下载文件:', cleanFileName); + } catch (error) { + console.error('下载文件失败:', error); + alert('下载失败,请稍后重试'); + } + }; + const handleDownload = () => { - console.log('下载模板:', template.id); - // 这里应该是实际的下载逻辑 + if (template.file_path) { + const fileExtension = template.file_format || 'docx'; + const fileName = `${template.title}.${fileExtension}`; + downloadFile(template.file_path, fileName); + } else { + alert('文件路径不存在,无法下载'); + } }; const handlePreview = () => { console.log('预览模板:', template.id); - // 这里应该打开预览模态框或新页面 + // 页面内预览,滚动到预览区域 + const previewElement = document.getElementById('template-preview'); + if (previewElement) { + previewElement.scrollIntoView({ behavior: 'smooth' }); + } }; - const handleFavorite = () => { + /* const handleFavorite = () => { setIsFavorited(!isFavorited); console.log('收藏状态:', !isFavorited); - }; + }; */ - const handleShare = () => { - console.log('分享模板:', template.id); - // 这里应该是分享功能 - }; + /* const handleShare = () => { + // 复制当前页面URL到剪贴板 + navigator.clipboard.writeText(window.location.href).then(() => { + alert('链接已复制到剪贴板'); + }).catch(() => { + alert('复制失败,请手动复制链接'); + }); + }; */ - const renderStars = (rating: number) => { + // 注释掉评分相关功能 + /* const renderStars = (rating: number) => { const stars = []; const fullStars = Math.floor(rating); @@ -240,14 +226,14 @@ export default function ContractTemplateDetail() { } } return stars; - }; + }; */ // 创建文件内容对象用于FilePreview组件 - const fileContent = { + const fileContent = template.pdf_file_path ? { title: template.title, - contractNumber: template.templateCode, - // 设置PDF路径,FilePreview会自动拼接基础URL - path: 'contract-template/买卖合同/买卖合同范本.pdf', + contractNumber: template.template_code, + // 使用pdf_file_path字段 + path: template.pdf_file_path, parties: { partyA: { name: '', @@ -263,7 +249,7 @@ export default function ContractTemplateDetail() { } }, sections: [] - }; + } : null; return (
@@ -282,7 +268,8 @@ export default function ContractTemplateDetail() {
{/* 详情头部 */}
-
+ {/* 注释掉类型和评分显示 */} + {/*
{template.type}
@@ -290,20 +277,35 @@ export default function ContractTemplateDetail() { {template.rating} (156评价)
-
+
*/}

{template.title}

模板编号: - {template.templateCode} + {template.template_code}
更新时间: - {template.updateTime} + {new Date(template.updated_at).toLocaleDateString('zh-CN')}
+ 所属分类: + {template.category?.name || '其他'} +
+
+ 文件格式: + {template.file_format?.toUpperCase()} +
+ {template.is_featured && ( +
+ 特色推荐: + +
+ )} + {/* 注释掉使用次数、文件大小、适用范围、法律依据等字段 */} + {/*
使用次数: {template.useCount.toLocaleString()}次
@@ -318,7 +320,7 @@ export default function ContractTemplateDetail() {
法律依据: {template.legalBasis} -
+
*/}
@@ -329,27 +331,30 @@ export default function ContractTemplateDetail() { 立即下载使用 - - + )} + {/* 注释掉收藏功能 */} + {/* - + */}
@@ -359,14 +364,18 @@ export default function ContractTemplateDetail() {

模板简介

- {template.description}模板包含完整的合同条款结构, - 包括合同主体、标的物、价格条款、交付方式、付款条件、违约责任、争议解决等核心内容。 - 适用于各类烟草产品的销售业务,能够有效保护交易双方的合法权益。 + {template.description || '该合同模板为标准格式,包含完整的合同条款结构,适用于相关业务场景的合同签署。'} + {template.category?.description && ( + <> +

+ 适用范围:{template.category.description} + + )}

- {/* 主要特点 */} -
+ {/* 注释掉主要特点模块 */} + {/*

主要特点

{template.features.map((feature, index) => ( @@ -379,10 +388,10 @@ export default function ContractTemplateDetail() {
))}
-
+
*/} - {/* 合同条款结构 */} -
+ {/* 注释掉合同条款结构模块 */} + {/*

合同条款结构

{template.structure.map((item) => ( @@ -397,51 +406,53 @@ export default function ContractTemplateDetail() {
))}
-
+ */} - {/* 合同预览 */} -
-

合同预览

-
- {/* 使用更强的样式隔离 */} -
- + {/* 合同预览 - 只有当存在pdf_file_path时才显示 */} + {fileContent && ( +
+

合同预览

+
+ {/* 使用更强的样式隔离 */} +
+ +
-
+ )} - {/* 用户评价 */} -
+ {/* 注释掉用户评价模块 */} + {/*

用户评价

{template.reviews.map((review, index) => ( @@ -462,7 +473,7 @@ export default function ContractTemplateDetail() {
))}
-
+
*/}
diff --git a/app/routes/contract-template.list._index.tsx b/app/routes/contract-template.list._index.tsx index 743487c..49ccb04 100644 --- a/app/routes/contract-template.list._index.tsx +++ b/app/routes/contract-template.list._index.tsx @@ -24,25 +24,6 @@ export const meta: MetaFunction = () => { // 将数据库模板转换为前端显示格式 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 = '专业版'; - } */ - - // 添加调试信息 - console.log('原始模板数据:', template); - console.log('file_path:', template.file_path); - console.log('file_format:', template.file_format); - return { id: template.id.toString(), title: template.title,