From c17c80a5d4b4ceb8f4347e43da14c0c31c0615f7 Mon Sep 17 00:00:00 2001
From: tony.cheng <chengmingwei_1984122@126.com>
Date: Thu, 05 Feb 2026 18:27:19 +0800
Subject: [PATCH] feat: 完成法律条文查询API对接及优化

---
 web-app/src/components/tools/LawDetailContent.jsx |  185 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 132 insertions(+), 53 deletions(-)

diff --git a/web-app/src/components/tools/LawDetailContent.jsx b/web-app/src/components/tools/LawDetailContent.jsx
index f099af1..587fbdf 100644
--- a/web-app/src/components/tools/LawDetailContent.jsx
+++ b/web-app/src/components/tools/LawDetailContent.jsx
@@ -1,17 +1,105 @@
 import React, { useState, useEffect } from 'react';
-import { mockLawDetail } from '../../mocks/lawMocks';
+import { Spin, message } from 'antd';
+import LawAPIService from '../../services/LawAPIService';
 import './LawDetailContent.css';
 
+/**
+ * 格式化日期为 YYYY年MM月DD日 格式
+ * @param {string} dateStr - 日期字符串 YYYY-MM-DD
+ * @returns {string} 格式化后的日期
+ */
+const formatDate = (dateStr) => {
+  if (!dateStr) return '-';
+  try {
+    const date = new Date(dateStr);
+    const year = date.getFullYear();
+    const month = date.getMonth() + 1;
+    const day = date.getDate();
+    return `${year}年${month}月${day}日`;
+  } catch (error) {
+    return dateStr;
+  }
+};
+
+/**
+ * 从 provision_text 中提取章节列表
+ * @param {string} provisionText - 法律原文纯文本
+ * @returns {Array} 章节对象数组 [{id, title}, ...]
+ */
+const extractChapters = (provisionText) => {
+  if (!provisionText) return [];
+  
+  const startMarker = "\n\n目  录\n";
+  const endMarker = "\n\n第一章 总则\n\n";
+  
+  const startIndex = provisionText.indexOf(startMarker);
+  const endIndex = provisionText.indexOf(endMarker);
+  
+  if (startIndex === -1 || endIndex === -1) {
+    console.warn('未找到章节目录标记,跳过章节提取');
+    return [];
+  }
+  
+  const tocContent = provisionText.substring(
+    startIndex + startMarker.length, 
+    endIndex
+  );
+  
+  const lines = tocContent.split('\n').filter(line => line.trim());
+  
+  return lines.map((line, index) => ({
+    id: `chapter-${index + 1}`,
+    title: line.trim()
+  }));
+};
+
 const LawDetailContent = ({ lawId }) => {
-  const [activeChapter, setActiveChapter] = useState('chapter1');
+  const [loading, setLoading] = useState(false);
+  const [activeChapter, setActiveChapter] = useState(null);
   const [lawDetail, setLawDetail] = useState(null);
+  const [chapters, setChapters] = useState([]);
 
   useEffect(() => {
-    // 模拟根据 lawId 获取详情
-    setLawDetail(mockLawDetail);
+    const loadDetail = async () => {
+      if (!lawId) return;
+      
+      setLoading(true);
+      try {
+        const response = await LawAPIService.getLawOriginalDetail(lawId);
+        const detailData = response.data;
+        
+        // 从 provision_text 提取章节
+        const extractedChapters = extractChapters(detailData.provision_text || '');
+        
+        setLawDetail(detailData);
+        setChapters(extractedChapters);
+        
+        // 设置默认激活第一个章节
+        if (extractedChapters.length > 0) {
+          setActiveChapter(extractedChapters[0].id);
+        }
+      } catch (error) {
+        message.error('详情加载失败');
+        console.error('详情加载失败:', error);
+      } finally {
+        setLoading(false);
+      }
+    };
+    
+    loadDetail();
   }, [lawId]);
 
-  if (!lawDetail) return <div className="law-detail-loading">加载中...</div>;
+  if (loading) {
+    return (
+      <div className="law-detail-loading" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '400px' }}>
+        <Spin size="large" tip="加载中..." />
+      </div>
+    );
+  }
+
+  if (!lawDetail) {
+    return <div className="law-detail-loading">暂无数据</div>;
+  }
 
   const handleChapterClick = (chapterId) => {
     setActiveChapter(chapterId);
@@ -24,80 +112,71 @@
   return (
     <div className="law-detail-modal-body">
       {/* 章节导航 */}
-      <div className="law-detail-chapter-nav">
-        <h3 className="law-detail-chapter-nav-title">
-          <i className="fas fa-list-ol"></i>
-          章节导航
-        </h3>
-        <div className="law-detail-chapter-list">
-          {lawDetail.chapters.map((chapter) => (
-            <a
-              key={chapter.id}
-              href={`#${chapter.id}`}
-              className={`law-detail-chapter-link ${activeChapter === chapter.id ? 'active' : ''}`}
-              onClick={(e) => {
-                e.preventDefault();
-                handleChapterClick(chapter.id);
-              }}
-            >
-              {chapter.title}
-            </a>
-          ))}
+      {chapters.length > 0 && (
+        <div className="law-detail-chapter-nav">
+          <h3 className="law-detail-chapter-nav-title">
+            <i className="fas fa-list-ol"></i>
+            章节导航
+          </h3>
+          <div className="law-detail-chapter-list">
+            {chapters.map((chapter) => (
+              <a
+                key={chapter.id}
+                href={`#${chapter.id}`}
+                className={`law-detail-chapter-link ${activeChapter === chapter.id ? 'active' : ''}`}
+                onClick={(e) => {
+                  e.preventDefault();
+                  handleChapterClick(chapter.id);
+                }}
+              >
+                {chapter.title}
+              </a>
+            ))}
+          </div>
         </div>
-      </div>
+      )}
 
       {/* 法律详情容器 */}
       <div className="law-detail-main-container">
         <div className="law-detail-header">
-          <h2 className="law-detail-title">{lawDetail.lawName}</h2>
+          <h2 className="law-detail-title">{lawDetail.title || '未命名法律'}</h2>
           <div className="law-detail-meta-grid">
             <div className="law-detail-meta-item">
               <span className="law-detail-meta-label">时效性:</span>
-              <span className="law-detail-meta-value status-effective">{lawDetail.status}</span>
+              <span className="law-detail-meta-value status-effective">{lawDetail.validity_name || '其他'}</span>
             </div>
             <div className="law-detail-meta-item">
               <span className="law-detail-meta-label">法律效力位阶:</span>
-              <span className="law-detail-meta-value">{lawDetail.effectLevel}</span>
+              <span className="law-detail-meta-value">{lawDetail.law_nature_name || '-'}</span>
             </div>
             <div className="law-detail-meta-item">
               <span className="law-detail-meta-label">制定机关:</span>
-              <span className="law-detail-meta-value">{lawDetail.org}</span>
+              <span className="law-detail-meta-value">{lawDetail.authority_name || '-'}</span>
             </div>
             <div className="law-detail-meta-item">
               <span className="law-detail-meta-label">公布日期:</span>
-              <span className="law-detail-meta-value">{lawDetail.publishDate}</span>
+              <span className="law-detail-meta-value">{formatDate(lawDetail.publish_time)}</span>
             </div>
             <div className="law-detail-meta-item">
               <span className="law-detail-meta-label">实施日期:</span>
-              <span className="law-detail-meta-value">{lawDetail.effectiveDate}</span>
+              <span className="law-detail-meta-value">{formatDate(lawDetail.implementation_time)}</span>
             </div>
           </div>
         </div>
 
         <div className="law-detail-content-area">
-          {lawDetail.chapters.map((chapter) => (
-            <div className="law-detail-chapter-section" id={chapter.id} key={chapter.id}>
-              <h3 className="law-detail-chapter-title">
-                <i className="fas fa-bookmark"></i>
-                {chapter.title}
-              </h3>
-              <div className="law-detail-articles-container">
-                {chapter.articles.map((article, index) => (
-                  <div className="law-detail-article-item" key={index}>
-                    <div className="law-detail-article-number">{article.number}</div>
-                    <div className="law-detail-article-content">
-                      {article.content.split('\n').map((line, i) => (
-                        <React.Fragment key={i}>
-                          {line}
-                          {i < article.content.split('\n').length - 1 && <br />}
-                        </React.Fragment>
-                      ))}
-                    </div>
-                  </div>
-                ))}
-              </div>
+          {lawDetail.provision_text ? (
+            <div className="law-detail-provision-text">
+              {lawDetail.provision_text.split('\n').map((line, index) => (
+                <React.Fragment key={index}>
+                  {line}
+                  {index < lawDetail.provision_text.split('\n').length - 1 && <br />}
+                </React.Fragment>
+              ))}
             </div>
-          ))}
+          ) : (
+            <div className="law-detail-no-content">暂无详细内容</div>
+          )}
         </div>
       </div>
     </div>

--
Gitblit v1.8.0