From 6a2adec4956d5f5eef09c2e6e16d70460dc27772 Mon Sep 17 00:00:00 2001
From: chengmw <chengmingwei_1984122@126.com>
Date: Wed, 01 Apr 2026 10:17:57 +0800
Subject: [PATCH] feat: 新增调解看板 UI 组件和服务 - 包含头部、警告提示、AI 建议卡片、协商进度、当事人信息卡片及时间轴 API

---
 web-app/src/components/common/AppHeader.jsx                            |  124 ++++
 web-app/src/components/dashboard/PartyInfoCard.jsx                     |  136 +++++
 web-app/src/components/common/WarningAlert.css                         |  119 ++++
 web-app/src/services/MediationTimelineAPIService.js                    |   31 +
 web-app/src/components/dashboard/AISuggestionCard.css                  |   57 ++
 web-app/src/components/dashboard/NegotiationProgress.jsx               |   88 +++
 web-app/src/components/dashboard/AISuggestionCard.jsx                  |   50 +
 web-app/src/components/dashboard/NegotiationProgress.css               |   75 ++
 openspec/changes/upgrade-homepage-layout/tasks.md                      |   79 +++
 openspec/changes/upgrade-homepage-layout/specs/homepage-layout/spec.md |  166 ++++++
 web-app/src/components/common/WarningAlert.jsx                         |  116 ++++
 openspec/changes/upgrade-homepage-layout/design.md                     |  163 ++++++
 web-app/src/components/dashboard/PartyInfoCard.css                     |   82 +++
 web-app/src/components/common/AppHeader.css                            |  131 +++++
 openspec/changes/upgrade-homepage-layout/proposal.md                   |   88 +++
 15 files changed, 1,505 insertions(+), 0 deletions(-)

