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:
@@ -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}>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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="踩"
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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' }}
|
||||
>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}>
|
||||
还没有评论,快来发表第一条吧~
|
||||
|
||||
@@ -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 ? '收起' : '展开'}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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') && (
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 || '打开小程序'}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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" }}
|
||||
|
||||
@@ -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)}
|
||||
>
|
||||
投资日历
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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="打开菜单"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}>
|
||||
完善资料,享受更好服务
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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} 条通知`}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 }}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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="检查中..."
|
||||
|
||||
@@ -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={{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
立即升级
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user