Browse Source

投手数据

houxiaohua 6 months ago
parent
commit
408c3fc0de
69 changed files with 866 additions and 56 deletions
  1. 1 1
      dist/assets/index-DkEyGQlH.css
  2. 2 0
      dist/assets/index-BqJQZnq2.js
  3. 0 2
      dist/assets/index-_SrrqTY2.js
  4. 1 0
      dist/assets/index-fX4pqW2g.css
  5. 1 1
      dist/index.html
  6. 1 1
      dist/js/Home/index.COF239Tt.js
  7. 1 1
      dist/js/_dialog/_dialog.Cpytk8fu.js
  8. 1 1
      dist/js/_input/_input.jWWQm4vg.js
  9. 1 1
      dist/js/_inputAppend/_inputAppend.CCJ1GuXW.js
  10. 1 1
      dist/js/_select/_select.C6pFIK_J.js
  11. 1 1
      dist/js/_tooltip/_tooltip.DiJSvxgS.js
  12. 0 1
      dist/js/acStatement/index.BOCDSglN.js
  13. 1 0
      dist/js/acStatement/index.D3FKJpvY.js
  14. 1 1
      dist/js/adAccountGroup/index.DlhBs_je.js
  15. 1 1
      dist/js/adTask/index.D-li6PBo.js
  16. 1 1
      dist/js/adTask3/index.Dvy9lQZd.js
  17. 1 1
      dist/js/adqManage/index.CvVqvSKv.js
  18. 1 1
      dist/js/adqManage3/index.ByWW73rk.js
  19. 1 1
      dist/js/api/api.TK6ShRug.js
  20. 1 1
      dist/js/api/api.Cy7QJEb6.js
  21. 1 1
      dist/js/api/api.C9algqxV.js
  22. 1 1
      dist/js/basisMoudle/error.B2jce3A_.js
  23. 1 1
      dist/js/basisMoudle/login.DppgjDEY.js
  24. 1 1
      dist/js/checkboxDefault/checkboxDefault.D0ssFWr7.js
  25. 1 1
      dist/js/collectClip/index.BZ2ALwGp.js
  26. 1 1
      dist/js/commonList/commonList.iYHf4_OJ.js
  27. 1 1
      dist/js/configArea/index.CP5T6sX-.js
  28. 1 1
      dist/js/configArea/index.CtmsqZ3_.js
  29. 1 1
      dist/js/define/define.DylUo_PP.js
  30. 1 0
      dist/js/gdtList/index.J84JGOt1.js
  31. 0 1
      dist/js/gdtList/index.fjOMQgJd.js
  32. 1 1
      dist/js/gdtList3/index.COgA4CNN.js
  33. 0 1
      dist/js/index/index.BCGc-LRM.js
  34. 1 1
      dist/js/index/index.Be-j9UFA.js
  35. 1 0
      dist/js/index/index.CJcjcXY5.js
  36. 1 1
      dist/js/index/index.RhGaqGG_.js
  37. 1 1
      dist/js/index/index.DLEPT1Y6.js
  38. 1 1
      dist/js/layout/index.CGiovUbn.js
  39. 1 1
      dist/js/layout/index_head.BRAZe66a.js
  40. 1 1
      dist/js/limitManage/index.B1ouhM9X.js
  41. 1 0
      dist/js/list/list.BUCn_3yl.js
  42. 1 1
      dist/js/materialBlock/materialBlock.DVtJ0-M2.js
  43. 1 0
      dist/js/materialData/index.B9z8QG7o.js
  44. 0 1
      dist/js/materialData/index.DigymOlM.js
  45. 1 1
      dist/js/materialLibrary/index.ClN8MML4.js
  46. 1 1
      dist/js/materialTs/materialTs.gF1T6kO5.js
  47. 1 1
      dist/js/memberManage/index.CnblNNx_.js
  48. 1 1
      dist/js/menu/index.BQp1HIwt.js
  49. 1 1
      dist/js/miniprogram/index.DpkOeVjv.js
  50. 1 1
      dist/js/oeAdAccount/index.CoCgnY3I.js
  51. 1 0
      dist/js/oePromoterData/index.DaND-OOc.js
  52. 1 1
      dist/js/projectManage/index.jVe64Rgo.js
  53. 1 1
      dist/js/radioGroup/radioGroup.BKxaY0nx.js
  54. 1 1
      dist/js/tableInfo/tableInfo.CgDJWhsq.js
  55. 1 1
      dist/js/tagBlock/tagBlock.B2YbYFuy.js
  56. 1 1
      dist/js/taskList/index.jdVmIrpe.js
  57. 1 1
      dist/js/teamManage/index.TnFlrTtW.js
  58. 1 1
      dist/js/timeScreen/timeScreen.DGLDz8LF.js
  59. 1 1
      dist/js/warning/warning.Dqc5b6DR.js
  60. 1 1
      dist/js/wechatPage/index.BHh7fTUF.js
  61. 1 1
      dist/js/weekTime/weekTime.Caf7R77p.js
  62. 1 1
      dist/js/weekTime/weekTime.BCcYysXu.js
  63. 1 0
      src/api/api.ts
  64. 1 1
      src/components/businessMoudle/dataManagement/acStatement/dataList.vue
  65. 271 0
      src/components/businessMoudle/dataManagement/oePromoterData/dataList.vue
  66. 41 0
      src/components/businessMoudle/dataManagement/oePromoterData/hooks/index.ts
  67. 357 0
      src/components/businessMoudle/dataManagement/oePromoterData/hooks/trend.ts
  68. 128 0
      src/components/businessMoudle/dataManagement/oePromoterData/index.vue
  69. 9 0
      src/router/index.ts

