// src/views/Company/components/DynamicTracking/index.js // 动态跟踪 - 独立一级 Tab 组件(包含新闻动态等二级 Tab) import React, { useState, useEffect, useCallback } from "react"; import { Box, Tabs, TabList, TabPanels, Tab, TabPanel, } from "@chakra-ui/react"; import { FaNewspaper, FaBullhorn, FaCalendarAlt } from "react-icons/fa"; import { logger } from "@utils/logger"; import { getApiBase } from "@utils/apiConfig"; import NewsEventsTab from "../CompanyOverview/NewsEventsTab"; import AnnouncementsPanel from "../CompanyOverview/BasicInfoTab/components/AnnouncementsPanel"; import DisclosureSchedulePanel from "../CompanyOverview/BasicInfoTab/components/DisclosureSchedulePanel"; import { THEME } from "../CompanyOverview/BasicInfoTab/config"; // API配置 const API_BASE_URL = getApiBase(); // 二级 Tab 配置 const TRACKING_TABS = [ { key: "news", name: "新闻动态", icon: FaNewspaper }, { key: "announcements", name: "公司公告", icon: FaBullhorn }, { key: "disclosure", name: "财报披露日程", icon: FaCalendarAlt }, ]; /** * 动态跟踪组件 * * 功能: * - 二级 Tab 结构 * - Tab1: 新闻动态(复用 NewsEventsTab) * - 预留后续扩展 * * @param {Object} props * @param {string} props.stockCode - 股票代码 */ const DynamicTracking = ({ stockCode: propStockCode }) => { const [stockCode, setStockCode] = useState(propStockCode || "000001"); const [activeTab, setActiveTab] = useState(0); // 新闻动态状态 const [newsEvents, setNewsEvents] = useState([]); const [newsLoading, setNewsLoading] = useState(false); const [newsPagination, setNewsPagination] = useState({ page: 1, per_page: 10, total: 0, pages: 0, has_next: false, has_prev: false, }); const [searchQuery, setSearchQuery] = useState(""); const [stockName, setStockName] = useState(""); const [dataLoaded, setDataLoaded] = useState(false); // 监听 props 中的 stockCode 变化 useEffect(() => { if (propStockCode && propStockCode !== stockCode) { setStockCode(propStockCode); setDataLoaded(false); setNewsEvents([]); setStockName(""); setSearchQuery(""); } }, [propStockCode, stockCode]); // 获取股票名称(用于搜索) const fetchStockName = useCallback(async () => { try { const response = await fetch( `${API_BASE_URL}/api/stock/${stockCode}/basic-info` ); const result = await response.json(); if (result.success && result.data) { const name = result.data.SECNAME || result.data.ORGNAME || stockCode; setStockName(name); return name; } return stockCode; } catch (err) { logger.error("DynamicTracking", "fetchStockName", err, { stockCode }); return stockCode; } }, [stockCode]); // 加载新闻事件数据 const loadNewsEvents = useCallback( async (query, page = 1) => { setNewsLoading(true); try { const searchTerm = query || stockName || stockCode; const response = await fetch( `${API_BASE_URL}/api/events?q=${encodeURIComponent(searchTerm)}&page=${page}&per_page=10` ); const result = await response.json(); if (result.success) { setNewsEvents(result.data || []); setNewsPagination({ page: result.pagination?.page || page, per_page: result.pagination?.per_page || 10, total: result.pagination?.total || 0, pages: result.pagination?.pages || 0, has_next: result.pagination?.has_next || false, has_prev: result.pagination?.has_prev || false, }); } } catch (err) { logger.error("DynamicTracking", "loadNewsEvents", err, { stockCode }); setNewsEvents([]); } finally { setNewsLoading(false); } }, [stockCode, stockName] ); // 首次加载 useEffect(() => { const initLoad = async () => { if (stockCode && !dataLoaded) { const name = await fetchStockName(); await loadNewsEvents(name, 1); setDataLoaded(true); } }; initLoad(); }, [stockCode, dataLoaded, fetchStockName, loadNewsEvents]); // 搜索处理 const handleSearchChange = (value) => { setSearchQuery(value); }; const handleSearch = () => { loadNewsEvents(searchQuery || stockName, 1); }; // 分页处理 const handlePageChange = (page) => { loadNewsEvents(searchQuery || stockName, page); }; return ( {TRACKING_TABS.map((tab) => ( {tab.name} ))} {/* 新闻动态 Tab */} {/* 公司公告 Tab */} {/* 财报披露日程 Tab */} ); }; export default DynamicTracking;