From d100657dacb25df91013ef25432620e6ae10d1f8 Mon Sep 17 00:00:00 2001
From: shimai <shimai@example.com>
Date: Thu, 09 Apr 2026 16:56:44 +0800
Subject: [PATCH] feat:增加白云案件类案数据

---
 web-app/src/components/dashboard/TabContainer.jsx | 1451 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 1,278 insertions(+), 173 deletions(-)

diff --git a/web-app/src/components/dashboard/TabContainer.jsx b/web-app/src/components/dashboard/TabContainer.jsx
index 2b42c5f..e390898 100644
--- a/web-app/src/components/dashboard/TabContainer.jsx
+++ b/web-app/src/components/dashboard/TabContainer.jsx
@@ -1,21 +1,48 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
 import { useCaseData } from '../../contexts/CaseDataContext';
-import { formatDuration, formatSuccessRate, formatRoundCount } from '../../utils/stateTranslator';
+import { formatDuration, formatSuccessRate } from '../../utils/stateTranslator';
 import ProcessAPIService from '../../services/ProcessAPIService';
-import { message, Spin } from 'antd';
+import EvidenceAPIService from '../../services/EvidenceAPIService';
+import MediationAgreementAPIService from '../../services/MediationAgreementAPIService';
+import { getMergedParams } from '../../utils/urlParams';
+import { message, Spin, Tag, Modal, Button, Input, Image } from 'antd';
+import { PhoneOutlined } from '@ant-design/icons';
+import { CallRecordModal } from '../call-record';
+
+// 新增组件导入
+import PartyInfoCard from './PartyInfoCard';
+import NegotiationProgress from './NegotiationProgress';
+import AISuggestionCard from './AISuggestionCard';
+
+const { TextArea } = Input;
 
 /**
  * 选项卡容器组件 - 4个选项卡
+ * 通过 forwardRef 暴露 switchTab 方法供父组件调用
  */
-const TabContainer = () => {
+const TabContainer = forwardRef((props, ref) => {
   const [activeTab, setActiveTab] = useState('mediation-data-board');
+  // 证据材料汇总Tab的审核状态badge
+  const [evidenceBadge, setEvidenceBadge] = useState(null);
+
+  // 暴露 switchTab 方法给父组件
+  useImperativeHandle(ref, () => ({
+    switchTab: (tabKey) => {
+      setActiveTab(tabKey);
+    }
+  }));
 
   const tabs = [
     { key: 'mediation-data-board', label: '调解分析', icon: 'fa-chart-line' },
     { key: 'mediation-board', label: 'AI调解实时看板', icon: 'fa-tv' },
-    { key: 'evidence-board', label: '证据材料汇总', icon: 'fa-file-alt', badge: '待审核' },
+    { key: 'evidence-board', label: '证据材料汇总', icon: 'fa-file-alt', badge: evidenceBadge },
     { key: 'agreement-section', label: '调解协议', icon: 'fa-file-contract', badge: '待确认' },
   ];
+
+  // 更新证据材料汇总Tab的badge状态
+  const handleEvidenceStatusChange = (status) => {
+    setEvidenceBadge(status);
+  };
 
   return (
     <div className="tab-container">
@@ -51,7 +78,7 @@
         {/* 证据材料汇总 */}
         <div className={`tab-pane ${activeTab === 'evidence-board' ? 'active' : ''}`}>
           <div className="tab-content-area">
-            <EvidenceBoard />
+            <EvidenceBoard onStatusChange={handleEvidenceStatusChange} />
           </div>
         </div>
 
@@ -64,6 +91,29 @@
       </div>
     </div>
   );
+});
+
+/**
+ * 获取成功率同比数据
+ */
+const getSuccessRateYoY = (mediation) => {
+  // 优先使用API返回的同比值
+  if (mediation?.yoy_success_rate !== undefined && mediation?.yoy_success_rate !== null) {
+    return {
+      rate: mediation.yoy_success_rate,
+      hours: mediation.yoy_before_hours || 0
+    };
+  }
+  
+  // 计算同比值
+  const currentRate = mediation?.success_rate || 0;
+  const lastRate = mediation?.last_success_rate || 0;
+  const diff = (currentRate - lastRate) * 100;
+  
+  return {
+    rate: diff,
+    hours: mediation?.yoy_before_hours || 0
+  };
 };
 
 /**
@@ -72,17 +122,25 @@
 const MediationDataBoard = () => {
   const { caseData } = useCaseData();
   const timeline = caseData || {};
+  const mediation = timeline.mediation || {};
   
   // 从 timeline 获取数据
   const gapContent = timeline.result || '暂无分歧分析';
   const updateTime = formatDuration(timeline.before_duration);
-  const successRate = formatSuccessRate(timeline.mediation?.success_rate);
-  const roundCount = formatRoundCount(timeline.mediation?.mediation_count);
+  const successRate = formatSuccessRate(mediation.success_rate);
+  
+  // 获取成功率数值(用于进度条)
+  const successRateValue = (mediation.success_rate || 0) * 100;
+  
+  // 获取同比数据
+  const yoyData = getSuccessRateYoY(mediation);
+  const yoyRate = yoyData.rate >= 0 ? `+${yoyData.rate.toFixed(0)}%` : `${yoyData.rate.toFixed(0)}%`;
+  const yoyHours = yoyData.hours;
   
   return (
     <div className="mediation-metrics">
-      {/* 左侧:诉求差距分析 */}
-      <div className="metric-card">
+      {/* 左侧:诉求差距分析 + AI建议 */}
+      <div className="metric-card left-column">
         <div className="metric-title">
           <i className="fas fa-exclamation-circle"></i>
           <span>诉求差距分析</span>
@@ -98,28 +156,36 @@
               {gapContent}
             </div>
           </div>
+          {/* AI调解建议 */}
+          <AISuggestionCard />
         </div>
       </div>
 
-      {/* 右侧:调解数据 */}
-      <div className="metric-card">
-        <div className="metric-title">
-          <i className="fas fa-exchange-alt"></i>
-          <span>调解数据</span>
-        </div>
-        <div className="metric-content">
-          <div className="success-metric">
-            <div className="success-value">{successRate}</div>
-            <div className="success-label">预计调解成功概率</div>
-            <div className="success-change">
-              
-              {/* <i className="fas fa-arrow-up"></i><span>较{updateTime} +8%</span> */}
+      {/* 右侧:申请双方 + 成功率 + 协商沟通 */}
+      <div className="metric-card right-column">
+        {/* 申请双方信息 */}
+        <PartyInfoCard />
+        
+        {/* 预计调解成功率 */}
+        <div className="success-rate-section">
+          <div className="success-rate-label">预计调解成功率</div>
+          <div className="success-rate-row">
+            <span className="success-rate-value">{successRate}</span>
+            <div className="success-rate-yoy">
+              <img src="/mom.png" alt="" className="yoy-icon-img" />
+              <span className="yoy-rate">{yoyRate}</span>
+              <span className="yoy-time">较{yoyHours}小时前</span>
             </div>
-            <div style={{ marginTop: 15, fontSize: '0.9rem', color: 'var(--gray-color)' }}>
-              协商沟通:<span style={{ color: 'var(--dark-color)', fontWeight: 600 }}>{roundCount}</span>
+          </div>
+          <div className="success-rate-progress">
+            <div className="progress-bar-bg">
+              <div className="progress-bar-fill" style={{ width: `${successRateValue}%` }}></div>
             </div>
           </div>
         </div>
+        
+        {/* 协商沟通进度 */}
+        <NegotiationProgress />
       </div>
     </div>
   );
@@ -133,17 +199,36 @@
   const [records, setRecords] = useState([]);
   const [loading, setLoading] = useState(false);
   const [error, setError] = useState(null);
