From 88a31d5a960bd10f3799bc00f8aa24461567d06e Mon Sep 17 00:00:00 2001
From: shimai <shimai@example.com>
Date: Tue, 07 Apr 2026 15:23:43 +0800
Subject: [PATCH] Merge branch 'test/tony.cheng/260312' of http://120.79.193.119:9090/r/~chengmw/cloud-melody-front into test/shimai.huang/260309
---
web-app/src/components/dashboard/PartyInfoCard.jsx | 142 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 142 insertions(+), 0 deletions(-)
diff --git a/web-app/src/components/dashboard/PartyInfoCard.jsx b/web-app/src/components/dashboard/PartyInfoCard.jsx
new file mode 100644
index 0000000..af4b002
--- /dev/null
+++ b/web-app/src/components/dashboard/PartyInfoCard.jsx
@@ -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;
--
Gitblit v1.8.0