张延森 hace 5 años
padre
commit
0720b8422a

+ 4
- 1
src/components/SelectBuilding.vue Ver fichero

@@ -1,5 +1,5 @@
1 1
 <template>
2
-  <el-select v-model="val" filterable placeholder="请选择">
2
+  <el-select v-model="val" filterable placeholder="请选择" @change="handleChange">
3 3
     <el-option
4 4
       v-for="item in buildings"
5 5
       :key="item.buildingId"
@@ -43,6 +43,9 @@ export default {
43 43
     ...mapActions([
44 44
       'getBuildings',
45 45
     ]),
46
+    handleChange(e) {
47
+      this.$emit('change', e)
48
+    }
46 49
   },
47 50
 }
48 51
 </script>

+ 7
- 1
src/components/XMSearchForm.vue Ver fichero

@@ -1,5 +1,5 @@
1 1
 <template>
2
-  <el-form :inline="true" size="small" class="search-form">
2
+  <el-form :inline="true" :size="size" class="search-form">
3 3
     <slot></slot>
4 4
     <el-form-item>
5 5
       <el-button type="primary" @click="submit">搜索</el-button>
@@ -11,6 +11,12 @@
11 11
 <script>
12 12
 export default {
13 13
   name: 'search-form',
14
+  props: {
15
+    size: {
16
+      type: String,
17
+      default: 'small',
18
+    }
19
+  },
14 20
   methods: {
15 21
     submit() {
16 22
       this.$emit('submit')

+ 32
- 7
src/config/api.js Ver fichero

@@ -345,19 +345,40 @@ const apis = {
345 345
         method:'get',
346 346
         url: `${commPrefix}/selectUserResource`
347 347
     },
348
-    newsUserCount: {
349
-        method:'get',
350
-        url: `${commPrefix}/selectNewsUserCount`
351
-    },
352 348
     userConversion: {
353 349
       method:'get',
354 350
       url: `${commPrefix}/selectConversion`
355 351
     },
356
-
352
+    userActive: {
353
+      method:'get',
354
+      url: `${commPrefix}/selectActiveUserCount`
355
+    },
357 356
     newUser: {
358 357
       method:'get',
359 358
       url: `${commPrefix}/selectNewsUserCount`
360
-    }
359
+    },
360
+    userBehavior: {
361
+      summary: {
362
+        method:'get',
363
+        url: `${commPrefix}/selectUserBehavior`
364
+      },
365
+      profile: {
366
+        method:'get',
367
+        url: `${commPrefix}/selectEventAll`
368
+      },
369
+    },
370
+    intentionUsers: {
371
+      method:'get',
372
+      url: `${commPrefix}/selectIntentionUser`
373
+    },
374
+    userSex: {
375
+      method:'get',
376
+      url: `${commPrefix}/selectSexUser`
377
+    },
378
+    userCity: {
379
+      method:'get',
380
+      url: `${commPrefix}/selectCityUser`
381
+    },
361 382
   },
362 383
   bizEvent: {
363 384
     dict: {
@@ -366,7 +387,11 @@ const apis = {
366 387
     },
367 388
     list: {
368 389
       method:'get',
369
-      url: `${commPrefix}/tdBizEventType`
390
+      url: `${commPrefix}/tdBizEvent`
391
+    },
392
+    properties: {
393
+      method:'get',
394
+      url: `${commPrefix}/taEventProperties`
370 395
     },
371 396
   }
372 397
 }

+ 149
- 30
src/store/modules/indexEcharts.js Ver fichero

@@ -5,7 +5,10 @@ export default {
5 5
   namespaced: true,
6 6
   state: {
7 7
     echartsInfo: {},
8
-    newsUserCount:{}
8
+    newsUserCount:{},
9
+    bizEvents: [],
10
+    bizEventTypes: [],
11
+    bizEventProperties: [],
9 12
   },
10 13
   mutations: {
11 14
     updateList (state, payload) {
@@ -14,12 +17,84 @@ export default {
14 17
     updateNewsUserCount (state, payload) {
15 18
       state.newsUserCount = payload
16 19
     },
20
+    updateEvents (state, payload) {
21
+      state.bizEvents = payload
22
+    },
23
+    updateEventTypes (state, payload) {
24
+      state.bizEventTypes = payload
25
+    },
26
+    updateEventProperties (state, payload) {
27
+      state.bizEventProperties = payload
28
+    },
17 29
   },
18 30
   actions: {
19 31
     setDetailNull ({ commit }) {
20 32
       commit('updateList', {})
21 33
     },
22 34
 
35
+    getBizEvents ({ state, commit }) {
36
+      if (state.bizEvents && state.bizEvents.length) {
37
+        return Promise.resolve(state.bizEvents)
38
+      }
39
+
40
+      return new Promise((resolve, reject) => {
41
+        request({
42
+          ...apis.bizEvent.list,
43
+          params: { pageSize: 9999 }
44
+        }).then((data) => {
45
+          commit('updateEvents', data.records)
46
+          resolve(data.records)
47
+        }).catch((err) => {
48
+          const message = err.message || err.msg
49
+          if (typeof message === 'string') {
50
+            reject(message)
51
+          }
52
+        })
53
+      })
54
+    },
55
+
56
+    getBizEventTypes ({ state, commit }) {
57
+      if (state.bizEventTypes && state.bizEventTypes.length) {
58
+        return Promise.resolve(state.bizEventTypes)
59
+      }
60
+
61
+      return new Promise((resolve, reject) => {
62
+        request({
63
+          ...apis.bizEvent.dict,
64
+          params: { pageSize: 9999 }
65
+        }).then((data) => {
66
+          commit('updateEventTypes', data.records)
67
+          resolve(data.records)
68
+        }).catch((err) => {
69
+          const message = err.message || err.msg
70
+          if (typeof message === 'string') {
71
+            reject(message)
72
+          }
73
+        })
74
+      })
75
+    },
76
+
77
+    getBizEventProperties ({ state, commit }, payload = {}) {
78
+      if (state.bizEventProperties && state.bizEventProperties.length) {
79
+        return Promise.resolve(state.bizEventProperties)
80
+      }
81
+
82
+      return new Promise((resolve, reject) => {
83
+        request({
84
+          ...apis.bizEvent.properties,
85
+          params: { pageSize: 9999, ...payload }
86
+        }).then((data) => {
87
+          commit('updateEventProperties', data.records)
88
+          resolve(data.records)
89
+        }).catch((err) => {
90
+          const message = err.message || err.msg
91
+          if (typeof message === 'string') {
92
+            reject(message)
93
+          }
94
+        })
95
+      })
96
+    },
97
+
23 98
     getUserConversionRate(_, payload) {
24 99
       return new Promise((resolve, reject) => {
25 100
         request({
@@ -67,34 +142,6 @@ export default {
67 142
         })
68 143
       })
69 144
     },
70
-    // changeExchangeStatus (_, payload) {
71
-    //   return new Promise((resolve, reject) => {
72
-    //     request({
73
-    //       ...apis.exchange.change,
74
-    //       data: payload,
75
-    //     }).then((data) => {
76
-    //       resolve(data)
77
-    //     }).catch((err) => {
78
-    //       const message = err.message || err.msg
79
-
80
-    //       if (typeof message === 'string') {
81
-    //         reject(message)
82
-    //       }
83
-    //     })
84
-    //   })
85
-    // },
86
-    // verifyById (_, payload) {
87
-    //   return new Promise((resolve, reject) => {
88
-    //     request({
89
-    //       ...apis.exchange.update,
90
-    //       urlData: payload,
91
-    //     }).then((data) => {
92
-    //       resolve(data)
93
-    //     }).catch((err) => {
94
-    //       reject(err)
95
-    //     })
96
-    //   })
97
-    // }
98 145
     getUserResource({ commit }, payload) { // 用户来源 详情页
99 146
       return new Promise((resolve, reject) => {
100 147
         request({
@@ -106,6 +153,78 @@ export default {
106 153
           reject(err)
107 154
         })
108 155
       })
109
-    }
156
+    },
157
+    getUserBehaviorSummary({ commit }, payload) {
158
+      return new Promise((resolve, reject) => {
159
+        request({
160
+          ...apis.indexEcharts.userBehavior.summary,
161
+          params: payload
162
+        }).then((data) => {
163
+          resolve(data)
164
+        }).catch((err) => {
165
+          reject(err)
166
+        })
167
+      })
168
+    },
169
+    getUserBehaviorProfile({ commit }, payload) {
170
+      return new Promise((resolve, reject) => {
171
+        request({
172
+          ...apis.indexEcharts.userBehavior.profile,
173
+          params: payload
174
+        }).then((data) => {
175
+          resolve(data)
176
+        }).catch((err) => {
177
+          reject(err)
178
+        })
179
+      })
180
+    },
181
+    getIntentionUsers({ commit }, payload) {
182
+      return new Promise((resolve, reject) => {
183
+        request({
184
+          ...apis.indexEcharts.intentionUsers,
185
+          params: { pageSize: 9999, ...payload }
186
+        }).then((data) => {
187
+          resolve(data.records)
188
+        }).catch((err) => {
189
+          reject(err)
190
+        })
191
+      })
192
+    },
193
+    getUserSex({ commit }, payload) {
194
+      return new Promise((resolve, reject) => {
195
+        request({
196
+          ...apis.indexEcharts.userSex,
197
+          params: { pageSize: 9999, ...payload }
198
+        }).then((data) => {
199
+          resolve(data.selectSexUser)
200
+        }).catch((err) => {
201
+          reject(err)
202
+        })
203
+      })
204
+    },
205
+    getUserCity({ commit }, payload) {
206
+      return new Promise((resolve, reject) => {
207
+        request({
208
+          ...apis.indexEcharts.userCity,
209
+          params: { pageSize: 9999, ...payload }
210
+        }).then((data) => {
211
+          resolve(data.records)
212
+        }).catch((err) => {
213
+          reject(err)
214
+        })
215
+      })
216
+    },
217
+    getUserActive({ commit }, payload) {
218
+      return new Promise((resolve, reject) => {
219
+        request({
220
+          ...apis.indexEcharts.userActive,
221
+          params: { pageSize: 9999, ...payload }
222
+        }).then((data) => {
223
+          resolve(data.selectActiveUserCount)
224
+        }).catch((err) => {
225
+          reject(err)
226
+        })
227
+      })
228
+    },
110 229
   }
111 230
 }

+ 83
- 161
src/views/indexEcharts/behaviorAnalysis.vue Ver fichero

@@ -1,183 +1,105 @@
1 1
 <template>
2 2
 <div>
3
-  <div class="system-table-search">
4
-      <div>
5
-        <ul>
6
-          <li>
7
-            <span>用户事件</span>
8
-            <el-select v-model="form.verifyStatus" placeholder="请选择">
9
-              <el-option v-for="(item,i) in gridData || []" :key="i" :label="item.name" :value="item.value"></el-option>
10
-            </el-select>
11
-          </li>
12
-          <li>
13
-            <el-select v-model="form.verifyStatus" placeholder="请选择">
14
-              <el-option v-for="(item,i) in gridData || []" :key="i" :label="item.name" :value="item.value"></el-option>
15
-            </el-select>
16
-          </li>
17
-          <li>
18
-            <span>属性</span>
19
-            <el-select v-model="form.verifyStatus" placeholder="请选择">
20
-              <el-option v-for="(item,i) in gridData || []" :key="i" :label="item.name" :value="item.value"></el-option>
21
-            </el-select>
22
-          </li>
23
-        </ul>
24
-      </div>
3
+  <xm-search size="medium" @submit="search">
4
+    <div>
5
+      <el-form-item label="选择项目">
6
+        <select-building v-model="formData.buildingId"></select-building>
7
+      </el-form-item>
8
+      <el-form-item label="用户事件">
9
+        <el-select v-model="formData.eventType" placeholder="所有事件组">
10
+          <el-option v-for="item in bizEventTypes" :key="item.typeId" :label="item.typeName" :value="item.typeId"></el-option>
11
+        </el-select>
12
+      </el-form-item>
13
+      <el-form-item>
14
+        <el-select v-model="formData.event" placeholder="请选择事件">
15
+          <el-option v-for="item in bizEvents" :key="item.eventCode" :label="item.eventName" :value="item.eventCode"></el-option>
16
+        </el-select>
17
+      </el-form-item>
18
+      <el-form-item label="属性">
19
+        <el-select v-model="formData.activity" placeholder="请选择属性">
20
+          <el-option v-for="item in eventProperties" :key="item.propertyCode" :label="item.propertyName" :value="item.propertyCode"></el-option>
21
+        </el-select>
22
+      </el-form-item>
25 23
     </div>
26
-  <p>最近一周 最近一个月 
27
-    <el-date-picker
28
-      v-model="value"
29
-      type="daterange"
30
-      start-placeholder="开始日期"
31
-      end-placeholder="结束日期"
32
-      default-value="2019-08-08">
33
-    </el-date-picker>
34
-    <el-button class="btn" size="mini"  type="primary" @click="search">查询</el-button>
35
-  </p>
24
+    <el-form-item>
25
+      <el-button type="text" @click="() => getDataOf(7)">最近7天</el-button>
26
+      <el-button type="text" @click="() => getDataOf(30)">最近1月</el-button>
27
+    </el-form-item>
28
+    <el-form-item>
29
+      <el-date-picker
30
+        v-model="dateRange"
31
+        type="daterange"
32
+        start-placeholder="开始日期"
33
+        end-placeholder="结束日期"
34
+        style="margin-left: 16px">
35
+      </el-date-picker>
36
+    </el-form-item>
37
+  </xm-search>
36 38
   
37
-  <div class="grid-content" ref="thirdChart"  id="thirdChart"  :style="{ height: '500px',margin:'20px 0',border:'1px solid #eee', padding:'20px',borderRadius:'5px'}" ></div>
38
-   <el-table :data="tableData2"  border  center  style="width: 100%">
39
-    <el-table-column label="用户姓名" prop="name"></el-table-column>
40
-    <el-table-column label="手机号" prop="phone"></el-table-column>
41
-    <el-table-column label="意向楼盘" prop="building"></el-table-column>
42
-    <el-table-column label="意向值" prop="num"></el-table-column>
43
-  </el-table>
44
-
39
+  <user-behavior :data-zoom="true" ref="chart" mode="all"></user-behavior>
45 40
 </div>
46 41
 </template>
47 42
 
48 43
 <script>
49
-import { createNamespacedHelpers } from "vuex";
50
-import apis from "../../config/api";
51
-import { mapState } from "vuex";
52
-import Echarts from "echarts";
44
+import dayjs from 'dayjs'
45
+import { createNamespacedHelpers } from "vuex"
46
+
47
+const { mapActions } = createNamespacedHelpers("indexEcharts")
53 48
 
54 49
 export default {
55
-  components: {},
50
+  components: {
51
+    UserBehavior: () => import('./components/UserBehavior')
52
+  },
56 53
   data() {
57 54
     return {
58
-      form: {
59
-        verifyStatus: ""
55
+      formData: {
56
+        eventType: '',
57
+        event: '',
58
+        activity: '',
59
+        buildingId: '',
60
+        pageSize: 9999,
60 61
       },
61
-      gridData: [
62
-        {
63
-          name: "未通过",
64
-          value: "0"
65
-        },
66
-        {
67
-          name: "已通过",
68
-          value: "1"
69
-        },
70
-        {
71
-          name: "已驳回",
72
-          value: "2"
73
-        }
74
-      ],
75
-      value: "",
76
-      tableData2: [
77
-        {
78
-          num: "98",
79
-          name: "王晓红",
80
-          phone: "15742389456",
81
-          building: "香颂.蔚澜半岛"
82
-        },
83
-        {
84
-          num: "99",
85
-          name: "王晓红2",
86
-          phone: "15742389456",
87
-          building: "香颂.蔚澜半岛"
88
-        },
89
-        {
90
-          num: "88",
91
-          name: "王晓红3",
92
-          phone: "15742389456",
93
-          building: "香颂.蔚澜半岛"
94
-        },
95
-        {
96
-          num: "94",
97
-          name: "王晓红4",
98
-          phone: "15742389456",
99
-          building: "香颂.蔚澜半岛"
100
-        }
101
-      ]
62
+      dateRange: [],
63
+      bizEvents: [],
64
+      bizEventTypes: [],
65
+      eventProperties: [],
102 66
     };
103 67
   },
104 68
   computed: {},
105
-  methods: {
106
-    search() {},
107
-    drawLine() {
108
-      // 折线图
109
-      let thirdChart = Echarts.init(this.$refs.thirdChart);
110
-      // 绘制图表
111
-      thirdChart.setOption({
112
-        title: {
113
-          text: "访问人数"
114
-        },
115
-        color: ["#000", "green", "#5793f3", "#d14a61", "#241bba", "orange"],
116
-        tooltip: {
117
-          trigger: "axis"
118
-        },
119
-        legend: {
120
-          data: ["首页", "项目", "咨询", "名片", "活动", "资讯"]
121
-        },
122
-        grid: {
123
-          left: "3%",
124
-          right: "4%",
125
-          bottom: "3%",
126
-          containLabel: true
127
-        },
128
-        toolbox: {},
129
-        xAxis: {
130
-          type: "category",
131
-          boundaryGap: false,
132
-          data: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
133
-        },
134
-        yAxis: {
135
-          type: "value"
136
-        },
137
-        series: [
138
-          {
139
-            name: "首页",
140
-            type: "line",
141
-            stack: "1",
142
-            data: [120, 132, 101, 134, 90, 230, 210]
143
-          },
144
-          {
145
-            name: "项目",
146
-            type: "line",
147
-            stack: "2",
148
-            data: [220, 182, 191, 234, 290, 330, 310]
149
-          },
150
-          {
151
-            name: "咨询",
152
-            type: "line",
153
-            stack: "3",
154
-            data: [150, 232, 201, 154, 190, 330, 410]
155
-          },
156
-          {
157
-            name: "名片",
158
-            type: "line",
159
-            stack: "4",
160
-            data: [320, 332, 301, 334, 390, 330, 320]
161
-          },
162
-          {
163
-            name: "活动",
164
-            type: "line",
165
-            stack: "5",
166
-            data: [820, 932, 901, 544, 1290, 1330, 1320]
167
-          },
168
-          {
169
-            name: "资讯",
170
-            type: "line",
171
-            stack: "6",
172
-            data: [400, 500, 201, 934, 1290, 1423, 777]
173
-          }
174
-        ]
175
-      });
69
+  watch: {
70
+    formData: {
71
+      handler(nw) {
72
+        const { eventType, buildingId } = nw
73
+        if (!eventType && !buildingId) return
74
+
75
+        this.getBizEventProperties({ eventType, buildingId }).then((dt) => (this.eventProperties = dt))
76
+      },
77
+      deep: true
176 78
     }
177 79
   },
80
+  methods: {
81
+    ...mapActions([
82
+      'getBizEvents',
83
+      'getBizEventTypes',
84
+      'getBizEventProperties',
85
+    ]),
86
+    search() {
87
+      const [startDate, endDate] = this.dateRange
88
+      this.$refs.chart.getData({ startDate, endDate, ...this.formData })
89
+    },
90
+    getDataOf(days) {      
91
+      const endDate = new Date()
92
+      const startDate = dayjs().subtract(days, 'day').toDate()
93
+
94
+      this.$refs.chart.getData({ startDate, endDate, ...this.formData })
95
+    },
96
+  },
178 97
   mounted() {
179
-    this.drawLine();
180
-  }
98
+  },
99
+  created () {
100
+    this.getBizEvents().then((dt) => (this.bizEvents = dt))
101
+    this.getBizEventTypes().then((dt) => (this.bizEventTypes = dt))
102
+  },
181 103
 };
182 104
 </script>
183 105
 

+ 35
- 8
src/views/indexEcharts/components/IntentionalCustomers.vue Ver fichero

@@ -2,29 +2,56 @@
2 2
   <div class="chart-box">
3 3
     <header-cell>
4 4
       <h3>意向客户</h3>
5
-      <select-building slot="action"></select-building>
5
+      <select-building slot="action" @change="handleBuildingChange"></select-building>
6 6
     </header-cell>
7 7
 
8
-    <el-table :data="tableData"  border  center  style="width: 100%; margin-top: 16px">
9
-      <el-table-column label="用户姓名" prop="name"></el-table-column>
8
+    <el-table v-loading="loading" :data="dataset"  border  center  style="width: 100%; margin-top: 16px">
9
+      <el-table-column label="用户姓名" prop="personName"></el-table-column>
10 10
       <el-table-column label="手机号" prop="phone"></el-table-column>
11
-      <el-table-column label="意向楼盘" prop="building"></el-table-column>
12
-      <el-table-column label="意向值" prop="num"></el-table-column>
11
+      <el-table-column label="意向楼盘" prop="buildingName"></el-table-column>
12
+      <el-table-column label="意向值" prop="intention"></el-table-column>
13 13
     </el-table>
14 14
   </div>
15 15
 </template>
16 16
 
17 17
 <script>
18
+import dayjs from 'dayjs'
19
+import { createNamespacedHelpers } from "vuex"
20
+
21
+const { mapActions } = createNamespacedHelpers("indexEcharts")
22
+
18 23
 export default {
19 24
   name: 'IntentionalCustomers',
20 25
   props: ['value'],
21 26
   components: {
22 27
     HeaderCell: () => import('@/components/HeaderCell'),
23 28
   },
24
-  computed: {
25
-    tableData() {
26
-      return this.value || []
29
+  data() {
30
+    return {
31
+      loading: false,
32
+      dataset: [],
33
+    }
34
+  },
35
+  methods: {
36
+    ...mapActions(['getIntentionUsers']),
37
+    handleBuildingChange(buildingId) {
38
+      this.getData({ buildingId })
39
+    },
40
+    getData(filters = {}) {
41
+      const endDate = new Date()
42
+      const startDate = dayjs().subtract(7, 'day').toDate()
43
+
44
+      this.loading = true
45
+      this.getIntentionUsers({ startDate, endDate, ...filters}).then((dt) => {
46
+        this.loading = false
47
+        this.dataset = dt
48
+      }).catch(() => {
49
+        this.loading = false
50
+      })
27 51
     }
52
+  },
53
+  mounted () {
54
+    this.getData()
28 55
   }
29 56
 }
30 57
 </script>

+ 42
- 4
src/views/indexEcharts/components/UserActive.vue Ver fichero

@@ -1,7 +1,12 @@
1 1
 <template>
2 2
   <div class="chart-box">
3
-    <h3>活跃用户数</h3>
4
-    <v-chart class="chart" :options="options" />
3
+    <header-cell>
4
+      <h3>活跃用户数</h3>
5
+      <el-select v-model="theType" slot="action" @change="handleTypesChange">
6
+        <el-option v-for="item in types" :key="item.value" :label="item.label" :value="item.value"></el-option>
7
+      </el-select>
8
+    </header-cell>
9
+    <v-chart class="chart" v-loading="loading" :options="options" />
5 10
   </div>
6 11
 </template>
7 12
 
@@ -9,15 +14,28 @@
9 14
 import ECharts from 'vue-echarts'
10 15
 import 'echarts/lib/chart/bar'
11 16
 import 'echarts/lib/component/tooltip'
17
+import dayjs from 'dayjs'
18
+import { createNamespacedHelpers } from "vuex"
19
+
20
+const { mapActions } = createNamespacedHelpers("indexEcharts")
12 21
 
13 22
 export default {
14 23
   name: 'UserActive',
15 24
   components: {
16 25
     'v-chart': ECharts,
26
+    HeaderCell: () => import('@/components/HeaderCell')
17 27
   },
18 28
   props: [ 'value' ],
19 29
   data () {
20 30
     return {
31
+      loading: false,
32
+      dataset: [],
33
+      theType: 'day',
34
+      types: [
35
+        {label: '日活跃', value: 'day'},
36
+        {label: '周活跃', value: 'week'},
37
+        {label: '月活跃', value: 'month'},
38
+      ],
21 39
       defaultOpt: {
22 40
         legend: { show: false },
23 41
         color: ['#8954BA', '#175DFB', '#0BB963', '#27DEFF', '#E713D2', '#E71313'],
@@ -34,11 +52,31 @@ export default {
34 52
         series: {
35 53
           type: 'bar',
36 54
           name: '活跃用户',
37
-          data: (this.value || []).map(x => ([ x.date,!x.activityCount ? 0 : x.activityCount ]))
55
+          data: (this.dataset || []).map(x => ([ x.date,!x.activityCount ? 0 : x.activityCount ]))
38 56
         }
39 57
       }
40 58
     }
41
-  }
59
+  },
60
+  methods: {
61
+    ...mapActions(['getUserActive']),
62
+    getData(filers) {
63
+      // const endDate = new Date()
64
+      // const startDate = dayjs().subtract(7, 'day').toDate()
65
+      this.loading = true
66
+      this.getUserActive(filers).then((data) => {
67
+        this.dataset = data || []
68
+        this.loading = false
69
+      }).catch(() => {
70
+        this.loading = true
71
+      })
72
+    },
73
+    handleTypesChange (e) {
74
+      this.getData({ dateType: e })
75
+    }
76
+  },
77
+  mounted() {
78
+    this.getData({ dateType: this.theType })
79
+  },
42 80
 }
43 81
 </script>
44 82
 

+ 97
- 10
src/views/indexEcharts/components/UserBehavior.vue Ver fichero

@@ -1,10 +1,35 @@
1 1
 <template>
2
-  <div class="chart-box">
3
-    <header-cell>
4
-      <h3>用户行为 <small>最近七天</small></h3>
5
-      <select-building slot="action"></select-building>
6
-    </header-cell>
7
-    <v-chart class="chart" :options="options" />
2
+  <div>
3
+    <div class="chart-box" v-if="mode === 'all' || mode === 'lines'">
4
+      <header-cell>
5
+        <h3>用户行为 <small>{{subtitle}}</small></h3>
6
+        <select-building slot="action" v-if="selectBuilding" @change="handleBuildingChange"></select-building>
7
+      </header-cell>
8
+      <v-chart class="chart" v-loading="loading" :options="options" />
9
+    </div>
10
+    <div class="chart-box" v-if="mode === 'all' || mode === 'table'">
11
+      <el-table :data="tableData"  border  center  style="width: 100%" height="400">
12
+        <el-table-column label="访问事件" prop="eventName"></el-table-column>
13
+        <el-table-column label="访问用户" prop="userName"></el-table-column>
14
+        <el-table-column label="访问次数">
15
+          <template slot-scope="scope">
16
+            <el-button type="text" @click="showDetail(scope.row)">{{scope.row.accessCount}}</el-button>
17
+          </template>
18
+        </el-table-column>
19
+        <el-table-column label="首次访问时间" prop="visitTime"></el-table-column>
20
+        <el-table-column label="离开时间" prop="leaveTime"></el-table-column>
21
+      </el-table>
22
+    </div>
23
+    <el-dialog
24
+      title="访问记录"
25
+      :visible.sync="dialogVisible"
26
+      width="50%">
27
+      <el-table v-loading="detailData.length > 0" :data="detailData"  border  center  style="width: 100%" height="400">
28
+        <el-table-column type="index" width="50"></el-table-column>
29
+        <el-table-column label="访问时间" prop="visitTime"></el-table-column>
30
+        <el-table-column label="离开时间" prop="leaveTime"></el-table-column>
31
+      </el-table>
32
+    </el-dialog>
8 33
   </div>
9 34
 </template>
10 35
 
@@ -12,32 +37,48 @@
12 37
 import ECharts from 'vue-echarts'
13 38
 import 'echarts/lib/chart/line'
14 39
 import 'echarts/lib/component/tooltip'
40
+import 'echarts/lib/component/dataZoom'
15 41
 import dayjs from 'dayjs'
16 42
 import HeaderCell from '@/components/HeaderCell'
43
+import { createNamespacedHelpers } from "vuex"
44
+
45
+const { mapActions } = createNamespacedHelpers("indexEcharts")
17 46
 
18 47
 export default {
19 48
   name: 'UserBehavior',
20 49
   components: {
21
-    'v-chart': ECharts,
22 50
     HeaderCell,
23 51
   },
24 52
   props: [
25 53
     'value',
54
+    'subtitle',
55
+    'dataZoom',
56
+    'selectBuilding',
57
+    'mode',
26 58
   ],
27 59
   data() {
28 60
     return {
61
+      loading: false,
62
+      dataset: {},
63
+      dialogVisible: false,
64
+      detailData: [],
29 65
       baseOpt: {
30
-        legend: {},
66
+        legend: { show: true, zlevel: 10 },
31 67
         color: ['#8954BA', '#175DFB', '#0BB963', '#27DEFF', '#E713D2', '#E71313'],
32
-        tooltip: {},
68
+        tooltip: {
69
+          trigger: 'axis'
70
+        },
33 71
         xAxis: { type: 'time' },
34 72
         yAxis: {},
35 73
       },
36 74
     }
37 75
   },
38 76
   computed: {
77
+    tableData () {
78
+      return (this.dataset.data || {}).records || []
79
+    },
39 80
     options() {
40
-      const seriesMaker = (this.value || []).reduce((series, item) => {
81
+      const seriesMaker = (this.dataset.selectUserBehavior || []).reduce((series, item) => {
41 82
         let { date, activityCount, activity } = item
42 83
         date = dayjs(date).format('YYYY-MM-DD')
43 84
         if (!activityCount) activityCount = 0
@@ -48,8 +89,23 @@ export default {
48 89
         return series;
49 90
       }, {})
50 91
 
92
+      const dataZoom = this.dataZoom ? 
93
+        [
94
+          {
95
+            type: 'inside',
96
+            start: 0,
97
+            end: 100
98
+          },
99
+          {
100
+            type: 'slider',
101
+            start: 0,
102
+            end: 100
103
+          },
104
+        ] : undefined
105
+
51 106
       return {
52 107
         ...this.baseOpt,
108
+        dataZoom,
53 109
         series: Object.keys(seriesMaker).map(x => {
54 110
           return {
55 111
             type: 'line',
@@ -60,6 +116,37 @@ export default {
60 116
       }
61 117
     }
62 118
   },
119
+  methods: {
120
+    ...mapActions([
121
+      'getUserBehaviorSummary',
122
+      'getUserBehaviorProfile',
123
+    ]),
124
+    getData(filers) {
125
+      this.loading = true
126
+      this.getUserBehaviorSummary(filers).then((data) => {
127
+        this.dataset = data || {}
128
+        this.loading = false
129
+      }).catch(() => {
130
+        this.loading = true
131
+      })
132
+    },
133
+    showDetail (row) {
134
+      this.detailData = []
135
+      this.dialogVisible = true
136
+      this.getUserBehaviorProfile({ event: row.event, personId: row.personId }).then((data) => {
137
+        this.detailData = data
138
+      })
139
+    },
140
+    handleBuildingChange (e) {
141
+      this.getData({ buildingId: e })
142
+    },
143
+  },
144
+  mounted () {
145
+    const endDate = new Date()
146
+    const startDate = dayjs().subtract(7, 'day').toDate()
147
+
148
+    this.getData({ startDate, endDate, pageSize: 9999 })
149
+  },
63 150
 }
64 151
 </script>
65 152
 

+ 25
- 2
src/views/indexEcharts/components/UserSex.vue Ver fichero

@@ -1,7 +1,7 @@
1 1
 <template>
2 2
   <div class="chart-box">
3 3
     <h3>性别比例</h3>
4
-    <v-chart class="chart" :options="options" />
4
+    <v-chart v-loading="loading" class="chart" :options="options" />
5 5
   </div>
6 6
 </template>
7 7
 
@@ -9,6 +9,10 @@
9 9
 import ECharts from 'vue-echarts'
10 10
 import 'echarts/lib/chart/pie'
11 11
 import 'echarts/lib/component/tooltip'
12
+import dayjs from 'dayjs'
13
+import { createNamespacedHelpers } from "vuex"
14
+
15
+const { mapActions } = createNamespacedHelpers("indexEcharts")
12 16
 
13 17
 export default {
14 18
   name: 'UserSex',
@@ -20,6 +24,8 @@ export default {
20 24
   ],
21 25
   data() {
22 26
     return {
27
+      loading: false,
28
+      dataset: [],
23 29
       defaultOpt: {
24 30
         legend: {},
25 31
         color: ['#6A96F8', '#F5749E'],
@@ -38,11 +44,28 @@ export default {
38 44
         ...this.defaultOpt,
39 45
         series: {
40 46
           ...this.defaultOpt.series,
41
-          data: this.value || [],
47
+          data: this.dataset || [],
42 48
         },
43 49
       }
44 50
     }
45 51
   },
52
+  methods: {
53
+    ...mapActions(['getUserSex']),
54
+    getData(filers) {
55
+      this.loading = true
56
+      this.getUserSex(filers).then((data) => {
57
+        this.dataset = data || {}
58
+        this.loading = false
59
+      }).catch(() => {
60
+        this.loading = true
61
+      })
62
+    },
63
+  },
64
+  mounted () {
65
+    const endDate = new Date()
66
+    const startDate = dayjs().subtract(7, 'day').toDate()
67
+    this.getData({ startDate, endDate })
68
+  },
46 69
 }
47 70
 </script>
48 71
 

+ 2
- 2
src/views/indexEcharts/components/UserSource.vue Ver fichero

@@ -1,7 +1,7 @@
1 1
 <template>
2 2
   <div>
3 3
     <div class="chart-box" v-if="mode == 'all' || mode == 'report'">
4
-      <h3>用户来源 <small>{{subTitle}}</small></h3>
4
+      <h3>用户来源 <small>{{subtitle}}</small></h3>
5 5
       <v-chart v-loading="loading" class="chart" :options="options" />
6 6
     </div>
7 7
     <div class="chart-box" v-if="mode == 'all' || mode == 'table'">
@@ -33,7 +33,7 @@ export default {
33 33
   },
34 34
   props: [
35 35
     'value',
36
-    'subTitle',
36
+    'subtitle',
37 37
     'mode',
38 38
   ],
39 39
   data () {

+ 9
- 21
src/views/indexEcharts/index.vue Ver fichero

@@ -8,27 +8,27 @@
8 8
       <card label="总注册用户">{{echartsInfo.selectRegisteredCount}}</card>
9 9
     </el-col>
10 10
     <el-col :span="8">
11
-      <card label="最近7天新增" @click.native="toNewUsers()" class="under-line" >{{echartsInfo.selectRecentlyCount}}</card>
11
+      <card label="最近7天新增" @click.native="toNewUsers" class="under-line" >{{echartsInfo.selectRecentlyCount}}</card>
12 12
     </el-col>
13 13
   </el-row>
14
-  <user-source :value="userSourceData" mode="report" sub-title="最近七天"></user-source>
15
-  <user-behavior class="marginTB" :value="userBehaviorData" @click="toBehaviorAnalysis()"></user-behavior>
14
+  <user-source mode="report" subtitle="最近七天" @click.native="toUserSource"></user-source>
15
+  <user-behavior class="marginTB" mode="lines" :select-building="true" @click.native="toBehaviorAnalysis" subtitle="最近七天"></user-behavior>
16 16
  <el-row :gutter="20">
17 17
     <el-col :span="12">
18
-      <user-active :value="userActiveData"></user-active>
18
+      <user-active></user-active>
19 19
     </el-col>
20 20
     <el-col :span="12">
21 21
       <user-conversion></user-conversion>
22 22
     </el-col>
23 23
     <el-col :span="12">
24
-      <user-sex :value="userSexData"></user-sex>
24
+      <user-sex></user-sex>
25 25
     </el-col>
26 26
     <el-col :span="12">
27
-      <user-city :value="userCityData"></user-city>
27
+      <user-city></user-city>
28 28
     </el-col>
29 29
   </el-row>
30
-  <new-users class="marginTB" :value="newUserData" mode="table"></new-users>
31
-  <intentional-customers  class="marginTB"></intentional-customers>
30
+  <new-users class="marginTB" mode="table"></new-users>
31
+  <intentional-customers class="marginTB"></intentional-customers>
32 32
 </div>
33 33
 </template>
34 34
 
@@ -56,12 +56,6 @@ export default {
56 56
   },
57 57
   data() {
58 58
     return {
59
-      userSourceData: {},
60
-      userBehaviorData: [],
61
-      userActiveData: [],
62
-      userSexData: [],
63
-      userCityData: [],
64
-      newUserData: [],
65 59
     };
66 60
   },
67 61
   computed: {
@@ -73,13 +67,7 @@ export default {
73 67
     ...mapIndexEchartsActions(["getIndexEcharts", "setDetailNull"]),
74 68
     initPage() {
75 69
       this.setDetailNull();
76
-      this.getIndexEcharts().then(x => {
77
-        this.userSourceData = x.selectUserSource
78
-        this.userBehaviorData = x.selectUserBehavior
79
-        this.userActiveData = x.selectActiveUserCount
80
-        this.userSexData = x.selectSexUser
81
-        this.newUserData = this.echartsInfo.selectNewsUserCount
82
-      });;
70
+      this.getIndexEcharts().then(window.console.log);;
83 71
     },
84 72
     toNewUsers() {
85 73
       this.$router.push({ name: "newUsers" });