Yansen 2 years ago
parent
commit
25c364e781

+ 6
- 0
src/global.less View File

@@ -88,3 +88,9 @@ ol {
88 88
   background: transparent;
89 89
   border: none;
90 90
 }
91
+
92
+.amap-icon img,
93
+.amap-marker-content img {
94
+  width: 25px;
95
+  height: 34px;
96
+}

+ 42
- 0
src/pages/MonitoringScreen2/components/Banner.jsx View File

@@ -0,0 +1,42 @@
1
+import React from 'react';
2
+import StatisCard from '@/components/ScreenBox/StatisCard';
3
+import { getBasic } from '@/services/monitoringScreen';
4
+
5
+export default (props) => {
6
+  const [basic, setBasic] = React.useState();
7
+
8
+  React.useEffect(() => {
9
+    //顶部基本数据
10
+    getBasic()
11
+      .then((res) => {
12
+        var data = {};
13
+        for (let i = 0; i < res.length; i++) {
14
+          const element = res[i];
15
+          data[element.name] = element.value;
16
+        }
17
+        setBasic(data);
18
+      })
19
+      .catch((err) => {
20
+        console.log(err.message);
21
+      });
22
+  }, []);
23
+
24
+  return (
25
+    <>
26
+      <StatisCard
27
+        color="#23E8AE"
28
+        icon="icon1"
29
+        value={basic?.totalMachineryNum}
30
+        title="农机总数(台)"
31
+      />
32
+      <StatisCard
33
+        color="#0BDAFF"
34
+        icon="icon2"
35
+        value={basic?.totalMachineryUsed}
36
+        title="农机使用数(台)"
37
+      />
38
+      <StatisCard color="#F5CC5C" icon="icon3" value={basic?.totalOrderNum} title="总预约数" />
39
+      <StatisCard color="#C579FF" icon="icon4" value={basic?.totalServiceNum} title="总服务数" />
40
+    </>
41
+  );
42
+};

+ 0
- 15
src/pages/MonitoringScreen2/components/BasicChart.jsx View File

@@ -1,15 +0,0 @@
1
-import React from 'react';
2
-import SquareBox from '@/components/ScreenBox/SquareBox';
3
-import TitleBox from '@/components/ScreenBox/TitleBox';
4
-import ECharts from '@/components/ECharts';
5
-
6
-export default (props) => {
7
-  return (
8
-    <div style={{ height: '100%' }}>
9
-      <TitleBox value={props.title} />
10
-      <SquareBox style={{ height: 'calc(100% - 48px)', minHeight: '100px' }}>
11
-        <ECharts option={props.option} />
12
-      </SquareBox>
13
-    </div>
14
-  );
15
-};

+ 0
- 5
src/pages/MonitoringScreen2/components/ColorFont.jsx View File

@@ -1,5 +0,0 @@
1
-import React from 'react';
2
-
3
-export default (props) => {
4
-  return <font color={props.color}>{props.children}</font>;
5
-};

+ 19
- 0
src/pages/MonitoringScreen2/components/DeviceType.jsx View File

@@ -0,0 +1,19 @@
1
+import React from 'react';
2
+import RadioGroup from '@/components/ScreenBox/Radio/RadioGroup';
3
+
4
+export default (props) => {
5
+  const list = [
6
+    { id: '', name: '全部' },
7
+    { id: 'shensong', name: '深松' },
8
+    { id: 'feifang', name: '飞防' },
9
+  ];
10
+
11
+  const [value, setValue] = React.useState('');
12
+
13
+  const onChange = (val) => {
14
+    setValue(val);
15
+    props.onChange(val);
16
+  };
17
+
18
+  return <RadioGroup value={value} list={list} onChange={onChange} />;
19
+};

+ 0
- 17
src/pages/MonitoringScreen2/components/List/Item.jsx View File

@@ -1,17 +0,0 @@
1
-import React from 'react';
2
-import classNames from 'classnames';
3
-import Styles from './style.less';
4
-
5
-export default (props) => {
6
-  const classList = classNames(Styles['screen-item'], {
7
-    [Styles['yellow-item']]: props.color !== 'green',
8
-    [Styles['green-item']]: props.color === 'green',
9
-  });
10
-
11
-  return (
12
-    <div className={classList}>
13
-      <div />
14
-      <div>{props.children}</div>
15
-    </div>
16
-  );
17
-};

+ 0
- 66
src/pages/MonitoringScreen2/components/List/index.jsx View File