File diff suppressed because it is too large
+ 1 - 1
dist/assets/index-DkEyGQlH.css


File diff suppressed because it is too large
+ 2 - 0
dist/assets/index-BqJQZnq2.js


File diff suppressed because it is too large
+ 0 - 2
dist/assets/index-_SrrqTY2.js


File diff suppressed because it is too large
+ 1 - 0
dist/assets/index-fX4pqW2g.css


+ 1 - 1
dist/index.html

@@ -12,7 +12,7 @@
12 12
 			document.write('<script src="' + src + '"><\/script>');
13 13
 			})();
14 14
     </script>
15
-    <script type="module" crossorigin src="./assets/index-_SrrqTY2.js"></script>
15
+    <script type="module" crossorigin src="./assets/index-BqJQZnq2.js"></script>
16 16
     <link rel="modulepreload" crossorigin href="./js/@vue/@vue.lccsL1Mu.js">
17 17
     <link rel="modulepreload" crossorigin href="./js/vue-router/vue-router.D86bYXwF.js">
18 18
     <link rel="modulepreload" crossorigin href="./js/vue-demi/vue-demi.Dq6ymT-8.js">

File diff suppressed because it is too large
+ 1 - 1
dist/js/Home/index.COF239Tt.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/_dialog/_dialog.Cpytk8fu.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/_input/_input.jWWQm4vg.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/_inputAppend/_inputAppend.CCJ1GuXW.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/_select/_select.C6pFIK_J.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/_tooltip/_tooltip.DiJSvxgS.js


File diff suppressed because it is too large
+ 0 - 1
dist/js/acStatement/index.BOCDSglN.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/acStatement/index.D3FKJpvY.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/adAccountGroup/index.DlhBs_je.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/adTask/index.D-li6PBo.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/adTask3/index.Dvy9lQZd.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/adqManage/index.CvVqvSKv.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/adqManage3/index.ByWW73rk.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/api/api.TK6ShRug.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/api/api.Cy7QJEb6.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/api/api.C9algqxV.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/basisMoudle/error.B2jce3A_.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/basisMoudle/login.DppgjDEY.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/checkboxDefault/checkboxDefault.D0ssFWr7.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/collectClip/index.BZ2ALwGp.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/commonList/commonList.iYHf4_OJ.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/configArea/index.CP5T6sX-.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/configArea/index.CtmsqZ3_.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/define/define.DylUo_PP.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/gdtList/index.J84JGOt1.js


File diff suppressed because it is too large
+ 0 - 1
dist/js/gdtList/index.fjOMQgJd.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/gdtList3/index.COgA4CNN.js


File diff suppressed because it is too large
+ 0 - 1
dist/js/index/index.BCGc-LRM.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/index/index.Be-j9UFA.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/index/index.CJcjcXY5.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/index/index.RhGaqGG_.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/index/index.DLEPT1Y6.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/layout/index.CGiovUbn.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/layout/index_head.BRAZe66a.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/limitManage/index.B1ouhM9X.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/list/list.BUCn_3yl.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/materialBlock/materialBlock.DVtJ0-M2.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/materialData/index.B9z8QG7o.js


File diff suppressed because it is too large
+ 0 - 1
dist/js/materialData/index.DigymOlM.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/materialLibrary/index.ClN8MML4.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/materialTs/materialTs.gF1T6kO5.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/memberManage/index.CnblNNx_.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/menu/index.BQp1HIwt.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/miniprogram/index.DpkOeVjv.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/oeAdAccount/index.CoCgnY3I.js


File diff suppressed because it is too large
+ 1 - 0
dist/js/oePromoterData/index.DaND-OOc.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/projectManage/index.jVe64Rgo.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/radioGroup/radioGroup.BKxaY0nx.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/tableInfo/tableInfo.CgDJWhsq.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/tagBlock/tagBlock.B2YbYFuy.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/taskList/index.jdVmIrpe.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/teamManage/index.TnFlrTtW.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/timeScreen/timeScreen.DGLDz8LF.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/warning/warning.Dqc5b6DR.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/wechatPage/index.BHh7fTUF.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/weekTime/weekTime.Caf7R77p.js


File diff suppressed because it is too large
+ 1 - 1
dist/js/weekTime/weekTime.BCcYysXu.js


+ 1 - 0
src/api/api.ts

