add AI pick card

This commit is contained in:
clz
2026-07-27 17:22:29 +08:00
parent 30d9154086
commit 10dc2787df
14 changed files with 1453 additions and 5 deletions
@@ -0,0 +1,178 @@
import { AbsRowData, RowData, TableData } from '@b2b/hq_table';
import { TableRequestClient } from '@b2c/lib_baseui';
import { RequestHelper, StuffTableStruct } from '@kernel/lib_communication';
import {
CardData,
PickContractItem,
PickTabData,
} from '../../ai-pick/AiPickModels';
import { getUniqueContracts } from '../../ai-pick/AiPickUtils';
import { TableConstants } from '../../market-ranking/TableConstants';
const FRAME_ID = 2201;
const PAGE_ID = 4106;
const FIELD_IDS: number[] = [
TableConstants.DATA_ID_CODE_4,
TableConstants.DATA_ID_PRICE,
TableConstants.DATA_ID_MARKET,
TableConstants.DATA_ID_ZF_YTD,
];
interface AiPickQuote {
price?: number;
priceChg?: number;
}
export type AiPickCardDataListener = (cardData: CardData) => void;
class AiPickTableRequestClient extends TableRequestClient {
private requestParams: string;
private sourceCardData: CardData;
private listener: AiPickCardDataListener;
constructor(
requestParams: string,
sourceCardData: CardData,
listener: AiPickCardDataListener,
) {
super(FRAME_ID, PAGE_ID, [], null, undefined);
this.requestParams = requestParams;
this.sourceCardData = sourceCardData;
this.listener = listener;
this.setSubscribeIds(FIELD_IDS);
}
protected doRequest(): void {
RequestHelper.getHqManager()
.addRequestStructToBuff(this.frameId, this.pageId, this.getInstanceId(), this.requestParams);
RequestHelper.build().base(this.frameId, this.pageId, this, this.requestParams).request();
}
protected afterParserModel(tableData: TableData, _structData: StuffTableStruct): void {
const quoteMap: Map<string, AiPickQuote> = this.toQuoteMap(tableData);
const nextCardData: CardData = this.mergeQuoteData(quoteMap);
this.sourceCardData = nextCardData;
this.listener(nextCardData);
}
private toQuoteMap(tableData: TableData): Map<string, AiPickQuote> {
const quoteMap: Map<string, AiPickQuote> = new Map<string, AiPickQuote>();
if (!tableData.tableRows) {
return quoteMap;
}
tableData.tableRows.forEach((row: AbsRowData): void => {
if (!(row instanceof RowData)) {
return;
}
const codeValue = row.originalData.get(TableConstants.DATA_ID_CODE_4);
const marketValue = row.originalData.get(TableConstants.DATA_ID_MARKET);
if (codeValue === undefined || marketValue === undefined) {
return;
}
const quote: AiPickQuote = {
price: this.getNumber(row, TableConstants.DATA_ID_PRICE),
priceChg: this.getNumber(row, TableConstants.DATA_ID_ZF_YTD),
};
quoteMap.set(`${codeValue}_${marketValue}`, quote);
});
return quoteMap;
}
private mergeQuoteData(quoteMap: Map<string, AiPickQuote>): CardData {
const tabs: PickTabData[] =
this.sourceCardData.tabs.map((tab: PickTabData): PickTabData => {
const items: PickContractItem[] =
tab.items.map((item: PickContractItem): PickContractItem => {
const quote: AiPickQuote | undefined =
quoteMap.get(`${item.contract}_${item.market}`);
const nextItem: PickContractItem = {
contract: item.contract,
market: item.market,
name: item.name,
price: quote?.price ?? item.price,
priceChg: quote?.priceChg ?? item.priceChg,
isMain: item.isMain,
extraFields: item.extraFields,
};
return nextItem;
});
const nextTab: PickTabData = {
strategy: tab.strategy,
items: items,
keysList: tab.keysList,
fieldList: tab.fieldList,
};
return nextTab;
});
const nextCardData: CardData = { tabs: tabs };
return nextCardData;
}
private getNumber(row: RowData, fieldId: number): number | undefined {
const value = row.originalData.get(fieldId);
if (typeof value === 'number') {
return value;
}
if (typeof value === 'string' && value !== '' && value !== '--') {
const result: number = parseFloat(value);
return Number.isNaN(result) ? undefined : result;
}
return undefined;
}
}
export class AiPickHqRequestClient {
private static readonly instance: AiPickHqRequestClient =
new AiPickHqRequestClient();
private constructor() {
}
static getInstance(): AiPickHqRequestClient {
return AiPickHqRequestClient.instance;
}
subscribeHq(cardData: CardData, listener: AiPickCardDataListener): () => void {
const contracts: PickContractItem[] = getUniqueContracts(cardData);
if (contracts.length === 0) {
return (): void => {
};
}
const requestParams: string = this.buildRequestParams(contracts);
const requestClient: AiPickTableRequestClient =
new AiPickTableRequestClient(requestParams, cardData, listener);
requestClient.request(0, contracts.length);
return (): void => {
requestClient.release(true);
};
}
private buildRequestParams(contracts: PickContractItem[]): string {
return `\r\nsortid=-1\r\n` +
`sortorder=0\r\n` +
`push=1\r\n` +
`dataitem=${FIELD_IDS.map((fieldId: number): string => `${fieldId},`).join('')}\r\n` +
`codelist=${this.formatCodeList(contracts)}\r\n` +
`update=1\r\n` +
`scenario=qht_qihuo_sort\r\n` +
`precision=1\r\n` +
`pushtime=2.5\r\n`;
}
private formatCodeList(contracts: PickContractItem[]): string {
const markets: string[] = [];
const codeGroups: string[][] = [];
contracts.forEach((contract: PickContractItem): void => {
const marketIndex: number = markets.indexOf(contract.market);
if (marketIndex >= 0) {
codeGroups[marketIndex].push(contract.contract);
} else {
markets.push(contract.market);
codeGroups.push([contract.contract]);
}
});
return markets.map((market: string, index: number): string =>
`${market}(${codeGroups[index].map((code: string): string => `${code},`).join('')});`
).join('');
}
}
@@ -47,6 +47,7 @@ export interface FirstPageCardsConfig {
aiRiseFall: AllCardsCard
commodityOptions: CommodityOptionsCardConfig
marketRanking: AllCardsCard
aiPick: AllCardsCard
}
export class FirstPageCardsConfigLoader {