+  // 通话记录弹窗状态
+  const [callRecordVisible, setCallRecordVisible] = useState(false);
+  const [currentRecord, setCurrentRecord] = useState(null);
   
   // 获取案件数据
   const { caseData } = useCaseData();
   const timeline = caseData || {};
-  
+  const caseState = timeline.mediation?.state;
+
+
+  // 格式化时间戳为 YYYY-MM-DD HH:MM:SS
+  const formatTimestamp = (timestamp) => {
+    if (!timestamp) return '';
+    const date = new Date(timestamp);
+    const year = date.getFullYear();
+    const month = String(date.getMonth() + 1).padStart(2, '0');
+    const day = String(date.getDate()).padStart(2, '0');
+    const hours = String(date.getHours()).padStart(2, '0');
+    const minutes = String(date.getMinutes()).padStart(2, '0');
+    const seconds = String(date.getSeconds()).padStart(2, '0');
+    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+  };
+
   // person_type到avatar类型的映射
+  // 1: 申请人, 2: 被申请人, 3: AI调解员, 4: 调解员
   const getAvatarType = (personType) => {
     const typeMap = {
-      '1': 'ai',
-      '2': 'applicant',
-      '3': 'respondent',
+      '1': 'applicant',
+      '2': 'respondent',
+      '3': 'ai',
       '4': 'mediator'
     };
     return typeMap[personType] || 'ai';
@@ -161,23 +246,25 @@
   };
   
   // 获取角色显示名称
+  // 1: 申请人, 2: 被申请人, 3: AI调解员, 4: 调解员
   const getRoleDisplayName = (personType, creatorName) => {
     const roleMap = {
-      '1': 'AI调解员',
-      '2': `申请人(${creatorName})`,
-      '3': `被申请人(${creatorName})`,
+      '1': `申请人(${creatorName})`,
+      '2': `被申请人(${creatorName})`,
+      '3': 'AI调解员',
       '4': `调解员(${creatorName})`
     };
     return roleMap[personType] || creatorName;
   };
   
