李志伟 2 years ago
parent
commit
5af6b0475b

+ 50
- 0
src/components/GISMap/index.jsx View File

@@ -0,0 +1,50 @@
1
+import { useRef } from "react";
2
+import useMap from './map';
3
+import { useMarker, startAnimation, pauseAnimation, resumeAnimation, stopAnimation } from './marker';
4
+import './style.less';
5
+
6
+export default (props) => {
7
+  const { lineArr } = props
8
+  const container = useRef()
9
+  const { amapRef, map } = useMap(container);
10
+  // var lineArr = [
11
+  //   [116.478935, 39.997761],
12
+  //   [116.478939, 39.997825],
13
+  //   [116.478912, 39.998549],
14
+  //   [116.478912, 39.998549],
15
+  //   [116.478998, 39.998555],
16
+  //   [116.478998, 39.998555],
17
+  //   [116.479282, 39.99856],
18
+  //   [116.479658, 39.998528],
19
+  //   [116.480151, 39.998453],
20
+  //   [116.480784, 39.998302],
21
+  //   [116.480784, 39.998302],
22
+  //   [116.481149, 39.998184],
23
+  //   [116.481573, 39.997997],
24
+  //   [116.481863, 39.997846],
25
+  //   [116.482072, 39.997718],
26
+  //   [116.482362, 39.997718],
27
+  //   [116.483633, 39.998935],
28
+  //   [116.48367, 39.998968],
29
+  //   [116.484648, 39.999861],
30
+  // ];
31
+  useMarker(amapRef, map, lineArr);
32
+
33
+  return (
34
+    <>
35
+      <div ref={container} id="container" style={{ height: '700px', position: 'relative' }} >
36
+        <div className="input-card">
37
+          <h4>轨迹回放控制</h4>
38
+          <div className="input-item">
39
+            <input type="button" className="btn" value="开始动画" id="start" onClick={startAnimation} />
40
+            <input type="button" className="btn" value="暂停动画" id="pause" onClick={pauseAnimation} />
41
+          </div>
42
+          <div className="input-item">
43
+            <input type="button" className="btn" value="继续动画" id="resume" onClick={resumeAnimation} />
44
+            <input type="button" className="btn" value="停止动画" id="stop" onClick={stopAnimation} />
45
+          </div>
46
+        </div>
47
+      </div>
48
+    </>
49
+  )
50
+}

+ 29
- 0
src/components/GISMap/map.js View File

@@ -0,0 +1,29 @@
1
+import React, { useEffect, useRef, useState } from 'react';
2
+import loader from '@/components/AMap/loader';
3
+
4
+const plugins = ['AMap.MoveAnimation'];
5
+export default (containerRef) => {
6
+  const amapRef = useRef();
7
+  const [map, setMap] = useState();
8
+
9
+  useEffect(() => {
10
+    loader(plugins)
11
+      .then((AMap) => {
12
+        amapRef.current = AMap;
13
+
14
+        const mapInst = new AMap.Map(containerRef.current, {
15
+          zoom: 17,
16
+          resizeEnable: true,
17
+          center: [112.093131, 32.692095],
18
+        });
19
+
20
+        //
21
+        setMap(mapInst);
22
+      })
23
+      .catch((err) => {
24
+        console.log(err.message);
25
+      });
26
+  }, [containerRef]);
27
+
28
+  return { amapRef, map };
29
+};

+ 73
- 0
src/components/GISMap/marker.js View File

