Browse Source

增加收支统计页面

zq-0828-newMenu
zq 1 month ago
committed by pengda
parent
commit
61acea2ff7
  1. 13
      src/components/GuipSelect.vue
  2. 33
      src/router/index.js
  3. 431
      src/views/agent/expenseStatistics.vue
  4. 226
      src/views/agent/statisticalDetails.vue

13
src/components/GuipSelect.vue

@ -60,10 +60,12 @@ export default {
computed: {
processedOptions() {
// options
// let options = [1,5,3] || [];
let newOptions = null
let options = this.options || [];
// [1,12,22]
if (Array.isArray(options) && options.every(item => typeof item !== 'object')) {
return options.map((item, index) => ({
if (Array.isArray(options) && options.length > 0 && options.every(item => typeof item !== 'object')) {
newOptions = options.map((item, index) => ({
[this.valueKey]: index,
[this.labelKey]: item
}));
@ -76,19 +78,18 @@ export default {
[this.labelKey]: options[key]
}));
}
// extraItemoptions
if (this.extraItem && Object.keys(this.extraItem).length > 0) {
return [
newOptions = [
{
[this.labelKey]: this.extraItem.label || '',
[this.valueKey]: this.extraItem.value || '',
disabled: this.extraItem.disabled || false
},
...options
...newOptions
];
}
return options;
return newOptions;
}
},
watch: {

33
src/router/index.js

@ -321,6 +321,39 @@ const routes = [{
hideBreadcrumb: true // 一级页面不显示面包屑
}
},
{
path: '/agent/expenseStatistics',
name: '收支统计',
component: () => import( /* webpackChunkName: "expenseStatistics" */ '../views/agent/expenseStatistics.vue'),
meta: {
title:'各站点统计列表',
hideBreadcrumb: true // 一级页面不显示面包屑
}
},
{
path: '/agent/statisticalDetails',
name: '站点月详情',
component: () => import( /* webpackChunkName: "statisticalDetails" */ '../views/agent/statisticalDetails.vue'),
meta: {
breadcrumbParent: '收支统计' // 手动指定父级
}
},
{
path: '/agent/siteRank',
name: '站点排行',
component: () => import( /* webpackChunkName: "statisticalDetails" */ '../views/agent/statisticalDetails.vue'),
meta: {
breadcrumbParent: '各站点统计列表' // 手动指定父级
}
},
{
path: '/agent/serviceRank',
name: '服务排行',
component: () => import( /* webpackChunkName: "statisticalDetails" */ '../views/agent/statisticalDetails.vue'),
meta: {
breadcrumbParent: '各站点统计列表' // 手动指定父级
}
},
// -----------------分隔符-----------

431
src/views/agent/expenseStatistics.vue

@ -0,0 +1,431 @@
<template>
<div class="main-content12 expense-wrap">
<h3 class="pagetitle">收支统计</h3>
<div class="flex-common">
<div class="flex-between">
<el-tabs v-model="totalType" @tab-click="handleClick">
<el-tab-pane label="月统计列表" name="1"></el-tab-pane>
<el-tab-pane label="各站点统计列表" name="2"></el-tab-pane>
<el-tab-pane label="各服务统计列表" name="3"></el-tab-pane>
</el-tabs>
<div class="flex">
<GuipSelect label="服务类型" v-if="totalType == '3'" :options="[{label:'asd',value:'9'}]"></GuipSelect>
<GuipSelect label="时间" :options="[{label:'asd',value:'9'}]"></GuipSelect>
</div>
</div>
<div v-if="totalType == '1'" class="mt24 monthTotal-wrap flex">
<div class="total-item loss">
<div class="flex-between total-top">
<div class="top-left">
<img src="" alt="">
<b>月利润</b>
</div>
<span class="loss-tip">亏损</span>
</div>
<div class="price">
<b>8900</b>
</div>
<div class="gap24 flex-between total-bottom">
<div class="left column gap8">
<span>淘宝200.89</span>
<span>微信200.89</span>
<span>淘宝200.89</span>
</div>
<div class="right column gap8">
<span>淘宝200.89</span>
<span>支付宝200.89</span>
</div>
</div>
</div>
<div class="total-item">
<div class="flex-between total-top">
<div class="top-left">
<img src="" alt="">
<b>月利润</b>
</div>
<span class="loss-tip">亏损</span>
</div>
<div class="price">
<b>8900</b>
</div>
<div class="gap24 flex-between total-bottom">
<div class="left column gap8">
<span>淘宝200.89</span>
<span>微信200.89</span>
<span>淘宝200.89</span>
</div>
<div class="right column gap8">
<span>淘宝200.89</span>
<span>支付宝200.89</span>
</div>
</div>
</div>
<div class="total-item">
<div class="flex-between total-top">
<div class="top-left">
<img src="" alt="">
<b>月利润</b>
</div>
<span class="loss-tip">亏损</span>
</div>
<div class="price">
<b>8900</b>
</div>
<div class="gap24 flex-between total-bottom">
<div class="left column gap8">
<span>淘宝200.89</span>
<span>微信200.89</span>
<span>淘宝200.89</span>
</div>
<div class="right column gap8">
<span>淘宝200.89</span>
<span>支付宝200.89</span>
</div>
</div>
</div>
<div class="total-item">
<div class="flex-between total-top">
<div class="top-left">
<img src="" alt="">
<b>月利润</b>
</div>
<span class="loss-tip">亏损</span>
</div>
<div class="price">
<b>8900</b>
</div>
<div class="gap24 flex-between total-bottom">
<div class="left column gap8">
<span>淘宝200.89</span>
<span>微信200.89</span>
<span>淘宝200.89</span>
</div>
<div class="right column gap8">
<span>淘宝200.89</span>
<span>支付宝200.89</span>
</div>
</div>
</div>
</div>
<el-form class="mt24">
<GuipTable :tableData="monthTotalList" ref="multipleTable" autoColumn="true" :loading="tableLoading" style="flex:1"
:show-summary="totalType === '1'"
:summary-method="totalType === '1' ? getSummaries : null">
<el-table-column prop="date" label="日期" min-width="130px" v-if="totalType == '1'"></el-table-column>
<el-table-column prop="date1" label="站点名称" min-width="130px" v-if="totalType == '2'"></el-table-column>
<el-table-column prop="date2" label="服务名称" min-width="130px" v-if="totalType == '3'"></el-table-column>
<el-table-column prop="profit" label="利润" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit }}
</div>
</template>
</el-table-column>
<el-table-column prop="income" label="收入" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.income ? scope.row.income : '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="expenditure" label="支出" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.expenditure ? scope.row.expenditure : '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="orderVolume" label="单量" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.orderVolume ? scope.row.orderVolume : '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="profit1" label="淘宝收/支/单量" min-width="160px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit ? scope.row.profit : '-' }}
</div>
</template>
</el-table-column>
<el-table-column v-if="totalType == '3'"
key="top" prop="top" label="站点排行(利润)" width="250">
<template v-slot="{ row }">
<span v-if="true" slot="reference" class="flex">
NO.1 万方本科版
<svg-icon :size="14" @click="handleClick2(row.id,1,0)"
:path="require('@/assets/super/list-detail.svg')" :color="'#8A9099'"
:hoverColor="'#006AFF'" />
</span>
<span v-else slot="reference">暂无排行</span>
</template>
</el-table-column>
<el-table-column v-if="totalType == '2'"
key="top" prop="top" label="服务排行(利润)" width="250">
<template v-slot="{ row }">
<span v-if="true" slot="reference" class="flex">
NO.1 万方本科版
<svg-icon :size="14" @click="handleClick2(row.id,1,0)"
:path="require('@/assets/super/list-detail.svg')" :color="'#8A9099'"
:hoverColor="'#006AFF'" />
</span>
<span v-else slot="reference">暂无排行</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" v-if="totalType != '1'">
<template slot-scope="scope">
<GuipButton type="text" class="mr-16" @click="handleClick2(scope.row.id,0,1)">详情</GuipButton>
</template>
</el-table-column>
</GuipTable>
</el-form>
</div>
</div>
</template>
<script>
import GuipButton from '@/components/GuipButton.vue';
import GuipSelect from '@/components/GuipSelect.vue';
import GuipTable from '@/components/GuipTable.vue';
import SvgIcon from '@/components/SvgIcon.vue';
export default {
components: {
GuipTable,
GuipButton,
GuipSelect,
SvgIcon
},
props: {
total_type: {
type: String,
default: '1'
},
},
data() {
return {
totalType:'1',
tableLoading:false,
monthTotalList:[
{
date:'2025-08-26',
profit:19,
income:29,
},
{
profit:-87.9,
date:'2025-08-26',
income:7.9,
expenditure:40,
},
{
profit:619.46,
date:'2025-08-26',
income:79
},
],
top_list:[]
}
},
mounted() {
const {total_type} = this.$route.query
this.$nextTick(()=>{
this.totalType = this.total_type;
if(total_type)this.totalType = total_type;
})
console.log(this.total_type,total_type,'total_type===');
// this.getExpenseList()
},
methods: {
handleClick2(id,rankFlag,detailFlag){
this.$router.push(`/agent/serviceRank?totalType=${this.totalType}&rankFlag=${rankFlag}&detailFlag=${detailFlag}`)
},
handleClick(tab, event){
console.log(tab, event,'=====tab, event');
this.getExpenseList()
},
getSummaries(param) {
if(this.totalType != '1')return []
const { columns, data } = param;
const sums = [];
let obj = {
1:'profit',
2:'income',
3:'expenditure',
4:'orderVolume'
}
console.log(obj,'==');
columns.forEach((column, index) => {
// console.log(data,column, index,'====');
// const values = data.map(item => {
// item[column.property] = Number(item[column.property]) || 0
// return {...item}
// });
// console.log(values,'values===');
// for(let i = 1;i<4;i++){
// const incomeSum = this.getColumnReduce(data,obj[i]);
// sums[i] = incomeSum;
// console.log(sums[i],'sums[i]====sums[i]');
// }
const numericColumns = ['profit', 'income', 'expenditure', 'orderVolume'];
if (numericColumns.includes(column.property)) {
const values = data.map(item => Number(item[column.property]) || 0);
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
return !isNaN(value) ? prev + value : prev;
}, 0);
//
if (['profit', 'income', 'expenditure'].includes(column.property)) {
sums[index] = sums[index].toFixed(2) + ' 元';
}
} else {
sums[index] = 'N/A';
}
} else {
sums[index] = 'N/A';
}
if (index === 0) {
sums[index] = `2025年8月利润小计`;
}
//
// if (!data[0]?.hasOwnProperty(column.property) ||
// data.some(item => item[column.property] === null || item[column.property] === '')) {
// sums[index] = 'N/A';
// return;
// }
//
// sums[index] = values.reduce((prev, curr) => prev + curr, 0);
});
return sums;
},
getColumnReduce(data,key){
const incomeSum = data.reduce((sum, item) => sum + Number(item[key]), 0);
return incomeSum.toFixed(2)
},
getExpenseList() {
//
// this.tableLoading = true
// try {
// const requestParams = {
// date:'2025-08',
// totalType:this.totalType
// }
// this.$http('POST', '/agentnew/ajax_get_check_order_list', requestParams).then(response => {
// this.tableLoading = false
// console.log(response,'====');
// // this.$nextTick(() => {
// // this.monthTotalList = response.data.list
// // })
// }).catch(error => {
// console.error(error, 'error')
// })
// } catch (error) {
// console.error(':', error)
// } finally {
// this.tableLoading = false
// }
},
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-table__footer-wrapper tbody td.el-table__cell {
background-color: #E8F0FE; /* 背景色 */
color: #006AFF; /* 文字颜色 */
font-weight: 600;
}
.loss-profit{
color: #FF4D4F;
}
.expense-wrap{
.pagetitle {
text-align: left;
font-size: 16px;
font-weight: bold;
line-height: normal;
letter-spacing: 0.08em;
color: #1E2226;
margin-top: 8px;
}
.monthTotal-wrap{
display: grid;
grid-gap: 12px;
grid-template-columns: repeat(auto-fit, 287px);
}
.loss-tip{
width: 50px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
border-radius: 4px;
background: #FFF1F0;
box-sizing: border-box;
border: 1px solid #FFA39E;
font-size: 14px;
font-weight: normal;
line-height: 20px;
text-align: center;
letter-spacing: 0.08em;
color: #FF4D4F;
}
.total-item{
padding: 14px 16px;
font-size: 12px;
letter-spacing: 0.03em;
color: #23242B;
box-sizing: border-box;
border-radius: 4px;
background: #F2F7FF;
.price{
text-align: left;
font-size: 12px;
font-weight: normal;
line-height: 15px;
letter-spacing: 0.08em;
color: #1E2226;
margin: 14px 0;
b{
font-size: 22px;
line-height: 20px;
letter-spacing: normal;
}
}
.total-bottom{
align-items: flex-start;
}
}
.loss{
background: #FFF1F0;
.top-left b{
color: #FF4D4F;
}
}
.gain{
background: #EFFFE0;
.top-left b{
color: #00C261;
}
}
}
</style>

226
src/views/agent/statisticalDetails.vue

@ -0,0 +1,226 @@
<template>
<div class="main-content12 expense-wrap">
<div class="flex-common">
<el-form>
<div class="flex-between mb24">
<div class=" flex gap12">
<b>{{ }}turnitin中文站月详情</b>
<div class="flex gap12">
<span :class="['ver-anchor-point',]" v-for="item in serviceRanking" :key="item">{{ item }}</span>
</div>
</div>
<GuipSelect label="时间" :options="[{label:'asd',value:'9'}]"></GuipSelect>
</div>
<!-- show-summary -->
<GuipTable :tableData="monthTotalList" ref="multipleTable" autoColumn="true" :loading="tableLoading" style="flex:1">
<el-table-column prop="sort" label="排行" min-width="130px" v-if="rankFlag == 1"></el-table-column>
<el-table-column prop="date" label="日期" min-width="130px" v-if="detailFlag ==1"></el-table-column>
<el-table-column prop="date" label="站点排行" min-width="130px" v-if="totalType == '3' && detailFlag != 1"></el-table-column>
<el-table-column prop="date" label="服务排行" min-width="130px" v-if="totalType == '2' && detailFlag != 1"></el-table-column>
<el-table-column prop="profit" label="利润" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit }}
</div>
</template>
</el-table-column>
<el-table-column prop="income" label="收入" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit ? scope.row.profit : '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="expenditure" label="支出" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit ? scope.row.profit : '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="orderVolume" label="单量" min-width="110px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit ? scope.row.profit : '-' }}
</div>
</template>
</el-table-column>
<!-- 这个可能进行循环渲染 -->
<el-table-column prop="profit" label="淘宝收/支/单量" v-if="detailFlag" min-width="160px">
<template slot-scope="scope">
<div class="flex">
{{ scope.row.profit ? scope.row.profit : '-' }}
</div>
</template>
</el-table-column>
</GuipTable>
</el-form>
</div>
</div>
</template>
<script>
import GuipSelect from '@/components/GuipSelect.vue';
import GuipTable from '@/components/GuipTable.vue';
export default {
components: {
GuipTable,
GuipSelect,
},
data() {
return {
totalType:'1',
detailFlag:true,//
rankFlag:false,//
tableLoading:false,
monthTotalList:[
{'sort':1,'profit':20,income:304,expenditure:280,orderVolume:47},
{'sort':2,'profit':30,income:127,expenditure:89,orderVolume:36},
],
serviceRanking:{
'1':'利润排行',
'2':'收入排行',
'3':'支出排行',
'4':'检测量排行',
}
}
},
mounted() {
const {totalType,detailFlag,rankFlag} = this.$route.query
this.totalType = totalType;
this.detailFlag = detailFlag;
this.rankFlag = rankFlag;
this.getDetailList()
},
methods: {
getDetailList() {
console.log('调用了---');
// this.tableLoading = true
// try {
// const requestParams = {
// date:'2025-08',
// totalType:this.totalType
// }
// this.$http('POST', '/agentnew/ajax_get_check_order_list', requestParams).then(response => {
// this.tableLoading = false
// console.log(response,'====');
// // this.$nextTick(() => {
// // if (this.intervalId && response.data.maxid && this.orderListPrevMaxId && response.data.maxid > this.orderListPrevMaxId) {
// // console.log('');
// // this.playSound();
// // }
// // this.monthTotalList = response.data.list
// // })
// }).catch(error => {
// console.error(error, 'error')
// })
// } catch (error) {
// console.error(':', error)
// } finally {
// this.tableLoading = false
// }
},
}
}
</script>
<style lang="scss" scoped>
.el-form-item{
margin-bottom: 0 !important;
}
.expense-wrap{
.ver-anchor-point {
height: 28px;
display: flex;
align-items: center;
padding: 4px 12px;
white-space: nowrap;
transition: all .3s;
border-radius: 14px;
background: #FFFFFF;
box-sizing: border-box;
border: 1px solid #DFE2E6;
letter-spacing: 0.08em;
color: #8A9099;
cursor: pointer;
}
.ver-anchor-point:hover {
border-color: transparent;
transition: all .3s;
color: #006AFF;
background: #F2F3F5;
}
.pagetitle {
text-align: left;
font-size: 16px;
font-weight: bold;
line-height: normal;
letter-spacing: 0.08em;
color: #1E2226;
margin-top: 8px;
}
.monthTotal-wrap{
display: grid;
grid-gap: 12px;
grid-template-columns: repeat(auto-fit, 287px);
}
.loss-tip{
width: 50px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
border-radius: 4px;
background: #FFF1F0;
box-sizing: border-box;
border: 1px solid #FFA39E;
font-size: 14px;
font-weight: normal;
line-height: 20px;
text-align: center;
letter-spacing: 0.08em;
color: #FF4D4F;
}
.total-item{
padding: 14px 16px;
font-size: 12px;
letter-spacing: 0.03em;
color: #23242B;
box-sizing: border-box;
border-radius: 4px;
background: #F2F7FF;
.price{
text-align: left;
font-size: 12px;
font-weight: normal;
line-height: 15px;
letter-spacing: 0.08em;
color: #1E2226;
margin: 14px 0;
b{
font-size: 22px;
line-height: 20px;
letter-spacing: normal;
}
}
.total-bottom{
align-items: flex-start;
}
}
.loss{
background: #FFF1F0;
.top-left b{
color: #FF4D4F;
}
}
.gain{
background: #EFFFE0;
.top-left b{
color: #00C261;
}
}
}
</style>
Loading…
Cancel
Save