From 0e58af9f9460fdfd21f6cb3975b0ffd0392c554c Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Mon, 29 Dec 2025 16:17:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=BB=E5=8A=9B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 28 +++- .../components/MainForceInfo.tsx | 131 ++++++++++++------ .../StockQuoteCard/components/formatters.ts | 8 -- .../StockQuoteCard/hooks/useStockQuoteData.ts | 9 +- .../components/StockQuoteCard/index.tsx | 7 +- .../components/StockQuoteCard/types.ts | 9 +- 6 files changed, 123 insertions(+), 69 deletions(-) diff --git a/app.py b/app.py index 58ea9908..8f0e1895 100755 --- a/app.py +++ b/app.py @@ -9123,11 +9123,10 @@ def get_stock_quote_detail(stock_code): 'week52_high': None, 'week52_low': None, - # 主力动态(预留字段) - 'main_net_inflow': None, - 'institution_holding': None, - 'buy_ratio': None, - 'sell_ratio': None, + # 主力动态(数据来源:stock_main_capital_flow 表) + 'net_inflow': None, # 主力净流入量(万元) + 'main_inflow_ratio': None, # 主力净流入量占比(%) + 'net_active_buy_ratio': None, # 净主动买入额占比(%) 'update_time': None } @@ -9211,6 +9210,25 @@ def get_stock_quote_detail(stock_code): result_data['week52_high'] = float(w52.get('week52_high') or 0) result_data['week52_low'] = float(w52.get('week52_low') or 0) + # 3. 获取主力资金流向数据(取最新交易日) + capital_flow_query = text(""" + SELECT + net_inflow, + net_active_buy_ratio, + main_inflow_ratio + FROM stock_main_capital_flow + WHERE code = :stock_code + ORDER BY trade_date DESC + LIMIT 1 + """) + + capital_flow_result = conn.execute(capital_flow_query, {'stock_code': base_code}).fetchone() + if capital_flow_result: + cf = row_to_dict(capital_flow_result) + result_data['net_inflow'] = float(cf.get('net_inflow') or 0) if cf.get('net_inflow') is not None else None + result_data['main_inflow_ratio'] = float(cf.get('main_inflow_ratio') or 0) if cf.get('main_inflow_ratio') is not None else None + result_data['net_active_buy_ratio'] = float(cf.get('net_active_buy_ratio') or 0) if cf.get('net_active_buy_ratio') is not None else None + return jsonify({ 'success': True, 'data': result_data diff --git a/src/views/Company/components/StockQuoteCard/components/MainForceInfo.tsx b/src/views/Company/components/StockQuoteCard/components/MainForceInfo.tsx index 1964ce93..77fbc091 100644 --- a/src/views/Company/components/StockQuoteCard/components/MainForceInfo.tsx +++ b/src/views/Company/components/StockQuoteCard/components/MainForceInfo.tsx @@ -1,28 +1,25 @@ /** * MainForceInfo - 主力动态原子组件 * - * 显示主力资金和机构相关指标: - * - 主力净流入(带正负颜色) - * - 机构持仓比例 - * - 买卖比例进度条 + * 显示主力资金流向指标(数据来源:stock_main_capital_flow 表): + * - 主力净流入(万元,带正负颜色) + * - 主力流入占比(%) + * - 净主动买入占比(%,进度条展示) * * 注意:标题由外层 GlassSection 提供 */ import React, { memo } from 'react'; import { Box, VStack, HStack, Text, Progress } from '@chakra-ui/react'; -import { formatNetInflow } from './formatters'; import { DEEP_SPACE_THEME as T } from './theme'; export interface MainForceInfoProps { - /** 主力净流入(亿) */ - mainNetInflow: number; - /** 机构持仓比例(%) */ - institutionHolding: number; - /** 买入比例(%) */ - buyRatio: number; - /** 卖出比例(%) */ - sellRatio: number; + /** 主力净流入(万元) */ + netInflow: number | null; + /** 主力净流入量占比(%) */ + mainInflowRatio: number | null; + /** 净主动买入额占比(%) */ + netActiveBuyRatio: number | null; } /** @@ -54,6 +51,32 @@ const MetricRow: React.FC = ({ ); +/** + * 格式化主力净流入显示 + * 根据数值大小自动选择万/亿单位 + */ +const formatNetInflowValue = (value: number | null): string => { + if (value === null || value === undefined) return '--'; + const absValue = Math.abs(value); + const sign = value >= 0 ? '+' : ''; + + if (absValue >= 10000) { + // 超过1亿,显示为亿 + return `${sign}${(value / 10000).toFixed(2)}亿`; + } + // 否则显示万 + return `${sign}${value.toFixed(2)}万`; +}; + +/** + * 格式化百分比显示 + */ +const formatPercent = (value: number | null): string => { + if (value === null || value === undefined) return '--'; + const sign = value >= 0 ? '+' : ''; + return `${sign}${value.toFixed(2)}%`; +}; + /** * 主力动态展示组件 * @@ -61,51 +84,75 @@ const MetricRow: React.FC = ({ * 应由 GlassSection 包装以提供标题 */ export const MainForceInfo: React.FC = memo(({ - mainNetInflow, - institutionHolding, - buyRatio, - sellRatio, + netInflow, + mainInflowRatio, + netActiveBuyRatio, }) => { - const inflowColor = mainNetInflow >= 0 ? T.upColor : T.downColor; + const inflowColor = (netInflow ?? 0) >= 0 ? T.upColor : T.downColor; + const ratioColor = (mainInflowRatio ?? 0) >= 0 ? T.upColor : T.downColor; + + // 净主动买入占比用于进度条,范围可能是 -100 ~ 100,需要转换 + // 负值表示主动卖出多,正值表示主动买入多 + const buyRatioValue = netActiveBuyRatio ?? 0; + // 转换为 0-100 的进度条值(50为中点) + const progressValue = Math.min(100, Math.max(0, 50 + buyRatioValue / 2)); return ( - {/* 买卖比例进度条 */} + {/* 净主动买入占比进度条 */} - div': { - bg: T.upColor, - boxShadow: T.upGlow, - }, - }} - bg={T.downColor} - borderRadius="full" - h="8px" - /> - - - 买入 {buyRatio}% - - - 卖出 {sellRatio}% + + 净主动买入 + = 0 ? T.upColor : T.downColor} + fontWeight="600" + > + {formatPercent(netActiveBuyRatio)} + + div': { + bg: buyRatioValue >= 0 ? T.upColor : T.downColor, + boxShadow: buyRatioValue >= 0 ? T.upGlow : T.downGlow, + transition: 'all 0.3s ease', + }, + }} + bg="rgba(255,255,255,0.1)" + borderRadius="full" + h="8px" + /> + {/* 中点标记 */} + + + + 卖出 + 买入 + ); diff --git a/src/views/Company/components/StockQuoteCard/components/formatters.ts b/src/views/Company/components/StockQuoteCard/components/formatters.ts index 1cdf05e9..f3740a11 100644 --- a/src/views/Company/components/StockQuoteCard/components/formatters.ts +++ b/src/views/Company/components/StockQuoteCard/components/formatters.ts @@ -19,11 +19,3 @@ export const formatChangePercent = (percent: number): string => { const sign = percent >= 0 ? '+' : ''; return `${sign}${percent.toFixed(2)}%`; }; - -/** - * 格式化主力净流入显示 - */ -export const formatNetInflow = (value: number): string => { - const sign = value >= 0 ? '+' : ''; - return `${sign}${value.toFixed(2)}亿`; -}; diff --git a/src/views/Company/components/StockQuoteCard/hooks/useStockQuoteData.ts b/src/views/Company/components/StockQuoteCard/hooks/useStockQuoteData.ts index 5f6f943e..a282672d 100644 --- a/src/views/Company/components/StockQuoteCard/hooks/useStockQuoteData.ts +++ b/src/views/Company/components/StockQuoteCard/hooks/useStockQuoteData.ts @@ -42,11 +42,10 @@ const transformQuoteData = (apiData: any, stockCode: string): StockQuoteCardData week52Low: apiData.week52_low || apiData.week52Low || 0, week52High: apiData.week52_high || apiData.week52High || 0, - // 主力动态 - mainNetInflow: apiData.main_net_inflow || apiData.mainNetInflow || 0, - institutionHolding: apiData.institution_holding || apiData.institutionHolding || 0, - buyRatio: apiData.buy_ratio || apiData.buyRatio || 50, - sellRatio: apiData.sell_ratio || apiData.sellRatio || 50, + // 主力动态(数据来源:stock_main_capital_flow 表) + netInflow: apiData.net_inflow ?? apiData.netInflow ?? null, // 主力净流入量(万元) + mainInflowRatio: apiData.main_inflow_ratio ?? apiData.mainInflowRatio ?? null, // 主力净流入量占比(%) + netActiveBuyRatio: apiData.net_active_buy_ratio ?? apiData.netActiveBuyRatio ?? null, // 净主动买入额占比(%) // 更新时间 updateTime: apiData.update_time || apiData.updateTime || new Date().toLocaleString(), diff --git a/src/views/Company/components/StockQuoteCard/index.tsx b/src/views/Company/components/StockQuoteCard/index.tsx index bc5dd8fe..f07b2514 100644 --- a/src/views/Company/components/StockQuoteCard/index.tsx +++ b/src/views/Company/components/StockQuoteCard/index.tsx @@ -179,10 +179,9 @@ const StockQuoteCard: React.FC = ({ {/* 第三列:主力动态 */} diff --git a/src/views/Company/components/StockQuoteCard/types.ts b/src/views/Company/components/StockQuoteCard/types.ts index 12ceab04..e315cf50 100644 --- a/src/views/Company/components/StockQuoteCard/types.ts +++ b/src/views/Company/components/StockQuoteCard/types.ts @@ -33,11 +33,10 @@ export interface StockQuoteCardData { week52Low: number; // 52周最低 week52High: number; // 52周最高 - // 主力动态 - mainNetInflow: number; // 主力净流入(亿) - institutionHolding: number; // 机构持仓比例(百分比) - buyRatio: number; // 买入比例(百分比) - sellRatio: number; // 卖出比例(百分比) + // 主力动态(数据来源:stock_main_capital_flow 表) + netInflow: number | null; // 主力净流入量(万元) + mainInflowRatio: number | null; // 主力净流入量占比(%) + netActiveBuyRatio: number | null; // 净主动买入额占比(%) // 更新时间 updateTime: string; // 格式:YYYY-MM-DD HH:mm:ss