shimai
2026-03-09 2cfe2f7e5c51dc4cb2c312bb8acc4d664779005d
web-app/src/components/dashboard/TabContainer.jsx
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
import { useCaseData } from '../../contexts/CaseDataContext';
import { formatDuration, formatSuccessRate, formatRoundCount } from '../../utils/stateTranslator';
import ProcessAPIService from '../../services/ProcessAPIService';
@@ -11,11 +11,19 @@
/**
 * 选项卡容器组件 - 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' },
@@ -76,7 +84,7 @@
      </div>
    </div>
  );
};
});
/**
 * 调解数据看板
@@ -477,7 +485,7 @@
    // 使用getMergedParams获取参数(URL参数优先,默认值兜底)
    const params = getMergedParams();
    const caseId = params.caseId;
    const caseType = params.caseTypeFirst;
    const caseType = params.caseType ||params.caseTypeFirst;
    const platformCode = params.platform_code;
    
    console.log('EvidenceBoard loadData params:', { caseId, caseType, platformCode });
@@ -1082,9 +1090,55 @@
                            <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 
                                    ? (platformUrl ? `${platformUrl}/${img.show_url}` : 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}
@@ -1100,11 +1154,18 @@
                                    >
                                      <Image
                                        src={imgUrl}
                                        alt={img.file_name || `材料${index + 1}`}
                                        alt={fileName}
                                        style={{ width: '100%', height: '100%', objectFit: 'cover' }}
                                        fallback="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjgwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iODAiIGZpbGw9IiNmNWY1ZjUiLz48dGV4dCB4PSI1MCIgeT0iNDAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzk5OSI+5Zu+54mH6aKE6KeIPC90ZXh0Pjwvc3ZnPg=="
                                        preview={{
                                          mask: <span style={{ fontSize: 12 }}>预览</span>
                                          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>
@@ -1333,7 +1394,28 @@
    if (!caseId) return;
    setActionLoading(prev => ({ ...prev, download: true }));
    try {
      await MediationAgreementAPIService.downloadAgreement(caseId);
      // 调用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);
@@ -1348,7 +1430,7 @@
    if (!caseId) return;
    setActionLoading(prev => ({ ...prev, regenerate: true }));
    try {
      const response = await MediationAgreementAPIService.generateAgreement(caseId);
      const response = await MediationAgreementAPIService.regenerateAgreement(caseId);
      if (response?.data?.agreeContent) {
        setAgreementContent(response.data.agreeContent);
        message.success('协议重新生成成功!');