-  // 数据格式化函数
+  // 数据格式化函数(保留原始数据字段用于通话记录功能)
   const formatRecordData = (apiRecords) => {
     return apiRecords.map(record => ({
+      ...record, // 保留原始数据字段(person_id, job_id, creator等)
       avatar: getAvatarType(record.person_type),
       name: getRoleDisplayName(record.person_type, record.creator),
-      avatarText: record.creator?.charAt(0) || '',  // 头像显示名字第一个字
-      time: record.create_time,
+      avatarText: record.creator?.charAt(0) || '',
+      time: formatTimestamp(record.create_time),
       content: record.result,
       tags: record.tagList?.map(tag => ({
         text: tag.tag_name,
@@ -373,7 +460,40 @@
                 {getAvatarContent(item.avatar, item.avatarText)}
               </div>
               <div className="item-source">
-                <div style={{ fontWeight: 600, fontSize: '0.95rem', color: 'var(--dark-color)', marginBottom: 2 }}>{item.name}</div>
+                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
+                  <span style={{ fontWeight: 600, fontSize: '0.95rem', color: 'var(--dark-color)' }}>{item.name}</span>
+                  {item.avatar !== 'ai' && item.avatar !== 'mediator' && (
+                    <span 
+                      className="call-record-btn"
+                      style={{
+                        display: 'inline-flex',
+                        alignItems: 'center',
+                        gap: 4,
+                        padding: '2px 8px',
+                        fontSize: '0.75rem',
+                        background: '#e3f2fd',
+                        color: '#1890ff',
+                        borderRadius: 12,
+                        cursor: 'pointer',
+                        transition: 'all 0.2s'
+                      }}
+                      onClick={(e) => {
+                        e.stopPropagation();
+                        setCurrentRecord(item);
+                        setCallRecordVisible(true);
+                      }}
+                      onMouseEnter={(e) => {
+                        e.target.style.background = '#bbdefb';
+                      }}
+                      onMouseLeave={(e) => {
+                        e.target.style.background = '#e3f2fd';
+                      }}
+                    >
+                      <PhoneOutlined style={{ fontSize: 12 }} />
+                      通话记录
+                    </span>
+                  )}
+                </div>
                 <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)', display: 'flex', alignItems: 'center', gap: 6 }}>
                   <i className="far fa-clock"></i>
                   <span>{item.time}</span>
@@ -419,6 +539,13 @@
           </div>
         ))}
       </div>
+      
+      {/* 通话记录弹窗 */}
+      <CallRecordModal
+        visible={callRecordVisible}
+        onClose={() => setCallRecordVisible(false)}
+        record={currentRecord}
+      />
     </>
   );
 };
@@ -426,20 +553,281 @@
 /**
  * 证据材料汇总
  */
-const EvidenceBoard = () => {
-  const applicantEvidence = [
-    { name: '劳动合同', desc: '2023年8月1日-2026年1月31日,约定月工资¥14,000', time: '2026-01-15 09:35', status: 'verified' },
-    { name: '2026年1-3月工资条', desc: '显示工资发放记录,1月后无发放记录', time: '2026-01-15 09:36', status: 'verified' },
-    { name: '2026年第一季度考勤记录', desc: '显示全勤,无请假缺勤记录', time: '2026-01-15 09:37', status: 'verified' },
-    { name: '绩效考评表', desc: '第一季度绩效评分85分,达到奖金发放标准', time: '2026-01-15 09:38', status: 'verified' },
-    { name: '解除劳动合同通知书', desc: '公司2026年1月15日单方面解除合同', time: '2026-01-15 09:45', status: 'pending' },
-  ];
+const EvidenceBoard = ({ onStatusChange }) => {
+  // 从 Context 获取证据材料数据
+  const { evidenceData, loadEvidenceData } = useCaseData();
+  const { applicantMaterials, respondentMaterials, loading, error } = evidenceData;
+  
+  // 审核弹窗状态
+  const [auditModalVisible, setAuditModalVisible] = useState(false);
+  const [currentAuditItem, setCurrentAuditItem] = useState(null);
+  const [auditRemark, setAuditRemark] = useState('');
+  const [auditLoading, setAuditLoading] = useState(false);
+  const [returnModalVisible, setReturnModalVisible] = useState(false);
+  // 弹窗数据状态
+  const [modalDataLoading, setModalDataLoading] = useState(false);
+  const [personInfo, setPersonInfo] = useState(null);
+  const [evidenceImages, setEvidenceImages] = useState([]);
+  const [platformUrl, setPlatformUrl] = useState('');
 
-  const respondentEvidence = [
-    { name: '2026年1-3月考勤异常记录', desc: '显示李晓明1月有2天事假,应扣款¥1,333', time: '2026-01-15 09:50', status: 'pending' },
-    { name: '第一季度销售业绩报表', desc: '显示李晓明未完成销售KPI指标(完成率87%)', time: '2026-01-15 09:52', status: 'pending' },
-    { name: '员工离职申请表', desc: '李晓明2026年1月10日提交的辞职申请', time: '2026-01-15 09:55', status: 'pending' },
-  ];
+  // 计算整体审核状态(综合申请人和被申请人所有材料)
+  const calculateOverallTabStatus = (applicantList, respondentList) => {
+    const allMaterials = [...applicantList, ...respondentList];
+    if (!allMaterials || allMaterials.length === 0) return null;
+    
+    // 存在驳回状态 -> 显示"驳回"
+    const hasRejected = allMaterials.some(m => m.audit_state === -2);
+    if (hasRejected) return '驳回';
+    
+    // 存在待审核状态(0或-2) -> 显示"待审核"
+    const hasPending = allMaterials.some(m => m.audit_state === 0 || m.audit_state === -2);
+    if (hasPending) return '待审核';
+    
+    // 所有材料都已审核 -> 显示"已审核"
+    return '已审核';
+  };
+
+  // 监听数据变化,通知Tab标题状态
+  useEffect(() => {
+    const overallStatus = calculateOverallTabStatus(applicantMaterials, respondentMaterials);
+    if (onStatusChange) {
+      onStatusChange(overallStatus);
+    }
+  }, [applicantMaterials, respondentMaterials]); // eslint-disable-line react-hooks/exhaustive-deps
+
+  // 重新加载函数
+  const handleReload = () => {
+    const params = getMergedParams();
+    loadEvidenceData({
+      caseId: params.caseId,
+      caseType: params.caseType || params.caseTypeFirst,
+      caseTypeFirst: params.caseTypeFirst,
+      platformCode: params.platform_code
+    });
+  };
+
+  // 计算区域内整体审核状态(用于卡片标题旁的Tag显示)
+  const calculateOverallStatus = (materials) => {
+    if (!materials || materials.length === 0) return { text: '无数据', color: 'default' };
+    const hasRejected = materials.some(m => m.audit_state === -2);
+    if (hasRejected) return { text: '驳回', color: 'red' };
+    const hasPending = materials.some(m => m.audit_state === 0 || m.audit_state === -2);
+    if (hasPending) return { text: '待审核', color: 'orange' };
+    return { text: '已审核', color: 'green' };
+  };
+
+  const applicantStatus = calculateOverallStatus(applicantMaterials);
+  const respondentStatus = calculateOverallStatus(respondentMaterials);
+
+  // Loading状态
+  if (loading) {
+    return (
+      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: 300 }}>
+        <Spin size="large" tip="加载证据材料中..." />
+      </div>
+    );
+  }
+
+  // 错误状态
+  if (error) {
+    return (
+      <div style={{ textAlign: 'center', padding: 40, color: '#ff4d4f' }}>
+        <div style={{ fontSize: '1.2rem', marginBottom: 10 }}>
+          <i className="fas fa-exclamation-circle"></i> 数据加载失败
+        </div>
+        <div>{error}</div>
+        <button onClick={handleReload} style={{
+          marginTop: 15, padding: '8px 16px', backgroundColor: '#1890ff',
+          color: 'white', border: 'none', borderRadius: 4, cursor: 'pointer'
+        }}>重新加载</button>
+      </div>
+    );
+  }
+
+  // 获取材料审核状态样式
+  const getAuditStatusStyle = (auditState) => {
+    if (auditState === 1) {
+      // 已审核 - 绿色边框
+      return {
+        color: '#52c41a',
+        background: '#f6ffed',
+        border: '1px solid #b7eb8f',
+        borderRadius: 4,
+        padding: '2px 10px',
+        fontSize: '0.8rem',
+        fontWeight: 500,
+      };
+    }
+    // 待审核 - 橙色边框
+    return {
+      color: '#fa8c16',
+      background: '#fff7e6',
+      border: '1px solid #ffd591',
+      borderRadius: 4,
+      padding: '2px 10px',
+      fontSize: '0.8rem',
+      fontWeight: 500,
+    };
+  };
+
+  // 打开审核弹窗
+  const handleOpenAuditModal = async (item, type) => {
+    // 获取参数
+    const params = getMergedParams();
+    const caseId = params.caseId;
+    
+    // 设置当前审核项
+    const auditItem = { 
+      ...item, 
+      personType: type,
+      per_type: type === 'applicant' ? '15_020008-1' : '15_020008-2'
+    };
+    setCurrentAuditItem(auditItem);
+    setAuditRemark('');
+    setAuditModalVisible(true);
+    
+    // 获取platform_url
+    try {
+      const caseDataTimeline = JSON.parse(localStorage.getItem('case_data_timeline') || '{}');
+      const pUrl = caseDataTimeline?.process_config?.platform_url || '';
+      setPlatformUrl(pUrl);
+    } catch (e) {
+      console.warn('获取platform_url失败:', e);
+    }
+    
+    // 调用API获取弹窗数据
+    setModalDataLoading(true);
+    setPersonInfo(null);
+    setEvidenceImages([]);
+    
+    try {
+      // 并行调用两个API
+      const [personInfoRes, evidenceListRes] = await Promise.all([
+        EvidenceAPIService.getPersonInfo({
+          case_id: caseId,
+          evidence_type: item.evidence_type,
+          per_type: auditItem.per_type
+        }),
+        EvidenceAPIService.getEvidenceListByPerson({
+          case_id: caseId,
+          evidence_type: item.evidence_type,
+          per_type: auditItem.per_type,
+          person_id: item.person_id
+        })
+      ]);
+      
+      console.log('getPersonInfo response:', personInfoRes);
+      console.log('getEvidenceListByPerson response:', evidenceListRes);
+      
+      // 设置当事人信息
+      if (personInfoRes?.data) {
+        setPersonInfo(personInfoRes.data);
+      }
+      
+      // 设置图片列表
+      if (evidenceListRes?.data && Array.isArray(evidenceListRes.data)) {
+        setEvidenceImages(evidenceListRes.data);
+      }
+    } catch (err) {
+      console.error('加载弹窗数据失败:', err);
+      message.error('加载材料详情失败');
+    } finally {
+      setModalDataLoading(false);
+    }
+  };
+
+  // 关闭审核弹窗
+  const handleCloseAuditModal = () => {
+    setAuditModalVisible(false);
+    setCurrentAuditItem(null);
+    setAuditRemark('');
+    setPersonInfo(null);
+    setEvidenceImages([]);
+  };
+
+  // 审核通过
+  const handleAuditPass = async () => {
+    if (!currentAuditItem) return;
+    
+    const params = getMergedParams();
+    const caseId = params.caseId;
+    
+    setAuditLoading(true);
+    try {
+      // 获取文件ID列表
+      const fileIdList = evidenceImages.map(img => img.file_id || img.id).filter(Boolean);
+      
+      await EvidenceAPIService.auditEvidence({
+        case_id: caseId,
+        evidence_type: currentAuditItem.evidence_type,
+        person_id: currentAuditItem.person_id,
+        file_id_list: fileIdList,
+        audit_user: '当前用户', // TODO: 从登录信息获取
+        audit_state: 1,
+        audit_remark: ''
+      });
+      
+      message.success('审核通过!');
+      handleCloseAuditModal();
+      // 重新加载数据
+      handleReload();
+    } catch (err) {
+      console.error('审核失败:', err);
+      message.error('审核失败,请重试');
+    } finally {
+      setAuditLoading(false);
+    }
+  };
+
+  // 退回补充
+  const handleAuditReturn = async () => {
+    if (!currentAuditItem) return;
+    if (!auditRemark.trim()) {
+      message.warning('请填写退回意见');
+      return;
+    }
+    
+    const params = getMergedParams();
+    const caseId = params.caseId;
+    
+    setAuditLoading(true);
+    try {
+      // 获取文件ID列表
+      const fileIdList = evidenceImages.map(img => img.file_id || img.id).filter(Boolean);
+      
+      await EvidenceAPIService.auditEvidence({
+        case_id: caseId,
+        evidence_type: currentAuditItem.evidence_type,
+        person_id: currentAuditItem.person_id,
+        file_id_list: fileIdList,
+        audit_user: '当前用户', // TODO: 从登录信息获取
+        audit_state: 2,
+        audit_remark: auditRemark.trim()
+      });
+      
+      message.success('材料已退回,等待补充提交');
+      setReturnModalVisible(false);
+      handleCloseAuditModal();
+      handleReload();
+    } catch (err) {
+      console.error('退回失败:', err);
+      message.error('退回失败,请重试');
+    } finally {
+      setAuditLoading(false);
+    }
+  };
+
+  // 打开退回弹窗
+  const handleOpenReturnModal = () => {
+    setAuditRemark('');
+    setReturnModalVisible(true);
+  };
+
+  // 关闭退回弹窗
+  const handleCloseReturnModal = () => {
+    setReturnModalVisible(false);
+    setAuditRemark('');
+  };
 
   const renderEvidenceItem = (item, type) => (
     <div key={item.name} className="evidence-item" style={{
@@ -451,27 +839,52 @@
       justifyContent: 'space-between',
       alignItems: 'flex-start',
       marginBottom: 10,
+      position: 'relative',
     }}>
-      <div style={{ flex: 1 }}>
+      <div style={{ flex: 1, paddingRight: 70 }}>
         <div style={{ fontWeight: 600, fontSize: '0.9rem', marginBottom: 4, color: 'var(--dark-color)' }}>{item.name}</div>
-        <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)', lineHeight: 1.4 }}>{item.desc}</div>
+        <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)', lineHeight: 1.4 }}>{item.result}</div>
         <div style={{ fontSize: '0.75rem', color: 'var(--gray-color)', marginTop: 4, display: 'flex', alignItems: 'center', gap: 5 }}>
           <i className="far fa-clock"></i>
