张延森 4 년 전
부모
커밋
07ee462e34

+ 1
- 1
config/routes.js 파일 보기

@@ -25,7 +25,7 @@ export default [
25 25
           {
26 26
             path: '/index',
27 27
             name: '首页',
28
-            component: './Index',
28
+            component: './dashboard',
29 29
           },
30 30
           // {
31 31
           //   path: '/',

+ 11
- 0
src/pages/dashboard/components/ABPart.jsx 파일 보기

@@ -0,0 +1,11 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Row, Col } from 'antd'
3
+
4
+export default props => {
5
+  return (
6
+    <Row type="flex" align={props.align || "top"} justify="space-around" gutter={24}>
7
+      <Col span={16}>{props.a}</Col>
8
+      <Col span={8}>{props.b}</Col>
9
+    </Row>
10
+  )
11
+}

+ 35
- 0
src/pages/dashboard/components/BuildingStatic.jsx 파일 보기

@@ -0,0 +1,35 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Row, Col, Statistic, Icon, Spin } from 'antd'
3
+import { apis, fetch } from '@/utils/request'
4
+
5
+const getHouseVerified = fetch(apis.dashboard.houseVerified)
6
+
7
+export default props => {
8
+  const [loading, setLoading] = useState({})
9
+  const [data, setData] = useState({})
10
+
11
+  useEffect(() => {
12
+    setLoading(true)
13
+    getHouseVerified().then(res => {
14
+      setData(res)
15
+      setLoading(false)
16
+    }).catch(e => console.error(e) || setLoading(false))
17
+  }, [])
18
+
19
+
20
+  return (
21
+    <Spin spinning={loading}>
22
+      <Row gutter={16}>
23
+        <Col span={4}>
24
+          {/* <Statistic title={<div><Icon type="bell" style={{fontSize: '1.2em'}} /> 工单 </div>} value={112893} /> */}
25
+        </Col>
26
+        <Col span={10}>
27
+          <Statistic title={<div><Icon type="home" style={{fontSize: '1.2em'}} /> 已认证(户) </div>} value={data.valid} />
28
+        </Col>
29
+        <Col span={10}>
30
+          <Statistic title={<div><Icon type="home" style={{fontSize: '1.2em'}} /> 未认证(户) </div>} value={data.total - data.valid} />
31
+        </Col>
32
+      </Row>
33
+    </Spin>
34
+  )
35
+}

+ 69
- 0
src/pages/dashboard/components/CommAlert.jsx 파일 보기

@@ -0,0 +1,69 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Card, Alert, Icon } from 'antd'
3
+import { fetch, apis } from '@/utils/request'
4
+import Link from 'umi/link'
5
+
6
+const getTips = fetch(apis.dashboard.tips)
7
+
8
+export default props => {
9
+  const [loading, setLoading] = useState(false)
10
+  const [data, setData] = useState({})
11
+
12
+  useEffect(() => {
13
+    setLoading(true)
14
+    getTips().then(res => {
15
+      setData(res)
16
+      setLoading(false)
17
+    }).catch(e => console.error(e) || setLoading(false))
18
+  }, [])
19
+
20
+  const ticket = data.ticketNum ? `您有 ${data.ticketNum} 个待处理工单, 点击处理` : '暂无未处理工单'
21
+  const verify = data.verifyNum ? `您有 ${data.verifyNum} 条待审核记录, 点击处理` : '暂无业主申请'
22
+  const exchange = data.exchangeNum ? `累计有 ${data.exchangeNum} 条兑换记录, 点击查看` : '暂兑换记录'
23
+  const enlistNum = data.enlistNum && data.enlistNum.dynamicId ? `总计 ${data.enlistNum.num} 人报名参与 ${data.enlistNum.title} 活动, 点击查看` : '暂进行中活动'
24
+
25
+  return (
26
+    <Card title="日常工作" bordered={false} loading={loading}>
27
+      <Link to="/property/ticket">
28
+        <Alert
29
+          message="工单报修"
30
+          description={ticket}
31
+          type="success"
32
+          showIcon
33
+          icon={<Icon type="snippets" />}
34
+          style={{marginBottom: 16}}
35
+        />
36
+      </Link>
37
+      <Link to="/property/proprietor/audit">
38
+        <Alert
39
+          message="业主审核"
40
+          description={verify}
41
+          type="info"
42
+          showIcon
43
+          icon={<Icon type="user-add" />}
44
+          style={{marginBottom: 16}}
45
+        />
46
+      </Link>
47
+      <Link to="/integralMall/exchangeRecords">
48
+        <Alert
49
+          message="商品兑换"
50
+          description={exchange}
51
+          type="warning"
52
+          showIcon
53
+          icon={<Icon type="gift" />}
54
+          style={{marginBottom: 16}}
55
+        />
56
+      </Link>
57
+      <Link to={data.enlistNum && data.enlistNum.dynamicId ? `/activity/detailActivity?dynamicId=${data.enlistNum.dynamicId}` : '/activity/ActivityList'}>
58
+        <Alert
59
+          message="活动报名"
60
+          description={enlistNum}
61
+          type="error"
62
+          showIcon
63
+          icon={<Icon type="crown" />}
64
+          // style={{marginBottom: 16}}
65
+        />
66
+      </Link>
67
+    </Card>
68
+  )
69
+}

