Your Name 2 years ago
parent
commit
3df6cb2952

+ 2
- 2
config/proxy.js View File

@@ -11,8 +11,8 @@ export default {
11 11
     // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
12 12
     '/api/': {
13 13
       // 要代理的地址
14
-      // target: 'http://127.0.0.1:7080',
15
-      target: 'http://192.168.89.76:7080',
14
+      target: 'http://127.0.0.1:7080',
15
+      // target: 'http://192.168.89.76:7080',
16 16
       // target: 'http://machine.njyunzhi.com',
17 17
       // 配置了这个可以从 http 代理到 https
18 18
       // 依赖 origin 的功能可能需要这个,比如 cookie

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

@@ -0,0 +1,15 @@
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
+};

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

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

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

@@ -0,0 +1,17 @@
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
+};

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

@@ -0,0 +1,66 @@
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
+};

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

@@ -0,0 +1,97 @@
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
+}

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

@@ -0,0 +1,94 @@
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
+};

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

@@ -0,0 +1,105 @@
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
+};

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

@@ -0,0 +1,52 @@
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
+};

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

@@ -0,0 +1,59 @@
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
+};

+ 150
- 0
src/pages/MonitoringScreen2/hook.js View File

@@ -0,0 +1,150 @@
1
+import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+import useResize from '@/utils/hooks/useResize';
3
+
4
+export function useFullScreen(elRef) {
5
+  const [isFullScreen, setIsFullScreen] = useState(false);
6
+  const fullScreenRef = useRef();
7
+  fullScreenRef.current = isFullScreen;
8
+
9
+  const toggleFullScreen = useCallback((e) => {
10
+    if (!document.fullscreenElement) {
11
+      elRef.current
12
+        .requestFullscreen()
13
+        .then(() => {
14
+          setIsFullScreen(true);
15
+        })
16
+        .catch((err) => {
17
+          console.log(err.message);
18
+        });
19
+    }
20
+  }, []);
21
+
22
+  useEffect(() => {
23
+    const handleFullScreenChange = (e) => {
24
+      setIsFullScreen(document.fullscreenElement === fullScreenRef.current);
25
+    };
26
+
27
+    elRef.current.onfullscreenchange = handleFullScreenChange;
28
+
29
+    // elRef.current.addEventListener('fullscreenchange', handleFullScreenChange);
30
+
31
+    return elRef.current.removeEventListener('fullscreenchange', handleFullScreenChange);
32
+  }, []);
33
+
34
+  return { isFullScreen, toggleFullScreen };
35
+}
36
+
37
+export function useParticlesJs(id) {
38
+  useEffect(() => {
39
+    window.particlesJS(id, {
40
+      particles: {
41
+        number: {
42
+          value: 20,
43
+          density: {
44
+            enable: true,
45
+            value_area: 400,
46
+          },
47
+        },
48
+        color: {
49
+          value: '#2FB3DF',
50
+        },
51
+        shape: {
52
+          type: 'circle',
53
+          stroke: {
54
+            width: 0,
55
+            color: '#000000',
56
+          },
57
+          polygon: {
58
+            nb_sides: 5,
59
+          },
60
+          image: {
61
+            src: 'img/github.svg',
62
+            width: 100,
63
+            height: 100,
64
+          },
65
+        },
66
+        opacity: {
67
+          value: 0.3,
68
+          random: false,
69
+          anim: {
70
+            enable: false,
71
+            speed: 1,
72
+            opacity_min: 0.1,
73
+            sync: false,
74
+          },
75
+        },
76
+        size: {
77
+          value: 3,
78
+          random: true,
79
+          anim: {
80
+            enable: false,
81
+            speed: 40,
82
+            size_min: 0.1,
83
+            sync: false,
84
+          },
85
+        },
86
+        line_linked: {
87
+          enable: true,
88
+          distance: 150,
89
+          color: '#2FB3DF',
90
+          opacity: 0.3,
91
+          width: 2,
92
+        },
93
+        move: {
94
+          enable: true,
95
+          speed: 6,
96
+          direction: 'none',
97
+          random: false,
98
+          straight: false,
99
+          out_mode: 'out',
100
+          bounce: false,
101
+          attract: {
102
+            enable: false,
103
+            rotateX: 600,
104
+            rotateY: 1200,
105
+          },
106
+        },
107
+      },
108
+      interactivity: {
109
+        detect_on: 'canvas',
110
+        events: {
111
+          onhover: {
112
+            enable: false,
113
+            mode: 'bubble',
114
+          },
115
+          onclick: {
116
+            enable: false,
117
+            mode: 'push',
118
+          },
119
+          resize: true,
120
+        },
121
+        modes: {
122
+          grab: {
123
+            distance: 400,
124
+            line_linked: {
125
+              opacity: 1,
126
+            },
127
+          },
128
+          bubble: {
129
+            distance: 400,
130
+            size: 40,
131
+            duration: 2,
132
+            opacity: 8,
133
+            speed: 3,
134
+          },
135
+          repulse: {
136
+            distance: 200,
137
+            duration: 0.4,
138
+          },
139
+          push: {
140
+            particles_nb: 4,
141
+          },
142
+          remove: {
143
+            particles_nb: 2,
144
+          },
145
+        },
146
+      },
147
+      retina_detect: true,
148
+    });
149
+  }, []);
150
+}