-          <span>上传时间:{item.time}</span>
+          <span>上传时间:{item.update_time || item.create_time}</span>
         </div>
+        {/* 待审核时显示审核按钮 */}
+        {item.audit_state !== 1 && (
+          <button
+            onClick={() => handleOpenAuditModal(item, type)}
+            style={{
+              marginTop: 8,
+              padding: '4px 12px',
+              fontSize: '0.75rem',
+              background: '#1A6FB8',
+              color: 'white',
+              border: 'none',
+              borderRadius: 4,
+              cursor: 'pointer',
+              fontWeight: 600,
+              transition: 'all 0.2s ease',
+            }}
+            onMouseOver={(e) => {
+              e.target.style.background = '#0d4a8a';
+              e.target.style.transform = 'translateY(-1px)';
+            }}
+            onMouseOut={(e) => {
+              e.target.style.background = '#1A6FB8';
+              e.target.style.transform = 'translateY(0)';
+            }}
+          >
+            审核
+          </button>
+        )}
       </div>
-      <div style={{ marginLeft: 10 }}>
-        <span style={{
-          fontSize: '0.75rem',
-          padding: '3px 8px',
-          borderRadius: 12,
-          fontWeight: 600,
-          background: item.status === 'verified' ? '#d4edda' : '#fff3cd',
-          color: item.status === 'verified' ? '#155724' : '#856404',
-          border: `1px solid ${item.status === 'verified' ? '#c3e6cb' : '#ffeaa7'}`,
-        }}>
-          {item.status === 'verified' ? '已审核' : '待审核'}
-        </span>
+      {/* 右上角审核状态标签 */}
+      <div style={{
+        position: 'absolute',
+        top: 12,
+        right: 12,
+        ...getAuditStatusStyle(item.audit_state)
+      }}>
+        {item.audit_state === 1 ? '已审核' : '待审核'}
       </div>
     </div>
   );
@@ -491,10 +904,15 @@
             <i className="fas fa-user-tie" style={{ color: 'var(--primary-color)', marginRight: 8 }}></i>
             申请人材料
           </div>
-          <div style={{ fontSize: '0.85rem', color: 'var(--gray-color)', marginLeft: 'auto' }}>{applicantEvidence.length}份材料</div>
+          <Tag color={applicantStatus.color}>{applicantStatus.text}</Tag>
+          <div style={{ fontSize: '0.85rem', color: 'var(--gray-color)', marginLeft: 'auto' }}>{applicantMaterials.length}份材料</div>
         </div>
-        <div>
-          {applicantEvidence.map((item) => renderEvidenceItem(item, 'applicant'))}
+        <div style={{ maxHeight: 400, overflowY: 'auto' }}>
+          {applicantMaterials.length > 0 ? (
+            applicantMaterials.map((item) => renderEvidenceItem(item, 'applicant'))
+          ) : (
+            <div style={{ textAlign: 'center', padding: 40, color: 'var(--gray-color)' }}>暂无材料</div>
+          )}
         </div>
       </div>
 
@@ -511,12 +929,448 @@
             <i className="fas fa-building" style={{ color: '#e9c46a', marginRight: 8 }}></i>
             被申请人材料
           </div>
-          <div style={{ fontSize: '0.85rem', color: 'var(--gray-color)', marginLeft: 'auto' }}>{respondentEvidence.length}份材料</div>
+          <Tag color={respondentStatus.color}>{respondentStatus.text}</Tag>
+          <div style={{ fontSize: '0.85rem', color: 'var(--gray-color)', marginLeft: 'auto' }}>{respondentMaterials.length}份材料</div>
         </div>
-        <div>
-          {respondentEvidence.map((item) => renderEvidenceItem(item, 'respondent'))}
+        <div style={{ maxHeight: 400, overflowY: 'auto' }}>
+          {respondentMaterials.length > 0 ? (
+            respondentMaterials.map((item) => renderEvidenceItem(item, 'respondent'))
+          ) : (
+            <div style={{ textAlign: 'center', padding: 40, color: 'var(--gray-color)' }}>暂无材料</div>
+          )}
         </div>
       </div>
