refactor(layout): 统一页面边距管理,移除 Container 限制

- layoutConfig.js: 新增 LAYOUT_PADDING 常量 { base: 4, md: 6, lg: '80px' }
- MainLayout.js: 在 Outlet 容器上统一应用 px={LAYOUT_PADDING.x}
- HomeNavbar.js: 边距从 lg:8 改为 lg:'80px',与内容区对齐
- AppFooter.js: 移除 Container,边距改为 lg:'80px'

页面组件清理(移除冗余的 px/Container):
- Company, Community, Center, Profile, Settings
- ValueForum, DataBrowser, LimitAnalyse, StockOverview, Concept

特殊处理:
- CompanyHeader: 使用负边距实现全宽背景
- Concept Hero: 使用负边距实现全宽背景

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-24 18:29:19 +08:00
parent cac4f06c03
commit f5dbdfa84c
18 changed files with 59 additions and 80 deletions

View File

@@ -152,7 +152,7 @@ export default function HomeNavbar() {
borderColor={navbarBorder} borderColor={navbarBorder}
py={{ base: 2, md: 3 }} py={{ base: 2, md: 3 }}
> >
<Container maxW="container.xl" px={{ base: 3, md: 4 }} style={{ paddingRight: 'max(16px, env(safe-area-inset-right))' }}> <Box px={{ base: 4, md: 6, lg: '80px' }}>
<Flex justify="space-between" align="center"> <Flex justify="space-between" align="center">
{/* Logo - 价小前投研 */} {/* Logo - 价小前投研 */}
<BrandLogo /> <BrandLogo />
@@ -177,7 +177,7 @@ export default function HomeNavbar() {
followingEvents={followingEvents} followingEvents={followingEvents}
/> />
</Flex> </Flex>
</Container> </Box>
{/* 移动端抽屉菜单 (Phase 5 优化) */} {/* 移动端抽屉菜单 (Phase 5 优化) */}
<MobileDrawer <MobileDrawer

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Box, Container, VStack, HStack, Text, Link, useColorModeValue } from '@chakra-ui/react'; import { Box, VStack, HStack, Text, Link, useColorModeValue } from '@chakra-ui/react';
import RiskDisclaimer from '../components/RiskDisclaimer'; import RiskDisclaimer from '../components/RiskDisclaimer';
/** /**
@@ -8,8 +8,7 @@ import RiskDisclaimer from '../components/RiskDisclaimer';
*/ */
const AppFooter = () => { const AppFooter = () => {
return ( return (
<Box bg={useColorModeValue('gray.100', 'gray.800')} py={2}> <Box bg={useColorModeValue('gray.100', 'gray.800')} py={2} px={{ base: 4, md: 6, lg: '80px' }}>
<Container maxW="container.xl">
<VStack spacing={1}> <VStack spacing={1}>
<RiskDisclaimer /> <RiskDisclaimer />
<Text color="gray.500" fontSize="sm"> <Text color="gray.500" fontSize="sm">
@@ -32,7 +31,6 @@ const AppFooter = () => {
</Link> </Link>
</HStack> </HStack>
</VStack> </VStack>
</Container>
</Box> </Box>
); );
}; };

View File

@@ -9,7 +9,7 @@ import BackToTopButton from "./components/BackToTopButton";
import ErrorBoundary from "../components/ErrorBoundary"; import ErrorBoundary from "../components/ErrorBoundary";
import PageLoader from "../components/Loading/PageLoader"; import PageLoader from "../components/Loading/PageLoader";
import GlobalSidebar from "../components/GlobalSidebar"; import GlobalSidebar from "../components/GlobalSidebar";
import { BACK_TO_TOP_CONFIG, LAYOUT_SIZE } from "./config/layoutConfig"; import { BACK_TO_TOP_CONFIG, LAYOUT_SIZE, LAYOUT_PADDING } from "./config/layoutConfig";
// ✅ P0 性能优化:缓存静态组件,避免路由切换时不必要的重新渲染 // ✅ P0 性能优化:缓存静态组件,避免路由切换时不必要的重新渲染
// HomeNavbar (1623行) 和 AppFooter 不依赖路由参数,使用 memo 可大幅减少渲染次数 // HomeNavbar (1623行) 和 AppFooter 不依赖路由参数,使用 memo 可大幅减少渲染次数
@@ -40,7 +40,7 @@ export default function MainLayout() {
<Box flex="1" bg="#1A202C" position="relative" overflow="hidden"> <Box flex="1" bg="#1A202C" position="relative" overflow="hidden">
{/* 页面内容区域 - 全宽度,与导航栏对齐 */} {/* 页面内容区域 - 全宽度,与导航栏对齐 */}
<Box h="100%" overflowY="auto" display="flex" flexDirection="column"> <Box h="100%" overflowY="auto" display="flex" flexDirection="column">
<Box flex="1" pt={LAYOUT_SIZE.navbarHeight}> <Box flex="1" pt={LAYOUT_SIZE.navbarHeight} px={LAYOUT_PADDING.x}>
<ErrorBoundary> <ErrorBoundary>
<Suspense fallback={<PageLoader message="页面加载中..." />}> <Suspense fallback={<PageLoader message="页面加载中..." />}>
<Outlet /> <Outlet />

View File

@@ -170,6 +170,15 @@ export const LAYOUT_SIZE = {
contentMinHeight: 'calc(100vh - 60px)', // 100vh - navbar高度 contentMinHeight: 'calc(100vh - 60px)', // 100vh - navbar高度
}; };
/**
* 布局内边距配置
* 统一控制页面内容的水平内边距
* 右侧预留空间给 GlobalSidebar收起宽度 72px
*/
export const LAYOUT_PADDING = {
x: { base: 4, md: 6, lg: '80px' }, // 移动端 16px中屏 24px大屏 80px容纳工具栏
};
/** /**
* 响应式断点 * 响应式断点
* 与 Chakra UI 断点保持一致 * 与 Chakra UI 断点保持一致
@@ -189,5 +198,6 @@ export default {
BACK_TO_TOP_CONFIG, BACK_TO_TOP_CONFIG,
PAGE_LOADER_CONFIG, PAGE_LOADER_CONFIG,
LAYOUT_SIZE, LAYOUT_SIZE,
LAYOUT_PADDING,
BREAKPOINTS BREAKPOINTS
}; };

View File

@@ -23,7 +23,8 @@ const Center: React.FC = () => {
return ( return (
<Box bg={THEME.bg.primary} minH="100vh" overflowX="hidden"> <Box bg={THEME.bg.primary} minH="100vh" overflowX="hidden">
<Box px={{ base: 3, md: 4 }} py={{ base: 4, md: 6 }} maxW="container.xl" mx="auto"> {/* padding 由 MainLayout 统一设置 */}
<Box py={{ base: 4, md: 6 }}>
{/* 市场概览仪表盘 */} {/* 市场概览仪表盘 */}
<Box mb={4}> <Box mb={4}>
<MarketDashboard /> <MarketDashboard />

View File

@@ -8,8 +8,6 @@ import {
} from '@/store/slices/communityDataSlice'; } from '@/store/slices/communityDataSlice';
import { import {
Box, Box,
Container,
useBreakpointValue,
Skeleton, Skeleton,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@@ -45,23 +43,6 @@ const Community = () => {
// Ref用于首次滚动到内容区域 // Ref用于首次滚动到内容区域
const containerRef = useRef(null); const containerRef = useRef(null);
// 响应式容器宽度
const containerMaxW = useBreakpointValue({
base: '100%', // 移动端:全宽
sm: '100%', // 小屏:全宽
md: '100%', // 中屏:全宽
lg: '1200px', // 大屏1200px
xl: '1400px', // 超大屏1400px
});
// 响应式内边距
const containerPx = useBreakpointValue({
base: 2, // 移动端:最小内边距
sm: 3,
md: 4,
lg: 6,
});
// ⚡ 通知权限引导 // ⚡ 通知权限引导
const { browserPermission, requestBrowserPermission, registerEventUpdateCallback } = useNotification(); const { browserPermission, requestBrowserPermission, registerEventUpdateCallback } = useNotification();
@@ -165,8 +146,8 @@ const Community = () => {
return ( return (
<Box minH="100vh" bg={bgColor}> <Box minH="100vh" bg={bgColor}>
{/* 主内容区域 */} {/* 主内容区域 - padding 由 MainLayout 统一设置 */}
<Container ref={containerRef} maxW={containerMaxW} px={containerPx} pt={{ base: 3, md: 6 }} pb={{ base: 4, md: 8 }}> <Box ref={containerRef} pt={{ base: 3, md: 6 }} pb={{ base: 4, md: 8 }}>
{/* ⚡ 顶部说明面板(懒加载):产品介绍 + 沪深指数 + 热门概念词云 */} {/* ⚡ 顶部说明面板(懒加载):产品介绍 + 沪深指数 + 热门概念词云 */}
<Suspense fallback={ <Suspense fallback={
<Box mb={6} p={4} borderRadius="xl" bg="rgba(255,255,255,0.02)"> <Box mb={6} p={4} borderRadius="xl" bg="rgba(255,255,255,0.02)">
@@ -200,7 +181,7 @@ const Community = () => {
events={hotEvents} events={hotEvents}
onEventClick={communityEvents.trackNewsArticleClicked} onEventClick={communityEvents.trackNewsArticleClicked}
/> />
</Container> </Box>
</Box> </Box>
); );
}; };

View File

@@ -7,6 +7,7 @@ import { Box, Flex, HStack, VStack, Text } from '@chakra-ui/react';
import { AutoComplete, Input, Spin } from 'antd'; import { AutoComplete, Input, Spin } from 'antd';
import { SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import { useStockSearch } from '@hooks/useStockSearch'; import { useStockSearch } from '@hooks/useStockSearch';
import { LAYOUT_PADDING } from '@/layouts/config/layoutConfig';
import { THEME } from '../../config'; import { THEME } from '../../config';
import { FUI_COLORS, FUI_GLOW } from '../../theme/fui'; import { FUI_COLORS, FUI_GLOW } from '../../theme/fui';
import type { CompanyHeaderProps, StockSearchResult } from '../../types'; import type { CompanyHeaderProps, StockSearchResult } from '../../types';
@@ -115,17 +116,17 @@ SearchBox.displayName = 'SearchBox';
const CompanyHeader: React.FC<CompanyHeaderProps> = memo(({ onStockChange }) => ( const CompanyHeader: React.FC<CompanyHeaderProps> = memo(({ onStockChange }) => (
<Box <Box
position="relative" position="relative"
bg={FUI_COLORS.bg.primary} border="1px solid"
borderBottom="1px solid" borderRadius="8px"
borderColor={FUI_COLORS.line.default} sx={{
px={6} bg: FUI_COLORS.bg.primary,
py={4} borderColor: FUI_COLORS.line.default,
padding: '20px 20px',
}}
> >
<Flex <Flex
position="relative" position="relative"
zIndex={1} zIndex={1}
maxW="container.xl"
mx="auto"
justify="space-between" justify="space-between"
align="center" align="center"
> >

View File

@@ -332,7 +332,8 @@ const CompanyIndex: React.FC = () => {
position="relative" position="relative"
bg={THEME.bg} bg={THEME.bg}
minH="calc(100vh - 60px)" minH="calc(100vh - 60px)"
overflow="hidden" overflowX="visible"
overflowY="hidden"
> >
{/* ======================================== {/* ========================================
全局环境光效果 全局环境光效果
@@ -371,12 +372,10 @@ const CompanyIndex: React.FC = () => {
{/* {/*
内容容器 内容容器
- maxW="container.xl": 最大宽度限制,保持内容可读性
- mx="auto": 水平居中
- px={4}: 左右内边距 16px
- py={6}: 上下内边距 24px - py={6}: 上下内边距 24px
- 水平 padding 由 MainLayout 统一设置
*/} */}
<Box maxW="container.xl" mx="auto" px={4} py={6}> <Box py={6}>
{/* ======================================== {/* ========================================
股票行情卡片 股票行情卡片
======================================== ========================================

View File

@@ -4,7 +4,6 @@ import { logger } from '../../utils/logger';
import defaultEventImage from '../../assets/img/default-event.jpg'; import defaultEventImage from '../../assets/img/default-event.jpg';
import { import {
Box, Box,
Container,
Heading, Heading,
Text, Text,
Input, Input,
@@ -1538,12 +1537,14 @@ const ConceptCenter = () => {
{/* 导航栏已由 MainLayout 提供 */} {/* 导航栏已由 MainLayout 提供 */}
{/* Hero Section - 精简版 */} {/* Hero Section - 精简版 */}
{/* Hero Section - 使用负 margin 抵消 Layout 的 padding 实现全宽背景 */}
<Box <Box
position="relative" position="relative"
bgGradient="linear(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%)" bgGradient="linear(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%)"
color="white" color="white"
overflow="hidden" overflow="hidden"
zIndex={1} zIndex={1}
mx={{ base: -4, md: -6, lg: '-80px' }}
> >
{/* 科幻网格背景 */} {/* 科幻网格背景 */}
<Box <Box
@@ -1579,7 +1580,7 @@ const ConceptCenter = () => {
filter="blur(50px)" filter="blur(50px)"
/> />
<Container maxW="container.xl" position="relative" py={{ base: 8, md: 12 }}> <Box px={{ base: 4, md: 6, lg: '80px' }} position="relative" py={{ base: 8, md: 12 }}>
<VStack spacing={6}> <VStack spacing={6}>
{/* 标题区域 */} {/* 标题区域 */}
<VStack spacing={3} textAlign="center"> <VStack spacing={3} textAlign="center">
@@ -1743,11 +1744,11 @@ const ConceptCenter = () => {
</VStack> </VStack>
</Box> </Box>
</VStack> </VStack>
</Container> </Box>
</Box> </Box>
{/* 主内容区域 - 深色主题 */} {/* 主内容区域 - padding 由 MainLayout 统一设置 */}
<Container maxW="container.xl" py={10} position="relative" zIndex={1}> <Box py={10} position="relative" zIndex={1}>
<Box mb={6}> <Box mb={6}>
<DateSelector /> <DateSelector />
</Box> </Box>
@@ -2102,7 +2103,7 @@ const ConceptCenter = () => {
</Box> </Box>
</Box> </Box>
</Flex> </Flex>
</Container> </Box>
{/* 股票详情Modal - 复用通用组件 */} {/* 股票详情Modal - 复用通用组件 */}
<ConceptStocksModal <ConceptStocksModal

View File

@@ -1,7 +1,6 @@
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { import {
Box, Box,
Container,
Flex, Flex,
Text, Text,
Input, Input,
@@ -480,7 +479,8 @@ const DataBrowser: React.FC = () => {
pointerEvents="none" pointerEvents="none"
/> />
<Container maxW="container.xl" position="relative" zIndex={1}> {/* padding 由 MainLayout 统一设置 */}
<Box position="relative" zIndex={1}>
{/* 标题区域 */} {/* 标题区域 */}
<MotionBox <MotionBox
initial={{ opacity: 0, y: -20 }} initial={{ opacity: 0, y: -20 }}
@@ -866,7 +866,7 @@ const DataBrowser: React.FC = () => {
</Card> </Card>
</MotionBox> </MotionBox>
</Flex> </Flex>
</Container> </Box>
{/* 指标数据详情模态框 */} {/* 指标数据详情模态框 */}
{selectedMetric && ( {selectedMetric && (

View File

@@ -1,7 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Box, Box,
Container,
VStack, VStack,
HStack, HStack,
Heading, Heading,
@@ -263,8 +262,7 @@ export default function LimitAnalyse() {
{/* 导航栏已由 MainLayout 提供 */} {/* 导航栏已由 MainLayout 提供 */}
{/* 顶部Header */} {/* 顶部Header */}
<Box bgGradient="linear(to-br, blue.500, purple.600)" color="white" py={8}> <Box bgGradient="linear(to-br, blue.500, purple.600)" color="white" py={8} px={6} borderRadius="xl">
<Container maxW="container.xl">
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing={6} alignItems="stretch"> <SimpleGrid columns={{ base: 1, lg: 2 }} spacing={6} alignItems="stretch">
{/* 左侧:标题置顶,注释与图例贴底 */} {/* 左侧:标题置顶,注释与图例贴底 */}
<Flex direction="column" minH="420px" justify="space-between"> <Flex direction="column" minH="420px" justify="space-between">
@@ -366,11 +364,10 @@ export default function LimitAnalyse() {
</CardBody> </CardBody>
</Card> </Card>
</SimpleGrid> </SimpleGrid>
</Container>
</Box> </Box>
{/* 主内容区 */} {/* 主内容区 - padding 由 MainLayout 统一设置 */}
<Container maxW="container.xl" py={8}> <Box py={8}>
{/* 搜索框 */} {/* 搜索框 */}
<AdvancedSearch onSearch={handleSearch} loading={loading} /> <AdvancedSearch onSearch={handleSearch} loading={loading} />
@@ -402,7 +399,7 @@ export default function LimitAnalyse() {
{/* 高位股统计 */} {/* 高位股统计 */}
<HighPositionStocks dateStr={dateStr} /> <HighPositionStocks dateStr={dateStr} />
</Container> </Box>
{/* 弹窗 */} {/* 弹窗 */}
<SearchResultsModal <SearchResultsModal

View File

@@ -182,7 +182,7 @@ export default function ProfilePage() {
}; };
return ( return (
<Container maxW="container.xl" py={8}> <Box py={8}>
<VStack spacing={8} align="stretch"> <VStack spacing={8} align="stretch">
{/* 页面标题 */} {/* 页面标题 */}
<HStack justify="space-between"> <HStack justify="space-between">
@@ -627,6 +627,6 @@ export default function ProfilePage() {
</VStack> </VStack>
</SimpleGrid> </SimpleGrid>
</VStack> </VStack>
</Container> </Box>
); );
} }

View File

@@ -135,7 +135,6 @@ const ProfilePage = () => {
return ( return (
<Box bg={forumColors.background.main} minH="100vh" py="8"> <Box bg={forumColors.background.main} minH="100vh" py="8">
<Container maxW="container.xl">
{/* 用户信息头部 */} {/* 用户信息头部 */}
<Card <Card
bg={forumColors.background.card} bg={forumColors.background.card}
@@ -375,7 +374,6 @@ const ProfilePage = () => {
</Tabs> </Tabs>
</CardBody> </CardBody>
</Card> </Card>
</Container>
</Box> </Box>
); );
}; };

View File

@@ -2,7 +2,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { import {
Box, Box,
Container,
VStack, VStack,
HStack, HStack,
Text, Text,
@@ -219,7 +218,7 @@ export default function SettingsPage() {
}; };
return ( return (
<Container maxW="container.xl" py={8}> <Box py={8}>
<VStack spacing={8} align="stretch"> <VStack spacing={8} align="stretch">
{/* 页面标题 */} {/* 页面标题 */}
<Heading size="lg" color={headingColor}>账户设置</Heading> <Heading size="lg" color={headingColor}>账户设置</Heading>
@@ -543,6 +542,6 @@ export default function SettingsPage() {
</ModalContent> </ModalContent>
</Modal> </Modal>
</Container> </Box>
); );
} }

View File

@@ -3,7 +3,6 @@ import { useNavigate } from 'react-router-dom';
import { getApiBase } from '@utils/apiConfig'; import { getApiBase } from '@utils/apiConfig';
import { import {
Box, Box,
Container,
Heading, Heading,
Text, Text,
Input, Input,
@@ -633,6 +632,7 @@ const StockOverview = () => {
pt={{ base: 20, md: 24 }} pt={{ base: 20, md: 24 }}
pb={{ base: 16, md: 20 }} pb={{ base: 16, md: 20 }}
borderBottom={`1px solid rgba(139, 92, 246, 0.3)`} borderBottom={`1px solid rgba(139, 92, 246, 0.3)`}
borderRadius="xl"
zIndex={1} zIndex={1}
> >
{/* 背景装饰 */} {/* 背景装饰 */}
@@ -648,7 +648,7 @@ const StockOverview = () => {
filter="blur(60px)" filter="blur(60px)"
/> />
<Container maxW="container.xl" position="relative"> <Box px={6} position="relative">
<VStack spacing={8} align="center"> <VStack spacing={8} align="center">
<VStack spacing={4} textAlign="center" maxW="3xl"> <VStack spacing={4} textAlign="center" maxW="3xl">
<HStack spacing={3}> <HStack spacing={3}>
@@ -855,11 +855,11 @@ const StockOverview = () => {
</Stat> </Stat>
</SimpleGrid> </SimpleGrid>
</VStack> </VStack>
</Container> </Box>
</Box> </Box>
{/* 主内容区 */} {/* 主内容区 */}
<Container maxW="container.xl" py={10} position="relative" zIndex={1}> <Box py={10} px={6} position="relative" zIndex={1}>
{/* 日期选择器 */} {/* 日期选择器 */}
<Box mb={6}> <Box mb={6}>
<Flex align="center" gap={4} flexWrap="wrap"> <Flex align="center" gap={4} flexWrap="wrap">
@@ -1195,7 +1195,7 @@ const StockOverview = () => {
)} )}
</Card> </Card>
</Box> </Box>
</Container> </Box>
{/* 个股列表弹窗 */} {/* 个股列表弹窗 */}
<ConceptStocksModal <ConceptStocksModal

View File

@@ -6,7 +6,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Box, Box,
Container,
Heading, Heading,
Text, Text,
HStack, HStack,
@@ -157,7 +156,6 @@ const PostDetail = () => {
return ( return (
<Box minH="100vh" bg={forumColors.background.main} pt="80px" pb="20"> <Box minH="100vh" bg={forumColors.background.main} pt="80px" pb="20">
<Container maxW="container.xl">
{/* 返回按钮 */} {/* 返回按钮 */}
<Button <Button
leftIcon={<ArrowLeft size={18} />} leftIcon={<ArrowLeft size={18} />}
@@ -374,7 +372,6 @@ const PostDetail = () => {
</MotionBox> </MotionBox>
</Box> </Box>
</SimpleGrid> </SimpleGrid>
</Container>
{/* 图片预览弹窗 */} {/* 图片预览弹窗 */}
<ImagePreviewModal <ImagePreviewModal

View File

@@ -6,7 +6,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Box, Box,
Container,
Heading, Heading,
Text, Text,
Button, Button,
@@ -224,7 +223,6 @@ const PredictionTopicDetail = () => {
return ( return (
<Box minH="100vh" bg={forumColors.background.main} pt={LAYOUT_SIZE.navbarHeight} pb={{ base: "6", md: "20" }}> <Box minH="100vh" bg={forumColors.background.main} pt={LAYOUT_SIZE.navbarHeight} pb={{ base: "6", md: "20" }}>
<Container maxW="container.xl" px={{ base: "3", sm: "4", md: "6" }}>
{/* 头部:返回按钮 */} {/* 头部:返回按钮 */}
<Button <Button
variant="ghost" variant="ghost"
@@ -627,7 +625,6 @@ const PredictionTopicDetail = () => {
</MotionBox> </MotionBox>
</Box> </Box>
</SimpleGrid> </SimpleGrid>
</Container>
{/* 交易模态框 */} {/* 交易模态框 */}
<TradeModal <TradeModal

View File

@@ -6,7 +6,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Box, Box,
Container,
Heading, Heading,
Text, Text,
Button, Button,
@@ -154,7 +153,8 @@ const ValueForum = () => {
pt="80px" pt="80px"
pb="20" pb="20"
> >
<Container maxW="container.xl"> {/* padding 由 MainLayout 统一设置 */}
<Box>
{/* 顶部横幅 */} {/* 顶部横幅 */}
<MotionBox <MotionBox
initial={{ opacity: 0, y: -20 }} initial={{ opacity: 0, y: -20 }}
@@ -469,7 +469,7 @@ const ValueForum = () => {
</TabPanel> </TabPanel>
</TabPanels> </TabPanels>
</Tabs> </Tabs>
</Container> </Box>
{/* 发帖模态框 */} {/* 发帖模态框 */}
<CreatePostModal <CreatePostModal