+ 257
- 0
src/pages/MonitoringScreen2/index.jsx View File

@@ -0,0 +1,257 @@
1
+import getWeather from '@/components/AMap/weather';
2
+import GeoMap from '@/components/GeoMap';
3
+import ScreenHeader from '@/components/ScreenBox/ScreenHeader';
4
+import SquareBox from '@/components/ScreenBox/SquareBox';
5
+import StatisCard from '@/components/ScreenBox/StatisCard';
6
+import classNames from 'classnames';
7
+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';
20
+import { useParticlesJs } from './hook';
21
+
22
+import ColorFont from './components/ColorFont';
23
+import List from './components/List';
24
+import WorkArea from './components/WorkArea';
25
+import WorkData from './components/WorkData';
26
+import Styles from './style.less';
27
+
28
+export default (props) => {
29
+  const screenRef = useRef();
30
+  const [weather, setWeather] = useState('暂无天气信息');
31
+
32
+  const [basic, setBasic] = useState();
33
+
34
+  const [machineryTypeData, setMachineryTypeData] = useState([]);
35
+
36
+  const [machineryStatusData, setMachineryStatusData] = useState([
37
+    { name: '预约', value: 350 },
38
+    { name: '作业', value: 900 },
39
+    { name: '闲置', value: 650 },
40
+    { name: '离线', value: 180 },
41
+    { name: '维修', value: 380 },
42
+  ]);
43
+
44
+  const [workData, setWorkData] = useState([]);
45
+
46
+  const [workAreaData, setWorkAreaData] = useState([]);
47
+
48
+  const [machineTypeList, setMachineTypeList] = useState([{ id: 't0', name: '合作社' }]);
49
+
50
+  const [orgList, setOrgList] = useState();
51
+
52
+  const [machineList, setMachineList] = useState([]);
53
+  const [appointList, setAppointList] = useState();
54
+  const [acceptList, setAcceptList] = useState();
55
+
56
+  useEffect(() => {
57
+    //顶部基本数据
58
+    getBasic()
59
+      .then((res) => {
60
+        var data = {};
61
+        for (let i = 0; i < res.length; i++) {
62
+          const element = res[i];
63
+          data[element.name] = element.value;
64
+        }
65
+        setBasic(data);
66
+      })
67
+      .catch((err) => {
68
+        console.log(err.message);
69
+      });
70
+    //地图上合作社的marker
71
+    getOrgDetail()
72
+      .then((res) => {
73
+        res.forEach((item) => {
74
+          item.lnglat = [item['lng'] - 0, item['lat'] - 0];
75
+          item.machineryNum = item.machineryNum - 0;
76
+        });
77
+        setOrgList(res);
78
+      })
79
+      .catch((err) => {
80
+        console.log(err.message);
81
+      });
82
+    //获取地图上所有农机markers
83
+    getTypeBasic()
84
+      .then((res) => {
85
+        res.forEach((item) => {
86
+          item.lnglat = [item.location.split(',')[0] - 0, item.location.split(',')[1] - 0];
87
+        });
88
+        setMachineList(res);
89
+      })
90
+      .catch((err) => {
91
+        console.log(err.message);
92
+      });
93
+    //获取地图左侧选择的农机列表
94
+    getTypeList()
95
+      .then((res) => {
96
+        let data = [].concat(machineTypeList);
97
+        res.forEach((item) => {
98
+          data.push({ id: item.typeId, name: item.name });
99
+        });
100
+        setMachineTypeList(data);
101
+      })
102
+      .catch((err) => {
103
+        console.log(err.message);
104
+      });
105
+    //作业面积统计
106
+    getAreaDetail()
107
+      .then((res) => {
108
+        setWorkAreaData([].concat(res));
109
+      })
110
+      .catch((err) => {
111
+        console.log(err.message);
112
+      });
113
+    //农机类型统计
114
+    getMachineryBar()
115
+      .then((res) => {
116
+        setMachineryTypeData(res);
117
+      })
118
+      .catch((err) => {
119
+        console.log(err.message);
120
+      });
121
+    //农机作业数统计
122
+    getWorkNumPie()
123
+      .then((res) => {
124
+        setWorkData(res);
125
+      })
126
+      .catch((err) => {
127
+        console.log(err.message);
128
+      });
129
+
130
+    getMessageList({ messageType: 'appoint' })
131
+      .then((res) => {
132
+        setAppointList(res);
133
+      })
134
+      .catch((err) => {
135
+        console.log(err.message);
136
+      });
137
+    getMessageList({ messageType: 'accept' })
138
+      .then((res) => {
139
+        setAcceptList(res);
140
+      })
141
+      .catch((err) => {
142
+        console.log(err.message);
143
+      });
144
+
145
+    getWeather()
146
+      .then((res) => {
147
+        if (res && res.length) {
148
+          const { casts, city } = res[0];
149
+          const { dayweather, nighttemp, daytemp } = casts[0];
150
+          const [min, max] =
151
+            parseInt(nighttemp) > parseInt(daytemp) ? [daytemp, nighttemp] : [nighttemp, daytemp];
152
+          setWeather(`${city} ${dayweather} ${min}-${max} °C`);
153
+        } else {
154
+          setWeather('暂无天气信息');
155
+        }
156
+      })
157
+      .catch((err) => {
158
+        console.log(err.message);
159
+      });
160
+  }, []);
161
+
162
+  useParticlesJs(Styles['particles-js']);
163
+
164
+  return (
165
+    <div className={classNames(Styles['screen-page'], Styles['pd-lr-40'])} ref={screenRef}>
166
+      <div id={Styles['particles-js']} />
167
+      <div className={Styles['grail-layout']}>
168
+        <div className={Styles['grail-header']}>
169
+          <ScreenHeader weather={weather} />
170
+        </div>
171
+        <div className={classNames(Styles['grail-container'], Styles['mg-tp-30'])}>
172
+          <div className={Styles['grail-left']}>
173
+            <div className="flex flex-column full-height">
174
+              <div className="flex-0" style={{ minHeight: '37%' }}>
175
+                <MachineryType source={machineryTypeData} />
176
+              </div>
177
+              <div className="flex-1" style={{ marginTop: '30px' }}>
178
+                <MachineryStatus source={machineryStatusData} />
179
+              </div>
180
+            </div>
181
+          </div>
182
+          <div className={classNames(Styles['grail-content'], Styles['pd-lr-40'])}>
183
+            <div className={Styles['statis-container']}>
184
+              <StatisCard
185
+                color="#23E8AE"
186
+                icon="icon1"
187
+                value={basic?.totalMachineryNum}
188
+                title="农机总数(台)"
189
+              />
190
+              <StatisCard
191
+                color="#0BDAFF"
192
+                icon="icon2"
193
+                value={basic?.totalMachineryUsed}
194
+                title="农机使用数(台)"
195
+              />
196
+              <StatisCard
197
+                color="#F5CC5C"
198
+                icon="icon3"
199
+                value={basic?.totalOrderNum}
200
+                title="总预约数"
201
+              />
202
+              <StatisCard
203
+                color="#C579FF"
204
+                icon="icon4"
205
+                value={basic?.totalServiceNum}
206
+                title="总服务数"
207
+              />
208
+            </div>
209
+            <GeoMap machineTypeList={machineTypeList} orgList={orgList} machineList={machineList} />
210
+          </div>
211
+          <div className={Styles['grail-right']}>
212
+            <div className="flex flex-column full-height">
213
+              <div className="flex-0" style={{ minHeight: '46%' }}>
214
+                <WorkData source={workData} />
215
+              </div>
216
+              <div className="flex-1" style={{ marginTop: '30px' }}>
217
+                <WorkArea source={workAreaData} />
218
+              </div>
219
+            </div>
220
+          </div>
221
+        </div>
222
+        <div className={classNames(Styles['grail-footer'], Styles['mg-tp-30'])}>
223
+          <SquareBox>
224
+            <div className="flex" style={{ padding: '20px 0' }}>
225
+              <div className="flex-1">
226
+                <List title="预约订单">
227
+                  {appointList?.map((item) => {
228
+                    return (
229
+                      <div key={item.messageId}>
230
+                        <ColorFont color="#44F68B">[{item.appointTime}]</ColorFont>{' '}
231
+                        <ColorFont color="#F5CC5C">{item.appointPerson}</ColorFont> 预约了一台
232
+                        {item.appointMachineryType}。
233
+                      </div>
234
+                    );
235
+                  })}
236
+                </List>
237
+              </div>
238
+              <div className={classNames('flex-0', Styles['footer-middle'])} />
239
+              <div className="flex-1">
240
+                <List title="作业订单" color="green">
241
+                  {acceptList?.map((item) => {
242
+                    return (
243
+                      <div key={item.messageId}>
244
+                        <ColorFont color="#44F68B">[{item.acceptTime}]</ColorFont>{' '}
245
+                        <ColorFont color="#F5CC5C">{item.acceptPerson}</ColorFont> 接到了一个订单。
246
+                      </div>
247
+                    );
248
+                  })}
249
+                </List>
250
+              </div>
251
+            </div>
252
+          </SquareBox>
253
+        </div>
254
+      </div>
255
+    </div>
256
+  );
257
+};

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

