From 6b14010e1765842acc437ab130e5815bc623788d Mon Sep 17 00:00:00 2001
From: chengmw <chengmingwei_1984122@126.com>
Date: Thu, 02 Apr 2026 14:59:59 +0800
Subject: [PATCH] feat: 优化警告提示和调解流程 UI,新增 AI 背景和图片资源
---
web-app/src/components/dashboard/PartyInfoCard.jsx | 25 +++--
web-app/src/components/common/WarningAlert.css | 14 ++
web-app/public/to_person.png | 0
web-app/src/components/dashboard/AISuggestionCard.css | 39 +++++++--
web-app/public/ai-bg.png | 0
web-app/public/warning.png | 0
web-app/src/components/dashboard/AISuggestionCard.jsx | 3
web-app/src/components/dashboard/NegotiationProgress.css | 20 +++--
web-app/public/join.png | 0
web-app/src/components/common/WarningAlert.jsx | 9 +
web-app/public/mom.png | 0
web-app/public/in_person.png | 0
web-app/src/components/dashboard/PartyInfoCard.css | 26 ++++--
web-app/src/components/dashboard/TabContainer.jsx | 22 ++++-
web-app/src/App.css | 47 +++++++++--
15 files changed, 147 insertions(+), 58 deletions(-)
diff --git a/web-app/public/ai-bg.png b/web-app/public/ai-bg.png
new file mode 100644
index 0000000..d46f006
--- /dev/null
+++ b/web-app/public/ai-bg.png
Binary files differ
diff --git a/web-app/public/in_person.png b/web-app/public/in_person.png
new file mode 100644
index 0000000..45aac2c
--- /dev/null
+++ b/web-app/public/in_person.png
Binary files differ
diff --git a/web-app/public/join.png b/web-app/public/join.png
new file mode 100644
index 0000000..37a56fb
--- /dev/null
+++ b/web-app/public/join.png
Binary files differ
diff --git a/web-app/public/mom.png b/web-app/public/mom.png
new file mode 100644
index 0000000..f0eda19
--- /dev/null
+++ b/web-app/public/mom.png
Binary files differ
diff --git a/web-app/public/to_person.png b/web-app/public/to_person.png
new file mode 100644
index 0000000..ebd83f1
--- /dev/null
+++ b/web-app/public/to_person.png
Binary files differ
diff --git a/web-app/public/warning.png b/web-app/public/warning.png
new file mode 100644
index 0000000..74daa3a
--- /dev/null
+++ b/web-app/public/warning.png
Binary files differ
diff --git a/web-app/src/App.css b/web-app/src/App.css
index 2afd4ed..59fba74 100644
--- a/web-app/src/App.css
+++ b/web-app/src/App.css
@@ -720,8 +720,8 @@
background: #f8f9fa;
border-radius: 8px;
padding: 14px 16px;
- margin-bottom: 16px;
- text-align: center;
+ margin-bottom: 10px;
+ text-align: left;
}
.success-rate-label {
@@ -730,25 +730,30 @@
margin-bottom: 8px;
}
+.success-rate-row {
+ display: flex;
+ align-items: baseline;
+ gap: 10px;
+ margin-bottom: 10px;
+}
+
.success-rate-value {
font-size: 2.2rem;
font-weight: 700;
color: #1a6fb8;
line-height: 1;
- margin-bottom: 8px;
}
.success-rate-yoy {
display: flex;
align-items: center;
- justify-content: center;
- gap: 6px;
+ gap: 4px;
font-size: 0.8rem;
}
-.yoy-icon {
- color: #52c41a;
- font-size: 0.75rem;
+.yoy-icon-img {
+ width: 12px;
+ height: 7px;
}
.yoy-rate {
@@ -757,7 +762,27 @@
}
.yoy-time {
- color: #999;
+ color: #52c41a;
+}
+
+/* 进度条 */
+.success-rate-progress {
+ width: 100%;
+}
+
+.progress-bar-bg {
+ width: 100%;
+ height: 6px;
+ background: #e8e8e8;
+ border-radius: 3px;
+ overflow: hidden;
+}
+
+.progress-bar-fill {
+ height: 100%;
+ background: #1a6fb8;
+ border-radius: 3px;
+ transition: width 0.3s ease;
}
/* 调解数据看板 - 左右分栏布局 */
@@ -771,10 +796,10 @@
flex-direction: column;
padding: 0;
background: transparent;
- gap: 0;
+ gap: 0px;
}
-.metric-card.right-column > * {
+.metric-card.right-column > *:last-child {
margin-bottom: 0;
}
diff --git a/web-app/src/components/common/WarningAlert.css b/web-app/src/components/common/WarningAlert.css
index 2308984..ec36c75 100644
--- a/web-app/src/components/common/WarningAlert.css
+++ b/web-app/src/components/common/WarningAlert.css
@@ -23,10 +23,18 @@
min-width: 0;
}
-.warning-icon {
- color: #faad14;
- font-size: 1rem;
+.warning-icon-img {
+ width: 16px;
+ height: 16px;
flex-shrink: 0;
+ margin-right: 6px;
+}
+
+.warning-modal-icon {
+ width: 16px;
+ height: 16px;
+ margin-right: 8px;
+ vertical-align: middle;
}
.warning-label {
diff --git a/web-app/src/components/common/WarningAlert.jsx b/web-app/src/components/common/WarningAlert.jsx
index 42acb4b..656f7b1 100644
--- a/web-app/src/components/common/WarningAlert.jsx
+++ b/web-app/src/components/common/WarningAlert.jsx
@@ -5,17 +5,20 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Modal, List } from 'antd';
-import { WarningOutlined, RightOutlined } from '@ant-design/icons';
+import { RightOutlined } from '@ant-design/icons';
import { useCaseData } from '../../contexts/CaseDataContext';
import MediationTimelineAPIService from '../../services/MediationTimelineAPIService';
import './WarningAlert.css';
+
+// 警告图标图片
+const WARNING_ICON = '/warning.png';
/**
* 预警消息列表弹窗
*/
const WarningModal = ({ visible, warnings, onClose }) => (
<Modal
- title={<span><WarningOutlined style={{ color: '#faad14', marginRight: 8 }} />预警消息列表</span>}
+ title={<span><img src={WARNING_ICON} alt="warning" className="warning-modal-icon" />预警消息列表</span>}
open={visible}
onCancel={onClose}
footer={null}
@@ -90,7 +93,7 @@
return (
<div className="warning-alert">
<div className="warning-alert-content">
- <WarningOutlined className="warning-icon" />
+ <img src={WARNING_ICON} alt="warning" className="warning-icon-img" />
<span className="warning-label">预警:</span>
<span className="warning-text">{firstWarning.content}</span>
</div>
diff --git a/web-app/src/components/dashboard/AISuggestionCard.css b/web-app/src/components/dashboard/AISuggestionCard.css
index 01b6a3b..6137f5b 100644
--- a/web-app/src/components/dashboard/AISuggestionCard.css
+++ b/web-app/src/components/dashboard/AISuggestionCard.css
@@ -4,11 +4,23 @@
*/
.ai-suggestion-card {
- background: linear-gradient(135deg, #e6f4ff, #f0f7ff);
- border-radius: 8px;
+ background: #1a6fb8;
+ border-radius: 12px;
padding: 14px 16px;
margin-top: 12px;
- border-left: 4px solid #1a6fb8;
+ box-shadow: 0px 4px 6px -4px rgba(0,0,0,0.10), 0px 10px 15px -3px rgba(0,0,0,0.10);
+ position: relative;
+ overflow: hidden;
+}
+
+.ai-suggestion-bg {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+ width: 48px;
+ height: 50px;
+ opacity: 0.1;
+ pointer-events: none;
}
.ai-suggestion-header {
@@ -20,19 +32,19 @@
.ai-suggestion-icon {
font-size: 1rem;
- color: #1a6fb8;
+ color: #fff;
}
.ai-suggestion-title {
font-size: 0.9rem;
font-weight: 600;
- color: #0d4a8a;
+ color: #fff;
}
.ai-suggestion-content {
font-size: 0.85rem;
line-height: 1.6;
- color: #333;
+ color: #fff;
max-height: 80px;
overflow: hidden;
text-overflow: ellipsis;
@@ -47,11 +59,22 @@
}
.ai-suggestion-btn {
- padding: 0;
+ padding: 8px 24px;
font-size: 0.85rem;
- color: #1a6fb8;
+ color: #FFFFFF;
+ background: rgba(255, 255, 255, 0.9);
+ border-radius: 20px;
+ border: none;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ height: auto;
+ line-height: 1.5;
+ margin: 10px;
+ width: 90%;
+ background: rgba(255, 255, 255, 0.20);
+ border-radius: 8px;
}
.ai-suggestion-btn:hover {
color: #0d4a8a;
+ background: rgba(255, 255, 255, 1);
}
diff --git a/web-app/src/components/dashboard/AISuggestionCard.jsx b/web-app/src/components/dashboard/AISuggestionCard.jsx
index 4663f36..f326727 100644
--- a/web-app/src/components/dashboard/AISuggestionCard.jsx
+++ b/web-app/src/components/dashboard/AISuggestionCard.jsx
@@ -22,6 +22,9 @@
return (
<div className="ai-suggestion-card">
+ {/* 背景图标 */}
+ <img src="/ai-bg.png" alt="" className="ai-suggestion-bg" />
+
{/* 标题 */}
<div className="ai-suggestion-header">
<BulbOutlined className="ai-suggestion-icon" />
diff --git a/web-app/src/components/dashboard/NegotiationProgress.css b/web-app/src/components/dashboard/NegotiationProgress.css
index d2d6c83..111229b 100644
--- a/web-app/src/components/dashboard/NegotiationProgress.css
+++ b/web-app/src/components/dashboard/NegotiationProgress.css
@@ -7,7 +7,6 @@
background: #f8f9fa;
border-radius: 8px;
padding: 12px 16px;
- border-top: 3px solid #1a6fb8;
}
.negotiation-header {
@@ -40,21 +39,26 @@
.progress-dot-wrapper {
display: flex;
align-items: center;
- flex: 1;
+ justify-content: flex-start;
}
.progress-dot-wrapper.last {
flex: 0;
}
-/* 进度点 */
+/* 进度短横线 */
.progress-dot {
- width: 10px;
- height: 10px;
- border-radius: 50%;
+ width: 16px;
+ height: 4px;
+ border-radius: 2px;
background: #d9d9d9;
flex-shrink: 0;
transition: background 0.3s;
+ margin-left: 5px;
+}
+
+.progress-dot-wrapper:first-child .progress-dot {
+ margin-left: 0;
}
.progress-dot.active {
@@ -64,9 +68,9 @@
/* 连接线 */
.progress-line {
flex: 1;
- height: 3px;
+ height: 2px;
background: #d9d9d9;
- margin: 0 2px;
+ margin: 0 4px;
transition: background 0.3s;
}
diff --git a/web-app/src/components/dashboard/PartyInfoCard.css b/web-app/src/components/dashboard/PartyInfoCard.css
index 0a34ebe..b6538c4 100644
--- a/web-app/src/components/dashboard/PartyInfoCard.css
+++ b/web-app/src/components/dashboard/PartyInfoCard.css
@@ -7,7 +7,7 @@
background: #f8f9fa;
border-radius: 8px;
padding: 12px 16px;
- margin-bottom: 16px;
+ margin-bottom: 10px;
}
.party-info-title {
@@ -34,21 +34,28 @@
padding: 8px;
}
-/* 情绪标签 */
+/* 情绪标签 - 实心红背景白字 */
.party-tag {
position: absolute;
top: -4px;
left: 50%;
transform: translateX(-50%);
font-size: 0.7rem;
- padding: 0 6px;
- line-height: 18px;
- border-radius: 4px;
+ padding: 2px 8px;
+ line-height: 16px;
+ border-radius: 10px;
+ background-color: #ff4d4f !important;
+ color: white !important;
+ border: none !important;
}
-.party-avatar {
+.party-avatar-img {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
margin-top: 12px;
margin-bottom: 8px;
+ object-fit: cover;
}
.party-role {
@@ -76,7 +83,8 @@
padding: 0 8px;
}
-.vs-icon {
- font-size: 1.5rem;
- color: #d9d9d9;
+.vs-icon-img {
+ width: 24px;
+ height: 24px;
+ object-fit: contain;
}
diff --git a/web-app/src/components/dashboard/PartyInfoCard.jsx b/web-app/src/components/dashboard/PartyInfoCard.jsx
index c04a606..f33980d 100644
--- a/web-app/src/components/dashboard/PartyInfoCard.jsx
+++ b/web-app/src/components/dashboard/PartyInfoCard.jsx
@@ -4,11 +4,15 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
-import { Avatar, Tag } from 'antd';
-import { UserOutlined, TeamOutlined } from '@ant-design/icons';
+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';
@@ -41,8 +45,7 @@
* 当事人信息卡片
*/
const PartyCard = ({ person, isApplicantSide }) => {
- const avatarIcon = isApplicantSide ? <UserOutlined /> : <TeamOutlined />;
- const avatarBg = isApplicantSide ? '#1a6fb8' : '#faad14';
+ const avatarSrc = isApplicantSide ? APPLICANT_AVATAR : RESPONDENT_AVATAR;
return (
<div className={`party-card ${isApplicantSide ? 'applicant' : 'respondent'}`}>
@@ -54,11 +57,10 @@
)}
{/* 头像 */}
- <Avatar
- size={48}
- icon={avatarIcon}
- style={{ backgroundColor: avatarBg }}
- className="party-avatar"
+ <img
+ src={avatarSrc}
+ alt={isApplicantSide ? '申请人' : '被申请人'}
+ className="party-avatar-img"
/>
{/* 角色标签 */}
@@ -72,12 +74,15 @@
);
};
+// VS分隔符图片
+const VS_ICON = '/join.png';
+
/**
* VS分隔符
*/
const VSSeparator = () => (
<div className="vs-separator">
- <span className="vs-icon">⚖</span>
+ <img src={VS_ICON} alt="VS" className="vs-icon-img" />
</div>
);
diff --git a/web-app/src/components/dashboard/TabContainer.jsx b/web-app/src/components/dashboard/TabContainer.jsx
index 4e8c3a6..e390898 100644
--- a/web-app/src/components/dashboard/TabContainer.jsx
+++ b/web-app/src/components/dashboard/TabContainer.jsx
@@ -6,7 +6,7 @@
import MediationAgreementAPIService from '../../services/MediationAgreementAPIService';
import { getMergedParams } from '../../utils/urlParams';
import { message, Spin, Tag, Modal, Button, Input, Image } from 'antd';
-import { PhoneOutlined, ArrowUpOutlined } from '@ant-design/icons';
+import { PhoneOutlined } from '@ant-design/icons';
import { CallRecordModal } from '../call-record';
// 新增组件导入
@@ -129,6 +129,9 @@
const updateTime = formatDuration(timeline.before_duration);
const successRate = formatSuccessRate(mediation.success_rate);
+ // 获取成功率数值(用于进度条)
+ const successRateValue = (mediation.success_rate || 0) * 100;
+
// 获取同比数据
const yoyData = getSuccessRateYoY(mediation);
const yoyRate = yoyData.rate >= 0 ? `+${yoyData.rate.toFixed(0)}%` : `${yoyData.rate.toFixed(0)}%`;
@@ -166,11 +169,18 @@
{/* 预计调解成功率 */}
<div className="success-rate-section">
<div className="success-rate-label">预计调解成功率</div>
- <div className="success-rate-value">{successRate}</div>
- <div className="success-rate-yoy">
- <ArrowUpOutlined className="yoy-icon" />
- <span className="yoy-rate">{yoyRate}</span>
- <span className="yoy-time">较{yoyHours}小时前</span>
+ <div className="success-rate-row">
+ <span className="success-rate-value">{successRate}</span>
+ <div className="success-rate-yoy">
+ <img src="/mom.png" alt="" className="yoy-icon-img" />
+ <span className="yoy-rate">{yoyRate}</span>
+ <span className="yoy-time">较{yoyHours}小时前</span>
+ </div>
+ </div>
+ <div className="success-rate-progress">
+ <div className="progress-bar-bg">
+ <div className="progress-bar-fill" style={{ width: `${successRateValue}%` }}></div>
+ </div>
</div>
</div>
--
Gitblit v1.8.0