feat:首页接口对接
This commit is contained in:
parent
da91340bcf
commit
652aea1829
1
.env
1
.env
@ -3,3 +3,4 @@ COSMOS_ENDPOINT="http://156.229.167.121:26657"
|
||||
NODE_SECRET="aHVnZSBjb21wYW55IHBob25lIHdlc3QgcGxhY2Ugc2VtaW5hciBtaXJhY2xlIGxlbmQgbWFuZGF0ZSB0aGVuIGFkanVzdCBxdWl0IG1lYXQgY2hlYXAgbm9vZGxlIGNvdXBsZSBkZWZpbmUgbXVzY2xlIHB1bHNlIHNpc3RlciBwaWVjZSBkZXZpY2UgcHJpdmF0ZSBob29k"
|
||||
IS_DEBUG="true"
|
||||
ACCOUNT_NAME="de1"
|
||||
VITE_BASE_URL="http://10.66.66.234:6060"
|
||||
|
||||
27
src/api/flying-line.ts
Normal file
27
src/api/flying-line.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { api } from "@/utils/api";
|
||||
|
||||
const baseUrl = import.meta.env.VITE_BASE_URL;
|
||||
|
||||
// 通行认证
|
||||
export const getPassAuthentication = async () => {
|
||||
return await api.get(`${baseUrl}/step/pass_authentication`);
|
||||
};
|
||||
|
||||
// 流量混淆
|
||||
export const getTrafficObfuscation = async () => {
|
||||
return await api.get(`${baseUrl}/step/traffic_obfuscation`);
|
||||
}
|
||||
|
||||
// 嵌套加密
|
||||
export const getNestedEncryption = async () => {
|
||||
return await api.get(`${baseUrl}/step/nested_encryption`);
|
||||
}
|
||||
// 动态路由生成
|
||||
export const getDynamicRouteGeneration = async () => {
|
||||
return await api.get(`${baseUrl}/step/dynamic_route_generator`);
|
||||
}
|
||||
|
||||
// 应用分流
|
||||
export const getApplicationDiversion = async () => {
|
||||
return await api.get(`${baseUrl}/step/app_diversion`);
|
||||
}
|
||||
@ -499,7 +499,6 @@ export const WorldGeo = memo(
|
||||
label: {
|
||||
show: false,
|
||||
formatter: (params: any) => {
|
||||
console.log(params, "params");
|
||||
return `{${params.data.datas.country_code}|}`;
|
||||
},
|
||||
},
|
||||
|
||||
@ -473,7 +473,6 @@ export const WorldGeo = memo(
|
||||
label: {
|
||||
show: false,
|
||||
formatter: (params: any) => {
|
||||
console.log(params, "params");
|
||||
return `{${params.data.datas.country_code}|}`;
|
||||
},
|
||||
},
|
||||
|
||||
@ -32,14 +32,12 @@ export const WorldGeo = memo(
|
||||
({
|
||||
currentValue,
|
||||
newHomeProxies,
|
||||
selectedApp,
|
||||
tooltipType,
|
||||
tooltipClosed,
|
||||
setTooltipClosed,
|
||||
}: {
|
||||
currentValue: any;
|
||||
newHomeProxies: any;
|
||||
selectedApp: any;
|
||||
tooltipType: string;
|
||||
tooltipClosed: boolean;
|
||||
setTooltipClosed: (value: boolean) => void;
|
||||
@ -168,7 +166,7 @@ export const WorldGeo = memo(
|
||||
const positionCustomTooltip = () => {
|
||||
if (!customTooltipRef.current || !proxyGeoRef.current) return;
|
||||
// 找到US点
|
||||
const coords = geoCoordMap["GL"];
|
||||
const coords = geoCoordMap[currentValue?.[0]?.code ?? "GL"];
|
||||
if (!coords) return;
|
||||
try {
|
||||
// 将地理坐标转换为屏幕坐标
|
||||
@ -240,7 +238,7 @@ export const WorldGeo = memo(
|
||||
const positionCustomTooltip2 = () => {
|
||||
if (!customTooltip2Ref.current || !proxyGeoRef.current) return;
|
||||
// 找到US点
|
||||
const coords = geoCoordMap["ZA"];
|
||||
const coords = geoCoordMap[currentValue?.[0]?.code ?? "ZA"];
|
||||
if (!coords) return;
|
||||
try {
|
||||
// 将地理坐标转换为屏幕坐标
|
||||
@ -262,27 +260,6 @@ export const WorldGeo = memo(
|
||||
console.error("Error positioning tooltip:", error);
|
||||
}
|
||||
};
|
||||
// 主线每个节点tip竖线的经纬度,修改tip 竖线的高度也可以用这个
|
||||
const mianLineData = (data: typeof mainToData) => {
|
||||
return (
|
||||
data
|
||||
.map((item: any) => {
|
||||
const countryCode = item.country_code.toUpperCase();
|
||||
if (!(["RU", "FR"].includes(countryCode) && item.type === "start"))
|
||||
return null;
|
||||
const coords = geoCoordMap[countryCode] as
|
||||
| [number, number]
|
||||
| undefined;
|
||||
if (!coords) return null;
|
||||
return {
|
||||
name: countryCodeMap[countryCode],
|
||||
coords: [coords, [coords[0], coords[1] + 4]],
|
||||
value: countryCode,
|
||||
};
|
||||
})
|
||||
.filter((v: any) => !!v) ?? []
|
||||
);
|
||||
};
|
||||
const getLineItem = (
|
||||
preCode: string,
|
||||
nextCode: string
|
||||
@ -618,7 +595,6 @@ export const WorldGeo = memo(
|
||||
};
|
||||
// 创建带自定义提示框的涟漪点
|
||||
const createRipplePointsWithTooltip = (ripplePoints: any) => {
|
||||
console.log(ripplePoints, "asdasdas");
|
||||
return {
|
||||
type: "effectScatter",
|
||||
coordinateSystem: "geo",
|
||||
@ -640,7 +616,6 @@ export const WorldGeo = memo(
|
||||
label: {
|
||||
show: false,
|
||||
formatter: (params: any) => {
|
||||
console.log(params, "params");
|
||||
return `{${params.data.datas.country_code}|}`;
|
||||
},
|
||||
},
|
||||
@ -706,7 +681,6 @@ export const WorldGeo = memo(
|
||||
} as echarts.SeriesOption);
|
||||
}
|
||||
solidData.forEach((item) => {
|
||||
console.log(item, "item");
|
||||
// 如果没有连线数据,则跳过
|
||||
if (item[1].length === 0) {
|
||||
return;
|
||||
@ -788,98 +762,12 @@ export const WorldGeo = memo(
|
||||
});
|
||||
return true;
|
||||
};
|
||||
// 主线tip series
|
||||
const getMianLineTipData = (series: echarts.SeriesOption[] = []) => {
|
||||
series.push(
|
||||
// 柱状体的主干
|
||||
{
|
||||
name: "solidTip",
|
||||
type: "lines",
|
||||
zlevel: 5,
|
||||
effect: {
|
||||
show: false,
|
||||
symbolSize: 5, // 图标大小
|
||||
},
|
||||
lineStyle: {
|
||||
width: 0, // 尾迹线条宽度
|
||||
color: "#F0FFA2",
|
||||
opacity: 1, // 尾迹线条透明度
|
||||
curveness: 0, // 尾迹线条曲直度
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: "end",
|
||||
color: "#fff",
|
||||
formatter: (parameters) => {
|
||||
const isFr = parameters.value === "FR";
|
||||
console.log(parameters, "parameters");
|
||||
const name = isFr ? "权威节点团" : "待认证节点";
|
||||
return `{left|}{gap2|}{name${
|
||||
isFr ? "2" : "1"
|
||||
}|${name}}{gap3|}{right|}`;
|
||||
},
|
||||
rich: {
|
||||
// left: {
|
||||
// color: "transparent",
|
||||
// height: 35,
|
||||
// width: 8,
|
||||
// align: "center",
|
||||
// backgroundColor: {
|
||||
// image: `data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMSIgaGVpZ2h0PSI1OCIgdmlld0JveD0iMCAwIDExIDU4IiBmaWxsPSJub25lIj4KPHBhdGggZD0iTTExIDU2LjA4ODRIMVY0Ni4wODg0IiBzdHJva2U9IiNGRkZERDMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik0xIDExVjFIMTEiIHN0cm9rZT0iI0ZGRkREMyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTguNzI5NDkgMTlWMzkiIHN0cm9rZT0iI0ZGRkREMyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPC9zdmc+`, // 动态生成国旗图标
|
||||
// },
|
||||
// },
|
||||
gap1: {
|
||||
height: 35,
|
||||
width: 8,
|
||||
},
|
||||
gap2: {
|
||||
height: 35,
|
||||
width: 6,
|
||||
},
|
||||
name1: {
|
||||
color: "#FF6B01",
|
||||
align: "center",
|
||||
lineHeight: 35,
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
padding: [11, 16.52, 11, 16.52],
|
||||
backgroundColor: "rgba(63, 6, 3, 0.5)",
|
||||
},
|
||||
name2: {
|
||||
color: "#37FF00",
|
||||
align: "center",
|
||||
lineHeight: 35,
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
padding: [11, 16.52, 11, 16.52],
|
||||
backgroundColor: "rgba(4, 59, 27, 0.5)",
|
||||
},
|
||||
gap3: {
|
||||
height: 35,
|
||||
width: 8,
|
||||
},
|
||||
// right: {
|
||||
// color: "transparent",
|
||||
// height: 35,
|
||||
// width: 8,
|
||||
// align: "center",
|
||||
// backgroundColor: {
|
||||
// image: `data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSI1OCIgdmlld0JveD0iMCAwIDE0IDU4IiBmaWxsPSJub25lIj4KPHBhdGggZD0iTTEyLjczMDIgNDYuMDQzOVY1Ni4wNDM5SDIuNzMwMjIiIHN0cm9rZT0iI0ZGRkREMyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTIuNzMwMjIgMS4wNDM5NUgxMi43MzAyVjExLjA0MzkiIHN0cm9rZT0iI0ZGRkREMyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTEgMTkuMDQzOVYzOS4wNDM5IiBzdHJva2U9IiNGRkZERDMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+Cjwvc3ZnPg==`, // 动态生成国旗图标
|
||||
// },
|
||||
// },
|
||||
},
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
silent: true,
|
||||
data: mianLineData(mainToData),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 创建A点和B点,并添加飞线和标签
|
||||
const createSpecialPoints = (series: echarts.SeriesOption[]) => {
|
||||
// 定义点A和点B的坐标
|
||||
const pointA = [-42.604303, 71.706936];
|
||||
const pointB = [-106.346771, 56.130366];
|
||||
const pointA = geoCoordMap[currentValue[0]?.startPoint ?? "GL"];
|
||||
const pointB = geoCoordMap[currentValue[0]?.endPoint ?? "CA"];
|
||||
const newPointB = [pointB[0] + 14, pointB[1] + 10];
|
||||
// 添加A点 - 带涟漪效果的双层点
|
||||
series.push(
|
||||
@ -1021,14 +909,19 @@ export const WorldGeo = memo(
|
||||
const series: echarts.SeriesOption[] = [];
|
||||
getLianData(series);
|
||||
// getMianLineTipData(series); // 添加主线tip 暂时隐藏
|
||||
if (tooltipType === "PASS_AUTHENTICATION") {
|
||||
if (
|
||||
tooltipType === "PASS_AUTHENTICATION" &&
|
||||
currentValue &&
|
||||
currentValue.length &&
|
||||
currentValue[0]?.authenticationPoint
|
||||
) {
|
||||
console.log(currentValue, "values");
|
||||
|
||||
createSpecialPoints(series); // 添加特殊点和飞线
|
||||
if (newHomeProxies[0]?.authenticationPoint) {
|
||||
createRipplePointsFromCoordinates(
|
||||
newHomeProxies[0]?.authenticationPoint || [],
|
||||
series
|
||||
);
|
||||
}
|
||||
createRipplePointsFromCoordinates(
|
||||
currentValue[0]?.authenticationPoint || [],
|
||||
series
|
||||
);
|
||||
}
|
||||
|
||||
const option = {
|
||||
@ -1250,7 +1143,7 @@ export const WorldGeo = memo(
|
||||
customTooltipRef.current = null;
|
||||
customTooltip2Ref.current = null;
|
||||
};
|
||||
}, [tooltipClosed, tooltipType]);
|
||||
}, [tooltipClosed, tooltipType, currentValue]);
|
||||
return (
|
||||
<div className="flex-1 h-full flex flex-col">
|
||||
<div id="screenGeo" className="flex-1"></div>
|
||||
|
||||
@ -39,7 +39,13 @@ import {
|
||||
} from "./data/mockData";
|
||||
|
||||
import "./index.scss";
|
||||
import { App } from "antd";
|
||||
import {
|
||||
getApplicationDiversion,
|
||||
getDynamicRouteGeneration,
|
||||
getNestedEncryption,
|
||||
getPassAuthentication,
|
||||
getTrafficObfuscation,
|
||||
} from "@/api/flying-line";
|
||||
|
||||
export const DIALOGTYPE = {
|
||||
ADDNode: {
|
||||
@ -161,7 +167,7 @@ export const CONST_TOOLTIP_TYPE = {
|
||||
};
|
||||
|
||||
const DecentralizedElasticNetwork = () => {
|
||||
const { proxy_info, path_list, newHomeProxies } = useSelector(
|
||||
const { newHomeProxies } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
|
||||
@ -171,77 +177,111 @@ const DecentralizedElasticNetwork = () => {
|
||||
const [tooltipClosed, setTooltipClosed] = useState(false);
|
||||
|
||||
const [selectedApp, setSelectedApp] = useState<any>(null);
|
||||
const [dataInfo, setDataInfo] = useState<any>(null);
|
||||
|
||||
const currentValue = useMemo(() => {
|
||||
let value = dataInfo;
|
||||
|
||||
switch (tooltipType) {
|
||||
case CONST_TOOLTIP_TYPE.APP_DIVERSION.type:
|
||||
value = selectedApp ? [selectedApp] : [];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}, [tooltipType, selectedApp,dataInfo]);
|
||||
|
||||
const handleClickApp = (item: any) => {
|
||||
setSelectedApp(item);
|
||||
};
|
||||
|
||||
const getDataInfo = async () => {
|
||||
let value = [];
|
||||
|
||||
switch (tooltipType) {
|
||||
case CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type:
|
||||
const nestedEncryption = await getNestedEncryption();
|
||||
value = [nestedEncryption.data];
|
||||
break;
|
||||
case CONST_TOOLTIP_TYPE.TRAFFIC_OBFUSCATION.type:
|
||||
const trafficObfuscation = await getTrafficObfuscation();
|
||||
value = [trafficObfuscation.data];
|
||||
break;
|
||||
case CONST_TOOLTIP_TYPE.DYNAMIC_ROUTE_GENERATOR.type:
|
||||
const dynamicRouteGeneration = await getDynamicRouteGeneration();
|
||||
value = dynamicRouteGeneration.data;
|
||||
break;
|
||||
// case CONST_TOOLTIP_TYPE.APP_DIVERSION.type:
|
||||
// const applicationDiversion = await getApplicationDiversion();
|
||||
|
||||
// value = selectedApp ? [selectedApp] : [];
|
||||
// break;
|
||||
case CONST_TOOLTIP_TYPE.PASS_AUTHENTICATION.type:
|
||||
const passAuthentication = await getPassAuthentication();
|
||||
value = [passAuthentication.data];
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
console.log(value,'valuevalue')
|
||||
setDataInfo(value);
|
||||
};
|
||||
|
||||
const [appData, setAppData] = useState<any>([]);
|
||||
const appDiversion = useMemo(() => {
|
||||
return Apps.map((item) => {
|
||||
const findApp = APP_DIVERSION.find(
|
||||
(appItem) => item.name === appItem.name
|
||||
const findApp = appData.find(
|
||||
(appItem:any) => item.name === appItem.name
|
||||
);
|
||||
return {
|
||||
...item,
|
||||
...findApp,
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
const currentValue = useMemo(() => {
|
||||
let value = null;
|
||||
switch (tooltipType) {
|
||||
case CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type:
|
||||
value = [NESTED_ENCRYPTION];
|
||||
break;
|
||||
case CONST_TOOLTIP_TYPE.TRAFFIC_OBFUSCATION.type:
|
||||
value = [TRAFFIC_OBFUSCATION];
|
||||
break;
|
||||
case CONST_TOOLTIP_TYPE.DYNAMIC_ROUTE_GENERATOR.type:
|
||||
value = DYNAMIC_ROUTE_GENERATOR
|
||||
break;
|
||||
case CONST_TOOLTIP_TYPE.APP_DIVERSION.type:
|
||||
value = selectedApp ? [selectedApp] : []
|
||||
break;
|
||||
case CONST_TOOLTIP_TYPE.PASS_AUTHENTICATION.type:
|
||||
value = [PASS_AUTHENTICATION]
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}, [tooltipType,selectedApp]);
|
||||
}, [appData]);
|
||||
const initData = async () => {
|
||||
const applicationDiversion = await getApplicationDiversion();
|
||||
|
||||
const handleClickApp = (item: any) => {
|
||||
console.log("item", item);
|
||||
setSelectedApp(item);
|
||||
setAppData(applicationDiversion.data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getDataInfo();
|
||||
},[tooltipType])
|
||||
|
||||
useEffect(()=>{
|
||||
()=>{
|
||||
setTooltipClosed(false);
|
||||
}
|
||||
},[])
|
||||
useEffect(() => {
|
||||
initData();
|
||||
() => {
|
||||
setTooltipClosed(false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="decentralized w-full h-full flex flex-col relative">
|
||||
<div className="flex items-center gap-[60px] absolute top-12 left-12 z-10">
|
||||
{tooltipType === CONST_TOOLTIP_TYPE.APP_DIVERSION.type && appDiversion.map((item) => {
|
||||
return (
|
||||
<div
|
||||
key={item.name}
|
||||
className="flex items-center justify-center w-16 h-16 relative rounded-[4.95px] shadow-[0px_0px_3.299999952316284px_0px_rgba(84,87,255,1.00)] outline outline-[0.50px] outline-offset-[-0.50px] outline-indigo-50/60 overflow-hidden"
|
||||
onClick={() => handleClickApp(item)}
|
||||
>
|
||||
{selectedApp?.name === item?.name ? (
|
||||
<item.activeIcon />
|
||||
) : (
|
||||
<item.icon />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{tooltipType === CONST_TOOLTIP_TYPE.APP_DIVERSION.type &&
|
||||
appDiversion.map((item) => {
|
||||
return (
|
||||
<div
|
||||
key={item.name}
|
||||
className="flex items-center justify-center w-16 h-16 relative rounded-[4.95px] shadow-[0px_0px_3.299999952316284px_0px_rgba(84,87,255,1.00)] outline outline-[0.50px] outline-offset-[-0.50px] outline-indigo-50/60 overflow-hidden"
|
||||
onClick={() => handleClickApp(item)}
|
||||
>
|
||||
{selectedApp?.name === item?.name ? (
|
||||
<item.activeIcon />
|
||||
) : (
|
||||
<item.icon />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="mt-2 w-full h-full flex-1">
|
||||
<WorldGeo
|
||||
currentValue={currentValue}
|
||||
newHomeProxies={newHomeProxies}
|
||||
selectedApp={selectedApp}
|
||||
tooltipType={tooltipType}
|
||||
tooltipClosed={tooltipClosed}
|
||||
setTooltipClosed={setTooltipClosed}
|
||||
|
||||
@ -28,13 +28,13 @@ const createCountryRipple = (countryCode: string) => {
|
||||
};
|
||||
export const WorldGeo = memo(
|
||||
({
|
||||
newHomeProxies,
|
||||
dataInfo,
|
||||
selectedApp,
|
||||
tooltipType,
|
||||
tooltipClosed,
|
||||
setTooltipClosed,
|
||||
}: {
|
||||
newHomeProxies: any;
|
||||
dataInfo:any;
|
||||
selectedApp: any;
|
||||
tooltipType: string;
|
||||
tooltipClosed: boolean;
|
||||
@ -58,9 +58,10 @@ export const WorldGeo = memo(
|
||||
const labelContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const labelsRef = useRef<HTMLDivElement[]>([]);
|
||||
const mainToData = useMemo(() => {
|
||||
const newList = [ ...dataInfo.passAuthentication.data,...dataInfo.trafficObfuscation,...dataInfo.nestedEncryption,...dataInfo.dynamicRouteGeneration];
|
||||
// 使用新的数据结构
|
||||
const proxiesList =
|
||||
selectedApp && selectedApp ? [...newHomeProxies,selectedApp] : newHomeProxies ?? [];
|
||||
selectedApp && selectedApp ? [...newList,selectedApp] : newList ?? [];
|
||||
// 初始化数据数组 - 不再包含 startCountry
|
||||
const data: any = [];
|
||||
// 遍历代理列表
|
||||
@ -97,7 +98,7 @@ export const WorldGeo = memo(
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}, [newHomeProxies, selectedApp]);
|
||||
}, [dataInfo, selectedApp]);
|
||||
// 创建自定义提示框DOM元素
|
||||
const createCustomTooltip = () => {
|
||||
// 如果已经存在自定义提示框,则移除它
|
||||
@ -658,7 +659,6 @@ export const WorldGeo = memo(
|
||||
label: {
|
||||
show: false,
|
||||
formatter: (params: any) => {
|
||||
console.log(params, "params");
|
||||
return `{${params.data.datas.country_code}|}`;
|
||||
},
|
||||
},
|
||||
@ -868,8 +868,8 @@ export const WorldGeo = memo(
|
||||
// 创建A点和B点,并添加飞线和标签
|
||||
const createSpecialPoints = (series: echarts.SeriesOption[]) => {
|
||||
// 定义点A和点B的坐标
|
||||
const pointA = [-42.604303, 71.706936];
|
||||
const pointB = [-106.346771, 56.130366];
|
||||
const pointA =geoCoordMap[dataInfo.passAuthentication.startPoint ?? "GL"];
|
||||
const pointB =geoCoordMap[dataInfo.passAuthentication.endPoint ??"CA"];
|
||||
const newPointB = [pointB[0] + 14, pointB[1] + 10];
|
||||
// 添加A点 - 带涟漪效果的双层点
|
||||
series.push(
|
||||
@ -1012,9 +1012,9 @@ export const WorldGeo = memo(
|
||||
getLianData(series);
|
||||
// getMianLineTipData(series); // 添加主线tip 暂时隐藏
|
||||
createSpecialPoints(series); // 添加特殊点和飞线
|
||||
if (newHomeProxies[0]?.authenticationPoint) {
|
||||
if (dataInfo.passAuthentication?.authenticationPoint) {
|
||||
createRipplePointsFromCoordinates(
|
||||
newHomeProxies[0]?.authenticationPoint || [],
|
||||
dataInfo.passAuthentication?.authenticationPoint || [],
|
||||
series
|
||||
);
|
||||
}
|
||||
@ -1186,7 +1186,7 @@ export const WorldGeo = memo(
|
||||
proxyGeoRef.current?.setOption(option);
|
||||
// 创建DOM标签
|
||||
setTimeout(createDOMLabels, 100);
|
||||
}, [newHomeProxies, mainToData]);
|
||||
}, [dataInfo, mainToData]);
|
||||
useEffect(() => {
|
||||
const chartDom = document.getElementById("screenGeo");
|
||||
proxyGeoRef.current = echarts.init(chartDom);
|
||||
|
||||
@ -10,315 +10,368 @@ import OpenProxyPng from "@/assets/image/home/open-proxy.png";
|
||||
import web3BoxGif from "@/assets/gif/web3-box-bg.gif";
|
||||
import VectorSlideSvg from "@/assets/svg/home/vector-solide.svg?react";
|
||||
|
||||
|
||||
import { Apps, CONST_TOOLTIP_TYPE } from "@/pages/anti-forensics-forwarding";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import {
|
||||
setProxyInfoProxies,
|
||||
setProxiesList1,
|
||||
setProxiesList2,
|
||||
setProxyInfoProxies,
|
||||
setProxiesList1,
|
||||
setProxiesList2,
|
||||
} from "@/store/web3Slice";
|
||||
import type { AppDispatch, RootState } from "@/store";
|
||||
import "./index.scss";
|
||||
import { DialogConfig, FormAlertDialog } from "./components/FormAlertDialog";
|
||||
import { ClearNodeDialog } from "./components/ClearNodeDialog";
|
||||
import { blockChainApi } from "@/api/block";
|
||||
import {
|
||||
getPassAuthentication,
|
||||
getTrafficObfuscation,
|
||||
getNestedEncryption,
|
||||
getDynamicRouteGeneration,
|
||||
getApplicationDiversion,
|
||||
} from "@/api/flying-line";
|
||||
import { APP_DIVERSION } from "../anti-forensics-forwarding/data/mockData";
|
||||
|
||||
export const DIALOGTYPE = {
|
||||
ADDNode: {
|
||||
title: "添加节点",
|
||||
desc: "",
|
||||
successText: "添加",
|
||||
},
|
||||
AddNetwork: {
|
||||
title: "构建网络",
|
||||
desc: "",
|
||||
successText: "构建",
|
||||
},
|
||||
ADDNode: {
|
||||
title: "添加节点",
|
||||
desc: "",
|
||||
successText: "添加",
|
||||
},
|
||||
AddNetwork: {
|
||||
title: "构建网络",
|
||||
desc: "",
|
||||
successText: "构建",
|
||||
},
|
||||
};
|
||||
|
||||
export const NODEDIALOGTYPE = {
|
||||
ClearFailNode: {
|
||||
title: "清除掉线节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
ClearWargingNode: {
|
||||
title: "恶意节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
ClearFailNode: {
|
||||
title: "清除掉线节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
ClearWargingNode: {
|
||||
title: "恶意节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
};
|
||||
const NewHome = () => {
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const { web3List, web3List2, newHomeProxies } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const { web3List, web3List2, newHomeProxies } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
|
||||
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 [type, setType] = useState<DialogConfig>(DIALOGTYPE.ADDNode);
|
||||
const [nodeType, setNodeType] = useState<DialogConfig>(
|
||||
NODEDIALOGTYPE.ClearFailNode
|
||||
);
|
||||
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 [type, setType] = useState<DialogConfig>(DIALOGTYPE.ADDNode);
|
||||
const [nodeType, setNodeType] = useState<DialogConfig>(
|
||||
NODEDIALOGTYPE.ClearFailNode
|
||||
);
|
||||
|
||||
const [blockChain, setBlockChain] = useState<any>(null);
|
||||
const [tooltipClosed, setTooltipClosed] = useState(true);
|
||||
|
||||
const [tooltipClosed, setTooltipClosed] = useState(true);
|
||||
const [tooltipType, setTooltipType] = useState(
|
||||
CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type
|
||||
);
|
||||
|
||||
const [tooltipType, setTooltipType] = useState(
|
||||
CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type
|
||||
);
|
||||
const newWeb3List = useMemo(() => {
|
||||
// 展示最新的6个节点
|
||||
return web3List.slice(-6);
|
||||
}, [web3List]);
|
||||
|
||||
const appDiversion = useMemo(() => {
|
||||
return Apps.map((item) => {
|
||||
const findApp = APP_DIVERSION.find(
|
||||
(appItem) => item.name === appItem.name
|
||||
);
|
||||
return {
|
||||
...item,
|
||||
...findApp,
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
const newWeb3List = useMemo(() => {
|
||||
// 展示最新的6个节点
|
||||
return web3List.slice(-6);
|
||||
}, [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) => {
|
||||
setSelectedApp(item);
|
||||
};
|
||||
|
||||
async function handleSelectFile() {
|
||||
try {
|
||||
const selected = await openFile({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Excel Files",
|
||||
extensions: ["xlsx", "xls"], // 移除了扩展名前的点号
|
||||
},
|
||||
],
|
||||
});
|
||||
if (selected && typeof selected === "string") {
|
||||
if (selected.includes("验证节点包1")) {
|
||||
console.log("验证节点包1");
|
||||
dispatch(setProxiesList1());
|
||||
}
|
||||
if (selected.includes("验证节点包2")) {
|
||||
console.log("验证节点包2");
|
||||
dispatch(setProxiesList2());
|
||||
}
|
||||
setOpen(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error selecting file:", err);
|
||||
}
|
||||
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 ICircuitRequest = useMemo(() => {
|
||||
return {
|
||||
open,
|
||||
setOpen,
|
||||
successHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type,
|
||||
canSubmit: true,
|
||||
handleSelectFile,
|
||||
};
|
||||
}, [open, dialogLoading, type, handleSelectFile]);
|
||||
const handleClickApp = (item: any) => {
|
||||
setSelectedApp(item);
|
||||
};
|
||||
|
||||
const nodeSuccessHandle = () => {};
|
||||
async function handleSelectFile() {
|
||||
try {
|
||||
const selected = await openFile({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Excel Files",
|
||||
extensions: ["xlsx", "xls"], // 移除了扩展名前的点号
|
||||
},
|
||||
],
|
||||
});
|
||||
if (selected && typeof selected === "string") {
|
||||
if (selected.includes("验证节点包1")) {
|
||||
console.log("验证节点包1");
|
||||
dispatch(setProxiesList1());
|
||||
}
|
||||
if (selected.includes("验证节点包2")) {
|
||||
console.log("验证节点包2");
|
||||
dispatch(setProxiesList2());
|
||||
}
|
||||
setOpen(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error selecting file:", err);
|
||||
}
|
||||
}
|
||||
|
||||
const ClearNodeDialogProps = useMemo(() => {
|
||||
return {
|
||||
open: openNode,
|
||||
setOpen: setOpenNode,
|
||||
successHandle: nodeSuccessHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type: nodeType,
|
||||
canSubmit: true,
|
||||
};
|
||||
}, [openNode, dialogLoading, nodeType]);
|
||||
const ICircuitRequest = useMemo(() => {
|
||||
return {
|
||||
open,
|
||||
setOpen,
|
||||
successHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type,
|
||||
canSubmit: true,
|
||||
handleSelectFile,
|
||||
};
|
||||
}, [open, dialogLoading, type, handleSelectFile]);
|
||||
|
||||
// useEffect(() => {
|
||||
// dispatch(randomUpdateWeb3List());
|
||||
// dispatch(randomUpdateWeb3List2());
|
||||
// // 每1.5秒更新一次
|
||||
// const interval = setInterval(() => {
|
||||
// dispatch(randomUpdateWeb3List());
|
||||
// dispatch(randomUpdateWeb3List2());
|
||||
// }, 1500);
|
||||
const nodeSuccessHandle = () => {};
|
||||
|
||||
// return () => clearInterval(interval);
|
||||
// }, [dispatch]);
|
||||
const ClearNodeDialogProps = useMemo(() => {
|
||||
return {
|
||||
open: openNode,
|
||||
setOpen: setOpenNode,
|
||||
successHandle: nodeSuccessHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type: nodeType,
|
||||
canSubmit: true,
|
||||
};
|
||||
}, [openNode, dialogLoading, nodeType]);
|
||||
|
||||
useEffect(()=>{
|
||||
blockChainApi.getLatestBlock().then((res)=>{
|
||||
console.log("res",res)
|
||||
setBlockChain(res)
|
||||
})
|
||||
|
||||
},[])
|
||||
const [dataInfo, setDataInfo] = useState<any>({
|
||||
passAuthentication: {
|
||||
type: "PASS_AUTHENTICATION",
|
||||
name: "通行认证",
|
||||
startPoint: "GL",
|
||||
endPoint: "CA",
|
||||
authenticationPoint: [
|
||||
[-103.346771, 54.130366],
|
||||
[-120.346771, 52.130366],
|
||||
[-108.346771, 48.130366],
|
||||
[-98.346771, 46.130366],
|
||||
[-106.346771, 48.450366],
|
||||
[-101.346771, 53.130366],
|
||||
[-123.346771, 58.130366],
|
||||
[-111.346771, 65.443366],
|
||||
[-108.346771, 54.130366],
|
||||
[-116.346771, 59.130366],
|
||||
[-97.346771, 61.130366],
|
||||
[-95.346771, 63.130366],
|
||||
[-113.346771, 58.840366],
|
||||
[-99.346771, 59.130366],
|
||||
[-102.346771, 68.130366],
|
||||
],
|
||||
data: [
|
||||
{
|
||||
country_code: "gl",
|
||||
ingress_country_code: "dz",
|
||||
},
|
||||
{
|
||||
country_code: "br",
|
||||
ingress_country_code: "dz",
|
||||
},
|
||||
{
|
||||
country_code: "dz",
|
||||
ingress_country_code: "ru",
|
||||
},
|
||||
{
|
||||
country_code: "dz",
|
||||
ingress_country_code: "cn",
|
||||
},
|
||||
{
|
||||
country_code: "ru",
|
||||
ingress_country_code: "za",
|
||||
},
|
||||
],
|
||||
isLine: true,
|
||||
},
|
||||
trafficObfuscation: [],
|
||||
nestedEncryption: [],
|
||||
dynamicRouteGeneration: [],
|
||||
applicationDiversion: [],
|
||||
});
|
||||
|
||||
|
||||
const appDiversion = useMemo(() => {
|
||||
return Apps.map((item) => {
|
||||
const findApp = dataInfo.applicationDiversion.find(
|
||||
(appItem: any) => item.name === appItem.name
|
||||
);
|
||||
return {
|
||||
...item,
|
||||
...findApp,
|
||||
};
|
||||
});
|
||||
}, [dataInfo.applicationDiversion]);
|
||||
|
||||
return (
|
||||
<div className="decentralized w-full h-full flex flex-col relative">
|
||||
<div className="box"></div>
|
||||
<div className="w-full flex items-center justify-center relative">
|
||||
{/* <img
|
||||
const initData = async () => {
|
||||
const passAuthentication = await getPassAuthentication();
|
||||
const trafficObfuscation = await getTrafficObfuscation();
|
||||
const nestedEncryption = await getNestedEncryption();
|
||||
const applicationDiversion = await getApplicationDiversion();
|
||||
const dynamicRouteGeneration = await getDynamicRouteGeneration();
|
||||
|
||||
setDataInfo({
|
||||
passAuthentication: passAuthentication.data,
|
||||
trafficObfuscation: [trafficObfuscation.data],
|
||||
nestedEncryption: [nestedEncryption.data],
|
||||
applicationDiversion: applicationDiversion.data,
|
||||
dynamicRouteGeneration: dynamicRouteGeneration.data,
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
// blockChainApi.getLatestBlock().then((res) => {
|
||||
// console.log("res", res);
|
||||
// setBlockChain(res);
|
||||
// });
|
||||
initData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(dataInfo, "awaidataInfodataInfotawait");
|
||||
}, [dataInfo]);
|
||||
|
||||
return (
|
||||
<div className="decentralized w-full h-full flex flex-col relative">
|
||||
<div className="box"></div>
|
||||
<div className="w-full flex items-center justify-center relative">
|
||||
{/* <img
|
||||
className="w-[1693px] h-[271px] absolute top-[160px] left-[50%] translate-x-[-50%] z-10"
|
||||
src={linePng}
|
||||
alt=""
|
||||
/> */}
|
||||
{/* <div className="w-[90%] absolute top-0 left-0"></div> */}
|
||||
<div className="w-[1693px] h-full flex items-center justify-center absolute top-[90px]">
|
||||
<div className="w-[795px] h-full flex items-center justify-end gap-10 z-10">
|
||||
<div className="carousel-container !justify-end">
|
||||
{newWeb3List.map((item, index) => {
|
||||
// 随机0-10的整数
|
||||
const randomDelay =
|
||||
Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
className="w-[105px] relative carousel-item"
|
||||
key={`${item.id}-${index}`}
|
||||
style={{
|
||||
viewTransitionName: `web3-item-1-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className={cn(
|
||||
"!max-w-[186px] h-[160px] relative opacity-50 mix-blend-soft-light z-10"
|
||||
)}
|
||||
style={{
|
||||
left: `${
|
||||
-30 - randomDelay
|
||||
}px`,
|
||||
top: `${
|
||||
-30 - randomDelay
|
||||
}px`,
|
||||
}}
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
src={Web3Box2Png}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5 z-20">
|
||||
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
|
||||
{/* <div className="w-[90%] absolute top-0 left-0"></div> */}
|
||||
<div className="w-[1693px] h-full flex items-center justify-center absolute top-[90px]">
|
||||
<div className="w-[795px] h-full flex items-center justify-end gap-10 z-10">
|
||||
<div className="carousel-container !justify-end">
|
||||
{newWeb3List.map((item, index) => {
|
||||
// 随机0-10的整数
|
||||
const randomDelay = Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
className="w-[105px] relative carousel-item"
|
||||
key={`${item.id}-${index}`}
|
||||
style={{
|
||||
viewTransitionName: `web3-item-1-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className={cn(
|
||||
"!max-w-[186px] h-[160px] relative opacity-50 mix-blend-soft-light z-10"
|
||||
)}
|
||||
style={{
|
||||
left: `${-30 - randomDelay}px`,
|
||||
top: `${-30 - randomDelay}px`,
|
||||
}}
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img src={Web3Box2Png} className="w-full h-full" />
|
||||
<div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5 z-20">
|
||||
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
|
||||
{item.transactions}
|
||||
</div> */}
|
||||
<div className="text-lg">
|
||||
{item.balance} SOL
|
||||
</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="text-lg">{item.balance} SOL</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-fit mt-6 mx-[20px] flex-shrink-0">
|
||||
<VectorSlideSvg />
|
||||
</div>
|
||||
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
|
||||
<div className="carousel-container justify-start">
|
||||
{web3List2.map((item, index) => {
|
||||
const randomDelay =
|
||||
Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
key={`${item.id}-${index}`}
|
||||
className="w-[105px] relative carousel-item"
|
||||
style={{
|
||||
viewTransitionName: `web3-item-2-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className="!max-w-[186px] h-[160px] relative left-[-30px] top-[-30px] opacity-50 mix-blend-soft-light z-10"
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
src={Web3BoxPng}
|
||||
style={{
|
||||
left: `${-30 - randomDelay}px`,
|
||||
top: `${-30 - randomDelay}px`,
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
|
||||
<div className="text-lg">
|
||||
{item.balance} SOL
|
||||
</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="mt-2 w-full h-full flex-1">
|
||||
<WorldGeo
|
||||
newHomeProxies={newHomeProxies}
|
||||
selectedApp={selectedApp}
|
||||
tooltipType={tooltipType}
|
||||
tooltipClosed={tooltipClosed}
|
||||
setTooltipClosed={setTooltipClosed}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-fit mt-6 mx-[20px] flex-shrink-0">
|
||||
<VectorSlideSvg />
|
||||
</div>
|
||||
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
|
||||
<div className="carousel-container justify-start">
|
||||
{web3List2.map((item, index) => {
|
||||
const randomDelay = Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
key={`${item.id}-${index}`}
|
||||
className="w-[105px] relative carousel-item"
|
||||
style={{
|
||||
viewTransitionName: `web3-item-2-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className="!max-w-[186px] h-[160px] relative left-[-30px] top-[-30px] opacity-50 mix-blend-soft-light z-10"
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
src={Web3BoxPng}
|
||||
style={{
|
||||
left: `${-30 - randomDelay}px`,
|
||||
top: `${-30 - randomDelay}px`,
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
|
||||
<div className="text-lg">{item.balance} SOL</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="absolute bottom-[10px] left-[50%] translate-x-[-50%] w-[calc(100%-51px)] p-6 inline-flex justify-start items-center gap-10">
|
||||
<img src={OpenProxyPng} className="w-[193px] h-[90px] cursor-pointer" alt="" />
|
||||
{/* <div
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 w-full h-full flex-1">
|
||||
<WorldGeo
|
||||
dataInfo={dataInfo}
|
||||
selectedApp={selectedApp}
|
||||
tooltipType={tooltipType}
|
||||
tooltipClosed={tooltipClosed}
|
||||
setTooltipClosed={setTooltipClosed}
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute bottom-[10px] left-[50%] translate-x-[-50%] w-[calc(100%-51px)] p-6 inline-flex justify-start items-center gap-10">
|
||||
<img
|
||||
src={OpenProxyPng}
|
||||
className="w-[193px] h-[90px] cursor-pointer"
|
||||
alt=""
|
||||
/>
|
||||
{/* <div
|
||||
className="bt1 cursor-pointer"
|
||||
onClick={() => {
|
||||
setTooltipType(
|
||||
@ -340,26 +393,26 @@ const NewHome = () => {
|
||||
>
|
||||
流量混淆
|
||||
</div> */}
|
||||
{appDiversion.map((item) => {
|
||||
return (
|
||||
<div
|
||||
key={item.name}
|
||||
className="flex items-center justify-center w-16 h-16 relative rounded-[4.95px] shadow-[0px_0px_3.299999952316284px_0px_rgba(84,87,255,1.00)] outline outline-[0.50px] outline-offset-[-0.50px] outline-indigo-50/60 overflow-hidden"
|
||||
onClick={() => handleClickApp(item)}
|
||||
>
|
||||
{selectedApp?.name === item?.name ? (
|
||||
<item.activeIcon />
|
||||
) : (
|
||||
<item.icon />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{appDiversion.map((item) => {
|
||||
return (
|
||||
<div
|
||||
key={item.name}
|
||||
className="flex items-center justify-center w-16 h-16 relative rounded-[4.95px] shadow-[0px_0px_3.299999952316284px_0px_rgba(84,87,255,1.00)] outline outline-[0.50px] outline-offset-[-0.50px] outline-indigo-50/60 overflow-hidden"
|
||||
onClick={() => handleClickApp(item)}
|
||||
>
|
||||
{selectedApp?.name === item?.name ? (
|
||||
<item.activeIcon />
|
||||
) : (
|
||||
<item.icon />
|
||||
)}
|
||||
</div>
|
||||
<FormAlertDialog {...ICircuitRequest} />
|
||||
<ClearNodeDialog {...ClearNodeDialogProps} />
|
||||
</div>
|
||||
);
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<FormAlertDialog {...ICircuitRequest} />
|
||||
<ClearNodeDialog {...ClearNodeDialogProps} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewHome;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user