+ 72
- 0
src/pages/dashboard/components/ScrollAlert.jsx 파일 보기

@@ -0,0 +1,72 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Card, Carousel, Row, Col } from 'antd'
3
+import moment from 'moment'
4
+import { orderBy } from 'lodash'
5
+import { fetch, apis } from '@/utils/request'
6
+
7
+const getDynamic = fetch(apis.dashboard.dynamic)
8
+
9
+const Item = props => (
10
+  <Row gutter={24} type="flex" align="middle" style={{ marginTop: 8, marginBottom: 8 }}>
11
+    <Col span={8}>{props.dataSource.createDate}</Col>
12
+    <Col span={16}>{`${props.dataSource.nickname} ${props.dataSource.desc}`}</Col>
13
+  </Row>
14
+)
15
+
16
+export default props => {
17
+  const [loading, setLoading] = useState(false)
18
+  const [list, setList] = useState([])
19
+  const [showSlides, setShowSlides] = useState(0)
20
+
21
+  useEffect(() => {
22
+    const today = moment()
23
+    // 取最近 15 天的记录
24
+    const endDate = today.format('YYYY-MM-DD')
25
+    today.subtract(15, 'days')
26
+    const startDate = today.format('YYYY-MM-DD')
27
+
28
+    setLoading(true)
29
+    getDynamic({params: {startDate, endDate}}).then(res => {
30
+      const { ticketList, propList, billList } = res
31
+
32
+      // 组合list
33
+      const compList = [
34
+        ...(ticketList || []).map(x => ({...x, createDate: moment(x.createDate).format('YYYY-MM-DD HH:mm'), desc: '提了一个工单'})),
35
+        ...(propList || []).map(x => ({...x, createDate: moment(x.createDate).format('YYYY-MM-DD HH:mm'), desc: '申请了一个业主认证'})),
36
+        ...(billList || []).map(x => ({...x, createDate: moment(x.createDate).format('YYYY-MM-DD HH:mm'), desc: '缴了一笔费用'})),
37
+      ]
38
+      
39
+      if (compList.length === 0) {
40
+        setShowSlides(0)
41
+      } else {
42
+        setShowSlides(compList.length > 10 ? 10 : compList.length - 1)
43
+      }
44
+
45
+      // 按照时间倒叙
46
+      const newList = orderBy(compList, ['createDate'], ['desc'])
47
+      setList(newList)
48
+
49
+      setLoading(false)
50
+    }).catch(e => console.error(e) || setLoading(false))
51
+
52
+  }, [])
53
+
54
+  return (
55
+    <Card title="最新动态" loading={loading}>
56
+      <Carousel
57
+        dots={false}
58
+        autoplay={true}
59
+        lazyLoad={true}
60
+        infinite={true}
61
+        speed={500}
62
+        slidesToShow={showSlides}
63
+        slidesToScroll={1}
64
+        dotPosition="right"
65
+      >
66
+        {
67
+          list.map(x => <Item key={x.createDate} dataSource={x} />)
68
+        }
69
+      </Carousel>
70
+    </Card>
71
+  )
72
+}

+ 81
- 0
src/pages/dashboard/components/ShortCut.jsx 파일 보기