+
+      {/* 证据材料审查弹窗 */}
+      <Modal
+        title={null}
+        visible={auditModalVisible}
+        onCancel={handleCloseAuditModal}
+        footer={null}
+        width={900}
+        centered
+        destroyOnClose
+        bodyStyle={{ padding: 0 }}
+        className="doc-audit-modal"
+      >
+        {currentAuditItem && (
+          <div style={{ background: '#f5f7fa' }}>
+            {/* 头部 - 蓝色渐变 */}
+            <div style={{
+              background: 'linear-gradient(135deg, #1A6FB8 0%, #0d4a8a 100%)',
+              color: 'white',
+              padding: '20px 30px',
+            }}>
+              <div style={{ fontSize: 20, fontWeight: 600, marginBottom: 8 }}>证据材料审查</div>
+              <div style={{ fontSize: 14, opacity: 0.9 }}>
+                {currentAuditItem.personType === 'applicant' ? '申请人' : '被申请人'}提交的证据材料
+              </div>
+            </div>
+
+            {/* 主体内容 */}
+            <div style={{ padding: '20px 30px', background: 'white', margin: 0 }}>
+              {/* 审核说明 tip-box */}
+              <div style={{
+                background: '#f0f8ff',
+                borderRadius: 8,
+                padding: 16,
+                marginBottom: 24,
+                border: '1px solid #d9eafb',
+              }}>
+                <div style={{ color: '#1A6FB8', marginBottom: 8, fontSize: 15, fontWeight: 600 }}>审核说明</div>
+                <div style={{ color: '#555', fontSize: 14 }}>
+                  请仔细核对申请人提交的材料,确保材料真实、完整、有效。如有疑问或需要补充材料,请使用"退回补充"功能。
+                </div>
+              </div>
+
+              {/* 材料基本信息 */}
+              <div style={{ marginBottom: 24 }}>
+                <div style={{
+                  color: '#1A6FB8',
+                  fontSize: 16,
+                  fontWeight: 600,
+                  marginBottom: 16,
+                  display: 'flex',
+                  alignItems: 'center',
+                }}>
+                  <span style={{
+                    display: 'inline-block',
+                    width: 4,
+                    height: 16,
+                    background: '#1A6FB8',
+                    marginRight: 10,
+                    borderRadius: 2,
+                  }}></span>
+                  材料基本信息
+                </div>
+                {modalDataLoading ? (
+                  <div style={{ textAlign: 'center', padding: 20 }}>
+                    <Spin tip="加载中..." />
+                  </div>
+                ) : (
+                  <div style={{
+                    display: 'grid',
+                    gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
+                    gap: 16,
+                  }}>
+                    <div style={{ display: 'flex', marginBottom: 12 }}>
+                      <span style={{ fontWeight: 500, color: '#666', minWidth: 80 }}>提交人:</span>
+                      <span style={{ color: '#222', fontWeight: 500 }}>
+                        {personInfo 
+                          ? `${personInfo.per_class_name || (currentAuditItem.personType === 'applicant' ? '申请人' : '被申请人')}-${personInfo.true_name || ''}`
+                          : (currentAuditItem.personType === 'applicant' ? '申请方' : '被申请方')}
+                      </span>
+                    </div>
+                    <div style={{ display: 'flex', marginBottom: 12 }}>
+                      <span style={{ fontWeight: 500, color: '#666', minWidth: 80 }}>材料类型:</span>
+                      <span style={{ color: '#222', fontWeight: 500 }}>
+                        {currentAuditItem.evidence_type_name || currentAuditItem.name || '证据材料'}
+                      </span>
+                    </div>
+                    <div style={{ display: 'flex', marginBottom: 12 }}>
+                      <span style={{ fontWeight: 500, color: '#666', minWidth: 80 }}>材料数量:</span>
+                      <span style={{ color: '#222', fontWeight: 500 }}>
+                        {personInfo?.total_count ? `${personInfo.total_count}份` : `${evidenceImages.length || 1}份`}
+                      </span>
+                    </div>
+                    <div style={{ display: 'flex', marginBottom: 12 }}>
+                      <span style={{ fontWeight: 500, color: '#666', minWidth: 80 }}>提交时间:</span>
+                      <span style={{ color: '#222', fontWeight: 500 }}>
+                        {personInfo?.submit_time || currentAuditItem.update_time || currentAuditItem.create_time}
+                      </span>
+                    </div>
+                  </div>
+                )}
+              </div>
+
+              {/* 材料说明 */}
+              <div style={{ marginBottom: 24 }}>
+                <div style={{
+                  color: '#1A6FB8',
+                  fontSize: 16,
+                  fontWeight: 600,
+                  marginBottom: 16,
+                  display: 'flex',
+                  alignItems: 'center',
+                }}>
+                  <span style={{
+                    display: 'inline-block',
+                    width: 4,
+                    height: 16,
+                    background: '#1A6FB8',
+                    marginRight: 10,
+                    borderRadius: 2,
+                  }}></span>
+                  材料说明
+                </div>
+                <div style={{
+                  border: '1px solid #e8e8e8',
+                  borderRadius: 6,
+                  padding: 16,
+                  background: '#fafafa',
+                  minHeight: 100,
+                  fontSize: 14,
+                  lineHeight: 1.7,
+                }}>
+                  <p style={{ marginBottom: 8 }}>
+                    <strong>{currentAuditItem.name}</strong>
+                  </p>
+                  <p style={{ margin: 0, color: '#555' }}>
+                    {currentAuditItem.result || '暂无详细说明'}
+                  </p>
+                </div>
+              </div>
+
+              {/* 材料清单 */}
+              <div style={{ marginBottom: 24 }}>
+                <div style={{
+                  color: '#1A6FB8',
+                  fontSize: 16,
+                  fontWeight: 600,
+                  marginBottom: 16,
+                  display: 'flex',
+                  alignItems: 'center',
+                }}>
+                  <span style={{
+                    display: 'inline-block',
+                    width: 4,
+                    height: 16,
+                    background: '#1A6FB8',
+                    marginRight: 10,
+                    borderRadius: 2,
+                  }}></span>
+                  材料清单
+                </div>
+                <table style={{
+                  width: '100%',
+                  borderCollapse: 'collapse',
+                  borderRadius: 6,
+                  overflow: 'hidden',
+                  boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.03)',
+                  border: '1px solid #f0f0f0',
+                }}>
+                  <thead>
+                    <tr>
+                      <th style={{
+                        background: '#fafafa',
+                        color: '#333',
+                        fontWeight: 600,
+                        textAlign: 'left',
+                        padding: 16,
+                        borderBottom: '1px solid #f0f0f0',
+                        fontSize: 14,
+                        width: '40%',
+                      }}>材料信息</th>
+                      <th style={{
+                        background: '#fafafa',
+                        color: '#333',
+                        fontWeight: 600,
+                        textAlign: 'left',
+                        padding: 16,
+                        borderBottom: '1px solid #f0f0f0',
+                        fontSize: 14,
+                        width: '60%',
+                      }}>材料预览</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                    <tr>
+                      <td style={{ padding: 16, borderBottom: '1px solid #f5f5f5', verticalAlign: 'top', fontSize: 14 }}>
+                        <div style={{ fontWeight: 600, color: '#333', marginBottom: 6 }}>{currentAuditItem.name}</div>
+                        <div style={{ fontSize: 13, color: '#666', marginBottom: 4 }}>
+                          材料类型:{currentAuditItem.evidence_type_name || '证据材料'}
+                        </div>
+                        <div style={{ fontSize: 13, color: '#666', marginBottom: 4 }}>
+                          文件格式:{personInfo?.suffix || 'PDF/图片'}
+                        </div>
+                        <div style={{ fontSize: 13, color: '#666', marginBottom: 4 }}>
+                          上传时间:{personInfo?.submit_time || currentAuditItem.update_time || currentAuditItem.create_time}
+                        </div>
+                        {personInfo?.total_file_size && (
+                          <div style={{ fontSize: 13, color: '#666', marginBottom: 4 }}>
+                            文件大小:{personInfo.total_file_size}MB
+                          </div>
+                        )}
+                      </td>
+                      <td style={{ padding: 16, borderBottom: '1px solid #f5f5f5', verticalAlign: 'top', fontSize: 14 }}>
+                        {modalDataLoading ? (
+                          <div style={{ textAlign: 'center', padding: 20 }}>
+                            <Spin size="small" />
+                          </div>
+                        ) : evidenceImages.length > 0 ? (
+                          <>
+                            <Image.PreviewGroup>
+                              <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
+                                {evidenceImages.map((img, index) => {
+                                  // 判断 show_url 是否以 http 开头
+                                  const isFullUrl = img.show_url && img.show_url.startsWith('http');
+                                  // 如果是完整URL直接使用,否则拼接 platformUrl
+                                  const imgUrl = img.show_url 
+                                    ? (isFullUrl ? img.show_url : (platformUrl ? `${platformUrl}/${img.show_url}` : img.show_url))
+                                    : '';
+                                  // 获取文件名:true_name 为空时取 file_name
+                                  const rawFileName = img.true_name || img.file_name || `材料${index + 1}`;
+                                  // 获取文件类型后缀
+                                  const suffix = img.suffix || '';
+                                  // 检查文件名是否已包含后缀,避免重复
+                                  const fileName = suffix && rawFileName.toLowerCase().endsWith(`.${suffix.toLowerCase()}`) 
+                                    ? rawFileName 
+                                    : (suffix ? `${rawFileName}.${suffix}` : rawFileName);
+                                  const isPdf = suffix.toLowerCase() === 'pdf';
+                                  
+                                  if (isPdf) {
+                                    // PDF文件:直接打开PDF链接
+                                    return (
+                                      <div 
+                                        key={img.file_id || img.id || index}
+                                        style={{
+                                          width: 100,
+                                          height: 80,
+                                          borderRadius: 4,
+                                          overflow: 'hidden',
+                                          border: '1px solid #e8e8e8',
+                                          cursor: 'pointer',
+                                          transition: 'all 0.2s',
+                                          background: '#f5f5f5',
+                                          display: 'flex',
+                                          flexDirection: 'column',
+                                          alignItems: 'center',
+                                          justifyContent: 'center',
+                                        }}
+                                        onClick={() => {
+                                          // 直接打开PDF
+                                          window.open(imgUrl, '_blank');
+                                        }}
+                                      >
+                                        <i className="fas fa-file-pdf" style={{ fontSize: 32, color: '#ff4d4f' }} />
+                                        <span style={{ fontSize: 10, color: '#666', marginTop: 4, maxWidth: 90, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+                                          {fileName}
+                                        </span>
+                                      </div>
+                                    );
+                                  }
+                                  
+                                  // 图片文件:使用图片预览
+                                  return (
+                                    <div 
+                                      key={img.file_id || img.id || index}
+                                      style={{
+                                        width: 100,
+                                        height: 80,
+                                        borderRadius: 4,
+                                        overflow: 'hidden',
+                                        border: '1px solid #e8e8e8',
+                                        cursor: 'pointer',
+                                        transition: 'all 0.2s',
+                                      }}
+                                    >
+                                      <Image
+                                        src={imgUrl}
+                                        alt={fileName}
+                                        style={{ width: '100%', height: '100%', objectFit: 'cover' }}
+                                        fallback="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjgwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iODAiIGZpbGw9IiNmNWY1ZjUiLz48dGV4dCB4PSI1MCIgeT0iNDAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzk5OSI+5Zu+54mH6aKE6KeIPC90ZXh0Pjwvc3ZnPg=="
+                                        preview={{
+                                          mask: (
+                                            <span style={{ fontSize: 12, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
+                                              <span>预览</span>
+                                              <span style={{ fontSize: 10, marginTop: 2, maxWidth: 80, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+                                                {fileName}
+                                              </span>
+                                            </span>
+                                          )
+                                        }}
+                                      />
+                                    </div>
+                                  );
+                                })}
+                              </div>
+                            </Image.PreviewGroup>
+                            <div style={{ fontSize: 13, color: '#666', marginTop: 8 }}>共{evidenceImages.length}个文件</div>
+                          </>
+                        ) : (
+                          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
+                            <div style={{
+                              width: 100,
+                              height: 80,
+                              borderRadius: 4,
+                              overflow: 'hidden',
+                              border: '1px solid #e8e8e8',
+                              background: 'linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%)',
+                              display: 'flex',
+                              alignItems: 'center',
+                              justifyContent: 'center',
+                              color: '#999',
+                              fontSize: 13,
+                              fontWeight: 500,
+                            }}>
+                              暂无图片
+                            </div>
+                          </div>
+                        )}
+                      </td>
+                    </tr>
+                  </tbody>
+                </table>
+              </div>
+
+              {/* 操作按钮 */}
+              <div style={{
+                display: 'flex',
+                justifyContent: 'center',
+                gap: 16,
+                marginTop: 32,
+                paddingTop: 24,
+                borderTop: '1px solid #f0f0f0',
+              }}>
+                <Button
+                  type="primary"
+                  size="large"
+                  loading={auditLoading}
+                  onClick={handleAuditPass}
+                  style={{
+                    background: '#1A6FB8',
+                    borderColor: '#1A6FB8',
+                    minWidth: 120,
+                    height: 40,
+                    fontWeight: 500,
+                    boxShadow: '0 2px 0 rgba(0, 0, 0, 0.045)',
+                  }}
+                >
+                  审核通过
+                </Button>
+                <Button
+                  size="large"
+                  loading={auditLoading}
+                  onClick={handleOpenReturnModal}
+                  style={{
+                    background: 'white',
+                    color: '#1A6FB8',
+                    borderColor: '#1A6FB8',
+                    minWidth: 120,
+                    height: 40,
+                    fontWeight: 500,
+                    boxShadow: '0 2px 0 rgba(0, 0, 0, 0.015)',
+                  }}
+                >
+                  退回补充
+                </Button>
+              </div>
+            </div>
+          </div>
+        )}
+      </Modal>
+
+      {/* 退回补充子弹窗 */}
+      <Modal
+        title={
+          <div style={{ background: '#1A6FB8', margin: '-20px -24px', padding: '16px 24px', color: 'white' }}>
+            <span style={{ fontSize: 16, fontWeight: 600 }}>退回补充材料</span>
+          </div>
+        }
+        visible={returnModalVisible}
+        onCancel={handleCloseReturnModal}
+        footer={null}
+        width={480}
+        centered
+        destroyOnClose
+        bodyStyle={{ paddingTop: 24 }}
+      >
+        <div style={{ marginBottom: 20 }}>
+          <label style={{ display: 'block', fontWeight: 500, color: '#333', marginBottom: 8, fontSize: 14 }}>
+            退回意见:
+          </label>
+          <TextArea
+            value={auditRemark}
+            onChange={(e) => setAuditRemark(e.target.value)}
+            placeholder="请详细说明需要补充的材料内容及原因..."
+            rows={5}
+            style={{
+              borderRadius: 4,
+              resize: 'vertical',
+            }}
+          />
+        </div>
+        <div style={{
+          background: '#fafafa',
+          margin: '0 -24px -24px',
+          padding: '16px 24px',
+          display: 'flex',
+          justifyContent: 'flex-end',
+          gap: 12,
+        }}>
+          <Button onClick={handleCloseReturnModal} style={{ padding: '6px 16px' }}>
+            取消
+          </Button>
+          <Button
+            type="primary"
+            loading={auditLoading}
+            onClick={handleAuditReturn}
+            style={{ background: '#1A6FB8', borderColor: '#1A6FB8', padding: '6px 16px' }}
+          >
+            确认退回
+          </Button>
+        </div>
+      </Modal>
     </div>
   );
 };
@@ -525,6 +1379,186 @@
  * 调解协议
  */
 const AgreementSection = () => {
+  // 从 Context 获取调解协议数据
+  const { caseData, agreementData, loadAgreementData } = useCaseData();
+  const { content: agreementContent, loading, error } = agreementData;
+  
+  const [editModalVisible, setEditModalVisible] = useState(false);
+  const [editContent, setEditContent] = useState('');
+  const [editLoading, setEditLoading] = useState(false);
+  const [actionLoading, setActionLoading] = useState({
+    confirm: false,
+    download: false,
+    regenerate: false,
+  });
+
+  // 获取 caseId(兼容驼峰和蛇形命名)
+  const caseId = caseData?.caseId || caseData?.case_id || getMergedParams().caseId;
+
+  // 处理协议内容展示(纯文本,处理换行)
+  const renderAgreementContent = (content) => {
+    if (!content) return null;
+    // 处理 \n 换行,简单过滤 Markdown 符号
+    const lines = content.split('\n');
+    return lines.map((line, index) => {
+      // 简单过滤 ** 符号,保留文本
+      const cleanLine = line.replace(/\*\*/g, '');
+      if (!cleanLine.trim()) {
+        return <br key={index} />;
+      }
+      return (
+        <p key={index} style={{ margin: '8px 0', lineHeight: 1.6 }}>
+          {cleanLine}
+        </p>
+      );
+    });
+  };
+
+  // 重新加载协议
+  const handleReload = () => {
+    if (caseId) {
+      loadAgreementData(caseId);
+    }
+  };
+
+  // 确认协议
+  const handleConfirmAgreement = async () => {
+    if (!caseId) return;
+    setActionLoading(prev => ({ ...prev, confirm: true }));
+    try {
+      await MediationAgreementAPIService.confirmAgreement(caseId, 'mediator');
+      message.success('协议确认成功!');
+    } catch (err) {
+      console.error('确认协议失败:', err);
+      message.error('确认协议失败,请稍后重试');
+    } finally {
+      setActionLoading(prev => ({ ...prev, confirm: false }));
+    }
+  };
+
+  // 下载协议
+  const handleDownloadAgreement = async () => {
+    if (!caseId) return;
+    setActionLoading(prev => ({ ...prev, download: true }));
+    try {
+      // 调用API获取PDF文件流
+      const response = await MediationAgreementAPIService.downloadAgreement(caseId);
+      
+      // 创建Blob对象(PDF格式)
+      const blob = new Blob([response.data], { 
+        type: 'application/pdf' 
+      });
+      
+      // 创建下载链接
+      const url = window.URL.createObjectURL(blob);
+      const link = document.createElement('a');
+      link.href = url;
+      link.download = `调解协议_${caseId}.pdf`;
+      
+      // 触发下载
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+      
+      // 清理URL对象
+      window.URL.revokeObjectURL(url);
+      
+      message.success('协议下载成功!');
+    } catch (err) {
+      console.error('下载协议失败:', err);
+      message.error('下载协议失败,请稍后重试');
+    } finally {
+      setActionLoading(prev => ({ ...prev, download: false }));
+    }
+  };
+
+  // 重新生成协议
+  const handleRegenerateAgreement = async () => {
+    if (!caseId) return;
+    setActionLoading(prev => ({ ...prev, regenerate: true }));
+    try {
+      const response = await MediationAgreementAPIService.regenerateAgreement(caseId);
+      if (response?.data?.agreeContent) {
+        loadAgreementData(caseId);
+        message.success('协议重新生成成功!');
+      }
+    } catch (err) {
+      console.error('重新生成协议失败:', err);
+      message.error('重新生成协议失败,请稍后重试');
+    } finally {
+      setActionLoading(prev => ({ ...prev, regenerate: false }));
+    }
+  };
+
+  // 打开修改弹窗
+  const handleOpenEditModal = async () => {
+    if (!caseId) return;
+    setEditModalVisible(true);
+    setEditLoading(true);
+    try {
+      const response = await MediationAgreementAPIService.getAgreementDetail(caseId);
+      if (response?.data?.agreeContent) {
+        setEditContent(response.data.agreeContent);
+      }
+    } catch (err) {
+      console.error('获取协议内容失败:', err);
+      message.error('获取协议内容失败');
+    } finally {
+      setEditLoading(false);
+    }
+  };
+
+  // 关闭修改弹窗
+  const handleCloseEditModal = () => {
+    setEditModalVisible(false);
+    setEditContent('');
+  };
+
+  // 保存修改
+  const handleSaveEdit = async () => {
+    if (!caseId || !editContent.trim()) {
+      message.warning('协议内容不能为空');
+      return;
+    }
+    setEditLoading(true);
+    try {
+      await MediationAgreementAPIService.updateAgreement(caseId, editContent);
+      message.success('协议修改保存成功!');
+      handleCloseEditModal();
+      // 刷新协议内容
+      loadAgreementData(caseId);
+    } catch (err) {
+      console.error('保存协议失败:', err);
+      message.error('保存协议失败,请稍后重试');
+    } finally {
+      setEditLoading(false);
+    }
+  };
+
+  // Loading 状态
+  if (loading) {
+    return (
+      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: 300 }}>
+        <Spin size="large" tip="正在生成调解协议..." />
+      </div>
+    );
+  }
+
+  // 错误状态
+  if (error) {
+    return (
+      <div style={{ textAlign: 'center', padding: 40, color: '#ff4d4f' }}>
+        <div style={{ fontSize: '1.2rem', marginBottom: 10 }}>
+          <i className="fas fa-exclamation-circle"></i> {error}
+        </div>
+        <button onClick={handleReload} style={{
+          marginTop: 15, padding: '8px 16px', backgroundColor: '#1890ff',
+          color: 'white', border: 'none', borderRadius: 4, cursor: 'pointer'
+        }}>重新加载</button>
+      </div>
+    );
+  }
+
   return (
     <div style={{
       background: '#f8f9fa',
@@ -533,56 +1567,15 @@
       maxHeight: 450,
       overflowY: 'auto',
     }}>
+      {/* 协议内容展示区域 */}
       <div style={{ lineHeight: 1.5, fontSize: '0.9rem' }}>
-        <div style={{ textAlign: 'center', color: 'var(--secondary-color)', fontSize: '1.2rem', marginBottom: 20, fontWeight: 700 }}>
-          李晓明与广东好又多贸易有限公司劳动争议调解协议书
-        </div>
-
-        <p><strong>甲方(申请人):</strong>李晓明</p>
-        <p><strong>乙方(被申请人):</strong>广东好又多贸易有限公司</p>
-
-        <p style={{ textIndent: '2em', marginTop: 15 }}>
-          甲方与乙方因劳动报酬支付问题发生争议,双方于2026年1月15日向"云小调"劳动争议AI调解智能体申请调解。经AI调解员调解,双方本着平等自愿、互谅互让的原则,达成如下调解协议:
-        </p>
-
-        <h3 style={{ color: 'var(--secondary-color)', margin: '15px 0 8px', fontSize: '1rem' }}>一、争议事项</h3>
-        <p style={{ textIndent: '2em' }}>甲方主张乙方拖欠2026年1月至3月共三个月工资、2026年第一季度绩效奖金以及解除劳动合同经济补偿金,合计人民币52,800元。</p>
-
-        <h3 style={{ color: 'var(--secondary-color)', margin: '15px 0 8px', fontSize: '1rem' }}>二、调解结果</h3>
-        <p style={{ textIndent: '2em' }}>经调解,双方达成一致意见如下:</p>
-        <ul style={{ paddingLeft: 30, marginBottom: 12 }}>
-          <li style={{ marginBottom: 6 }}>乙方同意向甲方支付劳动报酬共计人民币肆万肆仟元整(¥44,000)</li>
-          <li style={{ marginBottom: 6 }}>支付方式:分两期支付
-            <ul style={{ paddingLeft: 20 }}>
-              <li>第一期:人民币贰万贰仟元整(¥22,000),于2026年1月30日前支付</li>
-              <li>第二期:人民币贰万贰仟元整(¥22,000),于2026年2月28日前支付</li>
-            </ul>
-          </li>
-          <li style={{ marginBottom: 6 }}>支付账户:甲方指定的银行账户(账户信息另行提供)</li>
-        </ul>
-
-        <h3 style={{ color: 'var(--secondary-color)', margin: '15px 0 8px', fontSize: '1rem' }}>三、双方权利义务</h3>
-        <ul style={{ paddingLeft: 30, marginBottom: 12 }}>
-          <li style={{ marginBottom: 6 }}>乙方应按约定时间足额支付上述款项</li>
-          <li style={{ marginBottom: 6 }}>甲方收到全部款项后,双方劳动关系正式解除</li>
-          <li style={{ marginBottom: 6 }}>双方互不追究其他法律责任,本协议履行完毕后,争议事项一次性了结</li>
-        </ul>
-
-        {/* 签名区域 */}
-        <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 20, paddingTop: 15, borderTop: '1px solid var(--border-color)' }}>
-          <div style={{ textAlign: 'center', width: '45%' }}>
-            <div style={{ borderBottom: '1px solid var(--dark-color)', padding: '15px 0 5px', marginBottom: 5 }}></div>
-            <div>甲方(申请人):李晓明</div>
-            <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)' }}>签字/盖章</div>
-            <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)', marginTop: 5 }}>日期:2026年1月15日</div>
+        {agreementContent ? (
+          renderAgreementContent(agreementContent)
+        ) : (
+          <div style={{ textAlign: 'center', color: 'var(--gray-color)', padding: 40 }}>
+            暂无协议内容
           </div>
-          <div style={{ textAlign: 'center', width: '45%' }}>
-            <div style={{ borderBottom: '1px solid var(--dark-color)', padding: '15px 0 5px', marginBottom: 5 }}></div>
-            <div>乙方(被申请人):广东好又多贸易有限公司</div>
-            <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)' }}>签字/盖章</div>
-            <div style={{ fontSize: '0.8rem', color: 'var(--gray-color)', marginTop: 5 }}>日期:2026年1月15日</div>
-          </div>
-        </div>
+        )}
       </div>
 
       {/* 操作按钮 */}
