web-app/src/components/dashboard/TabContainer.jsx
@@ -1,21 +1,41 @@
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 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';
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 +71,7 @@
        {/* 证据材料汇总 */}
        <div className={`tab-pane ${activeTab === 'evidence-board' ? 'active' : ''}`}>
          <div className="tab-content-area">
            <EvidenceBoard />
            <EvidenceBoard onStatusChange={handleEvidenceStatusChange} />
          </div>
        </div>
@@ -64,7 +84,7 @@
      </div>
    </div>
  );
};
});
/**
 * 调解数据看板
@@ -134,9 +154,26 @@
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  // 状态控制相关状态
  const [controlLoading, setControlLoading] = useState(false);
  const [confirmModalVisible, setConfirmModalVisible] = useState(false);
  const [controlAction, setControlAction] = useState(null); // 'terminate' or 'resume'
  const [remark, setRemark] = useState('');
  // 获取案件数据
  const { caseData } = useCaseData();
  const { caseData, refreshData } = useCaseData();
  const timeline = caseData || {};
  const caseState = timeline.mediation?.state;
  // 调试日志:输出关键数据
  useEffect(() => {
    console.log('===== MediationBoard 数据状态 =====');
    console.log('caseData:', caseData);
    console.log('timeline:', timeline);
    console.log('caseState:', caseState);
    console.log('mediation:', timeline.mediation);
    console.log('================================');
  }, [caseData, caseState, timeline]);
  
  // person_type到avatar类型的映射
  const getAvatarType = (personType) => {
@@ -325,6 +362,114 @@
    return avatarText || (avatar === 'applicant' ? '申' : avatar === 'respondent' ? '被' : '调');
  };
  // 状态控制按钮显示逻辑
  const shouldShowControlButton = () => {
    // 转换为数字类型进行比较,兼容字符串和数字
    const stateNum = Number(caseState);
    const show = stateNum === 0 || stateNum === 1 || stateNum === 5;
    console.log('状态控制按钮显示检查:', {
      caseState,
      caseStateType: typeof caseState,
      stateNum,
      show,
      conditions: {
        'stateNum === 0': stateNum === 0,
        'stateNum === 1': stateNum === 1,
        'stateNum === 5': stateNum === 5
      }
    });
    return show;
  };
  const getControlButtonProps = () => {
    // 转换为数字类型进行比较
    const stateNum = Number(caseState);
    console.log('获取按钮属性:', { caseState, caseStateType: typeof caseState, stateNum });
    if (stateNum === 0 || stateNum === 1) {
      return {
        text: '终止',
        style: 'terminate',
        action: 'terminate'
      };
    } else if (stateNum === 5) {
      return {
        text: '恢复',
        style: 'resume',
        action: 'resume'
      };
    }
    console.log('未匹配到按钮属性,返回null');
    return null;
  };
  // 处理状态控制按钮点击
  const handleControlButtonClick = (action) => {
    console.log('状态控制按钮点击:', { action });
    setControlAction(action);
    setConfirmModalVisible(true);
  };
  // 处理确认对话框确认
  const handleConfirmOk = async () => {
    console.log('确认对话框确认:', { controlAction, remark });
    if (!controlAction) {
      console.warn('控制动作为空');
      return;
    }
    setControlLoading(true);
    try {
      const params = getMergedParams();
      const actionCode = controlAction === 'terminate' ? 0 : 1;
      console.log('准备调用API:', {
        caseId: params.caseId,
        actionCode,
        userName: localStorage.getItem('userName') || '调解员',
        remark: remark || ''
      });
      // 验证必要参数
      if (!params.caseId) {
        throw new Error('案件ID不能为空');
      }
      await ProcessAPIService.updateMediationState(params.caseId, {
        action: actionCode,
        userName: localStorage.getItem('userName') || '调解员',
        remark: remark || ''
      });
      message.success('案件状态更新成功');
      setConfirmModalVisible(false);
      setRemark('');
      setControlAction(null);
      // 刷新数据
      refreshData();
    } catch (error) {
      console.error('状态更新失败:', error);
      const errorMessage = error.message || '状态更新失败,请稍后重试';
      message.error(errorMessage);
      // 如果是网络错误,提供更多帮助信息
      if (errorMessage.includes('网络') || errorMessage.includes('Network')) {
        message.info('请检查网络连接或联系管理员');
      }
    } finally {
      setControlLoading(false);
    }
  };
  // 处理确认对话框取消
  const handleConfirmCancel = () => {
    setConfirmModalVisible(false);
    setControlAction(null);
    setRemark('');
  };
  return (
    <>
      <div className="mediation-summary" style={{
@@ -419,6 +564,81 @@
          </div>
        ))}
      </div>
      {/* 状态控制按钮区域 */}
      {shouldShowControlButton() && (() => {
        const buttonProps = getControlButtonProps();
        if (!buttonProps) return null;
        return (
          <div style={{
            marginTop: 20,
            paddingTop: 15,
            borderTop: '1px solid #e9ecef',
            display: 'flex',
            justifyContent: 'center',
            gap: 12
          }}>
            <button
              onClick={() => handleControlButtonClick(buttonProps.action)}
              disabled={controlLoading}
              style={{
                padding: '10px 20px',
                borderRadius: 'var(--border-radius)',
                fontWeight: 600,
                fontSize: '0.9rem',
                cursor: controlLoading ? 'not-allowed' : 'pointer',
                display: 'flex',
                alignItems: 'center',
                gap: 6,
                border: 'none',
                ...(buttonProps.style === 'terminate' ? {
                  background: '#1A6FB8',
                  color: 'white',
                } : {
                  background: '#52c41a',
                  color: 'white',
                }),
                opacity: controlLoading ? 0.6 : 1,
              }}
            >
              {controlLoading ? (
                <><i className="fas fa-spinner fa-spin"></i>处理中...</>
              ) : (
                <><i className="fas fa-pause-circle"></i>{buttonProps.text}</>
              )}
            </button>
          </div>
        );
      })()}
      {/* 状态控制确认对话框 */}
      <Modal
        title={controlAction === 'terminate' ? '确认终止调解' : '确认恢复调解'}
        visible={confirmModalVisible}
        onOk={handleConfirmOk}
        onCancel={handleConfirmCancel}
        okText="确定"
        cancelText="取消"
        confirmLoading={controlLoading}
      >
        <p>
          {controlAction === 'terminate'
            ? '确定要终止当前AI调解流程吗?终止后调解将暂停,可在适当时机恢复。'
            : '确定要恢复AI调解流程吗?恢复后将从当前位置继续调解。'}
        </p>
        <div style={{ marginTop: 15 }}>
          <label style={{ display: 'block', marginBottom: 5, fontWeight: 500 }}>
            备注(可选):
          </label>
          <Input.TextArea
            value={remark}
            onChange={(e) => setRemark(e.target.value)}
            placeholder="请输入操作备注..."
            rows={3}
          />
        </div>
      </Modal>
    </>
  );
};
@@ -426,20 +646,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 +932,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 +997,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 +1022,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 +1472,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 +1660,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,71 +1683,176 @@
        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>
  );
};