|
@@ -68,14 +68,14 @@
|
|
|
<div v-for="(item, index) in routeData" :key="index" class="route-item2" @click="drawRoute(item)">
|
|
|
<div class="text-box1">
|
|
|
<div :class="'tag' + index">{{ getTag(index) }}</div>
|
|
|
- <div class="text1">{{ item.policy }}</div>
|
|
|
+ <div class="text1">{{ item.strategy }}</div>
|
|
|
</div>
|
|
|
<div class="route-info">
|
|
|
<div class="text-box2">
|
|
|
<i class="icon1" />
|
|
|
- <div class="gradient-text2">{{ item.date[0] }}</div>
|
|
|
+ <div class="gradient-text2">{{ item.duration[0] }}</div>
|
|
|
<div class="text2">小时</div>
|
|
|
- <div class="gradient-text2">{{ item.date[1] }}</div>
|
|
|
+ <div class="gradient-text2">{{ item.duration[1] }}</div>
|
|
|
<div class="text2">分钟</div>
|
|
|
</div>
|
|
|
<div class="line"></div>
|
|
@@ -95,15 +95,29 @@
|
|
|
<script lang="ts" setup name="FixedPointAnalysis">
|
|
|
import BigNumber from 'bignumber.js';
|
|
|
import { getEmergencyRescuePointInfoList } from '@/api/globalMap';
|
|
|
+import markImg from '@/assets/images/map/mark.png';
|
|
|
+import startImg from '@/assets/images/map/start.png';
|
|
|
+import endImg from '@/assets/images/map/end.png';
|
|
|
|
|
|
interface Props {
|
|
|
modelValue: boolean;
|
|
|
location?: string | number[];
|
|
|
+ activeMap: string;
|
|
|
}
|
|
|
+const AMapType = ['vectorgraph', 'satellite'];
|
|
|
const props = withDefaults(defineProps<Props>(), {});
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const { emergency_resource, disaster_relief_material } = toRefs<any>(proxy?.useDict('emergency_resource', 'disaster_relief_material'));
|
|
|
const emits = defineEmits(['update:modelValue']);
|
|
|
+import gcoord from 'gcoord';
|
|
|
+import Icon from 'ol/style/Icon';
|
|
|
+import Feature from 'ol/Feature';
|
|
|
+import Point from 'ol/geom/Point';
|
|
|
+import Style from 'ol/style/Style';
|
|
|
+import { LineString } from 'ol/geom';
|
|
|
+import { Stroke } from 'ol/style';
|
|
|
+
|
|
|
+const amapKey = 'e45d4caa2bef3c84714a2ed9b1e27d98';
|
|
|
let getMapUtils = inject('getMapUtils');
|
|
|
let showAddress = ref(true);
|
|
|
let routeData = ref([]);
|
|
@@ -170,105 +184,181 @@ const selectEvent = (item, unFitView) => {
|
|
|
selectMarker.setMap(null);
|
|
|
selectMarker = null;
|
|
|
}
|
|
|
- // 以 icon URL 的形式创建一个途经点
|
|
|
- const icon = new AMap.Icon({
|
|
|
- size: new AMap.Size(19, 31),
|
|
|
- image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png'
|
|
|
- });
|
|
|
- selectMarker = new AMap.Marker({
|
|
|
- position: new AMap.LngLat(item.longitude, item.latitude),
|
|
|
- icon: icon,
|
|
|
- offset: new AMap.Pixel(-13, -30)
|
|
|
- });
|
|
|
- selectMarker.setMap(map);
|
|
|
- if (!unFitView) {
|
|
|
- map.setFitView([selectMarker]);
|
|
|
+ if (AMapType.includes(props.activeMap)) {
|
|
|
+ // 以 icon URL 的形式创建一个途经点
|
|
|
+ const icon = new AMap.Icon({
|
|
|
+ size: new AMap.Size(19, 31),
|
|
|
+ image: markImg
|
|
|
+ });
|
|
|
+ selectMarker = new AMap.Marker({
|
|
|
+ position: new AMap.LngLat(item.longitude, item.latitude),
|
|
|
+ icon: icon,
|
|
|
+ offset: new AMap.Pixel(-13, -30)
|
|
|
+ });
|
|
|
+ selectMarker.setMap(map);
|
|
|
+ if (!unFitView) {
|
|
|
+ map.setFitView([selectMarker]);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const icon = new Icon({
|
|
|
+ src: markImg,
|
|
|
+ width: 19,
|
|
|
+ height: 31
|
|
|
+ });
|
|
|
+ const feature = new Feature({
|
|
|
+ geometry: new Point([item.longitude, item.latitude])
|
|
|
+ });
|
|
|
+ feature.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: icon
|
|
|
+ })
|
|
|
+ );
|
|
|
+ const vectorLayer = getMapUtils().getVectorLayer();
|
|
|
+ vectorLayer.getSource().addFeature(feature);
|
|
|
}
|
|
|
getList();
|
|
|
};
|
|
|
|
|
|
-const handleRoutes = (item) => {
|
|
|
- const start = [item.longitude, item.latitude];
|
|
|
- const end = [selectData.value.longitude, selectData.value.latitude];
|
|
|
+const handleRoutes = async (item) => {
|
|
|
+ const lnglat = gcoord.transform([item.longitude, item.latitude], gcoord.WGS84, gcoord.GCJ02);
|
|
|
+ const lnglat2 = gcoord.transform([selectData.value.longitude, selectData.value.latitude], gcoord.WGS84, gcoord.GCJ02);
|
|
|
+ const start = [lnglat[0], lnglat[1]];
|
|
|
+ const end = lnglat2;
|
|
|
showAddress.value = true;
|
|
|
routesAddress.value = item.address;
|
|
|
- calculateRoutes(start, end, 0);
|
|
|
-};
|
|
|
-// 计算并展示三条路线
|
|
|
-const calculateRoutes = (start, end, index) => {
|
|
|
- if (index >= 3) {
|
|
|
- return;
|
|
|
- }
|
|
|
- // 不同的策略或参数来生成不同的路线
|
|
|
- const policyMap = [
|
|
|
- AMap.DrivingPolicy.LEAST_TIME, // 最短时间
|
|
|
- AMap.DrivingPolicy.LEAST_DISTANCE, // 最短距离
|
|
|
- AMap.DrivingPolicy.LEAST_FEE // 最少费用
|
|
|
- ];
|
|
|
- driving.setPolicy(policyMap[index]);
|
|
|
+ // 10速度最快 返回结果会躲避拥堵,路程较短,尽量缩短时间,与高德地图的默认策略也就是不进行任何勾选一致
|
|
|
+ // 16费用最低 返回的结果尽量不走高速,并且尽量规划收费较低甚至免费的路径结果,与高德地图的“避免收费&不走高速”策略一致
|
|
|
+ const url = `https://restapi.amap.com/v3/direction/driving?origin=${start}&destination=${end}&key=${amapKey}`;
|
|
|
+ const response = await fetch(url + '&strategy=10');
|
|
|
|
|
|
- driving.search(new AMap.LngLat(start[0], start[1]), new AMap.LngLat(end[0], end[1]), function (status, result) {
|
|
|
- if (status === 'complete' && result.info === 'OK') {
|
|
|
- const route = result.routes[0];
|
|
|
- if (index === 0) {
|
|
|
- routeData.value = [];
|
|
|
- }
|
|
|
- route.date = formatDate(route.time);
|
|
|
- routeData.value.push(route);
|
|
|
+ if (!!response.ok) {
|
|
|
+ const data = await response.json();
|
|
|
+ if (data.route && data.route.paths) {
|
|
|
+ data.route.paths.forEach((item) => {
|
|
|
+ item.duration = formatDate(item.duration);
|
|
|
+ });
|
|
|
+ routeData.value = data.route.paths;
|
|
|
+ } else {
|
|
|
+ routeData.value = [];
|
|
|
}
|
|
|
-
|
|
|
- // 计算下一条路线
|
|
|
- calculateRoutes(start, end, index + 1);
|
|
|
- });
|
|
|
+ }
|
|
|
+ const response2 = await fetch(url + '&strategy=16');
|
|
|
+ if (!!response2.ok) {
|
|
|
+ const data2 = await response2.json();
|
|
|
+ if (data2.route && data2.route.paths) {
|
|
|
+ data2.route.paths.forEach((item) => {
|
|
|
+ item.duration = formatDate(item.duration);
|
|
|
+ });
|
|
|
+ routeData.value = routeData.value.concat(data2.route.paths);
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|
|
|
+
|
|
|
const drawRoute = (route) => {
|
|
|
const path = parseRouteToPath(route);
|
|
|
- if (!!startMarker) {
|
|
|
- map.remove(startMarker);
|
|
|
- startMarker = null;
|
|
|
- }
|
|
|
- if (!!endMarker) {
|
|
|
- map.remove(endMarker);
|
|
|
- endMarker = null;
|
|
|
- }
|
|
|
- if (!!routeLine) {
|
|
|
- routeLine.setMap(null);
|
|
|
- routeLine = null;
|
|
|
- }
|
|
|
- const icon1 = new AMap.Icon({
|
|
|
- size: new AMap.Size(19, 31),
|
|
|
- image: 'https://webapi.amap.com/theme/v1.3/markers/n/start.png'
|
|
|
- });
|
|
|
- const icon2 = new AMap.Icon({
|
|
|
- size: new AMap.Size(19, 31),
|
|
|
- image: 'https://webapi.amap.com/theme/v1.3/markers/n/end.png'
|
|
|
- });
|
|
|
- startMarker = new AMap.Marker({
|
|
|
- position: path[0],
|
|
|
- icon: icon1,
|
|
|
- offset: new AMap.Pixel(-13, -30),
|
|
|
- map: map
|
|
|
- });
|
|
|
+ if (AMapType.includes(props.activeMap)) {
|
|
|
+ if (!!startMarker) {
|
|
|
+ map.remove(startMarker);
|
|
|
+ startMarker = null;
|
|
|
+ }
|
|
|
+ if (!!endMarker) {
|
|
|
+ map.remove(endMarker);
|
|
|
+ endMarker = null;
|
|
|
+ }
|
|
|
+ if (!!routeLine) {
|
|
|
+ routeLine.setMap(null);
|
|
|
+ routeLine = null;
|
|
|
+ }
|
|
|
+ const icon1 = new AMap.Icon({
|
|
|
+ size: new AMap.Size(19, 31),
|
|
|
+ image: startImg
|
|
|
+ });
|
|
|
+ const icon2 = new AMap.Icon({
|
|
|
+ size: new AMap.Size(19, 31),
|
|
|
+ image: endImg
|
|
|
+ });
|
|
|
+ startMarker = new AMap.Marker({
|
|
|
+ position: path[0],
|
|
|
+ icon: icon1,
|
|
|
+ offset: new AMap.Pixel(-13, -30),
|
|
|
+ map: map
|
|
|
+ });
|
|
|
|
|
|
- endMarker = new AMap.Marker({
|
|
|
- position: path[path.length - 1],
|
|
|
- icon: icon2,
|
|
|
- offset: new AMap.Pixel(-13, -30),
|
|
|
- map: map
|
|
|
- });
|
|
|
- routeLine = new AMap.Polyline({
|
|
|
- path: path,
|
|
|
- isOutline: true,
|
|
|
- outlineColor: '#ffeeee',
|
|
|
- borderWeight: 2,
|
|
|
- strokeWeight: 5,
|
|
|
- strokeColor: '#0091ff',
|
|
|
- lineJoin: 'round'
|
|
|
- });
|
|
|
- routeLine.setMap(map);
|
|
|
+ endMarker = new AMap.Marker({
|
|
|
+ position: path[path.length - 1],
|
|
|
+ icon: icon2,
|
|
|
+ offset: new AMap.Pixel(-13, -30),
|
|
|
+ map: map
|
|
|
+ });
|
|
|
+ routeLine = new AMap.Polyline({
|
|
|
+ path: path,
|
|
|
+ isOutline: true,
|
|
|
+ outlineColor: '#ffeeee',
|
|
|
+ borderWeight: 2,
|
|
|
+ strokeWeight: 5,
|
|
|
+ strokeColor: '#0091ff',
|
|
|
+ lineJoin: 'round'
|
|
|
+ });
|
|
|
+ routeLine.setMap(map);
|
|
|
|
|
|
- // 调整视野达到最佳显示区域
|
|
|
- map.setFitView([startMarker, endMarker, routeLine]);
|
|
|
+ // 调整视野达到最佳显示区域
|
|
|
+ map.setFitView([startMarker, endMarker, routeLine]);
|
|
|
+ } else {
|
|
|
+ const vectorLayer = getMapUtils().getVectorLayer();
|
|
|
+ const source = vectorLayer.getSource();
|
|
|
+ if (!!startMarker) {
|
|
|
+ source.removeFeaure(startMarker);
|
|
|
+ startMarker = null;
|
|
|
+ }
|
|
|
+ if (!!endMarker) {
|
|
|
+ source.removeFeaure(endMarker);
|
|
|
+ endMarker = null;
|
|
|
+ }
|
|
|
+ if (!!routeLine) {
|
|
|
+ source.removeFeaure(routeLine);
|
|
|
+ routeLine = null;
|
|
|
+ }
|
|
|
+ startMarker = new Feature({
|
|
|
+ geometry: new Point(path[0])
|
|
|
+ });
|
|
|
+ endMarker = new Feature({
|
|
|
+ geometry: new Point(path[path.length - 1])
|
|
|
+ });
|
|
|
+ startMarker.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: startImg,
|
|
|
+ width: 19,
|
|
|
+ height: 31
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ endMarker.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: endImg,
|
|
|
+ width: 19,
|
|
|
+ height: 31
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ routeLine = new Feature({
|
|
|
+ geometry: new LineString(path)
|
|
|
+ });
|
|
|
+ routeLine.setStyle(
|
|
|
+ new Style({
|
|
|
+ stroke: new Stroke({
|
|
|
+ color: '#0091ff', // 主线条颜色
|
|
|
+ width: 5, // 主线条宽度
|
|
|
+ lineCap: 'round', // 线帽样式(可选)
|
|
|
+ lineJoin: 'round' // 线连接样式
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ source.addFeature(startMarker);
|
|
|
+ source.addFeature(routeLine);
|
|
|
+ source.addFeature(endMarker);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 解析DrivingRoute对象,构造成AMap.Polyline的path参数需要的格式
|
|
@@ -279,11 +369,14 @@ const parseRouteToPath = (route) => {
|
|
|
for (var i = 0, l = route.steps.length; i < l; i++) {
|
|
|
var step = route.steps[i];
|
|
|
|
|
|
- for (var j = 0, n = step.path.length; j < n; j++) {
|
|
|
- path.push(step.path[j]);
|
|
|
- }
|
|
|
+ // 按分号分割字符串,得到一个包含经纬度对的数组
|
|
|
+ const coordinatesPairs = step.polyline.split(';');
|
|
|
+ // 将每个经纬度对进一步分割成经度和纬度,并转换为一个对象
|
|
|
+ path = coordinatesPairs.map((pair) => {
|
|
|
+ const [longitude, latitude] = pair.split(',');
|
|
|
+ return gcoord.transform([longitude, latitude], gcoord.GCJ02, gcoord.WGS84);
|
|
|
+ });
|
|
|
}
|
|
|
-
|
|
|
return path;
|
|
|
};
|
|
|
function formatDate(seconds: number) {
|
|
@@ -305,15 +398,8 @@ function formatDate(seconds: number) {
|
|
|
return [hours, minutes];
|
|
|
}
|
|
|
const getTag = (index) => {
|
|
|
- let tag = '路线' + index;
|
|
|
- if (index === 0) {
|
|
|
- tag = '路线A';
|
|
|
- } else if (index === 1) {
|
|
|
- tag = '路线B';
|
|
|
- } else if (index === 2) {
|
|
|
- tag = '路线C';
|
|
|
- }
|
|
|
- return tag;
|
|
|
+ const arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
|
|
|
+ return '路线' + (arr[index] ? arr[index] : index);
|
|
|
};
|
|
|
// 搜索列表
|
|
|
const getList = () => {
|
|
@@ -332,22 +418,24 @@ const getList = () => {
|
|
|
total.value = res.total;
|
|
|
});
|
|
|
};
|
|
|
-onMounted(() => {
|
|
|
- AMap = getMapUtils().getAMap();
|
|
|
- map = getMapUtils().getMap();
|
|
|
- geocoder = new AMap.Geocoder({
|
|
|
- // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
|
|
|
- city: '010'
|
|
|
- });
|
|
|
+onMounted(async () => {
|
|
|
+ const gcj02Coord = gcoord.transform(props.location, gcoord.WGS84, gcoord.GCJ02);
|
|
|
tempState.longitude = props.location[0];
|
|
|
tempState.latitude = props.location[1];
|
|
|
- geocoder.getAddress(props.location, (status, result) => {
|
|
|
- if (status === 'complete' && result.info === 'OK') {
|
|
|
- tempState.address = result.regeocode.formattedAddress;
|
|
|
- }
|
|
|
- });
|
|
|
- //构造路线导航类
|
|
|
- driving = new AMap.Driving({});
|
|
|
+ map = getMapUtils().getMap();
|
|
|
+ if (AMapType.includes(props.activeMap)) {
|
|
|
+ AMap = getMapUtils().getAMap();
|
|
|
+ //构造路线导航类
|
|
|
+ driving = new AMap.Driving({});
|
|
|
+ }
|
|
|
+ // 调用高德逆向地理编码 API
|
|
|
+ const response = await fetch(`https://restapi.amap.com/v3/geocode/regeo?key=${amapKey}&location=${gcj02Coord[0]},${gcj02Coord[1]}`);
|
|
|
+ const result = await response.json();
|
|
|
+
|
|
|
+ // 解析地址信息
|
|
|
+ if (result.status === '1' && result.regeocode) {
|
|
|
+ tempState.address = result.regeocode.formatted_address;
|
|
|
+ }
|
|
|
});
|
|
|
</script>
|
|
|
|
|
@@ -368,11 +456,11 @@ onMounted(() => {
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
.search-box {
|
|
|
- width: 497px;
|
|
|
- height: 75px;
|
|
|
+ width: 100%;
|
|
|
+ height: 150px;
|
|
|
background: url('@/assets/images/electronicDisasterMapManage/box6.png') no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
- padding: 0 10px;
|
|
|
+ padding: 0 10px 0 30px;
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|