diff --git a/openspec/changes/upgrade-homepage-layout/design.md b/openspec/changes/upgrade-homepage-layout/design.md
new file mode 100644
index 0000000..aefb0ce
--- /dev/null
+++ b/openspec/changes/upgrade-homepage-layout/design.md
@@ -0,0 +1,163 @@
+# Design: 首页布局升级优化
+
+## Context
+
+当前首页(index.html)需要按照最新原型进行全面升级,涉及多个新组件的添加和现有组件的修改。本次升级主要目标是提升调解员工作效率,通过可视化展示关键信息。
+
+**原型参考**: `document/原型/index.html` 和用户提供的原型图片
+
+## Goals / Non-Goals
+
+### Goals
+- 1:1还原原型图视觉效果
+- 新增蓝色顶部Header,统一系统导航风格
+- 提供预警消息实时提示,提升调解员响应速度
+- 可视化展示申请双方信息和协商沟通进度
+- 增强调解成功率数据展示,提供同比分析
+
+### Non-Goals
+- 不修改现有API调用机制,复用CaseDataContext
+- 不修改底部悬浮控制面板
+- "查看详细策略建议"功能暂不实现跳转
+
+## Decisions
+
+### 1. 组件架构
+
+**Decision**: 新增独立组件,不侵入现有组件逻辑
+
+```
+components/
+├── common/
+│   ├── AppHeader.jsx          # 顶部Header(新增)
+│   └── WarningAlert.jsx       # 预警提示(新增)
+└── dashboard/
+    ├── PartyInfoCard.jsx      # 申请双方信息(新增)
+    ├── NegotiationProgress.jsx # 协商沟通(新增)
+    ├── AISuggestionCard.jsx   # AI调解建议(新增)
+    └── TabContainer.jsx       # 修改MediationDataBoard
+```
+
+**Rationale**: 保持单一职责,便于维护和测试
+
+### 2. 数据流设计
+
+**Decision**: 复用现有CaseDataContext,新增两个API调用
+
+```
+CaseDataContext
+├── caseData (现有)
+│   ├── mediation.success_rate
+│   ├── mediation.yoy_success_rate
+│   ├── mediation.yoy_before_hours
+│   └── mediation.mediation_count
+├── processNodes (现有)
+└── 新增API调用:
+    ├── getWarningNotifyList(mediationId)
+    └── getPersonList(caseId)
+```
+
+**Rationale**: 
+- 预警消息和当事人列表数据独立于timeline,需单独API获取
+- 成功率同比数据从现有timeline字段获取,无需新API
+
+### 3. Header数据来源
+
+**Decision**: 调解员信息从URL参数获取,使用getMergedParams工具
+
+```javascript
+// 从URL参数获取
+const params = getMergedParams();
+const mediatorInfo = {
+  trueName: params.trueName || '调解员',
+  unit: params.unit || '',
+  roleName: params.roleName || '',
+  avatar: params.avatar || DEFAULT_AVATAR
+};
+```
+
+**Rationale**: 调解员信息由外部系统传入,保持与现有参数获取机制一致
+
+### 4. 预警消息展示策略
+
+**Decision**: 
+- 单条消息: 直接在消息条展示完整内容
+- 多条消息: 展示第一条 + "还有N条预警" + "查看更多"按钮
+- 点击"查看更多": 弹出Modal展示全部预警列表
+
+### 5. 协商沟通进度计算
+
+**Decision**: 
+```javascript
+const currentRound = timeline.mediation?.mediation_count || 0;
+const nodeCount = processNodes.length;
+
+// 总次数计算
+let totalRounds = nodeCount;
+if (currentRound > nodeCount && !isLastNode) {
+  totalRounds = currentRound + 1;
+}
+
+// 渲染点线块
+const dots = Array(totalRounds).fill(false).map((_, i) => i < currentRound);
+```
+
+## Layout Structure
+
+```
+┌────────────────────────────────────────────────────────┐
+│  AppHeader (蓝色背景)                                    │
+│  [矛盾纠纷应用]                    [🔔2] [👤李X萌 XX区..]│
+├────────────────────────────────────────────────────────┤
+│  TopSection (现有案件信息头部)                           │
+├────────────────────────────────────────────────────────┤
+│  MediationProgress (调解进度条)                          │
+├────────────────────────────────────────────────────────┤
+│  WarningAlert (浅黄色预警提示)                           │
+│  ⚠️ 预警:申请人张三情绪激动...        [还有2条] [查看更多]│
+├────────────────────────────────────────────────────────┤
+│  TabContainer                                          │
+│  ┌─────────────────────────────────────────────────────┤
+│  │ MediationDataBoard (调解分析Tab)                     │
+│  │ ┌──────────────────────┬─────────────────────────┐  │
+│  │ │ 诉求差距分析          │ 申请双方                 │  │
+│  │ │ ┌────────────────┐   │ [👤申请人] VS [🏢被申请人]│  │
+│  │ │ │ 主要分歧点...   │   │                         │  │
+│  │ │ └────────────────┘   │ 预计调解成功率            │  │
+│  │ │                      │ 68% ↑+8% 较3小时前       │  │
+│  │ │ AI调解建议            │                         │  │
+│  │ │ ┌────────────────┐   │ 协商沟通                 │  │
+│  │ │ │ 建议调解员...   │   │ 第6轮                   │  │
+│  │ │ │ [查看详细策略]  │   │ ●━●━●━●━●━○             │  │
+│  │ │ └────────────────┘   │                         │  │
+│  │ └──────────────────────┴─────────────────────────┘  │
+│  └─────────────────────────────────────────────────────┤
+└────────────────────────────────────────────────────────┘
+```
+
+## Risks / Trade-offs
+
+### Risk 1: API响应延迟
+- **风险**: 预警消息和当事人列表API可能响应慢
+- **缓解**: 组件内部loading状态,不阻塞整体页面渲染
+
+### Risk 2: URL参数缺失
+- **风险**: 调解员信息URL参数可能为空
+- **缓解**: 提供默认值和默认头像
+
+### Risk 3: 布局兼容性
+- **风险**: 新增Header可能影响现有页面滚动
+- **缓解**: Header使用fixed定位,调整body padding-top
+
+## Migration Plan
+
+1. 先创建API服务和新组件(不影响现有功能)
+2. 在App.js中添加AppHeader(影响最小)
+3. 在MediationProgress下方添加WarningAlert
+4. 修改MediationDataBoard布局,集成新组件
+5. 调整CSS样式,验证视觉效果
+
+## Open Questions
+
+- [已解答] AI调解建议内容来源? → 先使用Mock数据
+- [已解答] "查看详细策略建议"跳转? → 暂不跳转,提示"功能升级中"
diff --git a/openspec/changes/upgrade-homepage-layout/proposal.md b/openspec/changes/upgrade-homepage-layout/proposal.md
new file mode 100644
index 0000000..e562710
--- /dev/null
+++ b/openspec/changes/upgrade-homepage-layout/proposal.md
@@ -0,0 +1,88 @@
+# Change: 首页布局升级优化
+
+## Why
+当前首页缺少顶部导航Header、预警提示、申请双方信息展示、协商沟通可视化和AI调解建议等关键功能模块,需要按照最新原型图进行布局升级,提升调解员工作效率和用户体验。
+
+## What Changes
+- **新增**: 蓝色顶部Header组件,包含系统名称、通知图标(带消息数量气泡)、调解员信息
+- **新增**: 预警提示消息条组件(浅黄色背景),支持多条消息查看弹窗
+- **新增**: 申请双方信息组件,展示申请人/被申请人信息及情绪标签
+- **修改**: 预计调解成功率组件,增加同比数据展示(如 +8% 较3小时前)
+- **新增**: 协商沟通面板组件,点线式可视化展示沟通轮次
+- **新增**: AI调解建议面板,展示调解建议内容和详情按钮
+- **新增**: 预警消息API服务 (`/api/v1/mediation-timeline/warning-notify-list/{mediation_id}`)
+- **新增**: 当事人列表API服务 (`/api/v1/mediation-timeline/person-list/{case_id}`)
+
+## Impact
+- **Affected specs**: homepage-layout
+- **Affected code**:
+  - `web-app/src/App.js` - 添加Header组件
+  - `web-app/src/App.css` - 新增Header和相关组件样式
+  - `web-app/src/components/dashboard/TopSection.jsx` - 添加预警提示
+  - `web-app/src/components/dashboard/TabContainer.jsx` - 修改MediationDataBoard组件
+  - 新增组件:
+    - `web-app/src/components/common/AppHeader.jsx` - 顶部Header
+    - `web-app/src/components/common/WarningAlert.jsx` - 预警提示
+    - `web-app/src/components/dashboard/PartyInfoCard.jsx` - 申请双方信息
+    - `web-app/src/components/dashboard/NegotiationProgress.jsx` - 协商沟通
+    - `web-app/src/components/dashboard/AISuggestionCard.jsx` - AI调解建议
+  - `web-app/src/services/MediationTimelineAPIService.js` - 新增API服务
+
+## Data Sources
+
+### 1. Header调解员信息
+从URL请求参数获取:
+- `trueName` - 姓名
+- `unit` - 地址
+- `roleName` - 角色
+- `avatar` - 头像(空则使用默认头像)
+
+### 2. 预警消息API
+```
+GET /api/v1/mediation-timeline/warning-notify-list/{mediation_id}
+
+Response:
+{
+  "code": 200,
+  "data": [
+    {
+      "id": "1",
+      "content": "申请人张三情绪激动...",
+      "create_time": "2026-12-20 12:30:15",
+      "level_type": "3"
+    }
+  ]
+}
+```
+
+### 3. 当事人列表API
+```
+GET /api/v1/mediation-timeline/person-list/{case_id}
+
+Response:
+{
+  "code": 200,
+  "data": [
+    {
+      "id": "202602261114261001",
+      "per_type": "15_020008-1",
+      "per_type_name": "申请方当事人",
+      "true_name": "刘树杰",
+      "record_id": "1001",
+      "tag_name": "情绪激动",
+      "tag_style": "red"
+    }
+  ]
+}
+```
+
+### 4. 成功率同比数据
+从 `CaseDataContext` 或 `localStorage.case_data_timeline` 获取:
+- `mediation.yoy_success_rate` - 同比增长率
+- 若为空: `(mediation.success_rate - mediation.last_success_rate) * 100`
+- `mediation.yoy_before_hours` - 对比时间(小时),若为空则为0
+
+### 5. 协商沟通轮次
+- 当前轮次: `timeline.mediation?.mediation_count`
+- 总次数: 默认为流程节点总数
+- 当沟通次数超过总次数且未到最后节点时: 总次数 = 沟通次数 + 1
diff --git a/openspec/changes/upgrade-homepage-layout/specs/homepage-layout/spec.md b/openspec/changes/upgrade-homepage-layout/specs/homepage-layout/spec.md
new file mode 100644
index 0000000..ecfb403
--- /dev/null
+++ b/openspec/changes/upgrade-homepage-layout/specs/homepage-layout/spec.md
@@ -0,0 +1,166 @@
+# Homepage Layout Specification
+
+## ADDED Requirements
+
+### Requirement: App Header Component
+系统 SHALL 在页面顶部显示蓝色背景的Header组件,包含系统名称、通知图标和调解员信息。
+
+#### Scenario: Header displays system name
+- **WHEN** 页面加载完成
+- **THEN** Header左侧显示"矛盾纠纷应用"系统名称
+
+#### Scenario: Header displays notification icon with badge
+- **WHEN** 存在未读通知消息
+- **THEN** Header右侧显示通知图标,图标右上角显示红色气泡,气泡内显示未读消息数量
+
+#### Scenario: Header displays mediator info from URL params
+- **WHEN** URL参数包含trueName、unit、roleName、avatar
+- **THEN** Header右侧显示调解员头像、姓名、"地址|角色"格式的信息
+
+#### Scenario: Header uses default avatar when param empty
+- **WHEN** URL参数avatar为空
+- **THEN** 使用系统默认头像图片
+
+#### Scenario: Notification popup on icon click
+- **WHEN** 用户点击通知图标
+- **THEN** 显示通知消息列表弹窗
+
+---
+
+### Requirement: Warning Alert Component
+系统 SHALL 在调解进度条下方显示预警提示消息条,支持多条消息查看。
+
+#### Scenario: Single warning message display
+- **WHEN** 预警消息API返回1条消息
+- **THEN** 预警条直接显示完整消息内容,背景为浅黄色
+
+#### Scenario: Multiple warning messages display
+- **WHEN** 预警消息API返回多条消息
+- **THEN** 预警条显示第一条消息 + "还有N条预警" + "查看更多"按钮
+
+#### Scenario: Warning modal on view more click
+- **WHEN** 用户点击"查看更多"按钮
+- **THEN** 弹出Modal显示全部预警消息列表
+
+#### Scenario: Warning API call
+- **WHEN** 页面加载且mediationId存在
+- **THEN** 调用 `/api/v1/mediation-timeline/warning-notify-list/{mediation_id}` 获取预警数据
+
+---
+
+### Requirement: Party Info Card Component
+系统 SHALL 在调解分析面板右侧显示申请双方信息卡片。
+
+#### Scenario: Applicant info display
+- **WHEN** 当事人列表API返回申请方当事人数据
+- **THEN** 左侧显示申请人头像、姓名,上方显示情绪标签(如有)
+
+#### Scenario: Respondent info display
+- **WHEN** 当事人列表API返回被申请方当事人数据
+- **THEN** 右侧显示被申请人头像、公司名称,上方显示标签(如有)
+
+#### Scenario: VS separator display
+- **WHEN** 同时存在申请人和被申请人
+- **THEN** 中间显示VS分隔符图标
+
+#### Scenario: Emotion tag style
+- **WHEN** 当事人数据包含tag_name和tag_style
+- **THEN** 按tag_style渲染标签颜色(red=红色等)
+
+#### Scenario: Person list API call
+- **WHEN** 页面加载且caseId存在
+- **THEN** 调用 `/api/v1/mediation-timeline/person-list/{case_id}` 获取当事人数据
+
+---
+
+### Requirement: Success Rate YoY Display
+系统 SHALL 在预计调解成功率组件中显示同比数据。
+
+#### Scenario: YoY rate from API field
+- **WHEN** timeline.mediation.yoy_success_rate存在
+- **THEN** 显示该值作为同比增长率(如+8%)
+
+#### Scenario: YoY rate calculation fallback
+- **WHEN** yoy_success_rate为空
+- **THEN** 计算 (success_rate - last_success_rate) * 100 作为同比增长率
+
+#### Scenario: YoY time display
+- **WHEN** timeline.mediation.yoy_before_hours存在
+- **THEN** 显示"较{yoy_before_hours}小时前"
+
+#### Scenario: YoY time default
+- **WHEN** yoy_before_hours为空
+- **THEN** 显示"较0小时前"
+
+---
+
+### Requirement: Negotiation Progress Component
+系统 SHALL 在调解分析面板右侧显示协商沟通进度组件。
+
+#### Scenario: Round count display
+- **WHEN** timeline.mediation.mediation_count存在
+- **THEN** 显示"第{mediation_count}轮"
+
+#### Scenario: Progress dots default count
+- **WHEN** 沟通次数 <= 流程节点总数
+- **THEN** 总次数 = 流程节点总数,已完成轮次显示蓝色,未完成显示灰色
+
+#### Scenario: Progress dots dynamic count
+- **WHEN** 沟通次数 > 流程节点总数 且 未到最后节点
+- **THEN** 总次数 = 沟通次数 + 1
+
+#### Scenario: Progress dots all complete
+- **WHEN** 已到达最后节点
+- **THEN** 全部点显示蓝色
+
+---
+
+### Requirement: AI Suggestion Card Component
+系统 SHALL 在诉求差距分析下方显示AI调解建议面板。
+
+#### Scenario: AI suggestion content display
+- **WHEN** 面板加载
+- **THEN** 显示AI调解建议内容(Mock数据),背景为浅蓝色
+
+#### Scenario: View detail button display
+- **WHEN** 面板加载
+- **THEN** 底部显示"查看详细策略建议"按钮
+
+#### Scenario: View detail button click
+- **WHEN** 用户点击"查看详细策略建议"按钮
+- **THEN** 显示提示消息"该功能正在升级中,敬请期待!"
+
+---
+
+### Requirement: Warning Notify API Service
+系统 SHALL 提供预警消息列表API服务方法。
+
+#### Scenario: Get warning notify list
+- **WHEN** 调用 getWarningNotifyList(mediationId)
+- **THEN** 发送GET请求到 `/api/v1/mediation-timeline/warning-notify-list/{mediationId}`
+- **AND** 返回预警消息数组
+
+---
+
+### Requirement: Person List API Service
+系统 SHALL 提供当事人列表API服务方法。
+
+#### Scenario: Get person list
+- **WHEN** 调用 getPersonList(caseId)
+- **THEN** 发送GET请求到 `/api/v1/mediation-timeline/person-list/{caseId}`
+- **AND** 返回当事人数组
+
+---
+
+## MODIFIED Requirements
+
+### Requirement: Mediation Data Board Layout
+系统 SHALL 将调解数据看板调整为左右两栏布局。
+
+#### Scenario: Left column content
+- **WHEN** 调解分析Tab激活
+- **THEN** 左列显示:诉求差距分析 + AI调解建议面板
+
+#### Scenario: Right column content
+- **WHEN** 调解分析Tab激活
+- **THEN** 右列显示:申请双方信息 + 预计调解成功率(含同比) + 协商沟通进度
diff --git a/openspec/changes/upgrade-homepage-layout/tasks.md b/openspec/changes/upgrade-homepage-layout/tasks.md
new file mode 100644
index 0000000..8496b29
--- /dev/null
+++ b/openspec/changes/upgrade-homepage-layout/tasks.md
@@ -0,0 +1,79 @@
+# Tasks: 首页布局升级优化
+
+## 1. API服务层
+
+- [ ] 1.1 创建 `MediationTimelineAPIService.js` 服务文件
+- [ ] 1.2 实现 `getWarningNotifyList(mediationId)` 方法 - 获取预警消息列表
+- [ ] 1.3 实现 `getPersonList(caseId)` 方法 - 获取当事人列表
+
+## 2. 蓝色顶部Header组件
+
+- [ ] 2.1 创建 `AppHeader.jsx` 组件
+- [ ] 2.2 实现左侧系统名称"矛盾纠纷应用"展示
+- [ ] 2.3 实现右侧通知图标 + 红色气泡消息数量
+- [ ] 2.4 实现右侧调解员信息展示(从URL参数获取trueName/unit/roleName/avatar)
+- [ ] 2.5 实现通知列表弹窗(点击通知图标触发)
+- [ ] 2.6 添加Header相关CSS样式(蓝色背景渐变)
+- [ ] 2.7 在 `App.js` 中集成 AppHeader 组件
+
+## 3. 预警提示消息组件
+
+- [ ] 3.1 创建 `WarningAlert.jsx` 组件
+- [ ] 3.2 实现浅黄色预警消息条展示(单条时直接显示)
+- [ ] 3.3 实现多条消息时右侧显示数量 + "查看更多"按钮
+- [ ] 3.4 实现预警消息详情弹窗(Modal)
+- [ ] 3.5 添加预警提示相关CSS样式
+- [ ] 3.6 在 `MediationProgress` 组件下方集成预警提示
+
+## 4. 申请双方信息组件
+
+- [ ] 4.1 创建 `PartyInfoCard.jsx` 组件
+- [ ] 4.2 实现申请人信息展示(头像 + 姓名 + 情绪标签)
+- [ ] 4.3 实现中间VS分隔符展示
+- [ ] 4.4 实现被申请人信息展示(头像 + 公司名称 + 标签)
+- [ ] 4.5 实现情绪标签样式(根据tag_style显示不同颜色)
+- [ ] 4.6 添加申请双方信息相关CSS样式
+- [ ] 4.7 在 `MediationDataBoard` 右侧区域集成组件
+
+## 5. 预计调解成功率组件改进
+
+- [ ] 5.1 修改 `MediationDataBoard` 中的成功率展示
+- [ ] 5.2 实现同比数据获取逻辑(yoy_success_rate或计算差值)
+- [ ] 5.3 实现"较X小时前"时间展示(yoy_before_hours)
+- [ ] 5.4 添加成功率同比展示样式(绿色上升箭头 + 百分比)
+
+## 6. 协商沟通组件
+
+- [ ] 6.1 创建 `NegotiationProgress.jsx` 组件
+- [ ] 6.2 实现"协商沟通"标题展示
+- [ ] 6.3 实现"第N轮"文字展示
+- [ ] 6.4 实现点线式沟通进度(默认6个点线块)
+- [ ] 6.5 实现进度着色逻辑(已完成蓝色/未完成灰色)
+- [ ] 6.6 实现总次数动态计算(基于流程节点和沟通次数)
+- [ ] 6.7 添加协商沟通相关CSS样式
+- [ ] 6.8 在 `MediationDataBoard` 右侧区域集成组件
+
+## 7. AI调解建议面板
+
+- [ ] 7.1 创建 `AISuggestionCard.jsx` 组件
+- [ ] 7.2 实现AI建议内容展示(Mock数据)
+- [ ] 7.3 实现"查看详细策略建议"按钮
+- [ ] 7.4 实现按钮点击提示("该功能正在升级中,敬请期待!")
+- [ ] 7.5 添加AI调解建议相关CSS样式(浅蓝色背景)
+- [ ] 7.6 在诉求差距分析下方集成组件
+
+## 8. 布局调整与整合
+
+- [ ] 8.1 调整 `App.css` 整体布局适配新Header
+- [ ] 8.2 调整 `MediationDataBoard` 布局为左右两栏
+- [ ] 8.3 确保各组件响应式适配
+- [ ] 8.4 验证1:1还原原型图效果
+
+## 9. 验证与测试
+
+- [ ] 9.1 验证Header通知功能正常
+- [ ] 9.2 验证预警消息API集成正常
+- [ ] 9.3 验证当事人列表API集成正常
+- [ ] 9.4 验证成功率同比数据计算正确
+- [ ] 9.5 验证协商沟通进度显示正确
+- [ ] 9.6 整体视觉与原型图对比验收
diff --git a/web-app/src/components/common/AppHeader.css b/web-app/src/components/common/AppHeader.css
new file mode 100644
index 0000000..ad94494
--- /dev/null
+++ b/web-app/src/components/common/AppHeader.css
@@ -0,0 +1,131 @@
+/**
+ * AppHeader 组件样式
+ * 蓝色顶部导航栏
+ */
+
+.app-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  background: linear-gradient(135deg, #1a6fb8, #0d4a8a);
+  color: white;
+  padding: 10px 24px;
+  height: 50px;
+  flex-shrink: 0;
+}
+
+/* 左侧区域 */
+.header-left {
+  display: flex;
+  align-items: center;
+}
+
+.header-title {
+  font-size: 1.1rem;
+  font-weight: 600;
+  letter-spacing: 1px;
+}
+
+/* 右侧区域 */
+.header-right {
+  display: flex;
+  align-items: center;
+  gap: 20px;
+}
+
+/* 通知图标区域 */
+.header-notification {
+  cursor: pointer;
+  padding: 6px;
+  border-radius: 50%;
+  transition: background 0.2s;
+}
+
+.header-notification:hover {
+  background: rgba(255, 255, 255, 0.15);
+}
+
+.header-bell-icon {
+  font-size: 1.2rem;
+  color: white;
+}
+
+/* 调解员信息区域 */
+.header-mediator {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.mediator-avatar {
+  width: 32px;
+  height: 32px;
+  border: 2px solid rgba(255, 255, 255, 0.3);
+}
+
+.mediator-details {
+  display: flex;
+  flex-direction: column;
+  line-height: 1.3;
+}
+
+.mediator-name {
+  font-size: 0.9rem;
+  font-weight: 600;
+}
+
+.mediator-role {
+  font-size: 0.75rem;
+  opacity: 0.85;
+}
+
+.mediator-status-dot {
+  width: 8px;
+  height: 8px;
+  background: #52c41a;
+  border-radius: 50%;
+  margin-left: 4px;
+}
+
+/* 通知列表弹窗 */
+.notification-popover .ant-popover-inner {
+  max-width: 320px;
+}
+
+.notification-list {
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+.notification-item {
+  padding: 8px 0;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.notification-item:last-child {
+  border-bottom: none;
+}
+
+.notification-content {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.notification-text {
+  font-size: 0.85rem;
+  color: #333;
+  line-height: 1.4;
+}
+
+.notification-time {
+  font-size: 0.75rem;
+  color: #999;
+}
+
+.notification-empty {
+  padding: 20px;
+  text-align: center;
+  color: #999;
+  font-size: 0.85rem;
+}
diff --git a/web-app/src/components/common/AppHeader.jsx b/web-app/src/components/common/AppHeader.jsx
new file mode 100644
index 0000000..abd1f39
--- /dev/null
+++ b/web-app/src/components/common/AppHeader.jsx
@@ -0,0 +1,124 @@
+/**
+ * AppHeader 组件 - 蓝色顶部导航栏
+ * 包含系统名称、通知图标、调解员信息
+ */
+
+import React, { useState, useCallback } from 'react';
+import { Badge, Popover, List, Avatar } from 'antd';
+import { BellOutlined, UserOutlined } from '@ant-design/icons';
+import { getMergedParams } from '../../utils/urlParams';
+import './AppHeader.css';
+
+// 默认头像
+const DEFAULT_AVATAR = 'http://gz.hugeinfo.com.cn/dyh/wx414ae04ac3f10b4e/images/pngAI_logo.png';
+
+/**
+ * 从URL参数获取调解员信息
+ */
+const getMediatorInfo = () => {
+  const params = getMergedParams();
+  return {
+    trueName: params.trueName || '调解员',
+    unit: params.unit || '',
+    roleName: params.roleName || '管理员',
+    avatar: params.avatar || ''
+  };
+};
+
+/**
+ * 通知列表组件
+ */
+const NotificationList = ({ notifications, onClose }) => {
+  if (!notifications?.length) {
+    return (
+      <div className="notification-empty">
+        <span>暂无新通知</span>
+      </div>
+    );
+  }
+
+  return (
+    <List
+      className="notification-list"
+      dataSource={notifications}
+      renderItem={(item) => (
+        <List.Item className="notification-item">
+          <div className="notification-content">
+            <span className="notification-text">{item.content || item.title}</span>
+            <span className="notification-time">{item.create_time || item.time}</span>
+          </div>
+        </List.Item>
+      )}
+    />
+  );
+};
+
+/**
+ * AppHeader 主组件
+ */
+const AppHeader = ({ notifications = [] }) => {
+  const [popoverVisible, setPopoverVisible] = useState(false);
+  const mediatorInfo = getMediatorInfo();
+
+  // 处理Popover显示状态
+  const handlePopoverChange = useCallback((visible) => {
+    setPopoverVisible(visible);
+  }, []);
+
+  // 渲染通知图标和气泡
+  const renderNotificationIcon = () => (
+    <Badge count={notifications.length} offset={[-2, 2]} size="small">
+      <BellOutlined className="header-bell-icon" />
+    </Badge>
+  );
+
+  // 渲染调解员信息
+  const renderMediatorInfo = () => (
+    <div className="header-mediator">
+      <Avatar 
+        src={mediatorInfo.avatar || DEFAULT_AVATAR} 
+        icon={!mediatorInfo.avatar && <UserOutlined />}
+        className="mediator-avatar"
+      />
+      <div className="mediator-details">
+        <span className="mediator-name">{mediatorInfo.trueName}</span>
+        <span className="mediator-role">
+          {mediatorInfo.unit && `${mediatorInfo.unit} | `}{mediatorInfo.roleName}
+        </span>
+      </div>
+      <span className="mediator-status-dot" />
+    </div>
+  );
+
+  return (
+    <header className="app-header">
+      {/* 左侧:系统名称 */}
+      <div className="header-left">
+        <span className="header-title">矛盾纠纷应用</span>
+      </div>
+
+      {/* 右侧:通知+调解员信息 */}
+      <div className="header-right">
+        {/* 通知图标 */}
+        <Popover
+          content={<NotificationList notifications={notifications} />}
+          title="系统通知"
+          trigger="click"
+          open={popoverVisible}
+          onOpenChange={handlePopoverChange}
+          placement="bottomRight"
+          overlayClassName="notification-popover"
+        >
+          <div className="header-notification">
+            {renderNotificationIcon()}
+          </div>
+        </Popover>
+
+        {/* 调解员信息 */}
+        {renderMediatorInfo()}
+      </div>
+    </header>
+  );
+};
+
+export default AppHeader;
diff --git a/web-app/src/components/common/WarningAlert.css b/web-app/src/components/common/WarningAlert.css
new file mode 100644
index 0000000..2308984
--- /dev/null
+++ b/web-app/src/components/common/WarningAlert.css
@@ -0,0 +1,119 @@
+/**
+ * WarningAlert 组件样式
+ * 预警提示消息条
+ */
+
+.warning-alert {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background: linear-gradient(135deg, #fffbe6, #fff7e0);
+  border: 1px solid #ffe58f;
+  border-left: 4px solid #faad14;
+  border-radius: 6px;
+  padding: 10px 16px;
+  margin: 0 24px 12px;
+}
+
+.warning-alert-content {
+  display: flex;
+  align-items: center;
+  flex: 1;
+  gap: 6px;
+  min-width: 0;
+}
+
+.warning-icon {
+  color: #faad14;
+  font-size: 1rem;
+  flex-shrink: 0;
+}
+
+.warning-label {
+  color: #d46b08;
+  font-weight: 600;
+  font-size: 0.9rem;
+  flex-shrink: 0;
+}
+
+.warning-text {
+  color: #ad6800;
+  font-size: 0.9rem;
+  line-height: 1.4;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.warning-alert-actions {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  flex-shrink: 0;
+  margin-left: 16px;
+}
+
+.warning-count {
+  color: #d46b08;
+  font-size: 0.85rem;
+  font-weight: 500;
+}
+
+.warning-more-btn {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  background: transparent;
+  border: 1px solid #faad14;
+  color: #d46b08;
+  padding: 4px 10px;
+  border-radius: 4px;
+  font-size: 0.8rem;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+.warning-more-btn:hover {
+  background: #faad14;
+  color: white;
+}
+
+/* 弹窗样式 */
+.warning-modal .ant-modal-body {
+  max-height: 400px;
+  overflow-y: auto;
+}
+
+.warning-modal-item {
+  display: flex;
+  flex-direction: column;
+  padding: 12px 0;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.warning-modal-item:last-child {
+  border-bottom: none;
+}
+
+.warning-modal-content {
+  display: flex;
+  gap: 8px;
+  line-height: 1.5;
+}
+
+.warning-modal-index {
+  color: #faad14;
+  font-weight: 600;
+  flex-shrink: 0;
+}
+
+.warning-modal-text {
+  color: #333;
+  font-size: 0.9rem;
+}
+
+.warning-modal-time {
+  color: #999;
+  font-size: 0.8rem;
+  margin-top: 6px;
+}
diff --git a/web-app/src/components/common/WarningAlert.jsx b/web-app/src/components/common/WarningAlert.jsx
new file mode 100644
index 0000000..42acb4b
--- /dev/null
+++ b/web-app/src/components/common/WarningAlert.jsx
@@ -0,0 +1,116 @@
+/**
+ * WarningAlert 组件 - 预警提示消息条
+ * 在调解进度条下方显示预警消息
+ */
+
+import React, { useState, useEffect, useCallback } from 'react';
+import { Modal, List } from 'antd';
+import { WarningOutlined, RightOutlined } from '@ant-design/icons';
+import { useCaseData } from '../../contexts/CaseDataContext';
+import MediationTimelineAPIService from '../../services/MediationTimelineAPIService';
+import './WarningAlert.css';
+
+/**
+ * 预警消息列表弹窗
+ */
+const WarningModal = ({ visible, warnings, onClose }) => (
+  <Modal
+    title={<span><WarningOutlined style={{ color: '#faad14', marginRight: 8 }} />预警消息列表</span>}
+    open={visible}
+    onCancel={onClose}
+    footer={null}
+    width={520}
+    className="warning-modal"
+  >
+    <List
+      dataSource={warnings}
+      renderItem={(item, index) => (
+        <List.Item className="warning-modal-item">
+          <div className="warning-modal-content">
+            <span className="warning-modal-index">{index + 1}.</span>
+            <span className="warning-modal-text">{item.content}</span>
+          </div>
+          <span className="warning-modal-time">{item.create_time}</span>
+        </List.Item>
+      )}
+    />
+  </Modal>
+);
+
+/**
+ * WarningAlert 主组件
+ */
+const WarningAlert = () => {
+  const { caseData } = useCaseData();
+  const [warnings, setWarnings] = useState([]);
+  const [modalVisible, setModalVisible] = useState(false);
+  const [loading, setLoading] = useState(false);
+
+  const mediationId = caseData?.mediation?.id;
+
+  // 加载预警消息
+  const loadWarnings = useCallback(async () => {
+    if (!mediationId) return;
+    
+    setLoading(true);
+    try {
+      const response = await MediationTimelineAPIService.getWarningNotifyList(mediationId);
+      setWarnings(response.data || []);
+    } catch (err) {
+      console.error('加载预警消息失败:', err);
+      setWarnings([]);
+    } finally {
+      setLoading(false);
+    }
+  }, [mediationId]);
+
+  // 组件挂载时加载数据
+  useEffect(() => {
+    loadWarnings();
+  }, [loadWarnings]);
+
+  // 打开弹窗
+  const handleOpenModal = useCallback(() => {
+    setModalVisible(true);
+  }, []);
+
+  // 关闭弹窗
+  const handleCloseModal = useCallback(() => {
+    setModalVisible(false);
+  }, []);
+
+  // 无预警消息时不渲染
+  if (!warnings.length || loading) {
+    return null;
+  }
+
+  const firstWarning = warnings[0];
+  const hasMore = warnings.length > 1;
+
+  return (
+    <div className="warning-alert">
+      <div className="warning-alert-content">
+        <WarningOutlined className="warning-icon" />
+        <span className="warning-label">预警:</span>
+        <span className="warning-text">{firstWarning.content}</span>
+      </div>
+
+      {hasMore && (
+        <div className="warning-alert-actions">
+          <span className="warning-count">还有{warnings.length - 1}条预警</span>
+          <button className="warning-more-btn" onClick={handleOpenModal}>
+            查看更多 <RightOutlined />
+          </button>
+        </div>
+      )}
+
+      <WarningModal 
+        visible={modalVisible}
+        warnings={warnings}
+        onClose={handleCloseModal}
+      />
+    </div>
+  );
+};
+
+export default WarningAlert;
diff --git a/web-app/src/components/dashboard/AISuggestionCard.css b/web-app/src/components/dashboard/AISuggestionCard.css
new file mode 100644
index 0000000..01b6a3b
--- /dev/null
+++ b/web-app/src/components/dashboard/AISuggestionCard.css
@@ -0,0 +1,57 @@
+/**
+ * AISuggestionCard 组件样式
+ * AI调解建议面板
+ */
+
+.ai-suggestion-card {
+  background: linear-gradient(135deg, #e6f4ff, #f0f7ff);
+  border-radius: 8px;
+  padding: 14px 16px;
+  margin-top: 12px;
+  border-left: 4px solid #1a6fb8;
+}
+
+.ai-suggestion-header {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-bottom: 10px;
+}
+
+.ai-suggestion-icon {
+  font-size: 1rem;
+  color: #1a6fb8;
+}
+
+.ai-suggestion-title {
+  font-size: 0.9rem;
+  font-weight: 600;
+  color: #0d4a8a;
+}
+
+.ai-suggestion-content {
+  font-size: 0.85rem;
+  line-height: 1.6;
+  color: #333;
+  max-height: 80px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 3;
+  -webkit-box-orient: vertical;
+}
+
+.ai-suggestion-footer {
+  margin-top: 10px;
+  text-align: center;
+}
+
+.ai-suggestion-btn {
+  padding: 0;
+  font-size: 0.85rem;
+  color: #1a6fb8;
+}
+
+.ai-suggestion-btn:hover {
+  color: #0d4a8a;
+}
diff --git a/web-app/src/components/dashboard/AISuggestionCard.jsx b/web-app/src/components/dashboard/AISuggestionCard.jsx
new file mode 100644
index 0000000..4663f36
--- /dev/null
+++ b/web-app/src/components/dashboard/AISuggestionCard.jsx
@@ -0,0 +1,50 @@
+/**
+ * AISuggestionCard 组件 - AI调解建议
+ * 展示AI生成的调解建议内容
+ */
+
+import React, { useCallback } from 'react';
+import { Button, message } from 'antd';
+import { BulbOutlined, RightOutlined } from '@ant-design/icons';
+import './AISuggestionCard.css';
+
+// Mock数据 - AI调解建议内容
+const MOCK_SUGGESTION = `建议调解员优先安抚申请人张三的情绪。目前双方在补偿金额上的差距已缩小至15%,可尝试引入"互谅互让"原则进行最后博弈。建议调解员优先安抚申请人张三的情绪。目前双方在补偿金额上的差距已缩小至15%,可尝试引入"互谅互让"原则进行最后博弈。建议调解员优先安抚申请人张三的情绪。`;
+
+/**
+ * AISuggestionCard 主组件
+ */
+const AISuggestionCard = () => {
+  // 点击查看详细策略建议
+  const handleViewDetail = useCallback(() => {
+    message.info('该功能正在升级中,敬请期待!');
+  }, []);
+
+  return (
+    <div className="ai-suggestion-card">
+      {/* 标题 */}
+      <div className="ai-suggestion-header">
+        <BulbOutlined className="ai-suggestion-icon" />
+        <span className="ai-suggestion-title">AI 调解建议</span>
+      </div>
+
+      {/* 建议内容 */}
+      <div className="ai-suggestion-content">
+        {MOCK_SUGGESTION}
+      </div>
+
+      {/* 查看详情按钮 */}
+      <div className="ai-suggestion-footer">
+        <Button 
+          type="link" 
+          className="ai-suggestion-btn"
+          onClick={handleViewDetail}
+        >
+          查看详细策略建议 <RightOutlined />
+        </Button>
+      </div>
+    </div>
+  );
+};
+
+export default AISuggestionCard;
diff --git a/web-app/src/components/dashboard/NegotiationProgress.css b/web-app/src/components/dashboard/NegotiationProgress.css
new file mode 100644
index 0000000..d2d6c83
--- /dev/null
+++ b/web-app/src/components/dashboard/NegotiationProgress.css
@@ -0,0 +1,75 @@
+/**
+ * NegotiationProgress 组件样式
+ * 协商沟通进度点线式展示
+ */
+
+.negotiation-progress {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 12px 16px;
+  border-top: 3px solid #1a6fb8;
+}
+
+.negotiation-header {
+  margin-bottom: 8px;
+}
+
+.negotiation-title {
+  font-size: 0.85rem;
+  color: #6c757d;
+  font-weight: 500;
+}
+
+.negotiation-round {
+  margin-bottom: 12px;
+}
+
+.round-text {
+  font-size: 1.3rem;
+  font-weight: 700;
+  color: #212529;
+}
+
+/* 进度点容器 */
+.negotiation-dots {
+  display: flex;
+  align-items: center;
+}
+
+/* 单个进度点+线 */
+.progress-dot-wrapper {
+  display: flex;
+  align-items: center;
+  flex: 1;
+}
+
+.progress-dot-wrapper.last {
+  flex: 0;
+}
+
+/* 进度点 */
+.progress-dot {
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  background: #d9d9d9;
+  flex-shrink: 0;
+  transition: background 0.3s;
+}
+
+.progress-dot.active {
+  background: #1a6fb8;
+}
+
+/* 连接线 */
+.progress-line {
+  flex: 1;
+  height: 3px;
+  background: #d9d9d9;
+  margin: 0 2px;
+  transition: background 0.3s;
+}
+
+.progress-line.active {
+  background: #1a6fb8;
+}
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;
diff --git a/web-app/src/components/dashboard/PartyInfoCard.css b/web-app/src/components/dashboard/PartyInfoCard.css
new file mode 100644
index 0000000..0a34ebe
--- /dev/null
+++ b/web-app/src/components/dashboard/PartyInfoCard.css
@@ -0,0 +1,82 @@
+/**
+ * PartyInfoCard 组件样式
+ * 申请双方信息展示
+ */
+
+.party-info-card {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 12px 16px;
+  margin-bottom: 16px;
+}
+
+.party-info-title {
+  font-size: 0.9rem;
+  color: #6c757d;
+  margin-bottom: 12px;
+  font-weight: 500;
+}
+
+.party-info-content {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+}
+
+/* 当事人卡片 */
+.party-card {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  position: relative;
+  flex: 1;
+  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;
+}
+
+.party-avatar {
+  margin-top: 12px;
+  margin-bottom: 8px;
+}
+
+.party-role {
+  font-size: 0.75rem;
+  color: #999;
+  margin-bottom: 4px;
+}
+
+.party-name {
+  font-size: 0.9rem;
+  font-weight: 600;
+  color: #333;
+  text-align: center;
+  max-width: 100px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+/* VS分隔符 */
+.vs-separator {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 8px;
+}
+
+.vs-icon {
+  font-size: 1.5rem;
+  color: #d9d9d9;
+}
diff --git a/web-app/src/components/dashboard/PartyInfoCard.jsx b/web-app/src/components/dashboard/PartyInfoCard.jsx
new file mode 100644
index 0000000..495a5a7
--- /dev/null
+++ b/web-app/src/components/dashboard/PartyInfoCard.jsx
@@ -0,0 +1,136 @@
+/**
+ * PartyInfoCard 组件 - 申请双方信息
+ * 展示申请人和被申请人信息,包含头像、姓名和情绪标签
+ */
+
+import React, { useState, useEffect, useCallback } from 'react';
+import { Avatar, Tag } from 'antd';
+import { UserOutlined, TeamOutlined } from '@ant-design/icons';
+import { useCaseData } from '../../contexts/CaseDataContext';
+import MediationTimelineAPIService from '../../services/MediationTimelineAPIService';
+import './PartyInfoCard.css';
+
+// 默认头像
+const DEFAULT_AVATAR_PERSON = 'http://gz.hugeinfo.com.cn/dyh/wx414ae04ac3f10b4e/images/pngAI_logo.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 avatarIcon = isApplicantSide ? <UserOutlined /> : <TeamOutlined />;
+  const avatarBg = isApplicantSide ? '#1a6fb8' : '#faad14';
+
+  return (
+    <div className={`party-card ${isApplicantSide ? 'applicant' : 'respondent'}`}>
+      {/* 标签 */}
+      {person.tag_name && (
+        <Tag color={getTagColor(person.tag_style)} className="party-tag">
+          {person.tag_name}
+        </Tag>
+      )}
+      
+      {/* 头像 */}
+      <Avatar 
+        size={48}
+        icon={avatarIcon}
+        style={{ backgroundColor: avatarBg }}
+        className="party-avatar"
+      />
+      
+      {/* 角色标签 */}
+      <span className="party-role">
+        {isApplicantSide ? '申请人' : '被申请人'}
+      </span>
+      
+      {/* 姓名/公司名 */}
+      <span className="party-name">{person.true_name}</span>
+    </div>
+  );
+};
+
+/**
+ * VS分隔符
+ */
+const VSSeparator = () => (
+  <div className="vs-separator">
+    <span className="vs-icon">⚖</span>
+  </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;
diff --git a/web-app/src/services/MediationTimelineAPIService.js b/web-app/src/services/MediationTimelineAPIService.js
new file mode 100644
index 0000000..40c73a9
--- /dev/null
+++ b/web-app/src/services/MediationTimelineAPIService.js
@@ -0,0 +1,31 @@
+/**
+ * 调解时间线扩展API Service
+ * 处理预警消息、当事人列表等相关接口
+ * 接口前缀: /api/v1/mediation-timeline/*
+ */
+
+import { request } from './request';
+
+class MediationTimelineAPIService {
+  /**
+   * 获取预警消息列表
+   * GET /api/v1/mediation-timeline/warning-notify-list/{mediation_id}
+   * @param {string} mediationId - 调解ID
+   * @returns {Promise<Array>} 预警消息列表
+   */
+  static getWarningNotifyList(mediationId) {
+    return request.get(`/api/v1/mediation-timeline/warning-notify-list/${mediationId}`);
+  }
+
+  /**
+   * 获取当事人列表
+   * GET /api/v1/mediation-timeline/person-list/{case_id}
+   * @param {string} caseId - 案件ID
+   * @returns {Promise<Array>} 当事人列表
+   */
+  static getPersonList(caseId) {
+    return request.get(`/api/v1/mediation-timeline/person-list/${caseId}`);
+  }
+}
+
+export default MediationTimelineAPIService;

--
Gitblit v1.8.0