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/NegotiationProgress.jsx | 88 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/web-app/src/components/dashboard/NegotiationProgress.jsx b/web-app/src/components/dashboard/NegotiationProgress.jsx
new file mode 100644
index 0000000..31050ff
--- /dev/null
+++ b/web-app/src/components/dashboard/NegotiationProgress.jsx
@@ -0,0 +1,88 @@
+/**
+ * NegotiationProgress 组件 - 协商沟通进度
+ * 点线式可视化展示沟通轮次
+ */
+
+import React, { useMemo } from 'react';
+import { useCaseData } from '../../contexts/CaseDataContext';
+import './NegotiationProgress.css';
+
+/**
+ * 计算总轮次和已完成轮次
+ */
+const calculateRounds = (mediationCount, nodeCount, currentNodeIndex) => {
+ const currentRound = mediationCount || 0;
+ let totalRounds = nodeCount || 6;
+ const isLastNode = currentNodeIndex >= nodeCount - 1;
+
+ // 当沟通次数超过总次数但未到最后节点时,总次数 = 沟通次数 + 1
+ if (currentRound > totalRounds && !isLastNode) {
+ totalRounds = currentRound + 1;
+ }
+
+ return { currentRound, totalRounds, isLastNode };
+};
+
+/**
+ * 进度点组件
+ */
+const ProgressDot = ({ isActive, isLast }) => (
+ <div className={`progress-dot-wrapper ${isLast ? 'last' : ''}`}>
+ <div className={`progress-dot ${isActive ? 'active' : ''}`} />
+ {!isLast && <div className={`progress-line ${isActive ? 'active' : ''}`} />}
+ </div>
+);
+
+/**
+ * NegotiationProgress 主组件
+ */
+const NegotiationProgress = () => {
+ const { caseData, processNodes } = useCaseData();
+
+ // 从数据中获取值
+ const mediationCount = caseData?.mediation?.mediation_count || 0;
+ const nodeCount = processNodes?.length || 6;
+
+ // 计算当前节点索引
+ const currentNodeIndex = useMemo(() => {
+ if (!processNodes?.length) return 0;
+ const activeNode = processNodes.findIndex(n => n.nodeState === 1);
+ return activeNode >= 0 ? activeNode : processNodes.length - 1;
+ }, [processNodes]);
+
+ // 计算轮次数据
+ const { currentRound, totalRounds, isLastNode } = useMemo(() => {
+ return calculateRounds(mediationCount, nodeCount, currentNodeIndex);
+ }, [mediationCount, nodeCount, currentNodeIndex]);
+
+ // 生成进度点数据
+ const dots = useMemo(() => {
+ return Array(totalRounds).fill(false).map((_, index) => {
+ // 如果是最后节点,全部显示蓝色
+ if (isLastNode) return true;
+ return index < currentRound;
+ });
+ }, [totalRounds, currentRound, isLastNode]);
+
+ return (
+ <div className="negotiation-progress">
+ <div className="negotiation-header">
+ <span className="negotiation-title">协商沟通</span>
+ </div>
+ <div className="negotiation-round">
+ <span className="round-text">第{currentRound}轮</span>
+ </div>
+ <div className="negotiation-dots">
+ {dots.map((isActive, index) => (
+ <ProgressDot
+ key={index}
+ isActive={isActive}
+ isLast={index === dots.length - 1}
+ />
+ ))}
+ </div>
+ </div>
+ );
+};
+
+export default NegotiationProgress;
--
Gitblit v1.8.0