feat:mock了一下后端数据 以及logs日志的接受传输格式,完善首页流量混淆和嵌套加密交互

This commit is contained in:
liyuanhu 2025-04-27 11:16:17 +08:00
parent 15bb6d8bc0
commit 5151bd35d0
3 changed files with 135 additions and 157 deletions

View File

@ -7,7 +7,6 @@ import worldGeoJson from "@/assets/echarts-map/json/world.json";
import { geoCoordMap, countryNameMap, countryCodeMap } from "@/data"; import { geoCoordMap, countryNameMap, countryCodeMap } from "@/data";
import { getUrl } from "@/lib/utils"; import { getUrl } from "@/lib/utils";
interface LinesItemType { interface LinesItemType {
name: string; name: string;
country_code: string; country_code: string;
@ -17,52 +16,51 @@ interface LinesItemType {
type LinesDataType = [LinesItemType, LinesItemType]; type LinesDataType = [LinesItemType, LinesItemType];
type LinesType = [string, LinesDataType[]]; type LinesType = [string, LinesDataType[]];
// 创建左侧自定义提示框组件 // 创建左侧自定义提示框组件
const CustomTooltipLeft = ({ const CustomTooltipLeft = ({
logs = [], logs = [],
onClose, onClose,
tooltipRef, tooltipRef,
title, title,
}: { }: {
logs?: string[], logs?: string[];
onClose: () => void, onClose: () => void;
tooltipRef: React.RefObject<HTMLDivElement>, tooltipRef: React.RefObject<HTMLDivElement>;
title: string, title: string;
}) => { }) => {
const [visibleLogs, setVisibleLogs] = useState<string[]>([]); const [visibleLogs, setVisibleLogs] = useState<string[]>([]);
const [isComplete, setIsComplete] = useState(false); const [isComplete, setIsComplete] = useState(false);
// 过滤掉空日志 // 过滤掉空日志
const filteredLogs = useMemo(() => { const filteredLogs = useMemo(() => {
return logs.filter(log => log && log.trim() !== ''); return logs.filter((log) => log && log.trim() !== "");
}, [logs]); }, [logs]);
// 使用useEffect实现逐条显示日志的效果 // 使用useEffect实现逐条显示日志的效果
useEffect(() => { useEffect(() => {
if (!filteredLogs || filteredLogs.length === 0) return; if (!filteredLogs || filteredLogs.length === 0) return;
// 重置状态 // 重置状态
setVisibleLogs([]); setVisibleLogs([]);
setIsComplete(false); setIsComplete(false);
// 先显示第一条日志 // 先显示第一条日志
setVisibleLogs([filteredLogs[0]]); setVisibleLogs([filteredLogs[0]]);
// 如果只有一条日志,直接设置完成 // 如果只有一条日志,直接设置完成
if (filteredLogs.length === 1) { if (filteredLogs.length === 1) {
setIsComplete(true); setIsComplete(true);
return; return;
} }
// 从第二条日志开始每500毫秒显示一条 // 从第二条日志开始每500毫秒显示一条
let currentIndex = 1; let currentIndex = 1;
const timer = setInterval(() => { const timer = setInterval(() => {
if (currentIndex < filteredLogs.length) { if (currentIndex < filteredLogs.length) {
setVisibleLogs(prev => [...prev, filteredLogs[currentIndex]]); setVisibleLogs((prev) => [...prev, filteredLogs[currentIndex]]);
currentIndex++; currentIndex++;
// 如果已经是最后一条,设置完成状态 // 如果已经是最后一条,设置完成状态
if (currentIndex >= filteredLogs.length) { if (currentIndex >= filteredLogs.length) {
clearInterval(timer); clearInterval(timer);
@ -73,73 +71,79 @@ const CustomTooltipLeft = ({
setIsComplete(true); setIsComplete(true);
} }
}, 500); }, 500);
// 清理函数 // 清理函数
return () => { return () => {
clearInterval(timer); clearInterval(timer);
}; };
}, [filteredLogs]); // 当过滤后的日志变化时重新开始动画 }, [filteredLogs]); // 当过滤后的日志变化时重新开始动画
// 自动滚动到最新的日志 // 自动滚动到最新的日志
const logsContainerRef = useRef<HTMLDivElement>(null); const logsContainerRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
if (logsContainerRef.current && visibleLogs.length > 0) { if (logsContainerRef.current && visibleLogs.length > 0) {
logsContainerRef.current.scrollTop = logsContainerRef.current.scrollHeight; logsContainerRef.current.scrollTop =
logsContainerRef.current.scrollHeight;
} }
}, [visibleLogs]); }, [visibleLogs]);
return ( return (
<div <div
id="custom-fixed-tooltip2" id="custom-fixed-tooltip2"
ref={tooltipRef} ref={tooltipRef}
style={{ style={{
position: "fixed", position: "fixed",
zIndex: 1000, zIndex: 1000,
pointerEvents: "auto", pointerEvents: "auto",
backgroundColor: "transparent" backgroundColor: "transparent",
}} }}
> >
<div className="tooltip-content"> <div className="tooltip-content">
<div className="fill-left"></div> <div className="fill-left"></div>
<div className="tip-box-left"> <div className="tip-box-left">
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<div className="label" style={{ color: "white", fontWeight: "bold" }}> <div
className="label"
style={{ color: "white", fontWeight: "bold" }}
>
{title} {title}
</div> </div>
<img <img
className="close-icon" className="close-icon"
src={getUrl("svg/Xwhite.svg")} src={getUrl("svg/Xwhite.svg")}
alt="" alt=""
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
onClick={onClose} onClick={onClose}
/> />
</div> </div>
{filteredLogs.length > 0 && ( {filteredLogs.length > 0 && (
<div <div
ref={logsContainerRef} ref={logsContainerRef}
className="logs-container mt-3 max-h-[450px] overflow-y-auto" className="logs-container mt-3 max-h-[450px] overflow-y-auto"
> >
{visibleLogs.length > 0 ? ( {visibleLogs.length > 0 ? (
<ul className="logs-list space-y-1.5"> <ul className="logs-list space-y-1.5">
{visibleLogs.map((log, index) => ( {visibleLogs.map(
log && log.trim() !== '' && ( (log, index) =>
<li log &&
key={index} log.trim() !== "" && (
className="log-item text-sm text-white py-1 px-2 bg-black/20 rounded animate-fadeIn" <li
> key={index}
{log} className="log-item text-sm text-white py-1 px-2 bg-black/20 rounded animate-fadeIn"
</li> >
) {log}
))} </li>
)
)}
</ul> </ul>
) : ( ) : (
<div className="text-sm text-gray-400 italic"> <div className="text-sm text-gray-400 italic">
... {logs.length > 0 ? "日志加载中..." : "暂无日志记录"}
</div> </div>
)} )}
{/* {!isComplete && filteredLogs.length > 0 && ( {/* {!isComplete && filteredLogs.length > 0 && (
<div className="loading-indicator mt-2 text-xs text-blue-300"> <div className="loading-indicator mt-2 text-xs text-blue-300">
... ...
@ -148,10 +152,10 @@ const CustomTooltipLeft = ({
</div> </div>
)} )}
</div> </div>
<img <img
className="line-img-left" className="line-img-left"
src={getUrl("svg/anti-forensics-forwarding/LineLeft.svg")} src={getUrl("svg/anti-forensics-forwarding/LineLeft.svg")}
alt="" alt=""
/> />
</div> </div>
</div> </div>
@ -182,7 +186,7 @@ export const WorldGeo = memo(
newHomeProxies: any; newHomeProxies: any;
tooltipType: string; tooltipType: string;
tooltipClosed: boolean; tooltipClosed: boolean;
trafficObfuscationLogs:any; trafficObfuscationLogs: any;
setTooltipClosed: (value: boolean) => void; setTooltipClosed: (value: boolean) => void;
}) => { }) => {
// const queryClient = useQueryClient() // const queryClient = useQueryClient()
@ -202,12 +206,10 @@ export const WorldGeo = memo(
>([]); >([]);
const labelContainerRef = useRef<HTMLDivElement | null>(null); const labelContainerRef = useRef<HTMLDivElement | null>(null);
const labelsRef = useRef<HTMLDivElement[]>([]); const labelsRef = useRef<HTMLDivElement[]>([]);
// 添加状态来控制是否显示tooltip // 添加状态来控制是否显示tooltip
const [showTooltip1, setShowTooltip1] = useState(false); const [showTooltip1, setShowTooltip1] = useState(false);
const [showTooltip2, setShowTooltip2] = useState(false); const [showTooltip2, setShowTooltip2] = useState(false);
const mainToData = useMemo(() => { const mainToData = useMemo(() => {
// 使用新的数据结构 // 使用新的数据结构
@ -249,7 +251,7 @@ export const WorldGeo = memo(
}); });
return data; return data;
}, [currentValue]); }, [currentValue]);
// 定位自定义提示框 - 优化版本 // 定位自定义提示框 - 优化版本
const positionCustomTooltip = () => { const positionCustomTooltip = () => {
if (!customTooltipRef.current || !proxyGeoRef.current) return; if (!customTooltipRef.current || !proxyGeoRef.current) return;
@ -272,7 +274,7 @@ export const WorldGeo = memo(
console.error("Error positioning tooltip:", error); console.error("Error positioning tooltip:", error);
} }
}; };
// 定位自定义提示框2 - 优化版本 // 定位自定义提示框2 - 优化版本
const positionCustomTooltip2 = () => { const positionCustomTooltip2 = () => {
if (!customTooltip2Ref.current || !proxyGeoRef.current) return; if (!customTooltip2Ref.current || !proxyGeoRef.current) return;
@ -299,9 +301,7 @@ export const WorldGeo = memo(
console.error("Error positioning tooltip:", error); console.error("Error positioning tooltip:", error);
} }
}; };
// 处理关闭tooltip2 // 处理关闭tooltip2
const handleCloseTooltip2 = () => { const handleCloseTooltip2 = () => {
setShowTooltip2(false); setShowTooltip2(false);
@ -1128,7 +1128,7 @@ export const WorldGeo = memo(
const handleResize = () => { const handleResize = () => {
proxyGeoRef.current?.resize(); proxyGeoRef.current?.resize();
updateLabelPositions(); updateLabelPositions();
// 重新定位tooltip // 重新定位tooltip
if (showTooltip1) { if (showTooltip1) {
positionCustomTooltip(); positionCustomTooltip();
@ -1181,7 +1181,7 @@ export const WorldGeo = memo(
if (tooltipType !== "PASS_AUTHENTICATION") { if (tooltipType !== "PASS_AUTHENTICATION") {
lineMidpointsRef.current = []; lineMidpointsRef.current = [];
} }
if (tooltipClosed) { if (tooltipClosed) {
if (tooltipType === "NESTED_ENCRYPTION") { if (tooltipType === "NESTED_ENCRYPTION") {
setShowTooltip1(true); setShowTooltip1(true);
@ -1202,7 +1202,7 @@ export const WorldGeo = memo(
setShowTooltip2(false); setShowTooltip2(false);
} }
}, [tooltipClosed, tooltipType, currentValue]); }, [tooltipClosed, tooltipType, currentValue]);
// 在地图初始化后定位tooltip // 在地图初始化后定位tooltip
useEffect(() => { useEffect(() => {
if (showTooltip1) { if (showTooltip1) {
@ -1215,12 +1215,12 @@ export const WorldGeo = memo(
return ( return (
<div className="flex-1 h-full flex flex-col"> <div className="flex-1 h-full flex flex-col">
<div id="screenGeo" className="flex-1"></div> <div id="screenGeo" className="flex-1"></div>
{/* 流量混淆提示框 */} {/* 流量混淆提示框 */}
{showTooltip2 && ( {showTooltip2 && (
<CustomTooltipLeft <CustomTooltipLeft
logs={trafficObfuscationLogs} logs={trafficObfuscationLogs}
onClose={handleCloseTooltip2} onClose={handleCloseTooltip2}
tooltipRef={customTooltip2Ref} tooltipRef={customTooltip2Ref}
title="流量混淆" title="流量混淆"
/> />
@ -1236,7 +1236,7 @@ export const WorldGeo = memo(
// from { opacity: 0; transform: translateY(5px); } // from { opacity: 0; transform: translateY(5px); }
// to { opacity: 1; transform: translateY(0); } // to { opacity: 1; transform: translateY(0); }
// } // }
// //
// .animate-fadeIn { // .animate-fadeIn {
// animation: fadeIn 0.3s ease-out forwards; // animation: fadeIn 0.3s ease-out forwards;
// } // }

View File

@ -109,7 +109,7 @@ const CustomTooltip = ({
> >
<div className="tooltip-content"> <div className="tooltip-content">
<img <img
className="line-img-hx" className="line-img-hx"
src={getUrl("svg/anti-forensics-forwarding/Line.svg")} src={getUrl("svg/anti-forensics-forwarding/Line.svg")}
alt="" alt=""
/> />
@ -153,15 +153,15 @@ const CustomTooltip = ({
</ul> </ul>
) : ( ) : (
<div className="text-sm text-gray-400 italic"> <div className="text-sm text-gray-400 italic">
... {logs.length > 0 ? "日志加载中..." : "暂无日志记录"}
</div> </div>
)} )}
{!isComplete && filteredLogs.length > 0 && ( {/* {!isComplete && filteredLogs.length > 0 && (
<div className="loading-indicator mt-2 text-xs text-blue-300"> <div className="loading-indicator mt-2 text-xs text-blue-300">
... ...
</div> </div>
)} )} */}
</div> </div>
)} )}
</div> </div>
@ -304,15 +304,15 @@ const CustomTooltipLeft = ({
</ul> </ul>
) : ( ) : (
<div className="text-sm text-gray-400 italic"> <div className="text-sm text-gray-400 italic">
... {logs.length > 0 ? "日志加载中..." : "暂无日志记录"}
</div> </div>
)} )}
{!isComplete && filteredLogs.length > 0 && ( {/* {!isComplete && filteredLogs.length > 0 && (
<div className="loading-indicator mt-2 text-xs text-blue-300"> <div className="loading-indicator mt-2 text-xs text-blue-300">
... ...
</div> </div>
)} )} */}
</div> </div>
)} )}
</div> </div>
@ -344,12 +344,16 @@ export const WorldGeo = memo(
selectedApp, selectedApp,
tooltipType, tooltipType,
tooltipClosed, tooltipClosed,
nestedEncryptionLogs,
trafficObfuscationLogs,
setTooltipClosed, setTooltipClosed,
}: { }: {
dataInfo: any; dataInfo: any;
selectedApp: any; selectedApp: any;
tooltipType: string; tooltipType: string;
tooltipClosed: boolean; tooltipClosed: boolean;
nestedEncryptionLogs: string[];
trafficObfuscationLogs: string[];
setTooltipClosed: (value: boolean) => void; setTooltipClosed: (value: boolean) => void;
}) => { }) => {
// const queryClient = useQueryClient() // const queryClient = useQueryClient()
@ -371,27 +375,8 @@ export const WorldGeo = memo(
const labelsRef = useRef<HTMLDivElement[]>([]); const labelsRef = useRef<HTMLDivElement[]>([]);
// 添加状态来控制是否显示tooltip // 添加状态来控制是否显示tooltip
const [showTooltip1, setShowTooltip1] = useState(false); const [showTooltip1, setShowTooltip1] = useState(true);
const [showTooltip2, setShowTooltip2] = useState(false); const [showTooltip2, setShowTooltip2] = useState(true);
// 模拟日志数据
const [nestedEncryptionLogs] = useState<string[]>([
"初始化嵌套加密...",
"生成密钥对...",
"应用第一层加密...",
"应用第二层加密...",
"应用第三层加密...",
"加密完成,准备传输...",
]);
const [trafficObfuscationLogs] = useState<string[]>([
"初始化流量混淆...",
"分析流量特征...",
"应用随机填充...",
"调整数据包时间间隔...",
"模拟HTTP流量...",
"混淆完成,准备传输...",
]);
// 添加调试日志 // 添加调试日志
useEffect(() => { useEffect(() => {
@ -517,8 +502,8 @@ export const WorldGeo = memo(
screenCoord.length === 2 screenCoord.length === 2
) { ) {
// 设置提示框位置 // 设置提示框位置
const left = `${screenCoord[0] - 626 + 20}px`; const left = `${screenCoord[0] - 626 + 48}px`;
const top = `${screenCoord[1] + 40 - 13}px`; const top = `${screenCoord[1] + 40 - 20}px`;
console.log("Setting tooltip2 position:", { left, top }); console.log("Setting tooltip2 position:", { left, top });
customTooltip2Ref.current.style.left = left; customTooltip2Ref.current.style.left = left;
@ -1443,27 +1428,17 @@ export const WorldGeo = memo(
// 修改处理tooltip的显示和隐藏的逻辑 // 修改处理tooltip的显示和隐藏的逻辑
useEffect(() => { useEffect(() => {
console.log("Tooltip effect triggered:", { tooltipClosed, tooltipType });
if (tooltipClosed) { if (tooltipClosed) {
if (tooltipType === "NESTED_ENCRYPTION") { setShowTooltip1(true);
setShowTooltip1(true); setShowTooltip2(true); // 确保另一个是关闭的
setShowTooltip2(false); // 确保另一个是关闭的 setTimeout(() => {
// 在下一个渲染周期后定位tooltip positionCustomTooltip();
setTimeout(() => { positionCustomTooltip2();
positionCustomTooltip(); }, 0);
}, 0);
} else if (tooltipType === "TRAFFIC_OBFUSCATION") {
setShowTooltip1(false); // 确保另一个是关闭的
setShowTooltip2(true);
// 在下一个渲染周期后定位tooltip
setTimeout(() => {
positionCustomTooltip2();
}, 0);
}
} else { } else {
setShowTooltip1(false); // setShowTooltip1(false);
setShowTooltip2(false); // setShowTooltip2(false);
} }
}, [ }, [
tooltipClosed, tooltipClosed,
@ -1484,25 +1459,26 @@ export const WorldGeo = memo(
{/* 嵌套加密提示框 */} {/* 嵌套加密提示框 */}
<CustomTooltip {showTooltip1 && (
logs={nestedEncryptionLogs} <CustomTooltip
onClose={handleCloseTooltip1} logs={nestedEncryptionLogs}
tooltipRef={customTooltipRef} onClose={handleCloseTooltip1}
title={CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.title} tooltipRef={customTooltipRef}
imageSrc={getUrl("image/nested-encryption.png")} title={CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.title}
/> imageSrc={getUrl("image/nested-encryption.png")}
/>
)}
{/* 流量混淆提示框 - 确保条件正确 */} {/* 流量混淆提示框 - 确保条件正确 */}
{showTooltip2 && (
<CustomTooltipLeft <CustomTooltipLeft
logs={trafficObfuscationLogs} logs={trafficObfuscationLogs}
onClose={handleCloseTooltip2} onClose={handleCloseTooltip2}
tooltipRef={customTooltip2Ref} tooltipRef={customTooltip2Ref}
title="流量混淆" title="流量混淆"
imageSrc={getUrl("image/traffic-obfuscation.png")} imageSrc={getUrl("image/traffic-obfuscation.png")}
/> />
)}
</div> </div>
); );
} }

View File

@ -67,10 +67,7 @@ const NewHome = () => {
(state: RootState) => state.serviceReducer (state: RootState) => state.serviceReducer
); );
const [isProxyLoading, setIsProxyLoading] = useState(false); const [isProxyLoading, setIsProxyLoading] = useState(false);
const [form] = Form.useForm();
const [open, setOpen] = useState(false);
const [openNode, setOpenNode] = useState(false);
const [dialogLoading] = useState(false);
const [selectedApp, setSelectedApp] = useState<any>(null); const [selectedApp, setSelectedApp] = useState<any>(null);
const [tooltipClosed, setTooltipClosed] = useState(true); const [tooltipClosed, setTooltipClosed] = useState(true);
@ -79,30 +76,32 @@ const NewHome = () => {
CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type
); );
// 模拟日志数据
const [nestedEncryptionLogs, setNestedEncryptionLogs] = useState<string[]>([
"1初始化嵌套加密...",
"2生成密钥对...",
"3应用第一层加密...",
"4应用第二层加密...",
"应用第三层加密...",
"加密完成,准备传输...",
]);
const [trafficObfuscationLogs, setTrafficObfuscationLogs] = useState<
string[]
>([
"2初始化流量混淆...",
"2分析流量特征...",
"3应用随机填充...",
"4调整数据包时间间隔...",
"模拟HTTP流量...",
"混淆完成,准备传输...",
]);
const newWeb3List = useMemo(() => { const newWeb3List = useMemo(() => {
// 展示最新的6个节点 // 展示最新的6个节点
return web3List.slice(-6); return web3List.slice(-6);
}, [web3List]); }, [web3List]);
const successHandle = async () => {
await form.validateFields();
const formValue: any = form.getFieldsValue();
if (type.title === DIALOGTYPE.ADDNode.title) {
setOpen(false);
} else {
const { inbound, outbound } = formValue || {};
if (inbound && outbound) {
dispatch(
setProxyInfoProxies({
country_code: inbound,
ingress_country_code: outbound,
})
);
setOpen(false);
}
}
};
const handleClickApp = (item: any) => { const handleClickApp = (item: any) => {
setSelectedApp(item); setSelectedApp(item);
}; };
@ -206,7 +205,8 @@ const NewHome = () => {
const nestedEncryption = await getNestedEncryption(); const nestedEncryption = await getNestedEncryption();
const applicationDiversion = await getApplicationDiversion(); const applicationDiversion = await getApplicationDiversion();
const dynamicRouteGeneration = await getDynamicRouteGeneration(); const dynamicRouteGeneration = await getDynamicRouteGeneration();
setNestedEncryptionLogs(nestedEncryption.logs);
setTrafficObfuscationLogs(trafficObfuscation.logs);
setDataInfo({ setDataInfo({
passAuthentication: passAuthentication.data, passAuthentication: passAuthentication.data,
trafficObfuscation: [trafficObfuscation.data], trafficObfuscation: [trafficObfuscation.data],
@ -327,6 +327,8 @@ const NewHome = () => {
<div className="mt-2 w-full h-full flex-1"> <div className="mt-2 w-full h-full flex-1">
<WorldGeo <WorldGeo
dataInfo={dataInfo} dataInfo={dataInfo}
nestedEncryptionLogs={nestedEncryptionLogs}
trafficObfuscationLogs={trafficObfuscationLogs}
selectedApp={selectedApp} selectedApp={selectedApp}
tooltipType={tooltipType} tooltipType={tooltipType}
tooltipClosed={tooltipClosed} tooltipClosed={tooltipClosed}