@@ -1,66 +0,0 @@
1
-import React, { useCallback, useEffect, useRef } from 'react';
2
-import { Swiper, SwiperSlide } from 'swiper/react';
3
-import { Autoplay } from 'swiper';
4
-import 'swiper/css';
5
-import classNames from 'classnames';
6
-import Item from './Item';
7
-import Styles from './style.less';
8
-
9
-export default (props) => {
10
-  const { title, color, children } = props;
11
-  const swiperRef = useRef();
12
-  const classList = classNames(Styles['list-title'], {
13
-    [Styles['yellow-title']]: color !== 'green',
14
-    [Styles['green-title']]: color === 'green',
15
-  });
16
-  const initAutoPlay = useCallback(
17
-    (swiper) => {
18
-      if (!children?.length || children?.length <= 3) {
19
-        swiper.autoplay.stop();
20
-      } else {
21
-        swiper.autoplay.start();
22
-      }
23
-    },
24
-    [children?.length],
25
-  );
26
-
27
-  useEffect(() => {
28
-    if (swiperRef.current) {
29
-      initAutoPlay(swiperRef.current);
30
-    }
31
-  }, [children?.length, initAutoPlay]);
32
-
33
-  const enable = children?.length && children?.length > 3;
34
-
35
-  return (
36
-    <div className={Styles['screen-list']}>
37
-      <div className={classList}>
38
-        <div>{title}</div>
39
-      </div>
40
-      <Swiper
41
-        height={48}
42
-        onSwiper={(swiper) => {
43
-          swiperRef.current = swiper;
44
-          initAutoPlay(swiper);
45
-        }}
46
-        className={Styles['list-body']}
47
-        //因为loop只能在组件初始化时改变所以加一个不让它创建初始化的属性就可以了
48
-        init={false}
49
-        autoplay={{
50
-          delay: 2500,
51
-          disableOnInteraction: false,
52
-        }}
53
-        loop={enable}
54
-        loopAdditionalSlides={2}
55
-        modules={[Autoplay]}
56
-        direction="vertical"
57
-      >
58
-        {React.Children.map(children, (child) => (
59
-          <SwiperSlide>
60
-            <Item color={color}>{child}</Item>
61
-          </SwiperSlide>
62
-        ))}
63
-      </Swiper>
64
-    </div>
65
-  );
66
-};

+ 0
- 97
src/pages/MonitoringScreen2/components/List/style.less View File

