refactor(icons): 迁移 components 目录图标到 lucide-react

- @chakra-ui/icons → lucide-react
- react-icons → lucide-react
- 涉及 49 个组件文件

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-25 12:23:19 +08:00
parent 5b05ae17c9
commit b2100d6f75
49 changed files with 250 additions and 282 deletions

View File

@@ -27,7 +27,8 @@ import {
Divider,
IconButton,
} from "@chakra-ui/react";
import { FaLock, FaWeixin } from "react-icons/fa";
import { Lock } from "lucide-react";
import { WechatOutlined } from '@ant-design/icons';
import { useAuth } from "../../contexts/AuthContext";
import { useAuthModal } from "../../hooks/useAuthModal";
import { useNotification } from "../../contexts/NotificationContext";
@@ -490,7 +491,7 @@ export default function AuthFormContent() {
<Text fontSize="xs" color="gray.500">其他登录方式</Text>
<IconButton
aria-label="微信登录"
icon={<Icon as={FaWeixin} w={4} h={4} />}
icon={<WechatOutlined style={{ fontSize: '16px' }} />}
size="sm"
variant="ghost"
color="#07C160"
@@ -511,7 +512,7 @@ export default function AuthFormContent() {
)}
</Box>
<Button type="submit" width="100%" size="lg" colorScheme="green" color="white" borderRadius="lg" isLoading={isLoading} loadingText={config.loadingText} fontWeight="bold"><Icon as={FaLock} mr={2} />{config.buttonText}</Button>
<Button type="submit" width="100%" size="lg" colorScheme="green" color="white" borderRadius="lg" isLoading={isLoading} loadingText={config.loadingText} fontWeight="bold"><Icon as={Lock} mr={2} />{config.buttonText}</Button>
{/* 隐私声明 */}
<Text fontSize="xs" color="gray.500" textAlign="center" mt={2}>

View File

