Your Name před 3 roky
rodič
revize
27f3e891fd

+ 36
- 0
src/components/Chart/index.jsx Zobrazit soubor

@@ -0,0 +1,36 @@
1
+import React, { useEffect, useRef, useMemo } from 'react'
2
+import * as echarts from '@/native/ec-canvas/echarts';
3
+
4
+function initChart(canvas, width, height, dpr) {
5
+  const chart = echarts.init(canvas, null, {
6
+    width: width,
7
+    height: height,
8
+    devicePixelRatio: dpr // new
9
+  });
10
+  canvas.setChart(chart);
11
+  return chart;
12
+}
13
+
14
+export default (props) => {
15
+  const { options } = props
16
+  const chartRef = useRef()
17
+  const ec = useMemo(() => {
18
+    const onInit = (...args) => {
19
+      const chart = initChart(...args)
20
+      chartRef.current = chart
21
+      return chart
22
+    }
23
+
24
+    return { onInit }
25
+  }, [])
26
+
27
+  useEffect(() => {
28
+    if (options && chartRef.current) {
29
+      chartRef.current.setOption(options);
30
+    }
31
+  }, [options])
32
+
33
+  return (
34
+    <ec-canvas ec={ec} />
35
+  )
36
+}

+ 4
- 1
src/constants/api.js Zobrazit soubor

@@ -303,5 +303,8 @@ export const API_CHANNEL_RANK = resolvePath('ranklist')
303 303
 // 获取报备客户详情
304 304
 export const API_CHANNEL_CUSTOMER_DETAIL = resolvePath('channelCustomer')
305 305
 
306
-// 获取渠道折线图
306
+// 渠道-折线图
307 307
 export const API_CHANNEL_LINE_CHAT = resolvePath('briefing/detail')
308
+
309
+// 渠道-销售简报
310
+export const API_CHANNEL_STAT_REPORT = resolvePath('briefing')

+ 27
- 101
src/pages/mine/partnerChannel/components/LineChat.jsx Zobrazit soubor

@@ -1,111 +1,37 @@
1
-import React, { useEffect, useRef, useState, useMemo } from 'react'
2
-import Taro from '@tarojs/taro'
3
-import * as echarts from '@/native/ec-canvas/echarts';
4
-import { getChannelLineChat } from '@/services/agent'
5
-
6
-function initChart(canvas, width, height, dpr) {
7
-  const chart = echarts.init(canvas, null, {
8
-    width: width,
9
-    height: height,
10
-    devicePixelRatio: dpr // new
11
-  });
12
-  canvas.setChart(chart);
13
-
14
-  // var option = {
15
-  //   xAxis: {
16
-  //     type: 'category',
17
-  //     boundaryGap: false,
18
-  //     data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
19
-  //     // show: false
20
-  //   },
21
-  //   yAxis: {
22
-  //     x: 'center',
23
-  //     type: 'value',
24
-  //     splitLine: {
25
-  //       lineStyle: {
26
-  //         type: 'dashed'
27
-  //       }
28
-  //     }
29
-  //     // show: false
30
-  //   },
31
-  //   series: [{
32
-  //     name: 'A',
33
-  //     type: 'line',
34
-  //     smooth: true,
35
-  //     data: [18, 36, 65, 30, 78, 40, 33]
36
-  //   }, {
37
-  //     name: 'B',
38
-  //     type: 'line',
39
-  //     smooth: true,
40
-  //     data: [12, 50, 51, 35, 70, 30, 20]
41
-  //   }, {
42
-  //     name: 'C',
43
-  //     type: 'line',
44
-  //     smooth: true,
45
-  //     data: [10, 30, 31, 50, 40, 20, 10]
46
-  //   }]
47
-  // };
48
-
49
-  // chart.setOption(option);
50
-  return chart;
51
-}
1
+import React, { useEffect, useState } from 'react'
2
+import Chart from '@/components/Chart'
52 3
 