@@ -597,73 +1590,185 @@
         justifyContent: 'center',
         gap: 12,
       }}>
-        <button style={{
-          padding: '10px 20px',
-          border: '2px solid #c3e6cb',
-          borderRadius: 'var(--border-radius)',
-          fontWeight: 600,
-          fontSize: '0.9rem',
-          cursor: 'pointer',
-          display: 'flex',
-          alignItems: 'center',
-          gap: 6,
-          background: '#d4edda',
-          color: '#155724',
-        }}>
-          <i className="fas fa-check-circle"></i>
+        <button
+          onClick={handleConfirmAgreement}
+          disabled={actionLoading.confirm}
+          style={{
+            padding: '10px 20px',
+            border: '2px solid #c3e6cb',
+            borderRadius: 'var(--border-radius)',
+            fontWeight: 600,
+            fontSize: '0.9rem',
+            cursor: actionLoading.confirm ? 'not-allowed' : 'pointer',
+            display: 'flex',
+            alignItems: 'center',
+            gap: 6,
+            background: '#d4edda',
+            color: '#155724',
+            opacity: actionLoading.confirm ? 0.6 : 1,
+          }}>
+          <i className={actionLoading.confirm ? "fas fa-spinner fa-spin" : "fas fa-check-circle"}></i>
           确认协议
         </button>
