| | |
| | | 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">{disputeTime || '2024-4-12 12:00'}</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">{region || '广东省/广州市'}</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">{disputeType}</span> |
| | | <span className="case-detail-info-value">{caseData.case_type_first_name}</span> |
| | | </div> |
| | | <div className="case-detail-info-item"> |
| | | <span className="case-detail-info-label">调解组织:</span> |
| | | <span className="case-detail-info-value">{court || '白云区新市街综治中心'}</span> |
| | | </div> |
| | | )} |
| | | </div> |
| | | </div> |
| | | |
| | | {/* 案件内容 */} |
| | | <div className="case-detail-body"> |
| | | {content?.overview && ( |
| | | {/* 案例概述 */} |
| | | {caseData.case_des && ( |
| | | <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.case_des}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {content?.plaintiffDemand && content.plaintiffDemand.length > 0 && ( |
| | | {/* 原告诉讼请求 */} |
| | | {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"> |
| | | <div className="case-detail-inner-content"> |
| | | <p>原告{caseData.plaintiff || '黄某'}起诉请求:</p> |
| | | <ol> |
| | | {content.plaintiffDemand.map((item, i) => ( |
| | | <li key={i}>{item}</li> |
| | | ))} |
| | | </ol> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {content?.courtDecision && ( |
| | | <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> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {content?.mediationBackground && ( |
| | | <div className="case-detail-section"> |
| | | <h3 className="case-detail-section-title">调解背景</h3> |
| | | <div className="case-detail-section-content"> |
| | | <p>{content.mediationBackground}</p> |
| | | <p>{caseData.case_claim}</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> |
| | | <div className="case-detail-section-content case-detail-mediation-process"> |
| | | <p>{content.mediationProcess}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {content?.mediationScheme && content.mediationScheme.length > 0 && ( |
| | | <div className="case-detail-section"> |
| | | <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> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {content?.mediationResult && ( |
| | | {/* 调解结果 */} |
| | | {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"> |
| | | <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> |
| | | <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"> |
| | | {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"> |
| | | {/* 案例概述 */} |
| | | {caseData.basic_case_info && ( |
| | | <div className="case-detail-section"> |
| | | <h3 className="case-detail-section-title">案例概述</h3> |
| | | <div className="case-detail-section-content"> |
| | | <p>{caseData.basic_case_info}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {content?.legalArticles && content.legalArticles.length > 0 && ( |
| | | {/* 原告介绍 */} |
| | | {caseData.plaintiff && ( |
| | | <div className="case-detail-section"> |
| | | <h3 className="case-detail-section-title">原告介绍</h3> |
| | | <div className="case-detail-section-content case-detail-plaintiff-demand"> |
| | | <p>{caseData.plaintiff}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {/* 被告介绍 */} |
| | | {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"> |
| | | <p>{caseData.trial_finding}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {/* 审理经过 */} |
| | | {caseData.trial_process && ( |
| | | <div className="case-detail-section"> |
| | | <h3 className="case-detail-section-title">审理经过</h3> |
| | | <div className="case-detail-section-content case-detail-mediation-process"> |
| | | <p>{caseData.trial_process}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {/* 审理程序 */} |
| | | {caseData.trial_procedure && ( |
| | | <div className="case-detail-section"> |
| | | <h3 className="case-detail-section-title">审理程序</h3> |
| | | <div className="case-detail-section-content case-detail-mediation-scheme"> |
| | | <p>{caseData.trial_procedure}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {/* 调解结果 */} |
| | | {caseData.judgment && ( |
| | | <div className="case-detail-section"> |
| | | <h3 className="case-detail-section-title">调解结果</h3> |
| | | <div className="case-detail-section-content case-detail-mediation-result"> |
| | | <p>{caseData.judgment}</p> |
| | | </div> |
| | | </div> |
| | | )} |
| | | |
| | | {/* 案例相关法律条文 */} |
| | | {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> |
| | | ); |
| | | }; |