
3 changed files with 1061 additions and 279 deletions
@ -0,0 +1,197 @@ |
|||||
|
// 在有边框,可以进行拖拽的情况下,实现宽度跟随变化(不太行,基本pass)
|
||||
|
import ResizeObserver from 'resize-observer-polyfill'; |
||||
|
import { |
||||
|
debounce |
||||
|
} from 'lodash'; |
||||
|
|
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
tableResizeObserver: null, |
||||
|
tableWidth: 0, |
||||
|
isDragging: false, // 新增拖拽状态标志
|
||||
|
lastDragTime: 0 // 记录最后一次拖拽时间
|
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
// 销毁观察者
|
||||
|
destroyTableResizeObserver() { |
||||
|
if (this.tableResizeObserver) { |
||||
|
this.tableResizeObserver.disconnect(); |
||||
|
this.tableResizeObserver = null; |
||||
|
} |
||||
|
}, |
||||
|
// 初始化监听
|
||||
|
initTableResizeObserver(tableRef, containerRef) { |
||||
|
this.$nextTick(() => { |
||||
|
const container = containerRef ? this.$refs[containerRef] : this.$el; |
||||
|
if (!container) return; |
||||
|
|
||||
|
this.destroyTableResizeObserver(); |
||||
|
|
||||
|
this.tableResizeObserver = new ResizeObserver( |
||||
|
debounce(entries => { |
||||
|
if (this.isDragging || Date.now() - this.lastDragTime < 300) return; |
||||
|
|
||||
|
const entry = entries[0]; |
||||
|
const newWidth = entry.contentRect.width; |
||||
|
|
||||
|
if (Math.abs(newWidth - this.tableWidth) > 5) { |
||||
|
this.tableWidth = newWidth; |
||||
|
this.forceSyncTableLayout(tableRef); |
||||
|
} |
||||
|
}, 100) |
||||
|
); |
||||
|
|
||||
|
this.tableResizeObserver.observe(container); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
// 强制同步表头和表体布局
|
||||
|
forceSyncTableLayout(tableRef) { |
||||
|
const table = this.$refs[tableRef].$refs.guiptable; |
||||
|
if (!table) return; |
||||
|
|
||||
|
// 先获取当前实际宽度
|
||||
|
const currentWidths = this.getCurrentColumnWidths(table); |
||||
|
|
||||
|
// 计算理论宽度
|
||||
|
const calculatedWidths = this.calculateColumnWidths(); |
||||
|
if (!calculatedWidths) return; |
||||
|
|
||||
|
this.$nextTick(() => { |
||||
|
// 1. 设置列定义的宽度
|
||||
|
table.columns.forEach(column => { |
||||
|
const prop = column.property || column.id; |
||||
|
column.width = currentWidths[prop] || calculatedWidths[prop]; |
||||
|
}); |
||||
|
|
||||
|
// 2. 同步DOM宽度
|
||||
|
this.updateDOMWidths(table); |
||||
|
|
||||
|
// 3. 特殊处理固定列
|
||||
|
this.handleFixedColumns(table); |
||||
|
|
||||
|
// 4. 强制重新布局(两次确保生效)
|
||||
|
table.doLayout(); |
||||
|
setTimeout(() => table.doLayout(), 50); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 获取当前DOM中的实际列宽
|
||||
|
getCurrentColumnWidths(table) { |
||||
|
const widths = {}; |
||||
|
const headerCells = table.$el.querySelectorAll('.el-table__header .cell'); |
||||
|
|
||||
|
headerCells.forEach(cell => { |
||||
|
const col = cell.closest('th'); |
||||
|
if (col && col.style.width) { |
||||
|
const prop = col.getAttribute('data-property') || |
||||
|
col.querySelector('.cell').getAttribute('data-property'); |
||||
|
if (prop) { |
||||
|
widths[prop] = parseInt(col.style.width); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return widths; |
||||
|
}, |
||||
|
|
||||
|
// 更新DOM元素宽度
|
||||
|
updateDOMWidths(table) { |
||||
|
const headerCols = table.$el.querySelectorAll('.el-table__header col'); |
||||
|
const bodyCols = table.$el.querySelectorAll('.el-table__body col'); |
||||
|
const headerCells = table.$el.querySelectorAll('.el-table__header th'); |
||||
|
const bodyCells = table.$el.querySelectorAll('.el-table__body td'); |
||||
|
|
||||
|
table.columns.forEach((column, index) => { |
||||
|
const width = column.width; |
||||
|
if (!width) return; |
||||
|
|
||||
|
// 设置colgroup中的宽度
|
||||
|
if (headerCols[index]) { |
||||
|
headerCols[index].width = width; |
||||
|
// headerCols[index].style.width = `${width}px`;
|
||||
|
headerCols[index].style.setProperty('width', `${width}px`, 'important'); |
||||
|
|
||||
|
} |
||||
|
if (bodyCols[index]) { |
||||
|
bodyCols[index].width = width; |
||||
|
// bodyCols[index].style.width = `${width}px`;
|
||||
|
bodyCols[index].style.setProperty('width', `${width}px`, 'important'); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// 设置实际单元格宽度
|
||||
|
if (headerCells[index]) { |
||||
|
// headerCells[index].style.width = `${width}px`;
|
||||
|
headerCells[index].style.setProperty('width', `${width}px`, 'important'); |
||||
|
headerCells[index].style.minWidth = `${width}px`; |
||||
|
|
||||
|
} |
||||
|
if (bodyCells[index]) { |
||||
|
// bodyCells[index].style.width = `${width}px`;
|
||||
|
bodyCells[index].style.setProperty('width', `${width}px`, 'important'); |
||||
|
bodyCells[index].style.minWidth = `${width}px`; |
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 处理固定列
|
||||
|
handleFixedColumns(table) { |
||||
|
const fixedLeft = table.$el.querySelector('.el-table__fixed'); |
||||
|
const fixedRight = table.$el.querySelector('.el-table__fixed-right'); |
||||
|
|
||||
|
if (fixedLeft) fixedLeft.style.height = 'auto'; |
||||
|
if (fixedRight) fixedRight.style.height = 'auto'; |
||||
|
}, |
||||
|
|
||||
|
// 处理拖拽开始
|
||||
|
handleHeaderDragStart() { |
||||
|
this.isDragging = true; |
||||
|
}, |
||||
|
|
||||
|
// 处理拖拽结束
|
||||
|
handleHeaderDragEnd(newWidth, oldWidth, column) { |
||||
|
this.isDragging = false; |
||||
|
this.lastDragTime = Date.now(); |
||||
|
|
||||
|
// 更新列比例配置
|
||||
|
const table = this.$refs[Object.keys(this.$refs).find(k => k.startsWith('myTable'))]; |
||||
|
if (!table || !this.tableWidth) return; |
||||
|
|
||||
|
const availableWidth = this.tableWidth - 20; |
||||
|
const newRatio = newWidth / availableWidth; |
||||
|
|
||||
|
// 更新当前列的ratio
|
||||
|
if (this.columnRatios && column.property) { |
||||
|
this.columnRatios[column.property] = newRatio; |
||||
|
} |
||||
|
|
||||
|
// 重新平衡其他列的比例
|
||||
|
this.balanceColumnRatios(column.property); |
||||
|
}, |
||||
|
|
||||
|
// 平衡其他列的比例
|
||||
|
balanceColumnRatios(changedColumnProp) { |
||||
|
if (!this.columnRatios) return; |
||||
|
|
||||
|
const otherColumns = Object.keys(this.columnRatios) |
||||
|
.filter(prop => prop !== changedColumnProp); |
||||
|
|
||||
|
const totalUsedRatio = Object.values(this.columnRatios).reduce((sum, r) => sum + r, 0); |
||||
|
const overflow = totalUsedRatio - 1; |
||||
|
|
||||
|
if (overflow > 0) { |
||||
|
const otherTotalRatio = otherColumns.reduce((sum, prop) => sum + this.columnRatios[prop], 0); |
||||
|
|
||||
|
otherColumns.forEach(prop => { |
||||
|
this.columnRatios[prop] -= (this.columnRatios[prop] / otherTotalRatio) * overflow; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
@ -0,0 +1,806 @@ |
|||||
|
<template> |
||||
|
<div class="demo-wrap min-flex-right"> |
||||
|
<div class="flex-between"> |
||||
|
<h2>{{ pageTitle }}</h2> |
||||
|
<CustomDropdown ref="dropdownRef" :placeholder="'('+viewDesc[this.view]+')'+text" width="280px"> |
||||
|
<DateSelect slot="normal" :view="view" v-model="selectedDate" @update-count="handleUpdateView" |
||||
|
@change="handleDateChange" /> |
||||
|
</CustomDropdown> |
||||
|
</div> |
||||
|
<div v-if="dataRank == 1 && (dataType == 'ver_type' || dataType == 'check_type')" |
||||
|
style="margin-bottom: 20px;text-align: left"> |
||||
|
<el-alert type="info" :closable="false" show-icon> |
||||
|
<template #title> |
||||
|
未计成本 |
||||
|
</template> |
||||
|
<div style="margin-top: 8px; line-height: 1.6; font-size: 14px; color: #606266;"> |
||||
|
<template v-if="dataType == 'ver_type'"> |
||||
|
1. AI(服务器成本) <span v-if="view == 'year'" style="color:red;">2025年(含)后计入成本</span><br /> |
||||
|
2. Turnitin <span v-if="view == 'year'" style="color:red;">2025年(含)后计入成本</span><br /> |
||||
|
3. 学术(知网PMLC,硕博VIP)<span v-if="view == 'year'" style="color:red;">2025年(含)后计入成本</span><br /> |
||||
|
</template> |
||||
|
<template v-if="dataType == 'check_type'"> |
||||
|
1. AI(服务器成本)<br /> |
||||
|
2. Turnitin国际版、TurnitinUK版、Turnitin国际版+AI<br /> |
||||
|
3. 知网PMLC,硕博VIP <span v-if="view == 'year'" style="color:red;">2025年(含)后计入成本</span><br /> |
||||
|
</template> |
||||
|
</div> |
||||
|
</el-alert> |
||||
|
</div> |
||||
|
<div class=" flex-common" id=""> |
||||
|
<el-form> |
||||
|
<div class="table-container" ref="tableContainer"> |
||||
|
<!-- @cell-mouse-enter="handleRowHover" --> |
||||
|
<GuipTable :tableData="tableData" style="width: 100%;" @sort-change="handleSortChange" |
||||
|
ref="elTable" :loading="tableLoading"> |
||||
|
<el-table-column prop="sort" label="排序" show-overflow-tooltip></el-table-column> |
||||
|
<el-table-column |
||||
|
v-if="(dataRank == 1 || dataRank == 2) && (dataType == 'ver_type' || dataType == 'check_type')" |
||||
|
prop="name" :key="selectedType" :label="type_select[selectedType]"> |
||||
|
|
||||
|
<template slot="header"> |
||||
|
<el-select class="custom-select tableHeaderSelect" height="34px" popper-class="custom-select-dropdown" |
||||
|
v-model="selectedType" @change="changeRankType"> |
||||
|
<el-option v-for="(item,type) in type_select" :key="type" :label="item" |
||||
|
:value="type"> |
||||
|
</el-option> |
||||
|
</el-select> |
||||
|
</template> |
||||
|
|
||||
|
<template slot-scope="scope"> |
||||
|
<GuipToolTip :content="scope.row.name"> |
||||
|
<div class="cell-content nowrap">{{ scope.row.name }}</div> |
||||
|
</GuipToolTip> |
||||
|
</template> |
||||
|
|
||||
|
</el-table-column> |
||||
|
<el-table-column v-else prop="name" :label="type_desc[dataType]"> |
||||
|
<template slot-scope="scope"> |
||||
|
<GuipToolTip :content="scope.row.name"> |
||||
|
<div class="cell-content nowrap">{{ scope.row.name }}</div> |
||||
|
</GuipToolTip> |
||||
|
</template> |
||||
|
|
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column v-for="(field, index) in valueFields" :key="field" |
||||
|
:label="labels[index] + (index == 3 ? current_month : '')" :prop="'value_' + String(index + 1)" |
||||
|
sortable="custom"> |
||||
|
|
||||
|
<!--产品利润排行展示查看更多--> |
||||
|
<template v-slot="{ row, $index }" v-if="index == 3 && dataRank == 1"> |
||||
|
<el-popover popper-class="custom-popover" v-model="row.id_popover" placement="top" trigger="manual" |
||||
|
:ref="`popover-${row.id}`" :visible-arrow="true" :append-to-body="false" @show="popshow"> |
||||
|
|
||||
|
<div v-if="type != 'agent'" class="pop-wrap"> |
||||
|
<div class="flex-between flex pop-top"> |
||||
|
<h3> |
||||
|
{{ text }} {{ row.name }} |
||||
|
<span class="lookMore" @click="goLookMoreData(row.id)">查看更多</span> |
||||
|
</h3> |
||||
|
<span class="flex point" @click="closePop(row,'id')"> |
||||
|
关闭<img src="@/assets/register/close.svg"> |
||||
|
</span> |
||||
|
</div> |
||||
|
<el-table :data="tableData1" style="width: 100%"> |
||||
|
<el-table-column prop="value_1" width="200" label="日期"></el-table-column> |
||||
|
|
||||
|
<el-table-column width="200" :label="rank_type_desc[dataRank]"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div class="flex"> |
||||
|
{{ scope.row.value_2 }} |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
<div v-else class="pop-wrap"> |
||||
|
<div class="flex-between flex pop-top"> |
||||
|
<h3> |
||||
|
{{ text }} {{ row.name }} |
||||
|
<span class="lookMore" @click="goLookCheckTypeRank(row.id)">查看更多</span> |
||||
|
</h3> |
||||
|
<span class="flex point" @click="closePop(row,'id')"> |
||||
|
关闭<img src="@/assets/register/close.svg"> |
||||
|
</span> |
||||
|
</div> |
||||
|
<el-table :data="tableData1" style="width: 100%"> |
||||
|
<el-table-column prop="sort" width="95" label="排序"></el-table-column> |
||||
|
<el-table-column prop="name" width="250" label="服务名称"></el-table-column> |
||||
|
<el-table-column prop="rate" width="130" label="毛利占比"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div class="flex"> |
||||
|
{{ scope.row.rate }} % |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column width="150" :label="rank_type_desc[dataRank]"> |
||||
|
<template slot-scope="scope"> |
||||
|
<div class="flex"> |
||||
|
{{ scope.row.value_1 }} |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="value_2" width="130" label="订单数"></el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
|
||||
|
<div class="flex" slot="reference"> |
||||
|
{{ row[field] }} |
||||
|
<svg-icon :size="16" :path="require('@/assets/super/list-detail.svg')" |
||||
|
:color="'#8A9099'" :hoverColor="'#006AFF'" |
||||
|
@click="handleClick(row, $index, 'id')" /> |
||||
|
</div> |
||||
|
</el-popover> |
||||
|
</template> |
||||
|
<template v-else slot-scope="scope"> |
||||
|
<div class="flex"> |
||||
|
{{ scope.row[field] }} |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<!--产品利润排行展示代理商排行--> |
||||
|
<el-table-column v-if="dataRank == 1 && (dataType == 'ver_type' || dataType == 'check_type')" |
||||
|
key="top" prop="id" :label="'代理商排行'+current_month" :width="valueFields.id"> |
||||
|
<template v-slot="{ row, $index }"> |
||||
|
<el-popover v-model="row.id_popover_2" :append-to-body="false" |
||||
|
popper-class="custom-popover" trigger="manual" :visible-arrow="true" |
||||
|
:ref="`popover_2-${row.id}`" @show="popshow"> |
||||
|
<div class="pop-wrap"> |
||||
|
<div class="flex-between flex pop-top"> |
||||
|
<h3> |
||||
|
{{ row.name }} 代理商排行 |
||||
|
<span class="lookMore" @click="goLookAgentRank(row.id)">查看更多</span> |
||||
|
</h3> |
||||
|
<span class="flex point" @click="closePop(row,'id')"> |
||||
|
关闭<img src="@/assets/register/close.svg"> |
||||
|
</span> |
||||
|
</div> |
||||
|
<el-table :data="tableData1" style="width: 100%"> |
||||
|
<el-table-column prop="sort" width="100" label="排行"></el-table-column> |
||||
|
<el-table-column prop="name" width="200" label="代理商"></el-table-column> |
||||
|
<el-table-column prop="value_1" width="200" label="销售额"></el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
<div slot="reference"> |
||||
|
<GuipToolTip :content="' No.1 '+top_list[row.id]['name']" |
||||
|
v-if="top_list[row.id]"> |
||||
|
<div class="flex"> |
||||
|
<span class="cell-content nowrap"> No.1 {{ top_list[row.id]['name'] |
||||
|
}}</span> |
||||
|
<svg-icon :size="16" :path="require('@/assets/super/list-detail.svg')" |
||||
|
:color="'#8A9099'" :hoverColor="'#006AFF'" |
||||
|
@click="handleClick2(row, $index, 'id')" /> |
||||
|
</div> |
||||
|
</GuipToolTip> |
||||
|
|
||||
|
<span class="cell-content" v-else>暂无排行</span> |
||||
|
</div> |
||||
|
</el-popover> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</GuipTable> |
||||
|
</div> |
||||
|
|
||||
|
<el-pagination background @size-change='handleSizeChange' @current-change='handleCurrentChange' |
||||
|
:current-page="currentPage" :page-size=pageSize layout="prev, pager, next,jumper" :total="total"> |
||||
|
</el-pagination> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script> |
||||
|
import DateSelect from '@/components/super/DateSelect.vue'; |
||||
|
import CustomDropdown from '@/components/CustomDropdown.vue'; |
||||
|
import GuipTable from '@/components/GuipTable.vue'; |
||||
|
import GuipToolTip from '@/components/GuipToolTip.vue'; |
||||
|
import SvgIcon from '@/components/SvgIcon.vue'; |
||||
|
import tableResizeMixin from '@/mixins/tableResizeMixin' |
||||
|
export default { |
||||
|
name: 'rank_batch_list', |
||||
|
mixins: [tableResizeMixin], |
||||
|
props: { |
||||
|
pageTitle: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
}, |
||||
|
rank_type: { |
||||
|
type: Number, |
||||
|
default: 0 |
||||
|
}, |
||||
|
type: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
} |
||||
|
}, |
||||
|
components: { |
||||
|
// HoverImage, |
||||
|
GuipToolTip, |
||||
|
DateSelect, |
||||
|
GuipTable, |
||||
|
SvgIcon, |
||||
|
CustomDropdown |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
|
||||
|
popoverRefs: {}, |
||||
|
resizePending: false, |
||||
|
resizeObserver: null, |
||||
|
viewDesc: { |
||||
|
'month': '月份', |
||||
|
'monthTwo': '月份', |
||||
|
'year': '年份', |
||||
|
}, |
||||
|
rank_type_desc: { |
||||
|
1: '毛利润', |
||||
|
2: '订单数', |
||||
|
3: '退单数', |
||||
|
4: '充值金额', |
||||
|
}, |
||||
|
type_desc: { |
||||
|
'agent': '代理商昵称', |
||||
|
'ver_type': '品牌名称', |
||||
|
'check_type': '服务名称', |
||||
|
}, |
||||
|
type_select: { |
||||
|
'ver_type': '按品牌名称', |
||||
|
'check_type': '按服务名称', |
||||
|
}, |
||||
|
tableWidth: 0, |
||||
|
// 列宽比例配置 |
||||
|
columnRatios: { |
||||
|
sort: 0.08, // 20% |
||||
|
name: 0.12, // 30% |
||||
|
value_1: 0.14, // 50% |
||||
|
value_2: 0.14, // 50% |
||||
|
value_3: 0.16, // 50% |
||||
|
value_4: 0.18, // 50% |
||||
|
id: 0.18 // 50% |
||||
|
}, |
||||
|
// 列最小宽度配置 |
||||
|
minWidths: { |
||||
|
name: 120, // 30% |
||||
|
sort: 90, // 20% |
||||
|
value_1: 120, // 50% |
||||
|
value_2: 120, // 50% |
||||
|
value_3: 120, // 50% |
||||
|
value_4: 120, // 50% |
||||
|
id: 120 // 50% |
||||
|
}, |
||||
|
selectedType: 'check_type', |
||||
|
view: 'month', |
||||
|
labels: ['', '', '', ''], |
||||
|
current_month: '', |
||||
|
valueFields: ['value_1', 'value_2', 'value_3', 'value_4'], |
||||
|
currentPage: 1, //当前页 |
||||
|
pageSize: 20, //每页的容量 |
||||
|
total: 0, //列表总数 |
||||
|
sort_by: 4, |
||||
|
sort_order: 2, |
||||
|
text: '',//下拉框显示具体文案 |
||||
|
selectedDate: new Date(),//默认当天日期 |
||||
|
dataType: '', |
||||
|
dataRank: '', |
||||
|
tableData: [], |
||||
|
top_list: [], |
||||
|
tableData1: [], |
||||
|
show_detail_index: 0, |
||||
|
tableLoading:false |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.init() |
||||
|
this.$nextTick(() => { |
||||
|
this.initTableResizeObserver('elTable', 'tableContainer') |
||||
|
}); |
||||
|
}, |
||||
|
watch: { |
||||
|
'$route'() { |
||||
|
this.init() |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
|
||||
|
handleHeaderDragStart() { |
||||
|
this.$options.methods.handleHeaderDragStart.call(this); |
||||
|
}, |
||||
|
|
||||
|
handleHeaderDragEnd(newWidth, oldWidth, column) { |
||||
|
this.$options.methods.handleHeaderDragEnd.call(this, newWidth, oldWidth, column); |
||||
|
}, |
||||
|
// 覆盖方法 |
||||
|
calculateColumnWidths() { |
||||
|
if (!this.tableWidth) return {}; |
||||
|
const availableWidth = this.tableWidth ; |
||||
|
const widths = {}; |
||||
|
|
||||
|
Object.keys(this.columnRatios).forEach(prop => { |
||||
|
const calculatedWidth = Math.floor(availableWidth * this.columnRatios[prop]); |
||||
|
// acc[key] = Math.max(calculatedWidth, this.minWidths[key]); |
||||
|
widths[prop] = Math.max( |
||||
|
Math.floor(calculatedWidth, this.minWidths[prop]), |
||||
|
80 // 最小宽度 |
||||
|
); |
||||
|
}); |
||||
|
return widths; |
||||
|
|
||||
|
}, |
||||
|
init() { |
||||
|
document.title = this.pageTitle; |
||||
|
|
||||
|
this.text = this.getNowDate() |
||||
|
this.dataType = this.type |
||||
|
this.dataRank = this.rank_type |
||||
|
|
||||
|
this.getRankingData(); |
||||
|
}, |
||||
|
handleUpdateView(newView) { |
||||
|
this.view = newView; |
||||
|
}, |
||||
|
getNowDate() { |
||||
|
const now = new Date(); |
||||
|
const year = now.getFullYear(); |
||||
|
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,补零 |
||||
|
const currentYearMonth = `${year}-${month}`; |
||||
|
return `${currentYearMonth}` |
||||
|
}, |
||||
|
getDate(dateStr) { |
||||
|
const date = new Date(dateStr); |
||||
|
const year = date.getFullYear(); // 2025 |
||||
|
const month = date.getMonth() + 1; // 3 (表示3月) |
||||
|
if (this.view == 'year') { |
||||
|
return `${year}` |
||||
|
} else { |
||||
|
return `${year}-${month}` |
||||
|
} |
||||
|
}, |
||||
|
handleDateChange(date) { |
||||
|
this.text = this.getDate(date) |
||||
|
this.selectedDate = date; |
||||
|
localStorage.setItem('date', JSON.stringify(date)) |
||||
|
|
||||
|
this.$refs.dropdownRef.closeDropdown(); |
||||
|
|
||||
|
this.currentPage = 1; |
||||
|
this.getRankingData() |
||||
|
}, |
||||
|
goLookMoreData(id) { |
||||
|
let query = {} |
||||
|
query.date = this.text |
||||
|
query.rank_type = this.dataRank |
||||
|
if (this.dataType == 'agent') { |
||||
|
query.aid = id |
||||
|
} |
||||
|
if (this.dataType == 'ver_type') { |
||||
|
query.ver_type = id |
||||
|
} |
||||
|
if (this.dataType == 'check_type') { |
||||
|
query.check_type = id |
||||
|
} |
||||
|
window.open(this.$router.resolve({ |
||||
|
path: '/super/ranking/detail', |
||||
|
query: query |
||||
|
}).href, '_blank') |
||||
|
}, |
||||
|
goLookAgentRank(id) { |
||||
|
let query = {} |
||||
|
query.date = this.text |
||||
|
query.rank_type = this.dataRank |
||||
|
query.type = 'agent' |
||||
|
if (this.dataType == 'ver_type') { |
||||
|
query.ver_type = id |
||||
|
} |
||||
|
if (this.dataType == 'check_type') { |
||||
|
query.check_type = id |
||||
|
} |
||||
|
window.open(this.$router.resolve({ |
||||
|
path: '/super/ranking/list', |
||||
|
query: query |
||||
|
}).href, '_blank') |
||||
|
}, |
||||
|
goLookCheckTypeRank(id) { |
||||
|
let query = {} |
||||
|
query.date = this.text |
||||
|
query.rank_type = this.dataRank |
||||
|
query.type = 'check_type' |
||||
|
query.aid = id |
||||
|
window.open(this.$router.resolve({ |
||||
|
path: '/super/ranking/list', |
||||
|
query: query |
||||
|
}).href, '_blank') |
||||
|
}, |
||||
|
closePop(row, type) { |
||||
|
row[type + '_popover'] = false; |
||||
|
row[type + '_popover_2'] = false; |
||||
|
}, |
||||
|
setPopoverRef(id, el) { |
||||
|
if (el) { |
||||
|
this.popoverRefs[id] = el |
||||
|
} |
||||
|
}, |
||||
|
getPopoverRef(id) { |
||||
|
return this.popoverRefs[id] |
||||
|
}, |
||||
|
handleClick(row, index, type) { |
||||
|
// 关闭其他行的弹框 |
||||
|
this.tableData.forEach((item, i) => { |
||||
|
item[type + '_popover_2'] = false; |
||||
|
if (i !== index) { |
||||
|
item[type + '_popover'] = false; |
||||
|
} |
||||
|
}); |
||||
|
// // 打开当前行的弹框 |
||||
|
row[type + '_popover'] = true; |
||||
|
|
||||
|
let obj = {} |
||||
|
if (this.dataType == 'agent') { |
||||
|
obj.aid = row.id |
||||
|
} |
||||
|
if (this.dataType == 'ver_type') { |
||||
|
obj.ver_type = row.id |
||||
|
} |
||||
|
if (this.dataType == 'check_type') { |
||||
|
obj.check_type = row.id |
||||
|
} |
||||
|
if (this.dataType == 'agent') { |
||||
|
let obj = {} |
||||
|
obj.aid = row.id |
||||
|
this.getCheckTypeRankingList(obj); |
||||
|
} else { |
||||
|
this.getRankingDetail(obj); |
||||
|
} |
||||
|
}, |
||||
|
handleClick2(row, index, type) { |
||||
|
// 关闭其他行的弹框 |
||||
|
this.tableData.forEach((item, i) => { |
||||
|
item[type + '_popover'] = false; |
||||
|
if (i !== index) { |
||||
|
item[type + '_popover_2'] = false; |
||||
|
} |
||||
|
}); |
||||
|
// 打开当前行的弹框 |
||||
|
row[type + '_popover_2'] = true; |
||||
|
|
||||
|
let obj = {} |
||||
|
if (this.dataType == 'agent') { |
||||
|
obj.aid = row.id |
||||
|
} |
||||
|
if (this.dataType == 'ver_type') { |
||||
|
obj.ver_type = row.id |
||||
|
} |
||||
|
if (this.dataType == 'check_type') { |
||||
|
obj.check_type = row.id |
||||
|
} |
||||
|
this.getAgentRankingList(obj); |
||||
|
}, |
||||
|
popshow() { |
||||
|
var ariaEls = document.querySelectorAll('.el-popover') |
||||
|
ariaEls.forEach((item) => { |
||||
|
item.removeAttribute('aria-hidden') |
||||
|
}) |
||||
|
|
||||
|
ariaEls = document.querySelectorAll('.el-radio__original') |
||||
|
ariaEls.forEach((item) => { |
||||
|
item.removeAttribute('aria-hidden') |
||||
|
}) |
||||
|
}, |
||||
|
handleSortChange({ prop, order }) { |
||||
|
this.sort_by = 4; |
||||
|
this.sort_order = 2; |
||||
|
if (order == 'ascending') { |
||||
|
this.sort_by = prop; |
||||
|
this.sort_order = 1; |
||||
|
} |
||||
|
if (order == 'descending') { |
||||
|
this.sort_by = prop; |
||||
|
this.sort_order = 2; |
||||
|
} |
||||
|
this.currentPage = 1; |
||||
|
this.getRankingData() |
||||
|
}, |
||||
|
handleRowHover(row) { |
||||
|
this.show_detail_index = row.sort |
||||
|
}, |
||||
|
changeRankType() { |
||||
|
this.dataType = this.selectedType |
||||
|
this.getRankingData() |
||||
|
}, |
||||
|
getRankingData() { |
||||
|
this.setLabelText(); |
||||
|
|
||||
|
if (this.dataType == 'agent') { |
||||
|
this.getAgentRanking() |
||||
|
} |
||||
|
if (this.dataType == 'ver_type') { |
||||
|
this.getVerRanking() |
||||
|
} |
||||
|
if (this.dataType == 'check_type') { |
||||
|
this.getTypeRanking() |
||||
|
} |
||||
|
}, |
||||
|
setLabelText() { |
||||
|
const date = new Date(this.text); |
||||
|
const year = date.getFullYear(); |
||||
|
const month = date.getMonth() + 1; |
||||
|
|
||||
|
const currentYear = new Date().getFullYear(); |
||||
|
const currentMonth = new Date().getMonth() + 1; |
||||
|
|
||||
|
this.current_month = ''; |
||||
|
if (this.view === 'month' && year == currentYear && month == currentMonth) { |
||||
|
this.current_month = '(当月)'; |
||||
|
} |
||||
|
|
||||
|
this.labels = []; |
||||
|
if (this.view === 'year') { |
||||
|
for (let i = 3; i >= 0; i--) { |
||||
|
this.labels.push((year - i) + '年' + this.rank_type_desc[this.dataRank]); |
||||
|
} |
||||
|
} else { |
||||
|
const monthLabels = []; |
||||
|
for (let i = 3; i >= 0; i--) { |
||||
|
let m = month - i; |
||||
|
if (m <= 0) m += 12; |
||||
|
|
||||
|
monthLabels.push(m + '月' + this.rank_type_desc[this.dataRank]); |
||||
|
} |
||||
|
this.labels = monthLabels; |
||||
|
} |
||||
|
}, |
||||
|
getAgentRanking() { |
||||
|
//代理商排行 |
||||
|
const that = this |
||||
|
that.tableData = [] |
||||
|
this.$http('POST', '/supernew/ajax_get_agent_batch_list', { |
||||
|
date: that.text, |
||||
|
rank_type: that.dataRank, |
||||
|
sort_by: that.sort_by, |
||||
|
sort_order: that.sort_order, |
||||
|
cur_page: that.currentPage, |
||||
|
page_size: that.pageSize, |
||||
|
}).then(response => { |
||||
|
this.$nextTick(() => { |
||||
|
that.tableData = response.data.list |
||||
|
that.total = response.data.total |
||||
|
}) |
||||
|
}).catch(error => { |
||||
|
console.error(error, 'error') |
||||
|
}) |
||||
|
}, |
||||
|
getVerRanking() { |
||||
|
//品牌排行 |
||||
|
const that = this |
||||
|
that.tableData = [] |
||||
|
that.top_list = [] |
||||
|
this.$http('POST', '/supernew/ajax_get_ver_batch_list', { |
||||
|
date: that.text, |
||||
|
rank_type: that.dataRank, |
||||
|
sort_by: that.sort_by, |
||||
|
sort_order: that.sort_order, |
||||
|
cur_page: that.currentPage, |
||||
|
page_size: that.pageSize, |
||||
|
}).then(response => { |
||||
|
this.$nextTick(() => { |
||||
|
that.tableData = response.data.list |
||||
|
that.top_list = response.data.top_list |
||||
|
that.total = response.data.total |
||||
|
}) |
||||
|
}).catch(error => { |
||||
|
console.error(error, 'error') |
||||
|
}) |
||||
|
}, |
||||
|
async getTypeRanking() { |
||||
|
//产品排行 |
||||
|
const that = this |
||||
|
that.tableData = [ |
||||
|
{ |
||||
|
id: 6, |
||||
|
name: "维普大学生版", |
||||
|
sort: 12334234232, |
||||
|
value_1: "23754.25", |
||||
|
value_2: "43012.15", |
||||
|
value_3: "61869.09", |
||||
|
value_4: "425537.45" |
||||
|
}, |
||||
|
{ |
||||
|
id: 94, |
||||
|
name: "AI中文范文", |
||||
|
sort: 2, |
||||
|
value_1: "8839.00", |
||||
|
value_2: "50174.00", |
||||
|
value_3: "120911.00", |
||||
|
value_4: "158772.50" |
||||
|
}, |
||||
|
{ |
||||
|
id: 61, |
||||
|
name: "维普大学生版", |
||||
|
sort: 11, |
||||
|
value_1: "23754.25", |
||||
|
value_2: "43012.15", |
||||
|
value_3: "61869.09", |
||||
|
value_4: "425537.45" |
||||
|
}, |
||||
|
{ |
||||
|
id: 941, |
||||
|
name: "AI中文范文", |
||||
|
sort: 21, |
||||
|
value_1: "8839.00", |
||||
|
value_2: "50174.00", |
||||
|
value_3: "120911.00", |
||||
|
value_4: "158772.50" |
||||
|
}, |
||||
|
{ |
||||
|
id: 62, |
||||
|
name: "维普大学生版", |
||||
|
sort: 12, |
||||
|
value_1: "23754.25", |
||||
|
value_2: "43012.15", |
||||
|
value_3: "61869.09", |
||||
|
value_4: "425537.45" |
||||
|
}, |
||||
|
{ |
||||
|
id: 942, |
||||
|
name: "AI中文范文", |
||||
|
sort: 22, |
||||
|
value_1: "8839.00", |
||||
|
value_2: "50174.00", |
||||
|
value_3: "120911.00", |
||||
|
value_4: "158772.50" |
||||
|
}, |
||||
|
{ |
||||
|
id: 63, |
||||
|
name: "维普大学生版", |
||||
|
sort: 13, |
||||
|
value_1: "23754.25", |
||||
|
value_2: "43012.15", |
||||
|
value_3: "61869.09", |
||||
|
value_4: "425537.45" |
||||
|
}, |
||||
|
{ |
||||
|
id: 943, |
||||
|
name: "AI中文范文", |
||||
|
sort: 23, |
||||
|
value_1: "8839.00", |
||||
|
value_2: "50174.00", |
||||
|
value_3: "120911.00", |
||||
|
value_4: "158772.50" |
||||
|
}, |
||||
|
] |
||||
|
that.top_list = { |
||||
|
6: { |
||||
|
id: "6", |
||||
|
name: "千校论文查重平台", |
||||
|
value_1: "214535.80" |
||||
|
}, |
||||
|
94: { |
||||
|
id: "94", |
||||
|
name: "尚志教育", |
||||
|
value_1: "149840.50" |
||||
|
}, |
||||
|
61: { |
||||
|
id: "61", |
||||
|
name: "千校论文查重平台", |
||||
|
value_1: "214535.80" |
||||
|
}, |
||||
|
941: { |
||||
|
id: "941", |
||||
|
name: "尚志教育", |
||||
|
value_1: "149840.50" |
||||
|
}, |
||||
|
62: { |
||||
|
id: "62", |
||||
|
name: "千校论文查重平台", |
||||
|
value_1: "214535.80" |
||||
|
}, |
||||
|
942: { |
||||
|
id: "942", |
||||
|
name: "尚志教育", |
||||
|
value_1: "149840.50" |
||||
|
}, |
||||
|
|
||||
|
} |
||||
|
// this.$http('POST', '/supernew/ajax_get_type_batch_list', { |
||||
|
// date: that.text, |
||||
|
// rank_type: that.dataRank, |
||||
|
// sort_by: that.sort_by, |
||||
|
// sort_order: that.sort_order, |
||||
|
// cur_page: that.currentPage, |
||||
|
// page_size: that.pageSize, |
||||
|
// }).then(response => { |
||||
|
// this.$nextTick(() => { |
||||
|
// that.tableData = response.data.list |
||||
|
// that.top_list = response.data.top_list |
||||
|
// that.total = response.data.total |
||||
|
// }) |
||||
|
// }).catch(error => { |
||||
|
// console.error(error, 'error') |
||||
|
// }) |
||||
|
}, |
||||
|
getRankingDetail(obj) { |
||||
|
const that = this |
||||
|
that.tableData1 = [] |
||||
|
this.$http('POST', '/supernew/ajax_get_rank_detail', { |
||||
|
date: that.text, |
||||
|
rank_type: that.dataRank, |
||||
|
sort_by: 2, |
||||
|
sort_order: 2, |
||||
|
...obj |
||||
|
}).then(response => { |
||||
|
this.$nextTick(() => { |
||||
|
that.tableData1 = response.data.list.slice(0, 5) |
||||
|
}) |
||||
|
}).catch(error => { |
||||
|
console.error(error, 'error') |
||||
|
}) |
||||
|
}, |
||||
|
getAgentRankingList(obj) { |
||||
|
const that = this |
||||
|
that.tableData1 = [] |
||||
|
this.$http('POST', '/supernew/ajax_get_agent_rank_list', { |
||||
|
date: that.text, |
||||
|
rank_type: that.dataRank, |
||||
|
cur_page: 1, |
||||
|
page_size: 5, |
||||
|
...obj |
||||
|
}).then(response => { |
||||
|
this.$nextTick(() => { |
||||
|
that.tableData1 = response.data.list |
||||
|
}) |
||||
|
}).catch(error => { |
||||
|
console.error(error, 'error') |
||||
|
}) |
||||
|
}, |
||||
|
getCheckTypeRankingList(obj) { |
||||
|
const that = this |
||||
|
that.tableData1 = [] |
||||
|
this.$http('POST', '/supernew/ajax_get_type_rank_list', { |
||||
|
date: that.text, |
||||
|
rank_type: that.dataRank, |
||||
|
cur_page: 1, |
||||
|
page_size: 5, |
||||
|
...obj |
||||
|
}).then(response => { |
||||
|
this.$nextTick(() => { |
||||
|
that.tableData1 = response.data.list.slice(0, 5) |
||||
|
}) |
||||
|
}).catch(error => { |
||||
|
console.error(error, 'error') |
||||
|
}) |
||||
|
}, |
||||
|
handleSizeChange(val) { |
||||
|
this.pageSize = val |
||||
|
this.getRankingData() |
||||
|
}, |
||||
|
handleCurrentChange(val) { |
||||
|
this.currentPage = val |
||||
|
this.getRankingData() |
||||
|
}, |
||||
|
}, |
||||
|
beforeDestory() { |
||||
|
if (this.resizeObserver) { |
||||
|
this.resizeObserver.disconnect(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
.lookMore { |
||||
|
cursor: pointer; |
||||
|
font-weight: 400; |
||||
|
} |
||||
|
|
||||
|
.table-container { |
||||
|
width: 100%; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.tableHeaderSelect ::v-deep .el-input__inner { |
||||
|
font-size: 14px; |
||||
|
font-weight: normal; |
||||
|
letter-spacing: 0.08em; |
||||
|
font-family: Microsoft YaHei UI; |
||||
|
color: #1E2226; |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue