Procházet zdrojové kódy

feat: 企微数据 - 短剧数据趋势 - 前端页面

zhengxy %!s(int64=2) %!d(string=před) roky
rodič
revize
58cddad2f0

+ 635 - 0
project/src/components/dataBoard/shortDramaTrends.vue

@@ -0,0 +1,635 @@
1
+<template>
2
+  <div>
3
+    <div class="screenBox flex">
4
+      <switchMpAdq v-model="filter.order_type" @change="onChangeOrderType" />
5
+      <el-button type="primary" size="mini" @click="onClickExport">导出Excel</el-button>
6
+    </div>
7
+    <!-- S 筛选区 -->
8
+    <div class="screenBox filter-wrap">
9
+      <!-- 日期 -->
10
+      <datePicker style="margin-right: 30px;" :reset="reset" title="自定义" :quickFlag="true" :afferent_time="default_time" :clearFlag="false" @changeTime="onChangeTime" />
11
+      <!-- 短剧 -->
12
+      <selfChannel style="margin-right: 30px;margin-left: -30px;" :reset="reset" title="短剧" type="dramaList" labelWidth @channelDefine="onChangePlayletId" />
13
+      <!-- 收益截止日期 -->
14
+      <div style="margin-right: 30px;" class="common-screen-item">
15
+        <label class="common-screen-label">收益截止日期</label>
16
+        <el-date-picker v-model="filter.closing_date" value-format="yyyy-MM-dd" type="date" placeholder="选择日期" size="small" style="width:150px" @change="onChangeClosingDate" />
17
+      </div>
18
+      <!-- 推广类型 -->
19
+      <selfChannel style="margin-right: 30px;margin-left: -30px;" :reset="reset" title="推广类型" type="promotionType" labelWidth @channelDefine="onChangePromotionType" />
20
+      <div class="flex">
21
+        <!-- 回本率(范围) -->
22
+        <inputRange style="margin-right: 10px;" v-model="filter.totalRoi" label="回本率" />
23
+        <el-button size="mini" type="primary" plain @click="onClickSearch">确定</el-button>
24
+        <el-button size="mini" plain @click="onClickReset">重置</el-button>
25
+      </div>
26
+    </div>
27
+    <!-- E 筛选区 -->
28
+
29
+    <!-- S 折线图 -->
30
+    <div class="trendBox mt-10" v-loading="chartLoading">
31
+      <div class="legendBox">
32
+        <div class="legendItem" v-for="(item, index) in legendList" :key="index" @click="onClickLegend(item, index)">{{ item.name }}
33
+          <div :class="['checkbox', item.selectFlag ? 'checkbox_active': '']" :style="item.selectFlag ? `background: ${item.color};border-color: ${item.color};`: '' "><i class="el-icon-check" /></div>
34
+        </div>
35
+      </div>
36
+      <div id="trend" style="width: 100%; height: 250px;" />
37
+    </div>
38
+    <!-- E 折线图 -->
39
+
40
+    <!-- S 表 -->
41
+    <div v-loading="loading">
42
+      <!-- S 汇总表 summaryTable -->
43
+      <ux-grid class="summaryTable" ref="summaryTable" :border="false" @row-click="() => { return }" :header-cell-style="getHeaderCellStyle" show-footer-overflow="tooltip" show-overflow="tooltip" size="mini">
44
+        <ux-table-column v-for="item in summaryTableCol" :key="item.column" :resizable="true" :field="item.column" :title="item.name" :min-width="item.min_width ? item.min_width : 120" :fixed="item.fixed ? item.fixed : ''" align="center">
45
+          <template #header>
46
+            <div class="flex-align-jus-center">
47
+              {{ item.name }}
48
+              <el-tooltip v-if="item.notes" :content="item.notes" placement="top">
49
+                <div><i class="el-icon-question"></i></div>
50
+              </el-tooltip>
51
+            </div>
52
+          </template>
53
+          <template v-slot="{ row }">
54
+            <span>{{ row[item.column] ? $formatNum(row[item.column]) : '-' }}</span>
55
+          </template>
56
+        </ux-table-column>
57
+      </ux-grid>
58
+      <!-- E 汇总表 summaryTable -->
59
+      <!-- S 明细表 detailsTable -->
60
+      <ux-grid class="detailsTable" ref="detailsTable" :border="false" @row-click="() => { return }" :header-cell-style="getHeaderCellStyle" show-footer-overflow="tooltip" show-overflow="tooltip" size="mini">
61
+        <ux-table-column v-for="item in detailsTableCol" :key="item.column" :resizable="true" :field="item.column" :title="item.name" :min-width="item.min_width ? item.min_width : 120" :fixed="item.fixed ? item.fixed : ''" align="center">
62
+          <template #header>
63
+            <div class="flex-align-jus-center">
64
+              {{ item.name }}
65
+              <div v-if="item.isSort" class="sort-wrap">
66
+                <i class="el-icon-caret-top" :class="{ 'active': filter.sort_field === item.column && filter.sort_type === 'asc' }" @click="onClickSort(item.column, 'asc')" />
67
+                <i class="el-icon-caret-bottom" :class="{ 'active': filter.sort_field === item.column && filter.sort_type === 'desc' }" @click="onClickSort(item.column, 'desc')" />
68
+              </div>
69
+              <el-tooltip v-if="item.notes" :content="item.notes" placement="top">
70
+                <div><i class="el-icon-question"></i></div>
71
+              </el-tooltip>
72
+            </div>
73
+          </template>
74
+          <template v-slot="{ row }">
75
+            <span>{{ row[item.column] ? $formatNum(row[item.column]) : '-' }}</span>
76
+          </template>
77
+        </ux-table-column>
78
+      </ux-grid>
79
+      <div class="pagination" v-show="pagination.total > 0">
80
+        <el-pagination background :current-page="pagination.page" @current-change="handleCurrentChange" layout="prev, pager, next" :page-count='Number(pagination.pages)' />
81
+      </div>
82
+      <!-- E 明细表 detailsTable -->
83
+    </div>
84
+    <!-- E 表 -->
85
+  </div>
86
+</template>
87
+<script>
88
+import datePicker from '@/components/assembly/screen/datePicker.vue'
89
+import inputRange from '@/components/dataBoard/inputRange.vue'
90
+import selfChannel from '@/components/assembly/screen/channel.vue'
91
+import switchMpAdq from '@/components/assembly/screen/switchMpAdq.vue'
92
+import { orderTypeOptions } from '@/assets/js/staticTypes'
93
+import _lodash from 'lodash'
94
+
95
+export default {
96
+  components: {
97
+    datePicker,
98
+    inputRange,
99
+    selfChannel,
100
+    switchMpAdq,
101
+  },
102
+  data () {
103
+    const DEFAULT_TIME = [this.$getDay(-30, false), this.$getDay(0, false)]
104
+    return {
105
+      default_time: DEFAULT_TIME,
106
+      reset: false,
107
+
108
+      chartLoading: false,
109
+      myChart: null,
110
+      chartDataList: [],
111
+      legendList: [
112
+        { name: '消耗', key: 'cust_total_uc', color: '#2983DF', selectFlag: true },
113
+        { name: '下单成本', key: 'cust_add_uc', color: '#00B38A', selectFlag: true },
114
+        { name: '首日arpu值', key: 'cust_loss_uc', color: '#EB4315', selectFlag: true },
115
+        { name: '首日roi', key: 'cust_gain_uc', color: '#AED570', selectFlag: true },
116
+        { name: '3天倍率', key: 'official_account_uc', color: '#EFAF47', selectFlag: true },
117
+        { name: '7天倍率', key: 'cust_pay_uc', color: '#7366FF', selectFlag: true },
118
+        { name: '15天倍率', key: 'cust_pay_amount', color: '#F28544', selectFlag: true },
119
+        { name: '30天倍率', key: 'charge_user_cost', color: '#E360C8', selectFlag: true },
120
+      ],
121
+
122
+      loading: false,
123
+      summaryTableCol: [
124
+        { "column": "date", "name": "用户注册时间", "notes": ""},
125
+        { "column": "advertiser_cost", "name": "投放消耗", "notes": "",},
126
+        { "column": "follow_uv", "name": "企微关注数", "notes": ""},
127
+        { "column": "per_follow_cost", "name": "企微关注成本", "notes": ""},
128
+        { "column": "total_roi", "name": "总回收", "notes": "总回收金额/投放消耗"},
129
+        { "column": "day1_roi", "name": "day1", "notes": ""}
130
+      ],
131
+      detailsTableCol: [
132
+        { "column": "date", "name": "用户注册时间", "notes": ""},
133
+        { "column": "advertiser_cost", "name": "投放消耗", "notes": "", isSort: 1},
134
+        { "column": "follow_uv", "name": "企微关注数", "notes": "", isSort: 1},
135
+        { "column": "per_follow_cost", "name": "企微关注成本", "notes": ""},
136
+        { "column": "total_roi", "name": "总回收", "notes": "总回收金额/投放消耗", isSort: 1},
137
+        { "column": "day1_roi", "name": "day1", "notes": ""}
138
+      ],
139
+      pagination: {
140
+        page: 1,
141
+        page_size: 20,
142
+        pages: 0,
143
+        total: 0,
144
+      },
145
+      filter: {
146
+        order_type: orderTypeOptions.MP,
147
+        time: DEFAULT_TIME, // 自定义日期
148
+        playlet_id: '', // 账号MP
149
+        closing_date: '', // 收益截止日期
150
+        promotion_type: '', // 推广类型
151
+        totalRoi: ['', ''], // 回本率(范围)
152
+        sort_field: '', // 排序字段
153
+        sort_type: '', // 升序/降序
154
+      },
155
+    }
156
+  },
157
+  computed: {
158
+    // // 当前列表是否为"MP运营数据"
159
+    // isMP() {
160
+    //   return this.filter.order_type === orderTypeOptions.MP
161
+    // },
162
+    // // 当前列表是否为"ADQ运营数据"
163
+    // isADQ() {
164
+    //   return this.filter.order_type === orderTypeOptions.ADQ
165
+    // },
166
+  },
167
+  created () {
168
+    this.handleGetList()
169
+    this.handleGetChart()
170
+  },
171
+  beforeDestroy () {
172
+    this.myChart && this.myChart.clear()
173
+  },
174
+  methods: {
175
+    // 获取列表数据
176
+    async handleGetList() {
177
+      console.log('handleGetList => ',)
178
+      console.log('filter => ', JSON.parse(JSON.stringify(this.filter)))
179
+      console.log('pagination => ', JSON.parse(JSON.stringify(this.pagination)))
180
+      // mock
181
+      await this.$nextTick()
182
+      this.$refs.summaryTable.reloadData([{
183
+        "date": "2022-08-24",
184
+        "advertiser_cost": "105.57",
185
+        "first_order_ucnt_unique": 0,
186
+        "first_order_ucnt": 0,
187
+        "follow_uv": 5,
188
+        "total_cvt_amt": "0.00",
189
+        "per_follow_cost": "21.11",
190
+        "total_roi": "0%",
191
+        "charge_data": "[0]",
192
+        "first_day_charge": "0.00",
193
+        "first_day_roi": "0%",
194
+        "first_order_cost": "0.00",
195
+        "first_order_cost_unique": "0.00",
196
+        "day1_roi": "0%"
197
+      }])
198
+      this.$refs.detailsTable.reloadData([{
199
+        "date": "2022-08-24",
200
+        "advertiser_cost": "105.57",
201
+        "first_order_ucnt_unique": 0,
202
+        "first_order_ucnt": 0,
203
+        "follow_uv": 5,
204
+        "total_cvt_amt": "0.00",
205
+        "per_follow_cost": "21.11",
206
+        "total_roi": "0%",
207
+        "charge_data": "[0]",
208
+        "first_day_charge": "0.00",
209
+        "first_day_roi": "0%",
210
+        "first_order_cost": "0.00",
211
+        "first_order_cost_unique": "0.00",
212
+        "day1_roi": "0%"
213
+      }, {
214
+        "date": "2022-08-25",
215
+        "advertiser_cost": "200",
216
+        "first_order_ucnt_unique": 1,
217
+        "first_order_ucnt": 1,
218
+        "follow_uv": 6,
219
+        "total_cvt_amt": "1.00",
220
+        "per_follow_cost": "1.11",
221
+        "total_roi": "8%",
222
+        "charge_data": "[0]",
223
+        "first_day_charge": "0.00",
224
+        "first_day_roi": "0%",
225
+        "first_order_cost": "0.00",
226
+        "first_order_cost_unique": "0.00",
227
+        "day1_roi": "0%"
228
+      }])
229
+      this.pagination.total = 2
230
+      this.pagination.pages = 2
231
+      // mock
232
+      return // mock
233
+      this.loading = true
234
+      this.$axios.get(`${this.URL.BASEURL}${this.URL.statistics_reg_range_report_new}`, {
235
+        params: {
236
+          begin_date: this.filter.time[0],
237
+          end_date: this.filter.time[1],
238
+          total_roi_min: this.filter.totalRoi[0],
239
+          total_roi_max: this.filter.totalRoi[1],
240
+          page: this.pagination.page,
241
+          page_size: this.pagination.page_size,
242
+        }
243
+      }).then((res) => {
244
+        var res = res.data
245
+        this.loading = false
246
+        if (res && res.errno == 0) {
247
+          this.summaryTableCol = res.rst.data.head;
248
+          this.$nextTick((item) => {
249
+            this.datas = res.rst.data.list // 知道为啥datas不在 data()方法里面定义吗?嘻嘻
250
+            this.$refs.summaryTable.reloadData(this.datas)
251
+          })
252
+          this.pagination.total = res.rst.pageInfo.total;
253
+          this.pagination.pages = res.rst.pageInfo.pages;
254
+        } else if (res.errno != 4002) {
255
+          this.$message({
256
+            message: res.err,
257
+            type: "warning"
258
+          })
259
+        }
260
+      }).catch((err) => {
261
+        this.loading = false
262
+      });
263
+    },
264
+    // 获取折线图数据
265
+    handleGetChart() {
266
+      console.log('handleGetChart => ')
267
+      // return // mock
268
+      this.chartLoading = true
269
+      this.$axios.get(this.URL.BASEURL + this.URL.stat_custTrendsNew, {
270
+        params: {
271
+          corpid: 'wpezvKNwAA9d7LlcuOOAhvlx5ikwJjHg',
272
+          start: '2022-08-09',
273
+          end: '2022-09-08',
274
+        }
275
+      }).then((_res) => {
276
+        const res = _res.data
277
+        this.chartLoading = false
278
+        if (res && res.errno == 0) {
279
+          this.chartDataList = res.rst
280
+          this.$nextTick(() => {
281
+            this.handleDrawChart()
282
+          })
283
+        } else if (res.errno != 4002) {
284
+          this.$message({
285
+            message: res.err,
286
+            type: "warning"
287
+          })
288
+        }
289
+      }).catch((err) => {
290
+        this.chartLoading = false
291
+      });
292
+    },
293
+    // 绘制折线图
294
+    handleDrawChart() {
295
+      this.myChart && this.myChart.clear()
296
+      const _this = this;
297
+      const series = []
298
+      const yAxis = []
299
+      const xArr = this.chartDataList.map(v => v.idate)
300
+      this.legendList.forEach((item, index) => {
301
+        if (item.selectFlag) {
302
+          yAxis.push({
303
+            type: "value",
304
+            name: '',
305
+            show: false,
306
+            position: 'left',
307
+            axisTick: {
308
+              show: false
309
+            },
310
+            splitLine: {
311
+              lineStyle: {
312
+                color: '#F2F2f2',
313
+                type: "dashed"
314
+              }
315
+            },
316
+            axisLine: {
317
+              show: true,
318
+              lineStyle: {
319
+                color: '#F2F2f2'
320
+              }
321
+            },
322
+            nameTextStyle: {
323
+              color: "#999999",
324
+              fontSize: 13,
325
+            },
326
+            axisLabel: {
327
+              color: '#999999',
328
+              fontSize: 12,
329
+              show: true,
330
+              formatter: function(params) {
331
+                return _this.$NumberHandle(params)
332
+              }
333
+            }
334
+          })
335
+
336
+          const data = this.chartDataList.map(v => v[item.key] || v[item.key] == 0 ? v[item.key] : '-')
337
+
338
+          series.push({
339
+            type: "line",
340
+            smooth: true,
341
+            name: item.name,
342
+            yAxisIndex: 0,
343
+            data,
344
+            lineStyle: {
345
+              width: 2
346
+            },
347
+            symbol: xArr.length == 1 ? 'emptyCircle' : 'none',
348
+            itemStyle: {
349
+              color: item.color,
350
+              borderType: "emptyCircle"
351
+            },
352
+          })
353
+        }
354
+      })
355
+      yAxis.forEach((item, index) => {
356
+        item.show = index == 0 ? true : false
357
+      })
358
+      series.forEach((item, index) => {
359
+        item.yAxisIndex = index
360
+      })
361
+      const option = {
362
+        title: '',
363
+        tooltip: {
364
+          trigger: 'axis',
365
+          show: true,
366
+          formatter: function(params) {
367
+            let result = `${params[0].name}<br/>`
368
+            params.forEach(item => {
369
+              result += `${item.marker}${item.seriesName}:${_this.$formatNum(item.value)}<br/>`
370
+            });
371
+            return result;
372
+          }
373
+        },
374
+        legend: {
375
+          itemWidth: 8,
376
+          itemHeight: 2,
377
+          icon: "plain",
378
+          show: false,
379
+          textStyle: {
380
+            fontSize: 12,
381
+            color: '#666666'
382
+          },
383
+        },
384
+        grid: {
385
+          top: '6%',
386
+          left: '4%',
387
+          right: '4%',
388
+          bottom: '16%',
389
+          containLabel: false
390
+        },
391
+        xAxis: [{
392
+          type: "category",
393
+          data: xArr,
394
+          boundaryGap: false,//设置数据从头开始
395
+          axisLine: {
396
+            show: true,
397
+            lineStyle: {
398
+              color: '#F2F2f2'
399
+            }
400
+          },
401
+          axisTick: {
402
+            show: false
403
+          },
404
+          splitLine: {
405
+            show: false
406
+          },
407
+          axisLabel: {
408
+            color: '#666',
409
+            fontSize: 10,
410
+            rotate: 30,
411
+          },
412
+        }],
413
+        yAxis,
414
+        series,
415
+      }
416
+      // 初始化echarts实例
417
+      this.myChart = this.myChart ? this.myChart : this.$echarts.init(document.getElementById('trend'));
418
+      this.myChart.setOption(option);
419
+    },
420
+    // 监听点击图例
421
+    async onClickLegend(currentItem, index) {
422
+      const arr = this.legendList.filter(v => v.selectFlag)
423
+      if (arr.length == 1 && arr[0].key == currentItem.key) {
424
+        return this.$message.warning('至少存在一条曲线')
425
+      }
426
+      const item = _lodash.cloneDeep(currentItem)
427
+      item.selectFlag = !item.selectFlag
428
+      this.$set(this.legendList, index, item)
429
+      await this.$nextTick()
430
+      this.handleDrawChart()
431
+    },
432
+    // 监听数据类型切换
433
+    onChangeOrderType() {
434
+      this.pagination.page = 1
435
+      this.handleGetList()
436
+    },
437
+    // 监听时间筛选变化
438
+    onChangeTime(time) {
439
+      this.filter.time = Array.isArray(time) ? time : []
440
+      this.pagination.page = 1
441
+      this.handleGetList()
442
+    },
443
+    // 监听“短剧”筛选变化
444
+    onChangePlayletId(val) {
445
+      this.filter.playlet_id = val
446
+      this.pagination.page = 1
447
+      this.handleGetList()
448
+    },
449
+    // 监听“收益截止日期”筛选变化
450
+    onChangeClosingDate(val) {
451
+      this.filter.closing_date = val || ''
452
+      this.pagination.page = 1
453
+      this.handleGetList()
454
+    },
455
+    // 监听“推广类型”筛选变化
456
+    onChangePromotionType(val) {
457
+      this.filter.promotion_type = val || ''
458
+      this.pagination.page = 1
459
+      this.handleGetList()
460
+    },
461
+    // 监听当前页变化
462
+    handleCurrentChange(currentPage) {
463
+      this.pagination.page = currentPage
464
+      this.handleGetList()
465
+    },
466
+    // 监听点击"确定(搜索)"按钮
467
+    onClickSearch() {
468
+      this.pagination.page = 1
469
+      this.handleGetList()
470
+    },
471
+    // 监听排序变化
472
+    onClickSort(sort_field, sort_type) {
473
+      // sort_type:升序asc、降序desc
474
+      if (this.filter.sort_field === sort_field) {
475
+        if (this.filter.sort_type === sort_type) {
476
+          // 点击的是当前排序字段 && 是当前排序类型 => 重置 取消排序
477
+          this.filter.sort_field = ''
478
+          this.filter.sort_type = ''
479
+        } else {
480
+          // 点击的是当前排序字段 && 非当前排序类型 => 设置排序类型
481
+          this.filter.sort_type = sort_type
482
+        }
483
+      } else {
484
+        // 点击的不是当前排序字段 => 设置排序字段和类型
485
+        this.filter.sort_field = sort_field
486
+        this.filter.sort_type = sort_type
487
+      }
488
+      // 后端排序 => 获取最新数据
489
+      this.pagination.page = 1
490
+      this.handleGetList()
491
+    },
492
+    // 监听点击"重置"按钮
493
+    onClickReset() {
494
+      this.reset = !this.reset
495
+      this.filter.order_type = orderTypeOptions.MP
496
+      this.filter.time = this.default_time
497
+      this.filter.playlet_id = ''
498
+      this.filter.closing_date = '',
499
+      this.filter.promotion_type = ''
500
+      this.filter.totalRoi = ['', '']
501
+      this.filter.sort_field = ''
502
+      this.filter.sort_type = ''
503
+      this.pagination.page = 1
504
+      this.handleGetList()
505
+    },
506
+    // 监听点击"导出"按钮
507
+    onClickExport() {
508
+      console.log('onClickExport => ')
509
+      if (!this.pagination.total) return this.$message.warning('暂无数据可导出')
510
+      this.loading = true
511
+      this.$axios.get(`${this.URL.BASEURL}${this.URL.statistics_reg_range_report_new}`, {
512
+        params: {
513
+          begin_date: this.filter.time[0],
514
+          end_date: this.filter.time[1],
515
+          total_roi_min: this.totalRoi[0],
516
+          total_roi_max: this.totalRoi[1],
517
+          page: 1,
518
+          page_size: this.$store.state.exportNumber,
519
+        }
520
+      }).then((res) => {
521
+        var res = res.data
522
+        this.loading = false
523
+        if (res && res.errno == 0) {
524
+          this.handleExport(res.rst.data.list)
525
+        } else if (res.errno != 4002) {
526
+          this.$message({
527
+            message: res.err,
528
+            type: "warning"
529
+          })
530
+        }
531
+      }).catch((err) => {
532
+        this.loading = false
533
+      });
534
+    },
535
+    // 执行导出逻辑
536
+    handleExport(data) {
537
+      let list = data;
538
+      let tHeader = this.summaryTableCol.map((v) => {
539
+        return v.name;
540
+      })
541
+      let filterVal = this.summaryTableCol.map((v) => {
542
+        return v.column
543
+      })
544
+      let excelDatas = [
545
+        {
546
+          tHeader: tHeader, // sheet表一头部
547
+          filterVal: filterVal, // 表一的数据字段
548
+          tableDatas: list, // 表一的整体json数据
549
+          sheetName: ''// 表一的sheet名字
550
+        }
551
+      ]
552
+      this.$exportOrder({ excelDatas, name: `账号数据趋势(导出时间:${this.$getDay(0)})` })
553
+    },
554
+    getHeaderCellStyle() {
555
+      return { backgroundColor: '#FFFFFF !important', border: 'none!important' }
556
+    },
557
+  }
558
+}
559
+</script>
560
+<style lang="scss" scoped>
561
+.screenBox {
562
+  position: relative;
563
+  background: #fff;
564
+  padding: 5px 20px;
565
+}
566
+.mt-10 {
567
+  margin-top: 10px;
568
+}
569
+.ml-10 {
570
+  margin-left: 10px;
571
+}
572
+.filter-wrap {
573
+  display: flex;
574
+  align-items: center;
575
+  flex-wrap: wrap;
576
+  padding-bottom: 10px;
577
+  & > div {
578
+    margin: 0 10px 10px 0;
579
+  }
580
+  & > button {
581
+    margin: -10px 0 0 10px;
582
+  }
583
+  .el-button+.el-button {
584
+    margin-left: 10px;
585
+  }
586
+}
587
+.trendBox {
588
+  background: #ffffff;
589
+  padding: 22px 23px;
590
+  position: relative;
591
+  .noData {
592
+    position: absolute;
593
+    top: 100px;
594
+    left: 0;
595
+    right: 0;
596
+    margin: auto;
597
+  }
598
+  .legendBox {
599
+    display: flex;
600
+    align-items: center;
601
+    .legendItem {
602
+      color: #333333;
603
+      font-size: 14px;
604
+      line-height: 20px;
605
+      display: flex;
606
+      align-items: center;
607
+      margin-right: 30px;
608
+      cursor: pointer;
609
+      user-select: none;
610
+    }
611
+  }
612
+}
613
+.summaryTable {
614
+  margin-top: 10px;
615
+}
616
+.detailsTable {
617
+  margin-top: 10px;
618
+}
619
+.sort-wrap {
620
+  display: flex;
621
+  flex-direction: column;
622
+  i {
623
+    cursor: pointer;
624
+    &.active {
625
+      color: #32B38A;
626
+    }
627
+  }
628
+  i:first-child {
629
+    margin-bottom: -3px;
630
+  }
631
+  i:last-child {
632
+    margin-top: -3px;
633
+  }
634
+}
635
+</style>

