This commit is contained in:
雷欧(林平凡)
2025-08-07 21:39:10 +08:00
parent 52266d4490
commit fadcd0ad5a
7 changed files with 258 additions and 113 deletions

View File

@@ -11,3 +11,4 @@ VUE_APP_BASE_API = ''
VUE_CLI_BABEL_TRANSPILE_MODULES = true
VUE_APP_BASE_API = 'http://127.0.0.1:30313'
port = 8888

View File

@@ -7,4 +7,5 @@ ENV = 'production'
# Jarvis/生产环境
VUE_APP_BASE_API = ''
# VUE_APP_BASE_API = 'http://134.175.126.60:30313'
VUE_APP_BASE_API = 'http://134.175.126.60:30313'
port = 8888

View File

@@ -68,5 +68,8 @@
"browserslist": [
"> 1%",
"last 2 versions"
]
],
"volta": {
"node": "18.20.8"
}
}

View File

@@ -50,3 +50,12 @@ export function getValidCodeSelectData() {
method: 'get'
})
}
// 获取订单统计数据
export function getOrderStatistics(query) {
return request({
url: '/jarvis/orderrows/statistics',
method: 'get',
params: query
})
}

View File

@@ -56,9 +56,9 @@
</el-table-column>
<el-table-column label="订单号" align="center" prop="orderId" width="120" />
<el-table-column label="商品名称" align="center" prop="skuName" :show-overflow-tooltip="true" min-width="200" />
<el-table-column label="商品价格" align="center" prop="price" width="100">
<el-table-column label="计佣金额" align="center" prop="estimateCosPrice" width="100">
<template slot-scope="scope">
<span>¥{{ scope.row.price }}</span>
<span>¥{{ scope.row.estimateCosPrice }}</span>
</template>
</el-table-column>
<el-table-column label="商品数量" align="center" prop="skuNum" width="80" />
@@ -466,6 +466,7 @@ export default {
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.queryParams.validCodes = [];
this.handleQuery();
},
// 多选框选中数据

View File

