# 技术实现方案:04-WS盘中价格实时更新 > 依据:PLAN-004 | 需求:R-005 | 设计约束:技术约束-001/003/008/010、产品约束-007 ## 技术选型 - **WebSocket 客户端**:浏览器原生 WebSocket(前端直连,无需 ws 库); - **连接地址**:`ws://<激活配置host>:8610/ws`,host 来自激活 QMT 连接配置(R-004 多配置机制,复用热切换); - **订阅协议**:`POST /data/subscribe` body `{ type: 'whole', codes: ['SH','SZ'] }` → `{ ok, sub_id }`; - **推送消息**:`{ type: 'whole', data: { '': TickSnapshot } }`,TickSnapshot.lastPrice = 现价; - **快照补初值**:连接后先 `GET /data/tick?codes=<关注codes>` 拉一次快照(WS 只推增量,无 prime); - **退订**:`POST /data/unsubscribe` body `{ sub_id }`(断开时清理)。 ## 架构设计 ### 前端行情数据流(事件驱动) ``` QMT Bridge WS (ws://:8610/ws) │ 推送 { type:'whole', data: { code: { lastPrice, ... } } } ▼ MarketDataProvider (React Context + useReducer) │ 维护 prices: Map │ 事件:onPrice(codes) → 通知订阅方 ▼ 3 个监控表格(AllPositionsTab / StrategyTab) │ 行渲染时读 prices.get(code) 叠加现价 ▼ PriceCell(格式化 + 红涨绿跌 + 变化高亮) ``` ### 关注列表(自动汇总) - 3 个表格各自渲染时,把出现的 code 上报给 MarketDataProvider(`registerCodes(codes)`); - Provider 合并为关注集合,作为快照拉取与推送过滤的依据; - 简化:全量推送本来就带所有 code,前端只从 prices Map 取自己行需要的 code(无需显式过滤,天然按需)。 ### 生命周期 - 挂载:获取激活配置 host → 拉快照 → 建 WS → 订阅 whole → 收推送更新 Map; - 配置切换:监听激活配置变化(host 变化)→ 断开旧 WS → 退订 → 重建连接; - 断开:指数退避静默重连 + 状态提示(连接中/已连接/重连中/断开)。 ## 涉及设计约束 | 约束 | 内容 | |---|---| | 技术约束-001 | 统一数据源抽象:行情实时数据仍走 QMT Bridge 适配器口径(现价字段 lastPrice 语义一致) | | 技术约束-003 | 直连 QMT Bridge(前端直连其原生 WS,不经过 MCP) | | 技术约束-008 | 复用激活 QMT 连接配置的 host(多配置热切换联动 WS) | | 技术约束-010(新增) | 前端直连 QMT Bridge WebSocket 订阅行情;服务端不中转 WS | | 产品约束-007(新增) | 3 个监控表格展示盘中现价列:红涨绿跌着色 + 变化高亮;仅现价一项 | ## 实现步骤 1. 服务端 API:新增 `qmt-connections/active-host`(返回 { host, baseUrl, wsUrl, name }); 2. MarketDataProvider.jsx:WS 客户端(连接/订阅/价格 Map/快照/重连/配置切换)+ Context; 3. PriceCell.jsx:现价单元格(格式化 + 涨跌色 + 高亮动画); 4. 3 表格接入:AllPositionsTab / StrategyTab 加「现价」列; 5. 构建安装 + 验收。