This commit is contained in:
Aifeilong 2023-09-27 19:19:46 +08:00
parent 326f6e97da
commit 77d3af2f1b
22 changed files with 11930 additions and 37352 deletions

34717
.pnp.cjs generated

File diff suppressed because one or more lines are too long

2042
.pnp.loader.mjs generated

File diff suppressed because it is too large Load Diff

1
.yarnrc.yml Normal file
View File

@ -0,0 +1 @@
nodeLinker: node-modules

11051
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/aliyun-theme": "^0.0.5",
"@ant-design/colors": "^7.0.0", "@ant-design/colors": "^7.0.0",
"@craco/craco": "^7.1.0", "@craco/craco": "^7.1.0",
"@rematch/core": "^2.2.0", "@rematch/core": "^2.2.0",
@ -13,7 +14,7 @@
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"ahooks": "^3.7.8", "ahooks": "^3.7.8",
"antd": "^5.8.4", "antd": "4.24.9",
"cesium": "^1.108.0", "cesium": "^1.108.0",
"craco-cesium": "^1.2.0", "craco-cesium": "^1.2.0",
"craco-less": "^3.0.1", "craco-less": "^3.0.1",

View File

@ -1,4 +1,4 @@
// @import "~antd/dist/antd.less"; @import "~antd/dist/antd.less";
html, html,
body, body,

View File

