312 lines
7.0 KiB
Vue
312 lines
7.0 KiB
Vue
|
|
<template>
|
||
|
|
<div class="trade-operation-distribution-effect">
|
||
|
|
<el-card shadow="hover">
|
||
|
|
<template #header>
|
||
|
|
<div class="card-header">
|
||
|
|
<span>分销效果核算</span>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
<!-- 搜索条件 -->
|
||
|
|
<div class="search-container">
|
||
|
|
<el-form :model="searchParams" :inline="true" class="search-form">
|
||
|
|
<el-form-item label="时间范围">
|
||
|
|
<el-date-picker
|
||
|
|
v-model="searchParams.dateRange"
|
||
|
|
type="daterange"
|
||
|
|
range-separator="至"
|
||
|
|
start-placeholder="开始日期"
|
||
|
|
end-placeholder="结束日期"
|
||
|
|
value-format="YYYY-MM-DD"
|
||
|
|
/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="达人名称">
|
||
|
|
<el-input v-model="searchParams.anchorName" placeholder="请输入达人名称" clearable />
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item>
|
||
|
|
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||
|
|
<el-button @click="handleReset">重置</el-button>
|
||
|
|
</el-form-item>
|
||
|
|
</el-form>
|
||
|
|
</div>
|
||
|
|
<!-- 分销效果趋势 -->
|
||
|
|
<div class="chart-container">
|
||
|
|
<el-card>
|
||
|
|
<template #header>
|
||
|
|
<div class="card-header">分销效果趋势</div>
|
||
|
|
</template>
|
||
|
|
<div ref="effectChartRef" class="chart"></div>
|
||
|
|
</el-card>
|
||
|
|
</div>
|
||
|
|
<!-- 核心指标 -->
|
||
|
|
<div class="stats-cards">
|
||
|
|
<el-card class="stats-card">
|
||
|
|
<div class="stats-card-title">总销售额</div>
|
||
|
|
<div class="stats-card-value">{{ statsData.totalSales || 0 }}</div>
|
||
|
|
</el-card>
|
||
|
|
<el-card class="stats-card">
|
||
|
|
<div class="stats-card-title">总佣金金额</div>
|
||
|
|
<div class="stats-card-value">{{ statsData.totalCommission || 0 }}</div>
|
||
|
|
</el-card>
|
||
|
|
<el-card class="stats-card">
|
||
|
|
<div class="stats-card-title">平均佣金率</div>
|
||
|
|
<div class="stats-card-value">{{ statsData.avgCommissionRate || 0 }}%</div>
|
||
|
|
</el-card>
|
||
|
|
<el-card class="stats-card">
|
||
|
|
<div class="stats-card-title">达人数量</div>
|
||
|
|
<div class="stats-card-value">{{ statsData.anchorCount || 0 }}</div>
|
||
|
|
</el-card>
|
||
|
|
</div>
|
||
|
|
<!-- 达人推广效果 -->
|
||
|
|
<div class="anchor-effect">
|
||
|
|
<el-card>
|
||
|
|
<template #header>
|
||
|
|
<div class="card-header">达人推广效果</div>
|
||
|
|
</template>
|
||
|
|
<el-table :data="anchorList" style="width: 100%">
|
||
|
|
<el-table-column prop="rank" label="排名" width="80" />
|
||
|
|
<el-table-column prop="anchorName" label="达人名称" />
|
||
|
|
<el-table-column prop="sales" label="销售额" />
|
||
|
|
<el-table-column prop="commission" label="佣金金额" />
|
||
|
|
<el-table-column prop="commissionRate" label="佣金率" />
|
||
|
|
<el-table-column prop="orderCount" label="订单数" />
|
||
|
|
<el-table-column prop="conversionRate" label="转化率" />
|
||
|
|
</el-table>
|
||
|
|
<div class="pagination-container">
|
||
|
|
<el-pagination
|
||
|
|
v-model:current-page="pagination.currentPage"
|
||
|
|
v-model:page-size="pagination.pageSize"
|
||
|
|
:page-sizes="[10, 20, 50, 100]"
|
||
|
|
layout="total, sizes, prev, pager, next, jumper"
|
||
|
|
:total="pagination.total"
|
||
|
|
@size-change="handleSizeChange"
|
||
|
|
@current-change="handleCurrentChange"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</el-card>
|
||
|
|
</div>
|
||
|
|
</el-card>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { ref, reactive, onMounted } from 'vue';
|
||
|
|
import * as echarts from 'echarts';
|
||
|
|
|
||
|
|
const searchParams = reactive({
|
||
|
|
dateRange: [],
|
||
|
|
anchorName: '',
|
||
|
|
});
|
||
|
|
|
||
|
|
const statsData = reactive({
|
||
|
|
totalSales: 0,
|
||
|
|
totalCommission: 0,
|
||
|
|
avgCommissionRate: 0,
|
||
|
|
anchorCount: 0,
|
||
|
|
});
|
||
|
|
|
||
|
|
interface AnchorItem {
|
||
|
|
rank: number;
|
||
|
|
anchorName: string;
|
||
|
|
sales: number;
|
||
|
|
commission: number;
|
||
|
|
commissionRate: number;
|
||
|
|
orderCount: number;
|
||
|
|
conversionRate: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
const anchorList = ref<AnchorItem[]>([]);
|
||
|
|
|
||
|
|
const pagination = reactive({
|
||
|
|
currentPage: 1,
|
||
|
|
pageSize: 10,
|
||
|
|
total: 0,
|
||
|
|
});
|
||
|
|
|
||
|
|
const effectChartRef = ref();
|
||
|
|
let effectChart: echarts.ECharts | null = null;
|
||
|
|
|
||
|
|
// 模拟分销效果趋势数据
|
||
|
|
const getMockEffectTrend = () => {
|
||
|
|
const dates = ['1月', '2月', '3月', '4月', '5月', '6月'];
|
||
|
|
return dates.map((date) => ({
|
||
|
|
date,
|
||
|
|
sales: 500000 + Math.random() * 1000000,
|
||
|
|
commission: 50000 + Math.random() * 200000,
|
||
|
|
}));
|
||
|
|
};
|
||
|
|
|
||
|
|
// 模拟达人推广效果数据
|
||
|
|
const getMockAnchorList = () => {
|
||
|
|
const anchors: AnchorItem[] = [];
|
||
|
|
for (let i = 1; i <= 20; i++) {
|
||
|
|
anchors.push({
|
||
|
|
rank: i,
|
||
|
|
anchorName: `达人${i}`,
|
||
|
|
sales: 100000 + Math.random() * 900000,
|
||
|
|
commission: 10000 + Math.random() * 180000,
|
||
|
|
commissionRate: 10 + Math.random() * 10,
|
||
|
|
orderCount: 100 + Math.floor(Math.random() * 900),
|
||
|
|
conversionRate: parseFloat((1 + Math.random() * 9).toFixed(2)),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return anchors;
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleSearch = () => {
|
||
|
|
// 使用模拟数据
|
||
|
|
statsData.totalSales = 5000000 + Math.random() * 5000000;
|
||
|
|
statsData.totalCommission = 500000 + Math.random() * 500000;
|
||
|
|
statsData.avgCommissionRate = 15 + Math.random() * 5;
|
||
|
|
statsData.anchorCount = 50 + Math.floor(Math.random() * 50);
|
||
|
|
anchorList.value = getMockAnchorList();
|
||
|
|
pagination.total = 20;
|
||
|
|
initEffectChart(getMockEffectTrend());
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleReset = () => {
|
||
|
|
searchParams.dateRange = [];
|
||
|
|
searchParams.anchorName = '';
|
||
|
|
pagination.currentPage = 1;
|
||
|
|
pagination.pageSize = 10;
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleSizeChange = (size: number) => {
|
||
|
|
pagination.pageSize = size;
|
||
|
|
handleSearch();
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleCurrentChange = (current: number) => {
|
||
|
|
pagination.currentPage = current;
|
||
|
|
handleSearch();
|
||
|
|
};
|
||
|
|
|
||
|
|
const initEffectChart = (effectTrend: any[]) => {
|
||
|
|
if (!effectChartRef.value) return;
|
||
|
|
|
||
|
|
if (effectChart) {
|
||
|
|
effectChart.dispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
effectChart = echarts.init(effectChartRef.value);
|
||
|
|
|
||
|
|
const option = {
|
||
|
|
tooltip: {
|
||
|
|
trigger: 'axis',
|
||
|
|
axisPointer: {
|
||
|
|
type: 'cross',
|
||
|
|
label: {
|
||
|
|
backgroundColor: '#6a7985',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
legend: {
|
||
|
|
data: ['销售额', '佣金金额'],
|
||
|
|
},
|
||
|
|
grid: {
|
||
|
|
left: '3%',
|
||
|
|
right: '4%',
|
||
|
|
bottom: '3%',
|
||
|
|
containLabel: true,
|
||
|
|
},
|
||
|
|
xAxis: {
|
||
|
|
type: 'category',
|
||
|
|
boundaryGap: false,
|
||
|
|
data: effectTrend.map((item) => item.date),
|
||
|
|
},
|
||
|
|
yAxis: [
|
||
|
|
{
|
||
|
|
type: 'value',
|
||
|
|
name: '金额',
|
||
|
|
position: 'left',
|
||
|
|
},
|
||
|
|
],
|
||
|
|
series: [
|
||
|
|
{
|
||
|
|
name: '销售额',
|
||
|
|
type: 'line',
|
||
|
|
data: effectTrend.map((item) => item.sales),
|
||
|
|
smooth: true,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '佣金金额',
|
||
|
|
type: 'line',
|
||
|
|
data: effectTrend.map((item) => item.commission),
|
||
|
|
smooth: true,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
};
|
||
|
|
|
||
|
|
effectChart.setOption(option);
|
||
|
|
};
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
handleSearch();
|
||
|
|
|
||
|
|
window.addEventListener('resize', () => {
|
||
|
|
effectChart?.resize();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.trade-operation-distribution-effect {
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-header {
|
||
|
|
font-size: 16px;
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
|
||
|
|
.search-container {
|
||
|
|
margin-bottom: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.search-form {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stats-cards {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(4, 1fr);
|
||
|
|
gap: 20px;
|
||
|
|
margin-bottom: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stats-card {
|
||
|
|
text-align: center;
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stats-card-title {
|
||
|
|
font-size: 14px;
|
||
|
|
color: #606266;
|
||
|
|
margin-bottom: 10px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.stats-card-value {
|
||
|
|
font-size: 24px;
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
|
||
|
|
.anchor-effect {
|
||
|
|
margin-bottom: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.pagination-container {
|
||
|
|
margin-top: 20px;
|
||
|
|
display: flex;
|
||
|
|
justify-content: flex-end;
|
||
|
|
}
|
||
|
|
|
||
|
|
.chart-container {
|
||
|
|
margin: 20px 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.chart {
|
||
|
|
width: 100%;
|
||
|
|
height: 400px;
|
||
|
|
}
|
||
|
|
</style>
|