@@ -1,5 +1,45 @@
<template>
<div class="app-container">
<!-- 查询条件 -->
<el-card style="margin-bottom: 20px;">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form-item label="时间范围" prop="dateRange">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="handleDateRangeChange">
</el-date-picker>
</el-form-item>
<el-form-item label="订单状态" prop="validCode">
<el-select v-model="queryParams.validCode" placeholder="请选择订单状态" clearable>
<el-option
v-for="dict in validCodeOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="商品ID" prop="skuId">
<el-input
v-model="queryParams.skuId"
placeholder="请输入商品ID"
clearable
style="width: 200px">
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 统计卡片 -->
<el-row :gutter="20">
<el-col :span="6">
<el-card>
@@ -7,7 +47,7 @@
<span>总订单数</span>
</div>
<div class="card-body">
<h2>{{ statistics.totalOrders }}</h2>
<h2>{{ statistics.totalOrders || 0 }}</h2>
<p>累计订单数量</p>
</div>
</el-card>
@@ -18,7 +58,7 @@
<span>总佣金</span>
</div>
<div class="card-body">
<h2>¥{{ statistics.totalCommission }}</h2>
<h2>¥{{ formatMoney(statistics.totalCommission) }}</h2>
<p>累计佣金收入</p>
</div>
</el-card>
@@ -26,27 +66,28 @@
<el-col :span="6">
<el-card>
<div slot="header">
<span>今日订单</span>
<span>总商品数</span>
</div>
<div class="card-body">
<h2>{{ statistics.todayOrders }}</h2>
<p>今日新增订单</p>
<h2>{{ statistics.totalSkuNum || 0 }}</h2>
<p>累计商品数量</p>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card>
<div slot="header">
<span>今日佣金</span>
<span>实际费用</span>
</div>
<div class="card-body">
<h2>¥{{ statistics.todayCommission }}</h2>
<p>今日佣金收入</p>
<h2>¥{{ formatMoney(statistics.totalActualFee) }}</h2>
<p>累计实际费用</p>
</div>
</el-card>
</el-col>
</el-row>
<!-- 图表区域 -->
<el-row :gutter="20" style="margin-top: 20px;">
<el-col :span="12">
<el-card>
@@ -61,33 +102,39 @@
<el-col :span="12">
<el-card>
<div slot="header">
<span>佣金趋势</span>
<span>佣金分布</span>
</div>
<div class="chart-container">
<div ref="trendChart" style="height: 300px;"></div>
<div ref="commissionChart" style="height: 300px;"></div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 状态详情表格 -->
<el-row :gutter="20" style="margin-top: 20px;">
<el-col :span="24">
<el-card>
<div slot="header">
<span>热门商品排行</span>
<span>订单状态详情</span>
</div>
<el-table :data="hotProducts" style="width: 100%">
<el-table-column prop="rank" label="排名" width="80" align="center" />
<el-table-column prop="skuName" label="商品名称" :show-overflow-tooltip="true" />
<el-table-column prop="orderCount" label="订单数量" width="120" align="center" />
<el-table-column prop="totalAmount" label="总金额" width="120" align="center">
<el-table :data="statusDetails" style="width: 100%">
<el-table-column prop="label" label="状态" width="120" />
<el-table-column prop="count" label="订单数量" width="120" align="center" />
<el-table-column prop="skuNum" label="商品数量" width="120" align="center" />
<el-table-column prop="commission" label="佣金" width="120" align="center">
<template slot-scope="scope">
¥{{ scope.row.totalAmount }}
¥{{ formatMoney(scope.row.commission) }}
</template>
</el-table-column>
<el-table-column prop="totalCommission" label="总佣金" width="120" align="center">
<el-table-column prop="actualFee" label="实际费用" width="120" align="center">
<template slot-scope="scope">
¥{{ scope.row.totalCommission }}
¥{{ formatMoney(scope.row.actualFee) }}
</template>
</el-table-column>
<el-table-column prop="percentage" label="占比" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.percentage }}%
</template>
</el-table-column>
</el-table>
@@ -99,68 +146,129 @@
<script>
import * as echarts from 'echarts'
import { getOrderStatistics, getValidCodeSelectData } from '@/api/system/orderrows'
export default {
name: "OrderStatistics",
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 查询参数
queryParams: {
beginTime: null,
endTime: null,
validCode: null,
skuId: null
},
// 日期范围
dateRange: [],
// 订单状态选项
validCodeOptions: [],
// 统计数据
statistics: {
totalOrders: 4307,
totalCommission: 125680.50,
todayOrders: 45,
todayCommission: 2340.80
totalOrders: 0,
totalCommission: 0,
totalSkuNum: 0,
totalActualFee: 0,
groupStats: {}
},
hotProducts: [
{
rank: 1,
skuName: "海尔【小红花套系】消毒柜EB150十口之家150L",
orderCount: 156,
totalAmount: 358944,
totalCommission: 21536.64
},
{
rank: 2,
skuName: "京东京造 快调哑铃可调节 男士家用 运动锻炼健身器材",
orderCount: 89,
totalAmount: 53311,
totalCommission: 1599.33
},
{
rank: 3,
skuName: "惠普HP 暗影精灵11台式电脑 游戏台式机主机",
orderCount: 67,
totalAmount: 428733,
totalCommission: 3429.86
},
{
rank: 4,
skuName: "梦龙 【王嘉尔推荐】柚子山茶花蜜口味冰淇淋",
orderCount: 234,
totalAmount: 13314.6,
totalCommission: 931.02
},
{
rank: 5,
skuName: "海尔彩屏家用麦浪消毒碗柜嵌入式 130L大容量",
orderCount: 45,
totalAmount: 85455,
totalCommission: 5127.3
}
]
// 状态详情数据
statusDetails: []
}
},
created() {
this.getValidCodeOptions()
this.getStatistics()
},
mounted() {
this.initCharts()
},
methods: {
/** 获取订单状态选项 */
getValidCodeOptions() {
getValidCodeSelectData().then(response => {
this.validCodeOptions = response.data
})
},
/** 获取统计数据 */
getStatistics() {
this.loading = true
getOrderStatistics(this.queryParams).then(response => {
this.statistics = response.data
this.processStatusDetails()
this.$nextTick(() => {
this.initCharts()
})
this.loading = false
}).catch(() => {
this.loading = false
})
},
/** 处理状态详情数据 */
processStatusDetails() {
const groupStats = this.statistics.groupStats || {}
this.statusDetails = Object.values(groupStats).map(item => {
const percentage = this.statistics.totalOrders > 0
? ((item.count / this.statistics.totalOrders) * 100).toFixed(2)
: '0.00'
return {
...item,
percentage
}
})
},
/** 格式化金额 */
formatMoney(amount) {
if (!amount && amount !== 0) return '0.00'
return parseFloat(amount).toFixed(2)
},
/** 日期范围变化处理 */
handleDateRangeChange(dates) {
if (dates && dates.length === 2) {
this.queryParams.beginTime = dates[0]
this.queryParams.endTime = dates[1]
} else {
this.queryParams.beginTime = null
this.queryParams.endTime = null
}
},
/** 搜索按钮操作 */
handleQuery() {
this.getStatistics()
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.resetForm("queryForm")
this.queryParams = {
beginTime: null,
endTime: null,
validCode: null,
skuId: null
}
this.getStatistics()
},
/** 初始化图表 */
initCharts() {
this.initStatusChart()
this.initTrendChart()
this.initCommissionChart()
},
/** 初始化状态分布图表 */
initStatusChart() {
const chartDom = this.$refs.statusChart
if (!chartDom) return
const myChart = echarts.init(chartDom)
const groupStats = this.statistics.groupStats || {}
const data = Object.values(groupStats).map(item => ({
value: item.count,
name: item.label
}))
const option = {
tooltip: {
trigger: 'item',
@@ -168,7 +276,8 @@ export default {
},
legend: {
orient: 'vertical',
left: 'left'
left: 'left',
type: 'scroll'
},
series: [
{
@@ -190,55 +299,59 @@ export default {
labelLine: {
show: false
},
data: [
{ value: 2153, name: '已完成' },
{ value: 1076, name: '已确认' },
{ value: 861, name: '待确认' },
{ value: 217, name: '已取消' }
]
data: data
}
]
}
myChart.setOption(option)
},
initTrendChart() {
const chartDom = this.$refs.trendChart
/** 初始化佣金分布图表 */
initCommissionChart() {
const chartDom = this.$refs.commissionChart
if (!chartDom) return
const myChart = echarts.init(chartDom)
const groupStats = this.statistics.groupStats || {}
const data = Object.values(groupStats)
.filter(item => item.commission > 0)
.map(item => ({
value: item.commission,
name: item.label
}))
const option = {
tooltip: {
trigger: 'axis'
trigger: 'item',
formatter: '{a} <br/>{b}: ¥{c} ({d}%)'
},
legend: {
data: ['订单数量', '佣金收入']
orient: 'vertical',
left: 'left',
type: 'scroll'
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: [
{
type: 'value',
name: '订单数量'
},
{
type: 'value',
name: '佣金(元)',
position: 'right'
}
],
series: [
{
name: '订单数量',
type: 'line',
data: [120, 132, 101, 134, 90, 230, 210]
name: '佣金分布',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
{
name: '佣金收入',
type: 'line',
yAxisIndex: 1,
data: [220, 182, 191, 234, 290, 330, 310]
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: data
}
]
}

View File

@@ -16,6 +16,12 @@
<el-option label="未激活" value="0" />
</el-select>
</el-form-item>
<el-form-item label="参与统计" prop="isCount">
<el-select v-model="queryParams.isCount" placeholder="参与统计" clearable style="width: 240px">
<el-option label="参与统计" value="1" />
<el-option label="不参与统计" value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -56,6 +62,13 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="参与统计" align="center" prop="isCount" min-width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.isCount === 1 ? 'success' : 'info'">
{{ scope.row.isCount === 1 ? '参与统计' : '不参与统计' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createdAt" min-width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createdAt) }}</span>
@@ -101,6 +114,12 @@
<el-radio :label="0">未激活</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="参与统计" prop="isCount">
<el-radio-group v-model="form.isCount">
<el-radio :label="1">参与统计</el-radio>
<el-radio :label="0">不参与统计</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
@@ -122,6 +141,11 @@
{{ currentAdmin.isActive === 1 ? '已激活' : '未激活' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="参与统计">
<el-tag :type="currentAdmin.isCount === 1 ? 'success' : 'info'">
{{ currentAdmin.isCount === 1 ? '参与统计' : '不参与统计' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ parseTime(currentAdmin.createdAt) }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ parseTime(currentAdmin.updatedAt) }}</el-descriptions-item>
</el-descriptions>
@@ -164,7 +188,8 @@ export default {
wxid: null,
name: null,
unionId: null,
isActive: null
isActive: null,
isCount: null
},
// 表单参数
form: {},
@@ -176,15 +201,6 @@ export default {
name: [
{ required: true, message: "姓名不能为空", trigger: "blur" }
],
unionId: [
{ required: true, message: "联盟ID不能为空", trigger: "blur" }
],
appKey: [
{ required: true, message: "应用密钥不能为空", trigger: "blur" }
],
secretKey: [
{ required: true, message: "秘密密钥不能为空", trigger: "blur" }
]
},
// 查看详情对话框
viewDialogVisible: false,
@@ -223,7 +239,8 @@ export default {
unionId: null,
appKey: null,
secretKey: null,
isActive: 1
isActive: 1,
isCount: 1
};
this.resetForm("form");
},