From 0f72cc633dc89a03c3bfd04e4ecc1ecb774d853d Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Fri, 26 Dec 2025 13:24:15 +0800 Subject: [PATCH] =?UTF-8?q?chore(Company):=20=E5=88=A0=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E5=8D=A0=E4=BD=8D=E7=AC=A6=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=92=8C=E5=BA=9F=E5=BC=83=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除的文件: - ForecastReport.js: 旧版占位符,功能已在 components/ForecastReport/index.tsx 实现 - MarketDataView.js: 旧版占位符,功能已在 components/MarketDataView/index.tsx 实现 - hooks/useCompanyStock.js: 功能已被 useCompanyData.ts 替代 - hooks/useCompanyWatchlist.js: 功能已被 useCompanyData.ts 替代 同步更新 STRUCTURE.md 文档 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/views/Company/ForecastReport.js | 31 ---- src/views/Company/MarketDataView.js | 31 ---- src/views/Company/STRUCTURE.md | 18 -- src/views/Company/hooks/useCompanyStock.js | 91 ---------- .../Company/hooks/useCompanyWatchlist.js | 166 ------------------ 5 files changed, 337 deletions(-) delete mode 100644 src/views/Company/ForecastReport.js delete mode 100644 src/views/Company/MarketDataView.js delete mode 100644 src/views/Company/hooks/useCompanyStock.js delete mode 100644 src/views/Company/hooks/useCompanyWatchlist.js diff --git a/src/views/Company/ForecastReport.js b/src/views/Company/ForecastReport.js deleted file mode 100644 index a4da1376..00000000 --- a/src/views/Company/ForecastReport.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { Box, Text, VStack, Icon } from '@chakra-ui/react'; -import { LineChart } from 'lucide-react'; - -/** - * 预测报告组件 - 占位符 - * TODO: 实现完整功能 - */ -const ForecastReport = ({ stockCode }) => { - return ( - - - - - 预测报告功能开发中 - - - 股票代码: {stockCode || '未选择'} - - - - ); -}; - -export default ForecastReport; diff --git a/src/views/Company/MarketDataView.js b/src/views/Company/MarketDataView.js deleted file mode 100644 index 174c5c31..00000000 --- a/src/views/Company/MarketDataView.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { Box, Text, VStack, Icon } from '@chakra-ui/react'; -import { BarChart2 } from 'lucide-react'; - -/** - * 市场数据视图组件 - 占位符 - * TODO: 实现完整功能 - */ -const MarketDataView = ({ stockCode }) => { - return ( - - - - - 市场数据功能开发中 - - - 股票代码: {stockCode || '未选择'} - - - - ); -}; - -export default MarketDataView; diff --git a/src/views/Company/STRUCTURE.md b/src/views/Company/STRUCTURE.md index 75fb13ae..c32e0ab0 100644 --- a/src/views/Company/STRUCTURE.md +++ b/src/views/Company/STRUCTURE.md @@ -10,8 +10,6 @@ src/views/Company/ ├── config.ts # 页面配置(主题、Tab 配置) ├── types.ts # 页面级类型定义 ├── STRUCTURE.md # 本文档 -├── ForecastReport.js # 盈利预测页面(旧版入口) -├── MarketDataView.js # 行情数据页面(旧版入口) │ ├── theme/ # FUI 主题系统 │ ├── index.ts # 主题导出 @@ -26,8 +24,6 @@ src/views/Company/ │ └── colorUtils.ts # 颜色工具函数 │ ├── hooks/ # 页面级 Hooks -│ ├── useCompanyStock.js # 股票代码管理(URL 同步) -│ ├── useCompanyWatchlist.js # 自选股管理(Redux 集成) │ ├── useCompanyEvents.js # PostHog 事件追踪 │ ├── useCompanyData.ts # 公司数据聚合 Hook │ └── useStockSearch.ts # 股票搜索 Hook @@ -382,20 +378,6 @@ Company 模块共使用 **27 个** API 接口(去重后)。 ### Hooks 目录 -#### `useCompanyStock.js` - 股票代码管理 -- **功能**: - - 管理当前股票代码状态 - - 双向同步 URL 参数(支持浏览器前进/后退) - - 处理搜索输入和提交 -- **依赖**:`react-router-dom` (useSearchParams) - -#### `useCompanyWatchlist.js` - 自选股管理 -- **功能**: - - 检查当前股票是否在自选股中 - - 提供添加/移除自选股功能 - - 与 Redux stockSlice 同步 -- **依赖**:Redux (`stockSlice`)、`AuthContext`、Chakra UI (useToast) - #### `useCompanyEvents.js` - 事件追踪 - **功能**: - 页面浏览追踪 diff --git a/src/views/Company/hooks/useCompanyStock.js b/src/views/Company/hooks/useCompanyStock.js deleted file mode 100644 index d55d220a..00000000 --- a/src/views/Company/hooks/useCompanyStock.js +++ /dev/null @@ -1,91 +0,0 @@ -// src/views/Company/hooks/useCompanyStock.js -// 股票代码管理 Hook - 处理 URL 参数同步和搜索逻辑 - -import { useState, useEffect, useCallback } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import { DEFAULT_STOCK_CODE, URL_PARAM_NAME } from '../constants'; - -/** - * 股票代码管理 Hook - * - * 功能: - * - 管理当前股票代码状态 - * - 双向同步 URL 参数 - * - 处理搜索输入和提交 - * - * @param {Object} options - 配置选项 - * @param {string} [options.defaultCode] - 默认股票代码 - * @param {string} [options.paramName] - URL 参数名 - * @param {Function} [options.onStockChange] - 股票代码变化回调 (newCode, prevCode) => void - * @returns {Object} 股票代码状态和操作方法 - */ -export const useCompanyStock = (options = {}) => { - const { - defaultCode = DEFAULT_STOCK_CODE, - paramName = URL_PARAM_NAME, - onStockChange, - } = options; - - const [searchParams, setSearchParams] = useSearchParams(); - - // 从 URL 参数初始化股票代码 - const [stockCode, setStockCode] = useState( - searchParams.get(paramName) || defaultCode - ); - - // 输入框状态(默认为空,不显示默认股票代码) - const [inputCode, setInputCode] = useState(''); - - /** - * 监听 URL 参数变化,同步到本地状态 - * 支持浏览器前进/后退按钮 - */ - useEffect(() => { - const urlCode = searchParams.get(paramName); - if (urlCode && urlCode !== stockCode) { - setStockCode(urlCode); - setInputCode(urlCode); - } - }, [searchParams, paramName, stockCode]); - - /** - * 执行搜索 - 更新 stockCode 和 URL - * @param {string} [code] - 可选,直接传入股票代码(用于下拉选择) - */ - const handleSearch = useCallback((code) => { - const trimmedCode = code || inputCode?.trim(); - - if (trimmedCode && trimmedCode !== stockCode) { - // 触发变化回调(用于追踪) - onStockChange?.(trimmedCode, stockCode); - - // 更新状态 - setStockCode(trimmedCode); - - // 更新 URL 参数 - setSearchParams({ [paramName]: trimmedCode }); - } - }, [inputCode, stockCode, paramName, setSearchParams, onStockChange]); - - /** - * 处理键盘事件 - 回车键触发搜索 - */ - const handleKeyDown = useCallback((e) => { - if (e.key === 'Enter') { - handleSearch(); - } - }, [handleSearch]); - - return { - // 状态 - stockCode, // 当前确认的股票代码 - inputCode, // 输入框中的值(未确认) - - // 操作方法 - setInputCode, // 更新输入框 - handleSearch, // 执行搜索 - handleKeyDown, // 处理回车键(改用 onKeyDown) - }; -}; - -export default useCompanyStock; diff --git a/src/views/Company/hooks/useCompanyWatchlist.js b/src/views/Company/hooks/useCompanyWatchlist.js deleted file mode 100644 index 56019470..00000000 --- a/src/views/Company/hooks/useCompanyWatchlist.js +++ /dev/null @@ -1,166 +0,0 @@ -// src/views/Company/hooks/useCompanyWatchlist.js -// 自选股管理 Hook - Company 页面专用,复用 Redux stockSlice - -import { useEffect, useCallback, useMemo, useRef } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { useToast } from '@chakra-ui/react'; -import { useAuth } from '@contexts/AuthContext'; -import { logger } from '@utils/logger'; -import { - loadWatchlist, - toggleWatchlist, - optimisticAddWatchlist, - optimisticRemoveWatchlist -} from '@store/slices/stockSlice'; -import { TOAST_MESSAGES } from '../constants'; - -/** - * Company 页面自选股管理 Hook - * - * 功能: - * - 检查当前股票是否在自选股中 - * - 提供添加/移除自选股功能 - * - 与 Redux stockSlice 同步 - * - * @param {Object} options - 配置选项 - * @param {string} options.stockCode - 当前股票代码 - * @param {Object} [options.tracking] - 追踪回调 - * @param {Function} [options.tracking.onAdd] - 添加自选时的追踪回调 - * @param {Function} [options.tracking.onRemove] - 移除自选时的追踪回调 - * @returns {Object} 自选股状态和操作方法 - */ -export const useCompanyWatchlist = ({ stockCode, tracking = {} } = {}) => { - const dispatch = useDispatch(); - const toast = useToast(); - const { isAuthenticated } = useAuth(); - - // 从 Redux 获取自选股列表 - const watchlist = useSelector((state) => state.stock.watchlist); - const watchlistLoading = useSelector((state) => state.stock.loading.watchlist); - - // 追踪是否已初始化(防止无限循环) - const hasInitializedRef = useRef(false); - - /** - * 派生状态:判断当前股票是否在自选股中 - * 使用 useMemo 避免重复计算 - */ - const isInWatchlist = useMemo(() => { - if (!stockCode || !Array.isArray(watchlist)) { - return false; - } - - // 标准化股票代码(提取6位数字) - const normalize = (code) => String(code || '').match(/(\d{6})/)?.[1] || ''; - const targetCode = normalize(stockCode); - - return watchlist.some((item) => normalize(item.stock_code) === targetCode); - }, [watchlist, stockCode]); - - /** - * 初始化:加载自选股列表 - * 使用 hasInitializedRef 防止无限循环(用户可能确实没有自选股) - */ - useEffect(() => { - if (!hasInitializedRef.current && isAuthenticated && !watchlistLoading) { - hasInitializedRef.current = true; - dispatch(loadWatchlist()); - } - }, [isAuthenticated, watchlistLoading, dispatch]); - - /** - * 切换自选股状态(乐观更新模式) - * 1. 立即更新 UI(无 loading) - * 2. 后台静默请求 API - * 3. 失败时回滚并提示 - */ - const toggle = useCallback(async () => { - // 参数校验 - if (!stockCode) { - logger.warn('useCompanyWatchlist', 'toggle', '无效的股票代码', { stockCode }); - toast(TOAST_MESSAGES.INVALID_CODE); - return; - } - - // 权限校验 - if (!isAuthenticated) { - logger.warn('useCompanyWatchlist', 'toggle', '用户未登录', { stockCode }); - toast(TOAST_MESSAGES.LOGIN_REQUIRED); - return; - } - - // 标准化股票代码用于匹配 - const normalize = (code) => String(code || '').match(/(\d{6})/)?.[1] || ''; - const targetCode = normalize(stockCode); - - // 从 watchlist 中找到原始 stock_code(保持与后端数据结构一致) - const matchedItem = watchlist.find( - item => normalize(item.stock_code) === targetCode - ); - // 移除时使用原始 stock_code,添加时使用传入的 stockCode - const codeForApi = isInWatchlist ? (matchedItem?.stock_code || stockCode) : stockCode; - - // 保存当前状态用于回滚 - const wasInWatchlist = isInWatchlist; - - logger.debug('useCompanyWatchlist', '切换自选股(乐观更新)', { - stockCode, - codeForApi, - wasInWatchlist, - action: wasInWatchlist ? 'remove' : 'add', - }); - - // 1. 乐观更新:立即更新 UI(不显示 loading) - if (wasInWatchlist) { - dispatch(optimisticRemoveWatchlist({ stockCode: codeForApi })); - } else { - dispatch(optimisticAddWatchlist({ stockCode: codeForApi, stockName: matchedItem?.stock_name || '' })); - } - - try { - // 2. 后台静默请求 API - await dispatch( - toggleWatchlist({ - stockCode: codeForApi, - stockName: matchedItem?.stock_name || '', - isInWatchlist: wasInWatchlist, - }) - ).unwrap(); - - // 3. 成功:触发追踪回调(不显示 toast,状态已更新) - if (wasInWatchlist) { - tracking.onRemove?.(stockCode); - } else { - tracking.onAdd?.(stockCode); - } - } catch (error) { - // 4. 失败:回滚状态 + 显示错误提示 - logger.error('useCompanyWatchlist', 'toggle', error, { - stockCode, - wasInWatchlist, - }); - - // 回滚操作 - if (wasInWatchlist) { - // 之前在自选中,乐观删除了,现在要恢复 - dispatch(optimisticAddWatchlist({ stockCode: codeForApi, stockName: matchedItem?.stock_name || '' })); - } else { - // 之前不在自选中,乐观添加了,现在要移除 - dispatch(optimisticRemoveWatchlist({ stockCode: codeForApi })); - } - - toast(TOAST_MESSAGES.WATCHLIST_ERROR); - } - }, [stockCode, isAuthenticated, isInWatchlist, watchlist, dispatch, toast, tracking]); - - return { - // 状态 - isInWatchlist, // 是否在自选股中 - isLoading: watchlistLoading, // 仅初始加载时显示 loading(乐观更新模式) - - // 操作方法 - toggle, // 切换自选状态 - }; -}; - -export default useCompanyWatchlist;