From 823cf3819f2f91adeada3707435d40b3dac8f7b4 Mon Sep 17 00:00:00 2001
From: tony.cheng <chengmingwei_1984122@126.com>
Date: Fri, 06 Feb 2026 18:15:05 +0800
Subject: [PATCH] feat: 实现证据材料审查弹窗功能
---
web-app/src/components/tools/TypicalCaseDetailContent.jsx | 312 ++++++++++++++++++++++++++++++++++++---------------
1 files changed, 221 insertions(+), 91 deletions(-)
diff --git a/web-app/src/components/tools/TypicalCaseDetailContent.jsx b/web-app/src/components/tools/TypicalCaseDetailContent.jsx
index dbc8c9d..d2f94e1 100644
--- a/web-app/src/components/tools/TypicalCaseDetailContent.jsx
+++ b/web-app/src/components/tools/TypicalCaseDetailContent.jsx
@@ -1,158 +1,288 @@
-import React from 'react';
+import React, { useState, useEffect, useRef } from 'react';
+import { Button } from 'antd';
+import { UpOutlined } from '@ant-design/icons';
import './TypicalCaseDetailContent.css';
/**
- * 典型案例详情内容组件 - 与原型 case_search_detail.html 保持一致
+ * 典型案例详情内容组件 - 根据案例类型展示不同内容
+ * @param {Object} caseData - 案例数据
+ * @param {string} caseType - 案例类型 'judgment' | 'mediation'
*/
-const TypicalCaseDetailContent = ({ caseData }) => {
+const TypicalCaseDetailContent = ({ caseData, caseType }) => {
+ const [showBackToTop, setShowBackToTop] = useState(false);
+ const containerRef = useRef(null);
+
+ // 监听滚动事件 - Hooks必须在所有条件语句之前调用
+ useEffect(() => {
+ let modalBody = null;
+
+ const handleScroll = () => {
+ if (modalBody) {
+ // 当滚动超过300px时显示返回顶部按钮
+ setShowBackToTop(modalBody.scrollTop > 300);
+ }
+ };
+
+ // 延迟获取DOM元素,确保Modal完全渲染
+ const timer = setTimeout(() => {
+ modalBody = document.querySelector('.case-detail-antd-modal .ant-modal-body');
+ if (modalBody) {
+ modalBody.addEventListener('scroll', handleScroll);
+ // 初始检查滚动位置
+ handleScroll();
+ }
+ }, 100);
+
+ return () => {
+ clearTimeout(timer);
+ if (modalBody) {
+ modalBody.removeEventListener('scroll', handleScroll);
+ }
+ };
+ }, [caseData]); // 当caseData变化时重新绑定
+
+ // 提前返回条件必须在所有Hooks之后
if (!caseData) return <div className="case-detail-loading">加载中...</div>;
- const { caseTitle, caseType, disputeType, caseNumber, court, judgmentDate, region, disputeTime, content } = caseData;
+ // 返回顶部函数
+ const scrollToTop = () => {
+ const modalBody = document.querySelector('.case-detail-antd-modal .ant-modal-body');
+ if (modalBody) {
+ modalBody.scrollTo({
+ top: 0,
+ behavior: 'smooth'
+ });
+ }
+ };
+ // 日期格式化函数
+ const formatDate = (dateStr) => {
+ if (!dateStr) return '';
+ const date = new Date(dateStr);
+ if (isNaN(date.getTime())) return dateStr;
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0');
+ const day = String(date.getDate()).padStart(2, '0');
+ return `${year}年${month}月${day}日`;
+ };
+
+ // 调解案例详情展示
+ if (caseType === 'mediation') {
+ return (
+ <div className="case-detail-container">
+ {/* 案件基本信息 */}
+ <div className="case-detail-info-section">
+ <h2 className="case-detail-info-title">案件基本信息</h2>
+
+ {/* 第一行:案件标题 */}
+ {caseData.case_title && (
+ <div className="case-detail-info-full">
+ <span className="case-detail-info-label">案件标题:</span>
+ <span className="case-detail-info-value">{caseData.case_title}</span>
+ </div>
+ )}
+
+ {/* 第二行:其他信息 */}
+ <div className="case-detail-info-grid">
+ {caseData.occur_time && (
+ <div className="case-detail-info-item">
+ <span className="case-detail-info-label">纠纷发生时间:</span>
+ <span className="case-detail-info-value">{formatDate(caseData.occur_time)}</span>
+ </div>
+ )}
+ {(caseData.que_prov_name || caseData.que_city_name) && (
+ <div className="case-detail-info-item">
+ <span className="case-detail-info-label">发生地点:</span>
+ <span className="case-detail-info-value">
+ {caseData.que_prov_name || ''}/{caseData.que_city_name || ''}
+ </span>
+ </div>
+ )}
+ {caseData.case_type_first_name && (
+ <div className="case-detail-info-item">
+ <span className="case-detail-info-label">纠纷类型:</span>
+ <span className="case-detail-info-value">{caseData.case_type_first_name}</span>
+ </div>
+ )}
+ </div>
+ </div>
+
+ {/* 案件内容 */}
+ <div className="case-detail-body">
+ {/* 案例概述 */}
+ {caseData.case_des && (
+ <div className="case-detail-section">
+ <h3 className="case-detail-section-title">案例概述</h3>
+ <div className="case-detail-section-content">
+ <p>{caseData.case_des}</p>
+ </div>
+ </div>
+ )}
+
+ {/* 原告诉讼请求 */}
+ {caseData.case_claim && (
+ <div className="case-detail-section">
+ <h3 className="case-detail-section-title">原告诉讼请求</h3>
+ <div className="case-detail-section-content case-detail-plaintiff-demand">
+ <p>{caseData.case_claim}</p>
+ </div>
+ </div>
+ )}
+
+ {/* 调解结果 */}
+ {caseData.agree_content && (
+ <div className="case-detail-section">
+ <h3 className="case-detail-section-title">调解结果</h3>
+ <div className="case-detail-section-content case-detail-mediation-result">
+ <p>{caseData.agree_content}</p>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ );
+ }
+
+ // 判决文书详情展示
return (
<div className="case-detail-container">
{/* 案件基本信息 */}
<div className="case-detail-info-section">
<h2 className="case-detail-info-title">案件基本信息</h2>
+
+ {/* 第一行:案件标题和案号 */}
+ <div className="case-detail-info-full">
+ {caseData.case_name && (
+ <>
+ <span className="case-detail-info-label">案件标题:</span>
+ <span className="case-detail-info-value">{caseData.case_name}</span>
+ </>
+ )}
+ {caseData.case_number && (
+ <>
+ <span className="case-detail-info-label" style={{ marginLeft: '30px' }}>案号:</span>
+ <span className="case-detail-info-value">{caseData.case_number}</span>
+ </>
+ )}
+ </div>
+
+ {/* 第二行:其他信息 */}
<div className="case-detail-info-grid">
- <div className="case-detail-info-item">
- <span className="case-detail-info-label">纠纷发生时间:</span>
- <span className="case-detail-info-value">{disputeTime || '2024-4-12 12:00'}</span>
- </div>
- <div className="case-detail-info-item">
- <span className="case-detail-info-label">发生地点:</span>
- <span className="case-detail-info-value">{region || '广东省/广州市'}</span>
- </div>
- <div className="case-detail-info-item">
- <span className="case-detail-info-label">纠纷类型:</span>
- <span className="case-detail-info-value">{disputeType}</span>
- </div>
- <div className="case-detail-info-item">
- <span className="case-detail-info-label">调解组织:</span>
- <span className="case-detail-info-value">{court || '白云区新市街综治中心'}</span>
- </div>
+ {caseData.judgment_date && (
+ <div className="case-detail-info-item">
+ <span className="case-detail-info-label">判决日期:</span>
+ <span className="case-detail-info-value">{formatDate(caseData.judgment_date)}</span>
+ </div>
+ )}
+ {caseData.court && (
+ <div className="case-detail-info-item">
+ <span className="case-detail-info-label">发生地点:</span>
+ <span className="case-detail-info-value">{caseData.court}</span>
+ </div>
+ )}
+ {caseData.case_reason && (
+ <div className="case-detail-info-item">
+ <span className="case-detail-info-label">纠纷类型:</span>
+ <span className="case-detail-info-value">{caseData.case_reason}</span>
+ </div>
+ )}
</div>
</div>
{/* 案件内容 */}
<div className="case-detail-body">
- {content?.overview && (
+ {/* 案例概述 */}
+ {caseData.basic_case_info && (
<div className="case-detail-section">
<h3 className="case-detail-section-title">案例概述</h3>
<div className="case-detail-section-content">
- {content.overview.split('\n').map((para, i) => (
- <p key={i}>{para}</p>
- ))}
+ <p>{caseData.basic_case_info}</p>
</div>
</div>
)}
- {content?.plaintiffDemand && content.plaintiffDemand.length > 0 && (
+ {/* 原告介绍 */}
+ {caseData.plaintiff && (
<div className="case-detail-section">
- <h3 className="case-detail-section-title">原告诉讼请求</h3>
+ <h3 className="case-detail-section-title">原告介绍</h3>
<div className="case-detail-section-content case-detail-plaintiff-demand">
- <div className="case-detail-inner-content">
- <p>原告{caseData.plaintiff || '黄某'}起诉请求:</p>
- <ol>
- {content.plaintiffDemand.map((item, i) => (
- <li key={i}>{item}</li>
- ))}
- </ol>
- </div>
+ <p>{caseData.plaintiff}</p>
</div>
</div>
)}
- {content?.courtDecision && (
+ {/* 被告介绍 */}
+ {caseData.defendant && (
+ <div className="case-detail-section">
+ <h3 className="case-detail-section-title">被告介绍</h3>
+ <div className="case-detail-section-content">
+ <p>{caseData.defendant}</p>
+ </div>
+ </div>
+ )}
+
+ {/* 法院审理与判决 */}
+ {caseData.trial_finding && (
<div className="case-detail-section">
<h3 className="case-detail-section-title">法院审理与判决</h3>
<div className="case-detail-section-content case-detail-court-decision">
- <div className="case-detail-inner-content">
- {content.courtDecision.split('\n').map((para, i) => (
- <p key={i}>{para}</p>
- ))}
- </div>
+ <p>{caseData.trial_finding}</p>
</div>
</div>
)}
- {content?.mediationBackground && (
+ {/* 审理经过 */}
+ {caseData.trial_process && (
<div className="case-detail-section">
- <h3 className="case-detail-section-title">调解背景</h3>
- <div className="case-detail-section-content">
- <p>{content.mediationBackground}</p>
- </div>
- </div>
- )}
-
- {content?.partiesPosition && (
- <div className="case-detail-section">
- <h3 className="case-detail-section-title">双方立场</h3>
- <div className="case-detail-section-content">
- <p><strong>{caseData.plaintiff || '黄某'}表示:</strong>{content.partiesPosition.plaintiff}</p>
- <p><strong>{caseData.defendant || '郭某'}认为:</strong>{content.partiesPosition.defendant}</p>
- </div>
- </div>
- )}
-
- {content?.mediationProcess && (
- <div className="case-detail-section">
- <h3 className="case-detail-section-title">调解过程</h3>
+ <h3 className="case-detail-section-title">审理经过</h3>
<div className="case-detail-section-content case-detail-mediation-process">
- <p>{content.mediationProcess}</p>
+ <p>{caseData.trial_process}</p>
</div>
</div>
)}
- {content?.mediationScheme && content.mediationScheme.length > 0 && (
+ {/* 审理程序 */}
+ {caseData.trial_procedure && (
<div className="case-detail-section">
- <h3 className="case-detail-section-title">调解方案</h3>
+ <h3 className="case-detail-section-title">审理程序</h3>
<div className="case-detail-section-content case-detail-mediation-scheme">
- <p>法官提出的调解方案:</p>
- <ul>
- {content.mediationScheme.map((item, i) => (
- <li key={i}>{item}</li>
- ))}
- </ul>
+ <p>{caseData.trial_procedure}</p>
</div>
</div>
)}
- {content?.mediationResult && (
+ {/* 调解结果 */}
+ {caseData.judgment && (
<div className="case-detail-section">
<h3 className="case-detail-section-title">调解结果</h3>
<div className="case-detail-section-content case-detail-mediation-result">
- <div className="case-detail-inner-content">
- <p>经过进一步的协商,双方最终接受了法官提出的调解方案。</p>
- <ol>
- {content.mediationResult.items.map((item, i) => (
- <li key={i}>{item}</li>
- ))}
- </ol>
- {content.mediationResult.note && (
- <div className="case-detail-note">
- <p>{content.mediationResult.note}</p>
- </div>
- )}
- </div>
+ <p>{caseData.judgment}</p>
</div>
</div>
)}
- {content?.legalArticles && content.legalArticles.length > 0 && (
+ {/* 案例相关法律条文 */}
+ {caseData.legal_basis && (
<div className="case-detail-section">
<h3 className="case-detail-section-title">案例相关法律条文</h3>
<div className="case-detail-section-content case-detail-legal-articles">
- {content.legalArticles.map((article, i) => (
- <div className="case-detail-article" key={i}>
- <div className="case-detail-article-title">{article.title}</div>
- <p>{article.content}</p>
- </div>
- ))}
+ <p>{caseData.legal_basis}</p>
</div>
</div>
)}
</div>
+
+ {/* 返回顶部按钮 */}
+ {showBackToTop && (
+ <Button
+ type="primary"
+ shape="circle"
+ icon={<UpOutlined />}
+ size="large"
+ className="back-to-top-btn"
+ onClick={scrollToTop}
+ />
+ )}
</div>
);
};
--
Gitblit v1.8.0