2
0
Files
fe.wfc/src/views/dashboard/modules/header-banner.vue
2025-01-21 19:50:28 +08:00

326 lines
12 KiB
Vue

<script setup lang="ts">
import {
EnvironmentOutlined,
SafetyOutlined,
HddOutlined,
GroupOutlined,
UserAddOutlined,
UserSwitchOutlined
} from '@ant-design/icons-vue';
import { computed, ref, onMounted } from 'vue';
import { getDashboardOverview } from '@/service/api/auth';
defineOptions({
name: 'HeaderBanner'
});
const overviewData = ref<Api.DashboardOverview>({
cloud: { connected: false },
siteNum: 0,
totalGatewayNum: 0,
connectedGatewayNum: 0,
disconnectedGatewayNum: 0,
totalSwitchNum: 0,
connectedSwitchNum: 0,
disconnectedSwitchNum: 0,
totalApNum: 0,
connectedApNum: 0,
disconnectedApNum: 0,
isolatedApNum: 0,
totalClientNum: 0,
wiredClientNum: 0,
wirelessClientNum: 0,
guestNum: 0,
registerUserNum: 0,
onlineUserNum: 0
});
const fetchOverviewData = async () => {
try {
const { data } = await getDashboardOverview();
console.log('Raw API response:', data);
if (data) {
overviewData.value = {
cloud: { connected: data.cloud?.connected ?? false },
siteNum: data.siteNum ?? 0,
totalGatewayNum: data.totalGatewayNum ?? 0,
connectedGatewayNum: data.connectedGatewayNum ?? 0,
disconnectedGatewayNum: data.disconnectedGatewayNum ?? 0,
totalSwitchNum: data.totalSwitchNum ?? 0,
connectedSwitchNum: data.connectedSwitchNum ?? 0,
disconnectedSwitchNum: data.disconnectedSwitchNum ?? 0,
totalApNum: data.totalApNum ?? 0,
connectedApNum: data.connectedApNum ?? 0,
disconnectedApNum: data.disconnectedApNum ?? 0,
isolatedApNum: data.isolatedApNum ?? 0,
totalClientNum: data.totalClientNum ?? 0,
wiredClientNum: data.wiredClientNum ?? 0,
wirelessClientNum: data.wirelessClientNum ?? 0,
guestNum: data.guestNum ?? 0,
registerUserNum: data.registerUserNum ?? 0,
onlineUserNum: data.onlineUserNum ?? 0
};
console.log('Processed overviewData:', overviewData.value);
console.log('AP Connected Count:', overviewData.value.connectedApNum);
}
} catch (error) {
console.error('Failed to fetch overview data:', error);
}
};
onMounted(() => {
fetchOverviewData();
});
const deviceStatus = computed(() => {
const status = {
ap: {
connected: Number(overviewData.value.connectedApNum) || 0,
disconnected: Number(overviewData.value.disconnectedApNum) || 0,
isolated: Number(overviewData.value.isolatedApNum) || 0
},
client: {
wiredUsers: Number(overviewData.value.wiredClientNum) || 0,
wirelessUsers: Number(overviewData.value.wirelessClientNum) || 0,
wirelessGuests: Number(overviewData.value.guestNum) || 0
},
users: {
registered: Number(overviewData.value.registerUserNum) || 0,
online: Number(overviewData.value.onlineUserNum) || 0
},
alerts: 0
};
console.log('Computed deviceStatus:', status);
return status;
});
const siteInfo = computed(() => ({
total: Number(overviewData.value.siteNum) || 0
}));
const otherDevices = computed(() => ({
gateways: {
total: Number(overviewData.value.totalGatewayNum) || 0,
connected: Number(overviewData.value.connectedGatewayNum) || 0,
disconnected: Number(overviewData.value.disconnectedGatewayNum) || 0
},
switches: {
total: Number(overviewData.value.totalSwitchNum) || 0,
connected: Number(overviewData.value.connectedSwitchNum) || 0,
disconnected: Number(overviewData.value.disconnectedSwitchNum) || 0
},
olts: {
total: 0,
connected: 0,
disconnected: 0
}
}));
</script>
<template>
<ACard :bordered="false" class="card-wrapper">
<div class="text-16px font-bold mb-4px">Controller Overview</div>
<ARow :gutter="[16, 16]">
<ACol :span="24">
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-8px">
<!-- Connected Status -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-blue-50 rounded-lg">
<icon-mdi-cloud class="text-primary text-24px" />
</div>
<div class="text-16px font-medium">Connected</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="text-12px text-gray-500">
Cloud Access
</div>
</div>
<!-- Sites -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-gray-100 rounded-lg relative">
<environment-outlined class="text-24px text-primary" />
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ siteInfo.total }}</span>
</div>
<div class="text-16px font-medium">Sites</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Total Sites: {{ siteInfo.total }}</span>
</div>
</div>
<!-- Gateways -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-gray-100 rounded-lg relative">
<safety-outlined class="text-24px text-primary" />
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ otherDevices.gateways.connected + otherDevices.gateways.disconnected }}</span>
</div>
<div class="text-16px font-medium">Gateways</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Connected: {{ otherDevices.gateways.connected }}</span>
<span>Disconnected: {{ otherDevices.gateways.disconnected }}</span>
</div>
</div>
<!-- Switches -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-gray-100 rounded-lg relative">
<hdd-outlined class="text-24px text-primary" />
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ otherDevices.switches.connected + otherDevices.switches.disconnected }}</span>
</div>
<div class="text-16px font-medium">Switches</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Connected: {{ otherDevices.switches.connected }}</span>
<span>Disconnected: {{ otherDevices.switches.disconnected }}</span>
</div>
</div>
<!-- OLTs -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-gray-100 rounded-lg relative">
<group-outlined class="text-24px text-primary" />
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ otherDevices.olts.total }}</span>
</div>
<div class="text-16px font-medium">OLTs</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Connected: {{ otherDevices.olts.connected }}</span>
<span>Disconnected: {{ otherDevices.olts.disconnected }}</span>
</div>
</div>
<!-- Register Users -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-blue-50 rounded-lg">
<user-add-outlined class="text-primary text-24px" />
</div>
<div class="text-16px font-medium">Register Users</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Register: {{ deviceStatus.users.registered }}</span>
</div>
</div>
<!-- Online Users -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-green-50 rounded-lg">
<user-switch-outlined class="text-primary text-24px" />
</div>
<div class="text-16px font-medium">Online Users</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Online: {{ deviceStatus.users.online }}</span>
</div>
</div>
<!-- AP Status -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-green-50 rounded-lg relative">
<icon-mdi-access-point class="text-primary text-24px" />
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">
{{ overviewData.totalApNum }}
</span>
</div>
<div class="text-16px font-medium">AP</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Connected: {{ deviceStatus.ap.connected }}</span>
<span>Disconnected: {{ deviceStatus.ap.disconnected }}</span>
<span>Isolated: {{ deviceStatus.ap.isolated }}</span>
</div>
</div>
<!-- Client Status -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-purple-50 rounded-lg relative">
<icon-mdi-laptop class="text-primary text-24px" />
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">
{{ overviewData.totalClientNum }}
</span>
</div>
<div class="text-16px font-medium">Client</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Wired client: {{ deviceStatus.client.wiredUsers }}</span>
<span>Wireless client: {{ deviceStatus.client.wirelessUsers }}</span>
<span>Wireless Guests: {{ deviceStatus.client.wirelessGuests }}</span>
</div>
</div>
<!-- Alerts -->
<div class="flex flex-col p-6px">
<div class="flex items-center gap-6px mb-6px">
<div class="size-48px flex-center bg-yellow-50 rounded-lg">
<icon-mdi-alert class="text-warning text-24px" />
</div>
<div class="text-16px font-medium">Alerts</div>
</div>
<div class="border-t border-gray-100 my-4px"></div>
<div class="flex flex-col text-12px text-gray-500">
<span>Alerts: {{ deviceStatus.alerts || 0 }}</span>
</div>
</div>
</div>
</ACol>
</ARow>
</ACard>
</template>
<style scoped>
.card-wrapper {
margin-bottom: 16px;
padding: 12px;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.size-48px {
width: 48px;
height: 48px;
position: relative;
}
.flex-col > span {
line-height: 1.5;
}
.bg-gray-50 {
background-color: #fafafa;
}
.p-6px {
padding: 6px;
}
.mt-8px {
margin-top: 8px;
}
.mb-6px {
margin-bottom: 6px;
}
</style>