Browse Source

feat: 企微数据 - 粉丝激活趋势 - 前端页面

zhengxy 2 years ago
parent
commit
4798dad7de

+ 654 - 0
project/src/components/dataBoard/fansActiveTrends.vue

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

+ 1 - 1
project/src/components/dataBoard/shortDramaTrends.vue

@@ -145,7 +145,7 @@ export default {
145 145
       filter: {
146 146
         order_type: orderTypeOptions.MP,
147 147
         time: DEFAULT_TIME, // 自定义日期
148
-        playlet_id: '', // 账号MP
148
+        playlet_id: '', // 短剧
149 149
         closing_date: '', // 收益截止日期
150 150
         promotion_type: '', // 推广类型
151 151
         totalRoi: ['', ''], // 回本率(范围)

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

@@ -57,6 +57,8 @@ const groupCodeAnalyse = () => import(/* webpackChunkName: 'groupCodeAnalyse' */
57 57
 const accountTrends = () => import(/* webpackChunkName: 'accountTrends' */ '@/components/dataBoard/accountTrends.vue')
58 58
 // 数据看板 - 短剧数据趋势
59 59
 const shortDramaTrends = () => import(/* webpackChunkName: 'shortDramaTrends' */ '@/components/dataBoard/shortDramaTrends.vue')
60
+// 数据看板 - 粉丝激活趋势
61
+const fansActiveTrends = () => import(/* webpackChunkName: 'fansActiveTrends' */ '@/components/dataBoard/fansActiveTrends.vue')
60 62
 
61 63
 // name与菜单配置的页面路由一致
62 64
 // meta下isData:true为数据看板,否则为助手
@@ -451,6 +453,17 @@ export var allRouter = [
451 453
         }
452 454
       },
453 455
       {
456
+        path: 'fansActiveTrends',
457
+        name: 'fansActiveTrends',
458
+        component: fansActiveTrends,
459
+        meta: {
460
+          keepAlive: false,
461
+          isLogin: true,
462
+          title: '粉丝激活趋势',
463
+          isData: true
464
+        }
465
+      },
466
+      {
454 467
         path: 'thePublic',
455 468
         name: 'thePublic',
456 469
         component: thePublic,