232 lines
6.8 KiB
JavaScript
232 lines
6.8 KiB
JavaScript
// src/views/Company/components/DeepAnalysis/index.js
|
||
// 深度分析 - 独立一级 Tab 组件(懒加载版本)
|
||
|
||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||
import { logger } from "@utils/logger";
|
||
import { getApiBase } from "@utils/apiConfig";
|
||
|
||
// 复用原有的展示组件
|
||
import DeepAnalysisTab from "../CompanyOverview/DeepAnalysisTab";
|
||
|
||
const API_BASE_URL = getApiBase();
|
||
|
||
/**
|
||
* Tab 与 API 接口映射
|
||
* - strategy 和 business 共用 comprehensive 接口
|
||
*/
|
||
const TAB_API_MAP = {
|
||
strategy: "comprehensive",
|
||
business: "comprehensive",
|
||
valueChain: "valueChain",
|
||
development: "keyFactors",
|
||
};
|
||
|
||
/**
|
||
* 深度分析组件
|
||
*
|
||
* 功能:
|
||
* - 按 Tab 懒加载数据(默认只加载战略分析)
|
||
* - 已加载的数据缓存,切换 Tab 不重复请求
|
||
* - 管理展开状态
|
||
*
|
||
* @param {Object} props
|
||
* @param {string} props.stockCode - 股票代码
|
||
*/
|
||
const DeepAnalysis = ({ stockCode }) => {
|
||
// 当前 Tab
|
||
const [activeTab, setActiveTab] = useState("strategy");
|
||
|
||
// 数据状态
|
||
const [comprehensiveData, setComprehensiveData] = useState(null);
|
||
const [valueChainData, setValueChainData] = useState(null);
|
||
const [keyFactorsData, setKeyFactorsData] = useState(null);
|
||
const [industryRankData, setIndustryRankData] = useState(null);
|
||
|
||
// 各接口独立的 loading 状态
|
||
const [comprehensiveLoading, setComprehensiveLoading] = useState(false);
|
||
const [valueChainLoading, setValueChainLoading] = useState(false);
|
||
const [keyFactorsLoading, setKeyFactorsLoading] = useState(false);
|
||
const [industryRankLoading, setIndustryRankLoading] = useState(false);
|
||
|
||
// 已加载的接口记录(用于缓存判断)
|
||
const loadedApisRef = useRef({
|
||
comprehensive: false,
|
||
valueChain: false,
|
||
keyFactors: false,
|
||
industryRank: false,
|
||
});
|
||
|
||
// 业务板块展开状态
|
||
const [expandedSegments, setExpandedSegments] = useState({});
|
||
|
||
// 用于追踪当前 stockCode,避免竞态条件
|
||
const currentStockCodeRef = useRef(stockCode);
|
||
|
||
// 切换业务板块展开状态
|
||
const toggleSegmentExpansion = (segmentIndex) => {
|
||
setExpandedSegments((prev) => ({
|
||
...prev,
|
||
[segmentIndex]: !prev[segmentIndex],
|
||
}));
|
||
};
|
||
|
||
/**
|
||
* 加载指定接口的数据
|
||
*/
|
||
const loadApiData = useCallback(
|
||
async (apiKey) => {
|
||
if (!stockCode) return;
|
||
|
||
// 已加载则跳过
|
||
if (loadedApisRef.current[apiKey]) return;
|
||
|
||
try {
|
||
switch (apiKey) {
|
||
case "comprehensive":
|
||
setComprehensiveLoading(true);
|
||
const comprehensiveRes = await fetch(
|
||
`${API_BASE_URL}/api/company/comprehensive-analysis/${stockCode}`
|
||
).then((r) => r.json());
|
||
// 检查 stockCode 是否已变更(防止竞态)
|
||
if (currentStockCodeRef.current === stockCode) {
|
||
if (comprehensiveRes.success)
|
||
setComprehensiveData(comprehensiveRes.data);
|
||
loadedApisRef.current.comprehensive = true;
|
||
}
|
||
break;
|
||
|
||
case "valueChain":
|
||
setValueChainLoading(true);
|
||
const valueChainRes = await fetch(
|
||
`${API_BASE_URL}/api/company/value-chain-analysis/${stockCode}`
|
||
).then((r) => r.json());
|
||
if (currentStockCodeRef.current === stockCode) {
|
||
if (valueChainRes.success) setValueChainData(valueChainRes.data);
|
||
loadedApisRef.current.valueChain = true;
|
||
}
|
||
break;
|
||
|
||
case "keyFactors":
|
||
setKeyFactorsLoading(true);
|
||
const keyFactorsRes = await fetch(
|
||
`${API_BASE_URL}/api/company/key-factors-timeline/${stockCode}`
|
||
).then((r) => r.json());
|
||
if (currentStockCodeRef.current === stockCode) {
|
||
if (keyFactorsRes.success) setKeyFactorsData(keyFactorsRes.data);
|
||
loadedApisRef.current.keyFactors = true;
|
||
}
|
||
break;
|
||
|
||
case "industryRank":
|
||
setIndustryRankLoading(true);
|
||
const industryRankRes = await fetch(
|
||
`${API_BASE_URL}/api/financial/industry-rank/${stockCode}`
|
||
).then((r) => r.json());
|
||
if (currentStockCodeRef.current === stockCode) {
|
||
if (industryRankRes.success) setIndustryRankData(industryRankRes.data);
|
||
loadedApisRef.current.industryRank = true;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
} catch (err) {
|
||
logger.error("DeepAnalysis", `loadApiData:${apiKey}`, err, {
|
||
stockCode,
|
||
});
|
||
} finally {
|
||
// 清除 loading 状态
|
||
if (apiKey === "comprehensive") setComprehensiveLoading(false);
|
||
if (apiKey === "valueChain") setValueChainLoading(false);
|
||
if (apiKey === "keyFactors") setKeyFactorsLoading(false);
|
||
if (apiKey === "industryRank") setIndustryRankLoading(false);
|
||
}
|
||
},
|
||
[stockCode]
|
||
);
|
||
|
||
/**
|
||
* 根据 Tab 加载对应的数据
|
||
*/
|
||
const loadTabData = useCallback(
|
||
(tabKey) => {
|
||
const apiKey = TAB_API_MAP[tabKey];
|
||
if (apiKey) {
|
||
loadApiData(apiKey);
|
||
}
|
||
},
|
||
[loadApiData]
|
||
);
|
||
|
||
/**
|
||
* Tab 切换回调
|
||
*/
|
||
const handleTabChange = useCallback(
|
||
(index, tabKey) => {
|
||
setActiveTab(tabKey);
|
||
loadTabData(tabKey);
|
||
},
|
||
[loadTabData]
|
||
);
|
||
|
||
// stockCode 变更时重置并加载默认 Tab 数据
|
||
useEffect(() => {
|
||
if (stockCode) {
|
||
// 更新 ref
|
||
currentStockCodeRef.current = stockCode;
|
||
|
||
// 重置所有数据和状态
|
||
setComprehensiveData(null);
|
||
setValueChainData(null);
|
||
setKeyFactorsData(null);
|
||
setIndustryRankData(null);
|
||
setExpandedSegments({});
|
||
loadedApisRef.current = {
|
||
comprehensive: false,
|
||
valueChain: false,
|
||
keyFactors: false,
|
||
industryRank: false,
|
||
};
|
||
|
||
// 重置为默认 Tab 并加载数据
|
||
setActiveTab("strategy");
|
||
// 加载默认 Tab 的数据(战略分析需要 comprehensive 和 industryRank)
|
||
loadApiData("comprehensive");
|
||
loadApiData("industryRank");
|
||
}
|
||
}, [stockCode, loadApiData]);
|
||
|
||
// 计算当前 Tab 的 loading 状态
|
||
const getCurrentLoading = () => {
|
||
const apiKey = TAB_API_MAP[activeTab];
|
||
switch (apiKey) {
|
||
case "comprehensive":
|
||
return comprehensiveLoading;
|
||
case "valueChain":
|
||
return valueChainLoading;
|
||
case "keyFactors":
|
||
return keyFactorsLoading;
|
||
default:
|
||
return false;
|
||
}
|
||
};
|
||
|
||
return (
|
||
<DeepAnalysisTab
|
||
comprehensiveData={comprehensiveData}
|
||
valueChainData={valueChainData}
|
||
keyFactorsData={keyFactorsData}
|
||
industryRankData={industryRankData}
|
||
loading={getCurrentLoading()}
|
||
cardBg="white"
|
||
expandedSegments={expandedSegments}
|
||
onToggleSegment={toggleSegmentExpansion}
|
||
activeTab={activeTab}
|
||
onTabChange={handleTabChange}
|
||
/>
|
||
);
|
||
};
|
||
|
||
export default DeepAnalysis;
|