@ -1,6 +1,8 @@
import { useDispatch } from "react-redux";
import { useCesium } from "resium"; import { useCesium } from "resium";
function AntarcticaFlytoQTP() { function AntarcticaFlytoQTP() {
const dispatch = useDispatch();
const { viewer } = useCesium(); const { viewer } = useCesium();
const { camera } = viewer; const { camera } = viewer;
@ -16,7 +18,7 @@ function AntarcticaFlytoQTP() {
duration: 10, duration: 10,
complete: function () { complete: function () {
setTimeout(() => { setTimeout(() => {
camera.flyTo(area1Options); camera.flyTo(plateauOptions);
}, 1000); }, 1000);
}, },
}; };
@ -63,8 +65,8 @@ function AntarcticaFlytoQTP() {
// //
const plateauOptions = { const plateauOptions = {
destination: Cesium.Cartesian3.fromDegrees(95, -30, 6000000), destination: Cesium.Cartesian3.fromDegrees(90, 20, 1600000),
duration: 10, duration: 5,
orientation: { orientation: {
heading: Cesium.Math.toRadians(-15.0), heading: Cesium.Math.toRadians(-15.0),
pitch: -Cesium.Math.PI_OVER_FOUR, pitch: -Cesium.Math.PI_OVER_FOUR,
@ -79,16 +81,23 @@ function AntarcticaFlytoQTP() {
// //
const sideViewOptions = { const sideViewOptions = {
destination: Cesium.Cartesian3.fromDegrees(70, -60, 14000000), destination: Cesium.Cartesian3.fromDegrees(80, -60, 16000000),
// destination: Cesium.Cartesian3.fromDegrees(130, -10.5, 20000000), // destination: Cesium.Cartesian3.fromDegrees(130, -10.5, 20000000),
duration: 5, duration: 5,
orientation: { orientation: {
heading: Cesium.Math.toRadians(-10.0), heading: Cesium.Math.toRadians(-10.0),
pitch: Cesium.Math.toRadians(-90), pitch: Cesium.Math.toRadians(-92),
roll: 6.0, roll: 6.0,
}, },
complete: () => { complete: () => {
viewer.clock.shouldAnimate = true; viewer.clock.shouldAnimate = true;
dispatch.data.updateToolbar({ showPanel: true });
setTimeout(() => {
camera.flyTo({
duration: 5,
destination: Cesium.Cartesian3.fromDegrees(90, -12, 14000000),
});
}, 40 * 1000);
}, },
}; };

View File

@ -1,17 +1,35 @@
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { CameraFlyTo } from "resium";
import LabFlytoQTP from "./LabFlytoQTP"; import LabFlytoQTP from "./LabFlytoQTP";
import AntarcticaFlytoQTP from "./AntarcticaFlytoQTP"; import AntarcticaFlytoQTP from "./AntarcticaFlytoQTP";
function CustomFlyTo({}) { function CustomFlyTo({}) {
const { type } = useParams(); const { type } = useParams();
return type === "1" ? ( switch (type) {
<LabFlytoQTP /> case "1":
) : type === "2" ? ( return <LabFlytoQTP />;
<AntarcticaFlytoQTP />
) : ( case "2":
<></> return <AntarcticaFlytoQTP />;
);
case "3":
// 西
return (
<CameraFlyTo
duration={5}
destination={Cesium.Cartesian3.fromDegrees(-38.0, 27, 16000000)}
/>
);
default:
//
return (
<CameraFlyTo
duration={5}
destination={Cesium.Cartesian3.fromDegrees(93, 30, 16000000)}
/>
);
}
} }
export default CustomFlyTo; export default CustomFlyTo;

View File

@ -9,7 +9,6 @@ const url = "http://analysis.tpdc.ac.cn/gs/geoserver/phitrellis/wms";
function LayerAntarcticaToQTP() { function LayerAntarcticaToQTP() {
const { imageLayer } = useSelector((state) => state.data); const { imageLayer } = useSelector((state) => state.data);
console.log("imageLayer :>> ", imageLayer);
const tempProvider = useMemo( const tempProvider = useMemo(
() => () =>
new WebMapServiceImageryProvider({ new WebMapServiceImageryProvider({

View File

@ -1,5 +1,6 @@
import { useEffect } from "react"; import { useState } from "react";
import { Entity, PointGraphics, useCesium } from "resium"; import { Entity, PointGraphics, useCesium } from "resium";
import { useInterval } from "ahooks";
// //
const dataAntarcticaToQTP = [ const dataAntarcticaToQTP = [
@ -12,17 +13,20 @@ const dataAntarcticaToQTP = [
{ longitude: 95, latitude: -30, height: 0, time: 60 }, { longitude: 95, latitude: -30, height: 0, time: 60 },
]; ];
let property;
function PathAntarcticaToQTP() { function PathAntarcticaToQTP() {
const { viewer } = useCesium(); const { viewer } = useCesium();
const [delay, setDelay] = useState(1000);
const start = viewer.clock.startTime; const start = viewer.clock.startTime;
const stop = viewer.clock.stopTime; const stop = viewer.clock.stopTime;
const currentTime = viewer.clock.currentTime;
const pathMaterial = new Cesium.Color(4 / 255, 251 / 255, 253 / 255); const pathMaterial = new Cesium.Color(4 / 255, 251 / 255, 253 / 255);
useInterval(() => {
if (viewer.clock?.shouldAnimate) setDelay(undefined);
}, delay);
/** /**
* 计算飞行路径 * 计算飞行路径
* 数据坐标 * 数据坐标
@ -51,10 +55,7 @@ function PathAntarcticaToQTP() {
return property; return property;
} }
useEffect(() => { const property = createProperty(dataAntarcticaToQTP);
property = createProperty(dataAntarcticaToQTP);
console.log("property 2:>> ", start, stop, currentTime, property);
}, []);
return ( return (
<Entity <Entity
@ -63,8 +64,8 @@ function PathAntarcticaToQTP() {
availability={ availability={
new Cesium.TimeIntervalCollection([ new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({ new Cesium.TimeInterval({
start: start, start,
stop: stop, stop,
}), }),
]) ])
} }

View File

@ -1,4 +1,6 @@
import { useState } from "react";
import { Entity, PointGraphics, useCesium } from "resium"; import { Entity, PointGraphics, useCesium } from "resium";
import { useInterval } from "ahooks";
// //
const dataLabToQTP = [ const dataLabToQTP = [
@ -11,6 +13,7 @@ const dataLabToQTP = [
function PathLabToQTP() { function PathLabToQTP() {
const { viewer } = useCesium(); const { viewer } = useCesium();
const [delay, setDelay] = useState(1000);
const start = viewer.clock.startTime; const start = viewer.clock.startTime;
const stop = viewer.clock.stopTime; const stop = viewer.clock.stopTime;
@ -20,6 +23,10 @@ function PathLabToQTP() {
color: new Cesium.Color(4 / 255, 251 / 255, 253 / 255), color: new Cesium.Color(4 / 255, 251 / 255, 253 / 255),
}); });
useInterval(() => {
if (viewer.clock?.shouldAnimate) setDelay(undefined);
}, delay);
/** /**
* 计算飞行路径 * 计算飞行路径
* 数据坐标 * 数据坐标
@ -28,8 +35,6 @@ function PathLabToQTP() {
function createProperty(source) { function createProperty(source) {
let property = new Cesium.SampledPositionProperty(); let property = new Cesium.SampledPositionProperty();
for (let i = 0; i < source.length; i++) { for (let i = 0; i < source.length; i++) {
const start = viewer.clock.startTime;
const stop = viewer.clock.stopTime;
let time = Cesium.JulianDate.addSeconds( let time = Cesium.JulianDate.addSeconds(
start, start,
source[i].time, source[i].time,
@ -42,7 +47,6 @@ function PathLabToQTP() {
); );
// //
property.addSample(time, position); property.addSample(time, position);
console.log("property for:>> ", property, start, stop, viewer);
} }
property.setInterpolationOptions({ property.setInterpolationOptions({
interpolationDegree: 10, interpolationDegree: 10,

View File

@ -1,4 +1,7 @@
const xx = [ import { Entity, EllipseGraphics } from "resium";
import { Cartesian3 } from "cesium";
const fluxData = [
0.03256254, -0.23182425, -0.040055223, -0.03476936, -0.40450656, -0.18742515, 0.03256254, -0.23182425, -0.040055223, -0.03476936, -0.40450656, -0.18742515,
0.045675285, -0.1613145, 0.06295018, -0.14455463, -0.30952197, 0.08164308, 0.045675285, -0.1613145, 0.06295018, -0.14455463, -0.30952197, 0.08164308,
0.019849295, 0.08785298, -0.22862722, -0.29176497, -0.1504006, 0.06978327, 0.019849295, 0.08785298, -0.22862722, -0.29176497, -0.1504006, 0.06978327,
@ -15,9 +18,82 @@ const xx = [
-0.04151492, -0.1793385, -0.04151492, -0.1793385,
]; ];
const colorBar = [
"#73d13d",
"#95de64",
"#b7eb8f",
"#d9f7be",
"#f6ffed",
"#fff1f0",
"#ffccc7",
"#ffa39e",
"#ff7875",
"#ff4d4f",
];
const ranges = [
[-999, -0.4],
[-0.4, -0.3],
[-0.3, -0.2],
[-0.2, -0.1],
[-0.1, 0],
[0, 0.1],
[0.1, 0.2],
[0.2, 0.3],
[0.3, 0.4],
[0.4, 999],
];
let dataIndex = 0;
const height = 201000;
// //
function HeatFlux() { function HeatFlux({ position, index }) {
return "heatFlux"; const [lon, lat] = position;
for (let i = 0; i < ranges.length; i++) {
const start = ranges[i][0];
const end = ranges[i][1];
if (fluxData[index] >= start && fluxData[index] <= end) {
dataIndex = i;
break;
}
}
return (
<Entity
id={`site-heat-flux-${index}`}
position={Cartesian3.fromDegrees(lon, lat, 0)}
description={`
<table className="description-table" style='width:100%'>
<tbody>
<tr>
<th style='width:40%; background-color:#4b4b4b; padding: 3' >
感热通量数据
</th>
<td style='background-color:#4b4b4b; padding: 3'>
${fluxData[index]}
</td>
</tr>
<tr>
<th style=' width: 40%; background-color: #323232; padding: 3 ' >
站点坐标
</th>
<td style=' background-color: #323232; padding: 3 ' > ${lon}${lat} </td>
</tr>
</tbody>
</table>
`}
>
<EllipseGraphics
material={new Cesium.Color.fromCssColorString(colorBar[dataIndex])}
semiMinorAxis={30000.0}
semiMajorAxis={30000.0}
extrudedHeight={400000}
height={height}
/>
</Entity>
);
} }
export default HeatFlux; export default HeatFlux;

View File

@ -1,4 +1,7 @@
const xx = [ import { Entity, EllipseGraphics } from "resium";
import { Cartesian3 } from "cesium";
const rainData = [
0.25309432, 0.296679, 0.39937696, -0.15093477, 0.17799897, 0.1186297, 0.25309432, 0.296679, 0.39937696, -0.15093477, 0.17799897, 0.1186297,
0.07794944, 0.086336374, -0.016019614, -0.10862, 0.026069753, -0.005777068, 0.07794944, 0.086336374, -0.016019614, -0.10862, 0.026069753, -0.005777068,
-0.04960121, -0.13736366, 0.268846, 0.32549506, 0.16180113, 0.34738356, -0.04960121, -0.13736366, 0.268846, 0.32549506, 0.16180113, 0.34738356,
@ -15,9 +18,80 @@ const xx = [
0.10854135, -0.10280543, 0.10854135, -0.10280543,
]; ];
const colorBar = [
"#ffc53d",
"#ffd666",
"#ffe58f",
"#fff1b8",
"#fffbe6",
"#e6f7ff",
"#bae7ff",
"#91d5ff",
"#69c0ff",
"#40a9ff",
];
const ranges = [
[-999, -0.4],
[-0.4, -0.3],
[-0.3, -0.2],
[-0.2, -0.1],
[-0.1, 0],
[0, 0.1],
[0.1, 0.2],
[0.2, 0.3],
[0.3, 0.4],
[0.4, 999],
];
let dataIndex = 0;
// //
function Rain() { function Rain({ position, index }) {
return "xx"; const [lon, lat] = position;
for (let i = 0; i < ranges.length; i++) {
const start = ranges[i][0];
const end = ranges[i][1];
if (rainData[index] >= start && rainData[index] <= end) {
dataIndex = i;
break;
}
}
return (
<Entity
id={`site-rain-${index}`}
position={Cartesian3.fromDegrees(lon, lat, 2000000)}
description={`
<table className="description-table" style='width:100%'>
<tbody>
<tr>
<th style='width:40%; background-color:#4b4b4b; padding: 3' >
青藏高原降水
</th>
<td style='background-color:#4b4b4b; padding: 3'>
${rainData[index]}
</td>
</tr>
<tr>
<th style=' width: 40%; background-color: #323232; padding: 3 ' >
站点坐标
</th>
<td style=' background-color: #323232; padding: 3 ' > ${lon}${lat} </td>
</tr>
</tbody>
</table>
`}
>
<EllipseGraphics
material={new Cesium.Color.fromCssColorString(colorBar[dataIndex])}
semiMinorAxis={30000.0}
semiMajorAxis={30000.0}
extrudedHeight={200000}
/>
</Entity>
);
} }
export default Rain; export default Rain;

View File

@ -1,19 +1,14 @@
import { Entity, Primitive } from "resium"; import { Fragment } from "react";
import Rain from "./Rain";
import HeatFlux from "./HeatFlux";
const positions = [ function Site({ position, index }) {
98, 38, 95, 37, 97, 37, 101, 37, 94, 36, 96, 36, 98, 36, 100, 36, 101, 36, return (
101, 36, 99, 35, 88, 29, 91, 29, 92, 28, 97, 33, 101, 34, 101, 33, 102, 35, <Fragment>
104, 34, 93, 31, 95, 31, 96, 32, 97, 31, 94, 29, 100, 29, 98, 28, 101, 29, <HeatFlux position={position} index={index} />
102, 28, 99, 27, 99, 27, 100, 26, 101, 26, 90, 38, 93, 38, 99, 38, 100, 38, <Rain position={position} index={index} />
93, 36, 100, 37, 102, 37, 93, 35, 80, 32, 84, 32, 90, 31, 91, 32, 92, 31, 81, </Fragment>
30, 88, 30, 91, 30, 87, 29, 91, 29, 85, 28, 87, 28, 89, 28, 89, 27, 92, 34, );
95, 32, 95, 34, 98, 34, 97, 33, 98, 32, 99, 33, 102, 33, 98, 31, 100, 31, 100,
32, 100, 32, 101, 30, 102, 31, 102, 32, 102, 31, 103, 32, 93, 30, 95, 29, 99,
30, 100, 30, 100, 30, 97, 29, 101, 30, 101, 27, 101, 27,
];
function Site() {
return <Entity></Entity>;
} }
export default Site; export default Site;

View File

@ -1,5 +1,30 @@
function Site() { import { useParams } from "react-router-dom";
return ""; import Site from "./Site";
import { chunk } from "lodash-es";
import { useSelector } from "react-redux";
const positions = [
98, 38, 95, 37, 97, 37, 101, 37, 94, 36, 96, 36, 98, 36, 100, 36, 101, 36,
101, 36, 99, 35, 88, 29, 91, 29, 92, 28, 97, 33, 101, 34, 101, 33, 102, 35,
104, 34, 93, 31, 95, 31, 96, 32, 97, 31, 94, 29, 100, 29, 98, 28, 101, 29,
102, 28, 99, 27, 99, 27, 100, 26, 101, 26, 90, 38, 93, 38, 99, 38, 100, 38,
93, 36, 100, 37, 102, 37, 93, 35, 80, 32, 84, 32, 90, 31, 91, 32, 92, 31, 81,
30, 88, 30, 91, 30, 87, 29, 91, 29, 85, 28, 87, 28, 89, 28, 89, 27, 92, 34,
95, 32, 95, 34, 98, 34, 97, 33, 98, 32, 99, 33, 102, 33, 98, 31, 100, 31, 100,
32, 100, 32, 101, 30, 102, 31, 102, 32, 102, 31, 103, 32, 93, 30, 95, 29, 99,
30, 100, 30, 100, 30, 97, 29, 101, 30, 101, 27, 101, 27,
];
function Sites() {
const { type } = useParams();
const { showSite } = useSelector((state) => state.data);
if (type !== "2") return <></>;
if (!showSite) return <></>;
return chunk(positions, 2).map((position, index) => {
return <Site key={`site-${index}`} index={index} position={position} />;
});
} }
export default Site; export default Sites;

View File

@ -0,0 +1,105 @@
import { useSelector } from "react-redux";
import styles from "./index.module.less";
const colorBar = [
"#ffc53d",
"#ffd666",
"#ffe58f",
"#fff1b8",
"#fffbe6",
"#e6f7ff",
"#bae7ff",
"#91d5ff",
"#69c0ff",
"#40a9ff",
];
const colorBar2 = [
"#73d13d",
"#95de64",
"#b7eb8f",
"#d9f7be",
"#f6ffed",
"#fff1f0",
"#ffccc7",
"#ffa39e",
"#ff7875",
"#ff4d4f",
];
function Legend42() {
return (
<div>
<div className={styles.verticalLegend} style={{ bottom: 476 }}>
<div className="legend-title">青藏高原感热通量</div>
<div style={{ flex: 1, width: "100%", display: "flex", gap: 8 }}>
<div className="legend-text">
{[-0.5, -0.4, -0.3, -0.2, -0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5].map(
(item, index) => {
return (
<div
key={`legend-text-item-${index}`}
className="legend-text-item"
>
{item}
</div>
);
}
)}
</div>
<div className="colorbar">
{colorBar2.map((color, index) => {
return (
<div
key={`colorbar-item-${index}`}
className="colorbar-item"
style={{ backgroundColor: color }}
title={`${(-0.5 + index * 0.1).toFixed(1)}~${(
-0.5 +
(index + 1) * 0.1
).toFixed(1)}`}
/>
);
})}
</div>
</div>
</div>
<div className={styles.verticalLegend}>
<div className="legend-title">青藏高原降水量</div>
<div style={{ flex: 1, width: "100%", display: "flex", gap: 8 }}>
<div className="legend-text">
{[-0.5, -0.4, -0.3, -0.2, -0.1, 0, 0.1, 0.2, 0.3, 0.4, 0.5].map(
(item, index) => {
return (
<div
key={`legend-text-item-${index}`}
className="legend-text-item"
>
{item}
</div>
);
}
)}
</div>
<div className="colorbar">
{colorBar.map((color, index) => {
return (
<div
key={`colorbar-item-${index}`}
className="colorbar-item"
style={{ backgroundColor: color }}
title={`${(-0.5 + index * 0.1).toFixed(1)}~${(
-0.5 +
(index + 1) * 0.1
).toFixed(1)}`}
/>
);
})}
</div>
</div>
</div>
</div>
);
}
export default Legend42;

View File

@ -1,11 +1,17 @@
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import Legend41 from "./Legend41"; import Legend41 from "./Legend41";
import Legend42 from "./Legend42";
import Legend45 from "./Legend45"; import Legend45 from "./Legend45";
import { useSelector } from "react-redux";
function Legends() { function Legends() {
const { type } = useParams(); const { type } = useParams();
const { toolbar } = useSelector((state) => state.data);
if (!toolbar.showPanel) return <></>;
if (type === "1") return <Legend41 />; if (type === "1") return <Legend41 />;
if (type === "2") return <Legend42 />;
else if (type === "5") return <Legend45 />; else if (type === "5") return <Legend45 />;
else return <></>; else return <></>;
} }

View File

@ -52,3 +52,58 @@
} }
} }
} }
.verticalLegend :global {
position: absolute;
bottom: 168px;
right: 0;
height: 300px;
width: 130px;
display: flex;
flex-direction: column;
align-items: center;
background-color: #1f485690;
border: 1px solid #04fbfd;
border-radius: 8px;
padding: 8px;
.legend-title {
color: #04fbfd;
}
.colorbar {
width: 100px;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
.colorbar-item {
flex: 1;
border: 2px black solid;
border-left: none;
border-right: none;
height: 25px;
width: 25px;
&:not(:nth-child(1)) {
border-top: none;
}
}
}
.legend-text {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
.legend-text-item {
flex: 1;
text-align: right;
font-weight: 600;
color: white;
-webkit-text-stroke: #04fbfd 1px;
}
}
}

View File

@ -25,12 +25,13 @@ function MapLayout() {
homeButton={false} homeButton={false}
sceneModePicker={false} sceneModePicker={false}
navigationHelpButton={false} navigationHelpButton={false}
shouldAnimate={true} shouldAnimate={false}
// infoBox={false} // infoBox={false}
timeline={false} timeline={false}
fullscreenButton={false} fullscreenButton={false}
geocoder={false} geocoder={false}
baseLayerPicker={false} baseLayerPicker={false}
animation={false}
> >
<CustomClock /> <CustomClock />
<CustomFlyTo /> <CustomFlyTo />

View File

@ -27,30 +27,30 @@
.ant-select-selector { .ant-select-selector {
color: #02f9ff; color: #02f9ff;
border: 1px solid #04fbfd !important; border: 1px solid #04fbfd !important;
background-color: #1f4856; background-color: #1f4856 !important;
padding: 4px 12px; padding: 4px 12px !important;
border-radius: 8px; border-radius: 8px !important;
height: 39px; height: 39px !important;
font-size: 16px; font-size: 14px !important;
.ant-select-selection-item { .ant-select-selection-item {
color: #02f9ff !important; color: #02f9ff !important;
} }
.ant-select-dropdown { .ant-select-dropdown {
background-color: #1f4856; background-color: #1f4856 !important;
.ant-select-item { .ant-select-item {
color: rgb(0, 242, 255); color: rgb(0, 242, 255);
font-size: 16px; font-size: 14px;
&:hover { &:hover {
background-color: #33a4a4; background-color: #33a4a4 !important;
} }
} }
.ant-select-item-option-selected { .ant-select-item-option-selected {
background-color: #33a4a4; background-color: #33a4a4 !important;
} }
} }

View File

@ -201,14 +201,3 @@ export const COLORS = {
"Color.YELLOWGREEN": Color.YELLOWGREEN, "Color.YELLOWGREEN": Color.YELLOWGREEN,
"Color.TRANSPARENT": Color.TRANSPARENT, "Color.TRANSPARENT": Color.TRANSPARENT,
}; };
export const PATH = {
实时视频: "/台站数据/实时视频",
实时监测: "http://chinare.hbaa.cn/iot/yulong.php",
在线数据: "/台站数据/在线数据",
数据申请: "/数据申请",
离线数据: "/manage/offlinedata",
申请审核: "/manage/applydata",
数据分类: "/manage/datatype",
用户管理: "/manage/user",
};

967
yarn.lock

File diff suppressed because it is too large Load Diff