# 技术实现方案:08-策略持仓行展开关联交易记录(Holding → 交易汇总) > 依据:PLAN-009 | 需求:R-010(Q1-Q3 定稿)| 设计约束:技术约束-012、技术约束-011(测试隔离) ## 技术选型 - 复用 R-009 的 holding_id 关联(trade_orders.holding_id); - 服务端:strategy-positions 附加 holding_id + trades/by-holding 端点; - 前端:StrategyTab 持仓行展开(懒加载内嵌汇总表)。 ## 数据流 ``` 策略持仓 tab: load() → strategy-positions(每行含 holding_id) 用户点击持仓行 → 展开 → trades/by-holding?holdingId=13 → 委托汇总列表 懒加载:不展开不请求 ``` ## 实现细节 ### 1. PositionManager.getStrategyPositions 附加 holding_id ```js async getStrategyPositions(strategyId) { const [positions, dataset, holdings] = await Promise.all([ this.getAllPositions(), this.storage.getDataset(strategyId), this.storage.getCurrentHoldings(strategyId), // 含 holding_id ]); const shareMap = new Map(dataset.map(d => [d.code, d.shares])); const holdingMap = new Map(holdings.map(h => [h.code, h.holdingId])); return positions.map(p => { const shares = shareMap.get(p.code) ?? 0; return shares > 0 ? { ...p, shares, holdingId: holdingMap.get(p.code) ?? null } : null; }).filter(Boolean); } ``` ### 2. SqliteStore.getOrdersByHolding ```js getOrdersByHolding(holdingId) { this.init(); return this.db.prepare( 'SELECT * FROM trade_orders WHERE holding_id=? ORDER BY insert_ts DESC' ).all(holdingId).map(r => this._mapOrderRow(r)); } ``` ### 3. api/trades.js:trades/by-holding 端点 ```js case 'trades/by-holding': return await storage.getTradeOrdersByHolding(args.holdingId); ``` ### 4. StrategyTab 展开 UI - 持仓行加展开箭头(类似交易记录 tab); - 展开时调 trades/by-holding,内嵌小表格显示委托汇总: 时间 / 方向 / 状态 / 委托量 / 成交量 / 均价 / 金额 / 费用; - 只显示委托汇总(ORDER_STATUS 中文映射复用); - 懒加载:展开时才请求,折叠清空。 ## 涉及设计约束 | 约束 | 内容 | |---|---| | 技术约束-012 | 数据存储遵循数据存储设计.md(复用 trade_orders.holding_id) | | 技术约束-011 | 测试用独立数据目录(ODL_TEST_DATA_DIR) |