@@ -0,0 +1,73 @@
1
+import React, { useEffect, useMemo, useRef } from 'react';
2
+
3
+let marker, lineArr;
4
+export function useMarker(amapRef, map, lujing) {
5
+  useMemo(() => {
6
+    if (!amapRef.current) return;
7
+    marker = new amapRef.current.Marker({
8
+      icon: 'https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png',
9
+      offset: new amapRef.current.Pixel(0, 0),
10
+    });
11
+  }, [map]);
12
+
13
+  useEffect(() => {
14
+    if (!amapRef.current || !marker || !lujing || lujing.length == 0) {
15
+      return;
16
+    }
17
+    lineArr = lujing;
18
+    //https://lbs.amap.com/api/jsapi-v2/documentation#marker
19
+    // 动态添加地图和marker的定位
20
+    console.log(marker);
21
+    marker.setPosition(lineArr[0]);
22
+    marker.setMap(map);
23
+    console.log(marker);
24
+    var polyline = new amapRef.current.Polyline({
25
+      map: map,
26
+      path: lineArr,
27
+      showDir: true,
28
+      strokeColor: '#28F', //线颜色
29
+      // strokeOpacity: 1,     //线透明度
30
+      strokeWeight: 6, //线宽
31
+      // strokeStyle: "solid"  //线样式
32
+    });
33
+
34
+    var passedPolyline = new amapRef.current.Polyline({
35
+      map: map,
36
+      strokeColor: '#AF5', //线颜色
37
+      strokeWeight: 6, //线宽
38
+    });
39
+    //给marker添加监控
40
+    marker.on('moving', function (e) {
41
+      passedPolyline.setPath(e.passedPath);
42
+      //marker运动时将marker置位地图中心
43
+      map.setCenter(e.target.getPosition(), true);
44
+    });
45
+    //地图跟随marker移动
46
+    map.setFitView();
47
+  }, [map, amapRef, lujing]);
48
+}
49
+export function startAnimation() {
50
+  if (marker) {
51
+    marker.moveAlong(lineArr, {
52
+      // 每一段的时长
53
+      duration: 500, //可根据实际采集时间间隔设置
54
+      // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
55
+      autoRotation: true,
56
+    });
57
+  }
58
+}
59
+export function pauseAnimation() {
60
+  if (marker) {
61
+    marker.pauseMove();
62
+  }
63
+}
64
+export function resumeAnimation() {
65
+  if (marker) {
66
+    marker.resumeMove();
67
+  }
68
+}
69
+export function stopAnimation() {
70
+  if (marker) {
71
+    marker.stopMove();
72
+  }
73
+}

+ 92
- 0
src/components/GISMap/style.less View File

@@ -0,0 +1,92 @@
1
+html {
2
+  font-size: 12px;
3
+}
4
+
5
+.input-card {
6
+  display: flex;
7
+  flex-direction: column;
8
+  min-width: 0;
9
+  word-wrap: break-word;
10
+  background-color: #fff;
11
+  background-clip: border-box;
12
+  border-radius: .25rem;
13
+  width: 22rem;
14
+  border-width: 0;
15
+  border-radius: 0.4rem;
16
+  box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
17
+  position: absolute;
18
+  z-index: 9;
19
+  bottom: 1rem;
20
+  right: 1rem;
21
+  -ms-flex: 1 1 auto;
22
+  flex: 1 1 auto;
23
+  padding: 0.75rem 1.25rem;
24
+}
25
+
26
+h4 {
27
+  font-family: inherit;
28
+  line-height: 1.8;
29
+  font-weight: 300;
30
+  color: inherit;
31
+  font-size: 1.1rem;
32
+  margin-top: 0;
33
+  margin-bottom: .5rem
34
+}
35
+
36
+.input-item {
37
+  position: relative;
38
+  display: -ms-flexbox;
39
+  display: flex;
40
+  -ms-flex-wrap: wrap;
41
+  flex-wrap: wrap;
42
+  -ms-flex-align: center;
43
+  align-items: center;
44
+  width: 100%;
45
+  height: 3rem;
46
+}
47
+
48
+.input-item:last-child {
49
+  margin-bottom: 0;
50
+}
51
+
52
+.btn {
53
+  display: inline-block;
54
+  font-weight: 400;
55
+  font-size: 1rem;
56
+  margin-right: 1.2rem;
57
+  width: 9rem;
58
+  text-align: center;
59
+  white-space: nowrap;
60
+  vertical-align: middle;
61
+  -webkit-user-select: none;
62
+  -moz-user-select: none;
63
+  -ms-user-select: none;
64
+  user-select: none;
65
+  border: 1px solid transparent;
66
+  transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
67
+  background-color: transparent;
68
+  background-image: none;
69
+  color: #25A5F7;
70
+  border-color: #25A5F7;
71
+  padding: .25rem .5rem;
72
+  line-height: 1.5;
73
+  border-radius: 1rem;
74
+  -webkit-appearance: button;
75
+  cursor:pointer;
76
+}
77
+
78
+.btn:hover {
79
+  color: #fff;
80
+  background-color: #25A5F7;
81
+  border-color: #25A5F7;
82
+  text-decoration: none
83
+}
84
+
85
+.btn:focus {
86
+  outline: 0;
87
+  box-shadow: none;
88
+}
89
+
90
+.input-card .btn:last-child{
91
+  margin-right: 0;
92
+}

