feat: 迭代03-05 交易记录接入、行情实时、QMT连接配置、data store 标准化

- R-004 QMT连接配置:多配置管理 + 会话头部快捷切换(03-QMT连接配置)
- R-005 WS盘中价格实时更新:服务端中转+缓存+前端轮询(04-WS盘中价格实时更新)
- R-006 策略数据 JSON data store 标准化(store.json/market.json/schema.json)
- R-007 交易记录接入:当日订单+成交单表合并(委托主行+展开成交明细)、时间段查询(今日/本周/本月+手动起止)、费用计算(佣金费率万m_dCommission+最低5元、印花税卖出万5、过户费双向万0.1)
- 架构治理:api 按领域拆分、component 目录、QmtHealthMonitor
This commit is contained in:
2026-09-01 13:21:49 +08:00
parent 5a723d514e
commit bb3f8bd28d
57 changed files with 5244 additions and 397 deletions
+42
View File
@@ -0,0 +1,42 @@
/**
* 服务端 HTTP API 公共工具
*
* 为什么不用 RPCconnection.rpc.intercept('/api')):
* DSH 的 /api 通道只能有一个 interceptorapi-gateway 已占用),
* 再 intercept 会抛 "already has an interceptor" 导致插件 apply 失败。
* 因此改用 webServer 自开路由(与 dsh-better-sidebar 的 /sidebar/api 同模式)。
*/
export const API_PREFIX = '/odl/api/';
/** 响应 JSON */
export function writeJson(res, status, data) {
res.writeHead(status, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
}
/** 读取 JSON body */
export async function readJsonBody(req) {
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
const raw = Buffer.concat(chunks).toString('utf8');
if (!raw) return {};
try {
return JSON.parse(raw);
} catch {
return {};
}
}
/** 从激活配置解析 baseUrl(连接列表为空时回退数据源当前 baseUrl) */
export function resolveActiveBaseUrl(settings, dataSource) {
const state = getQmtConnections(settings);
const active = getActiveQmtConnection(state);
return String(active?.baseUrl ?? dataSource?.baseUrl ?? '').replace(/\/+$/, '');
}
// 延迟引入 settings 函数避免循环依赖
import {
getQmtConnections,
getActiveQmtConnection,
} from '../settings.js';