Browse Source

排行榜优化

pull/33/head
pengda 2 days ago
parent
commit
96c2428746
  1. 175
      src/components/super/RankingLeft.vue
  2. 196
      src/components/super/RankingLeftMenu.vue
  3. 30
      src/views/super/Ranking/Purchase.vue
  4. 108
      src/views/super/Ranking/RankBatchList.vue
  5. 14
      src/views/super/Ranking/RankDetail.vue
  6. 47
      src/views/super/Ranking/RankList.vue
  7. 6
      src/views/super/Ranking/Ranking.vue

175
src/components/super/RankingLeft.vue

@ -0,0 +1,175 @@
<template>
<el-menu :default-active="activeMenu" class="el-menu-vertical-demo" @select="handleSelect" :collapse="isCollapse" :default-openeds="defaultOpeneds">
<div class="menu-top">
<span v-show="!isCollapse">导航</span>
<img v-if="!isCollapse" src="../../assets/menu-close.svg" @click="changeMenuStatus(true)" alt="">
<img v-else src="../../assets/menu-open.svg" @click="changeMenuStatus(false)" alt="">
</div>
<el-submenu v-for="item in menuData" :key="item.index" :index="item.index">
<template slot="title">
<i :class="item.icon"></i>
<span>{{ item.title }}</span>
</template>
<el-menu-item style="padding: 0 22px;" v-for="subItem in item.children" :key="subItem.index" :index="subItem.index">
{{ subItem.title }}
</el-menu-item>
</el-submenu>
</el-menu>
</template>
<script>
export default {
name: 'RankingLeft',
data() {
return {
isCollapse: false,
activeMenu: '',
defaultOpeneds: [], // <--
routerList: [],
menuData: [
{
index: '1',
title: '总利润',
icon: 'el-icon-menu',
children: [
{ index: '1-1', title: '年排行', path: '/super/ranking/yearProfit' },
{ index: '1-2', title: '月排行', path: '/super/ranking/monthProfit' }
]
},
{
index: '2',
title: '产品',
icon: 'el-icon-menu',
children: [
{ index: '2-1', title: '毛利润排行', path: '/super/ranking/checkProfit' },
{ index: '2-2', title: '订单数排行', path: '/super/ranking/checkOrdernum' },
{ index: '2-3', title: '退单数排行', path: '/super/ranking/checkRefund' },
{ index: '2-4', title: '负毛利排行', path: '/super/ranking/loss' }
]
},
{
index: '3',
title: '代理商',
icon: 'el-icon-menu',
children: [
{ index: '3-1', title: '毛利润排行', path: '/super/ranking/agentProfit' },
{ index: '3-2', title: '充值排行', path: '/super/ranking/agentRecharge' },
{ index: '3-3', title: '新加盟', path: '/super/ranking/agentNew' }
]
},
{
index: '4',
title: '设置',
icon: 'el-icon-menu',
children: [
{ index: '4-1', title: '采购价', path: '/super/ranking/purchase' },
{ index: '4-2', title: '阶段采购', path: '/super/ranking/stagePurchase' }
]
}
]
};
},
methods: {
changeMenuStatus(flag) {
this.isCollapse = flag;
},
handleSelect(index) {
this.activeMenu = index;
// menu path
const allItems = this.menuData.flatMap(menu => menu.children);
const targetItem = allItems.find(item => item.index === index);
if (targetItem && this.$route.path !== targetItem.path) {
this.$router.push(targetItem.path);
}
},
},
mounted() {
const allItems = this.menuData.flatMap(menu => menu.children.map(child => ({ ...child, parentIndex: menu.index })));
const current = allItems.find(item => item.path === this.$route.path);
this.activeMenu = current ? current.index : '';
this.defaultOpeneds = current ? [current.parentIndex] : [];
}
}
</script>
<style lang="scss" scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 158px;
min-width: 158px;
min-height: calc(100vh - 62px);
}
.el-menu-item {
padding: 0 22px;
}
.menu-top {
background: #FFFFFF;
box-sizing: border-box;
/* middle/middle_line_1 */
border-width: 0px 0px 1px 0px;
border-style: solid;
border-color: #DFE2E6;
padding: 15px 0px;
margin: 0 22px;
display: flex;
font-size: 16px;
color: #1E2226;
font-weight: bold;
line-height: normal;
letter-spacing: 0.08em;
justify-content: space-between;
align-items: center;
}
::v-deep .el-submenu {
width: 16px;
font-size: 16px;
}
::v-deep .el-submenu .el-menu-item {
min-width: 138px;
width: 100%;
}
::v-deep .el-submenu__title {
display: flex;
align-items: center;
justify-content: flex-start;
}
::v-deep .el-submenu__title:hover {
background-color: transparent;
cursor: not-allowed;
}
::v-deep .el-submenu__title .el-submenu__icon-arrow.el-icon-arrow-down {
display: none;
}
::v-deep .el-submenu .el-menu-item {
padding: 0 22px;
display: flex;
justify-content: flex-start;
}
::v-deep .el-submenu .el-menu-item {
height: 36px;
}
::v-deep.el-submenu .el-menu-item {
height: 36px;
line-height: 36px;
color: #8A9099;
letter-spacing: 0.08em;
}
::v-deep .el-menu-item:hover {
background: #F6F7FA;
}
::v-deep .el-menu-item.is-active {
color: #006AFF;
font-weight: bold;
}
</style>

