feat(DeepAnalysis): 竞争地位分析增加行业排名弹窗
- CompetitiveAnalysisCard 新增 Modal 弹窗展示行业排名详情 - 点击 Badge 或查看详情按钮可打开弹窗 - 弹窗采用黑金主题样式 - StrategyTab 移除独立的 IndustryRankingView 展示
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
* 竞争地位分析卡片
|
* 竞争地位分析卡片
|
||||||
*
|
*
|
||||||
* 显示竞争力评分、雷达图和竞争分析
|
* 显示竞争力评分、雷达图和竞争分析
|
||||||
|
* 包含行业排名弹窗功能
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { memo, useMemo } from 'react';
|
import React, { memo, useMemo } from 'react';
|
||||||
@@ -22,6 +23,14 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
Divider,
|
Divider,
|
||||||
SimpleGrid,
|
SimpleGrid,
|
||||||
|
Button,
|
||||||
|
Modal,
|
||||||
|
ModalOverlay,
|
||||||
|
ModalContent,
|
||||||
|
ModalHeader,
|
||||||
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
useDisclosure,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import {
|
import {
|
||||||
FaTrophy,
|
FaTrophy,
|
||||||
@@ -33,11 +42,32 @@ import {
|
|||||||
FaShieldAlt,
|
FaShieldAlt,
|
||||||
FaRocket,
|
FaRocket,
|
||||||
FaUsers,
|
FaUsers,
|
||||||
|
FaExternalLinkAlt,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
import { ScoreBar } from '../atoms';
|
import { ScoreBar } from '../atoms';
|
||||||
import { getRadarChartOption } from '../utils/chartOptions';
|
import { getRadarChartOption } from '../utils/chartOptions';
|
||||||
import type { ComprehensiveData, CompetitivePosition } from '../types';
|
import { IndustryRankingView } from '../../../FinancialPanorama/components';
|
||||||
|
import type { ComprehensiveData, CompetitivePosition, IndustryRankData } from '../types';
|
||||||
|
|
||||||
|
// 黑金主题弹窗样式
|
||||||
|
const MODAL_STYLES = {
|
||||||
|
content: {
|
||||||
|
bg: 'gray.900',
|
||||||
|
borderColor: 'rgba(212, 175, 55, 0.3)',
|
||||||
|
borderWidth: '1px',
|
||||||
|
maxW: '900px',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
color: 'yellow.500',
|
||||||
|
borderBottomColor: 'rgba(212, 175, 55, 0.2)',
|
||||||
|
borderBottomWidth: '1px',
|
||||||
|
},
|
||||||
|
closeButton: {
|
||||||
|
color: 'yellow.500',
|
||||||
|
_hover: { bg: 'rgba(212, 175, 55, 0.1)' },
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
// 样式常量 - 避免每次渲染创建新对象
|
// 样式常量 - 避免每次渲染创建新对象
|
||||||
const CARD_STYLES = {
|
const CARD_STYLES = {
|
||||||
@@ -57,6 +87,7 @@ const CHART_STYLE = { height: '320px' } as const;
|
|||||||
|
|
||||||
interface CompetitiveAnalysisCardProps {
|
interface CompetitiveAnalysisCardProps {
|
||||||
comprehensiveData: ComprehensiveData;
|
comprehensiveData: ComprehensiveData;
|
||||||
|
industryRankData?: IndustryRankData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 竞争对手标签组件
|
// 竞争对手标签组件
|
||||||
@@ -141,8 +172,10 @@ const AdvantagesSection = memo<AdvantagesSectionProps>(
|
|||||||
AdvantagesSection.displayName = 'AdvantagesSection';
|
AdvantagesSection.displayName = 'AdvantagesSection';
|
||||||
|
|
||||||
const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = memo(
|
const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = memo(
|
||||||
({ comprehensiveData }) => {
|
({ comprehensiveData, industryRankData }) => {
|
||||||
const competitivePosition = comprehensiveData.competitive_position;
|
const competitivePosition = comprehensiveData.competitive_position;
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
if (!competitivePosition) return null;
|
if (!competitivePosition) return null;
|
||||||
|
|
||||||
// 缓存雷达图配置
|
// 缓存雷达图配置
|
||||||
@@ -160,56 +193,99 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = memo(
|
|||||||
[competitivePosition.analysis?.main_competitors]
|
[competitivePosition.analysis?.main_competitors]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 判断是否有行业排名数据可展示
|
||||||
|
const hasIndustryRankData = industryRankData && industryRankData.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card {...CARD_STYLES}>
|
<>
|
||||||
<CardHeader>
|
<Card {...CARD_STYLES}>
|
||||||
<HStack>
|
<CardHeader>
|
||||||
<Icon as={FaTrophy} color="yellow.500" />
|
<HStack>
|
||||||
<Heading size="sm" color="yellow.500">竞争地位分析</Heading>
|
<Icon as={FaTrophy} color="yellow.500" />
|
||||||
{competitivePosition.ranking && (
|
<Heading size="sm" color="yellow.500">竞争地位分析</Heading>
|
||||||
<Badge
|
{competitivePosition.ranking && (
|
||||||
ml={2}
|
<Badge
|
||||||
bg="transparent"
|
ml={2}
|
||||||
border="1px solid"
|
bg="transparent"
|
||||||
borderColor="yellow.600"
|
border="1px solid"
|
||||||
color="yellow.500"
|
borderColor="yellow.600"
|
||||||
>
|
color="yellow.500"
|
||||||
行业排名 {competitivePosition.ranking.industry_rank}/
|
cursor={hasIndustryRankData ? 'pointer' : 'default'}
|
||||||
{competitivePosition.ranking.total_companies}
|
onClick={hasIndustryRankData ? onOpen : undefined}
|
||||||
</Badge>
|
_hover={hasIndustryRankData ? { bg: 'rgba(212, 175, 55, 0.1)' } : undefined}
|
||||||
)}
|
>
|
||||||
</HStack>
|
行业排名 {competitivePosition.ranking.industry_rank}/
|
||||||
</CardHeader>
|
{competitivePosition.ranking.total_companies}
|
||||||
<CardBody>
|
</Badge>
|
||||||
{/* 主要竞争对手 */}
|
)}
|
||||||
{/* {competitors.length > 0 && <CompetitorTags competitors={competitors} />} */}
|
{hasIndustryRankData && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="ghost"
|
||||||
|
color="yellow.500"
|
||||||
|
rightIcon={<Icon as={FaExternalLinkAlt} boxSize={3} />}
|
||||||
|
onClick={onOpen}
|
||||||
|
_hover={{ bg: 'rgba(212, 175, 55, 0.1)' }}
|
||||||
|
>
|
||||||
|
查看详情
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</HStack>
|
||||||
|
</CardHeader>
|
||||||
|
<CardBody>
|
||||||
|
{/* 主要竞争对手 */}
|
||||||
|
{/* {competitors.length > 0 && <CompetitorTags competitors={competitors} />} */}
|
||||||
|
|
||||||
{/* 评分和雷达图 */}
|
{/* 评分和雷达图 */}
|
||||||
{/* <Grid templateColumns="repeat(2, 1fr)" gap={6}>
|
{/* <Grid templateColumns="repeat(2, 1fr)" gap={6}>
|
||||||
<GridItem colSpan={GRID_COLSPAN}>
|
<GridItem colSpan={GRID_COLSPAN}>
|
||||||
<ScoreSection scores={competitivePosition.scores} />
|
<ScoreSection scores={competitivePosition.scores} />
|
||||||
</GridItem>
|
</GridItem>
|
||||||
|
|
||||||
<GridItem colSpan={GRID_COLSPAN}>
|
<GridItem colSpan={GRID_COLSPAN}>
|
||||||
{radarOption && (
|
{radarOption && (
|
||||||
<ReactECharts
|
<ReactECharts
|
||||||
option={radarOption}
|
option={radarOption}
|
||||||
style={CHART_STYLE}
|
style={CHART_STYLE}
|
||||||
theme="dark"
|
theme="dark"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</GridItem>
|
||||||
|
</Grid> */}
|
||||||
|
|
||||||
|
{/* <Divider my={4} borderColor="yellow.600" /> */}
|
||||||
|
|
||||||
|
{/* 竞争优势和劣势 */}
|
||||||
|
<AdvantagesSection
|
||||||
|
advantages={competitivePosition.analysis?.competitive_advantages}
|
||||||
|
disadvantages={competitivePosition.analysis?.competitive_disadvantages}
|
||||||
|
/>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* 行业排名弹窗 - 黑金主题 */}
|
||||||
|
<Modal isOpen={isOpen} onClose={onClose} size="4xl" scrollBehavior="inside">
|
||||||
|
<ModalOverlay bg="blackAlpha.700" />
|
||||||
|
<ModalContent {...MODAL_STYLES.content}>
|
||||||
|
<ModalHeader {...MODAL_STYLES.header}>
|
||||||
|
<HStack>
|
||||||
|
<Icon as={FaTrophy} color="yellow.500" />
|
||||||
|
<Text>行业排名详情</Text>
|
||||||
|
</HStack>
|
||||||
|
</ModalHeader>
|
||||||
|
<ModalCloseButton {...MODAL_STYLES.closeButton} />
|
||||||
|
<ModalBody py={4}>
|
||||||
|
{hasIndustryRankData && (
|
||||||
|
<IndustryRankingView
|
||||||
|
industryRank={industryRankData}
|
||||||
|
bgColor="gray.800"
|
||||||
|
borderColor="rgba(212, 175, 55, 0.3)"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</GridItem>
|
</ModalBody>
|
||||||
</Grid> */}
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
{/* <Divider my={4} borderColor="yellow.600" /> */}
|
</>
|
||||||
|
|
||||||
{/* 竞争优势和劣势 */}
|
|
||||||
<AdvantagesSection
|
|
||||||
advantages={competitivePosition.analysis?.competitive_advantages}
|
|
||||||
disadvantages={competitivePosition.analysis?.competitive_disadvantages}
|
|
||||||
/>
|
|
||||||
</CardBody>
|
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* 战略分析 Tab
|
* 战略分析 Tab
|
||||||
*
|
*
|
||||||
* 包含:核心定位 + 战略分析 + 竞争地位分析 + 行业排名
|
* 包含:核心定位 + 战略分析 + 竞争地位分析(含行业排名弹窗)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
StrategyAnalysisCard,
|
StrategyAnalysisCard,
|
||||||
CompetitiveAnalysisCard,
|
CompetitiveAnalysisCard,
|
||||||
} from '../components';
|
} from '../components';
|
||||||
import { IndustryRankingView } from '../../../FinancialPanorama/components';
|
|
||||||
import type { ComprehensiveData, IndustryRankData } from '../types';
|
import type { ComprehensiveData, IndustryRankData } from '../types';
|
||||||
|
|
||||||
export interface StrategyTabProps {
|
export interface StrategyTabProps {
|
||||||
@@ -43,17 +42,11 @@ const StrategyTab: React.FC<StrategyTabProps> = memo(({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 竞争地位分析 */}
|
{/* 竞争地位分析(包含行业排名弹窗) */}
|
||||||
{comprehensiveData?.competitive_position && (
|
{comprehensiveData?.competitive_position && (
|
||||||
<CompetitiveAnalysisCard comprehensiveData={comprehensiveData} />
|
<CompetitiveAnalysisCard
|
||||||
)}
|
comprehensiveData={comprehensiveData}
|
||||||
|
industryRankData={industryRankData}
|
||||||
{/* 行业排名 */}
|
|
||||||
{industryRankData && industryRankData.length > 0 && (
|
|
||||||
<IndustryRankingView
|
|
||||||
industryRank={industryRankData}
|
|
||||||
bgColor="white"
|
|
||||||
borderColor="gray.200"
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</TabPanelContainer>
|
</TabPanelContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user