chore(Company): 删除未使用的占位符组件和废弃 hooks

删除的文件:
- 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 <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-26 13:24:15 +08:00
parent 9d6c1e0396
commit 0f72cc633d
5 changed files with 0 additions and 337 deletions

View File

@@ -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 (
<Box
p={8}
borderRadius="lg"
bg="gray.50"
_dark={{ bg: 'gray.800' }}
textAlign="center"
>
<VStack spacing={4}>
<Icon as={LineChart} boxSize={12} color="gray.400" />
<Text fontSize="lg" fontWeight="medium" color="gray.600" _dark={{ color: 'gray.400' }}>
预测报告功能开发中
</Text>
<Text fontSize="sm" color="gray.500">
股票代码: {stockCode || '未选择'}
</Text>
</VStack>
</Box>
);
};
export default ForecastReport;

View File

@@ -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 (
<Box
p={8}
borderRadius="lg"
bg="gray.50"
_dark={{ bg: 'gray.800' }}
textAlign="center"
>
<VStack spacing={4}>
<Icon as={BarChart2} boxSize={12} color="gray.400" />
<Text fontSize="lg" fontWeight="medium" color="gray.600" _dark={{ color: 'gray.400' }}>
市场数据功能开发中
</Text>
<Text fontSize="sm" color="gray.500">
股票代码: {stockCode || '未选择'}
</Text>
</VStack>
</Box>
);
};
export default MarketDataView;

View File

@@ -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` - 事件追踪
- **功能**
- 页面浏览追踪

View File

@@ -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;

View File

@@ -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;