✨ feat: 首页指标卡
This commit is contained in:
9
gear-ui3/src/api/oa/dashboard.js
Normal file
9
gear-ui3/src/api/oa/dashboard.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询首页概览数据
|
||||||
|
export function overview() {
|
||||||
|
return request({
|
||||||
|
url: '/oa/dashboard/overview',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
204
gear-ui3/src/views/components/Statistic.vue
Normal file
204
gear-ui3/src/views/components/Statistic.vue
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dashboard-cards">
|
||||||
|
<el-card v-for="(card, index) in dataCards" :key="index" class="stats-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-info">
|
||||||
|
<h3 class="card-title">{{ card.title }}</h3>
|
||||||
|
<!-- 第三个卡片不显示value -->
|
||||||
|
<p class="card-value">{{ card.value }}</p>
|
||||||
|
</div>
|
||||||
|
<el-icon class="card-icon" :style="{ color: card.color }">
|
||||||
|
<component :is="card.icon" />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<!-- 第四个卡片不显示图表 -->
|
||||||
|
<div class="chart-container" v-if="index !== 3">
|
||||||
|
<div :ref="el => chartRefs[index] = el" class="chart"></div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ShoppingCart, Box, List, Monitor } from '@element-plus/icons-vue';
|
||||||
|
import { overview } from '@/api/oa/dashboard';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { ref, onMounted, nextTick } from 'vue';
|
||||||
|
|
||||||
|
const getColor = (index, alpha = 1) => {
|
||||||
|
const colors = [
|
||||||
|
`rgba(59, 130, 246, ${alpha})`,
|
||||||
|
`rgba(34, 197, 94, ${alpha})`,
|
||||||
|
`rgba(234, 179, 8, ${alpha})`,
|
||||||
|
`rgba(168, 85, 247, ${alpha})`
|
||||||
|
];
|
||||||
|
return colors[index % colors.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
const initCharts = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
// 只初始化前3个卡片的图表
|
||||||
|
dataCards.value.slice(0, 3).forEach((card, index) => {
|
||||||
|
const chart = echarts.init(chartRefs.value[index]);
|
||||||
|
// 判断是否为第三个图表(index=2),使用柱状图配置
|
||||||
|
const isBarChart = index === 2;
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
animation: false,
|
||||||
|
grid: {
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
data: card.chartData,
|
||||||
|
type: isBarChart ? 'bar' : 'line', // 第三个图表用柱状图,其他用折线图
|
||||||
|
smooth: !isBarChart, // 柱状图不需要平滑效果
|
||||||
|
showSymbol: false,
|
||||||
|
lineStyle: !isBarChart ? { // 折线图样式(柱状图不需要)
|
||||||
|
color: getColor(index)
|
||||||
|
} : undefined,
|
||||||
|
// 柱状图颜色配置
|
||||||
|
itemStyle: isBarChart ? {
|
||||||
|
color: getColor(index)
|
||||||
|
} : undefined,
|
||||||
|
// 折线图区域填充(柱状图不需要)
|
||||||
|
areaStyle: !isBarChart ? {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||||
|
offset: 0,
|
||||||
|
color: getColor(index, 0.2)
|
||||||
|
}, {
|
||||||
|
offset: 1,
|
||||||
|
color: getColor(index, 0.1)
|
||||||
|
}])
|
||||||
|
} : undefined
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
chart.setOption(option);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const dataCards = ref([
|
||||||
|
{
|
||||||
|
title: '本周订单总量',
|
||||||
|
value: '2,384',
|
||||||
|
icon: ShoppingCart,
|
||||||
|
color: '#3B82F6', // blue-500
|
||||||
|
chartData: [30, 40, 20, 50, 40, 60, 70]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '本周薪资成本',
|
||||||
|
value: '48',
|
||||||
|
icon: List,
|
||||||
|
color: '#F59E0B', // yellow-500
|
||||||
|
chartData: [20, 40, 30, 50, 40, 60, 50]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '库存排行',
|
||||||
|
// 第三个卡片不需要value
|
||||||
|
value: '-',
|
||||||
|
icon: Box,
|
||||||
|
color: '#10B981', // green-500
|
||||||
|
chartData: [40, 30, 50, 40, 60, 50, 70]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '系统状态',
|
||||||
|
value: '正常',
|
||||||
|
icon: Monitor,
|
||||||
|
color: '#8B5CF6', // purple-500
|
||||||
|
// 第四个卡片不需要图表数据
|
||||||
|
chartData: []
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const chartRefs = ref([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
overview().then(res => {
|
||||||
|
dataCards.value[0].value = res.data.orderStatistics.weekOrderCount;
|
||||||
|
dataCards.value[0].chartData = res.data.orderStatistics.weeklyTrend.map(item => item.value);
|
||||||
|
|
||||||
|
dataCards.value[1].value = res.data.salaryStatistics.weekSalary;
|
||||||
|
dataCards.value[1].chartData = res.data.salaryStatistics.weeklyTrend.map(item => item.value);
|
||||||
|
|
||||||
|
// 处理库存排行数据
|
||||||
|
dataCards.value[2].chartData = res.data.stockRanking.map(item => item.quantity);
|
||||||
|
|
||||||
|
initCharts();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.dashboard-cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-card {
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
transform: scale(1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-info {
|
||||||
|
// 用于包裹标题和值
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
color: #6B7280; // gray-500
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-value {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 3rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第四个卡片没有图表,调整一下底部边距
|
||||||
|
.stats-card:nth-child(4) .card-header {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
<!-- 第一行:头像+欢迎语 -->
|
<!-- 第一行:头像+欢迎语 -->
|
||||||
<UserGreeting />
|
<UserGreeting />
|
||||||
|
|
||||||
|
<Statistic />
|
||||||
|
|
||||||
<!-- 全部应用 -->
|
<!-- 全部应用 -->
|
||||||
<AllApplications @addFavorites="handleAddFavorites" />
|
<AllApplications @addFavorites="handleAddFavorites" />
|
||||||
</div>
|
</div>
|
||||||
@@ -11,6 +13,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import AllApplications from '@/components/AllApplications.vue';
|
import AllApplications from '@/components/AllApplications.vue';
|
||||||
import UserGreeting from '@/views/components/Hello.vue';
|
import UserGreeting from '@/views/components/Hello.vue';
|
||||||
|
import Statistic from '@/views/components/Statistic.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user