张延森 4 years ago
parent
commit
82cb4ab41a

+ 24
- 0
src/components/ECharts/echarts.js View File

@@ -0,0 +1,24 @@
1
+// echarts 包太大, 因此需要按需引入
2
+// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
3
+import * as echarts from 'echarts/core';
4
+// 引入柱状图图表,图表后缀都为 Chart
5
+import {
6
+  LineChart,
7
+  BarChart
8
+} from 'echarts/charts';
9
+// 引入提示框,标题,直角坐标系组件,组件后缀都为 Component
10
+import {
11
+    TitleComponent,
12
+    TooltipComponent,
13
+    GridComponent
14
+} from 'echarts/components';
15
+import {
16
+  CanvasRenderer,
17
+} from 'echarts/renderers';
18
+
19
+// 注册必须的组件
20
+echarts.use(
21
+  [CanvasRenderer, TitleComponent, TooltipComponent, GridComponent, BarChart, LineChart]
22
+);
23
+
24
+export default echarts;

+ 18
- 19
src/components/ECharts/index.jsx View File

@@ -1,26 +1,15 @@
1
-// echarts 包太大, 因此需要按需引入
2
-import React, { useEffect, useRef, useImperativeHandle } from 'react';
3
-// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
4
-import * as echarts from 'echarts/core';
5
-// 引入柱状图图表,图表后缀都为 Chart
6
-import {
7
-    BarChart
8
-} from 'echarts/charts';
9
-// 引入提示框,标题,直角坐标系组件,组件后缀都为 Component
10
-import {
11
-    TitleComponent,
12
-    TooltipComponent,
13
-    GridComponent
14
-} from 'echarts/components';
15 1
 
16
-// 注册必须的组件
17
-echarts.use(
18
-  [TitleComponent, TooltipComponent, GridComponent, BarChart]
19
-);
2
+import React, { useEffect, useRef, useImperativeHandle } from 'react';
3
+import echarts from './echarts';
20 4
 