@@ -0,0 +1,88 @@
1
+.screen-page {
2
+  position: relative;
3
+  width: 100%;
4
+  // height: 100%;
5
+  height: 100vh;
6
+  padding-bottom: 30px;
7
+
8
+  background-color: #021222;
9
+  background-image: url('~@/assets/images/screen/bg.png');
10
+  background-repeat: no-repeat;
11
+  background-size: 100% 100%;
12
+
13
+  #particles-js {
14
+    position: absolute;
15
+    z-index: 0;
16
+    width: calc(100% - 80px);
17
+    height: 100%;
18
+    background-color: transparent;
19
+  }
20
+
21
+  &.full-screen {
22
+    position: fixed;
23
+    top: 0;
24
+    left: 0;
25
+    z-index: 1000;
26
+  }
27
+
28
+  .grail-layout {
29
+    display: flex;
30
+    flex-direction: column;
31
+    height: 100%;
32
+
33
+    .grail-header,
34
+    .grail-footer {
35
+      flex: none;
36
+    }
37
+
38
+    .grail-container {
39
+      display: flex;
40
+      flex: 1;
41
+      overflow: hidden;
42
+
43
+      .grail-left,
44
+      .grail-right {
45
+        flex: 1;
46
+        overflow: hidden;
47
+      }
48
+
49
+      .grail-content {
50
+        display: flex;
51
+        flex: 2;
52
+        flex-direction: column;
53
+
54
+        & > div {
55
+          &:first-child {
56
+            flex: none;
57
+          }
58
+
59
+          &:last-child {
60
+            flex: 1;
61
+          }
62
+        }
63
+      }
64
+    }
65
+  }
66
+
67
+  .statis-container {
68
+    display: flex;
69
+    margin-bottom: 30px;
70
+  }
71
+
72
+  .footer-middle {
73
+    width: 1px;
74
+    margin: 0 30px;
75
+    background: #03122a;
76
+    border: 1px solid #204a89;
77
+    opacity: 0.26;
78
+  }
79
+}
80
+
81
+.pd-lr-40 {
82
+  padding-right: 40px;
83
+  padding-left: 40px;
84
+}
85
+
86
+.mg-tp-30 {
87
+  margin-top: 30px;
88
+}