+ 23
- 5
src/pages/Machinery/GIS/detail.jsx View File

@@ -1,9 +1,11 @@
1 1
 import { PageHeaderWrapper } from '@ant-design/pro-layout';
2 2
 import { Card, Button, Descriptions } from 'antd';
3 3
 import { useEffect, useState } from 'react';
4
-import { getJobDetail } from '@/services/job'
4
+import { getJobDetail, getJobGISDetail } from '@/services/job'
5 5
 import moment from 'moment';
6 6
 import { history } from 'umi';
7
+import getCoordinate from '@/utils/mapTogcj02'
8
+import GISMap from '@/components/GISMap';
7 9
 
8 10
 const goBack = () => {
9 11
   history.goBack();
@@ -15,11 +17,23 @@ export default (props) => {
15 17
   const { location } = props;
16 18
   const { id } = location.query;
17 19
   const [workInfo, setWorkInfo] = useState()
18
-
20
+  const [nlocationList, setNewLocationList] = useState()
19 21
   useEffect(() => {
20 22
     if (id) {
21 23
       getJobDetail(id).then((res) => {
22 24
         setWorkInfo(res)
25
+        getJobGISDetail({ jobId: id }).then((gisRes => {
26
+          let list, newlocation
27
+          list = gisRes.map(item => {
28
+            newlocation = getCoordinate(item.lng, item.lat);
29
+            return [newlocation.longitude, newlocation.latitude]
30
+          })
31
+          setNewLocationList(list)
32
+        })).catch(err => {
33
+          console.log(err.message);
34
+        })
35
+      }).catch(err => {
36
+        console.log(err.message);
23 37
       })
24 38
     }
25 39
   }, [id])
@@ -27,16 +41,20 @@ export default (props) => {
27 41
     <PageHeaderWrapper extra={[<Button key={id} type="default" onClick={() => goBack()}>
28 42
       返回
29 43
     </Button>]}>
30
-      <Card style={{ minHeight: '700px' }}>
31
-        <Descriptions style={{ margin: '0 32px' }}>
44
+      <Card title='作业详情'>
45
+        <Descriptions labelStyle={{ justifyContent: 'flex-end', minWidth: '5em' }} >
32 46
           <Descriptions.Item label="订单号">{workInfo?.orderNo}</Descriptions.Item>
33 47
           <Descriptions.Item label="合作社">{workInfo?.orgName}</Descriptions.Item>
34 48
           <Descriptions.Item label="农机">{workInfo?.machineryName}</Descriptions.Item>
35 49
           <Descriptions.Item label="农机手">{workInfo?.workerName}</Descriptions.Item>
36
-          <Descriptions.Item label="作业面积">{workInfo?.area}</Descriptions.Item>
50
+          <Descriptions.Item label="作业面积">{workInfo?.area}</Descriptions.Item>
37 51
           <Descriptions.Item label="作业时间">{formatterTime(workInfo?.startDate)}~{formatterTime(workInfo?.endDate)}</Descriptions.Item>
52
+          <Descriptions.Item label="作业地址">{workInfo?.address}</Descriptions.Item>
38 53
         </Descriptions>
39 54
       </Card>
55
+      <Card style={{ minHeight: '700px', marginTop: '32px' }}>
56
+        <GISMap lineArr={nlocationList} />
57
+      </Card>
40 58
     </PageHeaderWrapper>
41 59
   );
42 60
 };

+ 0
- 1
src/pages/Machinery/GIS/index.jsx View File

@@ -23,7 +23,6 @@ export default (props) => {
23 23
   }
24 24
   const onCancel = () => {
25 25
     setEditModal(false)
26
-    console.log(666);
27 26
   }
28 27
   useEffect(() => {
29 28
     getCooperativeList({ pageSize: 999 }).then((res) => {

+ 7
- 0
src/services/job.js View File

@@ -13,3 +13,10 @@ export const getJobList = (params) => request('/work-job', { params });
13 13
  * @returns
14 14
  */
15 15
 export const getJobDetail = (id) => request(`/work-job/${id}`);
16
+
17
+/**
18
+ * 查询作业GIS
19
+ * @param {*} params
20
+ * @returns
21
+ */
22
+export const getJobGISDetail = (params) => request(`/machinery-gps`, { params });

+ 66
- 0
src/utils/mapTogcj02.js View File

@@ -0,0 +1,66 @@
1
+//纬度转换
2
+function transformLatitude(x, y) {
3
+  let num = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
4
+  num += ((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0) / 3.0;
5
+  num += ((20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin((y / 3.0) * Math.PI)) * 2.0) / 3.0;
6
+  num +=
7
+    ((160.0 * Math.sin((y / 12.0) * Math.PI) + 320 * Math.sin((y * Math.PI) / 30.0)) * 2.0) / 3.0;
8
+  return num;
9
+}
10
+//经度转换
11
+function transformLongitude(x, y) {
12
+  let num = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
13
+  num += ((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0) / 3.0;
14
+  num += ((20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin((x / 3.0) * Math.PI)) * 2.0) / 3.0;
15
+  num +=
16
+    ((150.0 * Math.sin((x / 12.0) * Math.PI) + 300.0 * Math.sin((x / 30.0) * Math.PI)) * 2.0) / 3.0;
17
+  return num;
18
+}
19
+// 坐标转换
20
+function calculation(longitude, latitude) {
21
+  let a = 6378245.0; // 卫星椭球坐标投影到平面地图坐标系的投影因子。
22
+  let ee = 0.00669342162296594323; // 椭球的偏心率。
23
+  let lat = transformLatitude(longitude - 105.0, latitude - 35.0);
24
+  let lng = transformLongitude(longitude - 105.0, latitude - 35.0);
25
+  let radLat = (latitude / 180.0) * Math.PI;
26
+  let magic = Math.sin(radLat);
27
+  magic = 1 - ee * magic * magic;
28
+  let sqrtMagic = Math.sqrt(magic);
29
+  lat = (lat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * Math.PI);
30
+  lng = (lng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * Math.PI);
31
+  return {
32
+    longitude: lng,
33
+    latitude: lat,
34
+  };
35
+}
36
+// 判断是否为国外坐标
37
+function isOutOfChina(longitude, latitude) {
38
+  if (longitude < 72.004 || longitude > 137.8347) {
39
+    return true;
40
+  }
41
+  if (latitude < 0.8293 || latitude > 55.8271) {
42
+    return true;
43
+  }
44
+  return false;
45
+}
46
+// GPS坐标 转 高德坐标
47
+function getCoordinate(long, lat) {
48
+  let longitude = Number(long);
49
+  let latitude = Number(lat);
50
+  if (isOutOfChina(longitude, latitude)) {
51
+    //国外
52
+    return {
53
+      longitude: longitude,
54
+      latitude: latitude,
55
+    };
56
+  } else {
57
+    //国内
58
+    let obj = calculation(longitude, latitude);
59
+    return {
60
+      longitude: longitude + obj.longitude,
61
+      latitude: latitude + obj.latitude,
62
+    };
63
+  }
64
+}
65
+
66
+export default getCoordinate;