diff --git a/src/constants/professionalTheme.js b/src/constants/professionalTheme.js new file mode 100644 index 00000000..57a2ce5e --- /dev/null +++ b/src/constants/professionalTheme.js @@ -0,0 +1,118 @@ +// src/constants/professionalTheme.js +// 专业金融风格配色主题 - 黑色、灰色、金色 + +/** + * 专业配色方案 + * 主色调:黑色系 + 灰色系 + 金色点缀 + * 适用于金融、投资类产品 + */ +export const PROFESSIONAL_COLORS = { + // 背景色 + background: { + primary: '#0A0E17', // 深黑蓝 + secondary: '#151922', // 深灰 + card: '#1A1F2E', // 卡片背景 + cardHover: '#212633', // 卡片悬浮 + overlay: 'rgba(10, 14, 23, 0.95)', // 遮罩 + }, + + // 文字颜色 + text: { + primary: '#E8E9ED', // 主文字 - 浅灰白 + secondary: '#A0A4B8', // 次要文字 - 中灰 + tertiary: '#6B7280', // 三级文字 - 深灰 + muted: '#4B5563', // 弱化文字 + }, + + // 金色系 - 高端感 + gold: { + 50: '#FFF9E6', + 100: '#FFF3CC', + 200: '#FFE799', + 300: '#FFDB66', + 400: '#FFCF33', + 500: '#FFC300', // 主金色 + 600: '#CC9C00', + 700: '#997500', + 800: '#664E00', + 900: '#332700', + }, + + // 边框颜色 + border: { + light: '#2D3748', // 浅边框 + default: '#374151', // 默认边框 + dark: '#1F2937', // 深边框 + gold: '#FFC300', // 金色边框 + }, + + // 状态颜色 + status: { + success: '#10B981', // 成功/涨 + error: '#EF4444', // 错误/跌 + warning: '#F59E0B', // 警告 + info: '#3B82F6', // 信息 + }, + + // 渐变色 + gradients: { + gold: 'linear-gradient(135deg, #FFC300 0%, #FFD54F 100%)', + darkGold: 'linear-gradient(135deg, #997500 0%, #FFC300 100%)', + blackGold: 'linear-gradient(135deg, #0A0E17 0%, #2D2416 50%, #0A0E17 100%)', + card: 'linear-gradient(135deg, #1A1F2E 0%, #212633 100%)', + }, + + // 重要性等级金色配色 + importance: { + S: { + bg: 'rgba(255, 195, 0, 0.15)', + border: '#FFC300', + text: '#FFD54F', + badge: '#FFC300', + }, + A: { + bg: 'rgba(249, 115, 22, 0.15)', + border: '#F97316', + text: '#FB923C', + badge: '#F97316', + }, + B: { + bg: 'rgba(59, 130, 246, 0.15)', + border: '#3B82F6', + text: '#60A5FA', + badge: '#3B82F6', + }, + C: { + bg: 'rgba(107, 114, 128, 0.15)', + border: '#6B7280', + text: '#9CA3AF', + badge: '#6B7280', + }, + } +}; + +/** + * 获取专业配色 + * @param {string} category - 配色类别 + * @param {string} shade - 色阶 + */ +export const getProfessionalColor = (category, shade) => { + return PROFESSIONAL_COLORS[category]?.[shade] || '#E8E9ED'; +}; + +/** + * Chakra UI 主题扩展 + */ +export const professionalThemeExtension = { + colors: { + professional: PROFESSIONAL_COLORS, + }, + styles: { + global: { + body: { + bg: PROFESSIONAL_COLORS.background.primary, + color: PROFESSIONAL_COLORS.text.primary, + }, + }, + }, +}; diff --git a/src/views/Community/components/CompactSearchBox.js b/src/views/Community/components/CompactSearchBox.js index 5292cb5a..90d36431 100644 --- a/src/views/Community/components/CompactSearchBox.js +++ b/src/views/Community/components/CompactSearchBox.js @@ -17,6 +17,7 @@ import { fetchIndustryData, selectIndustryData, selectIndustryLoading } from '.. import { stockService } from '../../../services/stockService'; import { logger } from '../../../utils/logger'; import TradingTimeFilter from './TradingTimeFilter'; +import { PROFESSIONAL_COLORS } from '../../../constants/professionalTheme'; const { Option } = AntSelect; @@ -423,10 +424,10 @@ const CompactSearchBox = ({ return (
{/* 单行紧凑布局 */} @@ -448,11 +449,13 @@ const CompactSearchBox = ({ style={{ width: 240 }} > } + prefix={} style={{ borderRadius: '8px', - border: '2px solid #e6f7ff', - boxShadow: '0 2px 8px rgba(24, 144, 255, 0.1)' + border: `1px solid ${PROFESSIONAL_COLORS.border.default}`, + boxShadow: `0 2px 8px rgba(255, 195, 0, 0.1)`, + background: PROFESSIONAL_COLORS.background.secondary, + color: PROFESSIONAL_COLORS.text.primary }} /> @@ -460,7 +463,7 @@ const CompactSearchBox = ({ {/* 时间筛选 */}
- + } + suffixIcon={} /> @@ -526,7 +529,7 @@ const CompactSearchBox = ({ width: 130, borderRadius: '8px' }} - suffixIcon={} + suffixIcon={} > diff --git a/src/views/Community/components/DynamicNewsCard.js b/src/views/Community/components/DynamicNewsCard.js index 5c3f5011..a114931a 100644 --- a/src/views/Community/components/DynamicNewsCard.js +++ b/src/views/Community/components/DynamicNewsCard.js @@ -45,6 +45,7 @@ import { } from '../../../store/slices/communityDataSlice'; import { usePagination } from './DynamicNewsCard/hooks/usePagination'; import { PAGINATION_CONFIG, DISPLAY_MODES } from './DynamicNewsCard/constants'; +import { PROFESSIONAL_COLORS } from '../../../constants/professionalTheme'; // 🔍 调试:渲染计数器 let dynamicNewsCardRenderCount = 0; @@ -74,8 +75,8 @@ const DynamicNewsCard = forwardRef(({ }, ref) => { const dispatch = useDispatch(); const toast = useToast(); - const cardBg = useColorModeValue('white', 'gray.800'); - const borderColor = useColorModeValue('gray.200', 'gray.700'); + const cardBg = PROFESSIONAL_COLORS.background.card; + const borderColor = PROFESSIONAL_COLORS.border.default; // 通知权限相关 const { browserPermission, requestBrowserPermission } = useNotification(); @@ -409,10 +410,10 @@ const [currentMode, setCurrentMode] = useState('vertical'); {/* 第一行:标题 + 通知开关 + 更新时间 */} {/* 左侧:标题 */} - + - - 实时要闻·动态追踪 + + 实时要闻·动态追踪 @@ -473,7 +474,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); {/* 更新时间 */} - + 最后更新: {lastUpdateTime?.toLocaleTimeString() || '--'} @@ -542,7 +543,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); left={0} right={0} bottom={0} - bg={useColorModeValue('rgba(255, 255, 255, 0.85)', 'rgba(26, 32, 44, 0.85)')} + bg="rgba(26, 31, 46, 0.95)" display="flex" alignItems="center" justifyContent="center" @@ -550,8 +551,8 @@ const [currentMode, setCurrentMode] = useState('vertical'); borderRadius="md" > - - + + 正在加载最新事件... diff --git a/src/views/Community/components/DynamicNewsDetail/DynamicNewsDetailPanel.js b/src/views/Community/components/DynamicNewsDetail/DynamicNewsDetailPanel.js index e76054df..84956653 100644 --- a/src/views/Community/components/DynamicNewsDetail/DynamicNewsDetailPanel.js +++ b/src/views/Community/components/DynamicNewsDetail/DynamicNewsDetailPanel.js @@ -204,22 +204,10 @@ const DynamicNewsDetailPanel = ({ event, showHeader = true }) => { // 🎯 加载事件详情(增加浏览量) loadEventDetail(); - // PRO 和 MAX 会员的相关股票默认展开,其他情况收起 - const shouldOpenStocks = canAccessStocks; - setIsStocksOpen(shouldOpenStocks); + // 相关股票默认收起 + setIsStocksOpen(false); setHasLoadedStocks(false); - // PRO 和 MAX 会员自动加载股票数据(无论是否展开) - const shouldLoadStocks = canAccessStocks; // PRO 或 MAX 都有权限 - if (shouldLoadStocks) { - console.log('%c📊 [PRO/MAX会员] 自动加载相关股票数据', 'color: #10B981; font-weight: bold;', { - eventId: event?.id, - userTier - }); - loadStocksData(); - setHasLoadedStocks(true); - } - setIsConceptsOpen(false); setIsHistoricalOpen(false); setHasLoadedHistorical(false); diff --git a/src/views/Community/components/EventCard/HorizontalDynamicNewsEventCard.js b/src/views/Community/components/EventCard/HorizontalDynamicNewsEventCard.js index 32e11cbd..f525c4e5 100644 --- a/src/views/Community/components/EventCard/HorizontalDynamicNewsEventCard.js +++ b/src/views/Community/components/EventCard/HorizontalDynamicNewsEventCard.js @@ -13,6 +13,7 @@ import { useColorModeValue, } from '@chakra-ui/react'; import { getImportanceConfig } from '../../../../constants/importanceLevels'; +import { PROFESSIONAL_COLORS } from '../../../../constants/professionalTheme'; // 导入子组件 import ImportanceStamp from './ImportanceStamp'; @@ -53,45 +54,46 @@ const HorizontalDynamicNewsEventCard = ({ }) => { const importance = getImportanceConfig(event.importance); - // 所有 useColorModeValue 必须在顶层调用 - const cardBg = useColorModeValue('white', 'gray.800'); - const cardBgAlt = useColorModeValue('gray.50', 'gray.750'); - const selectedBg = useColorModeValue('blue.50', 'blue.900'); - const selectedBorderColor = useColorModeValue('blue.500', 'blue.400'); - const linkColor = useColorModeValue('blue.600', 'blue.400'); + // 专业配色 - 黑色、灰色、金色主题 + const cardBg = PROFESSIONAL_COLORS.background.card; + const cardBgHover = PROFESSIONAL_COLORS.background.cardHover; + const selectedBg = 'rgba(255, 195, 0, 0.1)'; // 金色半透明 + const selectedBorderColor = PROFESSIONAL_COLORS.gold[500]; + const linkColor = PROFESSIONAL_COLORS.text.primary; + const borderColor = PROFESSIONAL_COLORS.border.default; /** - * 根据平均涨幅计算背景色(分级策略)- 使用毛玻璃效果 + * 根据平均涨幅计算背景色(专业配色 - 深色主题) * @param {number} avgChange - 平均涨跌幅 - * @returns {string} Chakra UI 颜色值 + * @returns {string} CSS 颜色值 */ const getChangeBasedBgColor = (avgChange) => { const numChange = Number(avgChange); - // 如果没有涨跌幅数据,使用半透明背景 + // 如果没有涨跌幅数据,使用默认卡片背景 if (avgChange == null || isNaN(numChange)) { - return useColorModeValue('rgba(255, 255, 255, 0.8)', 'rgba(26, 32, 44, 0.8)'); + return PROFESSIONAL_COLORS.background.card; } - // 根据涨跌幅分级返回半透明背景色(毛玻璃效果) + // 根据涨跌幅分级返回深色主题背景色 const absChange = Math.abs(numChange); if (numChange > 0) { - // 涨:红色系半透明 - if (absChange >= 9) return useColorModeValue('rgba(254, 202, 202, 0.9)', 'rgba(127, 29, 29, 0.9)'); - if (absChange >= 7) return useColorModeValue('rgba(254, 202, 202, 0.8)', 'rgba(153, 27, 27, 0.8)'); - if (absChange >= 5) return useColorModeValue('rgba(254, 226, 226, 0.8)', 'rgba(185, 28, 28, 0.8)'); - if (absChange >= 3) return useColorModeValue('rgba(254, 226, 226, 0.7)', 'rgba(220, 38, 38, 0.7)'); - return useColorModeValue('rgba(254, 242, 242, 0.7)', 'rgba(239, 68, 68, 0.7)'); + // 涨:深红色系 + if (absChange >= 9) return 'rgba(239, 68, 68, 0.15)'; + if (absChange >= 7) return 'rgba(239, 68, 68, 0.12)'; + if (absChange >= 5) return 'rgba(239, 68, 68, 0.1)'; + if (absChange >= 3) return 'rgba(239, 68, 68, 0.08)'; + return 'rgba(239, 68, 68, 0.05)'; } else if (numChange < 0) { - // 跌:绿色系半透明 - if (absChange >= 9) return useColorModeValue('rgba(187, 247, 208, 0.9)', 'rgba(20, 83, 45, 0.9)'); - if (absChange >= 7) return useColorModeValue('rgba(187, 247, 208, 0.8)', 'rgba(22, 101, 52, 0.8)'); - if (absChange >= 5) return useColorModeValue('rgba(209, 250, 229, 0.8)', 'rgba(21, 128, 61, 0.8)'); - if (absChange >= 3) return useColorModeValue('rgba(209, 250, 229, 0.7)', 'rgba(22, 163, 74, 0.7)'); - return useColorModeValue('rgba(240, 253, 244, 0.7)', 'rgba(34, 197, 94, 0.7)'); + // 跌:深绿色系 + if (absChange >= 9) return 'rgba(16, 185, 129, 0.15)'; + if (absChange >= 7) return 'rgba(16, 185, 129, 0.12)'; + if (absChange >= 5) return 'rgba(16, 185, 129, 0.1)'; + if (absChange >= 3) return 'rgba(16, 185, 129, 0.08)'; + return 'rgba(16, 185, 129, 0.05)'; } - return useColorModeValue('rgba(255, 255, 255, 0.8)', 'rgba(26, 32, 44, 0.8)'); + return PROFESSIONAL_COLORS.background.card; }; return ( @@ -134,11 +136,13 @@ const HorizontalDynamicNewsEventCard = ({ top: 0, left: 0, right: 0, - height: '4px', - bgGradient: `linear(to-r, ${importance.color}, ${importance.borderColor})`, + height: '3px', + background: isSelected + ? PROFESSIONAL_COLORS.gradients.gold + : `linear-gradient(90deg, ${PROFESSIONAL_COLORS.importance[importance.level]?.border || PROFESSIONAL_COLORS.gold[500]} 0%, transparent 100%)`, borderTopLeftRadius: 'xl', borderTopRightRadius: 'xl', - opacity: isSelected ? 1 : 0.7, + opacity: 0.8, }} transition="all 0.3s cubic-bezier(0.4, 0, 0.2, 1)" cursor="pointer" diff --git a/src/views/Community/components/HeroPanel.js b/src/views/Community/components/HeroPanel.js index 1c189d36..3312d18f 100644 --- a/src/views/Community/components/HeroPanel.js +++ b/src/views/Community/components/HeroPanel.js @@ -42,6 +42,7 @@ import { import { TrendingUp, Activity, Globe, Zap } from 'lucide-react'; import ReactECharts from 'echarts-for-react'; import { logger } from '../../../utils/logger'; +import { PROFESSIONAL_COLORS } from '../../../constants/professionalTheme'; /** * 获取指数行情数据(日线数据) diff --git a/src/views/Community/index.js b/src/views/Community/index.js index e304f5ab..b4d6456e 100644 --- a/src/views/Community/index.js +++ b/src/views/Community/index.js @@ -33,6 +33,7 @@ import { useCommunityEvents } from './hooks/useCommunityEvents'; import { logger } from '../../utils/logger'; import { useNotification } from '../../contexts/NotificationContext'; +import { PROFESSIONAL_COLORS } from '../../constants/professionalTheme'; // 导航栏已由 MainLayout 提供,无需在此导入 @@ -43,10 +44,10 @@ const Community = () => { // Redux状态 const { popularKeywords, hotEvents } = useSelector(state => state.communityData); - // Chakra UI hooks - const bgColor = useColorModeValue('gray.50', 'gray.900'); - const alertBgColor = useColorModeValue('blue.50', 'blue.900'); - const alertBorderColor = useColorModeValue('blue.200', 'blue.700'); + // 专业配色 - 深色主题 + const bgColor = PROFESSIONAL_COLORS.background.primary; + const alertBgColor = 'rgba(59, 130, 246, 0.1)'; + const alertBorderColor = PROFESSIONAL_COLORS.border.default; // Ref:用于首次滚动到内容区域 const containerRef = useRef(null);