53 4
 export default (props) => {
54
-  const { buildingId, xType, dateRange } = props
5
+  const { dataSource } = props
55 6
 
56 7
   const [options, setOptions] = useState()
57
-  const chartRef = useRef()
58
-  const ec = useMemo(() => {
59
-    const onInit = (...args) => {
60
-      const chart = initChart(...args)
61
-      chartRef.current = chart
62
-      return chart
63
-    }
64
-
65
-    return { onInit }
66
-  }, [])
67
-
68
-  useEffect(() => {
69
-    if (buildingId) {
70
-      const [startDate, endDate] = dateRange
71
-      getChannelLineChat({
72
-        buildingId,
73
-        type: xType,
74
-        startDate: `${startDate}T00:00:00.000Z`,
75
-        endDate: `${endDate}T23:59:59.999Z`,
76
-      }).then((res) => {
77
-        const { newCustomerDetail } = res
78
-        const data = [[],[]];
79
-        (newCustomerDetail || []).forEach((it) => {
80
-          data[0].push(it.coordinate.substring(5))
81
-          data[1].push(it.customerNum)
82
-        })
83
-        setOptions({
84
-          xAxis: {
85
-            type: 'category',
86
-            data: data[0],
87
-          },
88
-          yAxis: {
89
-            type: 'value',
90
-          },
91
-          series: [{
92
-            type: 'line',
93
-            smooth: true,
94
-            data: data[1],
95
-          }],
96
-          color: ['#5470c6'],
97
-        })
98
-      })
99
-    }
100
-  }, [buildingId, dateRange, xType])
101 8
 
102 9
   useEffect(() => {
103
-    if (options) {
104
-      chartRef.current.setOption(options);
105
-    }
106
-  }, [options])
10
+    const data = [[],[]];
11
+    (dataSource || []).forEach((it) => {
12
+      const dt = it.coordinate.length >= 10 ? it.coordinate.substring(5) : it.coordinate
13
+
14
+      data[0].push(dt)
15
+      data[1].push(it.customerNum)
16
+    })
17
+    setOptions({
18
+      xAxis: {
19
+        type: 'category',
20
+        data: data[0],
21
+      },
22
+      yAxis: {
23
+        type: 'value',
24
+      },
25
+      series: [{
26
+        type: 'line',
27
+        smooth: true,
28
+        data: data[1],
29
+      }],
30
+      color: ['#5470c6'],
31
+    });
32
+  }, [dataSource])
107 33
 
108 34
   return (
109
-    <ec-canvas ec={ec} />
35
+    <Chart options={options} />
110 36
   )
111 37
 }

+ 28
- 0
src/pages/mine/partnerChannel/hooks/useChart.js Zobrazit soubor

@@ -0,0 +1,28 @@
1
+import { useState, useEffect } from 'react'
2
+import { getChannelLineChat } from '@/services/agent'
3
+import { fillTime, cutDays, cutMonths } from '../utils'
4
+
5
+const now = new Date()
6
+
7
+export default function useReport(buildingId) {
8
+  const [statType, setStatType] = useState('day')
9
+  const [custType, setCustType] = useState('new')
10
+  const [chartData, setChartData] = useState([])
11
+
12
+  useEffect(() => {
13
+    if (buildingId) {
14
+      const startDate = statType === 'month' ? cutMonths(now, 6) : cutDays(now, 7)
15
+      getChannelLineChat({
16
+        buildingId,
17
+        type: statType,
18
+        customerType: custType,
19
+        startDate: fillTime(startDate.toJSON().substring(0, 10), true),
20
+        endDate: fillTime(now.toJSON().substring(0, 10), false),
21
+      }).then((res) => {
22
+        setChartData(res || [])
23
+      })
24
+    }
25
+  }, [buildingId, statType, custType])
26
+
27
+  return [statType, setStatType, custType, setCustType, chartData]
28
+}

+ 25
- 0
src/pages/mine/partnerChannel/hooks/useRank.js Zobrazit soubor

