Merge branch 'feature_bugfix/251217_stock' of https://git.valuefrontier.cn/vf/vf_react into feature_bugfix/251217_stock
This commit is contained in:
@@ -32,7 +32,6 @@ import {
|
||||
// Assets
|
||||
import BasicImage from "assets/img/BasicImage.png";
|
||||
import React from "react";
|
||||
import { FaApple, FaFacebook, FaGoogle } from "react-icons/fa";
|
||||
import AuthBasic from "layouts/AuthBasic";
|
||||
|
||||
function LockBasic() {
|
||||
|
||||
@@ -30,7 +30,7 @@ import BasicImage from "assets/img/BasicImage.png";
|
||||
import React from "react";
|
||||
import AuthBasic from "layouts/AuthBasic";
|
||||
import { PinInputLight } from "components/PinInput/PinInput";
|
||||
import { IoIosRocket } from "react-icons/io";
|
||||
import { Rocket } from "lucide-react";
|
||||
|
||||
function LockBasic() {
|
||||
// Chakra color mode
|
||||
@@ -75,7 +75,7 @@ function LockBasic() {
|
||||
align="center"
|
||||
mb="30px"
|
||||
>
|
||||
<Icon as={IoIosRocket} color="white" w="36px" h="36px" />
|
||||
<Icon as={Rocket} color="white" w="36px" h="36px" />
|
||||
</Flex>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from "@chakra-ui/react";
|
||||
// Assets
|
||||
import { PinInputLight } from "components/PinInput/PinInput";
|
||||
import { IoIosRocket } from "react-icons/io";
|
||||
import { Rocket } from "lucide-react";
|
||||
import CoverImage from "assets/img/CoverImage.png";
|
||||
import React from "react";
|
||||
import AuthCover from "layouts/AuthCover";
|
||||
@@ -64,7 +64,7 @@ function LockCover() {
|
||||
align="center"
|
||||
mb="30px"
|
||||
>
|
||||
<Icon as={IoIosRocket} color="white" w="36px" h="36px" />
|
||||
<Icon as={Rocket} color="white" w="36px" h="36px" />
|
||||
</Flex>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import illustration from "assets/img/illustration-auth.png";
|
||||
import AuthIllustration from "layouts/AuthIllustration";
|
||||
import { PinInputDark } from "components/PinInput/PinInput";
|
||||
import { IoIosRocket } from "react-icons/io";
|
||||
import { Rocket } from "lucide-react";
|
||||
|
||||
function LockIllustration() {
|
||||
// Chakra color mode
|
||||
@@ -51,7 +51,7 @@ function LockIllustration() {
|
||||
justify='center'
|
||||
align='center'
|
||||
mb='30px'>
|
||||
<Icon as={IoIosRocket} color='white' w='36px' h='36px' />
|
||||
<Icon as={Rocket} color='white' w='36px' h='36px' />
|
||||
</Flex>
|
||||
<Text
|
||||
fontWeight='bold'
|
||||
|
||||
@@ -30,14 +30,14 @@ import {
|
||||
useColorModeValue,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FiEdit2,
|
||||
FiTrash2,
|
||||
FiFileText,
|
||||
FiCalendar,
|
||||
FiTrendingUp,
|
||||
FiChevronDown,
|
||||
FiChevronUp,
|
||||
} from 'react-icons/fi';
|
||||
Pencil,
|
||||
Trash2,
|
||||
FileText,
|
||||
Calendar,
|
||||
TrendingUp,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
} from 'lucide-react';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
@@ -191,7 +191,7 @@ export const EventCard = memo<EventCardProps>(({
|
||||
<VStack align="start" spacing={1} flex={1}>
|
||||
{/* 标题行 */}
|
||||
<HStack spacing={{ base: 1, md: 2 }} flexWrap="wrap">
|
||||
<Icon as={FiFileText} color={`${colorScheme}.500`} boxSize={{ base: 4, md: 5 }} />
|
||||
<Icon as={FileText} color={`${colorScheme}.500`} boxSize={{ base: 4, md: 5 }} />
|
||||
<Text fontWeight="bold" fontSize={{ base: 'md', md: 'lg' }}>
|
||||
{event.title}
|
||||
</Text>
|
||||
@@ -206,7 +206,7 @@ export const EventCard = memo<EventCardProps>(({
|
||||
{/* list 模式显示日期 */}
|
||||
{isListMode && (
|
||||
<HStack spacing={{ base: 1, md: 2 }} flexWrap="wrap">
|
||||
<Icon as={FiCalendar} boxSize={{ base: 2.5, md: 3 }} color={finalSecondaryText} />
|
||||
<Icon as={Calendar} boxSize={{ base: 2.5, md: 3 }} color={finalSecondaryText} />
|
||||
<Text fontSize={{ base: 'xs', md: 'sm' }} color={finalSecondaryText}>
|
||||
{dayjs(event.event_date || event.date).format('YYYY年MM月DD日')}
|
||||
</Text>
|
||||
@@ -219,7 +219,7 @@ export const EventCard = memo<EventCardProps>(({
|
||||
<HStack spacing={{ base: 0, md: 1 }}>
|
||||
{onEdit && (
|
||||
<IconButton
|
||||
icon={<FiEdit2 />}
|
||||
icon={<Pencil />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => onEdit(event)}
|
||||
@@ -228,7 +228,7 @@ export const EventCard = memo<EventCardProps>(({
|
||||
)}
|
||||
{onDelete && (
|
||||
<IconButton
|
||||
icon={<FiTrash2 />}
|
||||
icon={<Trash2 />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
colorScheme="red"
|
||||
@@ -258,7 +258,7 @@ export const EventCard = memo<EventCardProps>(({
|
||||
variant="ghost"
|
||||
colorScheme={colorScheme}
|
||||
mt={1}
|
||||
rightIcon={isExpanded ? <FiChevronUp /> : <FiChevronDown />}
|
||||
rightIcon={isExpanded ? <ChevronUp /> : <ChevronDown />}
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
>
|
||||
{isExpanded ? '收起' : '展开'}
|
||||
@@ -280,7 +280,7 @@ export const EventCard = memo<EventCardProps>(({
|
||||
const displayText = typeof stock === 'string' ? stock : `${stock.name}(${stock.code})`;
|
||||
return (
|
||||
<Tag key={stockCode || idx} size="sm" colorScheme="blue" variant="subtle">
|
||||
<TagLeftIcon as={FiTrendingUp} />
|
||||
<TagLeftIcon as={TrendingUp} />
|
||||
<TagLabel>{displayText}</TagLabel>
|
||||
</Tag>
|
||||
);
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Icon,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { FiFileText } from 'react-icons/fi';
|
||||
import { FileText } from 'lucide-react';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
||||
import {
|
||||
@@ -165,7 +165,7 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
||||
) : events.length === 0 ? (
|
||||
<Center py={{ base: 6, md: 8 }}>
|
||||
<VStack spacing={{ base: 2, md: 3 }}>
|
||||
<Icon as={FiFileText} boxSize={{ base: 8, md: 12 }} color="gray.300" />
|
||||
<Icon as={FileText} boxSize={{ base: 8, md: 12 }} color="gray.300" />
|
||||
<Text color={secondaryText} fontSize={{ base: 'sm', md: 'md' }}>暂无投资{label}</Text>
|
||||
</VStack>
|
||||
</Center>
|
||||
|
||||
@@ -21,14 +21,16 @@ import {
|
||||
Button,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FiEdit2,
|
||||
FiTrash2,
|
||||
FiCalendar,
|
||||
FiTrendingUp,
|
||||
FiChevronDown,
|
||||
FiChevronUp,
|
||||
} from 'react-icons/fi';
|
||||
import { FileText, Heart, Target } from 'lucide-react';
|
||||
Pencil,
|
||||
Trash2,
|
||||
Calendar,
|
||||
TrendingUp,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
FileText,
|
||||
Heart,
|
||||
Target,
|
||||
} from 'lucide-react';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
@@ -170,7 +172,7 @@ export const FUIEventCard = memo<FUIEventCardProps>(({
|
||||
<HStack spacing={0}>
|
||||
{onEdit && (
|
||||
<IconButton
|
||||
icon={<FiEdit2 size={14} />}
|
||||
icon={<Pencil size={14} />}
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
color={FUI_THEME.text.secondary}
|
||||
@@ -181,7 +183,7 @@ export const FUIEventCard = memo<FUIEventCardProps>(({
|
||||
)}
|
||||
{onDelete && (
|
||||
<IconButton
|
||||
icon={<FiTrash2 size={14} />}
|
||||
icon={<Trash2 size={14} />}
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
color={FUI_THEME.text.secondary}
|
||||
@@ -197,7 +199,7 @@ export const FUIEventCard = memo<FUIEventCardProps>(({
|
||||
|
||||
{/* 日期行 */}
|
||||
<HStack spacing={2}>
|
||||
<FiCalendar size={12} color={FUI_THEME.text.muted} />
|
||||
<Calendar size={12} color={FUI_THEME.text.muted} />
|
||||
<Text fontSize="xs" color={FUI_THEME.text.secondary}>
|
||||
{dayjs(event.event_date || event.date).format('YYYY年MM月DD日')}
|
||||
</Text>
|
||||
@@ -243,7 +245,7 @@ export const FUIEventCard = memo<FUIEventCardProps>(({
|
||||
mt={1}
|
||||
ml={4}
|
||||
_hover={{ bg: 'rgba(212, 175, 55, 0.1)' }}
|
||||
rightIcon={isExpanded ? <FiChevronUp /> : <FiChevronDown />}
|
||||
rightIcon={isExpanded ? <ChevronUp /> : <ChevronDown />}
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
>
|
||||
{isExpanded ? '收起' : '展开'}
|
||||
@@ -270,7 +272,7 @@ export const FUIEventCard = memo<FUIEventCardProps>(({
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.2)"
|
||||
>
|
||||
<TagLeftIcon as={FiTrendingUp} boxSize={3} />
|
||||
<TagLeftIcon as={TrendingUp} boxSize={3} />
|
||||
<TagLabel fontSize="xs">{displayText}</TagLabel>
|
||||
</Tag>
|
||||
);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* 黑金色主题,展示平台核心功能快捷入口
|
||||
*/
|
||||
import React, { useCallback } from 'react';
|
||||
import { Box, SimpleGrid, HStack, Text, Icon } from '@chakra-ui/react';
|
||||
import { CheckCircleIcon } from '@chakra-ui/icons';
|
||||
import { Box, SimpleGrid, HStack, Text } from '@chakra-ui/react';
|
||||
import { CheckCircle } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import GlassCard from '@components/GlassCard';
|
||||
import { CORE_FEATURES } from '@/constants/homeFeatures';
|
||||
@@ -35,10 +35,10 @@ const FeatureEntryPanel: React.FC = () => {
|
||||
>
|
||||
{/* 标题栏 - 参考投资仪表盘样式 */}
|
||||
<HStack mb={4} spacing={2}>
|
||||
<Icon
|
||||
as={CheckCircleIcon}
|
||||
boxSize={5}
|
||||
<CheckCircle
|
||||
size={20}
|
||||
color="rgba(72, 187, 120, 0.9)"
|
||||
style={{ display: 'inline-block' }}
|
||||
/>
|
||||
<Text
|
||||
fontSize="lg"
|
||||
|
||||
@@ -28,12 +28,12 @@ import {
|
||||
ButtonGroup,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FiCalendar,
|
||||
FiFileText,
|
||||
FiList,
|
||||
FiPlus,
|
||||
} from 'react-icons/fi';
|
||||
import { Target } from 'lucide-react';
|
||||
Calendar,
|
||||
FileText,
|
||||
List,
|
||||
Plus,
|
||||
Target,
|
||||
} from 'lucide-react';
|
||||
import GlassCard from '@components/GlassCard';
|
||||
|
||||
import { PlanningDataProvider } from './PlanningContext';
|
||||
@@ -148,7 +148,7 @@ const InvestmentPlanningCenter: React.FC = () => {
|
||||
{/* 视图切换按钮组 - H5隐藏 */}
|
||||
<ButtonGroup size="sm" isAttached display={{ base: 'none', md: 'flex' }}>
|
||||
<Button
|
||||
leftIcon={<Icon as={FiList} boxSize={4} />}
|
||||
leftIcon={<Icon as={List} boxSize={4} />}
|
||||
bg={viewMode === 'list' ? 'rgba(212, 175, 55, 0.2)' : 'transparent'}
|
||||
color={viewMode === 'list' ? goldAccent : 'rgba(255, 255, 255, 0.6)'}
|
||||
border="1px solid"
|
||||
@@ -159,7 +159,7 @@ const InvestmentPlanningCenter: React.FC = () => {
|
||||
列表视图
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<Icon as={FiCalendar} boxSize={4} />}
|
||||
leftIcon={<Icon as={Calendar} boxSize={4} />}
|
||||
bg={viewMode === 'calendar' ? 'rgba(212, 175, 55, 0.2)' : 'transparent'}
|
||||
color={viewMode === 'calendar' ? goldAccent : 'rgba(255, 255, 255, 0.6)'}
|
||||
border="1px solid"
|
||||
@@ -223,7 +223,7 @@ const InvestmentPlanningCenter: React.FC = () => {
|
||||
borderColor: goldAccent,
|
||||
}}
|
||||
>
|
||||
<Icon as={FiFileText} mr={1} boxSize={{ base: 3, md: 4 }} />
|
||||
<Icon as={FileText} mr={1} boxSize={{ base: 3, md: 4 }} />
|
||||
我的复盘 ({reviews.length})
|
||||
</Tab>
|
||||
</TabList>
|
||||
@@ -233,7 +233,7 @@ const InvestmentPlanningCenter: React.FC = () => {
|
||||
color={goldAccent}
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.3)"
|
||||
leftIcon={<Icon as={FiPlus} boxSize={3} />}
|
||||
leftIcon={<Icon as={Plus} boxSize={3} />}
|
||||
fontSize={{ base: '11px', md: 'sm' }}
|
||||
flexShrink={0}
|
||||
_hover={{ bg: 'rgba(212, 175, 55, 0.3)' }}
|
||||
|
||||
@@ -21,12 +21,12 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
FiCalendar,
|
||||
FiClock,
|
||||
FiStar,
|
||||
FiTrendingUp,
|
||||
FiAlertCircle,
|
||||
} from 'react-icons/fi';
|
||||
Calendar,
|
||||
Clock,
|
||||
Star,
|
||||
TrendingUp,
|
||||
AlertCircle,
|
||||
} from 'lucide-react';
|
||||
import { eventService } from '../../../services/eventService';
|
||||
import { logger } from '../../../utils/logger';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -153,7 +153,7 @@ export default function MyFutureEvents({ limit = 5 }) {
|
||||
return (
|
||||
<Center py={8}>
|
||||
<VStack spacing={3}>
|
||||
<Icon as={FiCalendar} boxSize={12} color="gray.300" />
|
||||
<Icon as={Calendar} boxSize={12} color="gray.300" />
|
||||
<Text color={secondaryText} fontSize="sm">
|
||||
暂无关注的未来事件
|
||||
</Text>
|
||||
@@ -214,7 +214,7 @@ export default function MyFutureEvents({ limit = 5 }) {
|
||||
<HStack spacing={3}>
|
||||
<Badge colorScheme={timeInfo.color} variant="subtle">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FiClock} boxSize={3} />
|
||||
<Icon as={Clock} boxSize={3} />
|
||||
<Text>{timeInfo.date}</Text>
|
||||
</HStack>
|
||||
</Badge>
|
||||
@@ -228,7 +228,7 @@ export default function MyFutureEvents({ limit = 5 }) {
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<Icon
|
||||
key={i}
|
||||
as={FiStar}
|
||||
as={Star}
|
||||
boxSize={3}
|
||||
color={i < event.star ? importanceColor : 'gray.300'}
|
||||
fill={i < event.star ? 'currentColor' : 'none'}
|
||||
@@ -247,7 +247,7 @@ export default function MyFutureEvents({ limit = 5 }) {
|
||||
)}
|
||||
{event.related_stocks && event.related_stocks.length > 0 && (
|
||||
<Tag size="sm" variant="subtle" colorScheme="purple">
|
||||
<Icon as={FiTrendingUp} boxSize={3} mr={1} />
|
||||
<Icon as={TrendingUp} boxSize={3} mr={1} />
|
||||
<TagLabel>{event.related_stocks.length}只相关股票</TagLabel>
|
||||
</Tag>
|
||||
)}
|
||||
@@ -271,7 +271,7 @@ export default function MyFutureEvents({ limit = 5 }) {
|
||||
{event.forecast && (
|
||||
<Box>
|
||||
<HStack spacing={1} mb={1}>
|
||||
<Icon as={FiAlertCircle} boxSize={3} color={secondaryText} />
|
||||
<Icon as={AlertCircle} boxSize={3} color={secondaryText} />
|
||||
<Text fontSize="xs" color={secondaryText}>
|
||||
预测
|
||||
</Text>
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
Tooltip,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { TimeIcon, BellIcon } from '@chakra-ui/icons';
|
||||
import { Clock, Bell } from 'lucide-react';
|
||||
import { useNotification } from '@contexts/NotificationContext';
|
||||
import EventScrollList from './EventScrollList';
|
||||
import ModeToggleButtons from './ModeToggleButtons';
|
||||
@@ -565,7 +565,7 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
||||
<HStack spacing={4}>
|
||||
<Heading size={isMobile ? "sm" : "md"} color={PROFESSIONAL_COLORS.text.primary}>
|
||||
<HStack spacing={2}>
|
||||
<TimeIcon color={PROFESSIONAL_COLORS.gold[500]} />
|
||||
<Clock size={20} color={PROFESSIONAL_COLORS.gold[500]} />
|
||||
<Text bgGradient={PROFESSIONAL_COLORS.gradients.gold} bgClip="text">实时要闻·动态追踪</Text>
|
||||
</HStack>
|
||||
</Heading>
|
||||
@@ -584,9 +584,8 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
||||
_hover={{ opacity: 0.8 }}
|
||||
transition="opacity 0.2s"
|
||||
>
|
||||
<Icon
|
||||
as={BellIcon}
|
||||
boxSize={3.5}
|
||||
<Bell
|
||||
size={14}
|
||||
color={PROFESSIONAL_COLORS.gold[500]}
|
||||
/>
|
||||
<Text
|
||||
|
||||
@@ -12,10 +12,7 @@ import {
|
||||
useColorModeValue,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
} from '@chakra-ui/icons';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* 分页控制器组件(使用 React.memo 优化,避免不必要的重新渲染)
|
||||
@@ -116,7 +113,7 @@ const PaginationControl = React.memo(({ currentPage, totalPages, onPageChange })
|
||||
<HStack spacing={1.5} justify="center" flexWrap="wrap">
|
||||
{/* 上一页按钮 */}
|
||||
<IconButton
|
||||
icon={<ChevronLeftIcon />}
|
||||
icon={<ChevronLeft size={14} />}
|
||||
size="xs"
|
||||
onClick={() => onPageChange(currentPage - 1)}
|
||||
isDisabled={currentPage === 1}
|
||||
@@ -164,7 +161,7 @@ const PaginationControl = React.memo(({ currentPage, totalPages, onPageChange })
|
||||
|
||||
{/* 下一页按钮 */}
|
||||
<IconButton
|
||||
icon={<ChevronRightIcon />}
|
||||
icon={<ChevronRight size={14} />}
|
||||
size="xs"
|
||||
onClick={() => onPageChange(currentPage + 1)}
|
||||
isDisabled={currentPage === totalPages}
|
||||
|
||||
@@ -23,8 +23,7 @@ import {
|
||||
Tooltip,
|
||||
Button,
|
||||
} from "@chakra-ui/react";
|
||||
import { ChevronDownIcon, ChevronUpIcon, RepeatIcon } from "@chakra-ui/icons";
|
||||
import { FiTrendingUp, FiZap } from "react-icons/fi";
|
||||
import { ChevronDown, ChevronUp, RefreshCw, TrendingUp, Zap } from "lucide-react";
|
||||
import { FireOutlined } from "@ant-design/icons";
|
||||
import dayjs from "dayjs";
|
||||
import { Select } from "antd";
|
||||
@@ -363,7 +362,7 @@ const MainlineCard = React.memo(
|
||||
)}
|
||||
</VStack>
|
||||
<Icon
|
||||
as={isExpanded ? ChevronUpIcon : ChevronDownIcon}
|
||||
as={isExpanded ? ChevronUp : ChevronDown}
|
||||
boxSize={4}
|
||||
color={COLORS.secondaryTextColor}
|
||||
ml={2}
|
||||
@@ -744,7 +743,7 @@ const MainlineTimelineViewComponent = forwardRef(
|
||||
<VStack spacing={4}>
|
||||
<Text color="red.500">加载失败: {error}</Text>
|
||||
<IconButton
|
||||
icon={<RepeatIcon />}
|
||||
icon={<RefreshCw size={16} />}
|
||||
colorScheme="blue"
|
||||
onClick={fetchMainlineData}
|
||||
aria-label="重试"
|
||||
@@ -761,7 +760,7 @@ const MainlineTimelineViewComponent = forwardRef(
|
||||
<Box display={display} p={8} bg={COLORS.containerBg} minH="400px">
|
||||
<Center h="400px">
|
||||
<VStack spacing={4}>
|
||||
<Icon as={FiZap} boxSize={12} color="gray.400" />
|
||||
<Icon as={Zap} boxSize={12} color="gray.400" />
|
||||
<Text color={COLORS.secondaryTextColor}>暂无主线数据</Text>
|
||||
<Text fontSize="sm" color={COLORS.secondaryTextColor}>
|
||||
尝试调整筛选条件
|
||||
@@ -801,7 +800,7 @@ const MainlineTimelineViewComponent = forwardRef(
|
||||
>
|
||||
<HStack spacing={4}>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FiTrendingUp} color="blue.400" />
|
||||
<Icon as={TrendingUp} color="blue.400" />
|
||||
<Text fontWeight="bold" color={COLORS.textColor} fontSize="sm">
|
||||
{mainline_count} 条主线
|
||||
</Text>
|
||||
@@ -900,7 +899,7 @@ const MainlineTimelineViewComponent = forwardRef(
|
||||
/>
|
||||
<Tooltip label="全部展开">
|
||||
<IconButton
|
||||
icon={<ChevronDownIcon />}
|
||||
icon={<ChevronDown size={16} />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
color={COLORS.secondaryTextColor}
|
||||
@@ -911,7 +910,7 @@ const MainlineTimelineViewComponent = forwardRef(
|
||||
</Tooltip>
|
||||
<Tooltip label="全部折叠">
|
||||
<IconButton
|
||||
icon={<ChevronUpIcon />}
|
||||
icon={<ChevronUp size={16} />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
color={COLORS.secondaryTextColor}
|
||||
@@ -922,7 +921,7 @@ const MainlineTimelineViewComponent = forwardRef(
|
||||
</Tooltip>
|
||||
<Tooltip label="刷新">
|
||||
<IconButton
|
||||
icon={<RepeatIcon />}
|
||||
icon={<RefreshCw size={16} />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
color={COLORS.secondaryTextColor}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
useBreakpointValue,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import { InfoIcon } from '@chakra-ui/icons';
|
||||
import { Info } from 'lucide-react';
|
||||
import HorizontalDynamicNewsEventCard from '../../EventCard/HorizontalDynamicNewsEventCard';
|
||||
import EventDetailScrollPanel from '../EventDetailScrollPanel';
|
||||
import EventDetailModal from '../../EventDetailModal';
|
||||
@@ -134,7 +134,7 @@ const VerticalModeLayout = React.memo(({
|
||||
/* 空状态 */
|
||||
<Center h="100%" minH="400px">
|
||||
<VStack spacing={4}>
|
||||
<InfoIcon w={12} h={12} color="gray.400" />
|
||||
<Info size={48} color="gray.400" />
|
||||
<Text fontSize="lg" color="gray.500" textAlign="center">
|
||||
当前筛选条件下暂无数据
|
||||
</Text>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/views/Community/components/EventCard/atoms/EventFollowButton.js
|
||||
import React from 'react';
|
||||
import { IconButton, Box } from '@chakra-ui/react';
|
||||
import { AiFillStar, AiOutlineStar } from 'react-icons/ai';
|
||||
import { Star } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* 事件关注按钮组件
|
||||
@@ -39,17 +39,11 @@ const EventFollowButton = ({
|
||||
boxShadow: 'md'
|
||||
}}
|
||||
icon={
|
||||
isFollowing ? (
|
||||
<AiFillStar
|
||||
size={iconSize}
|
||||
color="gold"
|
||||
/>
|
||||
) : (
|
||||
<AiOutlineStar
|
||||
size={iconSize}
|
||||
color="gold"
|
||||
/>
|
||||
)
|
||||
<Star
|
||||
size={iconSize}
|
||||
color="gold"
|
||||
fill={isFollowing ? "currentColor" : "none"}
|
||||
/>
|
||||
}
|
||||
onClick={handleClick}
|
||||
aria-label={isFollowing ? '取消关注' : '关注'}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/views/Community/components/EventCard/atoms/EventImportanceBadge.js
|
||||
import React from 'react';
|
||||
import { Badge, Tooltip, VStack, HStack, Text, Divider, Circle } from '@chakra-ui/react';
|
||||
import { InfoIcon } from '@chakra-ui/icons';
|
||||
import { Info } from 'lucide-react';
|
||||
import { getImportanceConfig, getAllImportanceLevels } from '@constants/importanceLevels';
|
||||
|
||||
/**
|
||||
@@ -86,7 +86,7 @@ const EventImportanceBadge = ({
|
||||
gap={1}
|
||||
flexShrink={0}
|
||||
>
|
||||
{showIcon && <InfoIcon boxSize={2.5} />}
|
||||
{showIcon && <Info size={10} />}
|
||||
{importance || 'C'}级
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/views/Community/components/EventCard/EventStats.js
|
||||
import React from 'react';
|
||||
import { HStack, Text, Tooltip } from '@chakra-ui/react';
|
||||
import { ViewIcon, ChatIcon, StarIcon } from '@chakra-ui/icons';
|
||||
import { Eye, MessageCircle, Star } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* 事件统计信息组件(浏览量、帖子数、关注数)
|
||||
@@ -31,7 +31,7 @@ const EventStats = ({
|
||||
{/* 浏览量 */}
|
||||
<Tooltip label="浏览量" placement="top">
|
||||
<HStack spacing={1}>
|
||||
<ViewIcon boxSize={iconSize} />
|
||||
<Eye size={iconSize === '12px' ? 12 : 16} />
|
||||
<Text fontSize={fontSize}>{viewCount}</Text>
|
||||
</HStack>
|
||||
</Tooltip>
|
||||
@@ -39,7 +39,7 @@ const EventStats = ({
|
||||
{/* 帖子数 */}
|
||||
<Tooltip label="帖子数" placement="top">
|
||||
<HStack spacing={1}>
|
||||
<ChatIcon boxSize={iconSize} />
|
||||
<MessageCircle size={iconSize === '12px' ? 12 : 16} />
|
||||
<Text fontSize={fontSize}>{postCount}</Text>
|
||||
</HStack>
|
||||
</Tooltip>
|
||||
@@ -47,7 +47,7 @@ const EventStats = ({
|
||||
{/* 关注数 */}
|
||||
<Tooltip label="关注数" placement="top">
|
||||
<HStack spacing={1}>
|
||||
<StarIcon boxSize={iconSize} />
|
||||
<Star size={iconSize === '12px' ? 12 : 16} />
|
||||
<Text fontSize={fontSize}>{followerCount}</Text>
|
||||
</HStack>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Box, Text, VStack, Icon } from '@chakra-ui/react';
|
||||
import { FaChartLine } from 'react-icons/fa';
|
||||
import { LineChart } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* 预测报告组件 - 占位符
|
||||
@@ -16,7 +16,7 @@ const ForecastReport = ({ stockCode }) => {
|
||||
textAlign="center"
|
||||
>
|
||||
<VStack spacing={4}>
|
||||
<Icon as={FaChartLine} boxSize={12} color="gray.400" />
|
||||
<Icon as={LineChart} boxSize={12} color="gray.400" />
|
||||
<Text fontSize="lg" fontWeight="medium" color="gray.600" _dark={{ color: 'gray.400' }}>
|
||||
预测报告功能开发中
|
||||
</Text>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Box, Text, VStack, Icon } from '@chakra-ui/react';
|
||||
import { FaChartBar } from 'react-icons/fa';
|
||||
import { BarChart2 } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* 市场数据视图组件 - 占位符
|
||||
@@ -16,7 +16,7 @@ const MarketDataView = ({ stockCode }) => {
|
||||
textAlign="center"
|
||||
>
|
||||
<VStack spacing={4}>
|
||||
<Icon as={FaChartBar} boxSize={12} color="gray.400" />
|
||||
<Icon as={BarChart2} boxSize={12} color="gray.400" />
|
||||
<Text fontSize="lg" fontWeight="medium" color="gray.600" _dark={{ color: 'gray.400' }}>
|
||||
市场数据功能开发中
|
||||
</Text>
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
ModalFooter,
|
||||
useDisclosure,
|
||||
} from "@chakra-ui/react";
|
||||
import { ExternalLinkIcon } from "@chakra-ui/icons";
|
||||
import { ExternalLink } from "lucide-react";
|
||||
|
||||
import { useAnnouncementsData } from "../../hooks/useAnnouncementsData";
|
||||
import { THEME } from "../config";
|
||||
@@ -92,7 +92,7 @@ const AnnouncementsPanel: React.FC<AnnouncementsPanelProps> = ({ stockCode, isAc
|
||||
)}
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<ExternalLinkIcon />}
|
||||
icon={<ExternalLink size={16} />}
|
||||
variant="ghost"
|
||||
color={THEME.goldLight}
|
||||
aria-label="查看原文"
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
SimpleGrid,
|
||||
Center,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaSitemap, FaBuilding, FaCheckCircle, FaTimesCircle } from "react-icons/fa";
|
||||
import { GitBranch, Building2, CheckCircle, XCircle } from "lucide-react";
|
||||
|
||||
import { useBranchesData } from "../../hooks/useBranchesData";
|
||||
import { THEME } from "../config";
|
||||
@@ -85,7 +85,7 @@ const BranchesPanel: React.FC<BranchesPanelProps> = ({ stockCode, isActive = tru
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.2)"
|
||||
>
|
||||
<Icon as={FaSitemap} boxSize={10} color={THEME.gold} opacity={0.6} />
|
||||
<Icon as={GitBranch} boxSize={10} color={THEME.gold} opacity={0.6} />
|
||||
</Box>
|
||||
<Text color={THEME.textSecondary} fontSize="sm">
|
||||
暂无分支机构信息
|
||||
@@ -118,7 +118,7 @@ const BranchesPanel: React.FC<BranchesPanelProps> = ({ stockCode, isActive = tru
|
||||
borderRadius="md"
|
||||
bg="rgba(212, 175, 55, 0.1)"
|
||||
>
|
||||
<Icon as={FaBuilding} boxSize={3.5} color={THEME.gold} />
|
||||
<Icon as={Building2} boxSize={3.5} color={THEME.gold} />
|
||||
</Box>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
@@ -134,7 +134,7 @@ const BranchesPanel: React.FC<BranchesPanelProps> = ({ stockCode, isActive = tru
|
||||
{/* 状态徽章 */}
|
||||
<Box sx={getStatusBadgeStyles(isActive)}>
|
||||
<Icon
|
||||
as={isActive ? FaCheckCircle : FaTimesCircle}
|
||||
as={isActive ? CheckCircle : XCircle}
|
||||
boxSize={3}
|
||||
/>
|
||||
<Text>{branch.business_status}</Text>
|
||||
|
||||
@@ -12,15 +12,15 @@ import {
|
||||
Icon,
|
||||
} from "@chakra-ui/react";
|
||||
import {
|
||||
FaBuilding,
|
||||
FaMapMarkerAlt,
|
||||
FaIdCard,
|
||||
FaUsers,
|
||||
FaBalanceScale,
|
||||
FaCalculator,
|
||||
FaBriefcase,
|
||||
FaFileAlt,
|
||||
} from "react-icons/fa";
|
||||
Building2,
|
||||
MapPin,
|
||||
CreditCard,
|
||||
Users,
|
||||
Scale,
|
||||
Calculator,
|
||||
Briefcase,
|
||||
FileText,
|
||||
} from "lucide-react";
|
||||
|
||||
// 使用统一主题
|
||||
import { COLORS, GLASS, glassCardStyle } from "@views/Company/theme";
|
||||
@@ -173,27 +173,27 @@ const BusinessInfoPanel: React.FC<BusinessInfoPanelProps> = ({ stockCode, isActi
|
||||
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing={4}>
|
||||
{/* 工商信息卡片 */}
|
||||
<Box {...glassCardStyle} p={4}>
|
||||
<SectionTitle icon={FaBuilding} title="工商信息" />
|
||||
<SectionTitle icon={Building2} title="工商信息" />
|
||||
<VStack spacing={2} align="stretch">
|
||||
<InfoRow
|
||||
icon={FaIdCard}
|
||||
icon={CreditCard}
|
||||
label="信用代码"
|
||||
value={basicInfo.credit_code}
|
||||
isCode
|
||||
/>
|
||||
<InfoRow
|
||||
icon={FaUsers}
|
||||
icon={Users}
|
||||
label="公司规模"
|
||||
value={basicInfo.company_size}
|
||||
/>
|
||||
<InfoRow
|
||||
icon={FaMapMarkerAlt}
|
||||
icon={MapPin}
|
||||
label="注册地址"
|
||||
value={basicInfo.reg_address}
|
||||
isMultiline
|
||||
/>
|
||||
<InfoRow
|
||||
icon={FaMapMarkerAlt}
|
||||
icon={MapPin}
|
||||
label="办公地址"
|
||||
value={basicInfo.office_address}
|
||||
isMultiline
|
||||
@@ -203,15 +203,15 @@ const BusinessInfoPanel: React.FC<BusinessInfoPanelProps> = ({ stockCode, isActi
|
||||
|
||||
{/* 服务机构卡片 */}
|
||||
<Box {...glassCardStyle} p={4}>
|
||||
<SectionTitle icon={FaBalanceScale} title="服务机构" />
|
||||
<SectionTitle icon={Scale} title="服务机构" />
|
||||
<VStack spacing={3} align="stretch">
|
||||
<ServiceCard
|
||||
icon={FaCalculator}
|
||||
icon={Calculator}
|
||||
label="会计师事务所"
|
||||
value={basicInfo.accounting_firm}
|
||||
/>
|
||||
<ServiceCard
|
||||
icon={FaBalanceScale}
|
||||
icon={Scale}
|
||||
label="律师事务所"
|
||||
value={basicInfo.law_firm}
|
||||
/>
|
||||
@@ -222,12 +222,12 @@ const BusinessInfoPanel: React.FC<BusinessInfoPanelProps> = ({ stockCode, isActi
|
||||
{/* 下半部分:主营业务 + 经营范围 */}
|
||||
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing={4}>
|
||||
<TextSection
|
||||
icon={FaBriefcase}
|
||||
icon={Briefcase}
|
||||
title="主营业务"
|
||||
content={basicInfo.main_business}
|
||||
/>
|
||||
<TextSection
|
||||
icon={FaFileAlt}
|
||||
icon={FileText}
|
||||
title="经营范围"
|
||||
content={basicInfo.business_scope}
|
||||
/>
|
||||
|
||||
@@ -24,11 +24,11 @@ import {
|
||||
Td,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaShareAlt,
|
||||
FaUserTie,
|
||||
FaSitemap,
|
||||
FaInfoCircle,
|
||||
} from 'react-icons/fa';
|
||||
Share2,
|
||||
UserRound,
|
||||
GitBranch,
|
||||
Info,
|
||||
} from 'lucide-react';
|
||||
|
||||
// 深空 FUI 主题配置(与 SubTabContainer 保持一致)
|
||||
const DEEP_SPACE = {
|
||||
@@ -46,10 +46,10 @@ const DEEP_SPACE = {
|
||||
|
||||
// 导航配置(与主组件 config.ts 保持同步)
|
||||
const OVERVIEW_TABS = [
|
||||
{ key: 'shareholder', name: '股权结构', icon: FaShareAlt },
|
||||
{ key: 'management', name: '管理团队', icon: FaUserTie },
|
||||
{ key: 'branches', name: '分支机构', icon: FaSitemap },
|
||||
{ key: 'business', name: '工商信息', icon: FaInfoCircle },
|
||||
{ key: 'shareholder', name: '股权结构', icon: Share2 },
|
||||
{ key: 'management', name: '管理团队', icon: UserRound },
|
||||
{ key: 'branches', name: '分支机构', icon: GitBranch },
|
||||
{ key: 'business', name: '工商信息', icon: Info },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Icon,
|
||||
SimpleGrid,
|
||||
} from "@chakra-ui/react";
|
||||
import type { IconType } from "react-icons";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
import { THEME } from "../../config";
|
||||
import ManagementCard from "./ManagementCard";
|
||||
@@ -19,7 +19,7 @@ import type { ManagementPerson, ManagementCategory } from "./types";
|
||||
interface CategorySectionProps {
|
||||
category: ManagementCategory;
|
||||
people: ManagementPerson[];
|
||||
icon: IconType;
|
||||
icon: LucideIcon;
|
||||
color: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
Tag,
|
||||
} from "@chakra-ui/react";
|
||||
import {
|
||||
FaVenusMars,
|
||||
FaGraduationCap,
|
||||
FaPassport,
|
||||
} from "react-icons/fa";
|
||||
Users as GenderIcon,
|
||||
GraduationCap,
|
||||
CreditCard,
|
||||
} from "lucide-react";
|
||||
|
||||
import { THEME } from "../../config";
|
||||
import { formatDate } from "../../utils";
|
||||
@@ -53,7 +53,7 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ person, categoryColor }
|
||||
</Text>
|
||||
{person.gender && (
|
||||
<Icon
|
||||
as={FaVenusMars}
|
||||
as={GenderIcon}
|
||||
color={person.gender === "男" ? "blue.400" : "pink.400"}
|
||||
boxSize={3}
|
||||
/>
|
||||
@@ -69,7 +69,7 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ person, categoryColor }
|
||||
<HStack spacing={2} flexWrap="wrap">
|
||||
{person.education && (
|
||||
<Tag size="sm" bg={THEME.tableHoverBg} color={THEME.textSecondary}>
|
||||
<Icon as={FaGraduationCap} mr={1} boxSize={3} />
|
||||
<Icon as={GraduationCap} mr={1} boxSize={3} />
|
||||
{person.education}
|
||||
</Tag>
|
||||
)}
|
||||
@@ -80,7 +80,7 @@ const ManagementCard: React.FC<ManagementCardProps> = ({ person, categoryColor }
|
||||
)}
|
||||
{person.nationality && person.nationality !== "中国" && (
|
||||
<Tag size="sm" bg="orange.600" color="white">
|
||||
<Icon as={FaPassport} mr={1} boxSize={3} />
|
||||
<Icon as={CreditCard} mr={1} boxSize={3} />
|
||||
{person.nationality}
|
||||
</Tag>
|
||||
)}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
import React, { useMemo } from "react";
|
||||
import {
|
||||
FaUserTie,
|
||||
FaCrown,
|
||||
FaEye,
|
||||
FaUsers,
|
||||
} from "react-icons/fa";
|
||||
UserRound,
|
||||
Crown,
|
||||
Eye,
|
||||
Users,
|
||||
} from "lucide-react";
|
||||
|
||||
import { useManagementData } from "../../../hooks/useManagementData";
|
||||
import { THEME } from "../../config";
|
||||
@@ -31,10 +31,10 @@ interface ManagementPanelProps {
|
||||
* 分类配置映射
|
||||
*/
|
||||
const CATEGORY_CONFIG: Record<ManagementCategory, CategoryConfig> = {
|
||||
高管: { icon: FaUserTie, color: THEME.gold },
|
||||
董事: { icon: FaCrown, color: THEME.goldLight },
|
||||
监事: { icon: FaEye, color: "green.400" },
|
||||
其他: { icon: FaUsers, color: THEME.textSecondary },
|
||||
高管: { icon: UserRound, color: THEME.gold },
|
||||
董事: { icon: Crown, color: THEME.goldLight },
|
||||
监事: { icon: Eye, color: "green.400" },
|
||||
其他: { icon: Users, color: THEME.textSecondary },
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/views/Company/components/CompanyOverview/BasicInfoTab/components/management/types.ts
|
||||
// 管理团队相关类型定义
|
||||
|
||||
import type { IconType } from "react-icons";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
/**
|
||||
* 管理人员信息
|
||||
@@ -31,6 +31,6 @@ export type CategorizedManagement = Record<ManagementCategory, ManagementPerson[
|
||||
* 分类配置项
|
||||
*/
|
||||
export interface CategoryConfig {
|
||||
icon: IconType;
|
||||
icon: LucideIcon;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
// src/views/Company/components/CompanyOverview/BasicInfoTab/config.ts
|
||||
// Tab 配置 + 黑金主题配置
|
||||
|
||||
import { IconType } from "react-icons";
|
||||
import {
|
||||
FaShareAlt,
|
||||
FaUserTie,
|
||||
FaSitemap,
|
||||
FaInfoCircle,
|
||||
} from "react-icons/fa";
|
||||
import { LucideIcon, Share2, UserRound, GitBranch, Info } from "lucide-react";
|
||||
|
||||
// 主题类型定义
|
||||
export interface Theme {
|
||||
@@ -54,7 +48,7 @@ export const THEME: Theme = {
|
||||
export interface TabConfig {
|
||||
key: string;
|
||||
name: string;
|
||||
icon: IconType;
|
||||
icon: LucideIcon;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
@@ -63,25 +57,25 @@ export const TAB_CONFIG: TabConfig[] = [
|
||||
{
|
||||
key: "shareholder",
|
||||
name: "股权结构",
|
||||
icon: FaShareAlt,
|
||||
icon: Share2,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
key: "management",
|
||||
name: "管理团队",
|
||||
icon: FaUserTie,
|
||||
icon: UserRound,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
key: "branches",
|
||||
name: "分支机构",
|
||||
icon: FaSitemap,
|
||||
icon: GitBranch,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
key: "business",
|
||||
name: "工商信息",
|
||||
icon: FaInfoCircle,
|
||||
icon: Info,
|
||||
enabled: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
Tag,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaArrowUp, FaArrowDown } from 'react-icons/fa';
|
||||
import { ArrowUp, ArrowDown } from 'lucide-react';
|
||||
import type { KeyFactorCardProps, ImpactDirection } from '../types';
|
||||
|
||||
// 黑金主题样式常量
|
||||
@@ -94,7 +94,7 @@ const KeyFactorCard: React.FC<KeyFactorCardProps> = ({ factor }) => {
|
||||
color={factor.year_on_year > 0 ? 'red.400' : 'green.400'}
|
||||
>
|
||||
<Icon
|
||||
as={factor.year_on_year > 0 ? FaArrowUp : FaArrowDown}
|
||||
as={factor.year_on_year > 0 ? ArrowUp : ArrowDown}
|
||||
mr={1}
|
||||
boxSize={3}
|
||||
/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { HStack, VStack, Box, Text, Icon, Badge } from '@chakra-ui/react';
|
||||
import { FaArrowRight } from 'react-icons/fa';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
|
||||
// 黑金主题配置(使用更亮的金色提高对比度)
|
||||
const THEME = {
|
||||
@@ -133,7 +133,7 @@ const ProcessNavigation: React.FC<ProcessNavigationProps> = memo(({
|
||||
/>
|
||||
|
||||
<Icon
|
||||
as={FaArrowRight}
|
||||
as={ArrowRight}
|
||||
color={THEME.textSecondary}
|
||||
boxSize={4}
|
||||
/>
|
||||
@@ -148,7 +148,7 @@ const ProcessNavigation: React.FC<ProcessNavigationProps> = memo(({
|
||||
/>
|
||||
|
||||
<Icon
|
||||
as={FaArrowRight}
|
||||
as={ArrowRight}
|
||||
color={THEME.textSecondary}
|
||||
boxSize={4}
|
||||
/>
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
SimpleGrid,
|
||||
Button,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaIndustry, FaExpandAlt, FaCompressAlt } from 'react-icons/fa';
|
||||
import { Factory, Maximize2, Minimize2 } from 'lucide-react';
|
||||
import type { BusinessSegment } from '../types';
|
||||
|
||||
// 黑金主题配置
|
||||
@@ -52,7 +52,7 @@ const BusinessSegmentsCard: React.FC<BusinessSegmentsCardProps> = ({
|
||||
<Card bg={THEME.cardBg} shadow="md">
|
||||
<CardHeader>
|
||||
<HStack>
|
||||
<Icon as={FaIndustry} color={THEME.gold} />
|
||||
<Icon as={Factory} color={THEME.gold} />
|
||||
<Heading size="sm" color={THEME.textPrimary}>业务板块详情</Heading>
|
||||
<Badge bg={THEME.gold} color="gray.900">{businessSegments.length} 个板块</Badge>
|
||||
</HStack>
|
||||
@@ -74,7 +74,7 @@ const BusinessSegmentsCard: React.FC<BusinessSegmentsCardProps> = ({
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
leftIcon={
|
||||
<Icon as={isExpanded ? FaCompressAlt : FaExpandAlt} />
|
||||
<Icon as={isExpanded ? Minimize2 : Maximize2} />
|
||||
}
|
||||
onClick={() => onToggleSegment(idx)}
|
||||
color={THEME.gold}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Badge,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaChartPie } from 'react-icons/fa';
|
||||
import { PieChart } from 'lucide-react';
|
||||
import { BusinessTreeItem } from '../atoms';
|
||||
import type { BusinessStructure } from '../types';
|
||||
|
||||
@@ -42,7 +42,7 @@ const BusinessStructureCard: React.FC<BusinessStructureCardProps> = ({
|
||||
<Card bg={THEME.cardBg} shadow="md">
|
||||
<CardHeader>
|
||||
<HStack>
|
||||
<Icon as={FaChartPie} color={THEME.gold} />
|
||||
<Icon as={PieChart} color={THEME.gold} />
|
||||
<Heading size="sm" color={THEME.textPrimary}>业务结构分析</Heading>
|
||||
<Badge bg={THEME.gold} color="gray.900">{businessStructure[0]?.report_period}</Badge>
|
||||
</HStack>
|
||||
|
||||
@@ -33,17 +33,17 @@ import {
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaTrophy,
|
||||
FaCog,
|
||||
FaStar,
|
||||
FaChartLine,
|
||||
FaDollarSign,
|
||||
FaFlask,
|
||||
FaShieldAlt,
|
||||
FaRocket,
|
||||
FaUsers,
|
||||
FaExternalLinkAlt,
|
||||
} from 'react-icons/fa';
|
||||
Trophy,
|
||||
Settings,
|
||||
Star,
|
||||
TrendingUp,
|
||||
DollarSign,
|
||||
FlaskConical,
|
||||
Shield,
|
||||
Rocket,
|
||||
Users,
|
||||
ExternalLink,
|
||||
} from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import { ScoreBar } from '../atoms';
|
||||
import { getRadarChartOption } from '../utils/chartOptions';
|
||||
@@ -110,7 +110,7 @@ const CompetitorTags = memo<CompetitorTagsProps>(({ competitors }) => (
|
||||
color="yellow.500"
|
||||
borderRadius="full"
|
||||
>
|
||||
<Icon as={FaUsers} mr={1} />
|
||||
<Icon as={Users} mr={1} />
|
||||
<TagLabel>{competitor}</TagLabel>
|
||||
</Tag>
|
||||
))}
|
||||
@@ -127,14 +127,14 @@ interface ScoreSectionProps {
|
||||
|
||||
const ScoreSection = memo<ScoreSectionProps>(({ scores }) => (
|
||||
<VStack spacing={4} align="stretch">
|
||||
<ScoreBar label="市场地位" score={scores?.market_position} icon={FaTrophy} />
|
||||
<ScoreBar label="技术实力" score={scores?.technology} icon={FaCog} />
|
||||
<ScoreBar label="品牌价值" score={scores?.brand} icon={FaStar} />
|
||||
<ScoreBar label="运营效率" score={scores?.operation} icon={FaChartLine} />
|
||||
<ScoreBar label="财务健康" score={scores?.finance} icon={FaDollarSign} />
|
||||
<ScoreBar label="创新能力" score={scores?.innovation} icon={FaFlask} />
|
||||
<ScoreBar label="风险控制" score={scores?.risk} icon={FaShieldAlt} />
|
||||
<ScoreBar label="成长潜力" score={scores?.growth} icon={FaRocket} />
|
||||
<ScoreBar label="市场地位" score={scores?.market_position} icon={Trophy} />
|
||||
<ScoreBar label="技术实力" score={scores?.technology} icon={Settings} />
|
||||
<ScoreBar label="品牌价值" score={scores?.brand} icon={Star} />
|
||||
<ScoreBar label="运营效率" score={scores?.operation} icon={TrendingUp} />
|
||||
<ScoreBar label="财务健康" score={scores?.finance} icon={DollarSign} />
|
||||
<ScoreBar label="创新能力" score={scores?.innovation} icon={FlaskConical} />
|
||||
<ScoreBar label="风险控制" score={scores?.risk} icon={Shield} />
|
||||
<ScoreBar label="成长潜力" score={scores?.growth} icon={Rocket} />
|
||||
</VStack>
|
||||
));
|
||||
|
||||
@@ -201,7 +201,7 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = memo(
|
||||
<Card {...CARD_STYLES}>
|
||||
<CardHeader>
|
||||
<HStack>
|
||||
<Icon as={FaTrophy} color="yellow.500" />
|
||||
<Icon as={Trophy} color="yellow.500" />
|
||||
<Heading size="sm" color="yellow.500">竞争地位分析</Heading>
|
||||
{competitivePosition.ranking && (
|
||||
<Badge
|
||||
@@ -223,7 +223,7 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = memo(
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
color="yellow.500"
|
||||
rightIcon={<Icon as={FaExternalLinkAlt} boxSize={3} />}
|
||||
rightIcon={<Icon as={ExternalLink} boxSize={3} />}
|
||||
onClick={onOpen}
|
||||
_hover={{ bg: 'rgba(212, 175, 55, 0.1)' }}
|
||||
>
|
||||
@@ -269,7 +269,7 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = memo(
|
||||
<ModalContent {...MODAL_STYLES.content}>
|
||||
<ModalHeader {...MODAL_STYLES.header}>
|
||||
<HStack>
|
||||
<Icon as={FaTrophy} color="yellow.500" />
|
||||
<Icon as={Trophy} color="yellow.500" />
|
||||
<Text>行业排名详情</Text>
|
||||
</HStack>
|
||||
</ModalHeader>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Box, HStack, VStack, Icon, Text } from '@chakra-ui/react';
|
||||
import { FaUsers } from 'react-icons/fa';
|
||||
import { Users } from 'lucide-react';
|
||||
import { THEME, ICON_MAP, HIGHLIGHT_HOVER_STYLES } from '../theme';
|
||||
import type { InvestmentHighlightItem } from '../../../types';
|
||||
|
||||
@@ -13,7 +13,7 @@ interface HighlightCardProps {
|
||||
}
|
||||
|
||||
export const HighlightCard = memo<HighlightCardProps>(({ highlight }) => {
|
||||
const IconComponent = ICON_MAP[highlight.icon] || FaUsers;
|
||||
const IconComponent = ICON_MAP[highlight.icon] || Users;
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { HStack, Icon, Text } from '@chakra-ui/react';
|
||||
import type { IconType } from 'react-icons';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import { THEME } from '../theme';
|
||||
|
||||
interface SectionHeaderProps {
|
||||
icon: IconType;
|
||||
icon: LucideIcon;
|
||||
title: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
Grid,
|
||||
GridItem,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaCrown, FaStar, FaBriefcase } from 'react-icons/fa';
|
||||
import { Crown, Star, Briefcase } from 'lucide-react';
|
||||
import type {
|
||||
QualitativeAnalysis,
|
||||
InvestmentHighlightItem,
|
||||
@@ -57,7 +57,7 @@ const CorePositioningCard: React.FC<CorePositioningCardProps> = memo(
|
||||
<Card {...CARD_STYLES}>
|
||||
<CardBody>
|
||||
<VStack spacing={4} align="stretch">
|
||||
<SectionHeader icon={FaCrown} title="核心定位" />
|
||||
<SectionHeader icon={Crown} title="核心定位" />
|
||||
{corePositioning?.one_line_intro && (
|
||||
<Box
|
||||
p={4}
|
||||
@@ -74,7 +74,7 @@ const CorePositioningCard: React.FC<CorePositioningCardProps> = memo(
|
||||
<Grid templateColumns={GRID_COLUMNS.twoColumnMd} gap={4}>
|
||||
<GridItem>
|
||||
<Box p={4} bg={THEME.light.cardBg} borderRadius="lg">
|
||||
<SectionHeader icon={FaStar} title="投资亮点" />
|
||||
<SectionHeader icon={Star} title="投资亮点" />
|
||||
<Text
|
||||
fontSize="sm"
|
||||
color={THEME.light.subtextColor}
|
||||
@@ -89,7 +89,7 @@ const CorePositioningCard: React.FC<CorePositioningCardProps> = memo(
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<Box p={4} bg={THEME.light.cardBg} borderRadius="lg">
|
||||
<SectionHeader icon={FaBriefcase} title="商业模式" />
|
||||
<SectionHeader icon={Briefcase} title="商业模式" />
|
||||
<Text
|
||||
fontSize="sm"
|
||||
color={THEME.light.subtextColor}
|
||||
@@ -126,7 +126,7 @@ const CorePositioningCard: React.FC<CorePositioningCardProps> = memo(
|
||||
<VStack spacing={0} align="stretch">
|
||||
{/* 核心定位区域(深色背景) */}
|
||||
<Box p={6} bg={THEME.dark.bg}>
|
||||
<SectionHeader icon={FaCrown} title="核心定位" />
|
||||
<SectionHeader icon={Crown} title="核心定位" />
|
||||
|
||||
{/* 一句话介绍 */}
|
||||
{corePositioning?.one_line_intro && (
|
||||
@@ -152,7 +152,7 @@ const CorePositioningCard: React.FC<CorePositioningCardProps> = memo(
|
||||
borderRight={BORDER_RIGHT_RESPONSIVE}
|
||||
borderColor="whiteAlpha.100"
|
||||
>
|
||||
<SectionHeader icon={FaStar} title="投资亮点" />
|
||||
<SectionHeader icon={Star} title="投资亮点" />
|
||||
<VStack spacing={3} align="stretch">
|
||||
{highlights.length > 0 ? (
|
||||
highlights.map((highlight, idx) => (
|
||||
@@ -168,7 +168,7 @@ const CorePositioningCard: React.FC<CorePositioningCardProps> = memo(
|
||||
|
||||
{/* 商业模式区域 */}
|
||||
<GridItem p={6}>
|
||||
<SectionHeader icon={FaBriefcase} title="商业模式" />
|
||||
<SectionHeader icon={Briefcase} title="商业模式" />
|
||||
<Box
|
||||
p={4}
|
||||
bg={THEME.light.cardBg}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
FaUniversity,
|
||||
FaFire,
|
||||
FaUsers,
|
||||
FaChartLine,
|
||||
FaMicrochip,
|
||||
FaShieldAlt,
|
||||
} from 'react-icons/fa';
|
||||
import type { IconType } from 'react-icons';
|
||||
University,
|
||||
Flame,
|
||||
Users,
|
||||
TrendingUp,
|
||||
Cpu,
|
||||
Shield,
|
||||
type LucideIcon,
|
||||
} from 'lucide-react';
|
||||
|
||||
// ==================== 主题常量 ====================
|
||||
|
||||
@@ -39,13 +39,13 @@ export const THEME = {
|
||||
|
||||
// ==================== 图标映射 ====================
|
||||
|
||||
export const ICON_MAP: Record<string, IconType> = {
|
||||
bank: FaUniversity,
|
||||
fire: FaFire,
|
||||
users: FaUsers,
|
||||
'trending-up': FaChartLine,
|
||||
cpu: FaMicrochip,
|
||||
'shield-check': FaShieldAlt,
|
||||
export const ICON_MAP: Record<string, LucideIcon> = {
|
||||
bank: University,
|
||||
fire: Flame,
|
||||
users: Users,
|
||||
'trending-up': TrendingUp,
|
||||
cpu: Cpu,
|
||||
'shield-check': Shield,
|
||||
};
|
||||
|
||||
// ==================== 样式常量 ====================
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
AccordionPanel,
|
||||
AccordionIcon,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaBalanceScale } from 'react-icons/fa';
|
||||
import { Scale } from 'lucide-react';
|
||||
import { KeyFactorCard } from '../atoms';
|
||||
import type { KeyFactors } from '../types';
|
||||
|
||||
@@ -66,7 +66,7 @@ const KeyFactorsCard: React.FC<KeyFactorsCardProps> = ({ keyFactors }) => {
|
||||
<Card {...CARD_STYLES} h="full">
|
||||
<CardHeader>
|
||||
<HStack>
|
||||
<Icon as={FaBalanceScale} color="yellow.500" />
|
||||
<Icon as={Scale} color="yellow.500" />
|
||||
<Heading size="sm" color={THEME.titleColor}>
|
||||
关键因素
|
||||
</Heading>
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
GridItem,
|
||||
Center,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaRocket, FaChartBar } from 'react-icons/fa';
|
||||
import { Rocket, BarChart2 } from 'lucide-react';
|
||||
import type { Strategy } from '../types';
|
||||
|
||||
// 样式常量 - 避免每次渲染创建新对象
|
||||
@@ -54,7 +54,7 @@ const EmptyState = memo(() => (
|
||||
<Box {...EMPTY_BOX_STYLES}>
|
||||
<Center>
|
||||
<VStack spacing={3}>
|
||||
<Icon as={FaChartBar} boxSize={10} color="yellow.600" />
|
||||
<Icon as={BarChart2} boxSize={10} color="yellow.600" />
|
||||
<Text fontWeight="medium">战略数据更新中</Text>
|
||||
<Text fontSize="sm" color="gray.500">
|
||||
战略方向和具体举措数据将在近期更新
|
||||
@@ -97,7 +97,7 @@ const StrategyAnalysisCard: React.FC<StrategyAnalysisCardProps> = memo(
|
||||
<Card {...CARD_STYLES}>
|
||||
<CardHeader>
|
||||
<HStack>
|
||||
<Icon as={FaRocket} color="yellow.500" />
|
||||
<Icon as={Rocket} color="yellow.500" />
|
||||
<Heading size="sm" color="yellow.500">战略分析</Heading>
|
||||
</HStack>
|
||||
</CardHeader>
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Box,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaHistory } from 'react-icons/fa';
|
||||
import { History } from 'lucide-react';
|
||||
import TimelineComponent from '../organisms/TimelineComponent';
|
||||
import type { DevelopmentTimeline } from '../types';
|
||||
|
||||
@@ -59,7 +59,7 @@ const TimelineCard: React.FC<TimelineCardProps> = ({ developmentTimeline }) => {
|
||||
<Card {...CARD_STYLES} h="full">
|
||||
<CardHeader>
|
||||
<HStack>
|
||||
<Icon as={FaHistory} color="yellow.500" />
|
||||
<Icon as={History} color="yellow.500" />
|
||||
<Heading size="sm" color={THEME.titleColor}>
|
||||
发展时间线
|
||||
</Heading>
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
Box,
|
||||
Flex,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaNetworkWired } from 'react-icons/fa';
|
||||
import { Network } from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import {
|
||||
ProcessNavigation,
|
||||
@@ -133,7 +133,7 @@ const ValueChainCard: React.FC<ValueChainCardProps> = memo(({
|
||||
{/* 头部区域 */}
|
||||
<CardHeader py={0}>
|
||||
<HStack flexWrap="wrap" gap={0}>
|
||||
<Icon as={FaNetworkWired} color={THEME.gold} />
|
||||
<Icon as={Network} color={THEME.gold} />
|
||||
<Heading size="sm" color={THEME.textPrimary}>
|
||||
产业链分析
|
||||
</Heading>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { Card, CardBody } from '@chakra-ui/react';
|
||||
import { FaBrain, FaBuilding, FaLink, FaHistory } from 'react-icons/fa';
|
||||
import { Brain, Building2, Link2, History } from 'lucide-react';
|
||||
import SubTabContainer, { type SubTabConfig } from '@components/SubTabContainer';
|
||||
import LoadingState from '../../LoadingState';
|
||||
import { StrategyTab, BusinessTab, ValueChainTab, DevelopmentTab } from './tabs';
|
||||
@@ -28,10 +28,10 @@ const THEME = {
|
||||
* Tab 配置
|
||||
*/
|
||||
const DEEP_ANALYSIS_TABS: SubTabConfig[] = [
|
||||
{ key: 'strategy', name: '战略分析', icon: FaBrain, component: StrategyTab },
|
||||
{ key: 'business', name: '业务结构', icon: FaBuilding, component: BusinessTab },
|
||||
{ key: 'valueChain', name: '产业链', icon: FaLink, component: ValueChainTab },
|
||||
{ key: 'development', name: '发展历程', icon: FaHistory, component: DevelopmentTab },
|
||||
{ key: 'strategy', name: '战略分析', icon: Brain, component: StrategyTab },
|
||||
{ key: 'business', name: '业务结构', icon: Building2, component: BusinessTab },
|
||||
{ key: 'valueChain', name: '产业链', icon: Link2, component: ValueChainTab },
|
||||
{ key: 'development', name: '发展历程', icon: History, component: DevelopmentTab },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
Icon,
|
||||
Button,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaCheckCircle, FaExclamationCircle } from 'react-icons/fa';
|
||||
import { CheckCircle, AlertCircle } from 'lucide-react';
|
||||
import type { TimelineEvent } from '../../types';
|
||||
|
||||
interface EventDetailModalProps {
|
||||
@@ -48,7 +48,7 @@ const EventDetailModal: React.FC<EventDetailModalProps> = ({
|
||||
<ModalHeader>
|
||||
<HStack>
|
||||
<Icon
|
||||
as={isPositive ? FaCheckCircle : FaExclamationCircle}
|
||||
as={isPositive ? CheckCircle : AlertCircle}
|
||||
color={isPositive ? 'red.500' : 'green.500'}
|
||||
boxSize={6}
|
||||
/>
|
||||
|
||||
@@ -20,10 +20,10 @@ import {
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaCalendarAlt,
|
||||
FaArrowUp,
|
||||
FaArrowDown,
|
||||
} from 'react-icons/fa';
|
||||
Calendar,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
} from 'lucide-react';
|
||||
import EventDetailModal from './EventDetailModal';
|
||||
import type { TimelineComponentProps, TimelineEvent } from '../../types';
|
||||
|
||||
@@ -74,7 +74,7 @@ const TimelineComponent: React.FC<TimelineComponentProps> = ({ events }) => {
|
||||
shadow="md"
|
||||
>
|
||||
<Icon
|
||||
as={isPositive ? FaArrowUp : FaArrowDown}
|
||||
as={isPositive ? ArrowUp : ArrowDown}
|
||||
color="white"
|
||||
boxSize={3}
|
||||
/>
|
||||
@@ -108,7 +108,7 @@ const TimelineComponent: React.FC<TimelineComponentProps> = ({ events }) => {
|
||||
</Text>
|
||||
<HStack spacing={2}>
|
||||
<Icon
|
||||
as={FaCalendarAlt}
|
||||
as={Calendar}
|
||||
boxSize={3}
|
||||
color="gray.500"
|
||||
/>
|
||||
|
||||
@@ -34,19 +34,19 @@ import {
|
||||
Tooltip,
|
||||
Button,
|
||||
} from '@chakra-ui/react';
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
FaBuilding,
|
||||
FaHandshake,
|
||||
FaUserTie,
|
||||
FaIndustry,
|
||||
FaCog,
|
||||
FaNetworkWired,
|
||||
FaFlask,
|
||||
FaStar,
|
||||
FaArrowRight,
|
||||
FaArrowLeft,
|
||||
} from 'react-icons/fa';
|
||||
ExternalLink,
|
||||
Building,
|
||||
Handshake,
|
||||
UserCircle,
|
||||
Factory,
|
||||
Settings,
|
||||
Network,
|
||||
FlaskConical,
|
||||
Star,
|
||||
ArrowRight,
|
||||
ArrowLeft,
|
||||
} from 'lucide-react';
|
||||
import type { ValueChainNode, RelatedCompany } from '../../types';
|
||||
|
||||
interface RelatedCompaniesModalProps {
|
||||
@@ -64,15 +64,15 @@ interface RelatedCompaniesModalProps {
|
||||
*/
|
||||
const getNodeTypeIcon = (type: string) => {
|
||||
const icons: Record<string, React.ComponentType> = {
|
||||
company: FaBuilding,
|
||||
supplier: FaHandshake,
|
||||
customer: FaUserTie,
|
||||
product: FaIndustry,
|
||||
service: FaCog,
|
||||
channel: FaNetworkWired,
|
||||
raw_material: FaFlask,
|
||||
company: Building,
|
||||
supplier: Handshake,
|
||||
customer: UserCircle,
|
||||
product: Factory,
|
||||
service: Settings,
|
||||
channel: Network,
|
||||
raw_material: FlaskConical,
|
||||
};
|
||||
return icons[type] || FaBuilding;
|
||||
return icons[type] || Building;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -242,7 +242,7 @@ const RelatedCompaniesModal: React.FC<RelatedCompaniesModalProps> = ({
|
||||
</VStack>
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<ExternalLinkIcon />}
|
||||
icon={<ExternalLink size={16} />}
|
||||
variant="ghost"
|
||||
colorScheme="blue"
|
||||
onClick={() => {
|
||||
@@ -287,8 +287,8 @@ const RelatedCompaniesModal: React.FC<RelatedCompaniesModalProps> = ({
|
||||
<Icon
|
||||
as={
|
||||
rel.role === 'source'
|
||||
? FaArrowRight
|
||||
: FaArrowLeft
|
||||
? ArrowRight
|
||||
: ArrowLeft
|
||||
}
|
||||
color={
|
||||
rel.role === 'source'
|
||||
@@ -323,7 +323,7 @@ const RelatedCompaniesModal: React.FC<RelatedCompaniesModalProps> = ({
|
||||
) : (
|
||||
<Center py={4}>
|
||||
<VStack spacing={2}>
|
||||
<Icon as={FaBuilding} boxSize={8} color="gray.300" />
|
||||
<Icon as={Building} boxSize={8} color="gray.300" />
|
||||
<Text fontSize="sm" color="gray.500">
|
||||
暂无相关公司
|
||||
</Text>
|
||||
|
||||
@@ -22,15 +22,15 @@ import {
|
||||
ScaleFade,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaBuilding,
|
||||
FaHandshake,
|
||||
FaUserTie,
|
||||
FaIndustry,
|
||||
FaCog,
|
||||
FaNetworkWired,
|
||||
FaFlask,
|
||||
FaStar,
|
||||
} from 'react-icons/fa';
|
||||
Building,
|
||||
Handshake,
|
||||
UserCircle,
|
||||
Factory,
|
||||
Settings,
|
||||
Network,
|
||||
FlaskConical,
|
||||
Star,
|
||||
} from 'lucide-react';
|
||||
import { logger } from '@utils/logger';
|
||||
import axios from '@utils/axiosConfig';
|
||||
import RelatedCompaniesModal from './RelatedCompaniesModal';
|
||||
@@ -71,17 +71,17 @@ const THEME = {
|
||||
*/
|
||||
const getNodeTypeIcon = (type: string) => {
|
||||
const icons: Record<string, React.ComponentType> = {
|
||||
company: FaBuilding,
|
||||
supplier: FaHandshake,
|
||||
customer: FaUserTie,
|
||||
product: FaIndustry,
|
||||
service: FaCog,
|
||||
channel: FaNetworkWired,
|
||||
raw_material: FaFlask,
|
||||
regulator: FaBuilding,
|
||||
end_user: FaUserTie,
|
||||
company: Building,
|
||||
supplier: Handshake,
|
||||
customer: UserCircle,
|
||||
product: Factory,
|
||||
service: Settings,
|
||||
channel: Network,
|
||||
raw_material: FlaskConical,
|
||||
regulator: Building,
|
||||
end_user: UserCircle,
|
||||
};
|
||||
return icons[type] || FaBuilding;
|
||||
return icons[type] || Building;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -195,7 +195,7 @@ const ValueChainNodeCard: React.FC<ValueChainNodeCardProps> = memo(({
|
||||
node.importance_score >= 70 && (
|
||||
<Tooltip label="重要节点">
|
||||
<span>
|
||||
<Icon as={FaStar} color={THEME.gold} boxSize={4} />
|
||||
<Icon as={Star} color={THEME.gold} boxSize={4} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
StatNumber,
|
||||
StatHelpText,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaCrown } from "react-icons/fa";
|
||||
import { Crown } from "lucide-react";
|
||||
import type { ActualControl } from "../../types";
|
||||
import { THEME } from "../../BasicInfoTab/config";
|
||||
|
||||
@@ -58,7 +58,7 @@ const ActualControlCard: React.FC<ActualControlCardProps> = ({ actualControl = [
|
||||
return (
|
||||
<Box>
|
||||
<HStack mb={4}>
|
||||
<Icon as={FaCrown} color={THEME.gold} boxSize={5} />
|
||||
<Icon as={Crown} color={THEME.gold} boxSize={5} />
|
||||
<Heading size="sm" color={THEME.gold}>实际控制人</Heading>
|
||||
</HStack>
|
||||
<Card bg={THEME.cardBg} borderColor={THEME.border} borderWidth="1px">
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
CardHeader,
|
||||
SimpleGrid,
|
||||
} from "@chakra-ui/react";
|
||||
import { FaChartPie, FaArrowUp, FaArrowDown } from "react-icons/fa";
|
||||
import { PieChart, ArrowUp, ArrowDown } from "lucide-react";
|
||||
import { echarts, type ECharts, type EChartsOption } from '@lib/echarts';
|
||||
import type { Concentration } from "../../types";
|
||||
import { THEME } from "../../BasicInfoTab/config";
|
||||
@@ -182,7 +182,7 @@ const ConcentrationCard: React.FC<ConcentrationCardProps> = ({ concentration = [
|
||||
return (
|
||||
<Box>
|
||||
<HStack mb={4}>
|
||||
<Icon as={FaChartPie} color={THEME.gold} boxSize={5} />
|
||||
<Icon as={PieChart} color={THEME.gold} boxSize={5} />
|
||||
<Heading size="sm" color={THEME.gold}>股权集中度</Heading>
|
||||
</HStack>
|
||||
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={4}>
|
||||
@@ -208,7 +208,7 @@ const ConcentrationCard: React.FC<ConcentrationCardProps> = ({ concentration = [
|
||||
colorScheme={item.ratio_change > 0 ? "red" : "green"}
|
||||
>
|
||||
<Icon
|
||||
as={item.ratio_change > 0 ? FaArrowUp : FaArrowDown}
|
||||
as={item.ratio_change > 0 ? ArrowUp : ArrowDown}
|
||||
mr={1}
|
||||
boxSize={3}
|
||||
/>
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, { useMemo, memo } from "react";
|
||||
import { Box, HStack, Heading, Badge, Icon, useBreakpointValue } from "@chakra-ui/react";
|
||||
import { Table, Tag, Tooltip, ConfigProvider } from "antd";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import { FaUsers, FaChartLine } from "react-icons/fa";
|
||||
import { Users, LineChart } from "lucide-react";
|
||||
import type { Shareholder } from "../../types";
|
||||
import { THEME } from "../../BasicInfoTab/config";
|
||||
|
||||
@@ -96,7 +96,7 @@ const ShareholdersTable: React.FC<ShareholdersTableProps> = ({
|
||||
if (type === "circulation") {
|
||||
return {
|
||||
title: title || "十大流通股东",
|
||||
icon: FaChartLine,
|
||||
icon: LineChart,
|
||||
iconColor: "purple.500",
|
||||
ratioField: "circulation_share_ratio" as keyof Shareholder,
|
||||
ratioLabel: "流通股比例",
|
||||
@@ -106,7 +106,7 @@ const ShareholdersTable: React.FC<ShareholdersTableProps> = ({
|
||||
}
|
||||
return {
|
||||
title: title || "十大股东",
|
||||
icon: FaUsers,
|
||||
icon: Users,
|
||||
iconColor: "green.500",
|
||||
ratioField: "total_share_ratio" as keyof Shareholder,
|
||||
ratioLabel: "持股比例",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Center, VStack, Icon, Text } from '@chakra-ui/react';
|
||||
import { FaNewspaper } from 'react-icons/fa';
|
||||
import { Newspaper } from 'lucide-react';
|
||||
import type { NewsEmptyStateProps } from '../types';
|
||||
|
||||
const NewsEmptyState: React.FC<NewsEmptyStateProps> = ({
|
||||
@@ -15,7 +15,7 @@ const NewsEmptyState: React.FC<NewsEmptyStateProps> = ({
|
||||
<Center h="400px">
|
||||
<VStack spacing={3}>
|
||||
<Icon
|
||||
as={FaNewspaper}
|
||||
as={Newspaper}
|
||||
boxSize={16}
|
||||
color={isBlackGold ? theme.gold : 'gray.300'}
|
||||
opacity={0.5}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
CardBody,
|
||||
Tag,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaEye, FaFire, FaChartLine } from 'react-icons/fa';
|
||||
import { Eye, Flame, TrendingUp } from 'lucide-react';
|
||||
import type { NewsEventCardProps } from '../types';
|
||||
import {
|
||||
getEventTypeIcon,
|
||||
@@ -117,7 +117,7 @@ const NewsEventCard: React.FC<NewsEventCardProps> = ({
|
||||
<HStack spacing={3}>
|
||||
{event.view_count !== undefined && (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaEye} boxSize={3} color={theme.textMuted} />
|
||||
<Icon as={Eye} boxSize={3} color={theme.textMuted} />
|
||||
<Text fontSize="xs" color={theme.textMuted}>
|
||||
{event.view_count}
|
||||
</Text>
|
||||
@@ -125,7 +125,7 @@ const NewsEventCard: React.FC<NewsEventCardProps> = ({
|
||||
)}
|
||||
{event.hot_score !== undefined && (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaFire} boxSize={3} color={theme.goldLight} />
|
||||
<Icon as={Flame} boxSize={3} color={theme.goldLight} />
|
||||
<Text fontSize="xs" color={theme.textMuted}>
|
||||
{event.hot_score.toFixed(1)}
|
||||
</Text>
|
||||
@@ -152,7 +152,7 @@ const NewsEventCard: React.FC<NewsEventCardProps> = ({
|
||||
<Box pt={2} borderTop="1px" borderColor={theme.cardBorder}>
|
||||
<HStack spacing={6} flexWrap="wrap">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaChartLine} boxSize={3} color={theme.textMuted} />
|
||||
<Icon as={TrendingUp} boxSize={3} color={theme.textMuted} />
|
||||
<Text fontSize="xs" color={theme.textMuted} fontWeight="medium">
|
||||
相关涨跌:
|
||||
</Text>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { Box, HStack, Text, Button, Icon } from '@chakra-ui/react';
|
||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import type { NewsPaginationProps } from '../types';
|
||||
|
||||
const NewsPagination: React.FC<NewsPaginationProps> = ({
|
||||
@@ -87,7 +87,7 @@ const NewsPagination: React.FC<NewsPaginationProps> = ({
|
||||
_hover={{ bg: theme.cardHoverBg, borderColor: theme.gold }}
|
||||
onClick={() => onPageChange(1)}
|
||||
isDisabled={!has_prev || isLoading}
|
||||
leftIcon={<Icon as={FaChevronLeft} />}
|
||||
leftIcon={<Icon as={ChevronLeft} />}
|
||||
>
|
||||
首页
|
||||
</Button>
|
||||
@@ -128,7 +128,7 @@ const NewsPagination: React.FC<NewsPaginationProps> = ({
|
||||
_hover={{ bg: theme.cardHoverBg, borderColor: theme.gold }}
|
||||
onClick={() => onPageChange(totalPages)}
|
||||
isDisabled={!has_next || isLoading}
|
||||
rightIcon={<Icon as={FaChevronRight} />}
|
||||
rightIcon={<Icon as={ChevronRight} />}
|
||||
>
|
||||
末页
|
||||
</Button>
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { HStack, Input, InputGroup, InputLeftElement, Button, Text, Icon } from '@chakra-ui/react';
|
||||
import { SearchIcon } from '@chakra-ui/icons';
|
||||
import { FaNewspaper } from 'react-icons/fa';
|
||||
import { Search, Newspaper } from 'lucide-react';
|
||||
import type { NewsSearchBarProps } from '../types';
|
||||
|
||||
const NewsSearchBar: React.FC<NewsSearchBarProps> = ({
|
||||
@@ -31,7 +30,7 @@ const NewsSearchBar: React.FC<NewsSearchBarProps> = ({
|
||||
<HStack flex={1} minW="300px">
|
||||
<InputGroup>
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<SearchIcon color={theme.textMuted} />
|
||||
<Search size={16} color={theme.textMuted} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
placeholder="搜索相关新闻..."
|
||||
@@ -60,7 +59,7 @@ const NewsSearchBar: React.FC<NewsSearchBarProps> = ({
|
||||
|
||||
{total > 0 && (
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FaNewspaper} color={theme.gold} />
|
||||
<Icon as={Newspaper} color={theme.gold} />
|
||||
<Text fontSize="sm" color={theme.textSecondary}>
|
||||
共找到{' '}
|
||||
<Text as="span" fontWeight="bold" color={theme.gold}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/views/Company/components/DynamicTracking/NewsEventsTab/types.ts
|
||||
// 新闻动态 - 类型定义
|
||||
|
||||
import type { IconType } from 'react-icons';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* 徽章样式配置
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// src/views/Company/components/DynamicTracking/NewsEventsTab/utils.ts
|
||||
// 新闻动态 - 工具函数
|
||||
|
||||
import type { IconType } from 'react-icons';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import {
|
||||
FaNewspaper,
|
||||
FaBullhorn,
|
||||
FaGavel,
|
||||
FaFlask,
|
||||
FaDollarSign,
|
||||
FaShieldAlt,
|
||||
FaFileAlt,
|
||||
FaIndustry,
|
||||
} from 'react-icons/fa';
|
||||
Newspaper,
|
||||
Megaphone,
|
||||
Gavel,
|
||||
FlaskConical,
|
||||
DollarSign,
|
||||
Shield,
|
||||
FileText,
|
||||
Factory,
|
||||
} from 'lucide-react';
|
||||
import type { ThemeConfig, BadgeStyle } from './types';
|
||||
|
||||
/**
|
||||
* 事件类型图标映射
|
||||
*/
|
||||
const EVENT_TYPE_ICONS: Record<string, IconType> = {
|
||||
企业公告: FaBullhorn,
|
||||
政策: FaGavel,
|
||||
技术突破: FaFlask,
|
||||
企业融资: FaDollarSign,
|
||||
政策监管: FaShieldAlt,
|
||||
政策动态: FaFileAlt,
|
||||
行业事件: FaIndustry,
|
||||
const EVENT_TYPE_ICONS: Record<string, LucideIcon> = {
|
||||
企业公告: Megaphone,
|
||||
政策: Gavel,
|
||||
技术突破: FlaskConical,
|
||||
企业融资: DollarSign,
|
||||
政策监管: Shield,
|
||||
政策动态: FileText,
|
||||
行业事件: Factory,
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取事件类型对应的图标
|
||||
*/
|
||||
export const getEventTypeIcon = (eventType?: string): IconType => {
|
||||
if (!eventType) return FaNewspaper;
|
||||
return EVENT_TYPE_ICONS[eventType] || FaNewspaper;
|
||||
export const getEventTypeIcon = (eventType?: string): LucideIcon => {
|
||||
if (!eventType) return Newspaper;
|
||||
return EVENT_TYPE_ICONS[eventType] || Newspaper;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
Card,
|
||||
CardBody,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaNewspaper, FaBullhorn, FaCalendarAlt, FaChartBar } from 'react-icons/fa';
|
||||
import { Newspaper, Megaphone, Calendar, BarChart2 } from 'lucide-react';
|
||||
|
||||
// 深空 FUI 主题配置(与 SubTabContainer 保持一致)
|
||||
const DEEP_SPACE = {
|
||||
@@ -35,10 +35,10 @@ const DEEP_SPACE = {
|
||||
|
||||
// 导航配置(与主组件保持同步)
|
||||
const TRACKING_TABS = [
|
||||
{ key: 'news', name: '新闻动态', icon: FaNewspaper },
|
||||
{ key: 'announcements', name: '公司公告', icon: FaBullhorn },
|
||||
{ key: 'disclosure', name: '财报披露日程', icon: FaCalendarAlt },
|
||||
{ key: 'forecast', name: '业绩预告', icon: FaChartBar },
|
||||
{ key: 'news', name: '新闻动态', icon: Newspaper },
|
||||
{ key: 'announcements', name: '公司公告', icon: Megaphone },
|
||||
{ key: 'disclosure', name: '财报披露日程', icon: Calendar },
|
||||
{ key: 'forecast', name: '业绩预告', icon: BarChart2 },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import React, { useState, useEffect, useMemo, useCallback, memo, lazy } from 'react';
|
||||
import { Card, CardBody } from '@chakra-ui/react';
|
||||
import { FaNewspaper, FaBullhorn, FaCalendarAlt, FaChartBar } from 'react-icons/fa';
|
||||
import { Newspaper, Megaphone, Calendar, BarChart2 } from 'lucide-react';
|
||||
|
||||
import SubTabContainer from '@components/SubTabContainer';
|
||||
import {
|
||||
@@ -29,28 +29,28 @@ const TRACKING_TABS = [
|
||||
{
|
||||
key: 'news',
|
||||
name: '新闻动态',
|
||||
icon: FaNewspaper,
|
||||
icon: Newspaper,
|
||||
component: NewsPanel,
|
||||
fallback: <NewsPanelSkeleton />,
|
||||
},
|
||||
{
|
||||
key: 'announcements',
|
||||
name: '公司公告',
|
||||
icon: FaBullhorn,
|
||||
icon: Megaphone,
|
||||
component: AnnouncementsPanel,
|
||||
fallback: <AnnouncementsSkeleton />,
|
||||
},
|
||||
{
|
||||
key: 'disclosure',
|
||||
name: '财报披露日程',
|
||||
icon: FaCalendarAlt,
|
||||
icon: Calendar,
|
||||
component: DisclosureSchedulePanel,
|
||||
fallback: <DisclosureScheduleSkeleton />,
|
||||
},
|
||||
{
|
||||
key: 'forecast',
|
||||
name: '业绩预告',
|
||||
icon: FaChartBar,
|
||||
icon: BarChart2,
|
||||
component: ForecastPanel,
|
||||
fallback: <ForecastPanelSkeleton />,
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
Grid,
|
||||
GridItem,
|
||||
} from '@chakra-ui/react';
|
||||
import { ArrowUpIcon, ArrowDownIcon } from '@chakra-ui/icons';
|
||||
import { ArrowUp, ArrowDown } from 'lucide-react';
|
||||
import { useToast } from '@chakra-ui/react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import { logger } from '@utils/logger';
|
||||
@@ -166,8 +166,8 @@ export const StockComparison: React.FC<StockComparisonProps> = ({
|
||||
<Td isNumeric color={diffColor}>
|
||||
{diff !== null ? (
|
||||
<HStack spacing={1} justify="flex-end">
|
||||
{diff > 0 && <ArrowUpIcon boxSize={3} />}
|
||||
{diff < 0 && <ArrowDownIcon boxSize={3} />}
|
||||
{diff > 0 && <ArrowUp size={12} />}
|
||||
{diff < 0 && <ArrowDown size={12} />}
|
||||
<Text>
|
||||
{metric.format === 'percent'
|
||||
? `${Math.abs(diff).toFixed(2)}pp`
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import { formatUtils } from '@services/financialService';
|
||||
import { alpha, fui, chartTheme } from '@views/Company/theme';
|
||||
|
||||
interface ChartDataItem {
|
||||
period: string;
|
||||
@@ -106,22 +107,22 @@ export const getComparisonChartOption = (
|
||||
text: '营收与利润趋势',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#D4AF37',
|
||||
color: fui.gold,
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(26, 32, 44, 0.95)',
|
||||
borderColor: 'rgba(212, 175, 55, 0.3)',
|
||||
backgroundColor: chartTheme.tooltip.bg,
|
||||
borderColor: chartTheme.tooltip.border,
|
||||
textStyle: {
|
||||
color: '#E2E8F0',
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: 'rgba(212, 175, 55, 0.5)',
|
||||
color: alpha('gold', 0.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -144,7 +145,7 @@ export const getComparisonChartOption = (
|
||||
data: revenueData.map((d) => d.period),
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(212, 175, 55, 0.3)',
|
||||
color: chartTheme.axisLine,
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
@@ -161,7 +162,7 @@ export const getComparisonChartOption = (
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(212, 175, 55, 0.3)',
|
||||
color: chartTheme.axisLine,
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
@@ -169,7 +170,7 @@ export const getComparisonChartOption = (
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(212, 175, 55, 0.1)',
|
||||
color: chartTheme.splitLine,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -182,7 +183,7 @@ export const getComparisonChartOption = (
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(212, 175, 55, 0.3)',
|
||||
color: chartTheme.axisLine,
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
@@ -201,7 +202,7 @@ export const getComparisonChartOption = (
|
||||
itemStyle: {
|
||||
color: (params: { dataIndex: number; value: number }) => {
|
||||
const idx = params.dataIndex;
|
||||
if (idx === 0) return '#D4AF37'; // 金色作为基准
|
||||
if (idx === 0) return fui.gold; // 金色作为基准
|
||||
const prevValue = revenueData[idx - 1].value;
|
||||
const currValue = params.value;
|
||||
// 红涨绿跌
|
||||
@@ -215,37 +216,18 @@ export const getComparisonChartOption = (
|
||||
yAxisIndex: 1,
|
||||
data: profitData.map((d) => d.value?.toFixed(2)),
|
||||
smooth: true,
|
||||
itemStyle: { color: '#D4AF37' },
|
||||
lineStyle: { width: 2, color: '#D4AF37' },
|
||||
itemStyle: { color: fui.gold },
|
||||
lineStyle: { width: 2, color: fui.gold },
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'rgba(212, 175, 55, 0.3)' },
|
||||
{ offset: 1, color: 'rgba(212, 175, 55, 0.05)' },
|
||||
],
|
||||
},
|
||||
color: chartTheme.goldGradient(0.3, 0.05),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
// 黑金主题饼图配色
|
||||
const BLACK_GOLD_PIE_COLORS = [
|
||||
'#D4AF37', // 金色
|
||||
'#B8860B', // 深金色
|
||||
'#FFD700', // 亮金色
|
||||
'#DAA520', // 金菊色
|
||||
'#CD853F', // 秘鲁色
|
||||
'#F4A460', // 沙褐色
|
||||
'#DEB887', // 实木色
|
||||
'#D2691E', // 巧克力色
|
||||
];
|
||||
// 黑金主题饼图配色(使用 chartTheme 统一定义)
|
||||
const BLACK_GOLD_PIE_COLORS = chartTheme.goldSeries;
|
||||
|
||||
/**
|
||||
* 生成主营业务饼图配置 - 黑金主题
|
||||
@@ -265,7 +247,7 @@ export const getMainBusinessPieOption = (
|
||||
subtext: subtitle,
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#D4AF37',
|
||||
color: fui.gold,
|
||||
fontSize: 14,
|
||||
},
|
||||
subtextStyle: {
|
||||
@@ -275,8 +257,8 @@ export const getMainBusinessPieOption = (
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: 'rgba(26, 32, 44, 0.95)',
|
||||
borderColor: 'rgba(212, 175, 55, 0.3)',
|
||||
backgroundColor: chartTheme.tooltip.bg,
|
||||
borderColor: chartTheme.tooltip.border,
|
||||
textStyle: {
|
||||
color: '#E2E8F0',
|
||||
},
|
||||
@@ -310,14 +292,14 @@ export const getMainBusinessPieOption = (
|
||||
},
|
||||
labelLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(212, 175, 55, 0.5)',
|
||||
color: alpha('gold', 0.5),
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(212, 175, 55, 0.5)',
|
||||
shadowColor: alpha('gold', 0.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
Text,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import { FileText, TrendingUp, Building2, Newspaper, BookOpen } from 'lucide-react';
|
||||
import MarkdownRenderer from './MarkdownRenderer';
|
||||
import { formatNumber } from '../utils/formatUtils';
|
||||
|
||||
@@ -28,8 +28,7 @@ import {
|
||||
Flex,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { SearchIcon, CloseIcon, AddIcon } from '@chakra-ui/icons';
|
||||
import { Database, TrendingUp } from 'lucide-react';
|
||||
import { Database, TrendingUp, Search, X, Plus } from 'lucide-react';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import { searchMetrics, fetchMetricData, type MetricSearchResult } from '@services/categoryService';
|
||||
@@ -233,7 +232,7 @@ const MetricOverlaySearch: React.FC<MetricOverlaySearchProps> = ({
|
||||
{/* Search input */}
|
||||
<InputGroup size="sm" mb={3}>
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<SearchIcon color={darkGoldTheme.textMuted} />
|
||||
<Search size={16} color={darkGoldTheme.textMuted} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
@@ -255,7 +254,7 @@ const MetricOverlaySearch: React.FC<MetricOverlaySearchProps> = ({
|
||||
<IconButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
icon={<CloseIcon w="8px" h="8px" />}
|
||||
icon={<X size={12} />}
|
||||
onClick={() => {
|
||||
setSearchQuery('');
|
||||
setSearchResults([]);
|
||||
@@ -318,7 +317,7 @@ const MetricOverlaySearch: React.FC<MetricOverlaySearchProps> = ({
|
||||
{isAdded ? (
|
||||
<Badge colorScheme="green" fontSize="10px">Added</Badge>
|
||||
) : (
|
||||
<AddIcon boxSize={3} color={darkGoldTheme.textMuted} />
|
||||
<Plus size={12} color={darkGoldTheme.textMuted} />
|
||||
)}
|
||||
</Flex>
|
||||
</ListItem>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { Box, Text, VStack, Center, Icon } from '@chakra-ui/react';
|
||||
import { InfoIcon } from '@chakra-ui/icons';
|
||||
import { Info } from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
|
||||
import { darkGoldTheme } from '../../../../constants';
|
||||
@@ -32,7 +32,7 @@ export interface DailyKLineChartProps {
|
||||
const EmptyState: React.FC<{ title: string; description: string }> = ({ title, description }) => (
|
||||
<Center h="300px">
|
||||
<VStack spacing={4}>
|
||||
<Icon as={InfoIcon} color={darkGoldTheme.textMuted} boxSize={12} />
|
||||
<Icon as={Info} color={darkGoldTheme.textMuted} boxSize={12} />
|
||||
<VStack spacing={2}>
|
||||
<Text color={darkGoldTheme.textMuted} fontSize="lg">{title}</Text>
|
||||
<Text color={darkGoldTheme.textMuted} fontSize="sm" textAlign="center">{description}</Text>
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
MenuItem,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { RepeatIcon, ChevronDownIcon, ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
|
||||
import { BarChart2, TrendingUp, Calendar, LineChart, Activity, Pencil } from 'lucide-react';
|
||||
import { BarChart2, TrendingUp, Calendar, LineChart, Activity, Pencil, RefreshCw, ChevronDown, Eye, EyeOff } from 'lucide-react';
|
||||
|
||||
import { darkGoldTheme, PERIOD_OPTIONS } from '../../../../constants';
|
||||
import type { IndicatorType, MainIndicatorType, DrawingType } from '../../../../utils/chartOptions';
|
||||
@@ -155,7 +154,7 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
leftIcon={showAnalysis ? <ViewOffIcon /> : <ViewIcon />}
|
||||
leftIcon={showAnalysis ? <EyeOff size={14} /> : <Eye size={14} />}
|
||||
onClick={onToggleAnalysis}
|
||||
{...(showAnalysis ? INACTIVE_BUTTON_STYLE : ACTIVE_BUTTON_STYLE)}
|
||||
minW="90px"
|
||||
@@ -171,7 +170,7 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
|
||||
as={Button}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
rightIcon={<ChevronDown size={14} />}
|
||||
{...INACTIVE_BUTTON_STYLE}
|
||||
minW="90px"
|
||||
>
|
||||
@@ -205,7 +204,7 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
|
||||
as={Button}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
rightIcon={<ChevronDown size={14} />}
|
||||
leftIcon={<Activity size={14} />}
|
||||
{...INACTIVE_BUTTON_STYLE}
|
||||
minW="100px"
|
||||
@@ -240,7 +239,7 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
|
||||
as={Button}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
rightIcon={<ChevronDown size={14} />}
|
||||
leftIcon={<Pencil size={14} />}
|
||||
{...(drawingType !== 'NONE' ? ACTIVE_BUTTON_STYLE : INACTIVE_BUTTON_STYLE)}
|
||||
minW="90px"
|
||||
@@ -296,7 +295,7 @@ const KLineToolbar: React.FC<KLineToolbarProps> = ({
|
||||
|
||||
{/* 刷新按钮 */}
|
||||
<Button
|
||||
leftIcon={<RepeatIcon />}
|
||||
leftIcon={<RefreshCw size={14} />}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={onRefreshMinuteData}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
GridItem,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { InfoIcon } from '@chakra-ui/icons';
|
||||
import { Info } from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
|
||||
// 导入实时行情 Hook 和五档盘口组件
|
||||
@@ -38,7 +38,7 @@ export interface MinuteChartWithOrderBookProps {
|
||||
const EmptyState: React.FC<{ title: string; description: string }> = ({ title, description }) => (
|
||||
<Center h="300px">
|
||||
<VStack spacing={4}>
|
||||
<Icon as={InfoIcon} color={darkGoldTheme.textMuted} boxSize={12} />
|
||||
<Icon as={Info} color={darkGoldTheme.textMuted} boxSize={12} />
|
||||
<VStack spacing={2}>
|
||||
<Text color={darkGoldTheme.textMuted} fontSize="lg">{title}</Text>
|
||||
<Text color={darkGoldTheme.textMuted} fontSize="sm" textAlign="center">{description}</Text>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 共享样式常量
|
||||
|
||||
import { darkGoldTheme } from '../../constants';
|
||||
import { alpha, fui } from '@views/Company/theme';
|
||||
import type { SystemStyleObject } from '@chakra-ui/react';
|
||||
|
||||
/**
|
||||
@@ -21,7 +22,7 @@ export const darkGoldCardStyle: SystemStyleObject = {
|
||||
*/
|
||||
export const darkGoldCardHoverStyle: SystemStyleObject = {
|
||||
borderColor: darkGoldTheme.borderHover,
|
||||
boxShadow: '0 8px 30px rgba(212, 175, 55, 0.15)',
|
||||
boxShadow: `0 8px 30px ${alpha('gold', 0.15)}`,
|
||||
transform: 'translateY(-2px)',
|
||||
};
|
||||
|
||||
@@ -47,7 +48,7 @@ export const dataRowStyle: SystemStyleObject = {
|
||||
* 表格行悬停样式
|
||||
*/
|
||||
export const tableRowHoverStyle: SystemStyleObject = {
|
||||
bg: 'rgba(212, 175, 55, 0.08)',
|
||||
bg: alpha('gold', 0.08),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -55,7 +56,7 @@ export const tableRowHoverStyle: SystemStyleObject = {
|
||||
*/
|
||||
export const tableBorderStyle: SystemStyleObject = {
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'rgba(212, 175, 55, 0.1)',
|
||||
borderColor: fui.border('subtle'),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -63,14 +64,14 @@ export const tableBorderStyle: SystemStyleObject = {
|
||||
*/
|
||||
export const financingRowStyle: SystemStyleObject = {
|
||||
p: 3,
|
||||
bg: 'rgba(212, 175, 55, 0.08)',
|
||||
bg: alpha('gold', 0.08),
|
||||
borderRadius: 'md',
|
||||
border: '1px solid',
|
||||
borderColor: 'rgba(212, 175, 55, 0.15)',
|
||||
borderColor: alpha('gold', 0.15),
|
||||
transition: 'all 0.2s',
|
||||
_hover: {
|
||||
bg: 'rgba(212, 175, 55, 0.12)',
|
||||
borderColor: 'rgba(212, 175, 55, 0.3)',
|
||||
bg: alpha('gold', 0.12),
|
||||
borderColor: alpha('gold', 0.3),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -127,8 +128,8 @@ export const sellRowStyle: SystemStyleObject = {
|
||||
*/
|
||||
export const dayCardStyle: SystemStyleObject = {
|
||||
p: 4,
|
||||
bg: 'rgba(212, 175, 55, 0.05)',
|
||||
bg: alpha('gold', 0.05),
|
||||
borderRadius: 'lg',
|
||||
border: '1px solid',
|
||||
borderColor: 'rgba(212, 175, 55, 0.15)',
|
||||
borderColor: alpha('gold', 0.15),
|
||||
};
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
VStack,
|
||||
Spinner,
|
||||
} from '@chakra-ui/react';
|
||||
import { SearchIcon } from '@chakra-ui/icons';
|
||||
import { BarChart2 } from 'lucide-react';
|
||||
import { BarChart2, Search } from 'lucide-react';
|
||||
import { useStockSearch, type Stock } from '../../../hooks/useStockSearch';
|
||||
|
||||
interface CompareStockInputProps {
|
||||
@@ -106,7 +105,7 @@ const CompareStockInput: React.FC<CompareStockInputProps> = ({
|
||||
<HStack spacing={2}>
|
||||
<InputGroup size="sm" w="160px">
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<SearchIcon color={textColor} boxSize={3} />
|
||||
<Search size={12} color={textColor} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
placeholder="对比股票"
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
Spinner,
|
||||
Center,
|
||||
} from '@chakra-ui/react';
|
||||
import { ArrowUpIcon, ArrowDownIcon } from '@chakra-ui/icons';
|
||||
import { ArrowUp, ArrowDown } from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
|
||||
import { COMPARE_METRICS } from '../../FinancialPanorama/constants';
|
||||
@@ -149,8 +149,8 @@ const StockCompareModal: React.FC<StockCompareModalProps> = ({
|
||||
<Td isNumeric color={diffColor} fontSize="sm">
|
||||
{diff !== null ? (
|
||||
<HStack spacing={1} justify="flex-end">
|
||||
{diff > 0 && <ArrowUpIcon boxSize={3} />}
|
||||
{diff < 0 && <ArrowDownIcon boxSize={3} />}
|
||||
{diff > 0 && <ArrowUp size={12} />}
|
||||
{diff < 0 && <ArrowDown size={12} />}
|
||||
<Text>
|
||||
{metric.format === 'percent'
|
||||
? `${Math.abs(diff).toFixed(2)}pp`
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
// src/views/Company/constants/index.js
|
||||
// 公司详情页面常量配置
|
||||
|
||||
import { FaChartLine, FaMoneyBillWave, FaChartBar, FaInfoCircle, FaBrain, FaNewspaper } from 'react-icons/fa';
|
||||
import { LineChart, Banknote, BarChart2, Info, Brain, Newspaper } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* Tab 配置
|
||||
* @type {Array<{key: string, name: string, icon: React.ComponentType}>}
|
||||
*/
|
||||
export const COMPANY_TABS = [
|
||||
{ key: 'overview', name: '公司档案', icon: FaInfoCircle },
|
||||
{ key: 'analysis', name: '深度分析', icon: FaBrain },
|
||||
{ key: 'market', name: '股票行情', icon: FaChartLine },
|
||||
{ key: 'financial', name: '财务全景', icon: FaMoneyBillWave },
|
||||
{ key: 'forecast', name: '盈利预测', icon: FaChartBar },
|
||||
{ key: 'tracking', name: '动态跟踪', icon: FaNewspaper },
|
||||
{ key: 'overview', name: '公司档案', icon: Info },
|
||||
{ key: 'analysis', name: '深度分析', icon: Brain },
|
||||
{ key: 'market', name: '股票行情', icon: LineChart },
|
||||
{ key: 'financial', name: '财务全景', icon: Banknote },
|
||||
{ key: 'forecast', name: '盈利预测', icon: BarChart2 },
|
||||
{ key: 'tracking', name: '动态跟踪', icon: Newspaper },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,6 +50,20 @@ export const FUI_COLORS = {
|
||||
default: 'rgba(212, 175, 55, 0.2)',
|
||||
emphasis: 'rgba(212, 175, 55, 0.4)',
|
||||
glow: 'rgba(212, 175, 55, 0.6)',
|
||||
// 完整透明度等级(用于替换硬编码)
|
||||
opacity03: 'rgba(212, 175, 55, 0.03)',
|
||||
opacity05: 'rgba(212, 175, 55, 0.05)',
|
||||
opacity08: 'rgba(212, 175, 55, 0.08)',
|
||||
opacity10: 'rgba(212, 175, 55, 0.1)',
|
||||
opacity12: 'rgba(212, 175, 55, 0.12)',
|
||||
opacity15: 'rgba(212, 175, 55, 0.15)',
|
||||
opacity20: 'rgba(212, 175, 55, 0.2)',
|
||||
opacity30: 'rgba(212, 175, 55, 0.3)',
|
||||
opacity40: 'rgba(212, 175, 55, 0.4)',
|
||||
opacity50: 'rgba(212, 175, 55, 0.5)',
|
||||
opacity60: 'rgba(212, 175, 55, 0.6)',
|
||||
opacity70: 'rgba(212, 175, 55, 0.7)',
|
||||
opacity80: 'rgba(212, 175, 55, 0.8)',
|
||||
},
|
||||
|
||||
// 文字
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 使用方式:
|
||||
* import { COLORS, GLOW, GLASS } from '@views/Company/theme';
|
||||
* import { FUI_COLORS, FUI_THEME } from '@views/Company/theme';
|
||||
* import { alpha, fui, chartTheme } from '@views/Company/theme';
|
||||
*/
|
||||
|
||||
// 完整主题对象
|
||||
@@ -20,6 +21,22 @@ export {
|
||||
// 主题组件
|
||||
export * from './components';
|
||||
|
||||
// ============================================
|
||||
// 工具函数导出(推荐使用)
|
||||
// ============================================
|
||||
|
||||
export {
|
||||
// 核心工具
|
||||
alpha,
|
||||
hex,
|
||||
fui,
|
||||
BASE_COLORS,
|
||||
OPACITY,
|
||||
chartTheme,
|
||||
// 类型
|
||||
type ColorName,
|
||||
} from './utils';
|
||||
|
||||
// ============================================
|
||||
// 便捷常量导出(推荐使用)
|
||||
// ============================================
|
||||
|
||||
251
src/views/Company/theme/utils/colorUtils.ts
Normal file
251
src/views/Company/theme/utils/colorUtils.ts
Normal file
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* FUI 颜色工具函数
|
||||
*
|
||||
* 提供便捷的颜色+透明度生成能力,用于替换硬编码的 rgba 值
|
||||
*
|
||||
* @example
|
||||
* // 替换 'rgba(212, 175, 55, 0.2)' 为:
|
||||
* alpha('gold', 0.2)
|
||||
*
|
||||
* // 或使用语义化 API:
|
||||
* fui.border() // => 'rgba(212, 175, 55, 0.2)'
|
||||
* fui.border('hover') // => 'rgba(212, 175, 55, 0.4)'
|
||||
*/
|
||||
|
||||
// ============================================
|
||||
// 基础色值(单一数据源)
|
||||
// ============================================
|
||||
|
||||
export const BASE_COLORS = {
|
||||
gold: { r: 212, g: 175, b: 55 }, // #D4AF37
|
||||
white: { r: 255, g: 255, b: 255 },
|
||||
black: { r: 0, g: 0, b: 0 },
|
||||
bgPrimary: { r: 15, g: 15, b: 26 }, // #0F0F1A
|
||||
bgElevated: { r: 26, g: 26, b: 46 }, // #1A1A2E
|
||||
positive: { r: 239, g: 68, b: 68 }, // #EF4444 涨
|
||||
negative: { r: 34, g: 197, b: 94 }, // #22C55E 跌
|
||||
warning: { r: 245, g: 158, b: 11 }, // #F59E0B
|
||||
info: { r: 59, g: 130, b: 246 }, // #3B82F6
|
||||
} as const;
|
||||
|
||||
export type ColorName = keyof typeof BASE_COLORS;
|
||||
|
||||
// ============================================
|
||||
// 核心工具函数
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 生成带透明度的颜色值
|
||||
* @param color - 颜色名称
|
||||
* @param opacity - 透明度 (0-1)
|
||||
* @returns rgba 字符串
|
||||
*
|
||||
* @example
|
||||
* alpha('gold', 0.2) => 'rgba(212, 175, 55, 0.2)'
|
||||
* alpha('white', 0.5) => 'rgba(255, 255, 255, 0.5)'
|
||||
*/
|
||||
export function alpha(color: ColorName, opacity: number): string {
|
||||
const { r, g, b } = BASE_COLORS[color];
|
||||
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取十六进制颜色值
|
||||
* @param color - 颜色名称
|
||||
* @returns hex 字符串
|
||||
*
|
||||
* @example
|
||||
* hex('gold') => '#D4AF37'
|
||||
*/
|
||||
export function hex(color: ColorName): string {
|
||||
const { r, g, b } = BASE_COLORS[color];
|
||||
const toHex = (n: number) => n.toString(16).padStart(2, '0').toUpperCase();
|
||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 预设透明度级别
|
||||
// ============================================
|
||||
|
||||
export const OPACITY = {
|
||||
/** 0.05 - 极淡背景 */
|
||||
ghost: 0.05,
|
||||
/** 0.08 - 微弱背景 */
|
||||
faint: 0.08,
|
||||
/** 0.1 - 淡背景/边框 */
|
||||
subtle: 0.1,
|
||||
/** 0.15 - 轻背景 */
|
||||
light: 0.15,
|
||||
/** 0.2 - 默认边框 */
|
||||
muted: 0.2,
|
||||
/** 0.3 - 标签边框 */
|
||||
soft: 0.3,
|
||||
/** 0.4 - 悬停边框 */
|
||||
medium: 0.4,
|
||||
/** 0.5 - 半透明 */
|
||||
half: 0.5,
|
||||
/** 0.6 - 发光边框 */
|
||||
emphasis: 0.6,
|
||||
/** 0.7 - 次要文字 */
|
||||
secondary: 0.7,
|
||||
/** 0.8 - 高可见 */
|
||||
high: 0.8,
|
||||
/** 0.95 - 主文字 */
|
||||
primary: 0.95,
|
||||
} as const;
|
||||
|
||||
// ============================================
|
||||
// 语义化颜色生成器
|
||||
// ============================================
|
||||
|
||||
type BorderVariant = 'subtle' | 'default' | 'hover' | 'emphasis';
|
||||
type BgVariant = 'ghost' | 'subtle' | 'light' | 'medium';
|
||||
type TextVariant = 'primary' | 'secondary' | 'muted' | 'dim';
|
||||
type GlowSize = 'sm' | 'md' | 'lg' | 'pulse';
|
||||
|
||||
/**
|
||||
* FUI 语义化颜色 API
|
||||
* 提供直观的颜色获取方式
|
||||
*/
|
||||
export const fui = {
|
||||
/**
|
||||
* 边框颜色
|
||||
* @example
|
||||
* fui.border() => 'rgba(212, 175, 55, 0.2)'
|
||||
* fui.border('hover') => 'rgba(212, 175, 55, 0.4)'
|
||||
*/
|
||||
border: (variant: BorderVariant = 'default'): string => {
|
||||
const opacityMap: Record<BorderVariant, number> = {
|
||||
subtle: 0.1,
|
||||
default: 0.2,
|
||||
hover: 0.4,
|
||||
emphasis: 0.6,
|
||||
};
|
||||
return alpha('gold', opacityMap[variant]);
|
||||
},
|
||||
|
||||
/**
|
||||
* 背景颜色(金色系)
|
||||
* @example
|
||||
* fui.bg() => 'rgba(212, 175, 55, 0.1)'
|
||||
* fui.bg('ghost') => 'rgba(212, 175, 55, 0.05)'
|
||||
*/
|
||||
bg: (variant: BgVariant = 'subtle'): string => {
|
||||
const opacityMap: Record<BgVariant, number> = {
|
||||
ghost: 0.05,
|
||||
subtle: 0.1,
|
||||
light: 0.15,
|
||||
medium: 0.2,
|
||||
};
|
||||
return alpha('gold', opacityMap[variant]);
|
||||
},
|
||||
|
||||
/**
|
||||
* 文字颜色(白色系)
|
||||
* @example
|
||||
* fui.text() => 'rgba(255, 255, 255, 0.95)'
|
||||
* fui.text('secondary') => 'rgba(255, 255, 255, 0.7)'
|
||||
*/
|
||||
text: (variant: TextVariant = 'primary'): string => {
|
||||
const opacityMap: Record<TextVariant, number> = {
|
||||
primary: 0.95,
|
||||
secondary: 0.7,
|
||||
muted: 0.5,
|
||||
dim: 0.3,
|
||||
};
|
||||
return alpha('white', opacityMap[variant]);
|
||||
},
|
||||
|
||||
/**
|
||||
* 发光效果(box-shadow 值)
|
||||
* @example
|
||||
* fui.glow() => '0 0 16px rgba(212, 175, 55, 0.4)'
|
||||
* fui.glow('lg') => '0 0 32px rgba(212, 175, 55, 0.5)'
|
||||
*/
|
||||
glow: (size: GlowSize = 'md'): string => {
|
||||
const sizeMap: Record<GlowSize, string> = {
|
||||
sm: `0 0 8px ${alpha('gold', 0.3)}`,
|
||||
md: `0 0 16px ${alpha('gold', 0.4)}`,
|
||||
lg: `0 0 32px ${alpha('gold', 0.5)}`,
|
||||
pulse: `0 0 20px ${alpha('gold', 0.6)}, 0 0 40px ${alpha('gold', 0.3)}`,
|
||||
};
|
||||
return sizeMap[size];
|
||||
},
|
||||
|
||||
/**
|
||||
* 玻璃态边框(完整 border 属性)
|
||||
* @example
|
||||
* fui.glassBorder() => '1px solid rgba(212, 175, 55, 0.2)'
|
||||
*/
|
||||
glassBorder: (variant: BorderVariant = 'default'): string => {
|
||||
return `1px solid ${fui.border(variant)}`;
|
||||
},
|
||||
|
||||
/**
|
||||
* 状态颜色
|
||||
*/
|
||||
status: {
|
||||
positive: hex('positive'), // #EF4444
|
||||
negative: hex('negative'), // #22C55E
|
||||
warning: hex('warning'), // #F59E0B
|
||||
info: hex('info'), // #3B82F6
|
||||
positiveBg: alpha('positive', 0.15),
|
||||
negativeBg: alpha('negative', 0.15),
|
||||
},
|
||||
|
||||
/**
|
||||
* 金色(主色调)
|
||||
*/
|
||||
gold: hex('gold'), // #D4AF37
|
||||
} as const;
|
||||
|
||||
// ============================================
|
||||
// 图表主题配置
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* ECharts 图表主题配置
|
||||
*/
|
||||
export const chartTheme = {
|
||||
// 轴线和网格线
|
||||
axisLine: alpha('gold', 0.3),
|
||||
splitLine: alpha('gold', 0.1),
|
||||
|
||||
// Tooltip
|
||||
tooltip: {
|
||||
bg: alpha('bgElevated', 0.95),
|
||||
border: alpha('gold', 0.3),
|
||||
text: alpha('white', 0.9),
|
||||
},
|
||||
|
||||
// 标题
|
||||
title: {
|
||||
color: hex('gold'),
|
||||
subtextColor: alpha('white', 0.6),
|
||||
},
|
||||
|
||||
// 金色系列配色
|
||||
goldSeries: [
|
||||
'#D4AF37',
|
||||
'#B8860B',
|
||||
'#FFD700',
|
||||
'#DAA520',
|
||||
'#CD853F',
|
||||
'#F4A460',
|
||||
'#DEB887',
|
||||
'#D2691E',
|
||||
],
|
||||
|
||||
// 渐变生成器
|
||||
goldGradient: (startOpacity = 0.3, endOpacity = 0.05) => ({
|
||||
type: 'linear' as const,
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: alpha('gold', startOpacity) },
|
||||
{ offset: 1, color: alpha('gold', endOpacity) },
|
||||
],
|
||||
}),
|
||||
} as const;
|
||||
15
src/views/Company/theme/utils/index.ts
Normal file
15
src/views/Company/theme/utils/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* FUI 主题工具函数导出
|
||||
*/
|
||||
|
||||
export {
|
||||
// 核心工具
|
||||
alpha,
|
||||
hex,
|
||||
fui,
|
||||
BASE_COLORS,
|
||||
OPACITY,
|
||||
chartTheme,
|
||||
// 类型
|
||||
type ColorName,
|
||||
} from './colorUtils';
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import type { ComponentType, ReactNode } from 'react';
|
||||
import type { IconType } from 'react-icons';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
|
||||
// ============================================
|
||||
@@ -34,7 +33,7 @@ export interface CompanyTheme {
|
||||
export interface TabConfig {
|
||||
key: string;
|
||||
name: string;
|
||||
icon: LucideIcon | IconType | ComponentType;
|
||||
icon: LucideIcon | ComponentType;
|
||||
component: ComponentType<TabComponentProps>;
|
||||
/** 自定义 Suspense fallback(如骨架屏) */
|
||||
fallback?: ReactNode;
|
||||
|
||||
@@ -33,21 +33,21 @@ import {
|
||||
useBreakpointValue,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
ChevronRightIcon,
|
||||
ExternalLinkIcon,
|
||||
ViewIcon,
|
||||
CalendarIcon,
|
||||
} from '@chakra-ui/icons';
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
ExternalLink,
|
||||
Eye,
|
||||
Calendar,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
FaChartLine,
|
||||
FaArrowUp,
|
||||
FaArrowDown,
|
||||
FaHistory,
|
||||
FaNewspaper,
|
||||
FaFileAlt,
|
||||
FaClock,
|
||||
} from 'react-icons/fa';
|
||||
LineChart,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
History,
|
||||
Newspaper as NewspaperIcon,
|
||||
FileText,
|
||||
Clock,
|
||||
} from 'lucide-react';
|
||||
import { keyframes } from '@emotion/react';
|
||||
|
||||
dayjs.locale('zh-cn');
|
||||
@@ -179,13 +179,13 @@ const ConceptTimelineModal = ({
|
||||
if (value > 0) {
|
||||
return {
|
||||
color: 'red',
|
||||
icon: FaArrowUp,
|
||||
icon: ArrowUp,
|
||||
text: `+${value.toFixed(2)}%`
|
||||
};
|
||||
} else if (value < 0) {
|
||||
return {
|
||||
color: 'green',
|
||||
icon: FaArrowDown,
|
||||
icon: ArrowDown,
|
||||
text: `${value.toFixed(2)}%`
|
||||
};
|
||||
} else {
|
||||
@@ -691,7 +691,7 @@ const ConceptTimelineModal = ({
|
||||
>
|
||||
<HStack spacing={{ base: 2, md: 4 }} flexWrap="wrap">
|
||||
<Icon
|
||||
as={FaChartLine}
|
||||
as={LineChart}
|
||||
boxSize={{ base: 4, md: 6 }}
|
||||
color="cyan.400"
|
||||
/>
|
||||
@@ -815,7 +815,7 @@ const ConceptTimelineModal = ({
|
||||
borderColor="red.400"
|
||||
flexShrink={0}
|
||||
>
|
||||
<Icon as={FaArrowUp} color="red.400" boxSize={{ base: 2, md: 3 }} />
|
||||
<Icon as={ArrowUp} color="red.400" boxSize={{ base: 2, md: 3 }} />
|
||||
<Text fontSize={{ base: 'xs', md: 'sm' }} fontWeight="medium" color="whiteAlpha.900" whiteSpace="nowrap">上涨</Text>
|
||||
</HStack>
|
||||
<HStack
|
||||
@@ -828,7 +828,7 @@ const ConceptTimelineModal = ({
|
||||
borderColor="green.400"
|
||||
flexShrink={0}
|
||||
>
|
||||
<Icon as={FaArrowDown} color="green.400" boxSize={{ base: 2, md: 3 }} />
|
||||
<Icon as={ArrowDown} color="green.400" boxSize={{ base: 2, md: 3 }} />
|
||||
<Text fontSize={{ base: 'xs', md: 'sm' }} fontWeight="medium" color="whiteAlpha.900" whiteSpace="nowrap">下跌</Text>
|
||||
</HStack>
|
||||
<HStack
|
||||
@@ -874,7 +874,7 @@ const ConceptTimelineModal = ({
|
||||
borderColor="whiteAlpha.200"
|
||||
>
|
||||
<Icon
|
||||
as={FaHistory}
|
||||
as={History}
|
||||
boxSize={24}
|
||||
color="purple.400"
|
||||
opacity={0.6}
|
||||
@@ -928,7 +928,7 @@ const ConceptTimelineModal = ({
|
||||
<VStack align="start" spacing={3} position="relative" zIndex={1}>
|
||||
<HStack spacing={3}>
|
||||
<Icon
|
||||
as={CalendarIcon}
|
||||
as={Calendar}
|
||||
boxSize={6}
|
||||
color="cyan.400"
|
||||
/>
|
||||
@@ -991,7 +991,7 @@ const ConceptTimelineModal = ({
|
||||
borderColor="blue.500"
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FaNewspaper} color="blue.400" boxSize={5} />
|
||||
<Icon as={Newspaper} color="blue.400" boxSize={5} />
|
||||
<Text fontWeight="bold" fontSize="lg" color="blue.300">
|
||||
{selectedDateData.events.filter(e => e.type === 'news').length}
|
||||
</Text>
|
||||
@@ -1007,7 +1007,7 @@ const ConceptTimelineModal = ({
|
||||
borderColor="green.500"
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FaFileAlt} color="green.400" boxSize={5} />
|
||||
<Icon as={FileText} color="green.400" boxSize={5} />
|
||||
<Text fontWeight="bold" fontSize="lg" color="green.300">
|
||||
{selectedDateData.events.filter(e => e.type === 'report').length}
|
||||
</Text>
|
||||
@@ -1109,7 +1109,7 @@ const ConceptTimelineModal = ({
|
||||
<HStack spacing={4} w="100%" justify="space-between" align="center" mt={1}>
|
||||
{event.time && (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaClock} color="whiteAlpha.500" boxSize={3} />
|
||||
<Icon as={Clock} color="whiteAlpha.500" boxSize={3} />
|
||||
<Text fontSize="xs" color="whiteAlpha.500" fontWeight="medium">
|
||||
{formatDateTime(event.time)}
|
||||
</Text>
|
||||
@@ -1120,7 +1120,7 @@ const ConceptTimelineModal = ({
|
||||
size="sm"
|
||||
colorScheme={event.type === 'news' ? 'blue' : 'green'}
|
||||
variant="solid"
|
||||
leftIcon={<ViewIcon />}
|
||||
leftIcon={<Eye size={16} />}
|
||||
boxShadow="sm"
|
||||
_hover={{
|
||||
transform: 'scale(1.05)',
|
||||
@@ -1175,7 +1175,7 @@ const ConceptTimelineModal = ({
|
||||
borderColor="whiteAlpha.200"
|
||||
>
|
||||
<Icon
|
||||
as={FaHistory}
|
||||
as={History}
|
||||
boxSize={20}
|
||||
color="purple.400"
|
||||
opacity={0.6}
|
||||
@@ -1286,7 +1286,7 @@ const ConceptTimelineModal = ({
|
||||
size="sm"
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
leftIcon={<ExternalLinkIcon />}
|
||||
leftIcon={<ExternalLink size={16} />}
|
||||
onClick={() => {
|
||||
const url = formatUrl(selectedReport.content_url);
|
||||
if (url) {
|
||||
@@ -1379,7 +1379,7 @@ const ConceptTimelineModal = ({
|
||||
size="sm"
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
leftIcon={<ExternalLinkIcon />}
|
||||
leftIcon={<ExternalLink size={16} />}
|
||||
onClick={() => window.open(selectedNews.url, '_blank')}
|
||||
_hover={{ bg: 'whiteAlpha.200' }}
|
||||
>
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
Flex,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { ChevronRightIcon } from '@chakra-ui/icons';
|
||||
import { FaFilter, FaTimes, FaHome } from 'react-icons/fa';
|
||||
import { ChevronRight, Filter, X, Home } from 'lucide-react';
|
||||
|
||||
const BreadcrumbNav = ({
|
||||
filter,
|
||||
@@ -139,7 +138,7 @@ const BreadcrumbNav = ({
|
||||
py={1}
|
||||
borderRadius="full"
|
||||
>
|
||||
<Icon as={FaFilter} boxSize={3} />
|
||||
<Icon as={Filter} boxSize={3} />
|
||||
<Text fontSize="sm" fontWeight="bold">
|
||||
层级筛选
|
||||
</Text>
|
||||
@@ -161,7 +160,7 @@ const BreadcrumbNav = ({
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
>
|
||||
<Icon as={FaHome} boxSize={3} />
|
||||
<Icon as={Home} boxSize={3} />
|
||||
全部
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
@@ -169,7 +168,7 @@ const BreadcrumbNav = ({
|
||||
{/* 面包屑路径 */}
|
||||
{breadcrumbs.map((crumb, index) => (
|
||||
<React.Fragment key={crumb.level}>
|
||||
<Icon as={ChevronRightIcon} color={styles.chevron.color} boxSize={4} />
|
||||
<Icon as={ChevronRight} color={styles.chevron.color} boxSize={4} />
|
||||
<Badge
|
||||
{...(isDarkMode ? {} : { colorScheme: styles.crumbBadge(crumb.level, index === breadcrumbs.length - 1).colorScheme })}
|
||||
bg={isDarkMode ? styles.crumbBadge(crumb.level, index === breadcrumbs.length - 1).bg : undefined}
|
||||
@@ -196,7 +195,7 @@ const BreadcrumbNav = ({
|
||||
<Tooltip label="清除筛选" placement="top">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<FaTimes />}
|
||||
icon={<X />}
|
||||
{...(isDarkMode ? {} : { colorScheme: 'red' })}
|
||||
color={isDarkMode ? styles.clearBtn.color : undefined}
|
||||
variant="ghost"
|
||||
|
||||
@@ -37,14 +37,16 @@ import {
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaArrowUp,
|
||||
FaArrowDown,
|
||||
FaChartLine,
|
||||
FaNewspaper,
|
||||
FaRocket,
|
||||
FaCrown,
|
||||
} from 'react-icons/fa';
|
||||
import { BsLightningFill, BsGraphUp, BsGraphDown } from 'react-icons/bs';
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
LineChart,
|
||||
Newspaper,
|
||||
Rocket,
|
||||
Crown,
|
||||
Zap,
|
||||
TrendingUp,
|
||||
TrendingDown,
|
||||
} from 'lucide-react';
|
||||
|
||||
const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
// 获取正确的API基础URL
|
||||
@@ -274,7 +276,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
const tabsData = [
|
||||
{
|
||||
label: '涨幅榜',
|
||||
icon: FaArrowUp,
|
||||
icon: ArrowUp,
|
||||
color: 'red',
|
||||
data: statsData.hot_concepts,
|
||||
renderItem: (item, index) => (
|
||||
@@ -314,7 +316,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</Badge>
|
||||
{index === 0 && (
|
||||
<Icon
|
||||
as={FaCrown}
|
||||
as={Crown}
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
@@ -329,12 +331,12 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</Text>
|
||||
<HStack spacing={2} fontSize="xs" color="whiteAlpha.600">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaChartLine} boxSize={2.5} />
|
||||
<Icon as={LineChart} boxSize={2.5} />
|
||||
<Text>{item.stock_count}股</Text>
|
||||
</HStack>
|
||||
<Text>·</Text>
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaNewspaper} boxSize={2.5} />
|
||||
<Icon as={Newspaper} boxSize={2.5} />
|
||||
<Text>{item.news_count}讯</Text>
|
||||
</HStack>
|
||||
</HStack>
|
||||
@@ -349,7 +351,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
px={2}
|
||||
py={1}
|
||||
>
|
||||
<Icon as={FaArrowUp} boxSize={2} mr={1} />
|
||||
<Icon as={ArrowUp} boxSize={2} mr={1} />
|
||||
{formatChange(item.change_pct)}
|
||||
</Badge>
|
||||
</Flex>
|
||||
@@ -357,7 +359,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
},
|
||||
{
|
||||
label: '跌幅榜',
|
||||
icon: FaArrowDown,
|
||||
icon: ArrowDown,
|
||||
color: 'green',
|
||||
data: statsData.cold_concepts,
|
||||
renderItem: (item, index) => (
|
||||
@@ -400,12 +402,12 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</Text>
|
||||
<HStack spacing={2} fontSize="xs" color="whiteAlpha.600">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaChartLine} boxSize={2.5} />
|
||||
<Icon as={LineChart} boxSize={2.5} />
|
||||
<Text>{item.stock_count}股</Text>
|
||||
</HStack>
|
||||
<Text>·</Text>
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaNewspaper} boxSize={2.5} />
|
||||
<Icon as={Newspaper} boxSize={2.5} />
|
||||
<Text>{item.news_count}讯</Text>
|
||||
</HStack>
|
||||
</HStack>
|
||||
@@ -420,7 +422,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
px={2}
|
||||
py={1}
|
||||
>
|
||||
<Icon as={FaArrowDown} boxSize={2} mr={1} />
|
||||
<Icon as={ArrowDown} boxSize={2} mr={1} />
|
||||
{formatChange(item.change_pct)}
|
||||
</Badge>
|
||||
</Flex>
|
||||
@@ -428,7 +430,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
},
|
||||
{
|
||||
label: '波动榜',
|
||||
icon: BsLightningFill,
|
||||
icon: Zap,
|
||||
color: 'purple',
|
||||
data: statsData.volatile_concepts,
|
||||
renderItem: (item, index) => (
|
||||
@@ -468,7 +470,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</Badge>
|
||||
{index === 0 && (
|
||||
<Icon
|
||||
as={BsLightningFill}
|
||||
as={Zap}
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
@@ -495,7 +497,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
px={2}
|
||||
py={1}
|
||||
>
|
||||
<Icon as={BsLightningFill} boxSize={2} mr={1} />
|
||||
<Icon as={Zap} boxSize={2} mr={1} />
|
||||
{item.volatility?.toFixed(1)}%
|
||||
</Badge>
|
||||
</Flex>
|
||||
@@ -503,7 +505,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
},
|
||||
{
|
||||
label: '连涨榜',
|
||||
icon: FaRocket,
|
||||
icon: Rocket,
|
||||
color: 'cyan',
|
||||
data: statsData.momentum_concepts,
|
||||
renderItem: (item, index) => (
|
||||
@@ -543,7 +545,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</Badge>
|
||||
{index === 0 && (
|
||||
<Icon
|
||||
as={FaRocket}
|
||||
as={Rocket}
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
@@ -570,7 +572,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
px={2}
|
||||
py={1}
|
||||
>
|
||||
<Icon as={FaRocket} boxSize={2} mr={1} />
|
||||
<Icon as={Rocket} boxSize={2} mr={1} />
|
||||
{item.consecutive_days}天
|
||||
</Badge>
|
||||
</Flex>
|
||||
@@ -620,7 +622,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
<Flex justify="space-between" align="center" w="full">
|
||||
<HStack spacing={2}>
|
||||
<Box p={2} bg="whiteAlpha.100" borderRadius="lg" border="1px solid" borderColor="cyan.500">
|
||||
<Icon as={FaChartLine} color="cyan.400" boxSize={4} />
|
||||
<Icon as={LineChart} color="cyan.400" boxSize={4} />
|
||||
</Box>
|
||||
<VStack align="start" spacing={0}>
|
||||
<Heading size="sm" color="white" fontWeight="bold">
|
||||
|
||||
@@ -31,18 +31,18 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { keyframes } from '@emotion/react';
|
||||
import {
|
||||
FaLayerGroup,
|
||||
FaSync,
|
||||
FaExpand,
|
||||
FaCompress,
|
||||
FaHome,
|
||||
FaArrowUp,
|
||||
FaArrowDown,
|
||||
FaCircle,
|
||||
FaTh,
|
||||
FaChevronRight,
|
||||
FaArrowLeft,
|
||||
} from 'react-icons/fa';
|
||||
Layers,
|
||||
RefreshCw,
|
||||
Maximize2,
|
||||
Minimize2,
|
||||
Home,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
Circle,
|
||||
Grid3x3,
|
||||
ChevronRight,
|
||||
ArrowLeft,
|
||||
} from 'lucide-react';
|
||||
import { logger } from '../../../utils/logger';
|
||||
|
||||
// 极光动画 - 黑金色主题
|
||||
@@ -1052,7 +1052,7 @@ const ForceGraphView = ({
|
||||
borderColor="whiteAlpha.100"
|
||||
>
|
||||
<VStack spacing={4}>
|
||||
<Icon as={FaLayerGroup} boxSize={16} color="gray.600" />
|
||||
<Icon as={Layers} boxSize={16} color="gray.600" />
|
||||
<Text color="gray.400">加载失败:{error}</Text>
|
||||
<Button
|
||||
colorScheme="purple"
|
||||
@@ -1078,7 +1078,7 @@ const ForceGraphView = ({
|
||||
<Tooltip label="返回上一层" placement="bottom">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<FaArrowLeft />}
|
||||
icon={<ArrowLeft />}
|
||||
onClick={handleGoBack}
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
@@ -1104,7 +1104,7 @@ const ForceGraphView = ({
|
||||
border="1px solid"
|
||||
borderColor="whiteAlpha.200"
|
||||
>
|
||||
<Icon as={FaTh} color="purple.300" />
|
||||
<Icon as={Grid3x3} color="purple.300" />
|
||||
<Text color="white" fontWeight="bold" fontSize="sm">
|
||||
概念矩形树图
|
||||
</Text>
|
||||
@@ -1123,7 +1123,7 @@ const ForceGraphView = ({
|
||||
{breadcrumbItems.map((item, index) => (
|
||||
<HStack key={index} spacing={2}>
|
||||
{index > 0 && (
|
||||
<Icon as={FaChevronRight} color="whiteAlpha.400" boxSize={3} />
|
||||
<Icon as={ChevronRight} color="whiteAlpha.400" boxSize={3} />
|
||||
)}
|
||||
<Text
|
||||
color={index === breadcrumbItems.length - 1 ? 'purple.300' : 'whiteAlpha.700'}
|
||||
@@ -1153,7 +1153,7 @@ const ForceGraphView = ({
|
||||
<Tooltip label="返回全部" placement="left">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<FaHome />}
|
||||
icon={<Home />}
|
||||
onClick={handleGoHome}
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
@@ -1174,7 +1174,7 @@ const ForceGraphView = ({
|
||||
<Tooltip label="刷新数据" placement="left">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<FaSync />}
|
||||
icon={<RefreshCw />}
|
||||
onClick={handleRefresh}
|
||||
isLoading={priceLoading}
|
||||
bg="whiteAlpha.100"
|
||||
@@ -1195,7 +1195,7 @@ const ForceGraphView = ({
|
||||
<Tooltip label={isFullscreen ? '退出全屏' : '全屏'} placement="left">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={isFullscreen ? <FaCompress /> : <FaExpand />}
|
||||
icon={isFullscreen ? <Minimize2 /> : <Maximize2 />}
|
||||
onClick={toggleFullscreen}
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
|
||||
@@ -27,87 +27,87 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { keyframes } from '@emotion/react';
|
||||
import {
|
||||
FaLayerGroup,
|
||||
FaExpand,
|
||||
FaCompress,
|
||||
FaSync,
|
||||
FaHome,
|
||||
FaChevronRight,
|
||||
FaBrain,
|
||||
FaMicrochip,
|
||||
FaRobot,
|
||||
FaMobileAlt,
|
||||
FaCar,
|
||||
FaBolt,
|
||||
FaRocket,
|
||||
FaShieldAlt,
|
||||
FaGlobe,
|
||||
FaIndustry,
|
||||
FaShoppingCart,
|
||||
FaCoins,
|
||||
FaHeartbeat,
|
||||
FaAtom,
|
||||
FaArrowUp,
|
||||
FaArrowDown,
|
||||
FaCubes,
|
||||
FaServer,
|
||||
FaCode,
|
||||
FaMagic,
|
||||
FaEye,
|
||||
FaPlane,
|
||||
FaSatellite,
|
||||
FaBatteryFull,
|
||||
FaSolarPanel,
|
||||
FaTags,
|
||||
FaExternalLinkAlt,
|
||||
} from 'react-icons/fa';
|
||||
Layers,
|
||||
Maximize2,
|
||||
Minimize2,
|
||||
RefreshCw,
|
||||
Home,
|
||||
ChevronRight,
|
||||
Brain,
|
||||
Cpu,
|
||||
Bot,
|
||||
Smartphone,
|
||||
Car,
|
||||
Zap,
|
||||
Rocket,
|
||||
Shield,
|
||||
Globe,
|
||||
Factory,
|
||||
ShoppingCart,
|
||||
Coins,
|
||||
Heart,
|
||||
Atom,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
Box as BoxIcon,
|
||||
Server,
|
||||
Code,
|
||||
Sparkles,
|
||||
Eye,
|
||||
Plane,
|
||||
Satellite,
|
||||
BatteryFull,
|
||||
Sun,
|
||||
Tags,
|
||||
ExternalLink,
|
||||
} from 'lucide-react';
|
||||
import { logger } from '../../../utils/logger';
|
||||
|
||||
// 一级分类图标映射
|
||||
const LV1_ICONS = {
|
||||
'人工智能': FaBrain,
|
||||
'半导体': FaMicrochip,
|
||||
'机器人': FaRobot,
|
||||
'消费电子': FaMobileAlt,
|
||||
'智能驾驶与汽车': FaCar,
|
||||
'新能源与电力': FaBolt,
|
||||
'空天经济': FaRocket,
|
||||
'国防军工': FaShieldAlt,
|
||||
'政策与主题': FaGlobe,
|
||||
'周期与材料': FaIndustry,
|
||||
'大消费': FaShoppingCart,
|
||||
'数字经济与金融科技': FaCoins,
|
||||
'全球宏观与贸易': FaGlobe,
|
||||
'医药健康': FaHeartbeat,
|
||||
'前沿科技': FaAtom,
|
||||
'人工智能': Brain,
|
||||
'半导体': Cpu,
|
||||
'机器人': Bot,
|
||||
'消费电子': Smartphone,
|
||||
'智能驾驶与汽车': Car,
|
||||
'新能源与电力': Zap,
|
||||
'空天经济': Rocket,
|
||||
'国防军工': Shield,
|
||||
'政策与主题': Globe,
|
||||
'周期与材料': Factory,
|
||||
'大消费': ShoppingCart,
|
||||
'数字经济与金融科技': Coins,
|
||||
'全球宏观与贸易': Globe,
|
||||
'医药健康': Heart,
|
||||
'前沿科技': Atom,
|
||||
};
|
||||
|
||||
// 二级分类图标映射
|
||||
const LV2_ICONS = {
|
||||
'AI基础设施': FaServer,
|
||||
'AI模型与软件': FaCode,
|
||||
'AI应用': FaMagic,
|
||||
'半导体设备': FaCubes,
|
||||
'半导体材料': FaAtom,
|
||||
'芯片设计与制造': FaMicrochip,
|
||||
'先进封装': FaCubes,
|
||||
'人形机器人整机': FaRobot,
|
||||
'机器人核心零部件': FaCubes,
|
||||
'其他类型机器人': FaRobot,
|
||||
'智能终端': FaMobileAlt,
|
||||
'XR与空间计算': FaEye,
|
||||
'华为产业链': FaMobileAlt,
|
||||
'自动驾驶解决方案': FaCar,
|
||||
'智能汽车产业链': FaCar,
|
||||
'车路协同': FaCar,
|
||||
'新型电池技术': FaBatteryFull,
|
||||
'电力设备与电网': FaBolt,
|
||||
'清洁能源': FaSolarPanel,
|
||||
'低空经济': FaPlane,
|
||||
'商业航天': FaSatellite,
|
||||
'无人作战与信息化': FaShieldAlt,
|
||||
'海军装备': FaShieldAlt,
|
||||
'军贸出海': FaGlobe,
|
||||
'AI基础设施': Server,
|
||||
'AI模型与软件': Code,
|
||||
'AI应用': Sparkles,
|
||||
'半导体设备': BoxIcon,
|
||||
'半导体材料': Atom,
|
||||
'芯片设计与制造': Cpu,
|
||||
'先进封装': BoxIcon,
|
||||
'人形机器人整机': Bot,
|
||||
'机器人核心零部件': BoxIcon,
|
||||
'其他类型机器人': Bot,
|
||||
'智能终端': Smartphone,
|
||||
'XR与空间计算': Eye,
|
||||
'华为产业链': Smartphone,
|
||||
'自动驾驶解决方案': Car,
|
||||
'智能汽车产业链': Car,
|
||||
'车路协同': Car,
|
||||
'新型电池技术': BatteryFull,
|
||||
'电力设备与电网': Zap,
|
||||
'清洁能源': Sun,
|
||||
'低空经济': Plane,
|
||||
'商业航天': Satellite,
|
||||
'无人作战与信息化': Shield,
|
||||
'海军装备': Shield,
|
||||
'军贸出海': Globe,
|
||||
};
|
||||
|
||||
// 根据涨跌幅获取背景渐变色(涨红跌绿)
|
||||
@@ -151,10 +151,10 @@ const formatChangePercent = (value) => {
|
||||
|
||||
// 获取图标
|
||||
const getIcon = (name, level) => {
|
||||
if (level === 'lv1') return LV1_ICONS[name] || FaLayerGroup;
|
||||
if (level === 'lv2') return LV2_ICONS[name] || FaCubes;
|
||||
if (level === 'lv3') return FaCubes;
|
||||
return FaTags;
|
||||
if (level === 'lv1') return LV1_ICONS[name] || Layers;
|
||||
if (level === 'lv2') return LV2_ICONS[name] || Box;
|
||||
if (level === 'lv3') return Box;
|
||||
return Tags;
|
||||
};
|
||||
|
||||
// 从 API 返回的名称中提取纯名称
|
||||
@@ -352,7 +352,7 @@ const GlassCard = ({ item, onClick, size = 'normal' }) => {
|
||||
{/* 外链图标 */}
|
||||
{isLeafConcept && (
|
||||
<Icon
|
||||
as={FaExternalLinkAlt}
|
||||
as={ExternalLink}
|
||||
boxSize={3}
|
||||
color="whiteAlpha.500"
|
||||
/>
|
||||
@@ -372,7 +372,7 @@ const GlassCard = ({ item, onClick, size = 'normal' }) => {
|
||||
<HStack spacing={1} align="center">
|
||||
{hasChange && (isPositive || isNegative) && (
|
||||
<Icon
|
||||
as={isPositive ? FaArrowUp : FaArrowDown}
|
||||
as={isPositive ? ArrowUp : ArrowDown}
|
||||
boxSize={3}
|
||||
color={getChangeTextColor(item.avg_change_pct)}
|
||||
/>
|
||||
@@ -766,7 +766,7 @@ const HierarchyView = ({
|
||||
<Center h="400px" position="relative">
|
||||
<AuroraBackground />
|
||||
<VStack spacing={4} position="relative" zIndex={1}>
|
||||
<Icon as={FaLayerGroup} boxSize={16} color="gray.600" />
|
||||
<Icon as={Layers} boxSize={16} color="gray.600" />
|
||||
<Text color="gray.400">加载失败:{error}</Text>
|
||||
<Button
|
||||
colorScheme="purple"
|
||||
@@ -787,7 +787,7 @@ const HierarchyView = ({
|
||||
<Center h="400px" position="relative">
|
||||
<AuroraBackground />
|
||||
<VStack spacing={4} position="relative" zIndex={1}>
|
||||
<Icon as={FaLayerGroup} boxSize={16} color="gray.600" />
|
||||
<Icon as={Layers} boxSize={16} color="gray.600" />
|
||||
<Text color="gray.400">暂无层级数据</Text>
|
||||
</VStack>
|
||||
</Center>
|
||||
@@ -832,14 +832,14 @@ const HierarchyView = ({
|
||||
{breadcrumbs.map((crumb, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{index > 0 && (
|
||||
<Icon as={FaChevronRight} color="whiteAlpha.400" boxSize={3} mx={1} />
|
||||
<Icon as={ChevronRight} color="whiteAlpha.400" boxSize={3} mx={1} />
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
bg={index === breadcrumbs.length - 1 ? 'purple.500' : 'transparent'}
|
||||
color={index === breadcrumbs.length - 1 ? 'white' : 'whiteAlpha.700'}
|
||||
leftIcon={index === 0 ? <FaHome /> : undefined}
|
||||
leftIcon={index === 0 ? <Home /> : undefined}
|
||||
onClick={() => handleBreadcrumbClick(crumb, index)}
|
||||
isDisabled={index === breadcrumbs.length - 1}
|
||||
fontWeight={index === breadcrumbs.length - 1 ? 'bold' : 'medium'}
|
||||
@@ -861,7 +861,7 @@ const HierarchyView = ({
|
||||
<Tooltip label="刷新涨跌幅" placement="top">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<FaSync />}
|
||||
icon={<RefreshCw />}
|
||||
onClick={handleRefreshPrice}
|
||||
isLoading={priceLoading}
|
||||
bg="whiteAlpha.100"
|
||||
@@ -876,7 +876,7 @@ const HierarchyView = ({
|
||||
<Tooltip label={isFullscreen ? '退出全屏' : '全屏'} placement="top">
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={isFullscreen ? <FaCompress /> : <FaExpand />}
|
||||
icon={isFullscreen ? <Minimize2 /> : <Maximize2 />}
|
||||
onClick={toggleFullscreen}
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
|
||||
@@ -79,9 +79,43 @@ import {
|
||||
Collapse,
|
||||
useBreakpointValue,
|
||||
} from '@chakra-ui/react';
|
||||
import { SearchIcon, ViewIcon, CalendarIcon, ExternalLinkIcon, StarIcon, ChevronDownIcon, InfoIcon, CloseIcon, ChevronRightIcon } from '@chakra-ui/icons';
|
||||
import { FaThLarge, FaList, FaTags, FaChartLine, FaRobot, FaTable, FaHistory, FaBrain, FaLightbulb, FaRocket, FaShieldAlt, FaCalendarAlt, FaArrowUp, FaArrowDown, FaNewspaper, FaFileAlt, FaExpand, FaCompress, FaClock, FaLock, FaSitemap, FaLayerGroup, FaCube, FaProjectDiagram } from 'react-icons/fa';
|
||||
import { BsGraphUp, BsLightningFill } from 'react-icons/bs';
|
||||
import {
|
||||
Search,
|
||||
Eye,
|
||||
Calendar,
|
||||
ExternalLink,
|
||||
Star,
|
||||
ChevronDown,
|
||||
Info,
|
||||
X,
|
||||
ChevronRight,
|
||||
LayoutGrid,
|
||||
List,
|
||||
Tags,
|
||||
LineChart,
|
||||
Bot,
|
||||
Table2,
|
||||
History,
|
||||
Brain,
|
||||
Lightbulb,
|
||||
Rocket,
|
||||
Shield,
|
||||
CalendarDays,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
Newspaper,
|
||||
FileText,
|
||||
Maximize2,
|
||||
Minimize2,
|
||||
Clock,
|
||||
Lock,
|
||||
GitBranch,
|
||||
Layers,
|
||||
Box as BoxIcon,
|
||||
Network,
|
||||
TrendingUp,
|
||||
Zap,
|
||||
} from 'lucide-react';
|
||||
import { keyframes } from '@emotion/react';
|
||||
import ConceptTimelineModal from './ConceptTimelineModal';
|
||||
import ConceptStatsPanel from './components/ConceptStatsPanel';
|
||||
@@ -769,7 +803,7 @@ const ConceptCenter = () => {
|
||||
|
||||
return (
|
||||
<HStack spacing={2}>
|
||||
<Icon as={CalendarIcon} boxSize={3} color="blue.500" />
|
||||
<Icon as={Calendar} boxSize={3} color="blue.500" />
|
||||
<Text fontSize="xs" color="gray.600" fontWeight="medium">
|
||||
添加于 {new Date(addedDate).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1021,7 +1055,7 @@ const ConceptCenter = () => {
|
||||
<Flex align="center" justify="space-between">
|
||||
<Box flex={1}>
|
||||
<HStack spacing={2} mb={{ base: 1, md: 2 }}>
|
||||
<Icon as={FaChartLine} boxSize={3} color="purple.300" />
|
||||
<Icon as={LineChart} boxSize={3} color="purple.300" />
|
||||
<Text fontSize="xs" color="purple.200" fontWeight="bold">
|
||||
热门个股
|
||||
</Text>
|
||||
@@ -1068,7 +1102,7 @@ const ConceptCenter = () => {
|
||||
</>
|
||||
) : (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaLock} boxSize="10px" color="yellow.400" />
|
||||
<Icon as={Lock} boxSize="10px" color="yellow.400" />
|
||||
<Text fontSize="xs" color="yellow.400" fontWeight="medium">
|
||||
升级查看{concept.stocks.length}只个股
|
||||
</Text>
|
||||
@@ -1077,7 +1111,7 @@ const ConceptCenter = () => {
|
||||
</HStack>
|
||||
</Box>
|
||||
<Icon
|
||||
as={hasFeatureAccess('hot_stocks') ? ChevronRightIcon : FaLock}
|
||||
as={hasFeatureAccess('hot_stocks') ? ChevronRight : FaLock}
|
||||
color={hasFeatureAccess('hot_stocks') ? 'purple.300' : 'yellow.400'}
|
||||
boxSize={4}
|
||||
/>
|
||||
@@ -1097,7 +1131,7 @@ const ConceptCenter = () => {
|
||||
if (latestOutbreak) {
|
||||
return (
|
||||
<HStack spacing={2}>
|
||||
<Icon as={BsLightningFill} boxSize={3} color="orange.400" />
|
||||
<Icon as={Zap} boxSize={3} color="orange.400" />
|
||||
<Text fontSize="xs" color="orange.300" fontWeight="medium">
|
||||
爆发于 {new Date(latestOutbreak).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1106,7 +1140,7 @@ const ConceptCenter = () => {
|
||||
} else if (addedDate) {
|
||||
return (
|
||||
<HStack spacing={2}>
|
||||
<Icon as={CalendarIcon} boxSize={3} color="cyan.400" />
|
||||
<Icon as={Calendar} boxSize={3} color="cyan.400" />
|
||||
<Text fontSize="xs" color="whiteAlpha.600" fontWeight="medium">
|
||||
添加于 {new Date(addedDate).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1202,7 +1236,7 @@ const ConceptCenter = () => {
|
||||
border="1px solid"
|
||||
borderColor="whiteAlpha.100"
|
||||
>
|
||||
<Icon as={FaTags} boxSize={{ base: 6, md: 8 }} color="white" opacity={0.8} />
|
||||
<Icon as={Tags} boxSize={{ base: 6, md: 8 }} color="white" opacity={0.8} />
|
||||
{hasChange && (
|
||||
<Badge
|
||||
position="absolute"
|
||||
@@ -1247,7 +1281,7 @@ const ConceptCenter = () => {
|
||||
_hover={{ color: 'purple.300' }}
|
||||
transition="color 0.2s"
|
||||
>
|
||||
<Icon as={FaChartLine} boxSize={4} color="purple.300" />
|
||||
<Icon as={LineChart} boxSize={4} color="purple.300" />
|
||||
<Text fontSize="sm" fontWeight="medium" color="whiteAlpha.800" _groupHover={{ color: 'purple.300' }}>
|
||||
{concept.stock_count || 0} 只股票
|
||||
</Text>
|
||||
@@ -1255,7 +1289,7 @@ const ConceptCenter = () => {
|
||||
|
||||
{hasChange && concept.price_info?.trade_date && (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaCalendarAlt} boxSize={4} color="cyan.400" />
|
||||
<Icon as={CalendarDays} boxSize={4} color="cyan.400" />
|
||||
<Text fontSize="sm" color="whiteAlpha.600">
|
||||
{new Date(concept.price_info.trade_date).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1270,7 +1304,7 @@ const ConceptCenter = () => {
|
||||
if (latestOutbreak) {
|
||||
return (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={BsLightningFill} boxSize={4} color="orange.400" />
|
||||
<Icon as={Zap} boxSize={4} color="orange.400" />
|
||||
<Text fontSize="sm" color="orange.300" fontWeight="medium">
|
||||
爆发于 {new Date(latestOutbreak).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1279,7 +1313,7 @@ const ConceptCenter = () => {
|
||||
} else if (addedDate) {
|
||||
return (
|
||||
<HStack spacing={1}>
|
||||
<Icon as={CalendarIcon} boxSize={4} color="cyan.400" />
|
||||
<Icon as={Calendar} boxSize={4} color="cyan.400" />
|
||||
<Text fontSize="sm" color="whiteAlpha.600">
|
||||
添加于 {new Date(addedDate).toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1297,7 +1331,7 @@ const ConceptCenter = () => {
|
||||
<HStack spacing={3}>
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<ViewIcon />}
|
||||
leftIcon={<Eye size={16} />}
|
||||
bg="whiteAlpha.100"
|
||||
color="white"
|
||||
border="1px solid"
|
||||
@@ -1373,7 +1407,7 @@ const ConceptCenter = () => {
|
||||
) : (
|
||||
<WrapItem>
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaLock} boxSize="8px" color="yellow.400" />
|
||||
<Icon as={Lock} boxSize="8px" color="yellow.400" />
|
||||
<Text fontSize="xs" color="yellow.400" fontWeight="medium">
|
||||
升级查看{concept.stocks.length}只
|
||||
</Text>
|
||||
@@ -1518,7 +1552,7 @@ const ConceptCenter = () => {
|
||||
_hover={{ opacity: 1 }}
|
||||
transition="opacity 0.2s"
|
||||
>
|
||||
<Icon as={InfoIcon} color="blue.300" boxSize={3} />
|
||||
<Icon as={Info} color="blue.300" boxSize={3} />
|
||||
<Text fontSize="xs" color="blue.200">
|
||||
数据更新至 {latestTradeDate.toLocaleDateString('zh-CN')}
|
||||
</Text>
|
||||
@@ -1585,7 +1619,7 @@ const ConceptCenter = () => {
|
||||
{/* 标题区域 */}
|
||||
<VStack spacing={3} textAlign="center">
|
||||
<HStack spacing={3} justify="center">
|
||||
<Icon as={FaBrain} boxSize={10} color="cyan.300" filter="drop-shadow(0 0 10px rgba(6, 182, 212, 0.5))" />
|
||||
<Icon as={Brain} boxSize={10} color="cyan.300" filter="drop-shadow(0 0 10px rgba(6, 182, 212, 0.5))" />
|
||||
</HStack>
|
||||
|
||||
<VStack spacing={1}>
|
||||
@@ -1601,7 +1635,7 @@ const ConceptCenter = () => {
|
||||
概念中心
|
||||
</Heading>
|
||||
<HStack spacing={2} justify="center">
|
||||
<Icon as={FaClock} boxSize={3} color="cyan.200" />
|
||||
<Icon as={Clock} boxSize={3} color="cyan.200" />
|
||||
<Text fontSize="xs" fontWeight="medium" opacity={0.8}>
|
||||
数据约下午4点更新
|
||||
</Text>
|
||||
@@ -1627,21 +1661,21 @@ const ConceptCenter = () => {
|
||||
boxShadow="0 8px 32px rgba(0, 0, 0, 0.3)"
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FaTags} boxSize={4} color="cyan.300" />
|
||||
<Icon as={Tags} boxSize={4} color="cyan.300" />
|
||||
<VStack spacing={0} align="start">
|
||||
<Text fontSize="xl" fontWeight="bold" color="cyan.300">500+</Text>
|
||||
<Text fontSize="xs" opacity={0.7}>概念板块</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FaChartLine} boxSize={4} color="purple.300" />
|
||||
<Icon as={LineChart} boxSize={4} color="purple.300" />
|
||||
<VStack spacing={0} align="start">
|
||||
<Text fontSize="xl" fontWeight="bold" color="purple.300">5000+</Text>
|
||||
<Text fontSize="xs" opacity={0.7}>相关个股</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
<Icon as={BsLightningFill} boxSize={4} color="yellow.300" />
|
||||
<Icon as={Zap} boxSize={4} color="yellow.300" />
|
||||
<VStack spacing={0} align="start">
|
||||
<Text fontSize="xl" fontWeight="bold" color="yellow.300">24/7</Text>
|
||||
<Text fontSize="xs" opacity={0.7}>实时监控</Text>
|
||||
@@ -1668,7 +1702,7 @@ const ConceptCenter = () => {
|
||||
>
|
||||
<InputGroup size="lg" flex={1}>
|
||||
<InputLeftElement pointerEvents="none" h="full">
|
||||
<Icon as={SearchIcon} color="purple.400" boxSize={5} />
|
||||
<Icon as={Search} color="purple.400" boxSize={5} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
placeholder="搜索概念板块、个股、关键词..."
|
||||
@@ -1696,7 +1730,7 @@ const ConceptCenter = () => {
|
||||
transform="translateY(-50%)"
|
||||
size="sm"
|
||||
aria-label="清除搜索"
|
||||
icon={<CloseIcon />}
|
||||
icon={<X size={16} />}
|
||||
variant="ghost"
|
||||
color="gray.500"
|
||||
borderRadius="full"
|
||||
@@ -1711,7 +1745,7 @@ const ConceptCenter = () => {
|
||||
borderRadius="0 50px 50px 0"
|
||||
bgGradient="linear(135deg, #667eea 0%, #764ba2 100%)"
|
||||
color="white"
|
||||
leftIcon={<SearchIcon />}
|
||||
leftIcon={<Search size={16} />}
|
||||
_hover={{
|
||||
bgGradient: 'linear(135deg, #5568d3 0%, #663a8e 100%)',
|
||||
transform: 'scale(1.02)',
|
||||
@@ -1777,7 +1811,7 @@ const ConceptCenter = () => {
|
||||
{/* 排序方式 - 仅在列表视图显示 */}
|
||||
{viewMode === 'list' && (
|
||||
<HStack spacing={4} align="center">
|
||||
<Icon as={FaTags} boxSize={4} color="purple.300" />
|
||||
<Icon as={Tags} boxSize={4} color="purple.300" />
|
||||
<Text fontWeight="bold" color="white">排序方式:</Text>
|
||||
<Select
|
||||
value={sortBy}
|
||||
@@ -1812,7 +1846,7 @@ const ConceptCenter = () => {
|
||||
borderRadius="full"
|
||||
boxShadow="0 0 10px rgba(59, 130, 246, 0.4)"
|
||||
>
|
||||
<Icon as={InfoIcon} color="white" boxSize={3} />
|
||||
<Icon as={Info} color="white" boxSize={3} />
|
||||
<Text fontSize="xs" color="white" fontWeight="medium">
|
||||
智能排序
|
||||
</Text>
|
||||
@@ -1896,7 +1930,7 @@ const ConceptCenter = () => {
|
||||
{selectedDate && viewMode !== 'hierarchy' && viewMode !== 'force3d' && (
|
||||
<Box mb={4} p={3} bg="rgba(59, 130, 246, 0.2)" borderRadius="xl" borderLeft="4px solid" borderColor="blue.400">
|
||||
<HStack>
|
||||
<Icon as={InfoIcon} color="blue.300" />
|
||||
<Icon as={Info} color="blue.300" />
|
||||
<Text fontSize="sm" color="whiteAlpha.800">
|
||||
当前显示 <Text as="strong" color="cyan.300">{selectedDate.toLocaleDateString('zh-CN')}</Text> 的概念涨跌幅数据
|
||||
{searchQuery && <span>,搜索词:<Text as="strong" color="cyan.300">"{searchQuery}"</Text></span>}
|
||||
@@ -2030,7 +2064,7 @@ const ConceptCenter = () => {
|
||||
) : viewMode !== 'hierarchy' && viewMode !== 'force3d' ? (
|
||||
<Center h="400px">
|
||||
<VStack spacing={6}>
|
||||
<Icon as={FaTags} boxSize={20} color="whiteAlpha.300" />
|
||||
<Icon as={Tags} boxSize={20} color="whiteAlpha.300" />
|
||||
<VStack spacing={2}>
|
||||
<Text fontSize="xl" color="white" fontWeight="medium">暂无概念数据</Text>
|
||||
<Text color="whiteAlpha.600">
|
||||
@@ -2075,7 +2109,7 @@ const ConceptCenter = () => {
|
||||
>
|
||||
<CardBody p={6}>
|
||||
<VStack spacing={4} textAlign="center">
|
||||
<Icon as={FaChartLine} boxSize={12} color="whiteAlpha.300" />
|
||||
<Icon as={LineChart} boxSize={12} color="whiteAlpha.300" />
|
||||
<VStack spacing={2}>
|
||||
<Heading size="md" color="white">
|
||||
概念统计中心
|
||||
@@ -2087,7 +2121,7 @@ const ConceptCenter = () => {
|
||||
<Button
|
||||
bg="blue.500"
|
||||
color="white"
|
||||
leftIcon={<Icon as={FaRocket} />}
|
||||
leftIcon={<Icon as={Rocket} />}
|
||||
onClick={() => {
|
||||
setUpgradeFeature('pro');
|
||||
setUpgradeModalOpen(true);
|
||||
|
||||
@@ -12,11 +12,11 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { init, dispose } from 'klinecharts';
|
||||
import {
|
||||
FaExpand,
|
||||
FaCompress,
|
||||
FaCamera,
|
||||
FaRedo,
|
||||
} from 'react-icons/fa';
|
||||
Maximize,
|
||||
Minimize,
|
||||
Camera,
|
||||
RotateCcw,
|
||||
} from 'lucide-react';
|
||||
import { MetricDataPoint } from '@services/categoryService';
|
||||
|
||||
// 黑金主题配色
|
||||
@@ -265,7 +265,7 @@ const KLineChartView: React.FC<KLineChartViewProps> = ({
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={handleReset}
|
||||
>
|
||||
<Icon as={FaRedo} />
|
||||
<Icon as={RotateCcw} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip label="截图">
|
||||
@@ -276,7 +276,7 @@ const KLineChartView: React.FC<KLineChartViewProps> = ({
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={handleScreenshot}
|
||||
>
|
||||
<Icon as={FaCamera} />
|
||||
<Icon as={Camera} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip label={isFullscreen ? '退出全屏' : '全屏'}>
|
||||
@@ -287,7 +287,7 @@ const KLineChartView: React.FC<KLineChartViewProps> = ({
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={toggleFullscreen}
|
||||
>
|
||||
<Icon as={isFullscreen ? FaCompress : FaExpand} />
|
||||
<Icon as={isFullscreen ? Minimize : Maximize} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</HStack>
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
Input,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaTable, FaChartLine, FaCalendar, FaDownload } from 'react-icons/fa';
|
||||
import { Table2, LineChart, Calendar, Download } from 'lucide-react';
|
||||
import { fetchMetricData, MetricDataResponse, TreeMetric } from '@services/categoryService';
|
||||
import SimpleLineChart from './SimpleLineChart';
|
||||
|
||||
@@ -182,7 +182,7 @@ const MetricDataModal: React.FC<MetricDataModalProps> = ({ isOpen, onClose, metr
|
||||
>
|
||||
<HStack spacing={4} wrap="wrap">
|
||||
<HStack flex="1" minW="200px">
|
||||
<Icon as={FaCalendar} color={themeColors.text.muted} />
|
||||
<Icon as={Calendar} color={themeColors.text.muted} />
|
||||
<Input
|
||||
type="date"
|
||||
size="sm"
|
||||
@@ -235,7 +235,7 @@ const MetricDataModal: React.FC<MetricDataModalProps> = ({ isOpen, onClose, metr
|
||||
variant="outline"
|
||||
borderColor={themeColors.border.gold}
|
||||
color={themeColors.text.gold}
|
||||
leftIcon={<FaDownload />}
|
||||
leftIcon={<Download />}
|
||||
onClick={handleExportCSV}
|
||||
isDisabled={!metricData || !metricData.data || metricData.data.length === 0}
|
||||
>
|
||||
@@ -260,7 +260,7 @@ const MetricDataModal: React.FC<MetricDataModalProps> = ({ isOpen, onClose, metr
|
||||
bg: themeColors.bg.card,
|
||||
}}
|
||||
>
|
||||
<Icon as={FaChartLine} mr={2} />
|
||||
<Icon as={LineChart} mr={2} />
|
||||
折线图
|
||||
</Tab>
|
||||
<Tab
|
||||
@@ -271,7 +271,7 @@ const MetricDataModal: React.FC<MetricDataModalProps> = ({ isOpen, onClose, metr
|
||||
bg: themeColors.bg.card,
|
||||
}}
|
||||
>
|
||||
<Icon as={FaTable} mr={2} />
|
||||
<Icon as={Table2} mr={2} />
|
||||
数据表格
|
||||
</Tab>
|
||||
</TabList>
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaExpand,
|
||||
FaCompress,
|
||||
FaCamera,
|
||||
FaRedo,
|
||||
} from 'react-icons/fa';
|
||||
Maximize,
|
||||
Minimize,
|
||||
Camera,
|
||||
RotateCcw,
|
||||
} from 'lucide-react';
|
||||
import { MetricDataPoint } from '@services/categoryService';
|
||||
|
||||
// 黑金主题配色
|
||||
@@ -386,7 +386,7 @@ const SimpleLineChart: React.FC<SimpleLineChartProps> = ({
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={handleReset}
|
||||
>
|
||||
<Icon as={FaRedo} />
|
||||
<Icon as={RotateCcw} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip label="截图">
|
||||
@@ -397,7 +397,7 @@ const SimpleLineChart: React.FC<SimpleLineChartProps> = ({
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={handleScreenshot}
|
||||
>
|
||||
<Icon as={FaCamera} />
|
||||
<Icon as={Camera} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip label={isFullscreen ? '退出全屏' : '全屏'}>
|
||||
@@ -408,7 +408,7 @@ const SimpleLineChart: React.FC<SimpleLineChartProps> = ({
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={toggleFullscreen}
|
||||
>
|
||||
<Icon as={isFullscreen ? FaCompress : FaExpand} />
|
||||
<Icon as={isFullscreen ? Minimize : Maximize} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</HStack>
|
||||
|
||||
@@ -21,17 +21,17 @@ import {
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaDatabase,
|
||||
FaFolder,
|
||||
FaFolderOpen,
|
||||
FaFile,
|
||||
FaSearch,
|
||||
FaHome,
|
||||
FaChevronRight,
|
||||
FaChevronDown,
|
||||
FaTimes,
|
||||
FaEye,
|
||||
} from 'react-icons/fa';
|
||||
Database,
|
||||
Folder,
|
||||
FolderOpen,
|
||||
File,
|
||||
Search,
|
||||
Home,
|
||||
ChevronRight,
|
||||
ChevronDown,
|
||||
X,
|
||||
Eye,
|
||||
} from 'lucide-react';
|
||||
import { motion } from 'framer-motion';
|
||||
import {
|
||||
fetchCategoryTree,
|
||||
@@ -126,7 +126,7 @@ const TreeNodeComponent: React.FC<{
|
||||
<Spinner size="xs" color={themeColors.primary.gold} mr={2} />
|
||||
) : hasChildren || !hasMetrics ? (
|
||||
<Icon
|
||||
as={isExpanded ? FaChevronDown : FaChevronRight}
|
||||
as={isExpanded ? ChevronDown : ChevronRight}
|
||||
color={themeColors.text.muted}
|
||||
mr={2}
|
||||
fontSize="xs"
|
||||
@@ -136,7 +136,7 @@ const TreeNodeComponent: React.FC<{
|
||||
)}
|
||||
|
||||
<Icon
|
||||
as={hasChildren || !hasMetrics ? (isExpanded ? FaFolderOpen : FaFolder) : FaFile}
|
||||
as={hasChildren || !hasMetrics ? (isExpanded ? FolderOpen : Folder) : File}
|
||||
color={hasChildren || !hasMetrics ? themeColors.primary.gold : themeColors.text.secondary}
|
||||
mr={2}
|
||||
/>
|
||||
@@ -244,7 +244,7 @@ const MetricCard: React.FC<{ metric: TreeMetric; onClick: () => void }> = ({ met
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
color={themeColors.primary.gold}
|
||||
leftIcon={<FaEye />}
|
||||
leftIcon={<Eye />}
|
||||
_hover={{ bg: themeColors.bg.cardHover }}
|
||||
>
|
||||
查看数据
|
||||
@@ -489,7 +489,7 @@ const DataBrowser: React.FC = () => {
|
||||
>
|
||||
<VStack spacing={4} align="stretch" mb={8}>
|
||||
<HStack spacing={4}>
|
||||
<Icon as={FaDatabase} color={themeColors.primary.gold} boxSize={8} />
|
||||
<Icon as={Database} color={themeColors.primary.gold} boxSize={8} />
|
||||
<VStack align="start" spacing={0}>
|
||||
<Text
|
||||
fontSize="3xl"
|
||||
@@ -568,7 +568,7 @@ const DataBrowser: React.FC = () => {
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
leftIcon={<FaSearch />}
|
||||
leftIcon={<Search />}
|
||||
bg={themeColors.primary.gold}
|
||||
color={themeColors.bg.primary}
|
||||
_hover={{ bg: themeColors.primary.goldLight }}
|
||||
@@ -579,7 +579,7 @@ const DataBrowser: React.FC = () => {
|
||||
</Button>
|
||||
{searchQuery && (
|
||||
<Button
|
||||
leftIcon={<FaTimes />}
|
||||
leftIcon={<X />}
|
||||
variant="ghost"
|
||||
color={themeColors.text.secondary}
|
||||
_hover={{ color: themeColors.text.primary }}
|
||||
@@ -625,7 +625,7 @@ const DataBrowser: React.FC = () => {
|
||||
<CardBody py={2}>
|
||||
<Breadcrumb
|
||||
spacing={2}
|
||||
separator={<Icon as={FaChevronRight} color={themeColors.text.muted} />}
|
||||
separator={<Icon as={ChevronRight} color={themeColors.text.muted} />}
|
||||
>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
@@ -633,7 +633,7 @@ const DataBrowser: React.FC = () => {
|
||||
_hover={{ color: themeColors.primary.gold }}
|
||||
onClick={() => handleBreadcrumbClick(-1)}
|
||||
>
|
||||
<Icon as={FaHome} />
|
||||
<Icon as={Home} />
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
{breadcrumbs.map((crumb, index) => (
|
||||
@@ -754,7 +754,7 @@ const DataBrowser: React.FC = () => {
|
||||
) : searchResults ? (
|
||||
<Flex justify="center" align="center" py={10}>
|
||||
<VStack spacing={3}>
|
||||
<Icon as={FaSearch} color={themeColors.text.muted} boxSize={12} />
|
||||
<Icon as={Search} color={themeColors.text.muted} boxSize={12} />
|
||||
<Text color={themeColors.text.muted}>未找到匹配的指标</Text>
|
||||
<Text color={themeColors.text.muted} fontSize="sm">
|
||||
尝试使用不同的关键词
|
||||
@@ -837,7 +837,7 @@ const DataBrowser: React.FC = () => {
|
||||
) : (
|
||||
<Flex justify="center" align="center" py={10}>
|
||||
<VStack spacing={3}>
|
||||
<Icon as={FaFolder} color={themeColors.text.muted} boxSize={12} />
|
||||
<Icon as={Folder} color={themeColors.text.muted} boxSize={12} />
|
||||
<Text color={themeColors.text.muted}>
|
||||
{currentNode.children && currentNode.children.length > 0
|
||||
? '该节点包含子分类,请展开查看'
|
||||
@@ -850,7 +850,7 @@ const DataBrowser: React.FC = () => {
|
||||
) : (
|
||||
<Flex justify="center" align="center" py={20}>
|
||||
<VStack spacing={4}>
|
||||
<Icon as={FaDatabase} color={themeColors.primary.gold} boxSize={16} />
|
||||
<Icon as={Database} color={themeColors.primary.gold} boxSize={16} />
|
||||
<Text color={themeColors.text.secondary} fontSize="lg" textAlign="center">
|
||||
选择左侧分类树节点查看详情
|
||||
</Text>
|
||||
|
||||
@@ -25,15 +25,14 @@ import {
|
||||
StatArrow
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaHeart,
|
||||
FaRegHeart,
|
||||
FaEye,
|
||||
FaComment,
|
||||
FaUsers,
|
||||
FaClock,
|
||||
FaCalendarAlt,
|
||||
FaChartLine
|
||||
} from 'react-icons/fa';
|
||||
Heart,
|
||||
Eye,
|
||||
MessageCircle,
|
||||
Users,
|
||||
Clock,
|
||||
Calendar,
|
||||
LineChart
|
||||
} from 'lucide-react';
|
||||
|
||||
const EventHeader = ({ event, onFollowToggle }) => {
|
||||
// 颜色主题
|
||||
@@ -174,7 +173,7 @@ const EventHeader = ({ event, onFollowToggle }) => {
|
||||
</HStack>
|
||||
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FaCalendarAlt} color={textSecondary} />
|
||||
<Icon as={Calendar} color={textSecondary} />
|
||||
<VStack align="flex-start" spacing={0}>
|
||||
<Text fontSize="sm" color={textPrimary}>
|
||||
{formatDate(event.created_at)}
|
||||
@@ -190,7 +189,7 @@ const EventHeader = ({ event, onFollowToggle }) => {
|
||||
{/* 右侧关注按钮 */}
|
||||
<Flex align="flex-start" justify="center">
|
||||
<Button
|
||||
leftIcon={<Icon as={event.is_following ? FaHeart : FaRegHeart} />}
|
||||
leftIcon={<Icon as={Heart} fill={event.is_following ? "currentColor" : "none"} />}
|
||||
colorScheme={event.is_following ? "red" : "blue"}
|
||||
variant={event.is_following ? "solid" : "outline"}
|
||||
size="lg"
|
||||
@@ -226,7 +225,7 @@ const EventHeader = ({ event, onFollowToggle }) => {
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaEye} />
|
||||
<Icon as={Eye} />
|
||||
<Text>浏览量</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
@@ -246,7 +245,7 @@ const EventHeader = ({ event, onFollowToggle }) => {
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaComment} />
|
||||
<Icon as={MessageCircle} />
|
||||
<Text>回复数</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
@@ -266,7 +265,7 @@ const EventHeader = ({ event, onFollowToggle }) => {
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaUsers} />
|
||||
<Icon as={Users} />
|
||||
<Text>关注数</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
@@ -286,7 +285,7 @@ const EventHeader = ({ event, onFollowToggle }) => {
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaChartLine} />
|
||||
<Icon as={LineChart} />
|
||||
<Text>热度分</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
|
||||
@@ -27,9 +27,9 @@ import {
|
||||
Tooltip
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaChartLine,
|
||||
FaInfoCircle
|
||||
} from 'react-icons/fa';
|
||||
LineChart,
|
||||
Info
|
||||
} from 'lucide-react';
|
||||
import { Tag } from 'antd';
|
||||
import { RobotOutlined } from '@ant-design/icons';
|
||||
import { stockService } from '@services/eventService';
|
||||
@@ -230,7 +230,7 @@ const HistoricalEvents = ({
|
||||
borderRadius="md"
|
||||
>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FaChartLine} color="yellow.600" boxSize="20px" />
|
||||
<Icon as={LineChart} color="yellow.600" boxSize="20px" />
|
||||
<VStack align="flex-start" spacing={1}>
|
||||
<Text fontSize="sm" fontWeight="bold" color="yellow.800">
|
||||
超预期得分: {expectationScore}
|
||||
@@ -306,7 +306,7 @@ const HistoricalEvents = ({
|
||||
{/* 右侧:相关股票按钮 */}
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<Icon as={FaChartLine} />}
|
||||
leftIcon={<Icon as={LineChart} boxSize={4} />}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleViewStocks(event);
|
||||
@@ -467,7 +467,7 @@ const StocksList = ({ stocks, eventTradingDate }) => {
|
||||
if (!stocks || stocks.length === 0) {
|
||||
return (
|
||||
<Box textAlign="center" py={12} color={textSecondary}>
|
||||
<Icon as={FaInfoCircle} boxSize="48px" mb={4} />
|
||||
<Icon as={Info} boxSize="48px" mb={4} />
|
||||
<Text fontSize="lg" mb={2}>暂无相关股票数据</Text>
|
||||
<Text fontSize="sm">该历史事件暂未关联股票信息</Text>
|
||||
</Box>
|
||||
@@ -533,7 +533,7 @@ const StocksList = ({ stocks, eventTradingDate }) => {
|
||||
variant="ghost"
|
||||
colorScheme={stock.event_day_change_pct > 0 ? 'red' : stock.event_day_change_pct < 0 ? 'green' : 'gray'}
|
||||
onClick={() => handleOpenKLine(stock)}
|
||||
rightIcon={<Icon as={FaChartLine} boxSize={3} />}
|
||||
rightIcon={<Icon as={LineChart} boxSize={3} />}
|
||||
px={2}
|
||||
>
|
||||
<Text
|
||||
|
||||
@@ -42,15 +42,15 @@ import {
|
||||
Container,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FiTrendingUp,
|
||||
FiBarChart2,
|
||||
FiPieChart,
|
||||
FiActivity,
|
||||
FiDownload,
|
||||
FiCalendar,
|
||||
FiTarget,
|
||||
FiZap,
|
||||
} from 'react-icons/fi';
|
||||
TrendingUp,
|
||||
BarChart2,
|
||||
PieChart,
|
||||
Activity,
|
||||
Download,
|
||||
Calendar,
|
||||
Target,
|
||||
Zap,
|
||||
} from 'lucide-react';
|
||||
import 'echarts-wordcloud';
|
||||
|
||||
// 导入现有的卡片组件
|
||||
@@ -484,7 +484,7 @@ const LimitAnalyse = () => {
|
||||
<HStack justify="space-between" align="center">
|
||||
<VStack align="start" spacing={2}>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiTrendingUp} color="blue.500" boxSize={6} />
|
||||
<Icon as={TrendingUp} color="blue.500" boxSize={6} />
|
||||
<Text fontSize="xl" fontWeight="bold">
|
||||
涨停分析
|
||||
</Text>
|
||||
@@ -508,7 +508,7 @@ const LimitAnalyse = () => {
|
||||
))}
|
||||
</Select>
|
||||
<Button
|
||||
leftIcon={<FiDownload />}
|
||||
leftIcon={<Icon as={Download} boxSize={4} />}
|
||||
colorScheme="blue"
|
||||
variant="outline"
|
||||
onClick={() => handleExport('excel')}
|
||||
@@ -536,7 +536,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl" overflow="hidden">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiPieChart} color="blue.500" boxSize={5} />
|
||||
<Icon as={PieChart} color="blue.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
板块分布
|
||||
</Text>
|
||||
@@ -564,7 +564,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl" overflow="hidden">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiBarChart2} color="green.500" boxSize={5} />
|
||||
<Icon as={BarChart2} color="green.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
板块股票数量
|
||||
</Text>
|
||||
@@ -592,7 +592,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl" overflow="hidden">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiPieChart} color="purple.500" boxSize={5} />
|
||||
<Icon as={PieChart} color="purple.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
板块关联TOP10
|
||||
</Text>
|
||||
@@ -637,7 +637,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl" overflow="hidden">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiPieChart} color="purple.500" boxSize={5} />
|
||||
<Icon as={PieChart} color="purple.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
板块关联关系图
|
||||
</Text>
|
||||
@@ -670,7 +670,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl" overflow="hidden">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiActivity} color="orange.500" boxSize={5} />
|
||||
<Icon as={Activity} color="orange.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
热点词云
|
||||
</Text>
|
||||
@@ -691,7 +691,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiActivity} color="purple.500" boxSize={5} />
|
||||
<Icon as={Activity} color="purple.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
数据统计
|
||||
</Text>
|
||||
@@ -700,25 +700,25 @@ const LimitAnalyse = () => {
|
||||
<CardBody>
|
||||
<Grid templateColumns="repeat(auto-fit, minmax(200px, 1fr))" gap={4}>
|
||||
<StatCard
|
||||
icon={FiTarget}
|
||||
icon={Target}
|
||||
label="涨停股票总数"
|
||||
value={totalStocks}
|
||||
color="blue"
|
||||
/>
|
||||
<StatCard
|
||||
icon={FiBarChart2}
|
||||
icon={BarChart2}
|
||||
label="涉及板块数"
|
||||
value={sectorCount}
|
||||
color="green"
|
||||
/>
|
||||
<StatCard
|
||||
icon={FiTrendingUp}
|
||||
icon={TrendingUp}
|
||||
label="平均涨幅"
|
||||
value={`${avgChange}%`}
|
||||
color="orange"
|
||||
/>
|
||||
<StatCard
|
||||
icon={FiZap}
|
||||
icon={Zap}
|
||||
label="最大涨幅"
|
||||
value={`${maxChange}%`}
|
||||
color="red"
|
||||
@@ -735,7 +735,7 @@ const LimitAnalyse = () => {
|
||||
<Card bg={cardBg} shadow="xl" borderRadius="2xl">
|
||||
<CardHeader>
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FiBarChart2} color="teal.500" boxSize={5} />
|
||||
<Icon as={BarChart2} color="teal.500" boxSize={5} />
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
板块详细数据
|
||||
</Text>
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
Center,
|
||||
Divider
|
||||
} from '@chakra-ui/react';
|
||||
import { FaEye, FaExternalLinkAlt, FaChartLine, FaCalendarAlt } from 'react-icons/fa';
|
||||
import { Eye, ExternalLink, LineChart, Calendar } from 'lucide-react';
|
||||
import dayjs from 'dayjs';
|
||||
import tradingDayUtils from '../../../utils/tradingDayUtils'; // 引入交易日工具
|
||||
import { logger } from '../../../utils/logger';
|
||||
@@ -230,7 +230,7 @@ const ConceptCard = ({ concept, tradingDate, onViewDetails }) => {
|
||||
<Button
|
||||
size="sm"
|
||||
colorScheme="blue"
|
||||
leftIcon={<FaChartLine />}
|
||||
leftIcon={<Icon as={LineChart} boxSize={4} />}
|
||||
flex={1}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -243,7 +243,7 @@ const ConceptCard = ({ concept, tradingDate, onViewDetails }) => {
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="blue"
|
||||
leftIcon={<FaEye />}
|
||||
leftIcon={<Icon as={Eye} boxSize={4} />}
|
||||
flex={1}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -532,7 +532,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
leftIcon={<FaChartLine />}
|
||||
leftIcon={<Icon as={LineChart} boxSize={5} />}
|
||||
onClick={() => window.open('https://valuefrontier.cn/concepts', '_blank')}
|
||||
>
|
||||
进入概念中心
|
||||
@@ -547,7 +547,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
{effectiveTradingDate && (
|
||||
<Box mb={4} p={3} bg={bgColor} borderRadius="md">
|
||||
<HStack spacing={2}>
|
||||
<FaCalendarAlt color={textColor} />
|
||||
<Icon as={Calendar} color={textColor} boxSize={4} />
|
||||
<Text fontSize="sm" color={textColor}>
|
||||
涨跌幅数据日期:{effectiveTradingDate}
|
||||
{eventTime && effectiveTradingDate !== dayjs(eventTime).format('YYYY-MM-DD') && (
|
||||
@@ -578,7 +578,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
leftIcon={<FaChartLine />}
|
||||
leftIcon={<Icon as={LineChart} boxSize={5} />}
|
||||
onClick={() => window.open('https://valuefrontier.cn/concepts', '_blank')}
|
||||
px={8}
|
||||
py={6}
|
||||
@@ -641,7 +641,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
{selectedConcept?.description && (
|
||||
<Box>
|
||||
<HStack mb={3}>
|
||||
<Icon as={FaChartLine} color="blue.500" />
|
||||
<Icon as={LineChart} color="blue.500" />
|
||||
<Text fontSize="md" fontWeight="bold">
|
||||
概念解析
|
||||
</Text>
|
||||
@@ -666,7 +666,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
{selectedConcept?.happened_times && selectedConcept.happened_times.length > 0 && (
|
||||
<Box>
|
||||
<HStack mb={3}>
|
||||
<Icon as={FaCalendarAlt} color="purple.500" />
|
||||
<Icon as={Calendar} color="purple.500" />
|
||||
<Text fontSize="md" fontWeight="bold">
|
||||
历史触发时间
|
||||
</Text>
|
||||
@@ -691,7 +691,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
{selectedConcept?.stocks && selectedConcept.stocks.length > 0 && (
|
||||
<Box>
|
||||
<HStack mb={3}>
|
||||
<Icon as={FaEye} color="green.500" />
|
||||
<Icon as={Eye} color="green.500" />
|
||||
<Text fontSize="md" fontWeight="bold">
|
||||
核心相关股票 ({selectedConcept.stock_count}只)
|
||||
</Text>
|
||||
@@ -760,7 +760,7 @@ const RelatedConcepts = ({ eventTitle, eventTime, eventId, loading: externalLoad
|
||||
onClick={() => {
|
||||
window.open(`https://valuefrontier.cn/htmls/${encodeURIComponent(selectedConcept.concept)}.html`, '_blank');
|
||||
}}
|
||||
leftIcon={<FaExternalLinkAlt />}
|
||||
leftIcon={<Icon as={ExternalLink} boxSize={4} />}
|
||||
>
|
||||
查看概念详情页
|
||||
</Button>
|
||||
|
||||
@@ -41,12 +41,12 @@ import {
|
||||
useToast
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaPlus,
|
||||
FaTrash,
|
||||
FaChartLine,
|
||||
FaRedo,
|
||||
FaSearch
|
||||
} from 'react-icons/fa';
|
||||
Plus,
|
||||
Trash2,
|
||||
LineChart,
|
||||
RefreshCw,
|
||||
Search
|
||||
} from 'lucide-react';
|
||||
import { echarts } from '@lib/echarts';
|
||||
import StockChartModal from '../../../components/StockChart/StockChartModal';
|
||||
|
||||
@@ -297,7 +297,7 @@ const RelatedStocks = ({
|
||||
<Flex mb={4} align="center" wrap="wrap" gap={4}>
|
||||
{/* 搜索框 */}
|
||||
<HStack>
|
||||
<FaSearch />
|
||||
<Icon as={Search} boxSize={4} />
|
||||
<Input
|
||||
placeholder="搜索股票代码或名称..."
|
||||
value={searchTerm}
|
||||
@@ -313,7 +313,7 @@ const RelatedStocks = ({
|
||||
<HStack>
|
||||
<Tooltip label="刷新报价">
|
||||
<IconButton
|
||||
icon={<FaRedo />}
|
||||
icon={<Icon as={RefreshCw} boxSize={4} />}
|
||||
size="sm"
|
||||
onClick={handleRefreshQuotes}
|
||||
isLoading={quotesLoading}
|
||||
@@ -487,7 +487,7 @@ const RelatedStocks = ({
|
||||
|
||||
<Tooltip label="查看K线图">
|
||||
<IconButton
|
||||
icon={<FaChartLine />}
|
||||
icon={<Icon as={LineChart} boxSize={3} />}
|
||||
size="xs"
|
||||
onClick={() => handleShowChart(stock)}
|
||||
aria-label="查看K线图"
|
||||
@@ -496,7 +496,7 @@ const RelatedStocks = ({
|
||||
|
||||
<Tooltip label="删除">
|
||||
<IconButton
|
||||
icon={<FaTrash />}
|
||||
icon={<Icon as={Trash2} boxSize={3} />}
|
||||
size="xs"
|
||||
colorScheme="red"
|
||||
variant="ghost"
|
||||
|
||||
@@ -32,8 +32,7 @@ import {
|
||||
Tooltip,
|
||||
Center
|
||||
} from '@chakra-ui/react';
|
||||
import { InfoIcon, ViewIcon } from '@chakra-ui/icons';
|
||||
import { Share2, GitBranch, Inbox } from 'lucide-react';
|
||||
import { Info, Eye, Share2, GitBranch, Inbox } from 'lucide-react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import { eventService } from '../../../services/eventService';
|
||||
import CitedContent from '../../../components/Citation/CitedContent';
|
||||
@@ -875,7 +874,7 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
py={1}
|
||||
borderRadius="md"
|
||||
>
|
||||
<Icon as={ViewIcon} mr={1} boxSize={3} />
|
||||
<Eye size={12} style={{ display: 'inline', marginRight: '4px' }} />
|
||||
点击节点查看详情
|
||||
</Text>
|
||||
{chartReady && (
|
||||
|
||||
@@ -37,7 +37,7 @@ import {
|
||||
useColorModeValue,
|
||||
} from '@chakra-ui/react';
|
||||
import { getFormattedTextProps } from '../../../utils/textUtils';
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import { ExternalLink } from 'lucide-react';
|
||||
import RiskDisclaimer from '../../../components/RiskDisclaimer';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import 'echarts-wordcloud';
|
||||
@@ -760,7 +760,7 @@ export const StockDetailModal = ({ isOpen, onClose, selectedStock }) => {
|
||||
<Button variant="ghost" mr={3} onClick={onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
<Button colorScheme="blue" leftIcon={<ExternalLinkIcon />}>
|
||||
<Button colorScheme="blue" leftIcon={<ExternalLink size={16} />}>
|
||||
查看K线图
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
} from '@chakra-ui/react';
|
||||
import { ChevronLeftIcon, ChevronRightIcon, CalendarIcon } from '@chakra-ui/icons';
|
||||
import { ChevronLeft, ChevronRight, Calendar } from 'lucide-react';
|
||||
|
||||
const EnhancedCalendar = ({
|
||||
selectedDate,
|
||||
@@ -110,20 +110,20 @@ const EnhancedCalendar = ({
|
||||
<VStack spacing={3}>
|
||||
<HStack justify="space-between" w="full">
|
||||
<IconButton
|
||||
icon={<ChevronLeftIcon />}
|
||||
icon={<ChevronLeft size={compact ? 16 : 20} />}
|
||||
size={compact ? 'sm' : 'md'}
|
||||
variant="ghost"
|
||||
onClick={() => setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1))}
|
||||
aria-label="上个月"
|
||||
/>
|
||||
<HStack spacing={2}>
|
||||
<CalendarIcon boxSize={5} />
|
||||
<Calendar size={20} />
|
||||
<Heading size={headerSize}>
|
||||
{currentMonth.getFullYear()}年 {monthNames[currentMonth.getMonth()]}
|
||||
</Heading>
|
||||
</HStack>
|
||||
<IconButton
|
||||
icon={<ChevronRightIcon />}
|
||||
icon={<ChevronRight size={compact ? 16 : 20} />}
|
||||
size={compact ? 'sm' : 'md'}
|
||||
variant="ghost"
|
||||
onClick={() => setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1))}
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
Flex,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { StarIcon, TriangleUpIcon } from '@chakra-ui/icons';
|
||||
import { Star, TrendingUp } from 'lucide-react';
|
||||
import { logger } from '../../../utils/logger';
|
||||
import ztStaticService from '../../../services/ztStaticService';
|
||||
|
||||
@@ -124,7 +124,7 @@ const HighPositionStocks = ({ dateStr }) => {
|
||||
<CardHeader bg="red.500" color="white" borderTopRadius="xl">
|
||||
<Flex justify="space-between" align="center">
|
||||
<HStack spacing={3}>
|
||||
<TriangleUpIcon boxSize={6} />
|
||||
<TrendingUp size={24} />
|
||||
<Heading size="md">高位股统计</Heading>
|
||||
</HStack>
|
||||
<HStack spacing={2}>
|
||||
@@ -203,7 +203,7 @@ const HighPositionStocks = ({ dateStr }) => {
|
||||
<HStack>
|
||||
<Text>{stock.stock_name}</Text>
|
||||
{stock.continuous_limit_up >= 5 && (
|
||||
<StarIcon color="red.500" boxSize={3} />
|
||||
<Star size={12} color="#E53E3E" fill="#E53E3E" />
|
||||
)}
|
||||
</HStack>
|
||||
</Td>
|
||||
@@ -241,7 +241,7 @@ const HighPositionStocks = ({ dateStr }) => {
|
||||
{/* 风险提示 */}
|
||||
<Box mt={4} p={3} bg="yellow.50" borderRadius="md" border="1px solid" borderColor="yellow.200">
|
||||
<HStack spacing={2}>
|
||||
<Icon as={TriangleUpIcon} color="yellow.500" />
|
||||
<Box as={TrendingUp} size={20} color="#D69E2E" />
|
||||
<Text fontSize="sm" color="yellow.700">
|
||||
<strong>风险提示:</strong>高位股通常具有较高的波动性和风险,请谨慎投资。
|
||||
连续涨停天数越多,风险相对越高。
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
AlertIcon,
|
||||
} from '@chakra-ui/react';
|
||||
import { formatTooltipText, getFormattedTextProps } from '../../../utils/textUtils';
|
||||
import { SearchIcon, DownloadIcon } from '@chakra-ui/icons';
|
||||
import { Search, Download } from 'lucide-react';
|
||||
|
||||
// 简化版搜索组件 - 仅支持股票代码/名称精确匹配
|
||||
export const AdvancedSearch = ({ onSearch, loading }) => {
|
||||
@@ -73,7 +73,7 @@ export const AdvancedSearch = ({ onSearch, loading }) => {
|
||||
<HStack w="full" spacing={3}>
|
||||
<InputGroup size="lg" flex={1}>
|
||||
<InputLeftElement>
|
||||
<SearchIcon color="gray.400" />
|
||||
<Search size={20} color="#A0AEC0" />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
placeholder="输入股票代码或名称搜索(如 600000 或 浦发银行)"
|
||||
@@ -89,7 +89,7 @@ export const AdvancedSearch = ({ onSearch, loading }) => {
|
||||
onClick={handleSearch}
|
||||
isLoading={loading}
|
||||
px={8}
|
||||
leftIcon={<SearchIcon />}
|
||||
leftIcon={<Search size={20} />}
|
||||
>
|
||||
搜索
|
||||
</Button>
|
||||
@@ -152,7 +152,7 @@ export const SearchResultsModal = ({ isOpen, onClose, searchResults, onStockClic
|
||||
</Badge>
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<DownloadIcon />}
|
||||
leftIcon={<Download size={16} />}
|
||||
onClick={exportResults}
|
||||
variant="outline"
|
||||
colorScheme="whiteAlpha"
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
useColorModeValue,
|
||||
Link,
|
||||
} from '@chakra-ui/react';
|
||||
import { StarIcon, TimeIcon, ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import { Star, Clock, ExternalLink } from 'lucide-react';
|
||||
|
||||
const SectorDetails = ({ sortedSectors, totalStocks }) => {
|
||||
// 使用 useRef 来维持展开状态,避免重新渲染时重置
|
||||
@@ -141,7 +141,7 @@ const SectorDetails = ({ sortedSectors, totalStocks }) => {
|
||||
>
|
||||
<Text fontWeight="bold" fontSize="md">{index + 1}</Text>
|
||||
</Circle>
|
||||
{sector === '公告' && <StarIcon />}
|
||||
{sector === '公告' && <Star size={16} />}
|
||||
<VStack align="start" spacing={0}>
|
||||
<Text fontWeight="bold" fontSize="lg">{sector}</Text>
|
||||
<Text fontSize="sm" opacity={0.9}>
|
||||
@@ -190,7 +190,7 @@ const SectorDetails = ({ sortedSectors, totalStocks }) => {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{stock.sname}
|
||||
<ExternalLinkIcon mx="2px" boxSize={3} />
|
||||
<Box as={ExternalLink} display="inline" size={12} style={{ marginLeft: '2px', marginRight: '2px', verticalAlign: 'middle' }} />
|
||||
</Link>
|
||||
<Badge colorScheme="purple" fontSize="xs">{stock.scode}</Badge>
|
||||
{stock.continuous_days && (
|
||||
@@ -207,7 +207,7 @@ const SectorDetails = ({ sortedSectors, totalStocks }) => {
|
||||
{/* 中间:时间和涨幅信息 */}
|
||||
<HStack spacing={4} fontSize="xs" color="gray.500" flex={1} justify="center">
|
||||
<HStack spacing={1}>
|
||||
<TimeIcon boxSize={3} />
|
||||
<Clock size={12} />
|
||||
<Text>涨停: {formatStockTime(stock)}</Text>
|
||||
</HStack>
|
||||
{stock.first_time && (
|
||||
|
||||
@@ -18,10 +18,7 @@ import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
RepeatIcon,
|
||||
ChevronUpIcon,
|
||||
} from '@chakra-ui/icons';
|
||||
import { RefreshCw, ChevronUp } from 'lucide-react';
|
||||
|
||||
// 导入拆分的组件
|
||||
// 注意:在实际使用中,这些组件应该被拆分到独立的文件中
|
||||
@@ -414,7 +411,7 @@ export default function LimitAnalyse() {
|
||||
<VStack spacing={3}>
|
||||
<Tooltip label="刷新数据" placement="left">
|
||||
<IconButton
|
||||
icon={<RepeatIcon />}
|
||||
icon={<RefreshCw size={20} />}
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
borderRadius="full"
|
||||
@@ -425,7 +422,7 @@ export default function LimitAnalyse() {
|
||||
</Tooltip>
|
||||
<Tooltip label="回到顶部" placement="left">
|
||||
<IconButton
|
||||
icon={<ChevronUpIcon />}
|
||||
icon={<ChevronUp size={20} />}
|
||||
colorScheme="gray"
|
||||
size="lg"
|
||||
borderRadius="full"
|
||||
|
||||
@@ -41,13 +41,12 @@ import TransactionRow from 'components/Tables/TransactionRow';
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
FaPaypal,
|
||||
FaPencilAlt,
|
||||
FaRegCalendarAlt,
|
||||
FaWallet,
|
||||
FaGem,
|
||||
} from 'react-icons/fa';
|
||||
import { RiMastercardFill } from 'react-icons/ri';
|
||||
Wallet,
|
||||
Edit2,
|
||||
Calendar,
|
||||
Gem,
|
||||
CreditCard,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
billingData,
|
||||
invoicesData,
|
||||
@@ -101,7 +100,7 @@ function Billing() {
|
||||
Argon x Chakra
|
||||
</Text>
|
||||
<Icon
|
||||
as={RiMastercardFill}
|
||||
as={CreditCard}
|
||||
w='48px'
|
||||
h='auto'
|
||||
color='gray.400'
|
||||
@@ -134,7 +133,7 @@ function Billing() {
|
||||
<Card p='16px' display='flex' align='center' justify='center'>
|
||||
<Flex direction='column' align='center' w='100%' py='14px'>
|
||||
<IconBox h={'60px'} w={'60px'} bg={iconBlue}>
|
||||
<Icon h={'24px'} w={'24px'} color='white' as={FaWallet} />
|
||||
<Icon h={'24px'} w={'24px'} color='white' as={Wallet} />
|
||||
</IconBox>
|
||||
<Flex
|
||||
direction='column'
|
||||
@@ -171,7 +170,7 @@ function Billing() {
|
||||
py='14px'
|
||||
>
|
||||
<IconBox h={'60px'} w={'60px'} bg='purple.500'>
|
||||
<Icon h={'24px'} w={'24px'} color='white' as={FaGem} />
|
||||
<Icon h={'24px'} w={'24px'} color='white' as={Gem} />
|
||||
</IconBox>
|
||||
<Flex
|
||||
direction='column'
|
||||
@@ -248,7 +247,7 @@ function Billing() {
|
||||
<Spacer />
|
||||
<Button p='0px' w='16px' h='16px' variant='no-effects'>
|
||||
<Icon
|
||||
as={FaPencilAlt}
|
||||
as={Edit2}
|
||||
color={colorMode === 'dark' && 'white'}
|
||||
/>
|
||||
</Button>
|
||||
@@ -277,7 +276,7 @@ function Billing() {
|
||||
variant='no-effects'
|
||||
>
|
||||
<Icon
|
||||
as={FaPencilAlt}
|
||||
as={Edit2}
|
||||
color={colorMode === 'dark' && 'white'}
|
||||
/>
|
||||
</Button>
|
||||
@@ -369,7 +368,7 @@ function Billing() {
|
||||
</Text>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={FaRegCalendarAlt}
|
||||
as={Calendar}
|
||||
color='gray.400'
|
||||
fontSize='md'
|
||||
me='6px'
|
||||
|
||||
@@ -56,14 +56,7 @@ import {
|
||||
} from 'components/Icons/Icons';
|
||||
import { HSeparator } from 'components/Separator/Separator';
|
||||
import React, { useState } from 'react';
|
||||
import { AiFillDelete } from 'react-icons/ai';
|
||||
import { BsArrowRight, BsCircleFill, BsToggleOn } from 'react-icons/bs';
|
||||
import { FaCube, FaUser } from 'react-icons/fa';
|
||||
import { GiSmartphone } from 'react-icons/gi';
|
||||
import { IoIosArrowUp, IoIosRocket, IoMdNotifications } from 'react-icons/io';
|
||||
import { IoDocumentText } from 'react-icons/io5';
|
||||
import { MdPowerSettingsNew } from 'react-icons/md';
|
||||
import { RiComputerLine } from 'react-icons/ri';
|
||||
import { Trash2, ArrowRight, Circle, ToggleLeft, Box as BoxIcon, User, Smartphone, ChevronUp, Rocket, Bell, FileText, Power, Monitor } from 'lucide-react';
|
||||
import { Element, Link } from 'react-scroll';
|
||||
|
||||
function Settings() {
|
||||
@@ -293,7 +286,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={IoIosRocket}
|
||||
as={Rocket}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -313,7 +306,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={IoDocumentText}
|
||||
as={FileText}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -333,7 +326,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={FaCube}
|
||||
as={Box}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -353,7 +346,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={BsToggleOn}
|
||||
as={ToggleLeft}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -373,7 +366,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={FaUser}
|
||||
as={User}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -393,7 +386,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={IoMdNotifications}
|
||||
as={Bell}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -413,7 +406,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={MdPowerSettingsNew}
|
||||
as={Power}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -433,7 +426,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center' justifySelf='flex-start' w='100%'>
|
||||
<Icon
|
||||
as={AiFillDelete}
|
||||
as={Trash2}
|
||||
me='12px'
|
||||
w='18px'
|
||||
h='18px'
|
||||
@@ -827,7 +820,8 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={BsCircleFill}
|
||||
as={Circle}
|
||||
fill='gray.500'
|
||||
w='6px'
|
||||
h='6px'
|
||||
color='gray.500'
|
||||
@@ -839,7 +833,8 @@ function Settings() {
|
||||
</Flex>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={BsCircleFill}
|
||||
as={Circle}
|
||||
fill='gray.500'
|
||||
w='6px'
|
||||
h='6px'
|
||||
color='gray.500'
|
||||
@@ -851,7 +846,8 @@ function Settings() {
|
||||
</Flex>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={BsCircleFill}
|
||||
as={Circle}
|
||||
fill='gray.500'
|
||||
w='6px'
|
||||
h='6px'
|
||||
color='gray.500'
|
||||
@@ -863,7 +859,8 @@ function Settings() {
|
||||
</Flex>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={BsCircleFill}
|
||||
as={Circle}
|
||||
fill='gray.500'
|
||||
w='6px'
|
||||
h='6px'
|
||||
color='gray.500'
|
||||
@@ -1059,7 +1056,7 @@ function Settings() {
|
||||
>
|
||||
Show Less
|
||||
</Text>
|
||||
<Icon as={IoIosArrowUp} color='gray.400' />
|
||||
<Icon as={ChevronUp} color='gray.400' />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
@@ -1460,7 +1457,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={RiComputerLine}
|
||||
as={Monitor}
|
||||
me='30px'
|
||||
w='28px'
|
||||
h='28px'
|
||||
@@ -1509,7 +1506,7 @@ function Settings() {
|
||||
See more
|
||||
</Text>
|
||||
<Icon
|
||||
as={BsArrowRight}
|
||||
as={ArrowRight}
|
||||
w='20px'
|
||||
h='20px'
|
||||
transition='all .3s ease'
|
||||
@@ -1527,7 +1524,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={RiComputerLine}
|
||||
as={Monitor}
|
||||
me='30px'
|
||||
w='28px'
|
||||
h='28px'
|
||||
@@ -1565,7 +1562,7 @@ function Settings() {
|
||||
See more
|
||||
</Text>
|
||||
<Icon
|
||||
as={BsArrowRight}
|
||||
as={ArrowRight}
|
||||
w='20px'
|
||||
h='20px'
|
||||
transition='all .3s ease'
|
||||
@@ -1583,7 +1580,7 @@ function Settings() {
|
||||
>
|
||||
<Flex align='center'>
|
||||
<Icon
|
||||
as={GiSmartphone}
|
||||
as={Smartphone}
|
||||
me='30px'
|
||||
w='28px'
|
||||
h='28px'
|
||||
@@ -1622,7 +1619,7 @@ function Settings() {
|
||||
See more
|
||||
</Text>
|
||||
<Icon
|
||||
as={BsArrowRight}
|
||||
as={ArrowRight}
|
||||
w='20px'
|
||||
h='20px'
|
||||
transition='all .3s ease'
|
||||
|
||||
@@ -43,7 +43,7 @@ import microsoftLogo from "assets/svg/microsoft-logo.svg";
|
||||
import msnLogo from "assets/svg/msn-logo.svg";
|
||||
import zohoLogo from "assets/svg/zoho-logo.svg";
|
||||
import Card from "components/Card/Card";
|
||||
import { FaCheckCircle, FaTimesCircle } from "react-icons/fa";
|
||||
import { CheckCircle, XCircle } from "lucide-react";
|
||||
|
||||
function Pricing() {
|
||||
const [activeButton, setActiveButton] = useState({
|
||||
@@ -155,7 +155,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -167,7 +167,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -179,7 +179,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaTimesCircle}
|
||||
as={XCircle}
|
||||
mr="8px"
|
||||
color={bgTimesIcon}
|
||||
/>
|
||||
@@ -191,7 +191,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaTimesCircle}
|
||||
as={XCircle}
|
||||
mr="8px"
|
||||
color={bgTimesIcon}
|
||||
/>
|
||||
@@ -203,7 +203,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaTimesCircle}
|
||||
as={XCircle}
|
||||
mr="8px"
|
||||
color={bgTimesIcon}
|
||||
/>
|
||||
@@ -215,7 +215,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaTimesCircle}
|
||||
as={XCircle}
|
||||
mr="8px"
|
||||
color={bgTimesIcon}
|
||||
/>
|
||||
@@ -244,7 +244,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -256,7 +256,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -268,7 +268,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -280,7 +280,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -292,7 +292,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaTimesCircle}
|
||||
as={XCircle}
|
||||
mr="8px"
|
||||
color={bgTimesIcon}
|
||||
/>
|
||||
@@ -304,7 +304,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaTimesCircle}
|
||||
as={XCircle}
|
||||
mr="8px"
|
||||
color={bgTimesIcon}
|
||||
/>
|
||||
@@ -333,7 +333,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -345,7 +345,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -357,7 +357,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -369,7 +369,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -381,7 +381,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
@@ -393,7 +393,7 @@ function Pricing() {
|
||||
<Icon
|
||||
w="20px"
|
||||
h="20px"
|
||||
as={FaCheckCircle}
|
||||
as={CheckCircle}
|
||||
mr="8px"
|
||||
color="blue.500"
|
||||
/>
|
||||
|
||||
@@ -42,14 +42,14 @@ import ImageArchitect1 from "assets/img/ImageArchitect1.png";
|
||||
import ImageArchitect2 from "assets/img/ImageArchitect2.png";
|
||||
import ImageArchitect3 from "assets/img/ImageArchitect3.png";
|
||||
import {
|
||||
FaCube,
|
||||
FaFacebook,
|
||||
FaInstagram,
|
||||
FaPenFancy,
|
||||
FaPlus,
|
||||
FaTwitter,
|
||||
} from "react-icons/fa";
|
||||
import { IoDocumentsSharp } from "react-icons/io5";
|
||||
Box,
|
||||
Facebook,
|
||||
Instagram,
|
||||
PenTool,
|
||||
Plus,
|
||||
Twitter,
|
||||
Files,
|
||||
} from "lucide-react";
|
||||
// Custom components
|
||||
import Card from "components/Card/Card";
|
||||
import CardBody from "components/Card/CardBody";
|
||||
@@ -170,7 +170,7 @@ function Overview() {
|
||||
dispatch({ type: "SWITCH_ACTIVE", payload: "overview" })
|
||||
}
|
||||
>
|
||||
<Icon color={textColor} as={FaCube} me="6px" />
|
||||
<Icon color={textColor} as={Box} me="6px" />
|
||||
<Text fontSize="xs" color={textColor} fontWeight="bold">
|
||||
OVERVIEW
|
||||
</Text>
|
||||
@@ -200,7 +200,7 @@ function Overview() {
|
||||
dispatch({ type: "SWITCH_ACTIVE", payload: "teams" })
|
||||
}
|
||||
>
|
||||
<Icon color={textColor} as={IoDocumentsSharp} me="6px" />
|
||||
<Icon color={textColor} as={Files} me="6px" />
|
||||
<Text fontSize="xs" color={textColor} fontWeight="bold">
|
||||
TEAMS
|
||||
</Text>
|
||||
@@ -229,7 +229,7 @@ function Overview() {
|
||||
dispatch({ type: "SWITCH_ACTIVE", payload: "projects" })
|
||||
}
|
||||
>
|
||||
<Icon color={textColor} as={FaPenFancy} me="6px" />
|
||||
<Icon color={textColor} as={PenTool} me="6px" />
|
||||
<Text fontSize="xs" color={textColor} fontWeight="bold">
|
||||
PROJECTS
|
||||
</Text>
|
||||
@@ -411,7 +411,7 @@ function Overview() {
|
||||
me="10px"
|
||||
_hover={{ color: "blue.500" }}
|
||||
>
|
||||
<Icon as={FaFacebook} />
|
||||
<Icon as={Facebook} />
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
@@ -420,7 +420,7 @@ function Overview() {
|
||||
me="10px"
|
||||
_hover={{ color: "blue.500" }}
|
||||
>
|
||||
<Icon as={FaInstagram} />
|
||||
<Icon as={Instagram} />
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
@@ -429,7 +429,7 @@ function Overview() {
|
||||
me="10px"
|
||||
_hover={{ color: "blue.500" }}
|
||||
>
|
||||
<Icon as={FaTwitter} />
|
||||
<Icon as={Twitter} />
|
||||
</Link>
|
||||
</Flex>
|
||||
</Flex>
|
||||
@@ -741,7 +741,7 @@ function Overview() {
|
||||
minHeight={{ sm: "200px", md: "100%" }}
|
||||
>
|
||||
<Flex direction="column" justifyContent="center" align="center">
|
||||
<Icon as={FaPlus} color={textColor} fontSize="lg" mb="12px" />
|
||||
<Icon as={Plus} color={textColor} fontSize="lg" mb="12px" />
|
||||
<Text fontSize="lg" color={textColor} fontWeight="bold">
|
||||
Create a New Project
|
||||
</Text>
|
||||
|
||||
@@ -53,9 +53,7 @@ import {
|
||||
} from "components/Icons/Icons";
|
||||
import { HSeparator } from "components/Separator/Separator";
|
||||
import React, { useReducer } from "react";
|
||||
import { BsPlus } from "react-icons/bs";
|
||||
import { FaCube, FaPenFancy } from "react-icons/fa";
|
||||
import { IoDocumentsSharp, IoEllipsisVerticalSharp } from "react-icons/io5";
|
||||
import { Plus, Box, PenTool, Files, MoreVertical } from "lucide-react";
|
||||
|
||||
const reducer = (state, action) => {
|
||||
if (action.type === "SWITCH_ACTIVE") {
|
||||
@@ -205,7 +203,7 @@ function Projects() {
|
||||
dispatch({ type: "SWITCH_ACTIVE", payload: "overview" })
|
||||
}
|
||||
>
|
||||
<Icon color={textColor} as={FaCube} me="6px" />
|
||||
<Icon color={textColor} as={Box} me="6px" />
|
||||
<Text fontSize="xs" color={textColor} fontWeight="bold">
|
||||
OVERVIEW
|
||||
</Text>
|
||||
@@ -235,7 +233,7 @@ function Projects() {
|
||||
dispatch({ type: "SWITCH_ACTIVE", payload: "teams" })
|
||||
}
|
||||
>
|
||||
<Icon color={textColor} as={IoDocumentsSharp} me="6px" />
|
||||
<Icon color={textColor} as={Files} me="6px" />
|
||||
<Text fontSize="xs" color={textColor} fontWeight="bold">
|
||||
TEAMS
|
||||
</Text>
|
||||
@@ -264,7 +262,7 @@ function Projects() {
|
||||
dispatch({ type: "SWITCH_ACTIVE", payload: "projects" })
|
||||
}
|
||||
>
|
||||
<Icon color={textColor} as={FaPenFancy} me="6px" />
|
||||
<Icon color={textColor} as={PenTool} me="6px" />
|
||||
<Text fontSize="xs" color={textColor} fontWeight="bold">
|
||||
PROJECTS
|
||||
</Text>
|
||||
@@ -324,7 +322,7 @@ function Projects() {
|
||||
<Menu isOpen={isOpen1} onClose={onClose1}>
|
||||
<MenuButton onClick={onOpen1} alignSelf="flex-start">
|
||||
<Icon
|
||||
as={IoEllipsisVerticalSharp}
|
||||
as={MoreVertical}
|
||||
color="gray.400"
|
||||
w="20px"
|
||||
h="20px"
|
||||
@@ -408,7 +406,7 @@ function Projects() {
|
||||
<Menu isOpen={isOpen2} onClose={onClose2}>
|
||||
<MenuButton onClick={onOpen2} alignSelf="flex-start">
|
||||
<Icon
|
||||
as={IoEllipsisVerticalSharp}
|
||||
as={MoreVertical}
|
||||
color="gray.400"
|
||||
w="20px"
|
||||
h="20px"
|
||||
@@ -494,7 +492,7 @@ function Projects() {
|
||||
<Menu isOpen={isOpen3} onClose={onClose3}>
|
||||
<MenuButton onClick={onOpen3} alignSelf="flex-start">
|
||||
<Icon
|
||||
as={IoEllipsisVerticalSharp}
|
||||
as={MoreVertical}
|
||||
color="gray.400"
|
||||
w="20px"
|
||||
h="20px"
|
||||
@@ -576,7 +574,7 @@ function Projects() {
|
||||
<Menu isOpen={isOpen4} onClose={onClose4}>
|
||||
<MenuButton onClick={onOpen4} alignSelf="flex-start">
|
||||
<Icon
|
||||
as={IoEllipsisVerticalSharp}
|
||||
as={MoreVertical}
|
||||
color="gray.400"
|
||||
w="20px"
|
||||
h="20px"
|
||||
@@ -659,7 +657,7 @@ function Projects() {
|
||||
<Menu isOpen={isOpen5} onClose={onClose5}>
|
||||
<MenuButton onClick={onOpen5} alignSelf="flex-start">
|
||||
<Icon
|
||||
as={IoEllipsisVerticalSharp}
|
||||
as={MoreVertical}
|
||||
color="gray.400"
|
||||
w="20px"
|
||||
h="20px"
|
||||
@@ -722,7 +720,7 @@ function Projects() {
|
||||
color={secondaryColor}
|
||||
>
|
||||
<Icon
|
||||
as={BsPlus}
|
||||
as={Plus}
|
||||
w="30px"
|
||||
h="30px"
|
||||
mb="12px"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user