-        <button style={{
-          padding: '10px 20px',
-          border: '2px solid #ffeaa7',
-          borderRadius: 'var(--border-radius)',
-          fontWeight: 600,
-          fontSize: '0.9rem',
-          cursor: 'pointer',
-          display: 'flex',
-          alignItems: 'center',
-          gap: 6,
-          background: '#fff3cd',
-          color: '#856404',
-        }}>
+        <button
+          onClick={handleOpenEditModal}
+          style={{
+            padding: '10px 20px',
+            border: '2px solid #ffeaa7',
+            borderRadius: 'var(--border-radius)',
+            fontWeight: 600,
+            fontSize: '0.9rem',
+            cursor: 'pointer',
+            display: 'flex',
+            alignItems: 'center',
+            gap: 6,
+            background: '#fff3cd',
+            color: '#856404',
+          }}>
           <i className="fas fa-edit"></i>
           修改协议
         </button>
-        <button style={{
-          padding: '10px 20px',
-          border: '2px solid #bbdefb',
-          borderRadius: 'var(--border-radius)',
-          fontWeight: 600,
-          fontSize: '0.9rem',
-          cursor: 'pointer',
-          display: 'flex',
-          alignItems: 'center',
-          gap: 6,
-          background: '#e3f2fd',
-          color: '#1565c0',
-        }}>
-          <i className="fas fa-download"></i>
+        <button
+          onClick={handleDownloadAgreement}
+          disabled={actionLoading.download}
+          style={{
+            padding: '10px 20px',
+            border: '2px solid #bbdefb',
+            borderRadius: 'var(--border-radius)',
+            fontWeight: 600,
+            fontSize: '0.9rem',
+            cursor: actionLoading.download ? 'not-allowed' : 'pointer',
+            display: 'flex',
+            alignItems: 'center',
+            gap: 6,
+            background: '#e3f2fd',
+            color: '#1565c0',
+            opacity: actionLoading.download ? 0.6 : 1,
+          }}>
+          <i className={actionLoading.download ? "fas fa-spinner fa-spin" : "fas fa-download"}></i>
           下载协议
         </button>