21 5
 export default React.forwardRef((props, ref) => {
22 6
   const el = useRef()
23 7
   const chartRef = useRef()
8
+  const style = {
9
+    width: props.width || '480px',
10
+    height: props.height || '360px',
11
+    ...props.style || {}
12
+  }
24 13
 
25 14
   // 向父组件公开 echarts 实例
26 15
   useImperativeHandle(ref, () => ({
@@ -35,5 +24,15 @@ export default React.forwardRef((props, ref) => {
35 24
     return () => chart.dispose()
36 25
   }, [props.option])
37 26
 
38
-  return <div ref={el}></div>
27
+  useEffect(() => {
28
+    if (chartRef.current) {
29
+      if (props.loading) {
30
+        chartRef.current.showLoading()
31
+      } else {
32
+        chartRef.current.hideLoading()
33
+      }
34
+    }
35
+  }, [props.loading])
36
+
37
+  return <div ref={el} style={style}></div>
39 38
 })

+ 20
- 0
src/components/ECharts/utils.js View File

@@ -0,0 +1,20 @@
1
+
2
+// source 合并到 target 上面, 并且会替换 target 同属性部分
3
+export function assignOption (target, source) {
4
+  const rtn = {...target}
5
+  Object.keys(source).forEach((key) => {
6
+    const val = source[key]
7
+    const origin = rtn[key]
8
+    if (typeof val === 'object') {
9
+      if (typeof origin === 'object') {
10
+        rtn[key] = assignOption(origin, val)
11
+      } else {
12
+        rtn[key] = val
13
+      }
14
+    } else {
15
+      rtn[key] = val
16
+    }
17
+  })
18
+
19
+  return rtn
20
+}

+ 94
- 0
src/pages/Welcome/components/LineCard.jsx View File

@@ -0,0 +1,94 @@
1
+import React, { useEffect, useRef, useState } from 'react'
2
+import moment from 'moment';
3
+import { Card, DatePicker } from 'antd';
4
+import ECharts from '@/components/ECharts'
5
+import echarts from '@/components/ECharts/echarts'
6
+import { assignOption } from '@/components/ECharts/utils'
7
+import request from '@/utils/request'
8
+import Title from './Title'
9
+
10
+const lineOption = {
11
+  xAxis: {
12
+    type: 'category',
13
+  },
14
+  yAxis: {
15
+    type: 'value'
16
+  },
17
+  series: {
18
+    type: 'line',
19
+    areaStyle: {
20
+      opacity: 0.8,
21
+      color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
22
+          offset: 0,
23
+          color: 'rgba(55, 162, 255)'
24
+      }, {
25
+          offset: 1,
26
+          color: 'rgba(1, 191, 236)'
27
+      }])
28
+    },
29
+    smooth: true,
30
+    lineStyle: {
31
+      width: 0
32
+    }
33
+  }
34
+}
35
+
36
+const Condition = (props) => (
37
+  <DatePicker.RangePicker value={props.value} onChange={props.onChange}/>
38
+)
39
+
40
+export default (props) => {
41
+  const chartRef = useRef()
42
+  const [loading, setLoading] = useState(false)
43
+  const [data, setData] = useState([])
44
+  const [option, setOption] = useState(lineOption)
45
+  const [dtRange, setDtRange] = useState([    
46
+    moment().subtract(30, 'days'),
47
+    moment(),
48
+  ])
49
+  const [params, setParams] = useState()
50
+
51
+  useEffect(() => {
52
+    setParams({
53
+      startDate: dtRange[0].format('YYYY-MM-DD'),      
54
+      endDate: dtRange[1].format('YYYY-MM-DD')
55
+    })
56
+  }, [dtRange])
57
+  
58
+  useEffect(() => {
59
+    if (params) {
60
+      setLoading(true)
61
+      request(props.api, { params }).then(res => {
62
+        setData(res)
63
+        setLoading(false)
64
+      }).catch(() => {
65
+        setLoading(false)
66
+      })
67
+    }
68
+  }, [params, props.api])
69
+
70
+  useEffect(() => {
71
+    const opt = assignOption(lineOption, {
72
+      xAxis: {
73
+        data: data.map((item) => item.dt)
74
+      },
75
+      series: {
76
+        data: data.map((item) => item.val)
77
+      }
78
+    })
79
+
80
+    setOption(opt)
81
+  }, [data])
82
+
83
+  return (
84
+    <Card
85
+      title={<Title text={props.title} icon={props.icon} />}
86
+      extra={<Condition value={dtRange} onChange={(vals) => setDtRange(vals)} />}
87
+      style={props.style}
88
+    >
89
+      <div style={{ margin: '0 auto', width: props.width || '100%'}}>
90
+        <ECharts loading={loading} ref={chartRef} option={option} width={props.width || '100%'} />
91
+      </div>
92
+    </Card>
93
+  )
94
+}

+ 23
- 0
src/pages/Welcome/components/NavCard.jsx View File

@@ -0,0 +1,23 @@
1
+import React from 'react'
2
+import { Card, Avatar } from 'antd'
3
+import { Link  } from 'umi';
4
+
5
+export default (props) => {
6
+  const style= {
7
+    color: '#fff',
8
+    background: props.color,
9
+    height: props.height || '120px'
10
+  }
11
+
12
+  return (
13
+    <Link to={props.link}>
14
+      <Card style={style}>
15
+        <Card.Meta
16
+          avatar={props.icon}
17
+          title={props.title}
18
+          description={props.description}
19
+        />
20
+      </Card>
21
+    </Link>
22
+  )
23
+}

+ 9
- 0
src/pages/Welcome/components/Title.jsx View File

@@ -0,0 +1,9 @@
1
+import React from 'react';
2
+import { Space } from 'antd';
3
+
4
+export default (props) => (
5
+  <Space>
6
+    {props.icon}
7
+    <div>{props.text}</div>
8
+  </Space>
9
+)

+ 48
- 49
src/pages/Welcome/index.jsx View File

@@ -1,9 +1,20 @@
1 1
 import React from 'react';
2 2
 import { PageContainer } from '@ant-design/pro-layout';
