diff --git a/src/views/Community/components/MarketOverviewBanner.js b/src/views/Community/components/MarketOverviewBanner.js
index 98ad8651..1c03ac1c 100644
--- a/src/views/Community/components/MarketOverviewBanner.js
+++ b/src/views/Community/components/MarketOverviewBanner.js
@@ -17,295 +17,31 @@ import {
FireOutlined,
RiseOutlined,
FallOutlined,
- ThunderboltOutlined,
- TrophyOutlined,
- BarChartOutlined,
CalendarOutlined,
- StockOutlined,
+ BarChartOutlined,
} from "@ant-design/icons";
-import { Modal, Table } from "antd";
import { getApiBase } from "@utils/apiConfig";
-// 涨跌颜色常量
-const UP_COLOR = "#FF4D4F"; // 涨 - 红色
-const DOWN_COLOR = "#52C41A"; // 跌 - 绿色
-const FLAT_COLOR = "#888888"; // 平 - 灰色
-
-/**
- * 判断是否在交易时间内 (9:30-15:00)
- */
-const isInTradingTime = () => {
- const now = new Date();
- const hours = now.getHours();
- const minutes = now.getMinutes();
- const time = hours * 60 + minutes;
- return time >= 570 && time <= 900; // 9:30-15:00
-};
-
-// 注入脉冲动画样式
-if (typeof document !== "undefined") {
- const styleId = "market-banner-animations";
- if (!document.getElementById(styleId)) {
- const styleSheet = document.createElement("style");
- styleSheet.id = styleId;
- styleSheet.innerText = `
- @keyframes pulse {
- 0%, 100% { opacity: 1; transform: scale(1); }
- 50% { opacity: 0.6; transform: scale(1.1); }
- }
- `;
- document.head.appendChild(styleSheet);
- }
-}
-
-/**
- * 格式化涨跌幅
- */
-const formatChg = (val) => {
- if (val === null || val === undefined) return "-";
- const num = parseFloat(val);
- if (isNaN(num)) return "-";
- return (num >= 0 ? "+" : "") + num.toFixed(2) + "%";
-};
-
-/**
- * 沪深实时涨跌条形图组件 - 紧凑版
- */
-const MarketStatsBarCompact = ({ marketStats }) => {
- if (!marketStats || marketStats.totalCount === 0) return null;
-
- const {
- risingCount = 0,
- flatCount = 0,
- fallingCount = 0,
- totalCount = 0,
- } = marketStats;
- const risePercent = totalCount > 0 ? (risingCount / totalCount) * 100 : 0;
- const flatPercent = totalCount > 0 ? (flatCount / totalCount) * 100 : 0;
- const fallPercent = totalCount > 0 ? (fallingCount / totalCount) * 100 : 0;
-
- return (
-
- {/* 标题 */}
-
-
- 沪深实时涨跌
-
-
- ({totalCount}只)
-
-
-
- {/* 进度条 */}
-
-
-
-
-
-
-
-
- {/* 数值标签 */}
-
-
-
-
- {risingCount}
-
-
- 涨
-
-
-
-
-
-
- {flatCount}
-
-
- 平
-
-
-
-
-
-
- {fallingCount}
-
-
- 跌
-
-
-
-
- );
-};
-
-/**
- * 环形进度图组件 - 仿图片样式
- * @param {boolean} noBorder - 是否不显示边框(用于嵌套在其他容器中)
- */
-const CircularProgressCard = ({ label, value, color = "#EC4899", size = 44, highlight = false, noBorder = false }) => {
- const percentage = parseFloat(value) || 0;
- const strokeWidth = 3;
- const radius = (size - strokeWidth) / 2;
- // 270度圆弧(底部有缺口)
- const arcLength = (270 / 360) * 2 * Math.PI * radius;
- const progressLength = (percentage / 100) * arcLength;
-
- return (
-
-
- {label}
-
-
-
- {/* 中心数值 */}
-
-
- {percentage.toFixed(1)}%
-
-
-
-
- );
-};
-
-/**
- * 紧凑数据卡片 - 通栏版
- */
-const BannerStatCard = ({ label, value, icon, color = "#7C3AED", highlight = false }) => (
-
-
-
- {icon}
-
-
- {label}
-
-
-
- {value}
-
-
-);
+// 模块化导入
+import {
+ UP_COLOR,
+ DOWN_COLOR,
+ isInTradingTime,
+ formatChg,
+} from "./MarketOverviewBanner/constants";
+import {
+ MarketStatsBarCompact,
+ CircularProgressCard,
+ BannerStatCard,
+} from "./MarketOverviewBanner/components";
+import StockTop10Modal from "./MarketOverviewBanner/StockTop10Modal";
const MarketOverviewBanner = () => {
const [loading, setLoading] = useState(true);
const [stats, setStats] = useState(null);
- const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split("T")[0]);
+ const [selectedDate, setSelectedDate] = useState(
+ new Date().toISOString().split("T")[0]
+ );
const [stockModalVisible, setStockModalVisible] = useState(false);
const dateInputRef = useRef(null);
@@ -337,7 +73,7 @@ const MarketOverviewBanner = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- // 日期变化时静默刷新(不显示 loading)
+ // 日期变化时静默刷新
useEffect(() => {
if (selectedDate) {
fetchStats(selectedDate, false);
@@ -371,6 +107,7 @@ const MarketOverviewBanner = () => {
if (!stats) return null;
const { summary, marketStats, topStocks = [] } = stats;
+ const today = new Date().toISOString().split("T")[0];
return (
@@ -420,9 +157,10 @@ const MarketOverviewBanner = () => {
)}
+
- {/* 返回今天按钮 - 当选择的不是今天时显示 */}
- {selectedDate !== new Date().toISOString().split("T")[0] && (
+ {/* 返回今天按钮 */}
+ {selectedDate !== today && (
{
borderColor: "rgba(255, 215, 0, 0.6)",
}}
transition="all 0.2s"
- onClick={() => setSelectedDate(new Date().toISOString().split("T")[0])}
+ onClick={() => setSelectedDate(today)}
>
返回今天
)}
- {/* 日期选择器 - 金色边框 */}
+ {/* 日期选择器 */}
{
value={selectedDate}
onChange={handleDateChange}
onClick={handleCalendarClick}
- max={new Date().toISOString().split("T")[0]}
+ max={today}
bg="transparent"
border="none"
color="#FFD700"
@@ -503,7 +241,7 @@ const MarketOverviewBanner = () => {
- {/* 右侧:6个指标卡片 - 1行6列 */}
+ {/* 右侧:6个指标卡片 */}
{
color="#F59E0B"
highlight
/>
- {/* 关联股票 + TOP10标签 - 与 BannerStatCard 样式统一 */}
+ {/* 关联股票卡片 */}
{
{/* 股票TOP10弹窗 */}
-
-
- 股票 TOP10
-
- }
- open={stockModalVisible}
- onCancel={() => setStockModalVisible(false)}
- footer={null}
- width={600}
- closeIcon={×}
- styles={{
- content: {
- background: "linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)",
- border: "1px solid rgba(236, 72, 153, 0.3)",
- },
- header: {
- background: "transparent",
- borderBottom: "1px solid rgba(255,255,255,0.1)",
- },
- }}
- >
-
- record.stockCode || record.stockName}
- pagination={false}
- size="small"
- className="stock-top10-table"
- columns={[
- {
- title: "排名",
- dataIndex: "rank",
- key: "rank",
- width: 60,
- render: (_, __, index) => (
-
- {index + 1}
-
- ),
- },
- {
- title: "股票代码",
- dataIndex: "stockCode",
- key: "stockCode",
- width: 100,
- render: (code) => (
-
- {code?.split(".")[0] || "-"}
-
- ),
- },
- {
- title: "股票名称",
- dataIndex: "stockName",
- key: "stockName",
- render: (name) => (
-
- {name || "-"}
-
- ),
- },
- {
- title: "最大涨幅",
- dataIndex: "maxChg",
- key: "maxChg",
- width: 100,
- align: "right",
- render: (val) => (
- = 0 ? UP_COLOR : DOWN_COLOR}
- >
- {formatChg(val)}
-
- ),
- },
- ]}
- />
-
+ setStockModalVisible(false)}
+ topStocks={topStocks}
+ />
);
};
diff --git a/src/views/Community/components/MarketOverviewBanner/StockTop10Modal.js b/src/views/Community/components/MarketOverviewBanner/StockTop10Modal.js
new file mode 100644
index 00000000..db6704d3
--- /dev/null
+++ b/src/views/Community/components/MarketOverviewBanner/StockTop10Modal.js
@@ -0,0 +1,138 @@
+// 股票 TOP10 弹窗组件
+
+import React from "react";
+import { Text, HStack } from "@chakra-ui/react";
+import { StockOutlined } from "@ant-design/icons";
+import { Modal, Table } from "antd";
+import { UP_COLOR, DOWN_COLOR, formatChg } from "./constants";
+
+// 弹窗内表格样式
+const modalTableStyles = `
+ .stock-top10-table .ant-table {
+ background: transparent !important;
+ }
+ .stock-top10-table .ant-table-thead > tr > th {
+ background: rgba(236, 72, 153, 0.1) !important;
+ color: rgba(255, 255, 255, 0.8) !important;
+ border-bottom: 1px solid rgba(236, 72, 153, 0.2) !important;
+ font-weight: 600;
+ }
+ .stock-top10-table .ant-table-tbody > tr > td {
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
+ padding: 10px 8px !important;
+ }
+ .stock-top10-table .ant-table-tbody > tr:nth-child(odd) {
+ background: rgba(255, 255, 255, 0.02) !important;
+ }
+ .stock-top10-table .ant-table-tbody > tr:nth-child(even) {
+ background: rgba(0, 0, 0, 0.1) !important;
+ }
+ .stock-top10-table .ant-table-tbody > tr:hover > td {
+ background: rgba(236, 72, 153, 0.15) !important;
+ }
+ .stock-top10-table .ant-table-cell {
+ background: transparent !important;
+ }
+`;
+
+// 表格列定义
+const tableColumns = [
+ {
+ title: "排名",
+ dataIndex: "rank",
+ key: "rank",
+ width: 60,
+ render: (_, __, index) => (
+
+ {index + 1}
+
+ ),
+ },
+ {
+ title: "股票代码",
+ dataIndex: "stockCode",
+ key: "stockCode",
+ width: 100,
+ render: (code) => (
+
+ {code?.split(".")[0] || "-"}
+
+ ),
+ },
+ {
+ title: "股票名称",
+ dataIndex: "stockName",
+ key: "stockName",
+ render: (name) => (
+
+ {name || "-"}
+
+ ),
+ },
+ {
+ title: "最大涨幅",
+ dataIndex: "maxChg",
+ key: "maxChg",
+ width: 100,
+ align: "right",
+ render: (val) => (
+ = 0 ? UP_COLOR : DOWN_COLOR}>
+ {formatChg(val)}
+
+ ),
+ },
+];
+
+/**
+ * 股票 TOP10 弹窗组件
+ */
+const StockTop10Modal = ({ visible, onClose, topStocks = [] }) => {
+ return (
+
+
+ 股票 TOP10
+
+ }
+ open={visible}
+ onCancel={onClose}
+ footer={null}
+ width={600}
+ closeIcon={×}
+ styles={{
+ content: {
+ background: "linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)",
+ border: "1px solid rgba(236, 72, 153, 0.3)",
+ },
+ header: {
+ background: "transparent",
+ borderBottom: "1px solid rgba(255,255,255,0.1)",
+ },
+ }}
+ >
+
+ record.stockCode || record.stockName}
+ pagination={false}
+ size="small"
+ className="stock-top10-table"
+ columns={tableColumns}
+ />
+
+ );
+};
+
+export default StockTop10Modal;
diff --git a/src/views/Community/components/MarketOverviewBanner/components.js b/src/views/Community/components/MarketOverviewBanner/components.js
new file mode 100644
index 00000000..03df4b3e
--- /dev/null
+++ b/src/views/Community/components/MarketOverviewBanner/components.js
@@ -0,0 +1,261 @@
+// MarketOverviewBanner 子组件
+
+import React from "react";
+import { Box, Text, HStack, Flex } from "@chakra-ui/react";
+import { UP_COLOR, DOWN_COLOR, FLAT_COLOR } from "./constants";
+
+/**
+ * 沪深实时涨跌条形图组件 - 紧凑版
+ */
+export const MarketStatsBarCompact = ({ marketStats }) => {
+ if (!marketStats || marketStats.totalCount === 0) return null;
+
+ const {
+ risingCount = 0,
+ flatCount = 0,
+ fallingCount = 0,
+ totalCount = 0,
+ } = marketStats;
+ const risePercent = totalCount > 0 ? (risingCount / totalCount) * 100 : 0;
+ const flatPercent = totalCount > 0 ? (flatCount / totalCount) * 100 : 0;
+ const fallPercent = totalCount > 0 ? (fallingCount / totalCount) * 100 : 0;
+
+ return (
+
+
+
+ 沪深实时涨跌
+
+
+ ({totalCount}只)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {risingCount}
+
+
+ 涨
+
+
+
+
+
+
+ {flatCount}
+
+
+ 平
+
+
+
+
+
+
+ {fallingCount}
+
+
+ 跌
+
+
+
+
+ );
+};
+
+/**
+ * 环形进度图组件
+ */
+export const CircularProgressCard = ({
+ label,
+ value,
+ color = "#EC4899",
+ size = 44,
+ highlight = false,
+ noBorder = false,
+}) => {
+ const percentage = parseFloat(value) || 0;
+ const strokeWidth = 3;
+ const radius = (size - strokeWidth) / 2;
+ const arcLength = (270 / 360) * 2 * Math.PI * radius;
+ const progressLength = (percentage / 100) * arcLength;
+
+ return (
+
+
+ {label}
+
+
+
+
+
+ {percentage.toFixed(1)}%
+
+
+
+
+ );
+};
+
+/**
+ * 紧凑数据卡片
+ */
+export const BannerStatCard = ({
+ label,
+ value,
+ icon,
+ color = "#7C3AED",
+ highlight = false,
+}) => (
+
+
+
+ {icon}
+
+
+ {label}
+
+
+
+ {value}
+
+
+);
diff --git a/src/views/Community/components/MarketOverviewBanner/constants.js b/src/views/Community/components/MarketOverviewBanner/constants.js
new file mode 100644
index 00000000..822a01ef
--- /dev/null
+++ b/src/views/Community/components/MarketOverviewBanner/constants.js
@@ -0,0 +1,43 @@
+// MarketOverviewBanner 常量定义
+
+// 涨跌颜色常量
+export const UP_COLOR = "#FF4D4F"; // 涨 - 红色
+export const DOWN_COLOR = "#52C41A"; // 跌 - 绿色
+export const FLAT_COLOR = "#888888"; // 平 - 灰色
+
+/**
+ * 判断是否在交易时间内 (9:30-15:00)
+ */
+export const isInTradingTime = () => {
+ const now = new Date();
+ const hours = now.getHours();
+ const minutes = now.getMinutes();
+ const time = hours * 60 + minutes;
+ return time >= 570 && time <= 900; // 9:30-15:00
+};
+
+/**
+ * 格式化涨跌幅
+ */
+export const formatChg = (val) => {
+ if (val === null || val === undefined) return "-";
+ const num = parseFloat(val);
+ if (isNaN(num)) return "-";
+ return (num >= 0 ? "+" : "") + num.toFixed(2) + "%";
+};
+
+// 注入脉冲动画样式
+if (typeof document !== "undefined") {
+ const styleId = "market-banner-animations";
+ if (!document.getElementById(styleId)) {
+ const styleSheet = document.createElement("style");
+ styleSheet.id = styleId;
+ styleSheet.innerText = `
+ @keyframes pulse {
+ 0%, 100% { opacity: 1; transform: scale(1); }
+ 50% { opacity: 0.6; transform: scale(1.1); }
+ }
+ `;
+ document.head.appendChild(styleSheet);
+ }
+}
diff --git a/src/views/Community/components/MarketOverviewBanner/index.js b/src/views/Community/components/MarketOverviewBanner/index.js
new file mode 100644
index 00000000..3ccca49a
--- /dev/null
+++ b/src/views/Community/components/MarketOverviewBanner/index.js
@@ -0,0 +1,5 @@
+// MarketOverviewBanner 模块导出
+
+export { UP_COLOR, DOWN_COLOR, FLAT_COLOR, isInTradingTime, formatChg } from "./constants";
+export { MarketStatsBarCompact, CircularProgressCard, BannerStatCard } from "./components";
+export { default as StockTop10Modal } from "./StockTop10Modal";