openspec/changes/upgrade-homepage-layout/proposal.md
@@ -10,8 +10,8 @@ - **修改**: 预计调解成功率组件,增加同比数据展示(如 +8% 较3小时前) - **新增**: 协商沟通面板组件,点线式可视化展示沟通轮次 - **新增**: AI调解建议面板,展示调解建议内容和详情按钮 - **新增**: 预警消息API服务 (`/api/v1/mediation-timeline/warning-notify-list/{mediation_id}`) - **新增**: 当事人列表API服务 (`/api/v1/mediation-timeline/person-list/{case_id}`) - **新增**: 预警消息API服务 (`/api/v1/mediation-timeline/v2/warning-notify-list/{mediation_id}`) - **新增**: 当事人列表API服务 (`/api/v1/mediation-timeline/v2/person-list/{case_id}`) ## Impact - **Affected specs**: homepage-layout @@ -39,7 +39,7 @@ ### 2. 预警消息API ``` GET /api/v1/mediation-timeline/warning-notify-list/{mediation_id} GET /api/v1/mediation-timeline/v2/warning-notify-list/{mediation_id} Response: { @@ -57,7 +57,7 @@ ### 3. 当事人列表API ``` GET /api/v1/mediation-timeline/person-list/{case_id} GET /api/v1/mediation-timeline/v2/person-list/{case_id} Response: { openspec/changes/upgrade-homepage-layout/specs/homepage-layout/spec.md
@@ -44,7 +44,7 @@ #### Scenario: Warning API call - **WHEN** 页面加载且mediationId存在 - **THEN** 调用 `/api/v1/mediation-timeline/warning-notify-list/{mediation_id}` 获取预警数据 - **THEN** 调用 `/api/v1/mediation-timeline/v2/warning-notify-list/{mediation_id}` 获取预警数据 --- @@ -69,7 +69,7 @@ #### Scenario: Person list API call - **WHEN** 页面加载且caseId存在 - **THEN** 调用 `/api/v1/mediation-timeline/person-list/{case_id}` 获取当事人数据 - **THEN** 调用 `/api/v1/mediation-timeline/v2/person-list/{case_id}` 获取当事人数据 --- @@ -137,7 +137,7 @@ #### Scenario: Get warning notify list - **WHEN** 调用 getWarningNotifyList(mediationId) - **THEN** 发送GET请求到 `/api/v1/mediation-timeline/warning-notify-list/{mediationId}` - **THEN** 发送GET请求到 `/api/v1/mediation-timeline/v2/warning-notify-list/{mediationId}` - **AND** 返回预警消息数组 --- @@ -147,7 +147,7 @@ #### Scenario: Get person list - **WHEN** 调用 getPersonList(caseId) - **THEN** 发送GET请求到 `/api/v1/mediation-timeline/person-list/{caseId}` - **THEN** 发送GET请求到 `/api/v1/mediation-timeline/v2/person-list/{caseId}` - **AND** 返回当事人数组 --- openspec/changes/upgrade-homepage-layout/tasks.md
@@ -2,78 +2,78 @@ ## 1. API服务层 - [ ] 1.1 创建 `MediationTimelineAPIService.js` 服务文件 - [ ] 1.2 实现 `getWarningNotifyList(mediationId)` 方法 - 获取预警消息列表 - [ ] 1.3 实现 `getPersonList(caseId)` 方法 - 获取当事人列表 - [x] 1.1 创建 `MediationTimelineAPIService.js` 服务文件 - [x] 1.2 实现 `getWarningNotifyList(mediationId)` 方法 - 获取预警消息列表 - [x] 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 组件 - [x] 2.1 创建 `AppHeader.jsx` 组件 - [x] 2.2 实现左侧系统名称"矛盾纠纷应用"展示 - [x] 2.3 实现右侧通知图标 + 红色气泡消息数量 - [x] 2.4 实现右侧调解员信息展示(从URL参数获取trueName/unit/roleName/avatar) - [x] 2.5 实现通知列表弹窗(点击通知图标触发) - [x] 2.6 添加Header相关CSS样式(蓝色背景渐变) - [x] 2.7 在 `App.js` 中集成 AppHeader 组件 ## 3. 预警提示消息组件 - [ ] 3.1 创建 `WarningAlert.jsx` 组件 - [ ] 3.2 实现浅黄色预警消息条展示(单条时直接显示) - [ ] 3.3 实现多条消息时右侧显示数量 + "查看更多"按钮 - [ ] 3.4 实现预警消息详情弹窗(Modal) - [ ] 3.5 添加预警提示相关CSS样式 - [ ] 3.6 在 `MediationProgress` 组件下方集成预警提示 - [x] 3.1 创建 `WarningAlert.jsx` 组件 - [x] 3.2 实现浅黄色预警消息条展示(单条时直接显示) - [x] 3.3 实现多条消息时右侧显示数量 + "查看更多"按钮 - [x] 3.4 实现预警消息详情弹窗(Modal) - [x] 3.5 添加预警提示相关CSS样式 - [x] 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` 右侧区域集成组件 - [x] 4.1 创建 `PartyInfoCard.jsx` 组件 - [x] 4.2 实现申请人信息展示(头像 + 姓名 + 情绪标签) - [x] 4.3 实现中间VS分隔符展示 - [x] 4.4 实现被申请人信息展示(头像 + 公司名称 + 标签) - [x] 4.5 实现情绪标签样式(根据tag_style显示不同颜色) - [x] 4.6 添加申请双方信息相关CSS样式 - [x] 4.7 在 `MediationDataBoard` 右侧区域集成组件 ## 5. 预计调解成功率组件改进 - [ ] 5.1 修改 `MediationDataBoard` 中的成功率展示 - [ ] 5.2 实现同比数据获取逻辑(yoy_success_rate或计算差值) - [ ] 5.3 实现"较X小时前"时间展示(yoy_before_hours) - [ ] 5.4 添加成功率同比展示样式(绿色上升箭头 + 百分比) - [x] 5.1 修改 `MediationDataBoard` 中的成功率展示 - [x] 5.2 实现同比数据获取逻辑(yoy_success_rate或计算差值) - [x] 5.3 实现"较X小时前"时间展示(yoy_before_hours) - [x] 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` 右侧区域集成组件 - [x] 6.1 创建 `NegotiationProgress.jsx` 组件 - [x] 6.2 实现"协商沟通"标题展示 - [x] 6.3 实现"第N轮"文字展示 - [x] 6.4 实现点线式沟通进度(默认6个点线块) - [x] 6.5 实现进度着色逻辑(已完成蓝色/未完成灰色) - [x] 6.6 实现总次数动态计算(基于流程节点和沟通次数) - [x] 6.7 添加协商沟通相关CSS样式 - [x] 6.8 在 `MediationDataBoard` 右侧区域集成组件 ## 7. AI调解建议面板 - [ ] 7.1 创建 `AISuggestionCard.jsx` 组件 - [ ] 7.2 实现AI建议内容展示(Mock数据) - [ ] 7.3 实现"查看详细策略建议"按钮 - [ ] 7.4 实现按钮点击提示("该功能正在升级中,敬请期待!") - [ ] 7.5 添加AI调解建议相关CSS样式(浅蓝色背景) - [ ] 7.6 在诉求差距分析下方集成组件 - [x] 7.1 创建 `AISuggestionCard.jsx` 组件 - [x] 7.2 实现AI建议内容展示(Mock数据) - [x] 7.3 实现"查看详细策略建议"按钮 - [x] 7.4 实现按钮点击提示("该功能正在升级中,敬请期待!") - [x] 7.5 添加AI调解建议相关CSS样式(浅蓝色背景) - [x] 7.6 在诉求差距分析下方集成组件 ## 8. 布局调整与整合 - [ ] 8.1 调整 `App.css` 整体布局适配新Header - [ ] 8.2 调整 `MediationDataBoard` 布局为左右两栏 - [ ] 8.3 确保各组件响应式适配 - [ ] 8.4 验证1:1还原原型图效果 - [x] 8.1 调整 `App.css` 整体布局适配新Header - [x] 8.2 调整 `MediationDataBoard` 布局为左右两栏 - [x] 8.3 确保各组件响应式适配 - [x] 8.4 验证1:1还原原型图效果 ## 9. 验证与测试 - [ ] 9.1 验证Header通知功能正常 - [ ] 9.2 验证预警消息API集成正常 - [ ] 9.3 验证当事人列表API集成正常 - [ ] 9.4 验证成功率同比数据计算正确 - [ ] 9.5 验证协商沟通进度显示正确 - [ ] 9.6 整体视觉与原型图对比验收 - [x] 9.1 验证Header通知功能正常 - [x] 9.2 验证预警消息API集成正常 - [x] 9.3 验证当事人列表API集成正常 - [x] 9.4 验证成功率同比数据计算正确 - [x] 9.5 验证协商沟通进度显示正确 - [x] 9.6 整体视觉与原型图对比验收 web-app/public/ai-bg.png
web-app/public/app_logo.png
web-app/public/in_person.png
web-app/public/join.png
web-app/public/mom.png
web-app/public/to_person.png
web-app/public/warning.png
web-app/src/App.css
@@ -715,6 +715,94 @@ font-weight: 600; } /* 预计调解成功率 - 新版样式 */ .success-rate-section { background: #f8f9fa; border-radius: 8px; padding: 14px 16px; margin-bottom: 10px; text-align: left; } .success-rate-label { font-size: 0.85rem; color: #6c757d; 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; } .success-rate-yoy { display: flex; align-items: center; gap: 4px; font-size: 0.8rem; } .yoy-icon-img { width: 12px; height: 7px; } .yoy-rate { color: #52c41a; font-weight: 600; } .yoy-time { 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; } /* 调解数据看板 - 左右分栏布局 */ .metric-card.left-column { display: flex; flex-direction: column; } .metric-card.right-column { display: flex; flex-direction: column; padding: 0; background: transparent; gap: 0px; } .metric-card.right-column > *:last-child { margin-bottom: 0; } /* 模态窗口样式 */ .modal-overlay { display: none; web-app/src/App.js
@@ -16,6 +16,10 @@ import ToolModal from './components/common/ToolModal'; import OutboundCallWidget from './components/common/OutboundCallWidget'; // 新增组件 import AppHeader from './components/common/AppHeader'; import WarningAlert from './components/common/WarningAlert'; // 工具内容组件 import WageCalculatorContent from './components/tools/WageCalculatorContent'; import LawSearchContent from './components/tools/LawSearchContent'; @@ -103,6 +107,9 @@ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" /> {/* 蓝色顶部Header */} <AppHeader /> {/* 顶部区域 */} <TopSection /> @@ -113,6 +120,9 @@ {/* AI调解进度 */} <MediationProgress /> {/* 预警提示消息 */} <WarningAlert /> {/* 选项卡容器 */} <TabContainer ref={tabContainerRef} /> </div> web-app/src/components/common/AppHeader.jsx
@@ -10,7 +10,7 @@ import './AppHeader.css'; // 默认头像 const DEFAULT_AVATAR = 'http://gz.hugeinfo.com.cn/dyh/wx414ae04ac3f10b4e/images/pngAI_logo.png'; const DEFAULT_AVATAR = '/app_logo.png'; /** * 从URL参数获取调解员信息 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 { 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> 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); } 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" /> 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; } 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; } web-app/src/components/dashboard/PartyInfoCard.jsx
@@ -4,14 +4,17 @@ */ 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 DEFAULT_AVATAR_PERSON = 'http://gz.hugeinfo.com.cn/dyh/wx414ae04ac3f10b4e/images/pngAI_logo.png'; // 申请人头像图片 const APPLICANT_AVATAR = '/in_person.png'; // 被申请人头像图片 const RESPONDENT_AVATAR = '/to_person.png'; /** * 根据per_type判断是申请方还是被申请方 @@ -42,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'}`}> @@ -55,11 +57,10 @@ )} {/* 头像 */} <Avatar size={48} icon={avatarIcon} style={{ backgroundColor: avatarBg }} className="party-avatar" <img src={avatarSrc} alt={isApplicantSide ? '申请人' : '被申请人'} className="party-avatar-img" /> {/* 角色标签 */} @@ -73,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> ); web-app/src/components/dashboard/TabContainer.jsx
@@ -1,6 +1,6 @@ import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; import { useCaseData } from '../../contexts/CaseDataContext'; import { formatDuration, formatSuccessRate, formatRoundCount } from '../../utils/stateTranslator'; import { formatDuration, formatSuccessRate } from '../../utils/stateTranslator'; import ProcessAPIService from '../../services/ProcessAPIService'; import EvidenceAPIService from '../../services/EvidenceAPIService'; import MediationAgreementAPIService from '../../services/MediationAgreementAPIService'; @@ -8,6 +8,11 @@ import { message, Spin, Tag, Modal, Button, Input, Image } from 'antd'; import { PhoneOutlined } from '@ant-design/icons'; import { CallRecordModal } from '../call-record'; // 新增组件导入 import PartyInfoCard from './PartyInfoCard'; import NegotiationProgress from './NegotiationProgress'; import AISuggestionCard from './AISuggestionCard'; const { TextArea } = Input; @@ -89,22 +94,53 @@ }); /** * 获取成功率同比数据 */ const getSuccessRateYoY = (mediation) => { // 优先使用API返回的同比值 if (mediation?.yoy_success_rate !== undefined && mediation?.yoy_success_rate !== null) { return { rate: mediation.yoy_success_rate, hours: mediation.yoy_before_hours || 0 }; } // 计算同比值 const currentRate = mediation?.success_rate || 0; const lastRate = mediation?.last_success_rate || 0; const diff = (currentRate - lastRate) * 100; return { rate: diff, hours: mediation?.yoy_before_hours || 0 }; }; /** * 调解数据看板 */ const MediationDataBoard = () => { const { caseData } = useCaseData(); const timeline = caseData || {}; const mediation = timeline.mediation || {}; // 从 timeline 获取数据 const gapContent = timeline.result || '暂无分歧分析'; const updateTime = formatDuration(timeline.before_duration); const successRate = formatSuccessRate(timeline.mediation?.success_rate); const roundCount = formatRoundCount(timeline.mediation?.mediation_count); 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)}%`; const yoyHours = yoyData.hours; return ( <div className="mediation-metrics"> {/* 左侧:诉求差距分析 */} <div className="metric-card"> {/* 左侧:诉求差距分析 + AI建议 */} <div className="metric-card left-column"> <div className="metric-title"> <i className="fas fa-exclamation-circle"></i> <span>诉求差距分析</span> @@ -120,28 +156,36 @@ {gapContent} </div> </div> {/* AI调解建议 */} <AISuggestionCard /> </div> </div> {/* 右侧:调解数据 */} <div className="metric-card"> <div className="metric-title"> <i className="fas fa-exchange-alt"></i> <span>调解数据</span> </div> <div className="metric-content"> <div className="success-metric"> <div className="success-value">{successRate}</div> <div className="success-label">预计调解成功概率</div> <div className="success-change"> <i className="fas fa-arrow-up"></i><span>较{updateTime} +8%</span> {/* 右侧:申请双方 + 成功率 + 协商沟通 */} <div className="metric-card right-column"> {/* 申请双方信息 */} <PartyInfoCard /> {/* 预计调解成功率 */} <div className="success-rate-section"> <div className="success-rate-label">预计调解成功率</div> <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 style={{ marginTop: 15, fontSize: '0.9rem', color: 'var(--gray-color)' }}> 协商沟通:<span style={{ color: 'var(--dark-color)', fontWeight: 600 }}>{roundCount}</span> </div> <div className="success-rate-progress"> <div className="progress-bar-bg"> <div className="progress-bar-fill" style={{ width: `${successRateValue}%` }}></div> </div> </div> </div> {/* 协商沟通进度 */} <NegotiationProgress /> </div> </div> ); web-app/src/components/dashboard/TopSection.jsx
@@ -23,7 +23,7 @@ <div className="title-icon"> <img style={{ width: 36 }} src="http://gz.hugeinfo.com.cn/dyh/wx414ae04ac3f10b4e/images/pngAI_logo.png" src="/app_logo.png" // alt="云小调" /> </div> web-app/src/services/MediationTimelineAPIService.js
@@ -14,7 +14,7 @@ * @returns {Promise<Array>} 预警消息列表 */ static getWarningNotifyList(mediationId) { return request.get(`/api/v1/mediation-timeline/warning-notify-list/${mediationId}`); return request.get(`/api/v1/mediation-timeline/v2/warning-notify-list/${mediationId}`); } /** @@ -24,7 +24,7 @@ * @returns {Promise<Array>} 当事人列表 */ static getPersonList(caseId) { return request.get(`/api/v1/mediation-timeline/person-list/${caseId}`); return request.get(`/api/v1/mediation-timeline/v2/person-list/${caseId}`); } }