update pay ui

This commit is contained in:
2025-12-11 11:31:14 +08:00
parent dae1a539ac
commit 86e31fd2bf

View File

@@ -116,56 +116,74 @@ const extractSZSEPrices = (stockData: SZSEStockData) => {
};
/**
* 处理深交所股票行情消息(新 API 格式type='stock'
* 处理深交所批量行情消息(新 API 格式,与 SSE 一致
* 格式:{ type: 'stock', data: { '000001': {...}, '000002': {...} }, timestamp: '...' }
*/
const handleSZSEStockMessage = (
data: SZSEStockData,
timestamp: string,
const handleSZSEBatchMessage = (
msg: SZSERealtimeMessage,
subscribedCodes: Set<string>,
prevQuotes: QuotesMap
): QuotesMap | null => {
const rawCode = data.security_id;
const fullCode = rawCode.includes('.') ? rawCode : `${rawCode}.SZ`;
const { data, timestamp } = msg;
if (!subscribedCodes.has(rawCode) && !subscribedCodes.has(fullCode)) {
// 新 API 格式data 是 { code: quote, ... } 的字典
if (!data || typeof data !== 'object') {
return null;
}
const { bidPrices, bidVolumes, askPrices, askVolumes } = extractSZSEOrderBook(data);
const { prevClose, volume, amount, upperLimit, lowerLimit, tradingPhase } = extractSZSEPrices(data);
const updated: QuotesMap = { ...prevQuotes };
updated[fullCode] = {
code: fullCode,
name: prevQuotes[fullCode]?.name || '',
price: data.last_px,
prevClose,
open: data.open_px,
high: data.high_px,
low: data.low_px,
volume,
amount,
numTrades: data.num_trades,
upperLimit,
lowerLimit,
change: data.last_px - prevClose,
changePct: calcChangePct(data.last_px, prevClose),
bidPrices,
bidVolumes,
askPrices,
askVolumes,
tradingPhase,
updateTime: data.update_time || timestamp,
exchange: 'SZSE',
} as QuoteData;
let hasUpdate = false;
return updated;
// 遍历所有股票数据
Object.entries(data).forEach(([code, quote]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stockData = quote as any;
if (!stockData || typeof stockData !== 'object') return;
const rawCode = stockData.security_id || code;
const fullCode = rawCode.includes('.') ? rawCode : `${rawCode}.SZ`;
// 只处理已订阅的代码
if (!subscribedCodes.has(code) && !subscribedCodes.has(rawCode) && !subscribedCodes.has(fullCode)) {
return;
}
hasUpdate = true;
const { bidPrices, bidVolumes, askPrices, askVolumes } = extractSZSEOrderBook(stockData);
const { prevClose, volume, amount, upperLimit, lowerLimit, tradingPhase } = extractSZSEPrices(stockData);
updated[fullCode] = {
code: fullCode,
name: prevQuotes[fullCode]?.name || '',
price: stockData.last_px,
prevClose,
open: stockData.open_px,
high: stockData.high_px,
low: stockData.low_px,
volume,
amount,
numTrades: stockData.num_trades,
upperLimit,
lowerLimit,
change: stockData.last_px - prevClose,
changePct: calcChangePct(stockData.last_px, prevClose),
bidPrices,
bidVolumes,
askPrices,
askVolumes,
tradingPhase,
updateTime: stockData.update_time || timestamp,
exchange: 'SZSE',
} as QuoteData;
});
return hasUpdate ? updated : null;
};
/**
* 处理深交所实时消息 (兼容新旧 API)
* 新 API: type='stock'/'bond'/'fund', data 直接是行情对象
* 旧 API: type='realtime', category='stock'/'bond'/etc
* 新 API (批量模式): type='stock'/'bond'/'fund', data = { code: quote, ... }
* 旧 API (单条模式): type='realtime', category='stock', data = { security_id, ... }
*/
const handleSZSERealtimeMessage = (
msg: SZSERealtimeMessage,
@@ -173,7 +191,22 @@ const handleSZSERealtimeMessage = (
prevQuotes: QuotesMap
): QuotesMap | null => {
const { type, category, data, timestamp } = msg;
const rawCode = data.security_id;
// 新 API 批量格式检测data 是字典 { code: quote, ... },没有 security_id 在顶层
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const anyData = data as any;
const isBatchFormat = anyData && typeof anyData === 'object' && !anyData.security_id;
if (isBatchFormat && (type === 'stock' || type === 'bond' || type === 'fund')) {
return handleSZSEBatchMessage(msg, subscribedCodes, prevQuotes);
}
// 旧 API 单条格式data 直接是行情对象 { security_id, last_px, ... }
const rawCode = anyData?.security_id;
if (!rawCode) {
return null;
}
const fullCode = rawCode.includes('.') ? rawCode : `${rawCode}.SZ`;
if (!subscribedCodes.has(rawCode) && !subscribedCodes.has(fullCode)) {