✨ feat: 可视化大屏完善
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<!-- 图表容器(含滚动) -->
|
||||
<div class="charts-container">
|
||||
<!-- Element 布局:el-row 为行容器,gutter 控制间距 -->
|
||||
<!-- Element 布局:行容器(不变) -->
|
||||
<el-row
|
||||
class="charts-row"
|
||||
:gutter="20"
|
||||
:style="{ height: `calc(100% - 40px)` }"
|
||||
>
|
||||
<!-- 动态渲染图表:遍历持久化后的配置数组 -->
|
||||
<!-- 动态渲染图表:应用高度配置(核心修改) -->
|
||||
<el-col
|
||||
v-for="(chartConfig, index) in persistedChartConfigs"
|
||||
:key="chartConfig.id"
|
||||
@@ -17,14 +17,15 @@
|
||||
:md="chartConfig.layout.md"
|
||||
:lg="chartConfig.layout.lg"
|
||||
:xl="chartConfig.layout.xl"
|
||||
:style="{ height: `calc(${100 / Math.ceil(persistedChartConfigs.length / 2)}% - 10px)` }"
|
||||
:style="{ height: `${chartConfig.height || 400}px`, marginBottom: '20px' }"
|
||||
>
|
||||
<!-- 动态加载图表组件 -->
|
||||
<!-- 动态加载图表组件:确保组件高度100% -->
|
||||
<component
|
||||
:is="chartComponentMap[chartConfig.componentName]"
|
||||
class="chart-item"
|
||||
v-bind="getChartProps(chartConfig)"
|
||||
:is-refreshing="isRefreshing"
|
||||
:chart-height="chartConfig.height || 400"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -32,150 +33,118 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useStorage } from '@vueuse/core'; // 导入持久化工具
|
||||
import { ElRow, ElCol } from 'element-plus'; // 导入Element布局组件
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { ElRow, ElCol } from 'element-plus';
|
||||
|
||||
// 1. 导入所有图表子组件
|
||||
// 1. 导入所有图表子组件(不变)
|
||||
import OrderTrendChart from '../components/OrderTrendChart.vue';
|
||||
import ProductSalesRank from '../components/ProductSalesRank.vue';
|
||||
import CustomerFollowStatus from '../components/CustomerFollowStatus.vue';
|
||||
import ReturnExchangeAnalysis from '../components/ReturnExchangeAnalysis.vue';
|
||||
import SalesByManagerChart from '../components/SalesByManagerChart.vue';
|
||||
import SalesByCustomerChart from '../components/SalesByCustomerChart.vue';
|
||||
import SalesMetricsCard from '../components/SalesMetricsCard.vue';
|
||||
import RecentOrdersTable from '../components/RecentOrdersTable.vue';
|
||||
|
||||
// 2. 图表组件映射表:用于动态匹配组件(组件名 → 组件实例)
|
||||
// 2. 图表组件映射表(不变)
|
||||
const chartComponentMap = {
|
||||
OrderTrendChart,
|
||||
ProductSalesRank,
|
||||
CustomerFollowStatus,
|
||||
ReturnExchangeAnalysis,
|
||||
SalesByManagerChart,
|
||||
SalesByCustomerChart
|
||||
SalesByCustomerChart,
|
||||
SalesMetricsCard,
|
||||
RecentOrdersTable
|
||||
};
|
||||
|
||||
// 3. 图表默认配置数组:定义每个图表的基础信息、布局、数据源
|
||||
// 3. 图表默认配置数组:新增height默认值(核心修改)
|
||||
const DEFAULT_CHART_CONFIGS = [
|
||||
{
|
||||
id: 'order-trend', // 唯一标识(不可重复)
|
||||
componentName: 'OrderTrendChart', // 对应组件名(与chartComponentMap匹配)
|
||||
title: '订单趋势图表', // 图表标题(可用于组件内部或表头)
|
||||
dataKey: 'orders', // 数据源key(对应props中的数据字段)
|
||||
layout: { // Element Col 布局配置(span范围:1-24,24为整行)
|
||||
xs: 24, // 超小屏:独占1行
|
||||
sm: 24, // 小屏:独占1行
|
||||
md: 12, // 中屏:占1/2行
|
||||
lg: 12, // 大屏:占1/2行
|
||||
xl: 12 // 超大屏:占1/2行
|
||||
}
|
||||
id: 'order-trend',
|
||||
componentName: 'OrderTrendChart',
|
||||
title: '订单趋势图表',
|
||||
dataKey: 'orders',
|
||||
height: 400, // 新增:默认高度400px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'product-rank',
|
||||
componentName: 'ProductSalesRank',
|
||||
title: '产品销售排行图表',
|
||||
dataKey: 'orderDetails', // 依赖orderDetails数据
|
||||
layout: {
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 12
|
||||
}
|
||||
dataKey: 'orderDetails',
|
||||
height: 400, // 新增:默认高度400px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'sales-manager',
|
||||
componentName: 'SalesByManagerChart',
|
||||
title: '负责人订单汇总',
|
||||
dataKey: 'orders', // 依赖orders数据
|
||||
layout: {
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 12
|
||||
}
|
||||
dataKey: 'orders',
|
||||
height: 400, // 新增:默认高度400px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'customer-follow',
|
||||
componentName: 'CustomerFollowStatus',
|
||||
title: '客户跟进状态图表',
|
||||
dataKey: 'customers', // 依赖customers数据
|
||||
layout: {
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 12
|
||||
}
|
||||
dataKey: 'customers',
|
||||
height: 400, // 新增:默认高度400px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'return-exchange',
|
||||
componentName: 'ReturnExchangeAnalysis',
|
||||
title: '退换货分析图表',
|
||||
dataKey: 'returnExchanges', // 依赖returnExchanges数据
|
||||
layout: {
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 12
|
||||
}
|
||||
dataKey: 'returnExchanges',
|
||||
height: 400, // 新增:默认高度400px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'sales-customer',
|
||||
componentName: 'SalesByCustomerChart',
|
||||
title: '客户订单汇总',
|
||||
dataKey: 'orders', // 依赖orders数据
|
||||
layout: {
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 12,
|
||||
lg: 12,
|
||||
xl: 12
|
||||
}
|
||||
dataKey: 'orders',
|
||||
height: 400, // 新增:默认高度400px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'sales-metrics',
|
||||
componentName: 'SalesMetricsCard',
|
||||
title: '销售指标图表',
|
||||
dataKey: ['orders', 'customers', 'returnExchanges'],
|
||||
height: 200, // 新增:指标卡高度较小,默认200px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
},
|
||||
{
|
||||
id: 'recent-orders',
|
||||
componentName: 'RecentOrdersTable',
|
||||
title: '最近订单',
|
||||
dataKey: 'orders',
|
||||
height: 500, // 新增:表格高度较大,默认500px
|
||||
layout: { xs:24, sm:24, md:12, lg:12, xl:12 }
|
||||
}
|
||||
];
|
||||
|
||||
// 4. 持久化图表配置:用useStorage存入localStorage,key为"saleDashboardChartConfigs"
|
||||
// 逻辑:优先读取localStorage中的配置,若无则使用默认配置
|
||||
// 4. 持久化图表配置(不变,但默认值包含height)
|
||||
const persistedChartConfigs = useStorage(
|
||||
'saleDashboardChartConfigs', // 存储key(自定义,确保唯一)
|
||||
DEFAULT_CHART_CONFIGS, // 默认值
|
||||
localStorage, // 存储介质(localStorage/sessionStorage)
|
||||
{ mergeDefaults: true } // 合并默认值与存储值(避免字段缺失)
|
||||
'saleDashboardChartConfigs',
|
||||
DEFAULT_CHART_CONFIGS,
|
||||
localStorage,
|
||||
{ mergeDefaults: true }
|
||||
);
|
||||
|
||||
// 5. 接收父组件传入的数据源与状态
|
||||
// 5. 接收父组件传入的数据源与状态(不变)
|
||||
const props = defineProps({
|
||||
orders: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
orderDetails: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
customers: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
returnExchanges: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
isRefreshing: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false
|
||||
}
|
||||
orders: { type: Array, required: true, default: () => [] },
|
||||
orderDetails: { type: Array, required: true, default: () => [] },
|
||||
customers: { type: Array, required: true, default: () => [] },
|
||||
returnExchanges: { type: Array, required: true, default: () => [] },
|
||||
isRefreshing: { type: Boolean, required: true, default: false }
|
||||
});
|
||||
|
||||
// 6. 工具函数:根据图表配置,动态生成组件所需的props
|
||||
// 6. 工具函数:传递props(不变)
|
||||
const getChartProps = (chartConfig) => {
|
||||
// 映射数据源:根据chartConfig.dataKey匹配props中的数据
|
||||
const dataMap = {
|
||||
orders: props.orders,
|
||||
orderDetails: props.orderDetails,
|
||||
@@ -183,45 +152,50 @@ const getChartProps = (chartConfig) => {
|
||||
returnExchanges: props.returnExchanges
|
||||
};
|
||||
|
||||
// 返回该图表需要的props(如OrderTrendChart需要:orders,ProductSalesRank需要:order-details)
|
||||
if (Array.isArray(chartConfig.dataKey)) {
|
||||
const o = { title: chartConfig.title };
|
||||
chartConfig.dataKey.forEach(key => {
|
||||
o[key.replace(/([A-Z])/g, '-$1').toLowerCase()] = dataMap[key];
|
||||
});
|
||||
return o;
|
||||
}
|
||||
return {
|
||||
// 驼峰转连字符(如orderDetails → order-details,匹配组件props定义)
|
||||
[chartConfig.dataKey.replace(/([A-Z])/g, '-$1').toLowerCase()]: dataMap[chartConfig.dataKey],
|
||||
title: chartConfig.title // 可选:传递标题给图表组件
|
||||
title: chartConfig.title
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 图表容器(含滚动) */
|
||||
/* 图表容器(不变) */
|
||||
.charts-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
background-color: #0f172a; /* 继承父组件深色背景 */
|
||||
background-color: #0f172a;
|
||||
}
|
||||
|
||||
/* Element Row 容器:清除默认margin,确保高度自适应 */
|
||||
/* 行容器(不变) */
|
||||
.charts-row {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start; /* 顶部对齐,避免空白 */
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
/* Element Col 容器:控制列的高度与间距 */
|
||||
/* 列容器:移除固定高度,由配置动态控制(核心修改) */
|
||||
.chart-col {
|
||||
margin-bottom: 20px; /* 行间距,与gutter配合 */
|
||||
box-sizing: border-box;
|
||||
/* 高度由父组件style动态设置,此处不固定 */
|
||||
}
|
||||
|
||||
/* 图表项样式:保持原有设计,适配弹性布局 */
|
||||
/* 图表项:100%高度继承列容器(核心修改) */
|
||||
.chart-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 100%; /* 关键:让组件填满列容器高度 */
|
||||
background-color: #1e293b;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
@@ -231,7 +205,7 @@ const getChartProps = (chartConfig) => {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 小屏幕下优化:减少内边距 */
|
||||
/* 小屏幕优化(不变) */
|
||||
@media (max-width: 768px) {
|
||||
.charts-container {
|
||||
padding: 10px;
|
||||
@@ -239,8 +213,5 @@ const getChartProps = (chartConfig) => {
|
||||
.chart-item {
|
||||
padding: 12px;
|
||||
}
|
||||
.chart-col {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user