Files
nonye/platform/src/components/dashboard/StatCards.vue
jrhlh bd1fc93771
Some checks failed
CI / build (push) Has been cancelled
1
2025-07-18 18:49:59 +08:00

183 lines
4.4 KiB
Vue

<template>
<div class="stat-cards-container">
<div class="stat-cards">
<StatCardItem
icon="user"
:iconComp="User"
:value="totalUsers"
trend="up"
trendValue="+10%"
label="总注册员工数"
desc="今日新增 1 人"
:progress="82"
iconColor="#667eea"
progressColor="#667eea"
/>
<StatCardItem
icon="device"
:iconComp="Server"
:value="totalDevicesCount"
trend="up"
trendValue="+2.1%"
label="总设备数"
desc="同比增长"
:progress="65"
iconColor="#764ba2"
progressColor="#764ba2"
/>
<StatCardItem
icon="temp"
:iconComp="Thermometer"
:value="29"
trend="up"
trendValue="+1.3%"
label="当前温度值"
desc="较昨日上升"
:progress="48"
iconColor="#f093fb"
progressColor="#f093fb"
/>
<StatCardItem
icon="fault"
:iconComp="AlertTriangle"
:value="repairDevicesCount - 1 "
trend="up"
trendValue="+0.7%"
label="故障设备总数"
desc="需重点关注"
:progress="22"
iconColor="#ff4d4f"
progressColor="#ff4d4f"
danger
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import axios from 'axios';
import { User, Server, Thermometer, AlertTriangle } from 'lucide-vue-next';
import StatCardItem from './StatCardItem.vue';
// 总用户数
const totalUsers = ref(0);
const apiUrl = import.meta.env.VITE_API_BASE_URL // 动态获取API基础URL
// 设备相关
const devices = ref([]);
const totalDevicesCount = computed(() => devices.value?.length || 0); // 计算设备总数
// 温度相关
const currentTemperature = ref('27.5'); // 默认值
const isTemperatureLoading = ref(true);
// 故障设备数
const repairDevicesCount = ref(0); // 初始化为0
// 获取用户总数
const fetchTotalUsers = async () => {
try {
const response = await axios.get(`${apiUrl}/personnel/users`);
totalUsers.value = response.data.data.length;
} catch (error) {
console.error('获取用户总数失败:', error);
totalUsers.value = 0;
}
};
// 获取设备列表
const fetchDevices = async () => {
try {
const response = await axios.get(`${apiUrl}/api/device/list`);
if (response.data.success) {
devices.value = response.data.data;
}
} catch (error) {
console.error('获取设备列表失败:', error);
}
};
// 获取温度数据
const fetchDeviceATemperature = async () => {
try {
isTemperatureLoading.value = true;
const response = await axios.get(`${apiUrl}/temperature/daily/average`, {
params: { deviceId: 1, date: '2025-05-27' }
});
if (response.data.code === 200) {
const avgTemp = response.data.data.temperatures?.[0];
currentTemperature.value = avgTemp ? `${avgTemp.toFixed(1)}°C` : '无数据';
} else {
currentTemperature.value = '数据获取失败';
}
} catch (error) {
console.error('获取温度数据失败:', error);
currentTemperature.value = '网络错误';
} finally {
isTemperatureLoading.value = false;
}
};
// 获取故障设备数
const fetchRepairDevicesCount = async () => { `${apiUrl}/dashboard`
try {
const response = await axios.get(`${apiUrl}/dashboard`);
repairDevicesCount.value = response.data.todayFaults || 0;
} catch (error) {
console.error('获取维修设备数失败:', error);
repairDevicesCount.value = 0;
}
};
// 初始化数据
onMounted(async () => {
await Promise.all([
fetchTotalUsers(),
fetchDevices(),
fetchDeviceATemperature(),
fetchRepairDevicesCount()
]);
});
</script>
<style scoped>
.stat-cards-container {
width: 100%;
}
.stat-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
width: 100%;
}
/* 响应式设计 */
@media (max-width: 1400px) {
.stat-cards {
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 20px;
}
}
@media (max-width: 1200px) {
.stat-cards {
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
}
@media (max-width: 768px) {
.stat-cards {
grid-template-columns: 1fr;
gap: 16px;
}
}
@media (max-width: 480px) {
.stat-cards {
gap: 12px;
}
}
</style>