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