196
src/components/super/RankingLeftMenu.vue

@ -1,196 +0,0 @@
<template>
<aside class="sidebar">
<ul>
<li v-for="item in menuList" :key="item.path">
<div class="flex">
<img :src="item.imgActive" alt="">
{{ item.name }}
</div>
<p :class="['flex', $route.path == item1.path ? 'curActive' : '']" v-for="(item1) in item.list"
@click="setActiveCur(item1.desc, item1)" :key="item1.name">{{ item1.name }}</p>
</li>
</ul>
</aside>
</template>
<script>
import {mapState} from 'vuex';
import store from '../../store';
export default {
name: 'Sidebar',
props: {},
data() {
return {
menuList: [
{
name: '总利润',
imgActive: require('@/assets/super/ranking-menu.svg'),
list: [
{
name: '年排行',
path: '/super/ranking/yearProfit',
},
{
name: '月排行',
path: '/super/ranking/monthProfit',
},
]
},
{
name: '产品',
imgActive: require('@/assets/super/ranking-menu.svg'),
list: [
{
name: '毛利润排行',
path: '/super/ranking/checkProfit',
},
{
name: '订单数排行',
path: '/super/ranking/checkOrdernum',
},
{
name: '退单数排行',
path: '/super/ranking/checkRefund',
},
{
name: '负毛利排行',
path: '/super/ranking/loss',
},
]
},
{
name: '代理商',
imgActive: require('@/assets/super/ranking-menu.svg'),
list: [
{
name: '毛利润排行',
path: '/super/ranking/agentProfit',
},
{
name: '充值排行',
path: '/super/ranking/agentRecharge',
},
{
name: '新加盟',
path: '/super/ranking/agentNew',
},
]
},
{
name: '设置',
imgActive: require('@/assets/super/ranking-menu.svg'),
list: [
{
name: '采购价',
path: '/super/ranking/purchase',
},
{
name: '阶段采购',
path: '/super/ranking/stagePurchase',
},
// {
// name: '',
// path: '/super/ranking/agentNew',
// },
]
},
]
}
},
mounted() {
},
created() {
},
computed: {
...mapState(['pageTitle']) // VuexshowSidebar
},
beforeDestroy() {
},
methods: {
setActiveCur(dom, item) {
if (this.$route.path != item.path) {
this.$router.push(item.path)
store.commit('SET_PAGETITLE', item.name);
}
setTimeout(() => {
this.setHighActive(dom)
}, 500)
},
setHighActive(dom) {
const ele = document.getElementById(dom)
if (!ele) return
ele.classList.add('ceshi')
ele.scrollIntoView({behavior: 'smooth', block: 'start'})
setTimeout(() => {
ele.classList.remove('ceshi')
}, 1000)
}
}
}
</script>
<style scoped lang="scss">
.sidebar {
width: 158px;
padding: 21px;
box-sizing: border-box;
background: #FFFFFF;
box-shadow: 0px 0px 11px 2px rgba(147, 147, 147, 0.11);
}
ul {
list-style: none;
padding: 0;
}
.not-point {
pointer-events: none;
/* 阻止鼠标事件 */
opacity: 0.5;
/* 可选,降低透明度以视觉上表示不可用 */
cursor: not-allowed;
/* 改变鼠标光标样式,表示不可用 */
}
li {
margin-bottom: 10px;
div {
letter-spacing: 0.08em;
color: #1E2226;
margin: 11px 0;
cursor: pointer;
img {
margin-right: 6px;
}
}
p {
margin: 9px 0;
letter-spacing: 0.08em;
line-height: 18px;
color: #8A9099;
cursor: pointer;
&:hover {
color: #006AFF;
}
}
.curActive {
color: #006AFF;
}
}
.active {
font-weight: bold;
letter-spacing: 0.08em;
color: #006AFF;
}
.item-active {
color: #006AFF;
}
</style>

