shimai
2026-04-03 6bb08c2297be1b6415c8bc02e6917eba6ee355e5
web-app/src/components/dashboard/TabContainer.jsx
@@ -1,4 +1,4 @@
import React, { useState, useEffect, forwardRef, useImperativeHandle } 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';
@@ -6,6 +6,8 @@
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';
const { TextArea } = Input;
@@ -153,17 +155,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';
@@ -181,23 +202,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,
@@ -393,7 +416,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>
@@ -439,6 +495,13 @@
          </div>
        ))}
      </div>
      {/* 通话记录弹窗 */}
      <CallRecordModal
        visible={callRecordVisible}
        onClose={() => setCallRecordVisible(false)}
        record={currentRecord}
      />
    </>
  );
};
@@ -1658,3 +1721,10 @@
};
export default TabContainer;