shimai
2026-04-03 e4dfe9f17d64d016376872b786d2987805ee41ef
web-app/src/components/dashboard/PartyInfoCard.jsx
New file
@@ -0,0 +1,142 @@
/**
 * PartyInfoCard 组件 - 申请双方信息
 * 展示申请人和被申请人信息,包含头像、姓名和情绪标签
 */
import React, { useState, useEffect, useCallback } from 'react';
import { Tag } from 'antd';
import { useCaseData } from '../../contexts/CaseDataContext';
import MediationTimelineAPIService from '../../services/MediationTimelineAPIService';
import './PartyInfoCard.css';
// 申请人头像图片
const APPLICANT_AVATAR = '/in_person.png';
// 被申请人头像图片
const RESPONDENT_AVATAR = '/to_person.png';
/**
 * 根据per_type判断是申请方还是被申请方
 */
const isApplicant = (perType) => {
  return perType?.includes('15_020008-1') || perType?.toLowerCase().includes('applicant');
};
/**
 * 获取标签颜色样式
 */
const getTagColor = (tagStyle) => {
  const colorMap = {
    red: 'red',
    orange: 'orange',
    yellow: 'gold',
    green: 'green',
    blue: 'blue',
    warning: 'orange',
    danger: 'red',
    success: 'green',
    primary: 'blue'
  };
  return colorMap[tagStyle] || 'default';
};
/**
 * 当事人信息卡片
 */
const PartyCard = ({ person, isApplicantSide }) => {
  const avatarSrc = isApplicantSide ? APPLICANT_AVATAR : RESPONDENT_AVATAR;
  return (
    <div className={`party-card ${isApplicantSide ? 'applicant' : 'respondent'}`}>
      {/* 标签 */}
      {person.tag_name && (
        <Tag color={getTagColor(person.tag_style)} className="party-tag">
          {person.tag_name}
        </Tag>
      )}
      {/* 头像 */}
      <img
        src={avatarSrc}
        alt={isApplicantSide ? '申请人' : '被申请人'}
        className="party-avatar-img"
      />
      {/* 角色标签 */}
      <span className="party-role">
        {isApplicantSide ? '申请人' : '被申请人'}
      </span>
      {/* 姓名/公司名 */}
      <span className="party-name">{person.true_name}</span>
    </div>
  );
};
// VS分隔符图片
const VS_ICON = '/join.png';
/**
 * VS分隔符
 */
const VSSeparator = () => (
  <div className="vs-separator">
    <div className="vs-line vs-line-left"></div>
    <img src={VS_ICON} alt="VS" className="vs-icon-img" />
    <div className="vs-line vs-line-right"></div>
  </div>
);
/**
 * PartyInfoCard 主组件
 */
const PartyInfoCard = () => {
  const { caseData } = useCaseData();
  const [persons, setPersons] = useState([]);
  const [loading, setLoading] = useState(false);
  const caseId = caseData?.caseId || caseData?.case_id;
  // 加载当事人数据
  const loadPersons = useCallback(async () => {
    if (!caseId) return;
    setLoading(true);
    try {
      const response = await MediationTimelineAPIService.getPersonList(caseId);
      setPersons(response.data || []);
    } catch (err) {
      console.error('加载当事人列表失败:', err);
      setPersons([]);
    } finally {
      setLoading(false);
    }
  }, [caseId]);
  // 组件挂载时加载数据
  useEffect(() => {
    loadPersons();
  }, [loadPersons]);
  // 分离申请方和被申请方
  const applicant = persons.find(p => isApplicant(p.per_type));
  const respondent = persons.find(p => !isApplicant(p.per_type));
  if (loading || persons.length === 0) {
    return null;
  }
  return (
    <div className="party-info-card">
      <div className="party-info-title">申请双方</div>
      <div className="party-info-content">
        {applicant && <PartyCard person={applicant} isApplicantSide={true} />}
        <VSSeparator />
        {respondent && <PartyCard person={respondent} isApplicantSide={false} />}
      </div>
    </div>
  );
};
export default PartyInfoCard;