@@ -11,8 +11,7 @@ import {
useToast,
Spinner
} from "@chakra-ui/react";
import { FaQrcode } from "react-icons/fa";
import { FiAlertCircle } from "react-icons/fi";
import { QrCode, AlertCircle } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { authService, WECHAT_STATUS, STATUS_MESSAGES } from "../../services/authService";
import { useAuthModal } from "../../hooks/useAuthModal";
@@ -508,7 +507,7 @@ export default function WechatRegister() {
) : (
/* 未获取:显示占位符 */
<Center width="100%" height="100%" flexDirection="column">
<Icon as={FaQrcode} w={16} h={16} color="gray.300" mb={4} />
<Icon as={QrCode} w={16} h={16} color="gray.300" mb={4} />
<Button
size="sm"
colorScheme="green"
@@ -535,7 +534,7 @@ export default function WechatRegister() {
backdropFilter="blur(4px)"
>
<VStack spacing={2}>
<Icon as={FiAlertCircle} w={8} h={8} color="white" />
<Icon as={AlertCircle} w={8} h={8} color="white" />
<Text color="white" fontSize="sm">二维码已过期</Text>
<Button
size="xs"

View File

@@ -21,8 +21,7 @@ import {
MenuItem,
Button,
} from '@chakra-ui/react';
import { FiSend, FiRefreshCw, FiSettings, FiDownload } from 'react-icons/fi';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { Send, RefreshCw, Settings, Download } from 'lucide-react';
import MessageBubble from './MessageBubble';
import { mcpService } from '../../services/mcpService';
import { logger } from '../../utils/logger';
@@ -252,14 +251,14 @@ export const ChatInterface = () => {
</HStack>
<HStack>
<IconButton
icon={<FiRefreshCw />}
icon={<RefreshCw />}
size="sm"
variant="ghost"
aria-label="清空对话"
onClick={handleClearChat}
/>
<IconButton
icon={<FiDownload />}
icon={<Download />}
size="sm"
variant="ghost"
aria-label="导出对话"
@@ -268,7 +267,7 @@ export const ChatInterface = () => {
<Menu>
<MenuButton
as={IconButton}
icon={<FiSettings />}
icon={<Settings />}
size="sm"
variant="ghost"
aria-label="设置"
@@ -360,7 +359,7 @@ export const ChatInterface = () => {
disabled={isLoading}
/>
<IconButton
icon={<FiSend />}
icon={<Send />}
colorScheme="blue"
aria-label="发送"
onClick={handleSendMessage}

View File

@@ -21,7 +21,7 @@ import {
Progress,
Fade,
} from '@chakra-ui/react';
import { FiSend, FiRefreshCw, FiDownload, FiCpu, FiUser, FiZap } from 'react-icons/fi';
import { Send, RefreshCw, Download, Cpu, User, Zap } from 'lucide-react';
import { PlanCard } from './PlanCard';
import { StepResultCard } from './StepResultCard';
import { mcpService } from '../../services/mcpService';
@@ -387,14 +387,14 @@ export const ChatInterfaceV2 = () => {
<Avatar
size="md"
bg="blue.500"
icon={<FiCpu fontSize="1.5rem" />}
icon={<Cpu fontSize="1.5rem" />}
/>
<VStack align="start" spacing={0}>
<Heading size="md">AI投资研究助手</Heading>
<HStack>
<Badge colorScheme="green" fontSize="xs">
<HStack spacing={1}>
<FiZap size={10} />
<Zap size={10} />
<span>智能分析</span>
</HStack>
</Badge>
@@ -407,14 +407,14 @@ export const ChatInterfaceV2 = () => {
<HStack>
<IconButton
icon={<FiRefreshCw />}
icon={<RefreshCw />}
size="sm"
variant="ghost"
aria-label="清空对话"
onClick={handleClearChat}
/>
<IconButton
icon={<FiDownload />}
icon={<Download />}
size="sm"
variant="ghost"
aria-label="导出对话"
@@ -507,7 +507,7 @@ export const ChatInterfaceV2 = () => {
size="lg"
/>
<IconButton
icon={isProcessing ? <Spinner size="sm" /> : <FiSend />}
icon={isProcessing ? <Spinner size="sm" /> : <Send />}
colorScheme="blue"
aria-label="发送"
onClick={handleSendMessage}
@@ -546,7 +546,7 @@ const MessageRenderer = ({ message }) => {
{message.content}
</Text>
</Box>
<Avatar size="sm" bg="blue.500" icon={<FiUser fontSize="1rem" />} />
<Avatar size="sm" bg="blue.500" icon={<User fontSize="1rem" />} />
</HStack>
</Flex>
);
@@ -555,7 +555,7 @@ const MessageRenderer = ({ message }) => {
return (
<Flex justify="flex-start">
<HStack align="flex-start" maxW="75%">
<Avatar size="sm" bg="purple.500" icon={<FiCpu fontSize="1rem" />} />
<Avatar size="sm" bg="purple.500" icon={<Cpu fontSize="1rem" />} />
<Box
bg={agentBubbleBg}
px={4}
@@ -580,7 +580,7 @@ const MessageRenderer = ({ message }) => {
return (
<Flex justify="flex-start">
<HStack align="flex-start" maxW="85%">
<Avatar size="sm" bg="blue.500" icon={<FiCpu fontSize="1rem" />} />
<Avatar size="sm" bg="blue.500" icon={<Cpu fontSize="1rem" />} />
<VStack align="stretch" flex={1}>
<PlanCard plan={message.plan} stepResults={[]} />
</VStack>
@@ -592,7 +592,7 @@ const MessageRenderer = ({ message }) => {
return (
<Flex justify="flex-start">
<HStack align="flex-start" maxW="85%">
<Avatar size="sm" bg="orange.500" icon={<FiCpu fontSize="1rem" />} />
<Avatar size="sm" bg="orange.500" icon={<Cpu fontSize="1rem" />} />
<VStack align="stretch" flex={1} spacing={3}>
<PlanCard plan={message.plan} stepResults={message.stepResults} />
{message.stepResults?.map((result, idx) => (
@@ -607,7 +607,7 @@ const MessageRenderer = ({ message }) => {
return (
<Flex justify="flex-start">
<HStack align="flex-start" maxW="85%">
<Avatar size="sm" bg="green.500" icon={<FiCpu fontSize="1rem" />} />
<Avatar size="sm" bg="green.500" icon={<Cpu fontSize="1rem" />} />
<VStack align="stretch" flex={1} spacing={3}>
{/* 最终总结 */}
<Box
@@ -657,7 +657,7 @@ const MessageRenderer = ({ message }) => {
return (
<Flex justify="flex-start">
<HStack align="flex-start" maxW="75%">
<Avatar size="sm" bg="red.500" icon={<FiCpu fontSize="1rem" />} />
<Avatar size="sm" bg="red.500" icon={<Cpu fontSize="1rem" />} />
<Box
bg="red.50"
color="red.700"

View File

@@ -14,7 +14,7 @@ import {
Badge,
VStack,
} from '@chakra-ui/react';
import { FiCopy, FiThumbsUp, FiThumbsDown } from 'react-icons/fi';
import { Copy, ThumbsUp, ThumbsDown } from 'lucide-react';
import ReactMarkdown from 'react-markdown';
/**
@@ -105,21 +105,21 @@ export const MessageBubble = ({ message, isUser, onCopy, onFeedback }) => {
{!isUser && (
<HStack mt={2} spacing={2}>
<IconButton
icon={<FiCopy />}
icon={<Copy />}
size="xs"
variant="ghost"
aria-label="复制"
onClick={handleCopy}
/>
<IconButton
icon={<FiThumbsUp />}
icon={<ThumbsUp />}
size="xs"
variant="ghost"
aria-label="赞"
onClick={() => onFeedback?.('positive')}
/>
<IconButton
icon={<FiThumbsDown />}
icon={<ThumbsDown />}
size="xs"
variant="ghost"
aria-label="踩"

View File

@@ -17,7 +17,7 @@ import {
useColorModeValue,
Divider,
} from '@chakra-ui/react';
import { FiTarget, FiCheckCircle, FiXCircle, FiClock, FiTool } from 'react-icons/fi';
import { Target, CheckCircle, XCircle, Clock, Wrench } from 'lucide-react';
/**
* 执行计划卡片组件
@@ -38,11 +38,11 @@ export const PlanCard = ({ plan, stepResults }) => {
const getStepIcon = (status) => {
switch (status) {
case 'success':
return FiCheckCircle;
return CheckCircle;
case 'failed':
return FiXCircle;
return XCircle;
default:
return FiClock;
return Clock;
}
};
@@ -70,7 +70,7 @@ export const PlanCard = ({ plan, stepResults }) => {
<VStack align="stretch" spacing={3}>
{/* 目标 */}
<HStack>
<Icon as={FiTarget} color="blue.500" boxSize={5} />
<Icon as={Target} color="blue.500" boxSize={5} />
<Text fontWeight="bold" fontSize="md">执行目标</Text>
</HStack>
<Text fontSize="sm" color={useColorModeValue('gray.600', '#9BA1A6')} pl={7}>

View File

@@ -15,7 +15,7 @@ import {
useColorModeValue,
Divider,
} from '@chakra-ui/react';
import { FiChevronDown, FiChevronUp, FiCheckCircle, FiXCircle, FiClock, FiDatabase } from 'react-icons/fi';
import { ChevronDown, ChevronUp, CheckCircle, XCircle, Clock, Database } from 'lucide-react';
/**
* 步骤结果卡片组件
@@ -31,11 +31,11 @@ export const StepResultCard = ({ stepResult }) => {
const getStatusIcon = () => {
switch (stepResult.status) {
case 'success':
return FiCheckCircle;
return CheckCircle;
case 'failed':
return FiXCircle;
return XCircle;
default:
return FiClock;
return Clock;
}
};
@@ -101,7 +101,7 @@ export const StepResultCard = ({ stepResult }) => {
</HStack>
<IconButton
icon={<Icon as={isExpanded ? FiChevronUp : FiChevronDown} />}
icon={<Icon as={isExpanded ? ChevronUp : ChevronDown} />}
size="sm"
variant="ghost"
aria-label={isExpanded ? "收起" : "展开"}
@@ -117,7 +117,7 @@ export const StepResultCard = ({ stepResult }) => {
{stepResult.arguments && Object.keys(stepResult.arguments).length > 0 && (
<VStack align="stretch" spacing={2} mb={3}>
<HStack>
<Icon as={FiDatabase} color="blue.500" boxSize={4} />
<Icon as={Database} color="blue.500" boxSize={4} />
<Text fontSize="xs" fontWeight="bold">请求参数:</Text>
</HStack>
<Code

View File

@@ -22,7 +22,7 @@ import {
useColorModeValue,
useBreakpointValue,
} from '@chakra-ui/react';
import { FaTable } from 'react-icons/fa';
import { Table2 } from 'lucide-react';
import marketService from '@services/marketService';
import { logger } from '@utils/logger';
@@ -161,7 +161,7 @@ const ConceptStocksModal: React.FC<ConceptStocksModalProps> = ({
<ModalContent bg={cardBg} maxH={isMobile ? '70vh' : undefined}>
<ModalHeader bg="purple.500" color="white" borderTopRadius="md">
<HStack>
<Icon as={FaTable} />
<Icon as={Table2} />
<Text>{concept?.concept_name} - </Text>
</HStack>
</ModalHeader>

View File

@@ -37,7 +37,7 @@ import GitHubButton from "react-github-btn";
import { HSeparator } from "components/Separator/Separator";
import PropTypes from "prop-types";
import React, { useState } from "react";
import { FaTwitter, FaFacebook } from "react-icons/fa";
import { Twitter, Facebook } from "lucide-react";
export default function Configurator(props) {
const {
@@ -172,7 +172,7 @@ export default function Configurator(props) {
href='https://twitter.com/intent/tweet?url=https://www.creative-tim.com/product/argon-dashboard-chakra-pro/&text=Check%20Argon%20Dashboard%20Chakra%20PRO%20made%20by%20@simmmple_web%20and%20@CreativeTim'>
<Button
colorScheme='twitter'
leftIcon={<FaTwitter />}
leftIcon={<Twitter size={16} />}
me='10px'>
<Text>Tweet</Text>
</Button>
@@ -180,7 +180,7 @@ export default function Configurator(props) {
<Link
isExternal='true'
href='https://www.facebook.com/sharer/sharer.php?u=https://www.creative-tim.com/product/argon-dashboard-chakra-pro/'>
<Button colorScheme='facebook' leftIcon={<FaFacebook />}>
<Button colorScheme='facebook' leftIcon={<Facebook size={16} />}>
<Text>Share</Text>
</Button>
</Link>

View File

@@ -17,7 +17,7 @@ import {
useColorModeValue,
Slide,
} from '@chakra-ui/react';
import { MdRefresh } from 'react-icons/md';
import { RefreshCw } from 'lucide-react';
/**
* 连接状态枚举
@@ -119,7 +119,7 @@ const ConnectionStatusBar = ({
<Button
size="sm"
colorScheme="red"
leftIcon={<MdRefresh />}
leftIcon={<RefreshCw size={16} />}
onClick={onRetry}
mr={2}
flexShrink={0}

View File

@@ -14,7 +14,7 @@ import {
Collapse,
useDisclosure,
} from '@chakra-ui/react';
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
import { ChevronDown, ChevronUp } from 'lucide-react';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { trackEventAsync } from '@/lib/posthog';
@@ -362,7 +362,7 @@ const ErrorPage: React.FC<ErrorPageProps> = ({
variant="ghost"
size="sm"
color="gray.500"
rightIcon={isTechOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
rightIcon={isTechOpen ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
onClick={onTechToggle}
_hover={{ bg: 'transparent', color: 'gray.400' }}
>

View File

@@ -23,7 +23,7 @@ import {
Button,
useDisclosure,
} from '@chakra-ui/react';
import { DeleteIcon } from '@chakra-ui/icons';
import { Trash2 } from 'lucide-react';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
@@ -117,7 +117,7 @@ const CommentItem = ({ comment, currentUserId, onDelete }) => {
{canDelete && (
<Tooltip label="删除评论" placement="top">
<IconButton
icon={<DeleteIcon />}
icon={<Trash2 size={14} />}
size="xs"
variant="ghost"
colorScheme="red"

View File

@@ -13,7 +13,7 @@ import {
Box,
useColorModeValue,
} from '@chakra-ui/react';
import { ChatIcon } from '@chakra-ui/icons';
import { MessageCircle } from 'lucide-react';
import CommentItem from './CommentItem';
const CommentList = ({ comments, loading, currentUserId, onDelete }) => {
@@ -44,7 +44,7 @@ const CommentList = ({ comments, loading, currentUserId, onDelete }) => {
bg={emptyBgColor}
borderRadius="full"
>
<ChatIcon boxSize={6} color={emptyTextColor} />
<MessageCircle size={24} color="var(--chakra-colors-gray-500)" style={{ display: 'block' }} />
</Box>
<Text fontSize="sm" color={emptyTextColor}>
还没有评论快来发表第一条吧~

View File

@@ -11,8 +11,8 @@ import {
IconButton,
Button,
} from '@chakra-ui/react';
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
import { PROFESSIONAL_COLORS } from '@constants/professionalTheme';
import { ChevronDown, ChevronUp } from 'lucide-react';
/**
* 可折叠模块标题组件
@@ -57,7 +57,7 @@ const CollapsibleHeader = ({
return null; // 简单模式不显示图标
}
// 详细模式:展开显示向上箭头,收起显示向下箭头
return isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />;
return isOpen ? <ChevronUp size={16} /> : <ChevronDown size={16} />;
};
return (
@@ -95,7 +95,7 @@ const CollapsibleHeader = ({
{/* 展开/收起图标showModeToggle 时显示在标题旁边) */}
{showModeToggle && (
<IconButton
icon={isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
icon={isOpen ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
size="xs"
variant="ghost"
aria-label={isOpen ? '收起' : '展开'}
@@ -125,7 +125,7 @@ const CollapsibleHeader = ({
{/* showModeToggle=false 时显示原有的 IconButton */}
{!showModeToggle && (
<IconButton
icon={isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
icon={isOpen ? <ChevronUp size={20} /> : <ChevronDown size={20} />}
size="sm"
variant="ghost"
aria-label={isOpen ? '收起' : '展开'}

View File

@@ -9,8 +9,8 @@ import {
Icon,
useColorModeValue,
} from '@chakra-ui/react';
import { ViewIcon } from '@chakra-ui/icons';
import { EventFollowButton } from '@views/Community/components/EventCard/atoms';
import { Eye } from 'lucide-react';
/**
* 精简信息栏组件
@@ -79,7 +79,7 @@ const CompactMetaBar = ({ event, importance, isFollowing, followerCount, onToggl
borderRadius="md"
boxShadow="sm"
>
<ViewIcon color="gray.400" boxSize={4} />
<Eye color="gray.400" size={16} />
<Text fontSize="sm" color={viewCountTextColor} whiteSpace="nowrap">
{(event.view_count || 0).toLocaleString()}
</Text>

View File

@@ -12,8 +12,8 @@ import {
Icon,
useColorModeValue,
} from '@chakra-ui/react';
import { ViewIcon } from '@chakra-ui/icons';
import dayjs from 'dayjs';
import { Eye } from 'lucide-react';
import StockChangeIndicators from '../StockChangeIndicators';
import { EventFollowButton } from '@views/Community/components/EventCard/atoms';
@@ -90,7 +90,7 @@ const EventHeaderInfo = ({ event, importance, isFollowing, followerCount, onTogg
<Flex align="left" mb={3} gap={4}>
{/* 浏览数 */}
<HStack spacing={1}>
<ViewIcon color="gray.400" boxSize={4} />
<Eye color="gray.400" size={16} />
<Text fontSize="sm" color="gray.400" whiteSpace="nowrap">
{(event.view_count || 0).toLocaleString()}次浏览
</Text>

View File

@@ -7,7 +7,7 @@ import {
Text,
useColorModeValue,
} from '@chakra-ui/react';
import { FaCalendarAlt } from 'react-icons/fa';
import { Calendar } from 'lucide-react';
import dayjs from 'dayjs';
/**
@@ -25,7 +25,7 @@ const TradingDateInfo = ({ effectiveTradingDate, eventTime }) => {
return (
<HStack spacing={2}>
<FaCalendarAlt color="gray" size={12} />
<Calendar color="gray" size={12} />
<Text fontSize="xs" color={stockCountColor}>
涨跌幅数据{effectiveTradingDate}
{eventTime && effectiveTradingDate !== dayjs(eventTime).format('YYYY-MM-DD') && (

View File

@@ -16,8 +16,8 @@ import {
Badge,
useColorModeValue,
} from '@chakra-ui/react';
import { StarIcon } from '@chakra-ui/icons';
import { Tag } from 'antd';
import { Star } from 'lucide-react';
import { RobotOutlined } from '@ant-design/icons';
import { selectIsMobile } from '@store/slices/deviceSlice';
import { MiniTimelineChart } from '@components/Charts/Stock';
@@ -197,7 +197,7 @@ const StockListItem = ({
size="xs"
variant={isInWatchlist ? 'solid' : 'outline'}
colorScheme={isInWatchlist ? 'yellow' : 'gray'}
icon={<StarIcon color={isInWatchlist ? undefined : 'gray.400'} />}
icon={<Star size={14} color={isInWatchlist ? undefined : 'gray.400'} fill={isInWatchlist ? 'currentColor' : 'none'} />}
onClick={handleWatchlistClick}
aria-label={isInWatchlist ? '已关注' : '加自选'}
borderRadius="full"

View File

@@ -18,7 +18,7 @@ import {
useDisclosure,
Icon,
} from '@chakra-ui/react';
import { FiSmartphone } from 'react-icons/fi';
import { Smartphone } from 'lucide-react';
// 默认小程序码图片(可替换为实际的小程序码)
// 注意:需要在微信公众平台生成小程序码图片
@@ -52,7 +52,7 @@ const QRCodeDisplay = ({
<Button
onClick={onOpen}
colorScheme="green"
leftIcon={<Icon as={FiSmartphone} />}
leftIcon={<Icon as={Smartphone} />}
{...buttonProps}
>
{children || '打开小程序'}

View File

@@ -19,7 +19,7 @@ import {
useToast,
Icon,
} from '@chakra-ui/react';
import { FiExternalLink, FiCopy, FiCheck } from 'react-icons/fi';
import { ExternalLink, Copy, Check } from 'lucide-react';
import { isIOSDevice } from './hooks/useWechatEnvironment';
// 小程序 AppID
@@ -145,7 +145,7 @@ const UrlSchemeLauncher = ({
isLoading={loading}
loadingText="正在跳转..."
colorScheme="green"
leftIcon={<Icon as={FiExternalLink} />}
leftIcon={<Icon as={ExternalLink} />}
style={buttonStyle}
{...buttonProps}
>
@@ -186,7 +186,7 @@ const UrlSchemeLauncher = ({
colorScheme="green"
width="100%"
onClick={handleRetry}
leftIcon={<Icon as={FiExternalLink} />}
leftIcon={<Icon as={ExternalLink} />}
>
打开微信
</Button>
@@ -194,7 +194,7 @@ const UrlSchemeLauncher = ({
variant="outline"
width="100%"
onClick={handleCopy}
leftIcon={<Icon as={copied ? FiCheck : FiCopy} />}
leftIcon={<Icon as={copied ? Check : Copy} />}
>
{copied ? '已复制' : '复制链接'}
</Button>

View File

@@ -48,8 +48,7 @@ import {
import { SidebarResponsive } from 'components/Sidebar/Sidebar';
import PropTypes from 'prop-types';
import { Fragment } from 'react';
import { AiFillStar } from 'react-icons/ai';
import { GoChevronDown, GoChevronRight } from 'react-icons/go';
import { Star, ChevronDown, ChevronRight } from 'lucide-react';
import { NavLink } from 'react-router-dom';
import { SidebarContext } from 'contexts/SidebarContext';
import routes from 'routes.js';
@@ -313,7 +312,7 @@ export default function AuthNavbar(props) {
{link.name}
</Text>
<Icon
as={GoChevronRight}
as={ChevronRight}
color={mainText}
w='14px'
h='14px'
@@ -419,7 +418,7 @@ export default function AuthNavbar(props) {
Pages
</Text>
<Icon
as={GoChevronDown}
as={ChevronDown}
color={mainText}
w='14px'
h='14px'
@@ -457,7 +456,7 @@ export default function AuthNavbar(props) {
Authentications
</Text>
<Icon
as={GoChevronDown}
as={ChevronDown}
color={mainText}
w='14px'
h='14px'
@@ -493,7 +492,7 @@ export default function AuthNavbar(props) {
w='50px'
mb='12px'
>
<Icon as={AiFillStar} w='25px' h='25px' color='blue.500' />
<Icon as={Star} w='25px' h='25px' color='blue.500' fill='currentColor' />
</IconBox>
<Text
fontSize='xl'
@@ -527,7 +526,7 @@ export default function AuthNavbar(props) {
Application
</Text>
<Icon
as={GoChevronDown}
as={ChevronDown}
color={mainText}
w='14px'
h='14px'
@@ -564,7 +563,7 @@ export default function AuthNavbar(props) {
Ecommerce
</Text>
<Icon
as={GoChevronDown}
as={ChevronDown}
color={mainText}
w='14px'
h='14px'

View File

@@ -21,9 +21,7 @@ import {
useColorModeValue,
useToast,
} from '@chakra-ui/react';
import { ChevronDownIcon, HamburgerIcon, SunIcon, MoonIcon } from '@chakra-ui/icons';
import { FiStar, FiCalendar, FiUser, FiSettings, FiHome, FiLogOut } from 'react-icons/fi';
import { FaCrown } from 'react-icons/fa';
import { ChevronDown, Menu as MenuIcon, Sun, Moon, Star, Calendar, User, Settings, Home, LogOut, Crown } from 'lucide-react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import { useAuthModal } from '../../hooks/useAuthModal';

View File

@@ -20,8 +20,8 @@ import {
ListItem,
Flex,
} from "@chakra-ui/react";
import { SearchIcon, CloseIcon } from "@chakra-ui/icons";
import { useStockSearch } from "@hooks/useStockSearch";
import { Search, X } from "lucide-react";
export function SearchBar(props) {
const { variant, children, ...rest } = props;
@@ -80,7 +80,7 @@ export function SearchBar(props) {
<Box ref={containerRef} position="relative" {...rest}>
<InputGroup borderRadius="8px" w="220px">
<InputLeftElement pointerEvents="none">
<SearchIcon color={searchIconColor} w="15px" h="15px" />
<Search color={searchIconColor} size={15} />
</InputLeftElement>
<Input
variant="search"
@@ -103,7 +103,7 @@ export function SearchBar(props) {
<IconButton
size="xs"
variant="ghost"
icon={<CloseIcon w="10px" h="10px" />}
icon={<X size={10} />}
onClick={clearSearch}
aria-label="清除搜索"
_hover={{ bg: "transparent" }}

View File

@@ -9,7 +9,7 @@ import {
ModalBody,
ModalCloseButton
} from '@chakra-ui/react';
import { FiCalendar } from 'react-icons/fi';
import { Calendar } from 'lucide-react';
import InvestmentCalendar from '@components/InvestmentCalendar';
/**
@@ -35,7 +35,7 @@ const CalendarButton = memo(() => {
colorScheme="blue"
variant="solid"
borderRadius="full"
leftIcon={<FiCalendar />}
leftIcon={<Calendar size={16} />}
onClick={() => setIsModalOpen(true)}
>
投资日历

View File

@@ -17,8 +17,7 @@ import {
Spinner,
useColorModeValue
} from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { FiCalendar } from 'react-icons/fi';
import { Calendar, ChevronDown } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { useFollowingEvents } from '../../../../hooks/useFollowingEvents';
import { getEventDetailUrl } from '@/utils/idEncoder';
@@ -67,8 +66,8 @@ const FollowingEventsMenu = memo(() => {
colorScheme="purple"
variant="solid"
borderRadius="full"
rightIcon={<ChevronDownIcon />}
leftIcon={<FiCalendar />}
rightIcon={<ChevronDown size={16} />}
leftIcon={<Calendar size={16} />}
>
自选事件
{followingEvents && followingEvents.length > 0 && (

View File

@@ -17,8 +17,7 @@ import {
Spinner,
useColorModeValue
} from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { FiStar } from 'react-icons/fi';
import { Star, ChevronDown } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { useWatchlist } from '../../../../hooks/useWatchlist';
import FavoriteButton from '@/components/FavoriteButton';
@@ -66,8 +65,8 @@ const WatchlistMenu = memo(() => {
colorScheme="teal"
variant="solid"
borderRadius="full"
rightIcon={<ChevronDownIcon />}
leftIcon={<FiStar />}
rightIcon={<ChevronDown size={16} />}
leftIcon={<Star size={16} />}
>
自选股
{watchlistQuotes && watchlistQuotes.length > 0 && (

View File

@@ -3,7 +3,7 @@
import React, { memo } from 'react';
import { HStack, IconButton, Box } from '@chakra-ui/react';
import { HamburgerIcon } from '@chakra-ui/icons';
import { Menu } from 'lucide-react';
// import ThemeToggleButton from '../ThemeToggleButton'; // ❌ 已删除 - 不再支持深色模式切换
import LoginButton from '../LoginButton';
import CalendarButton from '../CalendarButton';
@@ -84,7 +84,7 @@ const NavbarActions = memo(({
) : (
// 移动端:汉堡菜单(打开抽屉)
<IconButton
icon={<HamburgerIcon />}
icon={<Menu size={20} />}
variant="ghost"
onClick={onMenuOpen}
aria-label="打开菜单"

View File

@@ -17,7 +17,7 @@ import {
Box,
useColorModeValue
} from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { ChevronDown } from 'lucide-react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useNavigationEvents } from '../../../../hooks/useNavigationEvents';
import { useDelayedMenu } from '../../../../hooks/useDelayedMenu';
@@ -60,7 +60,7 @@ const DesktopNav = memo(({ isAuthenticated, user }) => {
<MenuButton
as={Button}
variant="ghost"
rightIcon={<ChevronDownIcon color={isActive(['/community', '/concepts']) ? 'white' : 'inherit'} />}
rightIcon={<ChevronDown size={16} color={isActive(['/community', '/concepts']) ? 'white' : 'currentColor'} />}
bg={isActive(['/community', '/concepts']) ? 'blue.600' : 'transparent'}
color={isActive(['/community', '/concepts']) ? 'white' : 'inherit'}
fontWeight={isActive(['/community', '/concepts']) ? 'bold' : 'normal'}
@@ -127,7 +127,7 @@ const DesktopNav = memo(({ isAuthenticated, user }) => {
<MenuButton
as={Button}
variant="ghost"
rightIcon={<ChevronDownIcon color={isActive(['/limit-analyse', '/stocks', '/trading-simulation']) ? 'white' : 'inherit'} />}
rightIcon={<ChevronDown size={16} color={isActive(['/limit-analyse', '/stocks', '/trading-simulation']) ? 'white' : 'currentColor'} />}
bg={isActive(['/limit-analyse', '/stocks', '/trading-simulation']) ? 'blue.600' : 'transparent'}
color={isActive(['/limit-analyse', '/stocks', '/trading-simulation']) ? 'white' : 'inherit'}
fontWeight={isActive(['/limit-analyse', '/stocks', '/trading-simulation']) ? 'bold' : 'normal'}
@@ -199,7 +199,7 @@ const DesktopNav = memo(({ isAuthenticated, user }) => {
<MenuButton
as={Button}
variant="ghost"
rightIcon={<ChevronDownIcon color={isActive(['/agent-chat', '/value-forum']) ? 'white' : 'inherit'} />}
rightIcon={<ChevronDown size={16} color={isActive(['/agent-chat', '/value-forum']) ? 'white' : 'currentColor'} />}
bg={isActive(['/agent-chat', '/value-forum']) ? 'blue.600' : 'transparent'}
color={isActive(['/agent-chat', '/value-forum']) ? 'white' : 'inherit'}
fontWeight={isActive(['/agent-chat', '/value-forum']) ? 'bold' : 'normal'}
@@ -274,7 +274,7 @@ const DesktopNav = memo(({ isAuthenticated, user }) => {
<MenuButton
as={Button}
variant="ghost"
rightIcon={<ChevronDownIcon />}
rightIcon={<ChevronDown size={16} />}
onMouseEnter={contactUsMenu.handleMouseEnter}
onMouseLeave={contactUsMenu.handleMouseLeave}
onClick={contactUsMenu.handleClick}

View File

@@ -14,7 +14,7 @@ import {
HStack,
Badge
} from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { ChevronDown } from 'lucide-react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useDelayedMenu } from '../../../../hooks/useDelayedMenu';
@@ -45,7 +45,7 @@ const MoreMenu = memo(({ isAuthenticated, user }) => {
<MenuButton
as={Button}
variant="ghost"
rightIcon={<ChevronDownIcon />}
rightIcon={<ChevronDown size={16} />}
fontWeight="medium"
onMouseEnter={moreMenu.handleMouseEnter}
onMouseLeave={moreMenu.handleMouseLeave}

View File

@@ -15,9 +15,7 @@ import {
useColorModeValue,
useDisclosure
} from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { FiHome, FiUser, FiSettings, FiLogOut } from 'react-icons/fi';
import { FaCrown } from 'react-icons/fa';
import { ChevronDown, Home, User, Settings, LogOut, Crown } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
/**
@@ -50,7 +48,7 @@ const PersonalCenterMenu = memo(({ user, handleLogout }) => {
as={Button}
size="sm"
variant="ghost"
rightIcon={<ChevronDownIcon />}
rightIcon={<ChevronDown size={16} />}
_hover={{ bg: hoverBg }}
onMouseEnter={onOpen}
onMouseLeave={onClose}
@@ -70,7 +68,7 @@ const PersonalCenterMenu = memo(({ user, handleLogout }) => {
</Box>
{/* 前往个人中心 */}
<MenuItem icon={<FiHome />} onClick={() => {
<MenuItem icon={<Home size={16} />} onClick={() => {
onClose(); // 先关闭菜单
navigate('/home/center');
}}>
@@ -80,13 +78,13 @@ const PersonalCenterMenu = memo(({ user, handleLogout }) => {
<MenuDivider />
{/* 账户管理组 */}
<MenuItem icon={<FiUser />} onClick={() => {
<MenuItem icon={<User size={16} />} onClick={() => {
onClose(); // 先关闭菜单
navigate('/home/profile');
}}>
个人资料
</MenuItem>
<MenuItem icon={<FiSettings />} onClick={() => {
<MenuItem icon={<Settings size={16} />} onClick={() => {
onClose(); // 先关闭菜单
navigate('/home/settings');
}}>
@@ -96,7 +94,7 @@ const PersonalCenterMenu = memo(({ user, handleLogout }) => {
<MenuDivider />
{/* 功能入口组 */}
<MenuItem icon={<FaCrown />} onClick={() => {
<MenuItem icon={<Crown size={16} />} onClick={() => {
onClose(); // 先关闭菜单
navigate('/home/pages/account/subscription');
}}>
@@ -106,7 +104,7 @@ const PersonalCenterMenu = memo(({ user, handleLogout }) => {
<MenuDivider />
{/* 退出 */}
<MenuItem icon={<FiLogOut />} onClick={handleLogout} color="red.500">
<MenuItem icon={<LogOut size={16} />} onClick={handleLogout} color="red.500">
退出登录
</MenuItem>
</MenuList>

View File

@@ -12,7 +12,7 @@ import {
IconButton,
Icon
} from '@chakra-ui/react';
import { FiStar } from 'react-icons/fi';
import { Star } from 'lucide-react';
/**
* 资料完整性提醒横幅组件
@@ -45,7 +45,7 @@ const ProfileCompletenessAlert = memo(({
<Container maxW="container.xl">
<HStack justify="space-between" align="center" spacing={{ base: 2, md: 4 }}>
<HStack spacing={{ base: 2, md: 3 }} flex={1} minW={0}>
<Icon as={FiStar} display={{ base: 'none', sm: 'block' }} />
<Icon as={Star} boxSize={5} display={{ base: 'none', sm: 'block' }} />
<VStack spacing={0} align="start" flex={1} minW={0}>
<Text fontSize={{ base: 'xs', md: 'sm' }} fontWeight="bold" noOfLines={1}>
完善资料享受更好服务

View File

@@ -14,8 +14,7 @@ import {
Flex,
useColorModeValue
} from '@chakra-ui/react';
import { FiStar, FiCalendar, FiUser, FiSettings, FiHome, FiLogOut } from 'react-icons/fi';
import { FaCrown } from 'react-icons/fa';
import { Star, Calendar, User, Settings, Home, LogOut, Crown } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import UserAvatar from './UserAvatar';
import { useSubscription } from '../../../../hooks/useSubscription';
@@ -84,7 +83,7 @@ const TabletUserMenu = memo(({
</Box>
{/* 订阅管理 - 移动端导航到订阅页面 */}
<MenuItem icon={<FaCrown />} onClick={() => navigate('/home/pages/account/subscription')}>
<MenuItem icon={<Crown size={16} />} onClick={() => navigate('/home/pages/account/subscription')}>
<Flex justify="space-between" align="center" w="100%">
<Text>订阅管理</Text>
<Badge colorScheme={getSubscriptionBadgeColor()}>
@@ -96,12 +95,12 @@ const TabletUserMenu = memo(({
<MenuDivider />
{/* 投资日历 */}
<MenuItem icon={<FiCalendar />} onClick={() => navigate('/community')}>
<MenuItem icon={<Calendar size={16} />} onClick={() => navigate('/community')}>
<Text>投资日历</Text>
</MenuItem>
{/* 自选股 */}
<MenuItem icon={<FiStar />} onClick={() => navigate('/home/center')}>
<MenuItem icon={<Star size={16} />} onClick={() => navigate('/home/center')}>
<Flex justify="space-between" align="center" w="100%">
<Text>我的自选股</Text>
{watchlistQuotes && watchlistQuotes.length > 0 && (
@@ -111,7 +110,7 @@ const TabletUserMenu = memo(({
</MenuItem>
{/* 自选事件 */}
<MenuItem icon={<FiCalendar />} onClick={() => navigate('/home/center')}>
<MenuItem icon={<Calendar size={16} />} onClick={() => navigate('/home/center')}>
<Flex justify="space-between" align="center" w="100%">
<Text>我的自选事件</Text>
{followingEvents && followingEvents.length > 0 && (
@@ -123,20 +122,20 @@ const TabletUserMenu = memo(({
<MenuDivider />
{/* 个人中心 */}
<MenuItem icon={<FiHome />} onClick={() => navigate('/home/center')}>
<MenuItem icon={<Home size={16} />} onClick={() => navigate('/home/center')}>
个人中心
</MenuItem>
<MenuItem icon={<FiUser />} onClick={() => navigate('/home/profile')}>
<MenuItem icon={<User size={16} />} onClick={() => navigate('/home/profile')}>
个人资料
</MenuItem>
<MenuItem icon={<FiSettings />} onClick={() => navigate('/home/settings')}>
<MenuItem icon={<Settings size={16} />} onClick={() => navigate('/home/settings')}>
账户设置
</MenuItem>
<MenuDivider />
{/* 退出登录 */}
<MenuItem icon={<FiLogOut />} onClick={handleLogout} color="red.500">
<MenuItem icon={<LogOut size={16} />} onClick={handleLogout} color="red.500">
退出登录
</MenuItem>
</MenuList>

View File

@@ -19,7 +19,7 @@ import {
} from '@chakra-ui/react';
import { keyframes } from '@emotion/react';
import { motion, AnimatePresence } from 'framer-motion';
import { MdClose, MdOpenInNew, MdSchedule, MdExpandMore, MdExpandLess, MdPerson, MdAccessTime } from 'react-icons/md';
import { X, ExternalLink, Clock as ClockIcon, ChevronDown, ChevronUp, User, Clock } from 'lucide-react';
import { useNotification } from '../../contexts/NotificationContext';
import {
NOTIFICATION_TYPE_CONFIGS,
@@ -479,7 +479,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
{/* 关闭按钮 */}
<IconButton
icon={<MdClose />}
icon={<X size={16} />}
size="xs"
variant="ghost"
colorScheme={typeConfig.colorScheme}
@@ -524,7 +524,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
>
{/* 时间信息 */}
<HStack spacing={1}>
<Icon as={MdAccessTime} w={3} h={3} />
<Icon as={Clock} w={3} h={3} />
<Text>
{publishTime && formatNotificationTime(publishTime)}
{!publishTime && pushTime && formatNotificationTime(pushTime)}
@@ -553,7 +553,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
<Badge colorScheme="gray" size="xs">预测</Badge>
{extra?.statusHint && (
<>
<Icon as={MdSchedule} w={3} h={3} color="gray.400" />
<Icon as={ClockIcon} w={3} h={3} color="gray.400" />
<Text color="gray.400">{extra.statusHint}</Text>
</>
)}
@@ -566,7 +566,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
<>
<Text display={{ base: "none", md: "inline" }}>|</Text>
<HStack spacing={1} display={{ base: "none", md: "flex" }}>
<Icon as={MdPerson} w={3} h={3} />
<Icon as={User} w={3} h={3} />
<Text>{author.name} - {author.organization}</Text>
</HStack>
</>
@@ -581,7 +581,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
{isNavigating ? (
<Spinner size="xs" />
) : (
<Icon as={MdOpenInNew} w={3} h={3} />
<Icon as={ExternalLink} w={3} h={3} />
)}
{/* Loading 时显示"跳转中...",否则显示"查看详情" */}
<Text color={isNavigating ? 'blue.500' : undefined}>
@@ -734,7 +734,7 @@ const NotificationContainer = () => {
outlineColor: 'blue.500',
outlineOffset: '2px',
}}
leftIcon={<Icon as={isExpanded ? MdExpandLess : MdExpandMore} />}
leftIcon={<Icon as={isExpanded ? ChevronUp : ChevronDown} />}
onClick={() => setIsExpanded(!isExpanded)}
aria-expanded={isExpanded}
aria-label={isExpanded ? '收起通知' : `展开查看还有 ${hiddenCount} 条通知`}

View File

@@ -27,7 +27,7 @@ import {
DrawerContent,
DrawerCloseButton,
} from '@chakra-ui/react';
import { MdSpeed, MdClose, MdRefresh, MdFileDownload } from 'react-icons/md';
import { Gauge, X, RefreshCw, Download } from 'lucide-react';
import { performanceMonitor } from '@/utils/performanceMonitor';
/**
@@ -98,7 +98,7 @@ export const PerformancePanel: React.FC = () => {
{/* 浮动按钮 */}
<IconButton
aria-label="Open performance panel"
icon={<MdSpeed />}
icon={<Gauge size={24} />}
position="fixed"
bottom="100px"
right="20px"
@@ -117,7 +117,7 @@ export const PerformancePanel: React.FC = () => {
<DrawerCloseButton />
<DrawerHeader borderBottomWidth="1px">
<HStack>
<MdSpeed size={24} />
<Gauge size={24} />
<Text></Text>
</HStack>
</DrawerHeader>
@@ -128,7 +128,7 @@ export const PerformancePanel: React.FC = () => {
{/* 操作按钮 */}
<HStack spacing={2}>
<Button
leftIcon={<MdRefresh />}
leftIcon={<RefreshCw size={16} />}
size="sm"
colorScheme="blue"
onClick={refreshData}
@@ -136,7 +136,7 @@ export const PerformancePanel: React.FC = () => {
</Button>
<Button
leftIcon={<MdFileDownload />}
leftIcon={<Download size={16} />}
size="sm"
colorScheme="green"
onClick={exportJSON}

View File

@@ -3,7 +3,7 @@
import React from 'react';
import { Flex, Box, Text, useColorModeValue } from '@chakra-ui/react';
import { TriangleUpIcon, TriangleDownIcon } from '@chakra-ui/icons';
import { ChevronUp, ChevronDown } from 'lucide-react';
import { getChangeColor } from '../utils/colorUtils';
/**
@@ -108,16 +108,12 @@ const StockChangeIndicators = ({
{/* 三角形图标 */}
{value !== 0 && (
value > 0 ? (
<TriangleUpIcon
w={2}
h={2}
color={numberColor}
<ChevronUp
style={{ width: '8px', height: '8px', color: numberColor }}
/>
) : (
<TriangleDownIcon
w={2}
h={2}
color={numberColor}
<ChevronDown
style={{ width: '8px', height: '8px', color: numberColor }}
/>
)
)}

View File

@@ -35,7 +35,7 @@ import {
Spinner,
} from '@chakra-ui/react';
import type { ComponentType } from 'react';
import type { IconType } from 'react-icons';
import type { LucideIcon } from 'lucide-react';
/**
* Tab 配置项
@@ -43,7 +43,7 @@ import type { IconType } from 'react-icons';
export interface SubTabConfig {
key: string;
name: string;
icon?: IconType | ComponentType;
icon?: LucideIcon | ComponentType;
component?: ComponentType<any>;
/** 自定义 Suspense fallback如骨架屏 */
fallback?: React.ReactNode;

View File

@@ -42,19 +42,19 @@ import { useSubscriptionEvents } from '../../hooks/useSubscriptionEvents';
// Icons
import {
FaWeixin,
FaGem,
FaCheck,
FaQrcode,
FaClock,
FaRedo,
FaCrown,
FaStar,
FaTimes,
FaInfinity,
FaChevronDown,
FaChevronUp,
} from 'react-icons/fa';
Crown,
Star,
Check,
QrCode,
Clock,
RefreshCw,
X,
Infinity,
ChevronDown,
ChevronUp,
Gem,
} from 'lucide-react';
import { WechatOutlined } from '@ant-design/icons';
import { getApiBase } from '../../utils/apiConfig';
// 会员协议 URL 配置
@@ -761,7 +761,7 @@ export default function SubscriptionContent() {
)}
{user.subscription_status === 'active' && user.subscription_type !== 'free' && (
<Icon
as={user.subscription_type === 'max' ? FaCrown : FaGem}
as={user.subscription_type === 'max' ? Crown : Gem}
color={user.subscription_type === 'max' ? 'purple.400' : 'blue.400'}
boxSize={6}
/>
@@ -909,7 +909,7 @@ export default function SubscriptionContent() {
<Flex justify="space-between" align="center">
<HStack spacing={3}>
<Icon
as={FaStar}
as={Star}
boxSize={8}
color="gray.400"
/>
@@ -945,7 +945,7 @@ export default function SubscriptionContent() {
return (
<HStack key={index} spacing={3} align="start">
<Icon
as={hasFreeAccess ? FaCheck : FaTimes}
as={hasFreeAccess ? Check : X}
color={hasFreeAccess ? 'blue.500' : 'gray.300'}
boxSize={4}
mt={0.5}
@@ -1031,7 +1031,7 @@ export default function SubscriptionContent() {
<Flex justify="space-between" align="center">
<HStack spacing={3}>
<Icon
as={plan.name === 'pro' ? FaGem : FaCrown}
as={plan.name === 'pro' ? Gem : Crown}
boxSize={8}
color={plan.name === 'pro' ? 'blue.400' : 'purple.400'}
/>
@@ -1139,7 +1139,7 @@ export default function SubscriptionContent() {
return (
<HStack key={index} spacing={3} align="start">
<Icon
as={isSupported ? FaCheck : FaTimes}
as={isSupported ? Check : X}
color={isSupported ? 'blue.500' : 'gray.300'}
boxSize={4}
mt={0.5}
@@ -1226,7 +1226,7 @@ export default function SubscriptionContent() {
如何取消订阅
</Text>
<Icon
as={openFaqIndex === 0 ? FaChevronUp : FaChevronDown}
as={openFaqIndex === 0 ? ChevronUp : ChevronDown}
color={textColor}
/>
</Flex>
@@ -1260,7 +1260,7 @@ export default function SubscriptionContent() {
支持哪些支付方式
</Text>
<Icon
as={openFaqIndex === 1 ? FaChevronUp : FaChevronDown}
as={openFaqIndex === 1 ? ChevronUp : ChevronDown}
color={textColor}
/>
</Flex>
@@ -1294,7 +1294,7 @@ export default function SubscriptionContent() {
升级或切换套餐时原套餐的费用怎么办
</Text>
<Icon
as={openFaqIndex === 2 ? FaChevronUp : FaChevronDown}
as={openFaqIndex === 2 ? ChevronUp : ChevronDown}
color={textColor}
/>
</Flex>
@@ -1342,7 +1342,7 @@ export default function SubscriptionContent() {
可以在月付和年付之间切换吗
</Text>
<Icon
as={openFaqIndex === 3 ? FaChevronUp : FaChevronDown}
as={openFaqIndex === 3 ? ChevronUp : ChevronDown}
color={textColor}
/>
</Flex>
@@ -1376,7 +1376,7 @@ export default function SubscriptionContent() {
是否支持退款
</Text>
<Icon
as={openFaqIndex === 4 ? FaChevronUp : FaChevronDown}
as={openFaqIndex === 4 ? ChevronUp : ChevronDown}
color={textColor}
/>
</Flex>
@@ -1430,7 +1430,7 @@ export default function SubscriptionContent() {
Pro版和Max版有什么区别
</Text>
<Icon
as={openFaqIndex === 5 ? FaChevronUp : FaChevronDown}
as={openFaqIndex === 5 ? ChevronUp : ChevronDown}
color={textColor}
/>
</Flex>
@@ -1467,7 +1467,7 @@ export default function SubscriptionContent() {
<ModalContent>
<ModalHeader>
<HStack>
<Icon as={FaWeixin} color="green.500" />
<WechatOutlined style={{ fontSize: '24px', color: '#52c41a' }} />
<Text>微信支付</Text>
</HStack>
</ModalHeader>
@@ -1509,7 +1509,7 @@ export default function SubscriptionContent() {
{priceInfo && priceInfo.is_upgrade && (
<Box bg="blue.50" p={3} borderRadius="md" mb={2}>
<HStack spacing={2} mb={2}>
<Icon as={FaCheck} color="blue.500" boxSize={4} />
<Icon as={Check} color="blue.500" boxSize={4} />
<Text fontSize="sm" fontWeight="bold" color="blue.700">
{priceInfo.upgrade_type === 'plan_upgrade' ? '套餐升级' :
priceInfo.upgrade_type === 'cycle_change' ? '周期变更' : '套餐和周期调整'}
@@ -1601,12 +1601,12 @@ export default function SubscriptionContent() {
)}
{promoCodeApplied && priceInfo && (
<HStack mt={2} p={2} bg="green.50" borderRadius="md">
<Icon as={FaCheck} color="green.500" />
<Icon as={Check} color="green.500" />
<Text color="green.700" fontSize="sm" fontWeight="medium" flex={1}>
优惠码已应用节省 ¥{priceInfo.discount_amount.toFixed(2)}
</Text>
<Icon
as={FaTimes}
as={X}
color="gray.500"
cursor="pointer"
onClick={handleRemovePromoCode}
@@ -1642,7 +1642,7 @@ export default function SubscriptionContent() {
<Button
colorScheme="green"
size="lg"
leftIcon={<Icon as={FaWeixin} />}
leftIcon={<WechatOutlined style={{ fontSize: '20px' }} />}
onClick={() => {
if (!agreementChecked) {
toast({
@@ -1673,7 +1673,7 @@ export default function SubscriptionContent() {
{/* 倒计时 */}
<Box p={3} bg="orange.50" borderRadius="lg">
<HStack justify="center" spacing={2} mb={2}>
<Icon as={FaClock} color="orange.500" />
<Icon as={Clock} color="orange.500" />
<Text color="orange.700" fontSize="sm">
二维码有效时间: {formatTime(paymentCountdown)}
</Text>
@@ -1710,7 +1710,7 @@ export default function SubscriptionContent() {
borderColor={borderColor}
borderRadius="lg"
>
<Icon as={FaQrcode} color="gray.400" boxSize={12} />
<Icon as={QrCode} color="gray.400" boxSize={12} />
</Flex>
)}
</Box>
@@ -1734,7 +1734,7 @@ export default function SubscriptionContent() {
<Button
flex={1}
variant="outline"
leftIcon={<Icon as={FaRedo} />}
leftIcon={<Icon as={RefreshCw} />}
onClick={handleCheckPaymentStatus}
isLoading={checkingPayment}
loadingText="检查中..."

View File

@@ -27,20 +27,19 @@ import {
Link as ChakraLink,
} from '@chakra-ui/react';
import {
FaWeixin,
FaGem,
FaCheck,
FaQrcode,
FaClock,
FaRedo,
FaCrown,
FaStar,
FaTimes,
FaChevronDown,
FaChevronUp,
FaExternalLinkAlt,
} from 'react-icons/fa';
import { AlipayCircleOutlined } from '@ant-design/icons';
Crown,
Star,
Check,
QrCode,
Clock,
RefreshCw,
X,
ChevronDown,
ChevronUp,
ExternalLink,
Gem,
} from 'lucide-react';
import { AlipayCircleOutlined, WechatOutlined } from '@ant-design/icons';
import { logger } from '../../utils/logger';
import { useAuth } from '../../contexts/AuthContext';
@@ -825,11 +824,11 @@ export default function SubscriptionContentNew() {
const getIconComponent = (iconName: string) => {
const icons: any = {
star: FaStar,
gem: FaGem,
crown: FaCrown,
star: Star,
gem: Gem,
crown: Crown,
};
return icons[iconName] || FaStar;
return icons[iconName] || Star;
};
// 获取按钮文字
@@ -967,7 +966,7 @@ export default function SubscriptionContentNew() {
<HStack justify="space-between" align="center">
<HStack spacing={3}>
<Icon
as={user.subscription_type === 'max' ? FaCrown : FaGem}
as={user.subscription_type === 'max' ? Crown : Gem}
color="#D4AF37"
boxSize={6}
/>
@@ -1003,7 +1002,7 @@ export default function SubscriptionContentNew() {
<Flex justify="space-between" align="center">
<HStack spacing={2}>
<Icon as={FaClock} color="rgba(212, 175, 55, 0.8)" boxSize={4} />
<Icon as={Clock} color="rgba(212, 175, 55, 0.8)" boxSize={4} />
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
</Text>
@@ -1065,7 +1064,7 @@ export default function SubscriptionContentNew() {
if (currentOption && currentOption.discountPercent > 0) {
return (
<HStack spacing={2}>
<Icon as={FaStar} color="#D4AF37" boxSize={4} />
<Icon as={Star} color="#D4AF37" boxSize={4} />
<Text fontSize="sm" color="#D4AF37" fontWeight="medium">
{currentOption.discountPercent}%
</Text>
@@ -1285,7 +1284,7 @@ export default function SubscriptionContentNew() {
}
>
<Icon
as={feature.enabled ? FaCheck : FaTimes}
as={feature.enabled ? Check : X}
color={feature.enabled ? '#000' : 'rgba(255, 255, 255, 0.3)'}
boxSize={3}
/>
@@ -1360,7 +1359,7 @@ export default function SubscriptionContentNew() {
{faq.question}
</Text>
<Icon
as={openFaqIndex === index ? FaChevronUp : FaChevronDown}
as={openFaqIndex === index ? ChevronUp : ChevronDown}
color="#D4AF37"
boxSize={5}
/>
@@ -1423,7 +1422,7 @@ export default function SubscriptionContentNew() {
transition="all 0.2s"
>
<HStack spacing={3}>
<Icon as={FaWeixin} color="#07C160" boxSize={6} />
<WechatOutlined style={{ fontSize: '24px', color: '#07C160' }} />
<Text color="white" fontWeight="medium"></Text>
</HStack>
</Button>
@@ -1460,7 +1459,7 @@ export default function SubscriptionContentNew() {
border="1px solid rgba(76, 175, 80, 0.3)"
>
<HStack spacing={2}>
<Icon as={FaCheck} color="green.400" />
<Icon as={Check} color="green.400" />
<Text color="green.400" fontSize="sm" fontWeight="medium">
{priceInfo.final_amount === 0
? `恭喜!您的当前订阅剩余价值足够直接升级到${selectedPlan.displayName},无需支付额外费用!`
@@ -1477,7 +1476,7 @@ export default function SubscriptionContentNew() {
border="1px solid rgba(255, 165, 0, 0.3)"
>
<HStack spacing={2}>
<Icon as={FaClock} color="orange.400" />
<Icon as={Clock} color="orange.400" />
<Text color="orange.400" fontSize="sm" fontWeight="medium">
{priceInfo.current_plan?.toUpperCase()}{selectedPlan.displayName}
</Text>
@@ -1492,7 +1491,7 @@ export default function SubscriptionContentNew() {
border="1px solid rgba(33, 150, 243, 0.3)"
>
<HStack spacing={2}>
<Icon as={FaRedo} color="blue.400" />
<Icon as={RefreshCw} color="blue.400" />
<Text color="blue.400" fontSize="sm" fontWeight="medium">
{selectedPlan.displayName}
</Text>
@@ -1536,7 +1535,7 @@ export default function SubscriptionContentNew() {
{promoCodeApplied && priceInfo.discount_amount > 0 && (
<Flex justify="space-between" align="center">
<HStack spacing={2}>
<Icon as={FaCheck} color="green.400" boxSize={3} />
<Icon as={Check} color="green.400" boxSize={3} />
<Text color="rgba(255, 255, 255, 0.7)" fontSize="sm">
</Text>
@@ -1606,12 +1605,12 @@ export default function SubscriptionContentNew() {
borderRadius="md"
border="1px solid rgba(72, 187, 120, 0.3)"
>
<Icon as={FaCheck} color="green.400" />
<Icon as={Check} color="green.400" />
<Text color="green.400" fontSize="sm" fontWeight="medium" flex={1}>
¥{priceInfo.discount_amount.toFixed(2)}
</Text>
<Icon
as={FaTimes}
as={X}
color="rgba(255, 255, 255, 0.5)"
cursor="pointer"
onClick={handleRemovePromoCode}
@@ -1672,7 +1671,7 @@ export default function SubscriptionContentNew() {
isDisabled={!selectedPlan}
leftIcon={paymentMethod === 'alipay'
? <Box as={AlipayCircleOutlined} fontSize="20px" />
: <Icon as={FaWeixin} boxSize={5} />}
: <WechatOutlined style={{ fontSize: '20px' }} />}
_hover={{
bgGradient: paymentMethod === 'alipay'
? 'linear-gradient(135deg, #4096ff, #1677FF)'
@@ -1770,7 +1769,7 @@ export default function SubscriptionContentNew() {
w="full"
>
<HStack justify="center" spacing={2} mb={2}>
<Icon as={FaClock} color="orange.400" />
<Icon as={Clock} color="orange.400" />
<Text color="orange.300" fontSize="sm">
: {formatTime(paymentCountdown)}
</Text>
@@ -1810,7 +1809,7 @@ export default function SubscriptionContentNew() {
borderColor="rgba(255, 255, 255, 0.2)"
borderRadius="lg"
>
<Icon as={FaQrcode} color="rgba(255, 255, 255, 0.3)" boxSize={12} />
<Icon as={QrCode} color="rgba(255, 255, 255, 0.3)" boxSize={12} />
</Flex>
)}
</Box>
@@ -1845,7 +1844,7 @@ export default function SubscriptionContentNew() {
bgGradient="linear-gradient(135deg, #1677FF, #0958d9)"
color="white"
fontWeight="bold"
leftIcon={<Icon as={FaExternalLinkAlt} />}
leftIcon={<Icon as={ExternalLink} />}
onClick={handleReopenAlipay}
_hover={{
bgGradient: 'linear-gradient(135deg, #4096ff, #1677FF)',
@@ -1864,7 +1863,7 @@ export default function SubscriptionContentNew() {
bgGradient="linear-gradient(135deg, #D4AF37, #B8941F)"
color="#000"
fontWeight="bold"
leftIcon={<Icon as={FaRedo} />}
leftIcon={<Icon as={RefreshCw} />}
onClick={handleForceUpdate}
isLoading={forceUpdating}
_hover={{

View File

@@ -12,7 +12,7 @@ import {
Text,
useColorModeValue,
} from '@chakra-ui/react';
import { FiStar } from 'react-icons/fi';
import { Star } from 'lucide-react';
import PropTypes from 'prop-types';
import SubscriptionContent from './SubscriptionContent';
@@ -23,7 +23,7 @@ export default function SubscriptionModal({ isOpen, onClose }) {
<ModalContent maxH="90vh">
<ModalHeader borderBottomWidth="1px" borderColor={useColorModeValue('gray.200', 'gray.600')}>
<HStack>
<Icon as={FiStar} color="blue.500" boxSize={5} />
<Icon as={Star} color="blue.500" boxSize={5} />
<Text>订阅管理</Text>
</HStack>
</ModalHeader>

View File

@@ -9,7 +9,7 @@ import {
Text,
useColorModeValue,
} from '@chakra-ui/react';
import { FaStar, FaCrown } from 'react-icons/fa';
import { Star, Crown } from 'lucide-react';
import { logger } from '../utils/logger';
/**
@@ -23,13 +23,13 @@ const SubscriptionBadge = ({ tier = 'pro', size = 'sm' }) => {
const config = {
pro: {
label: 'PRO专享',
icon: FaStar,
icon: Star,
bgGradient: 'linear(to-r, blue.400, purple.500)',
color: 'white',
},
max: {
label: 'MAX专享',
icon: FaCrown,
icon: Crown,
bgGradient: 'linear(to-r, pink.400, red.500)',
color: 'white',
},

View File

@@ -17,7 +17,7 @@ import {
Icon,
Divider
} from '@chakra-ui/react';
import { FaCrown, FaLock, FaStar, FaRocket } from 'react-icons/fa';
import { Crown, Lock, Star, Rocket } from 'lucide-react';
const SubscriptionUpgradeModal = ({
isOpen,
@@ -34,19 +34,19 @@ const SubscriptionUpgradeModal = ({
const subscriptionLevels = {
free: {
name: '免费版',
icon: FaLock,
icon: Lock,
color: 'gray',
features: ['基础事件浏览', '有限历史事件查看']
},
pro: {
name: 'Pro版',
icon: FaStar,
icon: Star,
color: 'blue',
features: ['相关标的分析', '相关概念分析', '完整历史事件']
},
max: {
name: 'Max版',
icon: FaCrown,
icon: Crown,
color: 'purple',
features: ['传导链分析', '高级分析工具', '实时数据推送', '所有Pro版功能']
}
@@ -66,7 +66,7 @@ const SubscriptionUpgradeModal = ({
<ModalContent bg={bgColor}>
<ModalHeader borderBottomWidth="1px" borderColor={borderColor}>
<HStack spacing={3}>
<Icon as={FaLock} color="red.500" boxSize={6} />
<Icon as={Lock} color="red.500" boxSize={6} />
<VStack align="start" spacing={0}>
<Text fontSize="lg" fontWeight="bold">
需要{requiredLevelInfo.name}订阅
@@ -144,7 +144,7 @@ const SubscriptionUpgradeModal = ({
borderRadius="md"
>
<HStack spacing={2}>
<Icon as={FaRocket} color="yellow.600" />
<Icon as={Rocket} color="yellow.600" />
<Text fontSize="sm" color={useColorModeValue('yellow.800', 'yellow.200')}>
升级到{requiredLevelInfo.name}即可解锁此功能
</Text>
@@ -160,7 +160,7 @@ const SubscriptionUpgradeModal = ({
</Button>
<Button
colorScheme={requiredLevelInfo.color}
leftIcon={<Icon as={FaCrown} />}
leftIcon={<Icon as={Crown} />}
onClick={handleUpgrade}
>
立即升级

View File

@@ -3,7 +3,7 @@
*/
import type { ComponentType, ReactNode } from 'react';
import type { IconType } from 'react-icons';
import type { LucideIcon } from 'lucide-react';
/**
* Tab 配置项
@@ -14,7 +14,7 @@ export interface TabConfig {
/** Tab 显示名称 */
name: string;
/** Tab 图标(可选) */
icon?: IconType | ComponentType;
icon?: LucideIcon | ComponentType;
/** Tab 内容组件(可选,如果不传则使用 children 渲染) */
component?: ComponentType<any>;
}

View File

@@ -35,12 +35,7 @@ import {
Tr,
} from "@chakra-ui/react";
import React, { useMemo } from "react";
import { GrFormNext, GrFormPrevious } from "react-icons/gr";
import {
TiArrowSortedDown,
TiArrowSortedUp,
TiArrowUnsorted,
} from "react-icons/ti";
import { ChevronRight, ChevronLeft, ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react";
import { usePagination, useSortBy, useTable } from "react-table";
function BasicTable(props) {
@@ -142,9 +137,9 @@ function BasicTable(props) {
as={
column.isSorted
? column.isSortedDesc
? TiArrowSortedDown
: TiArrowSortedUp
: TiArrowUnsorted
? ChevronDown
: ChevronUp
: ChevronsUpDown
}
/>
</Flex>
@@ -211,7 +206,7 @@ function BasicTable(props) {
borderColor: "gray.500",
}}
>
<Icon as={GrFormPrevious} w="16px" h="16px" color="gray.400" />
<Icon as={ChevronLeft} w="16px" h="16px" color="gray.400" />
</Button>
{pageSize === 5 ? (
<NumberInput
@@ -276,7 +271,7 @@ function BasicTable(props) {
borderColor: "gray.500",
}}
>
<Icon as={GrFormNext} w="16px" h="16px" color="gray.400" />
<Icon as={ChevronRight} w="16px" h="16px" color="gray.400" />
</Button>
</Stack>
</Flex>

View File

@@ -24,7 +24,7 @@ import {
useColorModeValue,
} from "@chakra-ui/react";
import React from "react";
import { FaPencilAlt, FaTrashAlt } from "react-icons/fa";
import { Pencil, Trash2 } from "lucide-react";
function BillingRow(props) {
const textColor = useColorModeValue("gray.700", "white");
@@ -70,7 +70,7 @@ function BillingRow(props) {
me={{ md: "12px" }}
>
<Flex color="red.500" cursor="pointer" align="center" p="12px">
<Icon as={FaTrashAlt} me="4px" />
<Icon as={Trash2} me="4px" />
<Text fontSize="sm" fontWeight="semibold">
DELETE
</Text>
@@ -78,7 +78,7 @@ function BillingRow(props) {
</Button>
<Button p="0px" variant="no-effects">
<Flex color={textColor} cursor="pointer" align="center" p="12px">
<Icon as={FaPencilAlt} me="4px" />
<Icon as={Pencil} me="4px" />
<Text fontSize="sm" fontWeight="semibold">
EDIT
</Text>

View File

@@ -36,12 +36,7 @@ import {
Tr,
} from "@chakra-ui/react";
import React, { useMemo } from "react";
import { GrFormNext, GrFormPrevious } from "react-icons/gr";
import {
TiArrowSortedDown,
TiArrowSortedUp,
TiArrowUnsorted,
} from "react-icons/ti";
import { ChevronRight, ChevronLeft, ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react";
import {
useGlobalFilter,
usePagination,
@@ -165,9 +160,9 @@ function SearchTable1(props) {
as={
column.isSorted
? column.isSortedDesc
? TiArrowSortedDown
: TiArrowSortedUp
: TiArrowUnsorted
? ChevronDown
: ChevronUp
: ChevronsUpDown
}
/>
</Flex>
@@ -235,7 +230,7 @@ function SearchTable1(props) {
borderColor: "gray.500",
}}
>
<Icon as={GrFormPrevious} w="16px" h="16px" color="gray.400" />
<Icon as={ChevronLeft} w="16px" h="16px" color="gray.400" />
</Button>
{pageSize === 5 ? (
<NumberInput
@@ -300,7 +295,7 @@ function SearchTable1(props) {
borderColor: "gray.500",
}}
>
<Icon as={GrFormNext} w="16px" h="16px" color="gray.400" />
<Icon as={ChevronRight} w="16px" h="16px" color="gray.400" />
</Button>
</Stack>
</Flex>

View File

@@ -40,15 +40,7 @@ import {
} from "@chakra-ui/react";
import React, { useMemo } from "react";
import { SearchBar } from "components/Navbars/SearchBar/SearchBar";
import { MdReplay, MdCheck } from "react-icons/md";
import { IoMdClose } from "react-icons/io";
import { FaCheckCircle, FaTimesCircle, FaUndoAlt } from "react-icons/fa";
import { GrFormNext, GrFormPrevious } from "react-icons/gr";
import {
TiArrowSortedDown,
TiArrowSortedUp,
TiArrowUnsorted,
} from "react-icons/ti";
import { RotateCcw, Check, X, CheckCircle, XCircle, Undo2, ChevronRight, ChevronLeft, ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react";
import {
useGlobalFilter,
usePagination,
@@ -145,9 +137,9 @@ function SearchTable2(props) {
as={
column.isSorted
? column.isSortedDesc
? TiArrowSortedDown
: TiArrowSortedUp
: TiArrowUnsorted
? ChevronDown
: ChevronUp
: ChevronsUpDown
}
/>
</Flex>
@@ -185,10 +177,10 @@ function SearchTable2(props) {
<Icon
as={
cell.value === "Paid"
? MdCheck
? Check
: cell.value === "Refunded"
? MdReplay
: IoMdClose
? RotateCcw
: X
}
color={
cell.value === "Paid"
@@ -283,7 +275,7 @@ function SearchTable2(props) {
borderColor: "gray.500",
}}
>
<Icon as={GrFormPrevious} w="16px" h="16px" color="gray.400" />
<Icon as={ChevronLeft} w="16px" h="16px" color="gray.400" />
</Button>
{pageSize === 5 ? (
<NumberInput
@@ -348,7 +340,7 @@ function SearchTable2(props) {
borderColor: "gray.500",
}}
>
<Icon as={GrFormNext} w="16px" h="16px" color="gray.400" />
<Icon as={ChevronRight} w="16px" h="16px" color="gray.400" />
</Button>
</Stack>
</Flex>

View File

@@ -26,7 +26,7 @@ import {
useColorModeValue,
} from "@chakra-ui/react";
import React from "react";
import { FaEllipsisV } from "react-icons/fa";
import { MoreVertical } from "lucide-react";
function DashboardTableRow(props) {
const { logo, name, status, budget, progression } = props;
@@ -74,7 +74,7 @@ function DashboardTableRow(props) {
</Td>
<Td>
<Button p="0px" bg="transparent">
<Icon as={FaEllipsisV} color="gray.400" cursor="pointer" />
<Icon as={MoreVertical} color="gray.400" cursor="pointer" />
</Button>
</Td>
</Tr>

View File

@@ -25,7 +25,7 @@ import {
useColorModeValue,
} from "@chakra-ui/react";
import React from "react";
import { BsCircleFill } from "react-icons/bs";
import { Circle } from "lucide-react";
function TablesReportsRow(props) {
const {
@@ -99,9 +99,10 @@ function TablesReportsRow(props) {
>
<Flex align="center">
<Icon
as={BsCircleFill}
as={Circle}
w="8px"
h="8px"
fill="currentColor"
color={
review === "Positive"
? "teal.300"

View File

@@ -7,8 +7,7 @@ import {
Tooltip,
useColorModeValue,
} from '@chakra-ui/react';
import { InfoIcon } from '@chakra-ui/icons';
import { FaCalendarAlt } from 'react-icons/fa';
import { Info, Calendar } from 'lucide-react';
export interface TradeDatePickerProps {
/** 当前选中的日期 */
@@ -117,7 +116,7 @@ const TradeDatePicker: React.FC<TradeDatePickerProps> = ({
<>
{/* 标签 */}
<HStack spacing={3}>
{showIcon && <Icon as={FaCalendarAlt} color={iconColor} boxSize={5} />}
{showIcon && <Icon as={Calendar} color={iconColor} boxSize={5} />}
<Text fontWeight="bold" color={labelColor}>
{label}
</Text>
@@ -157,7 +156,7 @@ const TradeDatePicker: React.FC<TradeDatePickerProps> = ({
_hover={{ opacity: 1 }}
transition="opacity 0.2s"
>
<Icon as={InfoIcon} color={tipIconColor} boxSize={3} />
<Info size={12} color="var(--chakra-colors-blue-300)" style={{ display: 'inline-block' }} />
<Text fontSize="xs" color={tipTextColor}>
{latestTradeDate.toLocaleDateString('zh-CN')}
</Text>