@@ -0,0 +1,25 @@
1
+import { useState, useEffect } from 'react'
2
+import { getChannelRank } from '@/services/agent'
3
+import { fillTime } from '../utils'
4
+
5
+const now = new Date()
6
+
7
+export default function useRank(buildingId) {
8
+  const [rankDateRange, setRankDateRange] = useState([now.toJSON().substring(0, 10), now.toJSON().substring(0, 10)])
9
+  const [rankList, setRankList] = useState([])
10
+
11
+  useEffect(() => {
12
+    if (buildingId) {
13
+      const [startDate, endDate] = rankDateRange
14
+      getChannelRank({
15
+        buildingId,
16
+        startDate: fillTime(startDate, true),
17
+        endDate: fillTime(endDate, false),
18
+      }).then((res) => {
19
+        setRankList(res || [])
20
+      })
21
+    }
22
+  }, [buildingId, rankDateRange])
23
+
24
+  return [rankDateRange, setRankDateRange, rankList]
25
+}

+ 25
- 0
src/pages/mine/partnerChannel/hooks/useReport.js Zobrazit soubor

@@ -0,0 +1,25 @@
1
+import { useState, useEffect } from 'react'
2
+import { getChannelStatReport } from '@/services/agent'
3
+import { fillTime } from '../utils'
4
+
5
+const now = new Date()
6
+
7
+export default function useReport(buildingId) {
8
+  const [reportDateRange, setReportDateRange] = useState([now.toJSON().substring(0, 10), now.toJSON().substring(0, 10)])
9
+  const [reportInfo, setReportInfo] = useState({})
10
+
11
+  useEffect(() => {
12
+    if (buildingId) {
13
+      const [startDate, endDate] = reportDateRange
14
+      getChannelStatReport({
15
+        buildingId,
16
+        startDate: fillTime(startDate, true),
17
+        endDate: fillTime(endDate, false),
18
+      }).then((res) => {
19
+        setReportInfo(res || {})
20
+      })
21
+    }
22
+  }, [buildingId, reportDateRange])
23
+
24
+  return [reportDateRange, setReportDateRange, reportInfo]
25
+}

+ 28
- 48
src/pages/mine/partnerChannel/index.jsx Zobrazit soubor

@@ -1,34 +1,43 @@
1 1
 import React, { useState, useEffect, useRef } from 'react'
2 2
 import withLayout from '@/layout'
3
+import Taro from '@tarojs/taro'
3 4
 import { ScrollView, Image } from '@tarojs/components'
4
-import { getChannelRank } from '@/services/agent'
5
+import { getChannelRank, getChannelStatReport } from '@/services/agent'
5 6
 import { fetch } from '@/utils/request'
6 7
 import { API_GET_AGENT_BUILDINGS } from '@/constants/api'
7
-import {  } from '@/constants/user'
8
+// import {  } from '@/constants/user'
8 9
 import DateRangePicker from '@/components/DateRangePicker'
9 10
 import Picker from '@/components/Picker'
10 11
 import LineChat from './components/LineChat'
12
+import useRank from './hooks/useRank'
13
+import useReport from './hooks/useReport'
14
+import useChart from './hooks/useChart'
11 15
 // import '@/assets/css/iconfont.css'
12 16
 import './index.scss'
13 17
 