+ 14 - 0
project/src/router/allRouter.js

@@ -53,7 +53,10 @@ const groupCodeIndex = () => import(/* webpackChunkName: 'groupCodeIndex' */ '@/
53 53
 const createGroupCode = () => import(/* webpackChunkName: 'createGroupCode' */ '@/components/groupCode/createGroupCode.vue')
54 54
 const groupCodeAnalyse = () => import(/* webpackChunkName: 'groupCodeAnalyse' */ '@/components/groupCode/groupCodeAnalyse.vue')
55 55
 
56
+// 数据看板 - 账号数据趋势
56 57
 const accountTrends = () => import(/* webpackChunkName: 'accountTrends' */ '@/components/dataBoard/accountTrends.vue')
58
+// 数据看板 - 短剧数据趋势
59
+const shortDramaTrends = () => import(/* webpackChunkName: 'shortDramaTrends' */ '@/components/dataBoard/shortDramaTrends.vue')
57 60
 
58 61
 // name与菜单配置的页面路由一致
59 62
 // meta下isData:true为数据看板,否则为助手
@@ -437,6 +440,17 @@ export var allRouter = [
437 440
         }
438 441
       },
439 442
       {
443
+        path: 'shortDramaTrends',
444
+        name: 'shortDramaTrends',
445
+        component: shortDramaTrends,
446
+        meta: {
447
+          keepAlive: false,
448
+          isLogin: true,
449
+          title: '短剧数据趋势',
450
+          isData: true
451
+        }
452
+      },
453
+      {
440 454
         path: 'thePublic',
441 455
         name: 'thePublic',
442 456
         component: thePublic,