@@ -0,0 +1,81 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Card, Row, Col, Icon, Spin } from 'antd'
3
+import moment from 'moment'
4
+import Link from 'umi/link'
5
+import { fetch, apis } from '@/utils/request'
6
+import ABPart from './ABPart'
7
+
8
+const Title = props => <div> <Icon type={props.icon} style={{color: props.color, fontSize: '1.2em'}} /> <span style={{display: 'inline-block', marginLeft: 8}}>{props.children}</span></div>
9
+const StatNum = props => <Spin spinning={props.loading}><div style={{textAlign: 'center'}}><span style={{fontSize: '2em'}}>{props.value}</span> {props.unit}</div></Spin>
10
+
11
+const getStatis = fetch(apis.dashboard.statis)
12
+
13
+export default props => {
14
+  const [loading, setLoading] = useState(false)
15
+  const [data, setData] = useState({})
16
+
17
+  useEffect(() => {
18
+    const today = moment()
19
+    // 当月第一天
20
+    const startDate = today.format('YYYY-MM-01')
21
+
22
+    // 当月最后一天,
23
+    // 因为当前日期是业务数据最大值, 因此当天的数据跟月末是一致的
24
+    const endDate = today.format(`YYYY-MM-DD`)
25
+
26
+    setLoading(true)
27
+    getStatis({params: {startDate, endDate}}).then(res => {
28
+      setData(res)
29
+      setLoading(false)
30
+    }).catch(er => setLoading(false))
31
+  }, [])
32
+
33
+  return (
34
+    <Row gutter={24}>
35
+      <Col span={6}>
36
+        <Link to="/property/buildingInfo">
37
+          <Card title={false}>
38
+            <ABPart
39
+              align="middle"
40
+              a={<Title icon="home" color="#f50">楼栋管理</Title>}
41
+              b={<StatNum loading={loading} value={data.buildingNum} unit="栋" />}
42
+            />
43
+          </Card>
44
+        </Link>
45
+      </Col>
46
+      <Col span={6}>
47
+        <Link to="/property/proprietor">
48
+          <Card title={false}>
49
+            <ABPart
50
+              align="middle"
51
+              a={<Title icon="user" color="#2db7f5">业主管理</Title>}
52
+              b={<StatNum loading={loading} value={data.propNum} unit="人" />}
53
+            />
54
+          </Card>
55
+        </Link>
56
+      </Col>
57
+      <Col span={6}>
58
+        <Link to="/property/bill/management">
59
+          <Card title={false}>
60
+            <ABPart
61
+              align="middle"
62
+              a={<Title icon="bank" color="#87d068">缴费管理(本月)</Title>}
63
+              b={<StatNum loading={loading} value={data.houseNum} unit="单" />}
64
+            />
65
+          </Card>
66
+        </Link>
67
+      </Col>
68
+      <Col span={6}>
69
+        <Link to="/property/bill/ticket">
70
+          <Card title={false}>
71
+            <ABPart
72
+              align="middle"
73
+              a={<Title icon="bell" color="#108ee9">工单管理(本月)</Title>}
74
+              b={<StatNum loading={loading} value={data.ticketNum} unit="条" />}
75
+            />
76
+          </Card>
77
+        </Link>
78
+      </Col>
79
+    </Row>
80
+  )
81
+}

+ 45
- 0
src/pages/dashboard/index.jsx 파일 보기

@@ -0,0 +1,45 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { PageHeader, Row, Col, Card, Icon } from 'antd'
3
+import ABPart from './components/ABPart'
4
+import BuildingStatic from './components/BuildingStatic'
5
+import ShortCut from './components/ShortCut'
6
+import CommAlert from './components/CommAlert'
7
+import ScrollAlert from './components/ScrollAlert'
8
+
9
+export default props => {
10
+  // const [] = useState()
11
+
12
+
13
+  // useEffect(() => {
14
+
15
+  // }, [])
16
+
17
+  const randText = `精铸致远,盛道自来。
18
+  今天的远道集团,以卓越的产品和服务创造高品质生活与理想工作为使命,建设家园,服务社会,创造美好生活。
19
+  我们相信,致远需要我们时刻创新奋进,而盛道的来临也正因为我们每一天为创造美好而不懈的努力!`
20
+
21
+  return (
22
+    <div>
23
+      <PageHeader
24
+        title="工作台"
25
+        backIcon={false}
26
+        ghost={false}
27
+      >
28
+        <ABPart
29
+          align="middle"
30
+          a={<div style={{verticalAlign: 'center'}}><p>管理员您好, 祝您开心每一天! </p><p>{randText}</p></div>}
31
+          b={<BuildingStatic />}
32
+        />
33
+      </PageHeader>
34
+
35
+      <div style={{marginTop: 24}}><ShortCut /></div>
36
+      
37
+      <div style={{marginTop: 24}}>
38
+        <ABPart
39
+          a={<CommAlert />}
40
+          b={<ScrollAlert />}
41
+        />
42
+      </div>
43
+    </div>
44
+  )
45
+}

+ 2
- 0
src/services/apis.js 파일 보기

@@ -5,6 +5,7 @@ import propUser from './prop_user_api'
5 5
 import announcement from './announcement_api'
6 6
 import ticket from './ticket_api'
7 7
 import propNews from './prop_news_api'
8
+import dashboard from './dashboard_api'
8 9
 
9 10
 const prefix = `${APIBaseURL}api/admin`
10 11
 
@@ -19,6 +20,7 @@ export default {
19 20
   announcement: announcement(prefix),
20 21
   ticket: ticket(prefix),
21 22
   propNews: propNews(prefix),
23
+  dashboard: dashboard(prefix),
22 24
   mp: {
23 25
     detail: {
24 26
       url: `${prefix}/taMpInfo`,

+ 25
- 0
src/services/dashboard_api.js 파일 보기

@@ -0,0 +1,25 @@
1
+
2
+export default prefix => {
3
+  return {
4
+    statis: {
5
+      url: `${prefix}/dashboard/statis`,
6
+      method: 'get',
7
+      action: `admin.dashboard.statis`
8
+    },
9
+    dynamic: {
10
+      url: `${prefix}/dashboard/dynamic`,
11
+      method: 'get',
12
+      action: `admin.dashboard.dynamic`
13
+    },
14
+    houseVerified: {
15
+      url: `${prefix}/dashboard/house-verified`,
16
+      method: 'get',
17
+      action: `admin.dashboard.house-verified`
18
+    },
19
+    tips: {
20
+      url: `${prefix}/dashboard/tips`,
21
+      method: 'get',
22
+      action: `admin.dashboard.tips`
23
+    }
24
+  }
25
+}