From 77f1643a5868ca480cdf60a07b5cecdc98a2d6c9 Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Sun, 14 Dec 2025 16:43:45 +0800 Subject: [PATCH] update pay ui --- src/services/ztStaticService.js | 114 +++++++----- .../components/DataVisualizationComponents.js | 24 ++- .../components/SearchComponents.js | 167 ++++-------------- src/views/LimitAnalyse/index.js | 81 +-------- 4 files changed, 135 insertions(+), 251 deletions(-) diff --git a/src/services/ztStaticService.js b/src/services/ztStaticService.js index 62bf0472..294a233e 100644 --- a/src/services/ztStaticService.js +++ b/src/services/ztStaticService.js @@ -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 { diff --git a/src/views/LimitAnalyse/components/DataVisualizationComponents.js b/src/views/LimitAnalyse/components/DataVisualizationComponents.js index d2c8ca7a..86a6bc04 100644 --- a/src/views/LimitAnalyse/components/DataVisualizationComponents.js +++ b/src/views/LimitAnalyse/components/DataVisualizationComponents.js @@ -512,7 +512,7 @@ const SectorRelationMap = ({ data }) => { }; // 数据分析主组件 -export const DataAnalysis = ({ dailyData, wordCloudData }) => { +export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr }) => { const cardBg = useColorModeValue('white', 'gray.800'); const pieData = useMemo(() => { @@ -538,10 +538,30 @@ export const DataAnalysis = ({ dailyData, wordCloudData }) => { return Object.values(dailyData.sector_data).flatMap(sector => sector.stocks || []); }, [dailyData]); + // 格式化日期显示 + const formatDate = (str) => { + if (!str || str.length !== 8) return ''; + return `${str.slice(0, 4)}年${parseInt(str.slice(4, 6))}月${parseInt(str.slice(6, 8))}日`; + }; + return ( - 数据分析 + + 数据分析 + {totalStocks !== undefined && ( + + {dateStr && ( + + {formatDate(dateStr)} + + )} + + 今日涨停: {totalStocks} 只 + + + )} + diff --git a/src/views/LimitAnalyse/components/SearchComponents.js b/src/views/LimitAnalyse/components/SearchComponents.js index d840aa36..405c1dca 100644 --- a/src/views/LimitAnalyse/components/SearchComponents.js +++ b/src/views/LimitAnalyse/components/SearchComponents.js @@ -1,18 +1,13 @@ import React, { useState } from 'react'; import { - Box, Card, CardBody, - VStack, HStack, Text, Button, Input, InputGroup, InputLeftElement, - Select, - RadioGroup, - Radio, Modal, ModalOverlay, ModalContent, @@ -39,14 +34,11 @@ import { AlertIcon, } from '@chakra-ui/react'; import { formatTooltipText, getFormattedTextProps } from '../../../utils/textUtils'; -import { SearchIcon, CalendarIcon, DownloadIcon } from '@chakra-ui/icons'; +import { SearchIcon, DownloadIcon } from '@chakra-ui/icons'; -// 高级搜索组件 +// 简化版搜索组件 - 仅支持股票代码/名称精确匹配 export const AdvancedSearch = ({ onSearch, loading }) => { const [searchKeyword, setSearchKeyword] = useState(''); - const [searchMode, setSearchMode] = useState('hybrid'); - const [searchType, setSearchType] = useState('all'); - const [dateRange, setDateRange] = useState({ start: '', end: '' }); const cardBg = useColorModeValue('white', 'gray.800'); const toast = useToast(); @@ -54,7 +46,7 @@ export const AdvancedSearch = ({ onSearch, loading }) => { const handleSearch = () => { if (!searchKeyword.trim()) { toast({ - title: '请输入搜索关键词', + title: '请输入股票代码或名称', status: 'warning', duration: 2000, }); @@ -62,139 +54,54 @@ export const AdvancedSearch = ({ onSearch, loading }) => { } const searchParams = { - query: searchKeyword, - mode: searchMode, - type: searchType, + query: searchKeyword.trim(), + mode: 'exact', // 固定为精确匹配 page: 1, page_size: 50, }; - // 添加日期范围 - if (dateRange.start || dateRange.end) { - searchParams.date_range = {}; - if (dateRange.start) searchParams.date_range.start = dateRange.start.replace(/-/g, ''); - if (dateRange.end) searchParams.date_range.end = dateRange.end.replace(/-/g, ''); - } - onSearch(searchParams); }; const clearSearch = () => { setSearchKeyword(''); - setDateRange({ start: '', end: '' }); - setSearchType('all'); - setSearchMode('hybrid'); }; return ( - - - - - - - setSearchKeyword(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && handleSearch()} - fontSize="md" - /> - - - - - - - - 搜索类型 - - - 全部 - 股票 - 涨停原因 - - - - - - 搜索模式 - - - - - 日期范围(可选) - - - - - - setDateRange({...dateRange, start: e.target.value})} - /> - - - - - - - setDateRange({...dateRange, end: e.target.value})} - /> - - - - - - - - - 提示:搜索结果将在新窗口中显示,不会影响当前页面的数据展示。 - 您可以搜索不同日期范围内的涨停股票进行对比分析。 - - - + + + + + + setSearchKeyword(e.target.value)} + onKeyPress={(e) => e.key === 'Enter' && handleSearch()} + fontSize="md" + /> + + + + ); diff --git a/src/views/LimitAnalyse/index.js b/src/views/LimitAnalyse/index.js index 85e57f70..ac0a1e7b 100755 --- a/src/views/LimitAnalyse/index.js +++ b/src/views/LimitAnalyse/index.js @@ -16,13 +16,8 @@ import { Tooltip, Card, CardBody, - Stat, - StatLabel, - StatNumber, - StatHelpText, - StatArrow, - Alert, - AlertIcon, + Alert, + AlertIcon, } from '@chakra-ui/react'; import { RepeatIcon, @@ -247,61 +242,6 @@ export default function LimitAnalyse() { return result; }; - // 渲染统计卡片 - const StatsCards = () => ( - - - - - 今日涨停 - - {dailyData?.total_stocks || 0} - - - - 较昨日 +23% - - - - - - - - - 最热板块 - - {dailyData?.summary?.top_sector || '-'} - - {dailyData?.summary?.top_sector_count || 0} 只 - - - - - - - - 公告涨停 - - {dailyData?.summary?.announcement_stocks || 0} - - 重大利好 - - - - - - - - 早盘强势 - - {dailyData?.summary?.zt_time_distribution?.morning || 0} - - 开盘涨停 - - - - - ); const formatDisplayDate = (date) => { if (!date) return ''; @@ -431,21 +371,10 @@ export default function LimitAnalyse() { {/* 主内容区 */} - {/* 统计卡片 */} - {loading ? ( - - {[...Array(4)].map((_, i) => ( - - ))} - - ) : ( - - )} - - {/* 高级搜索 */} + {/* 搜索框 */} - {/* 数据分析 - 移到板块详情上方 */} + {/* 数据分析(含涨停统计) */} {loading ? ( ) : ( @@ -453,6 +382,8 @@ export default function LimitAnalyse() { )}