update pay ui
This commit is contained in:
@@ -11,6 +11,7 @@ const DATA_BASE_URL = '/data/zt';
|
||||
const cache = {
|
||||
dates: null,
|
||||
daily: new Map(),
|
||||
stocksJsonl: null, // 缓存 stocks.jsonl 数据
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -203,80 +204,104 @@ const parseContinuousDays = (str) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 关键词搜索股票
|
||||
* 从缓存的数据中搜索
|
||||
* 加载 stocks.jsonl 文件
|
||||
* JSONL 格式:每行一个 JSON 对象
|
||||
*/
|
||||
const loadStocksJsonl = async () => {
|
||||
try {
|
||||
// 使用缓存
|
||||
if (cache.stocksJsonl) {
|
||||
return cache.stocksJsonl;
|
||||
}
|
||||
|
||||
const response = await fetch(`${DATA_BASE_URL}/stocks.jsonl`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const text = await response.text();
|
||||
const lines = text.trim().split('\n');
|
||||
const stocks = lines
|
||||
.filter(line => line.trim())
|
||||
.map(line => {
|
||||
try {
|
||||
return JSON.parse(line);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
// 缓存结果
|
||||
cache.stocksJsonl = stocks;
|
||||
|
||||
return stocks;
|
||||
} catch (error) {
|
||||
console.error('[ztStaticService] loadStocksJsonl error:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 简化版搜索股票
|
||||
* 仅支持股票代码或名称的精确/部分匹配
|
||||
* 使用 stocks.jsonl 作为数据源
|
||||
*/
|
||||
export const searchStocks = async (searchParams) => {
|
||||
try {
|
||||
const { query, date, date_range, page = 1, page_size = 20 } = searchParams;
|
||||
const { query, page = 1, page_size = 50 } = searchParams;
|
||||
|
||||
if (!query || query.trim() === '') {
|
||||
return { success: false, error: '搜索关键词不能为空' };
|
||||
return { success: false, error: '请输入股票代码或名称' };
|
||||
}
|
||||
|
||||
const queryLower = query.toLowerCase().trim();
|
||||
let allStocks = [];
|
||||
|
||||
// 确定要搜索的日期范围
|
||||
let datesToSearch = [];
|
||||
// 加载 stocks.jsonl 数据
|
||||
const allStocks = await loadStocksJsonl();
|
||||
|
||||
if (date) {
|
||||
datesToSearch = [date];
|
||||
} else if (date_range?.start && date_range?.end) {
|
||||
// 从缓存的日期中筛选
|
||||
const datesResult = await fetchAvailableDates();
|
||||
if (datesResult.success) {
|
||||
datesToSearch = datesResult.events
|
||||
.filter(d => d.date >= date_range.start && d.date <= date_range.end)
|
||||
.map(d => d.date);
|
||||
}
|
||||
} else {
|
||||
// 默认搜索最近 30 天
|
||||
const datesResult = await fetchAvailableDates();
|
||||
if (datesResult.success) {
|
||||
datesToSearch = datesResult.events.slice(0, 30).map(d => d.date);
|
||||
}
|
||||
if (allStocks.length === 0) {
|
||||
return { success: false, error: '搜索数据暂未加载,请稍后重试' };
|
||||
}
|
||||
|
||||
// 从每个日期的数据中搜索
|
||||
for (const d of datesToSearch) {
|
||||
const result = await fetchDailyAnalysis(d);
|
||||
if (result.success && result.data.stocks) {
|
||||
const stocks = result.data.stocks.map(s => ({ ...s, date: d }));
|
||||
allStocks = allStocks.concat(stocks);
|
||||
}
|
||||
}
|
||||
|
||||
// 关键词匹配
|
||||
// 简单的股票代码/名称匹配
|
||||
const results = allStocks
|
||||
.map(stock => {
|
||||
let score = 0;
|
||||
const scode = (stock.scode || '').toLowerCase();
|
||||
const sname = (stock.sname || '').toLowerCase();
|
||||
|
||||
// 精确匹配股票代码
|
||||
if (queryLower === (stock.scode || '').toLowerCase()) {
|
||||
// 精确匹配股票代码(最高优先级)
|
||||
if (scode === queryLower) {
|
||||
score = 100;
|
||||
}
|
||||
// 精确匹配股票名称
|
||||
else if (queryLower === (stock.sname || '').toLowerCase()) {
|
||||
else if (sname === queryLower) {
|
||||
score = 90;
|
||||
}
|
||||
// 部分匹配股票名称
|
||||
else if ((stock.sname || '').toLowerCase().includes(queryLower)) {
|
||||
// 股票代码以搜索词开头
|
||||
else if (scode.startsWith(queryLower)) {
|
||||
score = 80;
|
||||
}
|
||||
// 匹配板块
|
||||
else if ((stock.core_sectors || []).some(s => s.toLowerCase().includes(queryLower))) {
|
||||
// 股票名称包含搜索词
|
||||
else if (sname.includes(queryLower)) {
|
||||
score = 70;
|
||||
}
|
||||
// 匹配涨停原因
|
||||
else if ((stock.brief || '').toLowerCase().includes(queryLower)) {
|
||||
// 股票代码包含搜索词
|
||||
else if (scode.includes(queryLower)) {
|
||||
score = 60;
|
||||
}
|
||||
|
||||
return { ...stock, _score: score };
|
||||
})
|
||||
.filter(s => s._score > 0)
|
||||
.sort((a, b) => b._score - a._score || b.date.localeCompare(a.date));
|
||||
.sort((a, b) => {
|
||||
// 先按匹配度排序,再按日期降序
|
||||
if (b._score !== a._score) {
|
||||
return b._score - a._score;
|
||||
}
|
||||
return (b.date || '').localeCompare(a.date || '');
|
||||
});
|
||||
|
||||
// 分页
|
||||
const total = results.length;
|
||||
@@ -291,7 +316,7 @@ export const searchStocks = async (searchParams) => {
|
||||
page,
|
||||
page_size,
|
||||
total_pages: Math.ceil(total / page_size),
|
||||
search_mode: 'keyword',
|
||||
search_mode: 'exact',
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -324,6 +349,7 @@ export const fetchStocksBatchDetail = async (codes, date) => {
|
||||
export const clearCache = () => {
|
||||
cache.dates = null;
|
||||
cache.daily.clear();
|
||||
cache.stocksJsonl = null;
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
Reference in New Issue
Block a user