refactor: 财报披露日程独立为动态跟踪第三个 Tab
- 新建 DisclosureSchedulePanel 组件,独立展示财报披露日程 - 简化 AnnouncementsPanel,移除财报披露日程部分 - DynamicTracking 新增第三个 Tab:财报披露日程 - 更新 mock 数据字段名匹配组件需求 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,6 @@ import {
|
||||
Icon,
|
||||
Card,
|
||||
CardBody,
|
||||
SimpleGrid,
|
||||
Divider,
|
||||
IconButton,
|
||||
Button,
|
||||
Tag,
|
||||
@@ -25,11 +23,10 @@ import {
|
||||
ModalFooter,
|
||||
useDisclosure,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaCalendarAlt, FaBullhorn } from "react-icons/fa";
|
||||
import { FaBullhorn } from "react-icons/fa";
|
||||
import { ExternalLinkIcon } from "@chakra-ui/icons";
|
||||
|
||||
import { useAnnouncementsData } from "../../hooks/useAnnouncementsData";
|
||||
import { useDisclosureData } from "../../hooks/useDisclosureData";
|
||||
import { THEME } from "../config";
|
||||
import { formatDate } from "../utils";
|
||||
import LoadingState from "./LoadingState";
|
||||
@@ -39,8 +36,7 @@ interface AnnouncementsPanelProps {
|
||||
}
|
||||
|
||||
const AnnouncementsPanel: React.FC<AnnouncementsPanelProps> = ({ stockCode }) => {
|
||||
const { announcements, loading: announcementsLoading } = useAnnouncementsData(stockCode);
|
||||
const { disclosureSchedule, loading: disclosureLoading } = useDisclosureData(stockCode);
|
||||
const { announcements, loading } = useAnnouncementsData(stockCode);
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [selectedAnnouncement, setSelectedAnnouncement] = useState<any>(null);
|
||||
@@ -50,8 +46,6 @@ const AnnouncementsPanel: React.FC<AnnouncementsPanelProps> = ({ stockCode }) =>
|
||||
onOpen();
|
||||
};
|
||||
|
||||
const loading = announcementsLoading || disclosureLoading;
|
||||
|
||||
if (loading) {
|
||||
return <LoadingState message="加载公告数据..." />;
|
||||
}
|
||||
@@ -59,47 +53,6 @@ const AnnouncementsPanel: React.FC<AnnouncementsPanelProps> = ({ stockCode }) =>
|
||||
return (
|
||||
<>
|
||||
<VStack spacing={4} align="stretch">
|
||||
{/* 财报披露日程 */}
|
||||
{disclosureSchedule.length > 0 && (
|
||||
<Box>
|
||||
<HStack mb={3}>
|
||||
<Icon as={FaCalendarAlt} color={THEME.gold} />
|
||||
<Text fontWeight="bold" color={THEME.textPrimary}>财报披露日程</Text>
|
||||
</HStack>
|
||||
<SimpleGrid columns={{ base: 2, md: 4 }} spacing={3}>
|
||||
{disclosureSchedule.slice(0, 4).map((schedule: any, idx: number) => (
|
||||
<Card
|
||||
key={idx}
|
||||
bg={schedule.is_disclosed ? "green.900" : "orange.900"}
|
||||
border="1px solid"
|
||||
borderColor={schedule.is_disclosed ? "green.600" : "orange.600"}
|
||||
size="sm"
|
||||
>
|
||||
<CardBody p={3}>
|
||||
<VStack spacing={1}>
|
||||
<Badge colorScheme={schedule.is_disclosed ? "green" : "orange"}>
|
||||
{schedule.report_name}
|
||||
</Badge>
|
||||
<Text fontSize="sm" fontWeight="bold" color={THEME.textPrimary}>
|
||||
{schedule.is_disclosed ? "已披露" : "预计"}
|
||||
</Text>
|
||||
<Text fontSize="xs" color={THEME.textSecondary}>
|
||||
{formatDate(
|
||||
schedule.is_disclosed
|
||||
? schedule.actual_date
|
||||
: schedule.latest_scheduled_date
|
||||
)}
|
||||
</Text>
|
||||
</VStack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Divider borderColor={THEME.border} />
|
||||
|
||||
{/* 最新公告 */}
|
||||
<Box>
|
||||
<HStack mb={3}>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// src/views/Company/components/CompanyOverview/BasicInfoTab/components/DisclosureSchedulePanel.tsx
|
||||
// 财报披露日程 Tab Panel
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
Box,
|
||||
VStack,
|
||||
HStack,
|
||||
Text,
|
||||
Badge,
|
||||
Icon,
|
||||
Card,
|
||||
CardBody,
|
||||
SimpleGrid,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaCalendarAlt } from "react-icons/fa";
|
||||
|
||||
import { useDisclosureData } from "../../hooks/useDisclosureData";
|
||||
import { THEME } from "../config";
|
||||
import { formatDate } from "../utils";
|
||||
import LoadingState from "./LoadingState";
|
||||
|
||||
interface DisclosureSchedulePanelProps {
|
||||
stockCode: string;
|
||||
}
|
||||
|
||||
const DisclosureSchedulePanel: React.FC<DisclosureSchedulePanelProps> = ({ stockCode }) => {
|
||||
const { disclosureSchedule, loading } = useDisclosureData(stockCode);
|
||||
|
||||
if (loading) {
|
||||
return <LoadingState message="加载披露日程..." />;
|
||||
}
|
||||
|
||||
if (disclosureSchedule.length === 0) {
|
||||
return (
|
||||
<Box textAlign="center" py={8}>
|
||||
<Text color={THEME.textSecondary}>暂无披露日程数据</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<VStack spacing={4} align="stretch">
|
||||
<Box>
|
||||
<HStack mb={3}>
|
||||
<Icon as={FaCalendarAlt} color={THEME.gold} />
|
||||
<Text fontWeight="bold" color={THEME.textPrimary}>财报披露日程</Text>
|
||||
</HStack>
|
||||
<SimpleGrid columns={{ base: 2, md: 4 }} spacing={3}>
|
||||
{disclosureSchedule.map((schedule: any, idx: number) => (
|
||||
<Card
|
||||
key={idx}
|
||||
bg={schedule.is_disclosed ? "green.900" : "orange.900"}
|
||||
border="1px solid"
|
||||
borderColor={schedule.is_disclosed ? "green.600" : "orange.600"}
|
||||
size="sm"
|
||||
>
|
||||
<CardBody p={3}>
|
||||
<VStack spacing={1}>
|
||||
<Badge colorScheme={schedule.is_disclosed ? "green" : "orange"}>
|
||||
{schedule.report_name}
|
||||
</Badge>
|
||||
<Text fontSize="sm" fontWeight="bold" color={THEME.textPrimary}>
|
||||
{schedule.is_disclosed ? "已披露" : "预计"}
|
||||
</Text>
|
||||
<Text fontSize="xs" color={THEME.textSecondary}>
|
||||
{formatDate(
|
||||
schedule.is_disclosed
|
||||
? schedule.actual_date
|
||||
: schedule.latest_scheduled_date
|
||||
)}
|
||||
</Text>
|
||||
</VStack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default DisclosureSchedulePanel;
|
||||
@@ -5,7 +5,6 @@ import { IconType } from "react-icons";
|
||||
import {
|
||||
FaShareAlt,
|
||||
FaUserTie,
|
||||
FaBullhorn,
|
||||
FaSitemap,
|
||||
FaInfoCircle,
|
||||
} from "react-icons/fa";
|
||||
@@ -72,12 +71,6 @@ export const TAB_CONFIG: TabConfig[] = [
|
||||
icon: FaUserTie,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
key: "announcements",
|
||||
name: "公司公告",
|
||||
icon: FaBullhorn,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
key: "branches",
|
||||
name: "分支机构",
|
||||
|
||||
@@ -10,11 +10,14 @@ import {
|
||||
Tab,
|
||||
TabPanel,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaNewspaper } from "react-icons/fa";
|
||||
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();
|
||||
@@ -22,7 +25,8 @@ const API_BASE_URL = getApiBase();
|
||||
// 二级 Tab 配置
|
||||
const TRACKING_TABS = [
|
||||
{ key: "news", name: "新闻动态", icon: FaNewspaper },
|
||||
// 后续可扩展更多二级 Tab
|
||||
{ key: "announcements", name: "公司公告", icon: FaBullhorn },
|
||||
{ key: "disclosure", name: "财报披露日程", icon: FaCalendarAlt },
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -144,16 +148,26 @@ const DynamicTracking = ({ stockCode: propStockCode }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box bg={THEME.bg} p={4} borderRadius="md">
|
||||
<Tabs
|
||||
variant="enclosed"
|
||||
colorScheme="blue"
|
||||
variant="soft-rounded"
|
||||
index={activeTab}
|
||||
onChange={setActiveTab}
|
||||
isLazy
|
||||
>
|
||||
<TabList>
|
||||
<TabList bg={THEME.cardBg} borderBottom="1px solid" borderColor={THEME.border}>
|
||||
{TRACKING_TABS.map((tab) => (
|
||||
<Tab key={tab.key} fontWeight="medium">
|
||||
<Tab
|
||||
key={tab.key}
|
||||
fontWeight="medium"
|
||||
color={THEME.textSecondary}
|
||||
_selected={{
|
||||
color: THEME.tabSelected.color,
|
||||
bg: THEME.tabSelected.bg,
|
||||
borderRadius: "md",
|
||||
}}
|
||||
_hover={{ color: THEME.gold }}
|
||||
>
|
||||
{tab.name}
|
||||
</Tab>
|
||||
))}
|
||||
@@ -174,7 +188,15 @@ const DynamicTracking = ({ stockCode: propStockCode }) => {
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
{/* 后续可扩展更多 Tab Panel */}
|
||||
{/* 公司公告 Tab */}
|
||||
<TabPanel p={4}>
|
||||
<AnnouncementsPanel stockCode={stockCode} />
|
||||
</TabPanel>
|
||||
|
||||
{/* 财报披露日程 Tab */}
|
||||
<TabPanel p={4}>
|
||||
<DisclosureSchedulePanel stockCode={stockCode} />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user