Bladeren bron

feat: 平台推广数据

zhengxy 10 maanden geleden
bovenliggende
commit
d351d0c99e

+ 1 - 0
project/src/assets/config/interface_api.js

@@ -314,6 +314,7 @@ var api = {
314 314
   dataBoard_customerStaff_setStatus: "/api/user/updateUserStatus", // 客服数据统计 - 更新客服状态
315 315
   dataBoard_chatGroupData_list: "/api/chatGroup/chatGroupStatistic", // 客户群数据 - 列表
316 316
   dataBoard_chatGroupData_summary: "/api/chatGroup/chatGroupCondition", // 客户群数据 - 汇总
317
+  dataBoard_promotionData: '/api/populariz/promotionData', // 平台推广数据
317 318
 
318 319
   getPlatformOptions: "/api/intelligentMassSending/platformIndex", // 平台筛选选项
319 320
   accountManage_accountIndex: "/api/intelligentMassSending/accountIndex", // 平台账号管理 - 账号列表

+ 5 - 0
project/src/assets/js/staticTypes.js

@@ -247,3 +247,8 @@ export const isNewCustomerNoLoss = [
247 247
   { key: 0, val: '否' },
248 248
 ]
249 249
 
250
+export const promotionData = [
251
+  { key: 8, val: '映客' },
252
+  { key: 10, val: '番茄' },
253
+]
254
+

+ 4 - 0
project/src/components/assembly/screen/channel.vue

@@ -44,6 +44,7 @@ import {
44 44
   msgType,
45 45
   groupUserStatus,
46 46
   isNewCustomerNoLoss,
47
+  promotionData,
47 48
 } from '@/assets/js/staticTypes'
48 49
 export default {
49 50
   props: {
@@ -220,6 +221,9 @@ export default {
220 221
     } else if (this.type == 'isNewCustomerNoLoss') { // 是否新用户
221 222
       this.options = [...isNewCustomerNoLoss]
222 223
       this.placeholderVal = '请选择'
224
+    } else if (this.type == 'promotionData') {
225
+      this.options = [...promotionData]
226
+      this.placeholderVal = '请选择'
223 227
     } else {
224 228
       this.init()
225 229
     }

+ 4 - 0
project/src/components/assembly/screen/channelMultiple.vue

@@ -46,6 +46,7 @@ import {
46 46
   msgType,
47 47
   groupUserStatus,
48 48
   isNewCustomerNoLoss,
49
+  promotionData,
49 50
 } from '@/assets/js/staticTypes'
50 51
 export default {
51 52
   props: {
@@ -217,6 +218,9 @@ export default {
217 218
     } else if (this.type == 'isNewCustomerNoLoss') { // 是否新用户
218 219
       this.options = [...isNewCustomerNoLoss]
219 220
       this.placeholderVal = '请选择'
221
+    } else if (this.type == 'promotionData') { // 平台推广数据
222
+      this.options = [...promotionData]
223
+      this.placeholderVal = '请选择'
220 224
     } else {
221 225
       this.init()
222 226
     }

+ 4 - 0
project/src/components/assembly/screen/channelV2.vue

@@ -47,6 +47,7 @@ import {
47 47
   msgType,
48 48
   groupUserStatus,
49 49
   isNewCustomerNoLoss,
50
+  promotionData,
50 51
 } from '@/assets/js/staticTypes'
51 52
 export default {
52 53
   props: {
@@ -494,6 +495,9 @@ export default {
494 495
       } else if (this.type == 'isNewCustomerNoLoss') { // 是否新用户
495 496
         this.options = [...isNewCustomerNoLoss]
496 497
         this.placeholderVal = '请选择'
498
+      } else if (this.type == 'promotionData') { // 平台推广数据
499
+        this.options = [...promotionData]
500
+        this.placeholderVal = '请选择'
497 501
       } else {
498 502
         this.init()
499 503
       }

+ 331 - 0
project/src/components/dataBoard/promotionData.vue

@@ -0,0 +1,331 @@
1
+<template>
2
+  <div v-loading="loading">
3
+    <div class="screenBox flex-align-center">
4
+      <div class="flex-align-center" style="flex: 1">
5
+        <datePicker title="自定义" :is_include_today="false" :pickerOptions="pickerOptions" :quickFlag="true" :afferent_time="default_time" :clearFlag="false" @changeTime="changeTime" />
6
+        <selfInputV2 v-model="keyword" label_name="标题" placeholder="请输入关键字" labelWidth @change="onChangeKeyword" />
7
+        <selfChannelV2 v-model="plat_type" type='promotionData' title="平台" @change="onChangePlatType" />
8
+      </div>
9
+      <div class="right">
10
+        <el-button v-if="isCanExport" type="primary" size="mini" @click="init(1, 'export')">导出Excel</el-button>
11
+      </div>
12
+    </div>
13
+    <div class="dataInfoBox">
14
+      <div
15
+        class="dataInfoItem"
16
+        v-for="(item, index) in dataInfoArrs"
17
+        :key="index"
18
+      >
19
+        <div class="dataItemTitle">
20
+          <img :src="item.icon" style="height: 14px" class="titleIcon" />
21
+          <span>{{ item.label }}</span>
22
+        </div>
23
+        <div class="dataItem-data">
24
+          {{
25
+            dataInfo && (dataInfo[item.prop] || dataInfo[item.prop] == 0)
26
+              ? $formatNum(dataInfo[item.prop])
27
+              : "-"
28
+          }}
29
+          <span class="f15">{{
30
+            item.brackets_prop
31
+              ? `(${
32
+                  dataInfo &&
33
+                  (dataInfo[item.brackets_prop] ||
34
+                    dataInfo[item.brackets_prop] == 0)
35
+                    ? $formatNum(dataInfo[item.brackets_prop])
36
+                    : "-"
37
+                })`
38
+              : ""
39
+          }}</span>
40
+        </div>
41
+      </div>
42
+    </div>
43
+    <div>
44
+      <ux-grid
45
+        ref="plxTable"
46
+        :border="false"
47
+        @row-click="
48
+          () => {
49
+            return;
50
+          }
51
+        "
52
+        :header-cell-style="
53
+          () => {
54
+            return {
55
+              backgroundColor: '#FFFFFF !important',
56
+              border: 'none!important',
57
+            };
58
+          }
59
+        "
60
+        :height="height"
61
+        show-footer-overflow="tooltip"
62
+        show-overflow="tooltip"
63
+        size="mini"
64
+      >
65
+        <ux-table-column
66
+          v-for="item in desCol"
67
+          v-if="!item.excelShow"
68
+          :key="item.prop"
69
+          :resizable="true"
70
+          :field="item.prop"
71
+          :title="item.label"
72
+          :min-width="item.min_width ? item.min_width : 120"
73
+          :fixed="item.fixed ? item.fixed : ''"
74
+          align="center"
75
+        >
76
+          <template #header>
77
+            <div :class="['flex-align-jus-center']">
78
+              {{ item.label
79
+              }}{{ item.brackets_label ? `(${item.brackets_label})` : "" }}
80
+              <el-tooltip
81
+                v-if="item.notes"
82
+                :content="item.notes"
83
+                placement="top"
84
+              >
85
+                <div><i class="el-icon-question"></i></div>
86
+              </el-tooltip>
87
+            </div>
88
+          </template>
89
+          <template v-slot="{ row }">
90
+            <span v-if="item.prop === 'pid' || item.prop === 'adq_account_id'">{{ row[item.prop] }}</span>
91
+            <span v-else-if="item.prop === 'plat_type'">{{ row[item.prop] == 10 ? '番茄' : (row[item.prop] == 8 ? '映客' : '') }}</span>
92
+            <span v-else>{{ row[item.prop] !== "" && (row[item.prop] || row[item.prop] === 0 || row[item.prop] === "0")   ? $formatNum(row[item.prop])   : "-" }}</span>
93
+            <span v-if="item.brackets_label" >({{   row[item.brackets_prop] != "" && (row[item.brackets_prop] || row[item.brackets_prop] == 0) ? $formatNum(row[item.brackets_prop]) : "-" }})</span>
94
+          </template>
95
+        </ux-table-column>
96
+      </ux-grid>
97
+      <div class="pagination" v-show="total > 0">
98
+        <el-pagination
99
+          background
100
+          :current-page="page"
101
+          @current-change="handleCurrentChange"
102
+          layout="prev, pager, next, sizes, jumper"
103
+          :page-sizes="[20, 50, 100]"
104
+          @size-change="handleSizeChange"
105
+          :page-count="Number(pages)"
106
+        />
107
+      </div>
108
+    </div>
109
+  </div>
110
+</template>
111
+<script>
112
+import datePicker from "@/components/assembly/screen/datePicker.vue";
113
+import selfChannelV2 from "@/components/assembly/screen/channelV2.vue";
114
+import selfInputV2 from "@/components/assembly/screen/inputV2.vue";
115
+
116
+export default {
117
+  components: { selfChannelV2, datePicker, selfInputV2 },
118
+  data() {
119
+    return {
120
+      loading: false,
121
+      default_time: [this.$getDay(-8, false), this.$getDay(-1, false)],
122
+      pickerOptions: {
123
+        disabledDate(time) {
124
+          return time > Date.now() - 8.64e7;
125
+        },
126
+      },
127
+      height: "",
128
+      keyword: "",
129
+      plat_type: "",
130
+      time: [],
131
+      dataInfoArrs: [
132
+        {
133
+          prop: "cost",
134
+          label: "消耗金额",
135
+          icon: require("@/assets/img/icon/累计消耗@2x.png"),
136
+        },
137
+        {
138
+          prop: "first_day_charge",
139
+          label: "充值金额",
140
+          icon: require("@/assets/img/icon/累计充值@2x.png"),
141
+        },
142
+        {
143
+          prop: "first_roi",
144
+          label: "首日roi",
145
+          icon: require("@/assets/img/icon/roi@2x.png"),
146
+        }
147
+      ],
148
+      dataInfo: {},
149
+      desCol: [
150
+        { prop: "populariz_title", label: "推广标题", fixed: "left", min_width: "160" },
151
+        { prop: "pid", label: "推广ID", min_width: "160" },
152
+        { prop: "ref_date", label: "日期", min_width: "160" },
153
+        { prop: "plat_type", label: "平台" },
154
+        { prop: "adq_account_id", label: "投放账号" },
155
+        { prop: "cost", label: "消耗金额" },
156
+        { prop: "first_day_charge", label: "充值金额" },
157
+        { prop: "first_roi", label: "首日roi" },
158
+      ],
159
+      page: 1,
160
+      pages: 0,
161
+      total: 0,
162
+      page_size: 20,
163
+    };
164
+  },
165
+  computed: {
166
+    // 是否有“导出”权限
167
+    isCanExport() {
168
+      return !!this.$store.state.dataBoardAuth.can_export;
169
+    },
170
+  },
171
+  created() {
172
+    this.time = this.default_time;
173
+    this.height =
174
+      document.documentElement.clientHeight - 400 > 400
175
+        ? document.documentElement.clientHeight - 400
176
+        : 400;
177
+    this.init(1);
178
+  },
179
+  methods: {
180
+    changeTime(time) {
181
+      //筛选时间变化
182
+      if (!time || (time && time.length == 0)) {
183
+        this.time = [];
184
+      } else {
185
+        this.time = time;
186
+      }
187
+      this.init(1);
188
+    },
189
+    init(page, type) {
190
+      if (type != "export") {
191
+        this.page = page ? page : this.page;
192
+      } else {
193
+        if (this.total == 0) {
194
+          this.$message({
195
+            message: "暂无数据可导出",
196
+            type: "warning",
197
+          });
198
+          return;
199
+        }
200
+      }
201
+      this.loading = true;
202
+      this.$axios
203
+        .get(this.URL.BASEURL + this.URL.dataBoard_promotionData, {
204
+          params: {
205
+            send_time_start: this.time[0],
206
+            send_time_end: this.time[1],
207
+            keyword: this.keyword,
208
+            plat_type: this.plat_type,
209
+            page: type == "export" ? 1 : this.page,
210
+            page_size:
211
+              type == "export"
212
+                ? this.$store.state.exportNumber
213
+                : this.page_size,
214
+          },
215
+        })
216
+        .then((res) => {
217
+          var res = res.data;
218
+          this.loading = false;
219
+          if (res && res.errno == 0) {
220
+            console.log("res => ", res);
221
+            if (res.rst.extra) {
222
+              // 汇总数据
223
+              this.dataInfo = res.rst.extra;
224
+            }
225
+            if (type == "export") {
226
+              // 列表导出
227
+              this.exportEvent(res.rst.data);
228
+            } else {
229
+              // 列表数据
230
+              this.datas = res.rst.data;
231
+              this.$refs.plxTable && this.$refs.plxTable.reloadData(this.datas);
232
+              this.total = res.rst.pageInfo.total;
233
+              this.pages = res.rst.pageInfo.pages;
234
+            }
235
+          } else if (res.errno != 4002) {
236
+            this.$message({
237
+              message: res.err,
238
+              type: "warning",
239
+            });
240
+          }
241
+        })
242
+        .catch((err) => {
243
+          this.loading = false;
244
+        });
245
+    },
246
+    handleCurrentChange(val) {
247
+      this.init(val);
248
+    },
249
+    handleSizeChange(page_size) {
250
+      this.page_size = page_size;
251
+      this.init(1);
252
+    },
253
+    exportEvent(data) {
254
+      let list = data;
255
+      let tHeader = this.desCol.map((v) => {
256
+        return v.label;
257
+      });
258
+      let filterVal = this.desCol.map((v) => {
259
+        return v.prop;
260
+      });
261
+      let excelDatas = [
262
+        {
263
+          tHeader: tHeader, // sheet表一头部
264
+          filterVal: filterVal, // 表一的数据字段
265
+          tableDatas: list, // 表一的整体json数据
266
+          sheetName: "", // 表一的sheet名字
267
+        },
268
+      ];
269
+      this.$exportOrder({
270
+        excelDatas,
271
+        name: `平台推广数据(导出时间:${this.$getDay(0)})`,
272
+      });
273
+    },
274
+    onChangeKeyword(val) {
275
+      this.keyword = val;
276
+      this.init(1);
277
+    },
278
+    onChangePlatType(val) {
279
+      this.plat_type = val || ''
280
+      this.init(1);
281
+    },
282
+  },
283
+};
284
+</script>
285
+<style lang="scss" scoped>
286
+.screenBox {
287
+  background: #fff;
288
+  padding: 5px 20px;
289
+}
290
+
291
+.dataInfoBox {
292
+  display: flex;
293
+  margin-top: 10px;
294
+  flex-wrap: wrap;
295
+
296
+  .dataInfoItem {
297
+    background: #ffffff;
298
+    border-radius: 8px;
299
+    margin-right: 10px;
300
+    margin-bottom: 10px;
301
+    padding: 0 19px;
302
+    height: 70px;
303
+    display: flex;
304
+    flex-direction: column;
305
+    justify-content: center;
306
+    align-items: center;
307
+
308
+    .dataItemTitle {
309
+      display: flex;
310
+      align-items: center;
311
+      color: #6f6f6f;
312
+      font-size: 13px;
313
+      line-height: 17px;
314
+      font-weight: bold;
315
+
316
+      .titleIcon {
317
+        height: 16px;
318
+        margin-right: 4px;
319
+      }
320
+    }
321
+
322
+    .dataItem-data {
323
+      color: #000000;
324
+      font-size: 19px;
325
+      line-height: 28px;
326
+      font-weight: bold;
327
+      margin-top: 2px;
328
+    }
329
+  }
330
+}
331
+</style>

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

@@ -40,6 +40,7 @@ const playletData = () => import(/* webpackChunkName: 'playletData' */ '@/compon
40 40
 const operateDayRetrieve = () => import(/* webpackChunkName: 'operateDayRetrieve' */ '@/components/dataBoard/operateDayRetrieve.vue')
41 41
 const populariz = () => import(/* webpackChunkName: 'populariz' */ '@/components/dataBoard/populariz/index.vue')
42 42
 const sendData = () => import(/* webpackChunkName: 'sendData' */ '@/components/dataBoard/sendData/index.vue')
43
+const promotionData = () => import(/* webpackChunkName: 'promotionData' */ '@/components/dataBoard/promotionData.vue')
43 44
 const throwPerson = () => import(/* webpackChunkName: 'throwPerson' */ '@/components/dataBoard/throwPerson/index.vue')
44 45
 const regRangeReport = () => import(/* webpackChunkName: 'regRangeReport' */ '@/components/dataBoard/regRangeReport.vue')
45 46
 const regRangeReportHS = () => import(/* webpackChunkName: 'regRangeReportHS' */ '@/components/dataBoard/regRangeReportHS.vue')
@@ -876,6 +877,17 @@ export var allRouter = [
876 877
         }
877 878
       },
878 879
       {
880
+        path: 'promotionData',
881
+        name: 'promotionData',
882
+        component: promotionData,
883
+        meta: {
884
+          keepAlive: false,
885
+          isLogin: true,
886
+          title: '平台推广数据',
887
+          isData: true
888
+        }
889
+      },
890
+      {
879 891
         path: 'throwPerson',
880 892
         name: 'throwPerson',
881 893
         component: throwPerson,