|
@@ -13,10 +13,7 @@
|
|
|
<div class="card-title">总客户数</div>
|
|
<div class="card-title">总客户数</div>
|
|
|
<el-tag type="primary" effect="light">实时</el-tag>
|
|
<el-tag type="primary" effect="light">实时</el-tag>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="card-value">1,250</div>
|
|
|
|
|
- <div class="card-desc">
|
|
|
|
|
- <span>较上月 <span class="trend-up">+5.2% ↗</span></span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="card-value">{{ formatNumber(dashboardData.totalCustomers) }}</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
|
|
<el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
|
|
@@ -25,10 +22,7 @@
|
|
|
<div class="card-title">总订单数</div>
|
|
<div class="card-title">总订单数</div>
|
|
|
<el-tag type="success" effect="light">实时</el-tag>
|
|
<el-tag type="success" effect="light">实时</el-tag>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="card-value">3,520</div>
|
|
|
|
|
- <div class="card-desc">
|
|
|
|
|
- <span>较上月 <span class="trend-up">+12.4% ↗</span></span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="card-value">{{ formatNumber(dashboardData.totalOrders) }}</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
|
|
<el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
|
|
@@ -37,10 +31,7 @@
|
|
|
<div class="card-title">商品总量</div>
|
|
<div class="card-title">商品总量</div>
|
|
|
<el-tag type="warning" effect="light">总计</el-tag>
|
|
<el-tag type="warning" effect="light">总计</el-tag>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="card-value">485</div>
|
|
|
|
|
- <div class="card-desc">
|
|
|
|
|
- <span>本周上新 <span class="trend-up">+15 ↗</span></span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="card-value">{{ formatNumber(dashboardData.totalProducts) }}</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
|
|
<el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
|
|
@@ -49,10 +40,7 @@
|
|
|
<div class="card-title">本月营收</div>
|
|
<div class="card-title">本月营收</div>
|
|
|
<el-tag type="danger" effect="light">结算</el-tag>
|
|
<el-tag type="danger" effect="light">结算</el-tag>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="card-value">¥128,500</div>
|
|
|
|
|
- <div class="card-desc">
|
|
|
|
|
- <span>较上月 <span class="trend-down">-1.5% ↘</span></span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="card-value">{{ formatRevenue(dashboardData.monthlyRevenue) }}</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
@@ -60,7 +48,7 @@
|
|
|
<!-- 数据图表区域 -->
|
|
<!-- 数据图表区域 -->
|
|
|
<el-row :gutter="20" class="content-row">
|
|
<el-row :gutter="20" class="content-row">
|
|
|
<!-- 客户增长趋势 -->
|
|
<!-- 客户增长趋势 -->
|
|
|
- <el-col :xs="24" :sm="24" :lg="8" class="card-panel-col">
|
|
|
|
|
|
|
+ <el-col :xs="24" :sm="24" :lg="12" class="card-panel-col">
|
|
|
<el-card shadow="hover" class="chart-card">
|
|
<el-card shadow="hover" class="chart-card">
|
|
|
<template #header>
|
|
<template #header>
|
|
|
<div class="clearfix">
|
|
<div class="clearfix">
|
|
@@ -72,7 +60,7 @@
|
|
|
</el-col>
|
|
</el-col>
|
|
|
|
|
|
|
|
<!-- 订单金额趋势 -->
|
|
<!-- 订单金额趋势 -->
|
|
|
- <el-col :xs="24" :sm="24" :lg="8" class="card-panel-col">
|
|
|
|
|
|
|
+ <el-col :xs="24" :sm="24" :lg="12" class="card-panel-col">
|
|
|
<el-card shadow="hover" class="chart-card">
|
|
<el-card shadow="hover" class="chart-card">
|
|
|
<template #header>
|
|
<template #header>
|
|
|
<div class="clearfix">
|
|
<div class="clearfix">
|
|
@@ -84,7 +72,7 @@
|
|
|
</el-col>
|
|
</el-col>
|
|
|
|
|
|
|
|
<!-- 客户类型分布 -->
|
|
<!-- 客户类型分布 -->
|
|
|
- <el-col :xs="24" :sm="24" :lg="8" class="card-panel-col">
|
|
|
|
|
|
|
+ <!-- <el-col :xs="24" :sm="24" :lg="8" class="card-panel-col">
|
|
|
<el-card shadow="hover" class="chart-card">
|
|
<el-card shadow="hover" class="chart-card">
|
|
|
<template #header>
|
|
<template #header>
|
|
|
<div class="clearfix">
|
|
<div class="clearfix">
|
|
@@ -93,7 +81,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
<div ref="pieChartRef" style="height: 300px"></div>
|
|
<div ref="pieChartRef" style="height: 300px"></div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
- </el-col>
|
|
|
|
|
|
|
+ </el-col> -->
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
<!-- 列表区域 -->
|
|
<!-- 列表区域 -->
|
|
@@ -118,9 +106,7 @@
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
<el-table-column prop="status" label="状态" width="90">
|
|
<el-table-column prop="status" label="状态" width="90">
|
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
|
- <el-tag :type="getStatusType(scope.row.status)" size="small">
|
|
|
|
|
- {{ scope.row.status }}
|
|
|
|
|
- </el-tag>
|
|
|
|
|
|
|
+ <dict-tag :options="order_status" :value="scope.row.orderStatus" />
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
<el-table-column prop="date" label="下单时间" width="160" />
|
|
<el-table-column prop="date" label="下单时间" width="160" />
|
|
@@ -157,6 +143,9 @@
|
|
|
<script setup name="Index" lang="ts">
|
|
<script setup name="Index" lang="ts">
|
|
|
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
|
|
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
|
|
|
import * as echarts from 'echarts';
|
|
import * as echarts from 'echarts';
|
|
|
|
|
+import { customerIndexData } from '@/api/customer/customerFile/customerInfo';
|
|
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
+const { order_status } = toRefs<any>(proxy?.useDict('order_status'));
|
|
|
|
|
|
|
|
// 图表引用
|
|
// 图表引用
|
|
|
const barChartRef = ref<HTMLElement | null>(null);
|
|
const barChartRef = ref<HTMLElement | null>(null);
|
|
@@ -167,21 +156,54 @@ let barChart: echarts.ECharts | null = null;
|
|
|
let lineChart: echarts.ECharts | null = null;
|
|
let lineChart: echarts.ECharts | null = null;
|
|
|
let pieChart: echarts.ECharts | null = null;
|
|
let pieChart: echarts.ECharts | null = null;
|
|
|
|
|
|
|
|
|
|
+interface DashboardData {
|
|
|
|
|
+ totalCustomers: number;
|
|
|
|
|
+ totalOrders: number;
|
|
|
|
|
+ totalProducts: number;
|
|
|
|
|
+ monthlyRevenue: number;
|
|
|
|
|
+ customerTrend: { date: string; value: number }[];
|
|
|
|
|
+ orderAmountTrend: { date: string; value: number }[];
|
|
|
|
|
+ customerTypeDistribution: { name: string; value: number }[];
|
|
|
|
|
+ latestOrders: { orderNo: string; customer: string; product: string; amount: number; status: string; date: string }[];
|
|
|
|
|
+ hotProductRankings: { name: string; sales: number; percentage: number }[];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const dashboardData = ref<DashboardData>({
|
|
|
|
|
+ totalCustomers: 0,
|
|
|
|
|
+ totalOrders: 0,
|
|
|
|
|
+ totalProducts: 0,
|
|
|
|
|
+ monthlyRevenue: 0,
|
|
|
|
|
+ customerTrend: [],
|
|
|
|
|
+ orderAmountTrend: [],
|
|
|
|
|
+ customerTypeDistribution: [],
|
|
|
|
|
+ latestOrders: [],
|
|
|
|
|
+ hotProductRankings: []
|
|
|
|
|
+});
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+const formatNumber = (num: number) => num.toLocaleString('en-US');
|
|
|
|
|
+const formatRevenue = (num: number) => '¥' + num.toLocaleString('en-US');
|
|
|
|
|
+
|
|
|
|
|
+const orderList = ref<DashboardData['latestOrders']>([]);
|
|
|
|
|
+const productRankings = ref<DashboardData['hotProductRankings']>([]);
|
|
|
|
|
+
|
|
|
// 图表初始化
|
|
// 图表初始化
|
|
|
const initCharts = () => {
|
|
const initCharts = () => {
|
|
|
|
|
+ const data = dashboardData.value;
|
|
|
|
|
+
|
|
|
// 柱形图 - 客户趋势
|
|
// 柱形图 - 客户趋势
|
|
|
if (barChartRef.value) {
|
|
if (barChartRef.value) {
|
|
|
barChart = echarts.init(barChartRef.value);
|
|
barChart = echarts.init(barChartRef.value);
|
|
|
barChart.setOption({
|
|
barChart.setOption({
|
|
|
tooltip: { trigger: 'axis' },
|
|
tooltip: { trigger: 'axis' },
|
|
|
grid: { top: '15%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
grid: { top: '15%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
|
- xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
|
|
|
|
|
|
|
+ xAxis: { type: 'category', data: data.customerTrend.map((i) => i.date) },
|
|
|
yAxis: { type: 'value' },
|
|
yAxis: { type: 'value' },
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: '新增客户',
|
|
name: '新增客户',
|
|
|
type: 'bar',
|
|
type: 'bar',
|
|
|
- data: [12, 20, 15, 8, 7, 11, 13],
|
|
|
|
|
|
|
+ data: data.customerTrend.map((i) => i.value),
|
|
|
itemStyle: { color: '#409EFF' },
|
|
itemStyle: { color: '#409EFF' },
|
|
|
barWidth: '40%'
|
|
barWidth: '40%'
|
|
|
}
|
|
}
|
|
@@ -195,13 +217,13 @@ const initCharts = () => {
|
|
|
lineChart.setOption({
|
|
lineChart.setOption({
|
|
|
tooltip: { trigger: 'axis' },
|
|
tooltip: { trigger: 'axis' },
|
|
|
grid: { top: '15%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
grid: { top: '15%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
|
- xAxis: { type: 'category', boundaryGap: false, data: ['1日', '5日', '10日', '15日', '20日', '25日', '30日'] },
|
|
|
|
|
|
|
+ xAxis: { type: 'category', boundaryGap: false, data: data.orderAmountTrend.map((i) => i.date) },
|
|
|
yAxis: { type: 'value' },
|
|
yAxis: { type: 'value' },
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: '订单金额(元)',
|
|
name: '订单金额(元)',
|
|
|
type: 'line',
|
|
type: 'line',
|
|
|
- data: [8200, 9320, 9010, 9340, 12900, 13300, 13200],
|
|
|
|
|
|
|
+ data: data.orderAmountTrend.map((i) => i.value),
|
|
|
smooth: true,
|
|
smooth: true,
|
|
|
areaStyle: {
|
|
areaStyle: {
|
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
@@ -237,12 +259,7 @@ const initCharts = () => {
|
|
|
label: { show: true, fontSize: 16, fontWeight: 'bold' }
|
|
label: { show: true, fontSize: 16, fontWeight: 'bold' }
|
|
|
},
|
|
},
|
|
|
labelLine: { show: false },
|
|
labelLine: { show: false },
|
|
|
- data: [
|
|
|
|
|
- { value: 1048, name: '企业客户' },
|
|
|
|
|
- { value: 735, name: '大客户' },
|
|
|
|
|
- { value: 484, name: '代理商' },
|
|
|
|
|
- { value: 300, name: '其他' }
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ data: data.customerTypeDistribution
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
|
});
|
|
});
|
|
@@ -250,10 +267,8 @@ const initCharts = () => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
- nextTick(() => {
|
|
|
|
|
- initCharts();
|
|
|
|
|
- window.addEventListener('resize', handleResize);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ fetchDashboardData();
|
|
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const handleResize = () => {
|
|
const handleResize = () => {
|
|
@@ -269,56 +284,24 @@ onUnmounted(() => {
|
|
|
pieChart?.dispose();
|
|
pieChart?.dispose();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-// 模拟订单数据
|
|
|
|
|
-const orderList = ref([
|
|
|
|
|
- {
|
|
|
|
|
- orderNo: 'ORD20231001',
|
|
|
|
|
- customer: '张三网络',
|
|
|
|
|
- product: '达伯埃70gA4复印纸5包/箱',
|
|
|
|
|
- amount: '12800',
|
|
|
|
|
- status: '已支付',
|
|
|
|
|
- date: '2023-10-24 10:23:45'
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- orderNo: 'ORD20231002',
|
|
|
|
|
- customer: '李四科技',
|
|
|
|
|
- product: '惠普Q7551A(51A)硒鼓',
|
|
|
|
|
- amount: '4500',
|
|
|
|
|
- status: '待发货',
|
|
|
|
|
- date: '2023-10-24 09:15:30'
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- orderNo: 'ORD20231003',
|
|
|
|
|
- customer: '王五实业',
|
|
|
|
|
- product: '兄弟TN-175M品红色大容量硒鼓',
|
|
|
|
|
- amount: '35000',
|
|
|
|
|
- status: '已完成',
|
|
|
|
|
- date: '2023-10-23 16:40:12'
|
|
|
|
|
- },
|
|
|
|
|
- { orderNo: 'ORD20231004', customer: '赵六电商', product: '佳能IR2545i数码复印机', amount: '899', status: '待支付', date: '2023-10-23 15:20:00' },
|
|
|
|
|
- { orderNo: 'ORD20231005', customer: '钱七餐饮', product: '微信小程序点单系统', amount: '6800', status: '已完成', date: '2023-10-22 11:10:05' },
|
|
|
|
|
- { orderNo: 'ORD20231006', customer: '孙八教育', product: '在线直播课程系统升级', amount: '15000', status: '已支付', date: '2023-10-22 09:05:22' }
|
|
|
|
|
-]);
|
|
|
|
|
-
|
|
|
|
|
-// 模拟商品排行榜数据
|
|
|
|
|
-const productRankings = ref([
|
|
|
|
|
- { name: '达伯埃70gA4复印纸5包/箱', sales: 1250, percentage: 90 },
|
|
|
|
|
- { name: '旗舰70gA4复印纸8包/箱', sales: 980, percentage: 75 },
|
|
|
|
|
- { name: '惠普Q7551A(51A)硒鼓', sales: 856, percentage: 65 },
|
|
|
|
|
- { name: '兄弟TN-175M品红色大容量硒鼓', sales: 420, percentage: 40 },
|
|
|
|
|
- { name: '佳能IR2545i数码复印机', sales: 315, percentage: 30 },
|
|
|
|
|
- { name: '汇金7*70mm钻刀', sales: 258, percentage: 20 }
|
|
|
|
|
-]);
|
|
|
|
|
-
|
|
|
|
|
-// 获取状态对应标签类型
|
|
|
|
|
-const getStatusType = (status: string) => {
|
|
|
|
|
- const map: Record<string, string> = {
|
|
|
|
|
- '已支付': 'primary',
|
|
|
|
|
- '待发货': 'warning',
|
|
|
|
|
- '已完成': 'success',
|
|
|
|
|
- '待支付': 'danger'
|
|
|
|
|
- };
|
|
|
|
|
- return map[status] || ('info' as any);
|
|
|
|
|
|
|
+// 获取首页数据
|
|
|
|
|
+const fetchDashboardData = async () => {
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await customerIndexData();
|
|
|
|
|
+ if (res.data) {
|
|
|
|
|
+ dashboardData.value = res.data;
|
|
|
|
|
+ orderList.value = res.data.latestOrders || [];
|
|
|
|
|
+ productRankings.value = res.data.hotProductRankings || [];
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ initCharts();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取首页数据失败:', error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 排行榜进度条颜色
|
|
// 排行榜进度条颜色
|