backend/src/views/apps/babyhealth/dashborad/index.vue
2026-02-24 10:11:45 +08:00

294 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="statistics-container">
<!-- 第一行宝贝统计 -->
<el-row :gutter="20" class="data-overview">
<el-col :span="8" v-for="item in babyData" :key="item.title">
<el-card shadow="hover" class="data-card">
<div class="card-content">
<div class="icon-box" :style="{ backgroundColor: item.color }">
<i :class="item.icon"></i>
</div>
<div class="text-box">
<div class="title">{{ item.title }}</div>
<div class="value">{{ item.value.toLocaleString() }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 第二行:用户统计 -->
<el-row :gutter="20" class="data-overview" style="margin-top: 20px;">
<el-col :span="8" v-for="item in userData" :key="item.title">
<el-card shadow="hover" class="data-card">
<div class="card-content">
<div class="icon-box" :style="{ backgroundColor: item.color }">
<i :class="item.icon"></i>
</div>
<div class="text-box">
<div class="title">{{ item.title }}</div>
<div class="value">{{ item.value.toLocaleString() }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 图表区域 -->
<el-row :gutter="20" class="charts-row" style="margin-top: 20px;">
<!-- 宝贝增长趋势柱状图 -->
<el-col :span="12">
<el-card shadow="hover" header="宝贝增长趋势">
<div ref="babyChartRef" class="chart-box"></div>
</el-card>
</el-col>
<!-- 用户增长趋势柱状图 -->
<el-col :span="12">
<el-card shadow="hover" header="用户增长趋势">
<div ref="userChartRef" class="chart-box"></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, shallowRef, nextTick } from 'vue';
import * as echarts from 'echarts';
import { getDashborad } from '@/api/babyhealth';
// --- 类型定义 ---
interface SummaryItem {
title: string;
value: number;
icon: string;
color: string;
percentage: number;
isUp: boolean;
}
// --- 响应式数据 ---
const babyChartRef = ref<HTMLElement | null>(null);
const userChartRef = ref<HTMLElement | null>(null);
const babyChartInstance = shallowRef<echarts.ECharts | null>(null);
const userChartInstance = shallowRef<echarts.ECharts | null>(null);
const babyData = ref<SummaryItem[]>([
{ title: '总宝贝数', value: 0, icon: 'fa-solid fa-baby', color: '#67C23A', percentage: 0, isUp: false },
{ title: '男宝宝数', value: 0, icon: 'fa-solid fa-person', color: '#409EFF', percentage: 0, isUp: false },
{ title: '女宝宝数', value: 0, icon: 'fa-solid fa-person-dress', color: '#F56C6C', percentage: 0, isUp: false }
]);
const userData = ref<SummaryItem[]>([
{ title: '总用户数', value: 0, icon: 'fa-solid fa-users', color: '#3973FF', percentage: 0, isUp: false },
{ title: '父亲数', value: 0, icon: 'fa-solid fa-person', color: '#409EFF', percentage: 0, isUp: false },
{ title: '母亲数', value: 0, icon: 'fa-solid fa-person-dress', color: '#F56C6C', percentage: 0, isUp: false }
]);
// 调用总输出接口
async function fetchGetDashborad() {
try {
const res = await getDashborad();
if (res.code === 200 && res.data) {
const { userCounts, babyCounts } = res.data;
// 更新宝贝数据
if (babyCounts) {
babyData.value[0].value = babyCounts.total || 0; // 总宝贝数
babyData.value[1].value = babyCounts.male || 0; // 男宝宝数
babyData.value[2].value = babyCounts.female || 0; // 女宝宝数
// 更新宝贝图表
updateBabyChart(
babyCounts.total || 0,
babyCounts.male || 0,
babyCounts.female || 0
);
}
// 更新用户数据
if (userCounts) {
userData.value[0].value = userCounts.total || 0; // 总用户数
userData.value[1].value = userCounts.father || 0; // 父亲数
userData.value[2].value = userCounts.mother || 0; // 母亲数
// 更新用户图表
updateUserChart(
userCounts.total || 0,
userCounts.father || 0,
userCounts.mother || 0
);
}
}
} catch (error) {
console.error('获取仪表盘数据失败:', error);
}
}
// 初始化宝贝柱状图
const initBabyChart = () => {
if (babyChartRef.value) {
babyChartInstance.value = echarts.init(babyChartRef.value);
babyChartInstance.value.setOption({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
data: ['总宝贝数', '男宝宝数', '女宝宝数'],
axisTick: { alignWithLabel: true }
},
yAxis: { type: 'value' },
series: [
{
name: '数量',
type: 'bar',
barWidth: '60%',
data: [
{ value: 0, itemStyle: { color: '#67C23A' } },
{ value: 0, itemStyle: { color: '#409EFF' } },
{ value: 0, itemStyle: { color: '#F56C6C' } }
]
}
]
});
}
};
// 初始化用户柱状图
const initUserChart = () => {
if (userChartRef.value) {
userChartInstance.value = echarts.init(userChartRef.value);
userChartInstance.value.setOption({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
data: ['总用户数', '父亲数', '母亲数'],
axisTick: { alignWithLabel: true }
},
yAxis: { type: 'value' },
series: [
{
name: '数量',
type: 'bar',
barWidth: '60%',
data: [
{ value: 0, itemStyle: { color: '#3973FF' } },
{ value: 0, itemStyle: { color: '#409EFF' } },
{ value: 0, itemStyle: { color: '#F56C6C' } }
]
}
]
});
}
};
// 更新宝贝柱状图数据
const updateBabyChart = (total: number, male: number, female: number) => {
if (babyChartInstance.value) {
babyChartInstance.value.setOption({
series: [{
data: [
{ value: total, itemStyle: { color: '#67C23A' } },
{ value: male, itemStyle: { color: '#409EFF' } },
{ value: female, itemStyle: { color: '#F56C6C' } }
]
}]
});
}
};
// 更新用户柱状图数据
const updateUserChart = (total: number, father: number, mother: number) => {
if (userChartInstance.value) {
userChartInstance.value.setOption({
series: [{
data: [
{ value: total, itemStyle: { color: '#3973FF' } },
{ value: father, itemStyle: { color: '#409EFF' } },
{ value: mother, itemStyle: { color: '#F56C6C' } }
]
}]
});
}
};
// 生命周期与自适应
const handleResize = () => {
babyChartInstance.value?.resize();
userChartInstance.value?.resize();
};
onMounted(async () => {
initBabyChart();
initUserChart();
// 等待图表初始化完成后再加载数据
await nextTick();
await fetchGetDashborad();
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
babyChartInstance.value?.dispose();
userChartInstance.value?.dispose();
});
</script>
<style lang="less" scoped>
.statistics-container {
padding: 20px;
min-height: 100vh;
}
.data-overview {
margin-bottom: 20px;
}
.data-card {
.card-content {
display: flex;
align-items: center;
.icon-box {
width: 56px;
height: 56px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
color: #fff;
font-size: 24px;
}
}
.text-box {
.title {
font-size: 14px;
color: #909399;
}
.value {
font-size: 24px;
font-weight: bold;
margin: 4px 0;
color: var(--el-text-color-primary);
}
}
}
.charts-row {
margin-top: 20px;
.chart-box {
height: 350px;
width: 100%;
}
}
</style>