Yansen 2 anos atrás
pai
commit
590c80f382

BIN
src/assets/images/statistic/人员统计.png Ver arquivo


BIN
src/assets/images/statistic/任务统计.png Ver arquivo


BIN
src/assets/images/statistic/保障机构数.png Ver arquivo


BIN
src/assets/images/statistic/军供保障能力.png Ver arquivo


BIN
src/assets/images/statistic/接待军人总数.png Ver arquivo


BIN
src/assets/images/statistic/数字统计.png Ver arquivo


BIN
src/assets/images/statistic/社会保障机构分类统计.png Ver arquivo


BIN
src/assets/images/statistic/设备分类统计.png Ver arquivo


BIN
src/assets/images/statistic/设备数量.png Ver arquivo


+ 11
- 3
src/components/chart/index.jsx Ver arquivo

@@ -1,4 +1,4 @@
1
-import React, { useRef, useEffect } from 'react';
1
+import React, { useRef, useEffect, } from 'react';
2 2
 
3 3
 // 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
4 4
 import * as echarts from 'echarts/core';
@@ -51,7 +51,7 @@ echarts.use([
51 51
 ]);
52 52
 
53 53
 export default (props) => {
54
-  const { className, style, option } = props;
54
+  const { className, style, option, onInited, onRendered } = props;
55 55
 
56 56
   const domRef = useRef();
57 57
   const chartRef = useRef();
@@ -59,6 +59,10 @@ export default (props) => {
59 59
   useEffect(() => {
60 60
     if (!chartRef.current) {
61 61
       chartRef.current = echarts.init(domRef.current);
62
+
63
+      if (typeof onInited === 'function') {
64
+        onInited(chartRef.current);
65
+      }
62 66
     }
63 67
 
64 68
     const resize = () => {
@@ -71,6 +75,10 @@ export default (props) => {
71 75
     chartRef.current.setOption(option);
72 76
     resize();
73 77
 
78
+    if (typeof onRendered === 'function') {
79
+      onRendered(chartRef.current);
80
+    }
81
+
74 82
     window.addEventListener('resize', resize);    
75 83
     return () => window.removeEventListener('resize', resize);
76 84
   }, [option]);
@@ -78,4 +86,4 @@ export default (props) => {
78 86
   return (
79 87
     <div className={className} style={style} ref={domRef}></div>
80 88
   )
81
-}
89
+};

+ 2
- 2
src/layouts/AuthLayout/components/Container.jsx Ver arquivo

@@ -13,7 +13,7 @@ export default (props) => {
13 13
   
14 14
   useEffect(() => {
15 15
     const containerHeight = containerRef.current.offsetHeight;
16
-    const footerHeight = document.querySelector('.ant-layout-footer').offsetHeight;
16
+    const footerHeight = (document.querySelector('.ant-layout-footer') || {}).offsetHeight || 0;
17 17
     setMinHeight(containerHeight - footerHeight);
18 18
   }, []);
19 19
 
@@ -24,7 +24,7 @@ export default (props) => {
24 24
           <Outlet />
25 25
         {/* </PageTransition> */}
26 26
       </Content>
27
-      <Footer />
27
+      {!props.noFooter && <Footer />}      
28 28
     </div>
29 29
   )
30 30
 }

+ 2
- 2
src/layouts/AuthLayout/index.jsx Ver arquivo

@@ -17,7 +17,7 @@ export default (props) => {
17 17
   const { user, menus } = useModel('user');
18 18
   const location = useLocation();
19 19
   const { meta } = useRoute() || {};
20
-  const { noLayout = false, noSiderBar = false } = meta || {};
20
+  const { noLayout = false, noSiderBar = false, noFooter = false } = meta || {};
21 21
 
22 22
   const splitMenus = useMemo(() => menus.map(x => ({ ...x, children: undefined })), [menus]);
23 23
   const siderMenus = useMemo(() => {
@@ -37,7 +37,7 @@ export default (props) => {
37 37
                 <Header theme={theme} menus={splitMenus} location={location} />
38 38
                 <Layout>
39 39
                   { !noSiderBar && <SiderBar theme={theme} menus={siderMenus} location={location} /> }
40
-                  <Container location={location} />
40
+                  <Container location={location} noFooter={noFooter} />
41 41
                 </Layout>
42 42
               </Layout>
43 43
             )

+ 43
- 0
src/pages/statis/charts.jsx Ver arquivo

@@ -0,0 +1,43 @@
1
+import React from 'react';
2
+import { Row, Col } from 'antd';
3
+import Sumary from './components/Sumary';
4
+import Task from './components/Task';
5
+import DeviceType from './components/DeviceType';
6
+import StoreCost from './components/StoreCost';
7
+import User from './components/User';
8
+import Styles from './style.module.less';
9
+
10
+const mtp = {
11
+  marginTop: '24px',
12
+}
13
+
14
+export default (props) => {
15
+  const gutter = 24;
16
+
17
+  return (
18
+    <div className={Styles['chart-page']}>
19
+      <Sumary gutter={gutter} />
20
+      <Row gutter={gutter} style={mtp}>
21
+        <Col span={18}>
22
+          <Task />
23
+        </Col>
24
+        <Col span={6}>
25
+          <DeviceType />
26
+        </Col>
27
+      </Row>
28
+      <Row gutter={gutter} style={mtp}>
29
+        <Col span={12}>
30
+          <StoreCost />
31
+        </Col>
32
+        <Col span={12}>
33
+          <User />
34
+        </Col>
35
+      </Row>
36
+      <Row gutter={gutter} style={mtp}>
37
+        <Col span={24}>
38
+          <Task />
39
+        </Col>
40
+      </Row>
41
+    </div>
42
+  )
43
+}

+ 100
- 0
src/pages/statis/components/Age.jsx Ver arquivo

@@ -0,0 +1,100 @@
1
+import React from 'react';
2
+import * as echarts from 'echarts/core';
3
+import Chart from '@/components/chart';
4
+
5
+let dataIndex = 0;
6
+export default (props) => {
7
+
8
+  const chartRef = React.useRef();
9
+  const option = getOption({"20(含)至29岁": 10, "20(含)至39岁": 20, "40(含)至49岁": 30, "50(含)岁以上": 40});
10
+
11
+  React.useEffect(() => {
12
+    const t = setTimeout(() => {
13
+      const chart = chartRef.current;
14
+      chart.on('mousemove', function(e) {
15
+        chart.dispatchAction({ type: 'downplay', dataIndex });
16
+        chart.dispatchAction({ type: 'highlight', dataIndex: e.dataIndex });
17
+        dataIndex = e.dataIndex
18
+      });
19
+      chart.dispatchAction({ type: 'highlight', dataIndex });
20
+      clearTimeout(t);
21
+    }, 300);
22
+  }, []);
23
+
24
+  const onInited = (chart) => chartRef.current = chart;
25
+
26
+  return (
27
+    <Chart option={option} style={{ height: '270px' }} onInited={onInited} />
28
+  )
29
+}
30
+
31
+function getOption(seriesData) {
32
+  const data = Object.keys(seriesData).map(function(key) {
33
+    return {
34
+      value: seriesData[key],
35
+      name: key
36
+    }
37
+  });
38
+
39
+  return {
40
+    title: {
41
+      show: true,
42
+      top: '6%',
43
+      left: 'center',
44
+      text: '人员年龄统计',
45
+      textStyle: {
46
+        color: '#fff',
47
+        fontSize: 18,
48
+        fontWeight: 'normal'
49
+      }
50
+    },
51
+    color: ['#3DE0A4', '#FF8940', '#3FC9F4', '#CB55E9'],
52
+    series: [
53
+      {
54
+        type: 'pie',
55
+        top: '10%',
56
+        radius: ['60%', '70%'],
57
+        label: {
58
+          show: false,
59
+          position: 'center',
60
+          lineHeight: 28,
61
+          borderRadius: [100, 100, 100, 100],
62
+          borderColor: '#FD8F00',
63
+          borderWidth: 2,
64
+          padding: 16,
65
+          width: 100,
66
+          height: 100,
67
+          formatter: [
68
+            '{s1|{d}%}',
69
+            '{s2|{b}}',
70
+            '{s3|{c}}',
71
+          ].join('\n'),
72
+          rich: {
73
+            s1: {
74
+              color: '#FD8F00',
75
+              fontSize: 24,
76
+            },
77
+            s2: {
78
+              color: 'rgba(255, 255, 255, .7)',
79
+              fontSize: 16,
80
+            },
81
+            s3: {
82
+              color: '#fff',
83
+              fontSize: 18,
84
+            },
85
+          }
86
+        },
87
+        emphasis: {
88
+          scaleSize: 10,
89
+          label: {
90
+            show: true,
91
+          }
92
+        },
93
+        labelLine: {
94
+          show: false
95
+        },
96
+        data: data,
97
+      },
98
+    ]
99
+  };
100
+}

+ 84
- 0
src/pages/statis/components/DeviceType.jsx Ver arquivo

@@ -0,0 +1,84 @@
1
+import React from 'react';
2
+import * as echarts from 'echarts/core';
3
+import icon from '@/assets/images/statistic/设备分类统计.png';
4
+import Chart from '@/components/chart';
5
+import StatisCard from './StatisCard';
6
+
7
+let dataIndex = 0;
8
+
9
+export default (props) => {
10
+
11
+  const chartRef = React.useRef();
12
+  const option = getOption({ "制餐设备": 20, "运输设备": 33, "野外保障设备": 10 });
13
+
14
+  React.useEffect(() => {
15
+    const t = setTimeout(() => {
16
+      const chart = chartRef.current;
17
+      chart.on('mousemove', function(e) {
18
+        chart.dispatchAction({ type: 'downplay', dataIndex });
19
+        chart.dispatchAction({ type: 'highlight', dataIndex: e.dataIndex });
20
+        dataIndex = e.dataIndex
21
+      });
22
+      chart.dispatchAction({ type: 'highlight', dataIndex });
23
+      clearTimeout(t);
24
+    }, 300);
25
+  }, []);
26
+
27
+  const onInited = (chart) => chartRef.current = chart;
28
+
29
+  return (
30
+    <StatisCard
31
+      title="设备分类统计"
32
+      icon={icon}
33
+    >
34
+      <Chart option={option} style={{ height: '300px' }} onInited={onInited} />
35
+    </StatisCard>
36
+  )
37
+}
38
+
39
+function getOption(seriesData) {
40
+  const data = Object.keys(seriesData).map(function(key) {
41
+    return {
42
+      value: seriesData[key],
43
+      name: key
44
+    }
45
+  });
46
+
47
+  return {
48
+    color: ['#3DE0A4', '#FF8940', '#3FC9F4', '#CB55E9'],
49
+    series: [
50
+      {
51
+        name: '设备分类统计',
52
+        type: 'pie',
53
+        radius: ['40%', '70%'],
54
+        avoidLabelOverlap: false,
55
+        itemStyle: {
56
+          borderRadius: 10,
57
+          borderColor: '#071C51',
58
+          borderWidth: 4
59
+        },
60
+        label: {
61
+          show: false,
62
+          position: 'center',
63
+        },
64
+        emphasis: {
65
+          scaleSize: 16,
66
+          label: {
67
+            show: true,
68
+            color: '#ffffff',
69
+            fontSize: 16,
70
+            fontWeight: 'bold',
71
+            lineHeight: 24,
72
+            formatter: function (params) {
73
+              return params.name + '\n' + params.value
74
+            },
75
+          }
76
+        },
77
+        labelLine: {
78
+          show: false
79
+        },
80
+        data: data,
81
+      }
82
+    ]
83
+  };
84
+}

+ 132
- 0
src/pages/statis/components/Edu.jsx Ver arquivo

@@ -0,0 +1,132 @@
1
+import React from 'react';
2
+import * as echarts from 'echarts/core';
3
+import Chart from '@/components/chart';
4
+
5
+export default (props) => {
6
+
7
+  const option = getOption(["本科以上", "本科及大专", "大专以下"], [10, 20, 30]);
8
+
9
+  return (
10
+    <Chart option={option} style={{ height: '300px' }} />
11
+  )
12
+}
13
+
14
+function getOption(yAxisData, seriesData) {
15
+  var maxValue = seriesData.slice().sort().reverse()[0] - 0 + 10
16
+
17
+  var title = {
18
+    show: true,
19
+    top: '6%',
20
+    left: 'center',
21
+    text: '人员学历统计',
22
+    textStyle: {
23
+      color: '#fff',
24
+      fontSize: 18,
25
+      fontWeight: 'normal'
26
+    }
27
+  }
28
+
29
+  // 实际上是绘制了 seriesData.length 个的柱图
30
+  var percent = 100 / seriesData.length
31
+  var grid = seriesData.map(function (_, index) {
32
+    return {
33
+      top: (20 + index * 20 ) + '%',
34
+      height: percent + '%',
35
+    }
36
+  })
37
+
38
+  var xAxis = seriesData.map(function (_, index) {
39
+    return { type: 'value', show: false, gridIndex: index }
40
+  })
41
+
42
+  var yAxis = yAxisData.map(function(_, index) {
43
+    return {
44
+      type: 'category',
45
+      position: 'right',
46
+      gridIndex: index,
47
+      axisLine: { show: false },
48
+      axisTick: { show: false },
49
+      axisLabel: {
50
+        color: '#fff',
51
+        fontSize: 16,
52
+        formatter: function () {
53
+          return seriesData[index];
54
+        }
55
+      }
56
+    }
57
+  })
58
+
59
+  var colors = [
60
+    new echarts.graphic.LinearGradient(0, 0, 1, 0, [
61
+      { offset: 0, color: '#87E8C5' },
62
+      { offset: 1, color: '#15E096' }
63
+    ]),
64
+    new echarts.graphic.LinearGradient(0, 0, 1, 0, [
65
+      { offset: 0, color: '#00BFFA' },
66
+      { offset: 1, color: '#0160EB' }
67
+    ]),
68
+    new echarts.graphic.LinearGradient(0, 0, 1, 0, [
69
+      { offset: 0, color: '#FFBE4E' },
70
+      { offset: 1, color: '#F77C30' }
71
+    ]),
72
+  ]
73
+
74
+  var barGaps = []; // 用来做背景
75
+  var pictorialBar = []; // 尾部的圆
76
+  var series = seriesData.map(function(dt, index) {
77
+    barGaps.push({
78
+      type: 'bar',
79
+      silent: true,
80
+      name: yAxisData[index],
81
+      xAxisIndex: index,
82
+      yAxisIndex: index,
83
+      barWidth: 16,
84
+      barGap: '-180%',
85
+      data: [maxValue],
86
+      label: {
87
+        show: true,
88
+        position: [0, '-160%'],
89
+        formatter: '{a}',
90
+        color: '#fff',
91
+        fontSize: 16,
92
+      },
93
+      itemStyle: {
94
+        color: 'rgba(255, 255, 255, 0.05)',
95
+        borderColor: 'rgba(255, 255, 255, 0.2)',
96
+        borderWidth: 1
97
+      }
98
+    })
99
+
100
+    pictorialBar.push({
101
+      silent: true,
102
+      type: 'pictorialBar',
103
+      xAxisIndex: index,
104
+      yAxisIndex: index,
105
+      data: [dt],
106
+      symbol: 'circle',
107
+      symbolSize: [10, 10],
108
+      symbolPosition: 'end',
109
+      symbolOffset: ['50%', '-25%'],
110
+    })
111
+
112
+    return {
113
+      data: [dt],
114
+      type: 'bar',
115
+      barWidth: 6,
116
+      xAxisIndex: index,
117
+      yAxisIndex: index,
118
+    }
119
+  })
120
+
121
+  var option = {
122
+    title: title,
123
+    xAxis: xAxis,
124
+    yAxis: yAxis,
125
+    grid: grid,
126
+    color: colors,
127
+    series: series.concat(barGaps).concat(pictorialBar)
128
+  }
129
+
130
+  // console.log(option)
131
+  return option
132
+}

+ 88
- 0
src/pages/statis/components/Filter.jsx Ver arquivo

@@ -0,0 +1,88 @@
1
+import React from 'react';
2
+import { Row, Col, Radio, DatePicker } from 'antd';
3
+import moment from 'moment';
4
+import 'moment/locale/zh-cn';
5
+import locale from 'antd/es/locale/zh_CN';
6
+
7
+const { RangePicker } = DatePicker;
8
+const radioOptions = [
9
+  { label: '本月', value: '1' },
10
+  // { label: '本季', value: '2' },
11
+  { label: '本年', value: '3' },
12
+];
13
+
14
+export const yearRange = [
15
+  moment().startOf('year'),
16
+  moment(),
17
+]
18
+export const quarterRange = [
19
+  moment().startOf('quarter'),
20
+  moment(),
21
+]
22
+export const monthRange = [
23
+  moment().startOf('quarter'),
24
+  moment(),
25
+]
26
+
27
+export default (props) => {
28
+  const [dateRange, setDateRange] = React.useState([]);
29
+  const [radioValue, setRadioValue] = React.useState();
30
+
31
+  const onChange = (val) => {
32
+    if (typeof props.onChange === 'function') {
33
+      props.onChange(getStrValue(val));
34
+    }
35
+  }
36
+
37
+  const onPickerChange = val => {
38
+    setDateRange(val);
39
+    setRadioValue();
40
+    onChange(getStrValue(val));
41
+  }
42
+
43
+  const onRadioChange = e => {
44
+    const val = e.target.value;
45
+    setRadioValue(val);
46
+    let dateRange = [];
47
+    switch (val) {
48
+      case '1':
49
+        dateRange = monthRange;
50
+        break;
51
+      case '2':
52
+        dateRange = quarterRange;
53
+        break;
54
+      case '3':
55
+        dateRange = yearRange;
56
+        break;
57
+      default:
58
+        break;
59
+    }
60
+    
61
+    setDateRange(dateRange);
62
+    onChange(getStrValue(dateRange));
63
+  }
64
+
65
+  return (
66
+    <Row style={{ width: '460px' }} gutter={8}>
67
+      <Col span={14}>
68
+        <RangePicker locale={locale} value={dateRange} onChange={onPickerChange} />
69
+      </Col>
70
+      <Col span={10}>
71
+        <Radio.Group
72
+          options={radioOptions}
73
+          value={radioValue}
74
+          onChange={onRadioChange}
75
+          optionType="button"
76
+          buttonStyle="solid"
77
+        />
78
+      </Col>
79
+    </Row>
80
+  )
81
+}
82
+
83
+export function getStrValue(range) {
84
+  return [
85
+    range[0].format('YYYY-MM-DD'),
86
+    range[1].format('YYYY-MM-DD'),
87
+  ];
88
+}

+ 26
- 0
src/pages/statis/components/StatisCard.jsx Ver arquivo

@@ -0,0 +1,26 @@
1
+import React from 'react';
2
+import { Card } from 'antd';
3
+import './style.global.less';
4
+
5
+const Header = props => {
6
+  return (
7
+    <div className="statis-card-header">
8
+      <img src={props.icon} />
9
+      <span>{props.children}</span>
10
+    </div>
11
+  )
12
+}
13
+
14
+export default (props) => {
15
+  const { icon, title, extra } = props;
16
+
17
+  return (
18
+    <Card
19
+      className="statis-card"
20
+      title={<Header icon={icon}>{title}</Header>}
21
+      extra={extra}
22
+    >
23
+      {props.children}
24
+    </Card>
25
+  )
26
+}

+ 84
- 0
src/pages/statis/components/StoreCost.jsx Ver arquivo

@@ -0,0 +1,84 @@
1
+import React from 'react';
2
+import icon from '@/assets/images/statistic/社会保障机构分类统计.png';
3
+import Chart from '@/components/chart';
4
+import StatisCard from './StatisCard';
5
+import Filter from './Filter';
6
+
7
+export default (props) => {
8
+
9
+  const [year, setYear] = React.useState();
10
+  const option = getOption(["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], [0, 0, 0, 0, 0, 0, 8, 9, 10, 1, 1, 6])
11
+
12
+  return (
13
+    <StatisCard
14
+      title="成本分析"
15
+      icon={icon}
16
+      extra={<Filter />}
17
+    >
18
+      <Chart option={option} style={{ height: '300px' }} />
19
+    </StatisCard>
20
+  )
21
+}
22
+
23
+function getOption(xAxisData, seriesData) {
24
+  var axisLabel = {
25
+    fontSize: 14,
26
+    color: 'rgba(255,255,255, .6)'
27
+  };
28
+  var lineStyle = {
29
+    color: 'rgba(255,255,255, .16)',
30
+    type: 'dashed'
31
+  };
32
+
33
+  return {
34
+    xAxis: {
35
+      type: 'category',
36
+      axisLabel: Object.assign({
37
+        rotate: 45
38
+      }, axisLabel),
39
+      axisLine: {
40
+        show: true,
41
+        lineStyle: lineStyle
42
+      },
43
+      data: xAxisData
44
+    },
45
+    yAxis: {
46
+      axisLabel: axisLabel,
47
+      axisLine: {
48
+        show: true,
49
+        lineStyle: lineStyle
50
+      },
51
+      splitLine: {
52
+        lineStyle: lineStyle
53
+      },
54
+      type: 'value'
55
+    },
56
+    tooltip : {
57
+      trigger: 'axis',
58
+      axisPointer : {
59
+        type : 'shadow'
60
+      }
61
+    },
62
+    grid: {
63
+      top: 20,
64
+      left: 50,
65
+      right: 20,
66
+      bottom: 70,
67
+    },
68
+    color: ['#9242D1'],
69
+    animationEasing: 'elasticOut',
70
+    series: [
71
+      {
72
+        data: seriesData,
73
+        type: 'pictorialBar',
74
+        barWidth: 16,
75
+        symbol: 'rect',
76
+        symbolRepeat: true,
77
+        animationDuration: 6000,
78
+        animationDelay: function (dataIndex, params) {
79
+          return params.index * 30;
80
+        }
81
+      }
82
+    ]
83
+  }
84
+}

+ 41
- 0
src/pages/statis/components/Sumary.jsx Ver arquivo

@@ -0,0 +1,41 @@
1
+import React from 'react';
2
+import { Row, Col } from 'antd';
3
+import classNames from 'classnames';
4
+import icon1 from '@/assets/images/statistic/数字统计.png';
5
+import icon2 from '@/assets/images/statistic/接待军人总数.png';
6
+import icon3 from '@/assets/images/statistic/保障机构数.png';
7
+import icon4 from '@/assets/images/statistic/设备数量.png';
8
+import Styles from './style.module.less';
9
+
10
+const DataCard = (props) => {
11
+  const { className, icon } = props;
12
+
13
+  const cls = classNames(Styles['data-card'], className);
14
+
15
+  return (
16
+    <dl className={cls}>
17
+      <dt>0</dt>
18
+      <dd>任务总数</dd>
19
+      <img src={icon} alt="" />
20
+    </dl>
21
+  )
22
+}
23
+
24
+export default (props) => {
25
+  return (
26
+    <Row gutter={props.gutter} justify="space-between">
27
+      <Col span={6}>
28
+        <DataCard icon={icon1} className={Styles['bk1']} />
29
+      </Col>
30
+      <Col span={6}>
31
+        <DataCard icon={icon2} className={Styles['bk2']} />
32
+      </Col>
33
+      <Col span={6}>
34
+        <DataCard icon={icon3} className={Styles['bk3']} />
35
+      </Col>
36
+      <Col span={6}>
37
+        <DataCard icon={icon4} className={Styles['bk4']} />
38
+      </Col>
39
+    </Row>
40
+  )
41
+}

+ 81
- 0
src/pages/statis/components/Task.jsx Ver arquivo

@@ -0,0 +1,81 @@
1
+import React from 'react';
2
+import * as echarts from 'echarts/core';
3
+import icon from '@/assets/images/statistic/任务统计.png';
4
+import Chart from '@/components/chart';
5
+import StatisCard from './StatisCard';
6
+import Filter from './Filter';
7
+
8
+export default (props) => {
9
+
10
+  const option = getOption(["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], [0, 0, 0, 0, 0, 0, 8, 9, 10, 1, 1, 6])
11
+
12
+  return (
13
+    <StatisCard
14
+      title="任务统计"
15
+      icon={icon}
16
+      extra={<Filter />}
17
+    >
18
+      <Chart option={option} style={{ height: '300px' }} />
19
+    </StatisCard>
20
+  )
21
+}
22
+
23
+function getOption(xAxisData, seriesData) {
24
+  var axisLabel = {
25
+    fontSize: 14,
26
+    color: 'rgba(255,255,255, .6)',
27
+  };
28
+  var lineStyle = {
29
+    color: 'rgba(255,255,255, .16)',
30
+    type: 'dashed'
31
+  };
32
+
33
+  return {
34
+    tooltip : {
35
+      trigger: 'axis',
36
+      axisPointer : {
37
+        type : 'shadow'
38
+      }
39
+    },
40
+    xAxis: {
41
+      type: 'category',
42
+      axisLabel: axisLabel,
43
+      axisLine: {
44
+        show: true,
45
+        lineStyle: lineStyle
46
+      },
47
+      data: xAxisData
48
+    },
49
+    yAxis: {
50
+      axisLabel: axisLabel,
51
+      axisLine: {
52
+        show: true,
53
+        lineStyle: lineStyle
54
+      },
55
+      splitLine: {
56
+        lineStyle: lineStyle
57
+      },
58
+      type: 'value'
59
+    },
60
+    grid: {
61
+      top: 20,
62
+      left: 50,
63
+      right: 20,
64
+      bottom: 50,
65
+    },
66
+    series: [
67
+      {
68
+        data: seriesData,
69
+        type: 'bar',
70
+        barWidth: 16,
71
+        itemStyle: {
72
+          borderRadius: [16, 16, 0, 0],
73
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
74
+            { offset: 0, color: '#1EAED1' },
75
+            { offset: 1, color: '#6F39B9' }
76
+          ])
77
+        }
78
+      }
79
+    ]
80
+  }
81
+}

+ 25
- 0
src/pages/statis/components/User.jsx Ver arquivo

@@ -0,0 +1,25 @@
1
+import React from 'react';
2
+import { Row, Col } from 'antd';
3
+import icon from '@/assets/images/statistic/人员统计.png';
4
+import StatisCard from './StatisCard';
5
+import Edu from './Edu';
6
+import Age from './Age';
7
+
8
+
9
+export default (props) => {
10
+  return (
11
+    <StatisCard
12
+      title="人员统计"
13
+      icon={icon}
14
+    >
15
+      <Row>
16
+        <Col span={12}>
17
+          <Edu />
18
+        </Col>
19
+        <Col span={12}>
20
+          <Age />
21
+        </Col>
22
+      </Row>
23
+    </StatisCard>
24
+  )
25
+}

+ 101
- 0
src/pages/statis/components/style.global.less Ver arquivo

@@ -0,0 +1,101 @@
1
+@chart-card-bg: #071C51;
2
+@chart-card-radius: 20px;
3
+
4
+.statis-card {
5
+	position: relative;
6
+	border-radius: @chart-card-radius;
7
+  background: transparent;
8
+  box-shadow: none;
9
+  border-color: transparent;
10
+  z-index: 0;
11
+
12
+  .ant-card-head {
13
+    border-bottom: none;
14
+  }
15
+
16
+  .ant-picker, .ant-radio-button-wrapper, .ant-picker-separator {
17
+    background: transparent !important;
18
+    color: #bbb !important;
19
+  }
20
+
21
+  .ant-radio-button-wrapper-checked {
22
+    background: #1890ff !important;
23
+    color: #fff !important;
24
+  }
25
+
26
+  .ant-picker-input {
27
+    & > input {
28
+      color: #bbb !important;
29
+    }
30
+  }
31
+
32
+  .ant-select-selector {
33
+    background: transparent !important;
34
+    border: none !important;
35
+    color: #bbb;
36
+    font-size: 1.4em;
37
+  }
38
+
39
+  .ant-select-arrow {
40
+    color: #bbb;
41
+  }
42
+  
43
+  &, &::before, &::after {
44
+    overflow: hidden;
45
+    box-sizing: border-box;
46
+  }
47
+
48
+  @keyframes chart-card-rotate {
49
+    100% {
50
+      transform: rotate(1turn);
51
+    }
52
+  }
53
+
54
+  &::before {
55
+    content: '';
56
+    position: absolute;
57
+    z-index: -2;
58
+    left: -450%;
59
+    top: -450%;
60
+    width: 1000%;
61
+    height: 1000%;
62
+    background-color: #1E5983;
63
+    background-repeat: no-repeat;
64
+    background-position: 0 0, 100% 100%;
65
+    background-image: conic-gradient(from 0, transparent, rgba(168, 239, 255, 1), transparent 20%),
66
+    conic-gradient(from 180deg,transparent, rgba(168, 239, 255, 1), transparent 20%);
67
+    animation: chart-card-rotate 10s linear infinite;
68
+  }
69
+
70
+  &::after {
71
+    content: '';
72
+    position: absolute;
73
+    z-index: -1;
74
+    left: 2px;
75
+    top: 2px;
76
+    width: calc(100% - 4px);
77
+    height: calc(100% - 4px);
78
+    background: @chart-card-bg;
79
+    border-radius: @chart-card-radius - 2px;
80
+    box-shadow: 2px 2px 10px rgba(255,255,255, .2) inset, -2px -2px 10px rgba(255,255,255, .2) inset;
81
+  }
82
+
83
+  .statis-card-header {
84
+    img {
85
+      width: 28px;
86
+      height: 28px;
87
+      vertical-align: middle;
88
+      display: inline-block;
89
+      margin-right: .5em;
90
+    }
91
+    span {
92
+      font-size: 22px;
93
+      font-weight: 500;
94
+      color: transparent;
95
+      background-image: linear-gradient(0deg, #6F39B9 0%, #1EAED1 100%);
96
+      vertical-align: middle;
97
+      background-clip: text;
98
+      -webkit-background-clip: text;
99
+    }
100
+  }
101
+}

+ 75
- 0
src/pages/statis/components/style.module.less Ver arquivo

@@ -0,0 +1,75 @@
1
+@chart-card-bg: #071C51;
2
+@chart-card-radius: 20px;
3
+
4
+.data-card {
5
+  overflow: hidden;
6
+  position: relative;
7
+  border-radius: 8px;
8
+  box-shadow: rgba(0, 0, 0, 0.3) 0px 2px 3px;
9
+  box-sizing: border-box;
10
+  padding: 24px 0px 36px;
11
+  padding-left: 150px;
12
+  // box-sizing: border-box;
13
+  // padding-left: 150px;
14
+
15
+  dt {
16
+    font-size: 36px;
17
+  }
18
+
19
+  dd {
20
+    font-size: 16px;
21
+  }
22
+
23
+  dt, dd {
24
+    padding: 0;
25
+    font-weight: 400;
26
+    color: rgb(255, 255, 255);
27
+    line-height: 1.53846;
28
+  }
29
+
30
+  img {
31
+    position: absolute;
32
+    display: block;
33
+    top: 24px;
34
+    left: 30px;
35
+    width: 88px;
36
+    height: 88px;
37
+  }
38
+
39
+  &::before,&::after {
40
+    content: "";
41
+    position: absolute;
42
+    background: #FFFFFF;
43
+    opacity: 0.1;
44
+    border-radius: 50%;
45
+    font-size: 0;
46
+  }
47
+
48
+  &::before {
49
+    width: 166px;
50
+    height: 140px;
51
+    left: calc(100% - 88px);
52
+    top: -40px;
53
+  }
54
+  
55
+  &::after {
56
+    width: 281px;
57
+    height: 177px;
58
+    border-radius: 50%;
59
+    left: calc(100% - 160px);
60
+    top: 81px;
61
+  }
62
+
63
+  &.bk1 {
64
+    background: linear-gradient(90deg, #3886D6, #003789);
65
+  }
66
+  &.bk2 {
67
+    background: linear-gradient(90deg, #29A0B1, #3C1A63);
68
+  }
69
+  &.bk3 {
70
+    background: linear-gradient(90deg, #1570AB, #343894);
71
+  }
72
+  &.bk4 {
73
+    background: linear-gradient(90deg, #2788B6, #083A8C);
74
+  }
75
+}

+ 74
- 0
src/pages/statis/style.module.less Ver arquivo

@@ -0,0 +1,74 @@
1
+
2
+@chart-card-bg: #071C51;
3
+@chart-card-radius: 20px;
4
+
5
+
6
+.chart-page {
7
+  width: 100%;
8
+  height: calc(100vh - var(--header-height));
9
+  overflow-y: auto;
10
+  background: @chart-card-bg;
11
+  box-sizing: border-box;
12
+  padding: 24px;
13
+
14
+  .count {
15
+    border-radius: 20px;
16
+    
17
+    dl {
18
+      overflow: hidden;
19
+      position: relative;
20
+      box-sizing: border-box;
21
+      padding-left: 150px;
22
+
23
+      dt, dd {
24
+        padding: 0;
25
+      }
26
+
27
+      img {
28
+        position: absolute;
29
+        display: block;
30
+        top: 24px;
31
+        left: 30px;
32
+        width: 88px;
33
+        height: 88px;
34
+      }
35
+
36
+      &::before,&::after {
37
+        content: "";
38
+        position: absolute;
39
+        background: #FFFFFF;
40
+        opacity: 0.1;
41
+        border-radius: 50%;
42
+        font-size: 0;
43
+      }
44
+
45
+      &::before {
46
+        width: 166px;
47
+        height: 140px;
48
+        left: calc(100% - 88px);
49
+        top: -40px;
50
+      }
51
+      
52
+      &::after {
53
+        width: 281px;
54
+        height: 177px;
55
+        border-radius: 50%;
56
+        left: calc(100% - 160px);
57
+        top: 81px;
58
+      }
59
+
60
+      &:nth-child(1) {
61
+        background: linear-gradient(90deg, #3886D6, #003789);
62
+      }
63
+      &:nth-child(2) {
64
+        background: linear-gradient(90deg, #29A0B1, #3C1A63);
65
+      }
66
+      &:nth-child(3) {
67
+        background: linear-gradient(90deg, #1570AB, #343894);
68
+      }
69
+      &:nth-child(4) {
70
+        background: linear-gradient(90deg, #2788B6, #083A8C);
71
+      }
72
+    }
73
+  }
74
+}

+ 14
- 2
src/pages/stockClassification/edit/index.jsx Ver arquivo

@@ -65,7 +65,7 @@ export default (props) => {
65 65
         >
66 66
           <ProFormText
67 67
             name="name"
68
-            label="名称"
68
+            label="分类名称"
69 69
             placeholder="请输入名称"
70 70
             width={460}
71 71
             allowClear={false}
@@ -73,7 +73,7 @@ export default (props) => {
73 73
           />
74 74
           <ProFormSelect
75 75
             name="isFood"
76
-            label="食材"
76
+            label="是否食材"
77 77
             options={[
78 78
               { label: '是', value: 1 },
79 79
               { label: '否', value: 0 },
@@ -83,6 +83,18 @@ export default (props) => {
83 83
             allowClear={false}
84 84
             rules={[{ required: true, message: '请选择是否食材' }]}
85 85
           />
86
+          <ProFormSelect
87
+            name="isDevice"
88
+            label="是否设备"
89
+            options={[
90
+              { label: '是', value: 1 },
91
+              { label: '否', value: 0 },
92
+            ]}
93
+            placeholder="请选择"
94
+            width={460}
95
+            allowClear={false}
96
+            rules={[{ required: true, message: '请选择是否设备' }]}
97
+          />
86 98
         </ProForm>
87 99
       </Card>
88 100
     </PageContainer>

+ 5
- 1
src/routes/routes.jsx Ver arquivo

@@ -44,6 +44,7 @@ import EmergencyPlanDetail from "@/pages/cms/emergencyPlan/detail";
44 44
 import FilesList from "@/pages/cms/files/list";
45 45
 import MessageList from '@/pages/message';
46 46
 import MessageDetail from '@/pages/message/detail';
47
+import StatisCharts from '@/pages/statis/charts';
47 48
 
48 49
 /**
49 50
  * meta 用来扩展自定义数据数据
@@ -52,6 +53,7 @@ import MessageDetail from '@/pages/message/detail';
52 53
  *    hideInMenu: 布尔值, 如果为 false, 菜单不会显示
53 54
  *    noLayout: 布尔值, 如果为 true, 将不会使用默认布局
54 55
  *    noSiderBar: 布尔值, 如果为 true, 将没有左侧菜单栏
56
+ *    noFooter: 布尔值, 如果为 true, 将没有底部 footer 
55 57
  *    target: 字符串, 如果为 _blank, 将在新窗口打开
56 58
  * }
57 59
  */
@@ -241,9 +243,11 @@ export const authRoutes = [
241 243
   },
242 244
   {
243 245
     path: 'static',
244
-    element: <Container />,
246
+    element: <StatisCharts />,
245 247
     meta: {
246 248
       title: '数据分析',
249
+      noSiderBar: true,
250
+      noFooter: true,
247 251
     },
248 252
   },
249 253
   {