3
-import { Card, Alert, Typography } from 'antd';
3
+import { Card, Row, Col, Space, Button } from 'antd';
4
+import { LineChartOutlined, UserOutlined, ReadOutlined, BranchesOutlined } from '@ant-design/icons';
4 5
 // import { useIntl, FormattedMessage } from 'umi';
5 6
 import HeaderContent from './components/HeaderContent';
6
-import styles from './style.less';
7
+import LineCard from './components/LineCard';
8
+import NavCard from './components/NavCard';
9
+
10
+const navIconStyle = {
11
+  fontSize: '5em',
12
+  color: 'rgba(0, 0, 0, 0.04)'
13
+}
14
+
15
+const Text = (props) => (
16
+  <span style={{ color: props.color }}>{props.children}</span>
17
+)
7 18
 
8 19
 export default () => {
9 20
   // const intl = useIntl();
@@ -14,53 +25,41 @@ export default () => {
14 25
       }}
15 26
       content={<HeaderContent />}
16 27
     >
17
-      <Card>
18
-        <Alert
19
-          // message={intl.formatMessage({
20
-          //   id: 'pages.welcome.alertMessage',
21
-          //   defaultMessage: '更快更强的重型组件,已经发布。',
22
-          // })}
23
-          message="更快更强的重型组件,已经发布。"
24
-          type="success"
25
-          showIcon
26
-          banner
27
-          style={{
28
-            margin: -12,
29
-            marginBottom: 24,
30
-          }}
31
-        />
32
-        <Typography.Text strong>
33
-          {/* <FormattedMessage id="pages.welcome.advancedComponent" defaultMessage="高级表格" /> */}
34
-          高级表格{' '}
35
-          <a
36
-            href="https://procomponents.ant.design/components/table"
37
-            rel="noopener noreferrer"
38
-            target="__blank"
39
-          >
40
-            {/* <FormattedMessage id="pages.welcome.link" defaultMessage="欢迎使用" /> */}
41
-            欢迎使用
42
-          </a>
43
-        </Typography.Text>
44
-    
45
-        <Typography.Text
46
-          strong
47
-          style={{
48
-            marginBottom: 12,
49
-          }}
50
-        >
51
-          {/* <FormattedMessage id="pages.welcome.advancedLayout" defaultMessage="高级布局" /> */}
52
-          高级布局{' '}
53
-          <a
54
-            href="https://procomponents.ant.design/components/layout"
55
-            rel="noopener noreferrer"
56
-            target="__blank"
57
-          >
58
-            {/* <FormattedMessage id="pages.welcome.link" defaultMessage="欢迎使用" /> */}
59
-            欢迎使用
60
-          </a>
61
-        </Typography.Text>
62
-
63
-      </Card>
28
+      <Row gutter={24}>
29
+        <Col span={8}>
30
+          <NavCard
31
+            link="/student/student"
32
+            title={<Text color="rgba(255, 255, 255, .95)">学生管理</Text>}
33
+            color="#389e0d"
34
+            icon={<UserOutlined style={navIconStyle} />}
35
+          />
36
+        </Col>
37
+        <Col span={8}>
38
+          <NavCard
39
+            link="/post/list"
40
+            title={<Text color="rgba(255, 255, 255, .95)">科普管理</Text>}
41
+            color="#d48806"
42
+            icon={<ReadOutlined style={navIconStyle} />}
43
+          />
44
+        </Col>
45
+        <Col span={8}>
46
+          <NavCard
47
+            link="/medical/visit"
48
+            title={<Text color="rgba(255, 255, 255, .95)">就诊管理</Text>}
49
+            color="#08979c"
50
+            icon={<BranchesOutlined style={navIconStyle} />}
51
+          />
52
+        </Col>
53
+      </Row>
54
+      
55
+      <Row gutter={16} style={{ marginTop: '1.5em' }}>
56
+        <Col span={12}>
57
+          <LineCard icon={<LineChartOutlined />} title="科普浏览量统计" api="/index/post-pv" />
58
+        </Col>
59
+        <Col span={12}>
60
+          <LineCard icon={<LineChartOutlined />} title="学生阅读数统计" api="/index/post-uv" />
61
+        </Col>
62
+      </Row>
64 63
     </PageContainer>
65 64
   );
66 65
 };