14
-const lineXDicts = [
18
+const statTypeDicts = [
15 19
   {name: '按天', id: 'day'},
16 20
   {name: '按月', id: 'month'},
17 21
 ]
18
-
19
-const padMonth = m => m > 9 ? m : `0${m}`
22
+const custTypeDicts = [
23
+  {name: '新增人员', id: 'new'},
24
+  {name: '跟进', id: 'follow'},
25
+  {name: '成交', id: 'success'},
26
+]
20 27
 
21 28
 export default withLayout((props) => {
22 29
   
23 30
   const [showPicker, setShowPicker] = useState(false)
24
-  const [rankDateRange, setRankDateRange] = useState([])
25
-  const [reportDateRange, setReportDateRange] = useState([])
31
+  const pickerTrigger = useRef()
26 32
   const [buildingId, setBuildingId] = useState()
27 33
   const [buildingList, setBuildingList] = useState([])
28
-  const [rankList, setRankList] = useState([])
29
-  const [lineXType, setLineXType] = useState('day')
30
-  const [lingeDateRange, seteLineDateRange] = useState([])
31
-  const pickerTrigger = useRef()
34
+  const [,setRankDateRange, rankList] = useRank(buildingId)
35
+  const [,setReportDateRange, reportInfo] = useReport(buildingId)
36
+  const [statType, setStatType, custType, setCustType, chartData] = useChart(buildingId)
37
+
38
+  const handleMore = () => {
39
+    Taro.navigateTo({ url: '/pages/mine/myCustomer/index' })
40
+  }
32 41
 
33 42
   const handleRankDate = () => {
34 43
     pickerTrigger.current = 'rank'
@@ -60,35 +69,6 @@ export default withLayout((props) => {
60 69
     })
61 70
   }, [])
62 71
 
63
-  useEffect(() => {
64
-    if (buildingId) {
65
-      getChannelRank({buildingId}).then((res) => {
66
-        setRankList(res || [])
67
-      })
68
-    }
69
-  }, [buildingId])
70
-
71
-  useEffect(() => {
72
-    const now = new Date()
73
-    const endDay = now.toJSON().substring(0, 10)
74
-    if (lineXType === 'day') {
75
-      const cutDay = 7 * 24 * 60 * 60 * 1000
76
-      const start = new Date(now - cutDay)
77
-      seteLineDateRange([start.toJSON().substring(0, 10), endDay])
78
-    } else {
79
-      const cutMonth = 6
80
-      const curMonth = now.getMonth() + 1
81
-      const startMonth = curMonth - cutMonth + 1
82
-      if (startMonth <= 0) {
83
-        const startYear = now.getFullYear() - 1
84
-        seteLineDateRange([`${startYear}-${padMonth(startMonth + 12)}-01`, endDay])
85
-      } else {
86
-        seteLineDateRange([`${now.getFullYear()}-${padMonth(startMonth)}-01`, endDay])
87
-      }
88
-    }
89
-    
90
-  }, [lineXType])
91
-
92 72
   return (
93 73
     <view className='Page partnerChannel'>
94 74
       <DateRangePicker visable={showPicker} close={() => setShowPicker(false)} change={handlePickerChange} />
@@ -126,7 +106,7 @@ export default withLayout((props) => {
126 106
                     </view>
127 107
                     <view className='Num'>
128 108
                       <text></text>
129
-                      <text>{item.number}</text>
109
+                      <text>{`到访 ${item.number||0} 人`}</text>
130 110
                     </view>
131 111
                   </view>
132 112
                 ))
@@ -140,23 +120,23 @@ export default withLayout((props) => {
140 120
               <text>销售简报</text>
141 121
               <Image mode='heightFix' src={require('../../../assets/mine-icon23.png')} onClick={handleReportDate}></Image>
142 122
               <view className='flex-item'></view>
143
-              <text>更多</text>
123
+              <text onClick={handleMore}>更多</text>
144 124
               <text className='iconfont icon-jiantouright'></text>
145 125
             </view>
146 126
             <view className='List'>
147 127
               <view className='flex-h'>
148 128
                 <text className='flex-item'>新增客户</text>
149
-                <text>34人</text>
129
+                <text>{`${reportInfo.newCustomerNum||0}人`}</text>
150 130
                 <text className='iconfont icon-jiantouright'></text>
151 131
               </view>
152 132
               <view className='flex-h'>
153 133
                 <text className='flex-item'>跟进客户</text>
154
-                <text>34人</text>
134
+                <text>{`${reportInfo.followCustomerNum||0}人`}</text>
155 135
                 <text className='iconfont icon-jiantouright'></text>
156 136
               </view>
157 137
               <view className='flex-h'>
158 138
                 <text className='flex-item'>成交客户</text>
159
-                <text>34人</text>
139
+                <text>{`${reportInfo.successCustomerNum||0}人`}</text>
160 140
                 <text className='iconfont icon-jiantouright'></text>
161 141
               </view>
162 142
             </view>
@@ -168,16 +148,16 @@ export default withLayout((props) => {
168 148
               <text>销售趋势</text>
169 149
               <view className='flex-item'></view>
170 150
               <view className='Type'>
171
-                <text>新增客户</text>
151
+                <Picker kv={['name', 'id']} dicts={custTypeDicts} value={custType} onChange={setCustType} />
172 152
                 <text className='iconfont icon-sanjiaoxingdown'></text>
173 153
               </view>
174 154
               <view className='Sort'>
175
-                <Picker kv={['name', 'id']} dicts={lineXDicts} value={lineXType} onChange={setLineXType} />
155
+                <Picker kv={['name', 'id']} dicts={statTypeDicts} value={statType} onChange={setStatType} />
176 156
                 <text className='iconfont icon-sanjiaoxingdown'></text>
177 157
               </view>
178 158
             </view>
179 159
             <view className='LineChart'>
180
-              <LineChat buildingId={buildingId} xType={lineXType} dateRange={lingeDateRange} />
160
+              <LineChat dataSource={chartData} />
181 161
             </view>
182 162
           </view>
183 163
 

+ 43
- 0
src/pages/mine/partnerChannel/utils/index.js Zobrazit soubor

@@ -0,0 +1,43 @@
1
+
2
+
3
+const padMonth = m => m > 9 ? m : `0${m}`
4
+
5
+/**
6
+ * 补齐 ISO 的时间
7
+ * @param {*} dt 
8
+ * @param {*} isStart 
9
+ * @returns 
10
+ */
11
+export function fillTime(dt, isStart) {
12
+  const tm = isStart ? '00:00:00.000' : '23:59:59.999'
13
+  return `${dt}T${tm}Z`
14
+} 
15
+
16
+/**
17
+ * 日期减去天数, 并返回结果的凌晨
18
+ * @param {*} dt 
19
+ * @param {*} days 
20
+ * @returns 
21
+ */
22
+export function cutDays(dt, days) {
23
+  const ret = new Date(new Date(dt).valueOf() - days * 24 * 3600 * 1000)
24
+  return new Date(ret.toJSON().substring(0, 10))
25
+}
26
+
27
+/**
28
+ * 日期减去月数, 并返回结果月的第一天的凌晨
29
+ * @param {*} dt 
30
+ * @param {*} months 
31
+ * @returns 
32
+ */
33
+export function cutMonths(dt, months) {
34
+  const origin = new Date(dt)
35
+  const mon = origin.getMonth() + 1
36
+  const startMonth = mon - months + 1
37
+  if (startMonth <= 0) {
38
+    const startYear = origin.getFullYear() - 1
39
+    return new Date(`${startYear}-${padMonth(startMonth + 12)}-01`)
40
+  } else {
41
+    return new Date(`${origin.getFullYear()}-${padMonth(startMonth)}-01`)
42
+  }
43
+}

+ 8
- 0
src/services/agent.js Zobrazit soubor

@@ -8,6 +8,7 @@ import {
8 8
   API_EDIT_AGENT,
9 9
   API_CHANNEL_RANK,
10 10
   API_CHANNEL_LINE_CHAT,
11
+  API_CHANNEL_STAT_REPORT,
11 12
 } from '@/constants/api'
12 13
 
13 14
 
@@ -55,3 +56,10 @@ export const getChannelRank = (payload) => fetch({ url: API_CHANNEL_RANK, payloa
55 56
  * @returns 
56 57
  */
57 58
 export const getChannelLineChat = (payload) => fetch({ url: API_CHANNEL_LINE_CHAT, payload })
59
+
60
+/**
61
+ * 渠道-销售简报
62
+ * @param {*} payload 
63
+ * @returns 
64
+ */
65
+export const getChannelStatReport = (payload) => fetch({ url: API_CHANNEL_STAT_REPORT, payload })