@@ -177,6 +177,7 @@ export enum Api{
177 177
     report_ratio = '/api/report/ratio',
178 178
     report_accountReportList = '/api/report/accountReportList',
179 179
     report_projectReportList = '/api/report/projectReportList',
180
+    oe_promoter_data_report_list = '/api/report/promoterDataReport',
180 181
 
181 182
     materialData_videoView = '/api/report/videoView',
182 183
     materialData_videoReportList = '/api/report/videoReportList',

+ 1 - 1
src/components/businessMoudle/dataManagement/acStatement/dataList.vue

@@ -11,7 +11,7 @@
11 11
       <el-table ref="tableAccountRef" :data="tableInfo.tableList" :header-cell-style="tableHeaderStyle"
12 12
         style="width: 100%;" :key="tableInfo.updateKey" border empty-text="暂无数据" :summary-method="getSummaries" show-summary
13 13
         max-height="calc(100vh - 280px)">
14
-        <template v-for="item in tableInfo.descol">
14
+        <template v-if="tableInfo.total>0" v-for="item in tableInfo.descol">
15 15
           <el-table-column :fixed="item.disabled == 1" :prop="item.key_value"
16 16
             :min-width="item.key_value != 'advertiser_status' && item.key_value != 'advertiser_nick' && item.label.length <= 4 ? '120px' : item.label.length <= 8 ? '150px' : '200px'">
17 17
             <template #header>

+ 271 - 0
src/components/businessMoudle/dataManagement/oePromoterData/dataList.vue

@@ -0,0 +1,271 @@
1
+<template>
2
+  <div v-loading="loading" class="table_container">
3
+    <div class="tableTop">
4
+      <div class="title"></div>
5
+      <div>
6
+        <el-button class="lMar10" type="primary" plain @click="exportEvent">导出数据</el-button>
7
+      </div>
8
+    </div>
9
+    <div>
10
+      <el-table ref="tableAccountRef" :data="tableInfo.tableList" :header-cell-style="tableHeaderStyle"
11
+        style="width: 100%;" :key="tableInfo.updateKey" border empty-text="暂无数据" :summary-method="getSummaries" show-summary
12
+        max-height="calc(100vh - 280px)">
13
+        <template v-if="tableInfo.total>0" v-for="item in tableInfo.descol">
14
+          <el-table-column :fixed="item.disabled == 1" :prop="item.key_value"
15
+            :min-width="item.key_value != 'advertiser_status' && item.key_value != 'advertiser_nick' && item.label.length <= 4 ? '120px' : item.label.length <= 8 ? '150px' : '200px'">
16
+            <template #header>
17
+              <div class="flex" :class="[tableInfo.sortKey == item.key_value ? 'active_css' : '']">
18
+                <span :style="{ color: tableInfo.sortKey == item.key_value ? '#3173FF' : '' }">{{ item.label }}</span>
19
+                <el-tooltip v-if="item.tooltip && item.tooltip != item.label" placement="top" effect="dark"
20
+                  :content="item.tooltip"><i-ep-QuestionFilled class="lMar5 c-999 f14 pointer" /></el-tooltip>
21
+                <div v-if="item.if_sort == 1" class="sortBox lMar5 pointer">
22
+                  <div class="sortItem" @click="sortEvent(item.key_value, 'asc')">
23
+                    <el-icon
24
+                      :color="(tableInfo.sortType == 'asc' && tableInfo.sortKey == item.key_value) ? '#3173FF' : ''"><i-ep-CaretTop /></el-icon>
25
+                  </div>
26
+                  <div class="sortItem" @click="sortEvent(item.key_value, 'desc')">
27
+                    <el-icon
28
+                      :color="(tableInfo.sortType == 'desc' && tableInfo.sortKey == item.key_value) ? '#3173FF' : ''"><i-ep-CaretBottom /></el-icon>
29
+                  </div>
30
+                </div>
31
+              </div>
32
+            </template>
33
+            <template #default="scope">
34
+              <!-- 其他 -->
35
+              <div class="cellDiv" :class="tableInfo.sortKey == item.key_value ? 'active_css' : ''">
36
+                <el-tooltip :disabled="!(scope.row[item.key_value] && scope.row[item.key_value].length > 30)"
37
+                  effect="dark" :content="scope.row[item.key_value] + ''">
38
+                  <div class="clampTwo line21" style="flex: 1">
39
+                    {{ scope.row[item.key_value] || scope.row[item.key_value] == 0 ? (item.label.indexOf('ID') != -1 || item.label.indexOf('id') != -1 ? scope.row[item.key_value] : hasDot(scope.row[item.key_value], 2, true)) : '-'  }}<span
40
+                      v-if="item.label.indexOf('率') != -1 && (scope.row[item.key_value] || scope.row[item.key_value] == 0)">%</span>
41
+                  </div>
42
+                </el-tooltip>
43
+              </div>
44
+            </template>
45
+          </el-table-column>
46
+        </template>
47
+      </el-table>
48
+      <div class="paginationBox flex" style="justify-content: center" v-if="Number(tableInfo.total) > 0">
49
+        <el-pagination v-model:currentPage="tableInfo.currentPage" v-model:page-size="tableInfo.pageSize" background
50
+          :total="tableInfo.total" @current-change="handleCurrentChange" />
51
+      </div>
52
+    </div>
53
+  </div>
54
+</template>
55
+<script setup lang="ts">
56
+import { nextTick, onMounted, reactive, ref } from "vue";
57
+import { listTs } from "@/components/businessMoudle/gdtList/ts/list";
58
+import { Api } from "@/api/api";
59
+import { ElMessage } from "element-plus";
60
+import { getDay, hasDot } from "@/common/common";
61
+import http from "@/http/http";
62
+import { exportOrder } from "@/common/export/index.js";
63
+import Indicators from '@/components/businessMoudle/gdtList/indicators/index.vue'
64
+
65
+const props = defineProps({
66
+  mainPageInfo: {
67
+    type: Object,
68
+    default: () => { }
69
+  }
70
+})
71
+
72
+const downLoadTableRef = ref()
73
+const tableAccountRef = ref()
74
+const loading = ref<boolean>(false)
75
+const tableInfo = reactive<any>({
76
+  tableList: [],
77
+  descol: [],
78
+  summary: [],
79
+  sortKey: '',
80
+  currentPage: 1,
81
+  pageSize: 20,
82
+  total: 0,
83
+  totalPages: 0,//共多少页
84
+  sortType: 'desc',
85
+  updateKey: 1,
86
+})
87
+
88
+
89
+//排序
90
+const sortEvent = (row: any, order: string) => {
91
+  tableInfo.sortType = order;
92
+  tableInfo.sortKey = row
93
+  init(1)
94
+}
95
+
96
+//分页
97
+const handleCurrentChange = (val) => {
98
+  tableInfo.currentPage = val
99
+  init(val)
100
+}
101
+
102
+//导出
103
+const exportEvent = async () => {
104
+  loading.value = true;
105
+  let params = {
106
+    page: 1,
107
+    pageSize: 1000,
108
+    start_date: props.mainPageInfo.time[0],
109
+    end_date: props.mainPageInfo.time[1],
110
+    has_cost: props.mainPageInfo.has_cost,
111
+    promoter_id: props.mainPageInfo.promoter_id,
112
+    advertiser_name: props.mainPageInfo.keyword,
113
+  }
114
+  let res: any = await http.get(Api.oe_promoter_data_report_list, params)
115
+  loading.value = false;
116
+  if (res && res.errNo == '0') {
117
+    let list = res.rst.data.list;
118
+    let descol = [{
119
+        disabled: 1,
120
+        if_sort: 0,
121
+        key_value: "date",
122
+        label: "日期",
123
+        tooltip: ""
124
+      }].concat(res.rst.data?.explain)
125
+
126
+    let tHeader = descol.map((v) => {
127
+      return v.label;
128
+    })
129
+    let filterVal = descol.map((v) => {
130
+      return v.key_value
131
+    })
132
+    let excelDatas = [
133
+      {
134
+        tHeader: tHeader, // sheet表一头部
135
+        filterVal: filterVal, // 表一的数据字段
136
+        tableDatas: list, // 表一的整体json数据
137
+        sheetName: ''// 表一的sheet名字
138
+      }
139
+    ]
140
+    exportOrder({ excelDatas, name: `数据报表(导出时间:${getDay(0)})` })
141
+  } else {
142
+    ElMessage.error(res.errMsg)
143
+  }
144
+}
145
+
146
+//列表
147
+const init = async (page?: any, pageSize?: any) => {
148
+  loading.value = true;
149
+  let params = {
150
+    page: page ? page : tableInfo.currentPage,
151
+    page_size: pageSize ? pageSize : tableInfo.pageSize,
152
+    start_date: props.mainPageInfo.time[0],
153
+    end_date: props.mainPageInfo.time[1],
154
+    has_cost: props.mainPageInfo.has_cost,
155
+    promoter_id: props.mainPageInfo.promoter_id,
156
+    advertiser_name: props.mainPageInfo.keyword,
157
+  }
158
+  let res: any = await http.get(Api.oe_promoter_data_report_list, params)
159
+  loading.value = false;
160
+  if (res && res.errNo == '0') {
161
+    if (res.rst?.data?.summary?.length > 0) {
162
+      tableInfo.summary = res.rst?.data?.summary[0];
163
+    }
164
+    tableInfo.descol = [{
165
+        disabled: 1,
166
+        if_sort: 0,
167
+        key_value: "date",
168
+        label: "日期",
169
+        tooltip: ""
170
+      }].concat(res.rst?.data?.explain);
171
+    tableInfo.tableList = res.rst?.data?.list;
172
+    tableInfo.total = res.rst?.pageInfo.total
173
+    tableInfo.totalPages = res.rst?.pageInfo.total
174
+    tableInfo.updateKey ++;
175
+  } else {
176
+    ElMessage.error(res.errMsg)
177
+  }
178
+}
179
+
180
+/**合计计算 */
181
+const getSummaries = (param) => {
182
+  const { columns, data } = param
183
+  const sums: string[] = []
184
+  columns.forEach((column, index) => {
185
+    if (index === 0) {
186
+      sums[index] = ''
187
+      return
188
+    }
189
+    if (index === 1) {
190
+      sums[index] = '合计'
191
+      return
192
+    }
193
+    if (tableInfo.summary[column.property] && tableInfo.summary[column.property] != 0) {
194
+      let info = tableInfo.descol.filter((v) => {
195
+        return v.key_value == column.property
196
+      })
197
+      if (info.length > 0 && info[0].label?.indexOf('率') != -1) {
198
+        sums[index] = hasDot(tableInfo.summary[column.property], 2, false) + '%'
199
+      } else {
200
+        sums[index] = hasDot(tableInfo.summary[column.property], 2, true)
201
+      }
202
+    } else {
203
+      sums[index] = ''
204
+    }
205
+  })
206
+  return sums
207
+}
208
+
209
+const {
210
+  tableHeaderStyle,
211
+} = listTs()
212
+
213
+// 暴露自己的属性供父组件使用
214
+defineExpose({
215
+  init,
216
+});
217
+</script>
218
+<style lang="scss" scoped>
219
+:deep(.el-table__body-wrapper) {
220
+  order: 1;
221
+}
222
+
223
+:deep(.el-table__footer-wrapper) {
224
+  border-bottom: var(--el-table-border);
225
+  border-top: none;
226
+}
227
+
228
+:deep(.el-table__footer-wrapper tbody td.el-table__cell) {
229
+  background-color: #fafafa;
230
+}
231
+
232
+.el-table th div.cell {
233
+  white-space: nowrap;
234
+  text-overflow: ellipsis;
235
+  overflow: hidden;
236
+  max-width: 600px;
237
+  /* 设置最大宽度,根据需要调整 */
238
+}
239
+
240
+.table_container {
241
+  background-color: #fff;
242
+  margin-top: 10px;
243
+  padding: 20px;
244
+}
245
+
246
+.sortBox {
247
+  height: 16px;
248
+  margin-left: 2px;
249
+  margin-top: -4px;
250
+
251
+  .sortItem {
252
+    width: 8px;
253
+    height: 8px;
254
+    line-height: 8px;
255
+    cursor: pointer;
256
+    color: #999;
257
+  }
258
+}
259
+
260
+.tableTop {
261
+  display: flex;
262
+  align-items: center;
263
+  justify-content: space-between;
264
+  padding-bottom: 20px;
265
+
266
+  .title {
267
+    font-size: 14px;
268
+    color: #333;
269
+    font-weight: bold;
270
+  }
271
+}</style>

+ 41 - 0
src/components/businessMoudle/dataManagement/oePromoterData/hooks/index.ts

@@ -0,0 +1,41 @@
1
+import { Api } from "@/api/api"
2
+import http from "@/http/http"
3
+import { ElMessage } from "element-plus"
4
+import { reactive, ref } from "vue"
5
+import { getDay } from "@/common/common"
6
+
7
+export const ExpIndex = () => {
8
+  const dataListRef = ref()
9
+  const acTrendRef = ref<{change: ()=>void}>()
10
+  const costRef = ref()
11
+  const userRef = ref()
12
+  const pageInfo = reactive({
13
+    data_group: 'account',
14
+    time_type: 'day',
15
+    time: [ getDay(-7), getDay(0) ],
16
+    keyword: '',
17
+    has_cost: '',
18
+    acList: [],
19
+    userList: [],
20
+    promoter_id: '',//投手
21
+  })
22
+
23
+  /**获取操作人列表 */
24
+  const getUserList = async () => {
25
+    let res: any = await http.get(Api.user_list, {})
26
+    if (res && res.errNo == '0') {
27
+      pageInfo.userList = res.rst
28
+    } else {
29
+      ElMessage.error(res.errMsg)
30
+    }
31
+  }
32
+
33
+  return {
34
+    dataListRef,
35
+    acTrendRef,
36
+    userRef,
37
+    costRef,
38
+    pageInfo,
39
+    getUserList,
40
+  }
41
+}

+ 357 - 0
src/components/businessMoudle/dataManagement/oePromoterData/hooks/trend.ts

@@ -0,0 +1,357 @@
1
+import { Api } from "@/api/api"
2
+import http from "@/http/http"
3
+import { ElMessage } from "element-plus"
4
+import { reactive, ref } from "vue"
5
+
6
+export interface IReportTrend {
7
+  st_date: string,
8
+  en_date: string,
9
+  date_group?: string,
10
+  dimension: string,
11
+  keyword?: string,
12
+  user_ids?: any[],
13
+  account_ids?: any[],
14
+  team_ids?: any[],
15
+  top_num: number,
16
+  project_ids?: any[],
17
+  department_ids?: any[]
18
+}
19
+
20
+export const ExpTrend = () => {
21
+  const isCollapsed = ref(false)
22
+  const trendLoading = ref(false)
23
+  const overviewRef = ref()
24
+  const topNumRef = ref()
25
+  const tabInfo = reactive({
26
+    value: 'trend',
27
+    list: [
28
+      { name: '趋势分析', id: 'trend' },
29
+      { name: '占比分析', id: 'ratio' },
30
+    ]
31
+  })
32
+  const overviewData = reactive<{ list: any[], [key: string]: any }>({
33
+    list: [
34
+      { name: '消耗', key: 'cost', unit: '元' },
35
+      { name: '展示数', key: 'view_count' },
36
+      { name: '千次展示均价(CPM)', key: 'thousand_display_price', unit: '元' },
37
+      { name: '点击数', key: 'valid_click_count' },
38
+      { name: '点击率', key: 'ctr' },
39
+      { name: '点击均价', key: 'cpc' },
40
+      { name: '转化数', key: 'conversions_count' },
41
+      { name: '转化率', key: 'conversions_rate' },
42
+      { name: '转化成本', key: 'conversions_cost', unit: '元' },
43
+      { name: '激活数', key: 'activated_count' },
44
+      { name: '注册数', key: 'app_register_count' },
45
+    ],
46
+    legendArr: [],
47
+    trendDataList: [],
48
+    ratioDataList: []
49
+  })
50
+  const topNumList = reactive([
51
+    { name: 'Top5数据', val: 5 },
52
+    { name: 'Top10数据', val: 10 },
53
+  ])
54
+  const trendInfo = reactive({
55
+    option: {},
56
+    heights: '320px',
57
+  })
58
+  const ratioInfo = reactive({
59
+    option: {},
60
+    heights: '320px',
61
+  })
62
+
63
+  /**数据报表 - 趋势分析 */
64
+  const reportTrendEvent = async (params: IReportTrend) => {
65
+    trendLoading.value = true;
66
+    let res: any = await http.get(Api.report_trend, params)
67
+    trendLoading.value = false;
68
+    if (res && res.errNo == '0') {
69
+      overviewData.trendDataList = res.rst;
70
+      getTrend(params.dimension)
71
+    } else {
72
+      ElMessage.error(res.errMsg)
73
+    }
74
+  }
75
+
76
+  /**数据报表 - 占比分析 */
77
+  const reportRatioEvent = async (params: IReportTrend) => {
78
+    trendLoading.value = true;
79
+    let res: any = await http.get(Api.report_ratio, params)
80
+    trendLoading.value = false;
81
+    if (res && res.errNo == '0') {
82
+      overviewData.ratioDataList = res.rst;
83
+      radiuCharts(params.dimension)
84
+    } else {
85
+      ElMessage.error(res.errMsg)
86
+    }
87
+  }
88
+
89
+  const trendColor = ['#3B9FFF', '#4ECB73', '#F9D336', '#F1637B', '#9760E4', '#EF69FF', '#FCB161', '#62DDFF', '#C7C655', '#318730']
90
+  const getTrendOption = (yAxis, date, data) => {
91
+    return {
92
+      tooltip: {
93
+        trigger: 'axis',
94
+      },
95
+      grid: {
96
+        left: '7%',
97
+        right: '4%',
98
+        bottom: '10%'
99
+      },
100
+      xAxis: {
101
+        type: 'category',
102
+        boundaryGap: false,
103
+        data: date,
104
+        axisTick: {
105
+          show: false
106
+        },
107
+        axisLine: {
108
+          show: true,
109
+          lineStyle: {
110
+            color: '#cccccc'
111
+          }
112
+        },
113
+        axisLabel: {
114
+          color: '#666',
115
+        },
116
+      },
117
+      yAxis: yAxis,
118
+      series: data
119
+    }
120
+  }
121
+  /** 获取曲线数据 */
122
+  const getTrend = (dimension) => {
123
+    let time: any[] = [];
124
+    let dataInfo: any = {
125
+      trend_name: '',
126
+      trend: [],
127
+      data: []
128
+    };
129
+    overviewData.list.forEach((item) => {
130
+      if (item.key == overviewRef.value!.value) {
131
+        dataInfo.trend_name = item.name + (item.unit ? `(${item.unit})` : '')
132
+      }
133
+    });
134
+
135
+    let legendArr: any[] = []
136
+    let yAxis: any[] = []
137
+    yAxis.push({
138
+      name: dataInfo.trend_name,
139
+      type: 'value',
140
+      splitNumber: 4,
141
+      nameTextStyle: {
142
+        align: dataInfo.trend_name.length > 7 ? 'center' : 'right',
143
+      }
144
+    })
145
+
146
+    if (topNumRef.value?.value == 0) {//汇总
147
+      overviewData.trendDataList.forEach((item: any) => {
148
+        time.push(item.time)
149
+        dataInfo.trend.push(item[overviewRef.value!.value])
150
+      });
151
+      dataInfo.data.push({
152
+        name: '汇总',
153
+        type: 'line',
154
+        smooth: true,
155
+        itemStyle: {
156
+          color: trendColor[0]
157
+        },
158
+        data: dataInfo.trend
159
+      })
160
+      legendArr.push({
161
+        name: '汇总',
162
+        color: trendColor[0]
163
+      })
164
+    } else {
165
+      if (overviewData.trendDataList?.length > 0) {
166
+        overviewData.trendDataList[0].data.forEach((item: any) => {
167
+          time.push(item.time)
168
+        });
169
+      }
170
+      let name = '';
171
+      let id = '';
172
+      overviewData.trendDataList.forEach((item: any, index) => {
173
+        if (dimension == 'account') {//数据维度
174
+          name = item.account_name
175
+          id = item.account_id
176
+        }
177
+        if (dimension == 'user') {
178
+          name = item.username
179
+        }
180
+        if (dimension == 'team') {
181
+          name = item.name
182
+        }
183
+        if (dimension == 'project') {
184
+          name = item.name
185
+        }
186
+        let trendData: any[] = []
187
+        item.data?.forEach((s_item) => {
188
+          trendData.push(s_item[overviewRef.value!.value])
189
+        });
190
+        dataInfo.data.push({
191
+          name: `${name}${id != '' ? `(${id})` : ''}`,
192
+          type: 'line',
193
+          smooth: true,
194
+          itemStyle: {
195
+            color: trendColor[index]
196
+          },
197
+          data: trendData
198
+        })
199
+        legendArr.push({
200
+          name: name,
201
+          id: id,
202
+          color: trendColor[index]
203
+        })
204
+      });
205
+    }
206
+
207
+    overviewData.legendArr = legendArr
208
+
209
+    trendInfo.option = getTrendOption(yAxis, time, dataInfo.data)
210
+  }
211
+  /**占比图 */
212
+  const radiuCharts = (dimension) => {
213
+    let trend_name = ''
214
+    let totalValue = ''
215
+    overviewData.list.forEach((item) => {
216
+      if (item.key == overviewRef.value!.value) {
217
+        trend_name = item.name
218
+      }
219
+    });
220
+    let data: any[] = []
221
+    overviewData.ratioDataList.data.forEach((item) => {
222
+      if (dimension == 'account') {//数据维度
223
+        data.push({
224
+          value: item[`${overviewRef.value!.value}_pro`],
225
+          name: item.account_name,
226
+          id: item.account_id,
227
+        })
228
+      }
229
+      if (dimension == 'user') {
230
+        data.push({
231
+          value: item[`${overviewRef.value!.value}_pro`],
232
+          name: item.username,
233
+        })
234
+      }
235
+      if (dimension == 'team') {
236
+        data.push({
237
+          value: item[`${overviewRef.value!.value}_pro`],
238
+          name: item.name,
239
+        })
240
+      }
241
+      if (dimension == 'project') {
242
+        data.push({
243
+          value: item[`${overviewRef.value!.value}_pro`],
244
+          name: item.name,
245
+        })
246
+      }
247
+    });
248
+    totalValue = overviewData.ratioDataList.total[overviewRef.value!.value];
249
+    let option = {
250
+      title: {
251
+        zlevel: 0,
252
+        text: [`{name|${trend_name}}`, '{value|' + totalValue + '}'].join('\n'),
253
+        top: '38%',
254
+        left: '49.5%',
255
+        textAlign: 'center',
256
+        textStyle: {
257
+            rich: {
258
+                value: {
259
+                    color: '#303133',
260
+                    fontSize: 20,
261
+                    lineHeight: 24,
262
+                },
263
+                name: {
264
+                    color: '#303133',
265
+                    fontSize: 20,
266
+                    lineHeight: 35,
267
+                },
268
+            },
269
+        },
270
+      },
271
+      tooltip: {
272
+        trigger: 'item',
273
+        show: false
274
+      },
275
+      legend: {
276
+        top: '5%',
277
+        left: 'center',
278
+        show: false,
279
+      },
280
+      series: [
281
+        {
282
+          name: trend_name,
283
+          type: 'pie',
284
+          radius: ['40%', '70%'],
285
+          width: 600,
286
+          left: 'center',
287
+          itemStyle: {
288
+            normal: {
289
+              borderRadius: 10,
290
+              borderColor: '#fff',
291
+              borderWidth: 2,
292
+              color: function (colors) {
293
+                return trendColor[colors.dataIndex];
294
+              }
295
+            }
296
+          },
297
+          label: {
298
+            show: true,
299
+            alignTo: 'edge',
300
+            formatter(param) {
301
+              return `{name|${param.name}}\n${param.data.id ? `{id|${param.data.id}}:` : ''}{val|${param.percent}%}`
302
+            },
303
+            minMargin: 5,
304
+            edgeDistance: 10,
305
+            lineHeight: 15,
306
+            rich: {
307
+              name: {
308
+                color: '#888',
309
+              },
310
+            },
311
+          },
312
+          emphasis: {
313
+            label: {
314
+              show: true,
315
+              fontSize: 15,
316
+              fontWeight: 'bold'
317
+            }
318
+          },
319
+          labelLine: {
320
+            length: 15,
321
+            length2: 0,
322
+            maxSurfaceAngle: 80
323
+          },
324
+          labelLayout: function (params) {
325
+            const isLeft = params.labelRect.x < 600;
326
+            const points = params.labelLinePoints;
327
+            // Update the end point.
328
+            points[2][0] = isLeft
329
+              ? params.labelRect.x
330
+              : params.labelRect.x + params.labelRect.width;
331
+            return {
332
+              labelLinePoints: points
333
+            };
334
+          },
335
+          data: data
336
+        }
337
+      ]
338
+    };
339
+    ratioInfo.option = option
340
+  }
341
+
342
+  return {
343
+    isCollapsed,
344
+    tabInfo,
345
+    trendLoading,
346
+    topNumRef,
347
+    overviewRef,
348
+    overviewData,
349
+    topNumList,
350
+    trendInfo,
351
+    ratioInfo,
352
+    getTrend,
353
+    radiuCharts,
354
+    reportTrendEvent,
355
+    reportRatioEvent,
356
+  }
357
+}

+ 128 - 0
src/components/businessMoudle/dataManagement/oePromoterData/index.vue

@@ -0,0 +1,128 @@
1
+<template>
2
+  <div class="flex_between">
3
+    <div class="page_title">投手数据</div>
4
+    
5
+  </div>
6
+  <div class="screen_box">
7
+    <div class="flex tMar15">
8
+      <div class="label lMar20 rMar10">账户名称</div>
9
+      <el-input v-model="pageInfo.keyword" style="width: 200px" placeholder="请输入账户名称" clearable @clear="init" >
10
+        <template #append>
11
+          <el-button :icon="Search" @click="init"/>
12
+        </template>
13
+      </el-input>
14
+      <div class="label lMar20 rMar10">投手</div>
15
+      <Select ref="userRef"
16
+            selectWidth="180px"
17
+            @changeEvent="selectChange('userRef')" @clearEvent="selectChange('userRef')"
18
+            :filterFlag="true"
19
+            :optObj="{k:'id',la:'username',val:'id'}"
20
+            :options="pageInfo.userList"/>
21
+      <div class="label lMar20 rMar10">是否有消耗</div>
22
+      <Select ref="costRef"
23
+            selectWidth="180px"
24
+            @changeEvent="selectChange('costRef')" @clearEvent="selectChange('costRef')"
25
+            :filterFlag="true"
26
+            :optObj="{k:'value',la:'name',val:'value'}"
27
+            :options="hasCost.list"/>
28
+      <div class="flex">
29
+        <div class="label lMar20 rMar10">投放时间</div>
30
+        <el-date-picker v-model="pageInfo.time" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
31
+          size="default" style="width: 280px;" @change="init" :clearable="false" class="lMar10" />
32
+      </div>
33
+    </div>
34
+  </div>
35
+  <dataList ref="dataListRef" :mainPageInfo="pageInfo"></dataList>
36
+</template>
37
+<script setup lang="ts">
38
+import { Search } from '@element-plus/icons-vue'
39
+import { nextTick, onBeforeMount, reactive, ref } from 'vue';
40
+import { ExpIndex }  from './hooks/index'
41
+import { getCookie } from '@/common/common';
42
+import Select from '@/components/capsulationMoudle/_select.vue'
43
+import dataList from './dataList.vue'
44
+
45
+const userInfo = ref()
46
+const hasCost = ref({
47
+    list:[
48
+      {name:'否',value: 0},
49
+      {name:'是',value: 1},
50
+    ]
51
+})
52
+const {
53
+  dataListRef,
54
+  acTrendRef,
55
+  userRef,
56
+  costRef,
57
+  pageInfo,
58
+  getUserList,
59
+} = ExpIndex()
60
+
61
+/**点击select筛选 */
62
+const selectChange = (key) => {
63
+  if(key == 'userRef') {
64
+    pageInfo.promoter_id = userRef.value?.value;
65
+  }
66
+  if(key == 'costRef') {
67
+    pageInfo.has_cost = costRef.value?.value;
68
+  }
69
+  init()
70
+}
71
+
72
+const init = () => {
73
+  nextTick(()=>{
74
+    if(acTrendRef.value) {
75
+      acTrendRef.value.change()
76
+    }
77
+
78
+    if(dataListRef.value) {
79
+      dataListRef.value.init(1)
80
+    }
81
+  })
82
+}
83
+
84
+onBeforeMount(()=>{
85
+  userInfo.value = JSON.parse(getCookie('userInfo') as string)
86
+  getUserList()
87
+  init()
88
+})
89
+
90
+</script>
91
+<style lang="scss" scoped>
92
+.page_title {
93
+  font-size: 16px;
94
+  font-weight: bold;
95
+}
96
+
97
+.screen_box {
98
+  background-color: #fff;
99
+  padding: 20px;
100
+  margin-top: 10px;
101
+}
102
+
103
+.btn {
104
+  border: var(--el-border);
105
+  height: 30px;
106
+  line-height: 30px;
107
+  box-sizing: border-box;
108
+  border-radius: 4px;
109
+  padding: 0 15px;
110
+  margin-right: 10px;
111
+  font-size: 13px;
112
+  cursor: pointer;
113
+
114
+  &:hover {
115
+    color: #3173FF;
116
+  }
117
+
118
+  &.active {
119
+    background-color: #3173FF;
120
+    border-color: #3173FF;
121
+    color: #fff;
122
+
123
+    &:hover {
124
+      color: #fff;
125
+    }
126
+  }
127
+}
128
+</style>

+ 9 - 0
src/router/index.ts

@@ -32,6 +32,7 @@ const menuList = () => import('@/components/businessMoudle/menu/index.vue')
32 32
 const document = () => import('@/components/document/index.vue')
33 33
 const oeAdAccount = () => import('@/components/businessMoudle/oeAdAccount/index.vue')
34 34
 const adAccountGroup = () => import('@/components/businessMoudle/adAccountGroup/index.vue')
35
+const oePromoterData = () => import('@/components/businessMoudle/dataManagement/oePromoterData/index.vue')
35 36
 
36 37
 //数据报表
37 38
 const acStatement = () => import('@/components/businessMoudle/dataManagement/acStatement/index.vue')
@@ -269,6 +270,14 @@ const constantRoutes: Array<RouteRecordRaw> = [
269 270
           title: '账户组'
270 271
         }
271 272
       },
273
+      {
274
+        path: '/oePromoterData',
275
+        component: oePromoterData,
276
+        name: 'oePromoterData',
277
+        meta: {
278
+          title: '投手数据'
279
+        }
280
+      },
272 281
     ],
273 282
   },
274 283
 ]