30
src/views/super/Ranking/Purchase.vue

@ -18,18 +18,14 @@
<span>/</span>
</div>
</el-form-item>
<!-- <div class="flex-between" style="gap: 8px;">
<GuipInput label="采购单价" v-model="form.unit_price" prop="unit_price" unit="元"/>
<GuipInput v-model="form.unit_num" prop="unit_num" style="flex: 1;" unit="字(篇/页)"/>
</div> -->
<template v-if="type != 'purchase'">
<el-form-item label="阶段成本" prop="cost" label-width="73px">
<div style="display: flex; align-items: center; gap: 8px; width: 100%;">
<GuipInput v-model="form.cost" style="flex: 1;" />
<span></span>
</div>
</el-form-item>
<!-- <el-form-item label="阶段成本" prop="cost" label-width="73px">-->
<!-- <div style="display: flex; align-items: center; gap: 8px; width: 100%;">-->
<!-- <GuipInput v-model="form.cost" style="flex: 1;" />-->
<!-- <span></span>-->
<!-- </div>-->
<!-- </el-form-item>-->
<el-form-item label="起止日期" prop="date" label-width="73px">
<el-date-picker v-model="form.date" type="daterange" value-format="yyyy-MM-dd" range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" @input="testClick" style="width: 100%;"></el-date-picker>
@ -81,13 +77,13 @@
<el-table-column label="采购价">
<template slot-scope="scope">
<template v-if="scope.row.unit_price > 0">
<!-- <template v-if="scope.row.unit_price > 0">-->
单价{{ scope.row.unit_price }} / {{
scope.row.unit_num == 1 ? '篇' : scope.row.unit_num + '字' }}
</template>
<template v-else>
成本{{ scope.row.cost }}
</template>
<!-- </template>-->
<!-- <template v-else>-->
<!-- 成本{{ scope.row.cost }} -->
<!-- </template>-->
</template>
</el-table-column>
@ -311,7 +307,7 @@ export default {
})
} else {
if ((!form.unit_price || !form.unit_num) && !form.cost) {
this.$message.warning('请输入采购单价或阶段成本');
this.$message.warning('请输入采购单价');
return
}
@ -325,7 +321,7 @@ export default {
type: form.type,
unit_price: form.unit_price,
unit_num: form.unit_num,
cost: form.cost,
// cost: form.cost,
sdate: form.start_date,
edate: form.end_date,
}).then(response => {

108
src/views/super/Ranking/RankBatchList.vue

@ -12,6 +12,25 @@
@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>
<el-table :data="tableData"
@ -19,13 +38,13 @@
@sort-change="handleSortChange"
@cell-mouse-enter="handleRowHover">
<el-table-column prop="sort" label="排序" width="100"></el-table-column>
<el-table-column prop="sort" label="排序" width="95"></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]" width="200">
:label="type_select[selectedType]" width="250">
<template slot="header">
<el-select class="custom-select" popper-class="custom-select-dropdown" v-model="selectedType" @change="changeRankType">
@ -42,7 +61,7 @@
</template>
</el-table-column>
<el-table-column v-else prop="name" :label="type_desc[dataType]" width="150"></el-table-column>
<el-table-column v-else prop="name" :label="type_desc[dataType]" width="250"></el-table-column>
<el-table-column v-for="(field, index) in valueFields"
:key="field"
@ -51,14 +70,14 @@
sortable="custom">
<!--产品利润排行展示查看更多-->
<template v-if="index == 3 && dataRank == 1 && type != 'agent'" v-slot="{ row, $index }">
<template v-if="index == 3 && dataRank == 1" v-slot="{ row, $index }">
<el-popover v-model="row.id_popover"
placement="top"
trigger="manual"
:ref="`popover-${$index}`"
@show="popshow">
<div class="pop-wrap">
<div v-if="type != 'agent'" class="pop-wrap">
<div class="flex-between flex pop-top">
<h3>
{{ text }} {{ row.name }}
@ -80,6 +99,36 @@
</el-table-column>
</el-table>
</div>
<div v-else class="pop-wrap">
<div class="flex-between flex pop-top">
<h3>
{{ text }} {{ row.name }}
<span @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] }}
@ -98,7 +147,7 @@
</el-table-column>
<!--产品利润排行展示代理商排行-->
<el-table-column v-if="dataRank == 1 && (dataType == 'ver_type' || dataType == 'check_type')" key="top" prop="top" :label="'代理商排行'+current_month">
<el-table-column v-if="dataRank == 1 && (dataType == 'ver_type' || dataType == 'check_type')" key="top" prop="top" :label="'代理商排行'+current_month" width="250">
<template v-slot="{ row, $index }">
<el-popover v-model="row.id_popover_2"
placement="top"
@ -109,7 +158,7 @@
<div class="flex-between flex pop-top">
<h3>
{{ row.name }} 代理商排行
<span @click="goLookMoreRank(row.id)">查看更多</span>
<span @click="goLookAgentRank(row.id)">查看更多</span>
</h3>
<span class="flex point" @click="closePop(row,'id')">
关闭<img src="@/assets/register/close.svg">
@ -280,14 +329,11 @@ export default {
query: query
}).href, '_blank')
},
goLookMoreRank(id) {
goLookAgentRank(id) {
let query = {}
query.date = this.text
query.rank_type = this.dataRank
query.type = 'agent'
if (this.dataType == 'agent') {
query.aid = id
}
if (this.dataType == 'ver_type') {
query.ver_type = id
}
@ -299,6 +345,17 @@ export default {
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;
@ -324,7 +381,13 @@ export default {
if (this.dataType == 'check_type') {
obj.check_type = row.id
}
this.getRankingDetail(obj);
if(this.dataType == 'agent'){
let obj = {}
obj.aid = row.id
this.getCheckTypeRankingList(obj);
}else{
this.getRankingDetail(obj);
}
},
handleClick2(row, index, type) {
//
@ -347,7 +410,7 @@ export default {
if (this.dataType == 'check_type') {
obj.check_type = row.id
}
this.getRankingList(obj);
this.getAgentRankingList(obj);
},
popshow() {
var ariaEls = document.querySelectorAll('.el-popover')
@ -504,7 +567,7 @@ export default {
console.error(error, 'error')
})
},
getRankingList(obj) {
getAgentRankingList(obj) {
const that = this
that.tableData1 = []
this.$http('POST', '/supernew/ajax_get_agent_rank_list', {
@ -521,6 +584,23 @@ export default {
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()

14
src/views/super/Ranking/RankDetail.vue

@ -14,6 +14,20 @@
@change="handleDateChange"/>
</CustomDropdown>
</div>
<div v-if="dataType == 'month' || dataType == 'day'" 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;">
1. AI服务器成本<br />
2. Turnitin<br />
3. 学术知网PMLC硕博VIP<br />
</div>
</el-alert>
</div>
<div class=" flex-common" v-if="dataType == 'year'">
<el-form>
<el-table :data="tableData"

47
src/views/super/Ranking/RankList.vue

@ -12,6 +12,27 @@
@change="handleDateChange"/>
</CustomDropdown>
</div>
<div v-if="dataRank == 1" 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">
<!--产品利润排行展示总数-->
<div v-if="total_value>0 && dataRank == 1" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
@ -49,6 +70,8 @@
<el-table-column v-else prop="name" :label="type_desc[dataType]"></el-table-column>
<el-table-column prop="rate" label="毛利占比" v-if="dataRank == 1 && dataType == 'check_type'"></el-table-column>
<el-table-column prop="1" :label="rank_type_desc[dataRank]" sortable="custom">
<template v-slot="{ row, $index }">
<template v-if="dataRank == 3">
@ -87,6 +110,12 @@
</template>
</el-table-column>
<el-table-column prop="2" label="订单数" sortable="custom" v-if="dataRank == 1 && dataType == 'check_type'" >
<template slot-scope="scope">
{{ scope.row.value_2 }}
</template>
</el-table-column>
<el-table-column prop="2" label="退单率" sortable="custom" v-if="dataRank == 3">
<template v-slot="{ row, $index }">
<el-popover v-model="row.id_popover_2"
@ -139,14 +168,14 @@
</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="150" label="代理商"></el-table-column>
<el-table-column prop="value_2" width="100" label="退单率">
<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="value_2" width="130" label="退单率">
<template slot-scope="scope">
<span :class="scope.row.value_2>20?'color-red':''">{{ scope.row.value_2 }} %</span>
</template>
</el-table-column>
<el-table-column prop="value_1" width="100" label="退单数"></el-table-column>
<el-table-column prop="value_1" width="130" label="退单数"></el-table-column>
</el-table>
</div>
<!-- 触发弹框的按钮 -->
@ -166,7 +195,7 @@
</el-table-column>
</el-table>
<el-pagination background
<el-pagination v-if="dataType == 'agent' || dataType == 'loss'" background
@size-change='handleSizeChange'
@current-change='handleCurrentChange'
:current-page="currentPage"
@ -279,6 +308,7 @@ export default {
if (this.$route.query.type) this.dataType = this.$route.query.type
if (this.$route.query.rank_type) this.dataRank = this.$route.query.rank_type
if (Object.keys(this.$route.query).length > 0) this.showfilterTitle = true
this.setDateView()
if (this.dataType == 'loss') {
this.sort_order = 1;
@ -306,6 +336,13 @@ export default {
return `${year}-${month}`
}
},
setDateView(){
if (/^\d{4}$/.test(this.text)) {
this.view = 'year'
} else if (/^\d{4}-\d{2}$/.test(this.text)) {
this.view = 'month'
}
},
handleDateChange(date) {
this.text = this.getDate(date)
this.selectedDate = date;

6
src/views/super/Ranking/Ranking.vue

@ -1,6 +1,6 @@
<template>
<div class="siteSetting-wrap">
<RankingLeftMenu/>
<RankingLeft/>
<!-- 主内容区域 -->
<main class="main-content" ref="scrollContainer">
<router-view></router-view>
@ -10,7 +10,7 @@
</template>
<script>
import Footer from '@/components/Footer.vue';
import RankingLeftMenu from '@/components/super/RankingLeftMenu.vue'
import RankingLeft from '@/components/super/RankingLeft.vue'
export default {
//
@ -18,7 +18,7 @@ export default {
props: [''],
components: {
Footer,
RankingLeftMenu,
RankingLeft,
},
data() {
return {

Loading…
Cancel
Save