@@ -1,97 +0,0 @@
1
-.screen-list {
2
-  .list-title {
3
-    position: relative;
4
-    padding: 0 20px;
5
-
6
-    & > div {
7
-      height: 28px;
8
-      color: #ffffff;
9
-      font-weight: bold;
10
-      font-size: 18px;
11
-      line-height: 28px;
12
-
13
-      background: linear-gradient(0deg, #ffcf84 0%, #fb9900 93.84765625%);
14
-      background-clip: text;
15
-      -webkit-text-fill-color: transparent;
16
-    }
17
-
18
-    &::before {
19
-      position: absolute;
20
-      top: 50%;
21
-      left: 0;
22
-      width: 10px;
23
-      height: 10px;
24
-      background: linear-gradient(0deg, #ffcf84, #fb9900);
25
-      transform: translateY(-50%);
26
-      content: ' ';
27
-    }
28
-  }
29
-
30
-  .yellow-title {
31
-    &::before {
32
-      background: linear-gradient(0deg, #ffcf84, #fb9900);
33
-    }
34
-  }
35
-
36
-  .green-title {
37
-    & > div {
38
-      background: linear-gradient(0deg, #9fffc5 0%, #44f68b 93.84765625%);
39
-      background-clip: text;
40
-      -webkit-text-fill-color: transparent;
41
-    }
42
-
43
-    &::before {
44
-      background: linear-gradient(0deg, #9fffc5, #44f68b);
45
-    }
46
-  }
47
-
48
-  .screen-item {
49
-    position: relative;
50
-    padding: 0 20px;
51
-
52
-    & > div {
53
-      height: 48px;
54
-      color: #fff;
55
-      font-size: 16px;
56
-      line-height: 48px;
57
-
58
-      &:first-child {
59
-        position: absolute;
60
-        top: 0;
61
-        left: 0;
62
-        width: 100%;
63
-        height: 100%;
64
-        background: linear-gradient(0deg, rgba(61, 129, 240, 0.24), rgba(61, 129, 240, 0));
65
-        opacity: 0.5;
66
-      }
67
-    }
68
-
69
-    &::before {
70
-      position: absolute;
71
-      top: 50%;
72
-      left: 0;
73
-      width: 4px;
74
-      height: 8px;
75
-      background: #fb9900;
76
-      transform: translateY(-40%);
77
-      content: ' ';
78
-    }
79
-  }
80
-
81
-  .yellow-item {
82
-    &::before {
83
-      background: #fb9900;
84
-    }
85
-  }
86
-
87
-  .green-item {
88
-    &::before {
89
-      background: #25e1aa;
90
-    }
91
-  }
92
-
93
-  .list-body {
94
-    width: 100%;
95
-    height: 144px;
96
-  }
97
-}

+ 42
- 0
src/pages/MonitoringScreen2/components/MachineryInfo.jsx View File

@@ -0,0 +1,42 @@
1
+import React from 'react';
2
+import { Col, Row } from 'antd';
3
+
4
+export default React.forwardRef((props, ref) => {
5
+  const { data = {} } = props;
6
+  console.log(data);
7
+
8
+  return (
9
+    <div
10
+      ref={ref}
11
+      style={{
12
+        background: 'rgba(0,0,0,0.8)',
13
+        color: '#fff',
14
+        padding: '1em',
15
+        borderRadius: '4px',
16
+        width: '320px',
17
+      }}
18
+    >
19
+      <div style={{ textAlign: 'right' }}>X</div>
20
+      <Row gutter={16}>
21
+        <Col span={8}>农机名称</Col>
22
+        <Col span={16}>{data.machineryName || ''}</Col>
23
+      </Row>
24
+      <Row gutter={16}>
25
+        <Col span={8}>设备编号</Col>
26
+        <Col span={16}>{data.deviceNo || ''}</Col>
27
+      </Row>
28
+      <Row gutter={16}>
29
+        <Col span={8}>设备类型</Col>
30
+        <Col span={16}>{data.deviceType === 'shensong' ? '深松' : '飞防'}</Col>
31
+      </Row>
32
+      <Row gutter={16}>
33
+        <Col span={8}>当前状态</Col>
34
+        <Col span={16}>{data.onlineStatus === 1 ? '在线' : '下线'}</Col>
35
+      </Row>
36
+      <Row gutter={16}>
37
+        <Col span={8}>位置信息</Col>
38
+        <Col span={16}>{data.loc || ''}</Col>
39
+      </Row>
40
+    </div>
41
+  );
42
+});

+ 0
- 94
src/pages/MonitoringScreen2/components/MachineryStatus.jsx View File

@@ -1,94 +0,0 @@
1
-import React, { useEffect, useMemo, useRef } from 'react';
2
-import * as echarts from 'echarts/core';
3
-import deepCopy from '@/utils/deepCopy';
4
-import { hex2Rgb } from '@/utils/color';
5
-
6
-import { colorArr } from '@/components/ScreenBox/utils';
7
-import BasicChart from './BasicChart';
8
-
9
-const colorList = colorArr.map((x) => {
10
-  const rgb = hex2Rgb(x);
11
-  return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
12
-    {
13
-      offset: 0,
14
-      color: x, // 0% 处的颜色
15
-    },
16
-    {
17
-      offset: 0.2,
18
-      color: x, // 20% 处的颜色
19
-    },
20
-    {
21
-      offset: 1,
22
-      color: `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, 0)`, // 100% 处的颜色
23
-    },
24
-  ]);
25
-});
26
-
27
-const defaultOpt = {
28
-  tooltip: {
29
-    extraCssText: 'width:160px;height:40px;',
30
-  },
31
-  grid: {
32
-    top: 40,
33
-    right: 20,
34
-    bottom: 20,
35
-    left: 20,
36
-    containLabel: true,
37
-  },
38
-  xAxis: {
39
-    type: 'category',
40
-    splitLine: {
41
-      show: false,
42
-    },
43
-    axisTick: {
44
-      show: false,
45
-    },
46
-    axisLabel: {
47
-      color: '#fff',
48
-    },
49
-  },
50
-  yAxis: {
51
-    type: 'value',
52
-    splitLine: {
53
-      lineStyle: {
54
-        color: ['rgba(255, 255, 255, 0.1)'],
55
-        type: 'dashed',
56
-      },
57
-    },
58
-    axisTick: {
59
-      show: false,
60
-    },
61
-    axisLabel: {
62
-      color: '#fff',
63
-    },
64
-  },
65
-  series: [
66
-    {
67
-      type: 'bar',
68
-      barMaxWidth: 18,
69
-      itemStyle: {
70
-        borderRadius: 10,
71
-      },
72
-      label: {
73
-        show: true,
74
-        color: '#fff',
75
-        textBorderWidth: 0,
76
-        position: 'top',
77
-        // align: 'right',
78
-      },
79
-    },
80
-  ],
81
-};
82
-
83
-export default (props) => {
84
-  const option = useMemo(() => deepCopy(defaultOpt), []);
85
-  option.xAxis.data = props.source.map((x) => x.name);
86
-  option.series[0].data = props.source.map((x, i) => ({
87
-    value: x.value,
88
-    itemStyle: {
89
-      color: colorList[i % 6],
90
-    },
91
-  }));
92
-
93
-  return <BasicChart title="农机状态统计" option={option} />;
94
-};

+ 0
- 105
src/pages/MonitoringScreen2/components/MachineryType.jsx View File

@@ -1,105 +0,0 @@
1
-import React, { useEffect, useMemo, useState } from 'react';
2
-import * as echarts from 'echarts/core';
3
-import deepCopy from '@/utils/deepCopy';
4
-import { hex2Rgb } from '@/utils/color';
5
-import { colorArr } from '@/components/ScreenBox/utils';
6
-import BasicChart from './BasicChart';
7
-
8
-const colorList = colorArr.map((x) => {
9
-  const rgb = hex2Rgb(x);
10
-  return new echarts.graphic.LinearGradient(0, 1, 1, 1, [
11
-    {
12
-      offset: 0,
13
-      color: `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, 0)`, // 0% 处的颜色
14
-    },
15
-    {
16
-      offset: 0.8,
17
-      color: x, // 80% 处的颜色
18
-    },
19
-    {
20
-      offset: 1,
21
-      color: x, // 100% 处的颜色
22
-    },
23
-  ]);
24
-});
25
-
26
-const defaultOpt = {
27
-  tooltip: {
28
-    extraCssText: 'width:160px;height:40px;',
29
-  },
30
-  legend: {},
31
-  grid: {
32
-    top: 20,
33
-    right: 40,
34
-    bottom: 20,
35
-    left: 10,
36
-    containLabel: true,
37
-  },
38
-  xAxis: {
39
-    type: 'value',
40
-    splitLine: {
41
-      show: false,
42
-    },
43
-    axisTick: {
44
-      show: false,
45
-    },
46
-    axisLabel: {
47
-      show: false,
48
-    },
49
-  },
50
-  yAxis: {
51
-    type: 'category',
52
-    axisLine: {
53
-      show: false,
54
-    },
55
-    axisTick: {
56
-      show: false,
57
-    },
58
-    axisLabel: {
59
-      color: '#fff',
60
-      width: 40,
61
-      overflow: 'truncate',
62
-    },
63
-  },
64
-  series: [
65
-    {
66
-      type: 'bar',
67
-      barMaxWidth: 16,
68
-      itemStyle: {
69
-        borderRadius: 10,
70
-      },
71
-      encode: {
72
-        x: 'value',
73
-        y: 'key',
74
-      },
75
-      label: {
76
-        show: true,
77
-        color: '#fff',
78
-        textBorderWidth: 0,
79
-        position: 'right',
80
-        // align: 'right',
81
-      },
82
-      // showBackground: true,
83
-    },
84
-  ],
85
-};
86
-
87
-export default (props) => {
88
-  const option2 = useMemo(() => deepCopy(defaultOpt), []);
89
-
90
-  const [option, setOption] = useState(option2);
91
-
92
-  useEffect(() => {
93
-    var option3 = { ...option2 };
94
-    option3.yAxis.data = props.source.map((x) => x.name);
95
-    option3.series[0].data = props.source.map((x, i) => ({
96
-      value: x.value,
97
-      itemStyle: {
98
-        color: colorList[i % 3],
99
-      },
100
-    }));
101
-    setOption(option3);
102
-  }, [props.source]);
103
-
104
-  return <BasicChart title="农机类型统计" option={option} />;
105
-};

+ 0
- 52
src/pages/MonitoringScreen2/components/WorkArea.jsx View File

@@ -1,52 +0,0 @@
1
-import React, { useEffect, useMemo, useState } from 'react';
2
-import deepCopy from '@/utils/deepCopy';
3
-import { colorArr } from '@/components/ScreenBox/utils';
4
-import BasicChart from './BasicChart';
5
-
6
-const defaultOpt = {
7
-  // tooltip: {
8
-  //   trigger: 'item',
9
-  //   formatter: '{b} : {c} ({d}%)',
10
-  // },
11
-  color: colorArr,
12
-  legend: {
13
-    orient: 'vertical',
14
-    left: 'right',
15
-    bottom: '5%',
16
-    textStyle: { color: '#fff' },
17
-  },
18
-  toolbox: {},
19
-  series: [
20
-    {
21
-      type: 'pie',
22
-      radius: ['40%', '55%'],
23
-      center: ['40%', '50%'],
24
-      selectedMode: 'single',
25
-      avoidLabelOverlap: false,
26
-      label: {
27
-        color: '#fff',
28
-        formatter: '{b} \n{d}%',
29
-      },
30
-      // labelLine: {
31
-      //   length: 10,
32
-      //   length2: 36,
33
-      // },
34
-    },
35
-  ],
36
-};
37
-
38
-export default (props) => {
39
-  const option2 = useMemo(() => deepCopy(defaultOpt), []);
40
-
41
-  const [option, setOption] = useState(option2);
42
-
43
-  useEffect(() => {
44
-    var option3 = { ...option2 };
45
-    option3.series[0].data = props.source;
46
-    // 设置第一个是选中状态
47
-    (option3.series[0].data[0] || {}).selected = true;
48
-    setOption(option3);
49
-  }, [props.source]);
50
-
51
-  return <BasicChart title="农机作业量面积统计" option={option} />;
52
-};

+ 0
- 59
src/pages/MonitoringScreen2/components/WorkData.jsx View File

@@ -1,59 +0,0 @@
1
-import React, { useEffect, useMemo, useState } from 'react';
2
-import deepCopy from '@/utils/deepCopy';
3
-import { colorArr } from '@/components/ScreenBox/utils';
4
-import BasicChart from './BasicChart';
5
-
6
-const defaultOpt = {
7
-  // tooltip: {
8
-  //   trigger: 'item',
9
-  //   formatter: '{b} : {c} ({d}%)',
10
-  // },
11
-  color: colorArr,
12
-  legend: {
13
-    orient: 'vertical',
14
-    left: 'left',
15
-    top: '5%',
16
-    textStyle: { color: '#fff' },
17
-  },
18
-  series: [
19
-    {
20
-      type: 'pie',
21
-      radius: ['45%', '65%'],
22
-      itemStyle: {
23
-        borderRadius: 4,
24
-        borderColor: '#041B38',
25
-        borderWidth: 2,
26
-      },
27
-      label: {
28
-        show: false,
29
-        position: 'center',
30
-        formatter: '{b}\n{d}%',
31
-      },
32
-      emphasis: {
33
-        label: {
34
-          color: '#25E1AA',
35
-          show: true,
36
-          fontSize: '18',
37
-        },
38
-      },
39
-      labelLine: {
40
-        show: false,
41
-      },
42
-    },
43
-  ],
44
-};
45
-
46
-export default (props) => {
47
-  const option2 = useMemo(() => deepCopy(defaultOpt), []);
48
-
49
-  const [option, setOption] = useState(option2);
50
-
51
-  useEffect(() => {
52
-    var option3 = { ...option2 };
53
-    option3.series[0].data = props.source;
54
-    // 设置第一个是选中状态
55
-    setOption(option3);
56
-  }, [props.source]);
57
-
58
-  return <BasicChart title="农机作业数统计" option={option} />;
59
-};

+ 38
- 0
src/pages/MonitoringScreen2/components/machinery.js View File

@@ -0,0 +1,38 @@
1
+import React from 'react';
2
+import { transform } from './map/coordinate';
3
+
4
+export default function makeMachinery(machines, markers, map, AMap, onClick) {
5
+  if (!map) return;
6
+  if (!machines || !machines.length) return;
7
+
8
+  // 清除原记录
9
+  if (markers.length > 0) {
10
+    for (let i in markers) {
11
+      const marker = markers[i];
12
+      marker.setMap(null);
13
+      delete markers[i];
14
+    }
15
+  }
16
+
17
+  for (let item of machines) {
18
+    if (!item.location) continue;
19
+    if (item.location.indexOf('0.0') > -1) continue;
20
+
21
+    const position = transform(item.location);
22
+
23
+    const marker = new AMap.Marker({
24
+      map,
25
+      position,
26
+      icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
27
+      offset: new AMap.Pixel(-13, -30),
28
+    });
29
+
30
+    marker.on('click', () => onClick(item, position));
31
+    markers.push(marker);
32
+  }
33
+
34
+  // 第一个参数为空,表明用图上所有覆盖物 setFitview
35
+  // 第二个参数为false, 非立即执行
36
+  // 第三个参数设置上左下右的空白
37
+  map.setFitView(null, false, [150, 60, 100, 60]);
38
+}

+ 54
- 0
src/pages/MonitoringScreen2/components/map/coordinate.js View File

@@ -0,0 +1,54 @@
1
+
2
+/**  
3
+ * 单点坐标纠偏
4
+ */
5
+const pi = 3.14159265358979324;
6
+const a = 6378245.0;
7
+const ee = 0.00669342162296594323;
8
+const x_pi = 3.14159265358979324 * 3000.0 / 180.0;
9
+
10
+function outOfChina(lat, lon) {
11
+  if(lon < 72.004 || lon > 137.8347)
12
+      return true;
13
+  if(lat < 0.8293 || lat > 55.8271)
14
+      return true;
15
+  return false;
16
+};
17
+
18
+function transformLat(x, y) {
19
+  let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
20
+  ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
21
+  ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
22
+  ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
23
+  return ret;
24
+};
25
+
26
+function transformLon(x, y) {
27
+  let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
28
+  ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
29
+  ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
30
+  ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
31
+  return ret;
32
+};
33
+
34
+// wgs84 转 gcj02
35
+export function transform (location) {
36
+  const [wgLon, wgLat] = location.split(',').map(x => x - 0);
37
+  const latlng = [];
38
+  if(outOfChina(wgLat, wgLon)) {
39
+    latlng[0] = wgLon;
40
+    latlng[1] = wgLat;
41
+    return latlng;
42
+  }
43
+  let dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
44
+  let dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
45
+  const radLat = wgLat / 180.0 * pi;
46
+  let magic = Math.sin(radLat);
47
+  magic = 1 - ee * magic * magic;
48
+  const sqrtMagic = Math.sqrt(magic);
49
+  dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
50
+  dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
51
+  latlng[0] = wgLon + dLon;
52
+  latlng[1] = wgLat + dLat;
53
+  return latlng;
54
+};

+ 1
- 1
src/pages/MonitoringScreen2/components/map/index.jsx View File

@@ -5,7 +5,7 @@ import Map from './map';
5 5
 export default (props) => {
6 6
   return (
7 7
     <div className={Styles['geo-map-container']}>
8
-      <Map style={{ height: '100%' }} />
8
+      <Map style={{ height: '100%' }} {...props} />
9 9
       {props.children}
10 10
     </div>
11 11
   );

+ 7
- 11
src/pages/MonitoringScreen2/components/map/map.jsx View File

@@ -6,21 +6,19 @@ const dzData = geoData.features[0].geometry.coordinates[0][0];
6 6
 
7 7
 const plugins = ['AMap.ToolBar'];
8 8
 export default (props) => {
9
-  const { style, className } = props;
9
+  const { style, className, onReady } = props;
10 10
   const containerRef = React.useRef();
11
-  const mapRef = React.useRef();
12
-  const mapInstRef = React.useRef();
13 11
 
14 12
   React.useEffect(() => {
15 13
     loader(plugins)
16 14
       .then((AMap) => {
17
-        const mapInst = new AMap.Map(containerRef.current, {
18
-          mapStyle: 'amap://styles/light',
15
+        const map = new AMap.Map(containerRef.current, {
16
+          mapStyle: 'amap://styles/d8278c296329ee0867aa26718e23bb80',
19 17
           layers: [
20 18
             // 卫星
21 19
             new AMap.TileLayer.Satellite(),
22 20
             // 路网
23
-            // new AMap.TileLayer.RoadNet(),
21
+            new AMap.TileLayer.RoadNet(),
24 22
           ],
25 23
           zoom: 10,
26 24
           resizeEnable: true,
@@ -28,7 +26,7 @@ export default (props) => {
28 26
         });
29 27
 
30 28
         // 缩放按钮
31
-        mapInst.addControl(new AMap.ToolBar());
29
+        map.addControl(new AMap.ToolBar());
32 30
 
33 31
         // 绘制边线
34 32
         const dengzhou = new AMap.Polygon({
@@ -41,11 +39,9 @@ export default (props) => {
41 39
           strokeStyle: 'dashed',
42 40
           strokeDasharray: [5, 5],
43 41
         });
44
-        mapInst.add(dengzhou);
42
+        map.add(dengzhou);
45 43
 
46
-        //
47
-        mapRef.current = AMap;
48
-        mapInstRef.current = mapInst;
44
+        onReady(map, AMap);
49 45
       })
50 46
       .catch((err) => {
51 47
         console.log(err.message);

+ 102
- 152
src/pages/MonitoringScreen2/index.jsx View File

@@ -1,149 +1,116 @@
1 1
 import getWeather from '@/components/AMap/weather';
2 2
 // import GeoMap from '@/components/GeoMap';
3 3
 import ScreenHeader from '@/components/ScreenBox/ScreenHeader';
4
-import SquareBox from '@/components/ScreenBox/SquareBox';
5
-import StatisCard from '@/components/ScreenBox/StatisCard';
6 4
 import classNames from 'classnames';
7 5
 import { useEffect, useRef, useState } from 'react';
8
-import {
9
-  getBasic,
10
-  getOrgDetail,
11
-  getTypeList,
12
-  getAreaDetail,
13
-  getMachineryBar,
14
-  getWorkNumPie,
15
-  getTypeBasic,
16
-  getMessageList,
17
-} from '@/services/monitoringScreen';
18
-import MachineryStatus from './components/MachineryStatus';
19
-import MachineryType from './components/MachineryType';
6
+import { getDeviceMachineryList } from '@/services/monitoringScreen';
7
+import { regeo } from '@/components/AMap/service';
20 8
 import { useParticlesJs } from './hook';
21 9
 import Map from './components/map';
22
-
23
-import ColorFont from './components/ColorFont';
24
-import List from './components/List';
25
-import WorkArea from './components/WorkArea';
26
-import WorkData from './components/WorkData';
10
+import Banner from './components/Banner';
27 11
 import DeviceList from './components/DeviceList';
12
+import DeviceType from './components/DeviceType';
13
+import makeMachinery from './components/machinery';
14
+import MachineryInfo from './components/MachineryInfo';
28 15
 import Styles from './style.less';
29 16
 
30 17
 export default (props) => {
31 18
   const screenRef = useRef();
19
+  const mapRef = useRef();
20
+  const aMapRef = useRef();
21
+  const [mapReady, setMapReady] = useState(false);
32 22
   const [weather, setWeather] = useState('暂无天气信息');
23
+  const [machines, setMachines] = useState([]);
24
+  const machineMarkers = useRef([]);
25
+  const [deviceType, setDeviceType] = useState();
26
+  const [curMachine, setCurMachine] = useState();
27
+  const curPos = useRef();
28
+  const infoWinRef = useRef();
33 29
 
34
-  const [basic, setBasic] = useState();
35
-
36
-  const [machineryTypeData, setMachineryTypeData] = useState([]);
30
+  const onMapReady = (map, AMap) => {
31
+    mapRef.current = map;
32
+    aMapRef.current = AMap;
33
+    setMapReady(true);
34
+  };
37 35
 
38
-  const [machineryStatusData, setMachineryStatusData] = useState([
39
-    { name: '预约', value: 350 },
40
-    { name: '作业', value: 900 },
41
-    { name: '闲置', value: 650 },
42
-    { name: '离线', value: 180 },
43
-    { name: '维修', value: 380 },
44
-  ]);
45
-
46
-  const [workData, setWorkData] = useState([]);
36
+  useEffect(() => {
37
+    if (mapReady) {
38
+      makeMachinery(
39
+        machines,
40
+        machineMarkers.current,
41
+        mapRef.current,
42
+        aMapRef.current,
43
+        (machine, position) => {
44
+          // 创建信息窗体
45
+          setCurMachine(machine);
46
+          curPos.current = position;
47
+        },
48
+      );
49
+    }
50
+  }, [mapReady, machines]);
47 51
 
48
-  const [workAreaData, setWorkAreaData] = useState([]);
52
+  useEffect(() => {
53
+    if (mapReady) {
54
+      const map = mapRef.current;
55
+      const AMap = aMapRef.current;
49 56
 
50
-  const [machineTypeList, setMachineTypeList] = useState([{ id: 't0', name: '合作社' }]);
57
+      if (curMachine) {
58
+        const infoWindow = new AMap.InfoWindow({
59
+          isCustom: true, //使用自定义窗体
60
+          content: infoWinRef.current,
61
+          offset: new AMap.Pixel(16, -45),
62
+        });
51 63
 
52
-  const [orgList, setOrgList] = useState();
64
+        infoWindow.on('close', () => {
65
+          map.clearInfoWindow();
66
+        });
53 67
 
54
-  const [machineList, setMachineList] = useState([]);
55
-  const [appointList, setAppointList] = useState();
56
-  const [acceptList, setAcceptList] = useState();
68
+        infoWindow.open(map, curPos.current);
69
+      } else {
70
+        map.clearInfoWindow();
71
+      }
72
+    }
73
+  }, [curMachine, mapReady]);
57 74
 
58 75
   useEffect(() => {
59
-    //顶部基本数据
60
-    getBasic()
61
-      .then((res) => {
62
-        var data = {};
63
-        for (let i = 0; i < res.length; i++) {
64
-          const element = res[i];
65
-          data[element.name] = element.value;
76
+    const params = deviceType ? { deviceType } : undefined;
77
+    getDeviceMachineryList(params).then((res) => {
78
+      const locIds = [];
79
+      const locList = [];
80
+      const list = res || [];
81
+
82
+      for (let item of list) {
83
+        if (item.location && item.location.indexOf('0.0') === -1) {
84
+          locIds.push(item.machineryId);
85
+          locList.push(item.location);
66 86
         }
67
-        setBasic(data);
68
-      })
69
-      .catch((err) => {
70
-        console.log(err.message);
71
-      });
72
-    //地图上合作社的marker
73
-    getOrgDetail()
74
-      .then((res) => {
75
-        res.forEach((item) => {
76
-          item.lnglat = [item['lng'] - 0, item['lat'] - 0];
77
-          item.machineryNum = item.machineryNum - 0;
78
-        });
79
-        setOrgList(res);
80
-      })
81
-      .catch((err) => {
82
-        console.log(err.message);
83
-      });
84
-    //获取地图上所有农机markers
85
-    getTypeBasic()
86
-      .then((res) => {
87
-        res.forEach((item) => {
88
-          item.lnglat = [item.location.split(',')[0] - 0, item.location.split(',')[1] - 0];
89
-        });
90
-        setMachineList(res);
91
-      })
92
-      .catch((err) => {
93
-        console.log(err.message);
94
-      });
95
-    //获取地图左侧选择的农机列表
96
-    getTypeList()
97
-      .then((res) => {
98
-        let data = [].concat(machineTypeList);
99
-        res.forEach((item) => {
100
-          data.push({ id: item.typeId, name: item.name });
101
-        });
102
-        setMachineTypeList(data);
103
-      })
104
-      .catch((err) => {
105
-        console.log(err.message);
106
-      });
107
-    //作业面积统计
108
-    getAreaDetail()
109
-      .then((res) => {
110
-        setWorkAreaData([].concat(res));
111
-      })
112
-      .catch((err) => {
113
-        console.log(err.message);
114
-      });
115
-    //农机类型统计
116
-    getMachineryBar()
117
-      .then((res) => {
118
-        setMachineryTypeData(res);
119
-      })
120
-      .catch((err) => {
121
-        console.log(err.message);
122
-      });
123
-    //农机作业数统计
124
-    getWorkNumPie()
125
-      .then((res) => {
126
-        setWorkData(res);
127
-      })
128
-      .catch((err) => {
129
-        console.log(err.message);
130
-      });
87
+      }
131 88
 
132
-    getMessageList({ messageType: 'appoint' })
133
-      .then((res) => {
134
-        setAppointList(res);
135
-      })
136
-      .catch((err) => {
137
-        console.log(err.message);
138
-      });
139
-    getMessageList({ messageType: 'accept' })
140
-      .then((res) => {
141
-        setAcceptList(res);
142
-      })
143
-      .catch((err) => {
144
-        console.log(err.message);
145
-      });
89
+      if (locList.length > 0) {
90
+        // 高德接口, 请求地址的描述
91
+        regeo({ location: locList.join('|') })
92
+          .then((regs) => {
93
+            if (regs.status === '1') {
94
+              regs.regeocodes.forEach((addrs, inx) => {
95
+                const addr = addrs['formatted_address'];
96
+                const addressComponent = addrs.addressComponent;
97
+                const machine = list.filter((x) => x.machineryId === locIds[inx])[0];
98
+                machine.loc = addr.replace(addressComponent.province, ''); // 去掉省
99
+              });
100
+            }
101
+
102
+            setMachines(list);
103
+          })
104
+          .catch((er) => {
105
+            console.error(er);
146 106
 
107
+            setMachines(list);
108
+          });
109
+      }
110
+    });
111
+  }, [deviceType]);
112
+
113
+  useEffect(() => {
147 114
     getWeather()
148 115
       .then((res) => {
149 116
         if (res && res.length) {
@@ -172,44 +139,27 @@ export default (props) => {
172 139
         </div>
173 140
         <div className={classNames(Styles['grail-container'], Styles['mg-tp-30'])}>
174 141
           <div className={classNames(Styles['grail-content'], Styles['pd-lr-40'])}>
175
-            <div className={Styles['statis-container']}>
176
-              <StatisCard
177
-                color="#23E8AE"
178
-                icon="icon1"
179
-                value={basic?.totalMachineryNum}
180
-                title="农机总数(台)"
181
-              />
182
-              <StatisCard
183
-                color="#0BDAFF"
184
-                icon="icon2"
185
-                value={basic?.totalMachineryUsed}
186
-                title="农机使用数(台)"
187
-              />
188
-              <StatisCard
189
-                color="#F5CC5C"
190
-                icon="icon3"
191
-                value={basic?.totalOrderNum}
192
-                title="总预约数"
193
-              />
194
-              <StatisCard
195
-                color="#C579FF"
196
-                icon="icon4"
197
-                value={basic?.totalServiceNum}
198
-                title="总服务数"
199
-              />
200
-            </div>
201
-            {/* <GeoMap machineTypeList={machineTypeList} orgList={orgList} machineList={machineList} /> */}
202
-            <Map>
142
+            {/* <div className={Styles['statis-container']}>
143
+              <Banner />
144
+            </div> */}
145
+            <Map onReady={onMapReady}>
203 146
               <div
204 147
                 className={Styles['map-addon']}
205
-                style={{ right: '20px', bottom: '100px', width: '600px' }}
148
+                style={{
149
+                  top: '60px',
150
+                  left: '60px',
151
+                  width: '120px',
152
+                }}
206 153
               >
207
-                <DeviceList />
154
+                <DeviceType onChange={setDeviceType} />
208 155
               </div>
209 156
             </Map>
210 157
           </div>
211 158
         </div>
212 159
       </div>
160
+      <div style={{ position: 'absolute', zIndex: -1 }}>
161
+        <MachineryInfo data={curMachine} ref={infoWinRef} />
162
+      </div>
213 163
     </div>
214 164
   );
215 165
 };

+ 3
- 0
src/pages/MonitoringScreen2/style.less View File

@@ -90,4 +90,7 @@
90 90
 .map-addon {
91 91
   position: absolute;
92 92
   z-index: 20;
93
+  padding: 1em;
94
+  background: rgba(0, 0, 0, 0.6);
95
+  border-radius: 6px;
93 96
 }

+ 8
- 0
src/services/monitoringScreen.js View File

@@ -57,3 +57,11 @@ export const getTypeBasic = (params) => request('/screen-data/machinery/all', {
57 57
  * @returns
58 58
  */
59 59
 export const getMessageList = (params) => request('/screen-data/message', { params });
60
+
61
+/**
62
+ *  获取绑定设备农机
63
+ * @param {*} params
64
+ * @returns
65
+ */
66
+export const getDeviceMachineryList = (params) =>
67
+  request('/screen-data/machinery-device', { params });