-        <button style={{
-          padding: '10px 20px',
-          border: '2px solid #bee5eb',
-          borderRadius: 'var(--border-radius)',
-          fontWeight: 600,
-          fontSize: '0.9rem',
-          cursor: 'pointer',
-          display: 'flex',
-          alignItems: 'center',
-          gap: 6,
-          background: '#d1ecf1',
-          color: '#0c5460',
-        }}>
-          <i className="fas fa-redo"></i>
+        <button
+          onClick={handleRegenerateAgreement}
+          disabled={actionLoading.regenerate}
+          style={{
+            padding: '10px 20px',
+            border: '2px solid #bee5eb',
+            borderRadius: 'var(--border-radius)',
+            fontWeight: 600,
+            fontSize: '0.9rem',
+            cursor: actionLoading.regenerate ? 'not-allowed' : 'pointer',
+            display: 'flex',
+            alignItems: 'center',
+            gap: 6,
+            background: '#d1ecf1',
+            color: '#0c5460',
+            opacity: actionLoading.regenerate ? 0.6 : 1,
+          }}>
+          <i className={actionLoading.regenerate ? "fas fa-spinner fa-spin" : "fas fa-redo"}></i>
           重新生成
         </button>
       </div>
+
+      {/* 修改调解协议书弹窗 */}
+      <Modal
+        title={null}
+        visible={editModalVisible}
+        onCancel={handleCloseEditModal}
+        footer={null}
+        width={1000}
+        centered
+        destroyOnClose
+        bodyStyle={{ padding: 0 }}
+      >
+        <div style={{ background: '#f5f7fa' }}>
+          {/* 头部 */}
+          <div style={{
+            background: '#1A6FB8',
+            color: 'white',
+            padding: '25px 30px',
+            borderBottom: '5px solid #0d4a8a',
+          }}>
+            <div style={{ fontSize: 24, fontWeight: 600, marginBottom: 10 }}>在线修改调解协议书</div>
+            <div style={{ fontSize: 16, opacity: 0.9 }}>编辑协议内容</div>
+          </div>
+
+          {/* 主体内容 */}
+          <div style={{ padding: '25px 30px', background: 'white' }}>
+            {/* 编辑提示 */}
+            <div style={{
+              fontSize: 14,
+              color: '#666',
+              marginBottom: 15,
+              padding: 10,
+              background: '#f0f8ff',
+              borderRadius: 5,
+              borderLeft: '3px solid #1A6FB8',
+            }}>
+              <strong>编辑提示:</strong>下方文本框中的协议内容可直接编辑修改。编辑完成后,请点击底部的"保存修改"按钮。
+            </div>
+
+            {/* 协议编辑区域 */}
+            <div style={{ marginBottom: 25 }}>
+              {editLoading ? (
+                <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: 400 }}>
+                  <Spin size="large" tip="加载协议内容..." />
+                </div>
+              ) : (
+                <TextArea
+                  value={editContent}
+                  onChange={(e) => setEditContent(e.target.value)}
+                  style={{
+                    border: '1px solid #d0e3ff',
+                    borderRadius: 8,
+                    minHeight: 500,
+                    padding: 20,
+                    fontSize: 16,
+                    lineHeight: 1.8,
+                    background: '#f9fafc',
+                  }}
+                  placeholder="请输入协议内容..."
+                />
+              )}
+            </div>
+
+            {/* 操作按钮 */}
+            <div style={{
+              display: 'flex',
+              justifyContent: 'flex-end',
+              marginTop: 30,
+              paddingTop: 20,
+              borderTop: '1px solid #eaeaea',
+            }}>
+              <Button
+                type="primary"
+                size="large"
+                loading={editLoading}
+                onClick={handleSaveEdit}
+                style={{
+                  padding: '12px 36px',
+                  height: 'auto',
+                  fontWeight: 600,
+                  fontSize: 16,
+                  background: '#1A6FB8',
+                  borderColor: '#1A6FB8',
+                }}
+              >
+                保存修改
+              </Button>
+            </div>
+          </div>
+        </div>
+      </Modal>
     </div>
   );
 };
 
 export default TabContainer;
+
+
+
+
+
+
+

--
Gitblit v1.8.0