fix:完善首页,引入新离线图标

master
wangrunpu 1 day ago
parent 43eaa30810
commit 66fad8c586

@ -2,11 +2,6 @@ import type { RouteRecordStringComponent } from '@vben/types';
import { $t } from '@vben/locales';
const {
version,
// vite inject-metadata 插件注入的全局变量
} = __VBEN_ADMIN_METADATA__ || {};
/**
*
*
@ -42,40 +37,15 @@ const localRoutes: RouteRecordStringComponent[] = [
*/
export const localMenuList: RouteRecordStringComponent[] = [
{
component: 'BasicLayout',
name: 'Home',
path: '/home',
component: '/dashboard/home/index',
meta: {
icon: 'solar:home-broken',
affixTab: true,
title: 'page.dashboard.home',
order: -1,
title: 'page.dashboard.title',
// 不使用基础布局(仅在顶级生效)
noBasicLayout: true,
},
name: 'Dashboard',
path: '/',
redirect: '/home',
children: [
{
name: 'Home',
path: '/home',
component: '/dashboard/home/index',
meta: {
icon: 'solar:home-broken',
affixTab: true,
title: 'page.dashboard.home',
},
},
{
name: 'V5UpdateLog',
path: '/changelog',
component: '/演示使用自行删除/changelog/index',
meta: {
icon: 'lucide:book-open-text',
keepAlive: true,
title: '更新记录',
badge: `当前: ${version}`,
badgeVariants: 'bg-primary',
},
},
],
},
{
component: '/_core/about/index',

@ -1,28 +1,501 @@
<script lang="ts" setup>
// ECharts
import type { EchartsUIType } from '@vben/plugins/echarts';
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { VbenIcon } from '@vben/icons';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Card, Col, Flex, Row } from 'ant-design-vue';
const router = useRouter();
//
const statisticsData = ref([
{
title: '设备数量',
value: 702,
icon: 'solar:bedside-table-2-line-duotone',
color: '#40c9c6',
url: '/device/device',
},
{
title: '传感器数量',
value: 700,
icon: 'solar:box-line-duotone',
color: '#36a3f7',
url: '/device/sensor',
},
{
title: '监测数据',
value: 359_660,
icon: 'solar:course-up-broken',
color: '#34bfa3',
url: '/monitoring-data',
},
{
title: '告警数量',
value: 280_625,
icon: 'bellBingLineDuotone',
color: '#f7883a',
url: '/alarm-list',
},
]);
//
const weatherInfo = ref({
city: '香港',
date: '2025-12-16',
temperature: '17°C / 23°C',
description: '多云',
windDirection: '东',
windSpeed: '23.4 级',
icon: 'solar:sun-linear',
class: 'low-temperature text-2xl',
});
// 使
const usageData = ref({
cpu: 65,
memory: 72,
disk: 45,
});
// ECharts
const cpuChartRef = ref<EchartsUIType>();
const memoryChartRef = ref<EchartsUIType>();
const diskChartRef = ref<EchartsUIType>();
import { Card, Flex } from 'ant-design-vue';
const { renderEcharts: renderCpuChart } = useEcharts(cpuChartRef);
const { renderEcharts: renderMemoryChart } = useEcharts(memoryChartRef);
const { renderEcharts: renderDiskChart } = useEcharts(diskChartRef);
// ECharts
onMounted(() => {
// CPU 使 (Ring Gauge)
renderCpuChart({
series: [
{
type: 'gauge',
startAngle: 90,
endAngle: -270,
pointer: {
show: false,
},
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
borderWidth: 1,
borderColor: '#464646',
},
},
axisLine: {
lineStyle: {
width: 16,
},
},
splitLine: {
show: false,
distance: 0,
length: 10,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
distance: 50,
},
data: [
{
value: usageData.value.cpu,
name: 'CPU',
title: {
offsetCenter: ['0%', '-10%'], //
},
detail: {
valueAnimation: true,
offsetCenter: ['0%', '10%'],
},
},
],
title: {
fontSize: 14,
color: '#666',
},
detail: {
fontSize: 20,
fontWeight: 'bold',
color: '#333',
formatter: '{value}%',
},
},
],
});
// 使 (Ring Gauge)
renderMemoryChart({
series: [
{
type: 'gauge',
startAngle: 90,
endAngle: -270,
pointer: {
show: false,
},
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
borderWidth: 1,
borderColor: '#464646',
},
},
axisLine: {
lineStyle: {
width: 16,
},
},
splitLine: {
show: false,
distance: 0,
length: 10,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
distance: 50,
},
data: [
{
value: usageData.value.memory,
name: '内存',
title: {
offsetCenter: ['0%', '-10%'], //
},
detail: {
valueAnimation: true,
offsetCenter: ['0%', '10%'],
},
},
],
title: {
fontSize: 14,
color: '#666',
},
detail: {
fontSize: 20,
fontWeight: 'bold',
color: '#333',
formatter: '{value}%',
},
},
],
});
// 使 (Ring Gauge)
renderDiskChart({
series: [
{
type: 'gauge',
startAngle: 90,
endAngle: -270,
pointer: {
show: false,
},
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
borderWidth: 1,
borderColor: '#464646',
},
},
axisLine: {
lineStyle: {
width: 16,
},
},
splitLine: {
show: false,
distance: 0,
length: 10,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
distance: 50,
},
data: [
{
value: usageData.value.disk,
name: '磁盘',
title: {
offsetCenter: ['0%', '-10%'], //
},
detail: {
valueAnimation: true,
offsetCenter: ['0%', '10%'],
},
},
],
title: {
fontSize: 14,
color: '#666',
},
detail: {
fontSize: 20,
fontWeight: 'bold',
color: '#333',
formatter: '{value}%',
},
},
],
});
});
//
const handleCardClick = (url?: string) => {
if (url) {
router.push(url);
}
};
</script>
<template>
<Page :auto-content-height="true">
<Flex justify="space-between" align="flex-start">
<Card class="w-full">
<Flex justify="space-between" align="center">
<span> hhh </span>
<VbenIcon icon="solar:home-broken" class="size-8 flex-shrink-0" />
</Flex>
</Card>
<Card class="w-full">
<p>card content</p>
</Card>
<Card class="w-full">
<p>card content</p>
</Card>
<Card class="w-full">
<p>card content</p>
</Card>
</Flex>
<Row :gutter="[20, 20]" class="mb-5">
<!-- 左侧 -->
<Col :span="24" :lg="16">
<!-- 统计数据 -->
<div class="mb-5 grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card
v-for="(item, index) in statisticsData"
:key="index"
class="shadow-md transition-all duration-300 hover:shadow-lg"
:class="{
'cursor-pointer hover:-translate-y-1 hover:scale-105': item.url,
}"
@click="handleCardClick(item.url)"
>
<Flex justify="flex-start" align="center" class="gap-5">
<VbenIcon
:icon="item.icon"
class="size-8 flex-shrink-0"
:style="{ color: item.color }"
/>
<Flex justify="center" :vertical="true">
<span class="text-gray-500">{{ item.title }}</span>
<span class="text-2xl font-medium">{{
item.value.toLocaleString()
}}</span>
</Flex>
</Flex>
</Card>
</div>
<Card title="设备分布地图" class="shadow-md">
<div
class="flex h-96 items-center justify-center rounded bg-gray-100"
>
<span class="text-gray-500">地图展示区域</span>
</div>
</Card>
<!-- 使用率图表 -->
<Card title="系统资源使用率" class="mt-5 shadow-md">
<Row :gutter="20">
<Col :span="8">
<div class="text-center">
<EchartsUI ref="cpuChartRef" height="250px" width="100%" />
<p class="mt-2 font-medium">CPU使用率</p>
</div>
</Col>
<Col :span="8">
<div class="text-center">
<EchartsUI ref="memoryChartRef" height="250px" width="100%" />
<p class="mt-2 font-medium">内存使用率</p>
</div>
</Col>
<Col :span="8">
<div class="text-center">
<EchartsUI ref="diskChartRef" height="250px" width="100%" />
<p class="mt-2 font-medium">磁盘使用率</p>
</div>
</Col>
</Row>
</Card>
</Col>
<!-- 右侧天气信息 -->
<Col :span="24" :lg="8">
<Card
class="weather-card cursor-pointer bg-gradient-to-r from-blue-50 to-indigo-50 shadow-md transition-shadow hover:shadow-lg"
>
<div class="flex flex-col md:flex-row">
<!-- 天气图标区域 -->
<div class="mb-4 flex items-center justify-center md:mb-0 md:w-2/5">
<div class="weather-main">
<VbenIcon :icon="weatherInfo.icon" class="text-6xl" />
</div>
</div>
<!-- 天气信息区域 -->
<div class="md:w-3/5">
<div class="weather-header">
<h2 class="text-2xl font-bold">{{ weatherInfo.city }}</h2>
<div class="date-week text-gray-500">
<span>{{ weatherInfo.date }}</span>
</div>
</div>
<Flex align="center">
<Flex :vertical="true">
<div :class="weatherInfo.class">
{{ weatherInfo.temperature.split(' / ')[0] }}
</div>
</Flex>
<Flex :vertical="true" align="center" class="w-1/2">
<div class="">
{{ weatherInfo.temperature.split(' / ')[1] }}
</div>
<div class="">
{{ weatherInfo.description }}
</div>
</Flex>
</Flex>
<Flex align="center" class="gap-2">
<Flex align="center">
<VbenIcon icon="solar:black-hole-3-linear" />
<span>{{ weatherInfo.windDirection }}</span>
</Flex>
<Flex align="center">
<span>{{ weatherInfo.windSpeed }}</span>
</Flex>
</Flex>
</div>
</div>
</Card>
<!-- 信息栏 -->
<Card title="信息栏" class="mt-5 shadow-md">
<div class="space-y-3">
<div
class="flex items-center justify-between rounded p-2 hover:bg-gray-50"
>
<div>
<span
class="mr-2 rounded bg-orange-100 px-2 py-1 text-xs text-orange-800"
>公告</span
>
<span>涉尘涉爆管理平台V1.0发布</span>
</div>
<span class="text-sm text-gray-400">2025-12-20</span>
</div>
<div
class="flex items-center justify-between rounded p-2 hover:bg-gray-50"
>
<div>
<span
class="mr-2 rounded bg-blue-100 px-2 py-1 text-xs text-blue-800"
>信息</span
>
<span>设备现已支持4G+MQTT</span>
</div>
<span class="text-sm text-gray-400">2021-12-15</span>
</div>
</div>
</Card>
<!-- 设备状态分布 -->
<Card title="设备状态分布" class="mt-5 shadow-md">
<div
class="flex h-80 items-center justify-center rounded bg-gray-100"
>
<span class="text-gray-500">饼图展示区域</span>
</div>
</Card>
</Col>
</Row>
<!-- 第三行图表展示 -->
<Row :gutter="[20, 20]" class="mb-5">
<Col :span="24" :lg="12">
<!-- 移除了设备状态分布卡片 -->
</Col>
</Row>
</Page>
</template>
<style scoped>
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
.card-enter-active,
.card-leave-active {
transition: all 0.3s ease;
}
.card-enter-from,
.card-leave-to {
opacity: 0;
transform: translateY(10px);
}
/* 天气信息卡片样式优化 */
.weather-card {
border-radius: 12px;
transition: all 0.3s ease;
}
.weather-card:hover {
transform: translateY(-5px);
}
.weather-main {
animation: pulse 2s infinite;
}
.low-temperature {
font-size: 1.5rem /* 24px */;
font-weight: 700;
line-height: 2rem /* 32px */;
color: #00a2ff;
text-shadow: 0 2px 4px rgb(59 130 246 / 30%);
}
.high-temperature {
font-size: 1.5rem /* 24px */;
font-weight: 700;
line-height: 2rem /* 32px */;
color: #dd4a68;
text-shadow: 0 2px 4px rgb(239 68 68 / 30%);
}
/* 添加过渡效果 */
</style>

@ -86,7 +86,7 @@ export async function vue(): Promise<Linter.Config[]> {
'vue/dot-location': ['error', 'property'],
'vue/dot-notation': ['error', { allowKeywords: true }],
'vue/eqeqeq': ['error', 'smart'],
'vue/html-closing-bracket-newline': 'error',
'vue/html-closing-bracket-newline': 'warn',
'vue/html-indent': 'off',
// 'vue/html-indent': ['error', 2],
'vue/html-quotes': ['error', 'double'],

@ -47,11 +47,17 @@ import users from '@iconify/icons-ph/users-light';
import insatnceLine from '@iconify/icons-ri/instance-line';
import todoLine from '@iconify/icons-ri/todo-line';
import Authy from '@iconify/icons-simple-icons/authy';
import bedsideTable2LineDuotone from '@iconify/icons-solar/bedside-table-2-line-duotone';
import bellBingLineDuotone from '@iconify/icons-solar/bell-bing-line-duotone';
import blackHole3Linear from '@iconify/icons-solar/black-hole-3-linear';
import boxLineDuotone from '@iconify/icons-solar/box-line-duotone';
import courseUpBroken from '@iconify/icons-solar/course-up-broken';
import FolderWithFilesOutline from '@iconify/icons-solar/folder-with-files-outline';
import homeBroken from '@iconify/icons-solar/home-broken';
import monitorBoldDuotone from '@iconify/icons-solar/monitor-bold-duotone';
import monitorCameraOutlined from '@iconify/icons-solar/monitor-camera-outline';
import monitorPhoneOutlined from '@iconify/icons-solar/monitor-smartphone-outline';
import sunLinear from '@iconify/icons-solar/sun-linear';
import InterfaceLoginDialPadFingerPasswordDialPadDotFinger from '@iconify/icons-streamline/interface-login-dial-pad-finger-password-dial-pad-dot-finger';
import categoryPlus from '@iconify/icons-tabler/category-plus';
import code from '@iconify/icons-tabler/code';
@ -78,6 +84,12 @@ addIcon(
addIcon('solar:folder-with-files-outline', FolderWithFilesOutline);
addIcon('simple-icons:authy', Authy);
addIcon('solar:monitor-smartphone-outline', monitorPhoneOutlined);
addIcon('solar:black-hole-3-linear', blackHole3Linear);
addIcon('solar:sun-linear', sunLinear);
addIcon('solar:bedside-table-2-line-duotone', bedsideTable2LineDuotone);
addIcon('solar:box-line-duotone', boxLineDuotone);
addIcon('solar:course-up-broken', courseUpBroken);
addIcon('solar:bell-bing-line-duotone', bellBingLineDuotone);
addIcon('solar:home-broken', homeBroken);
addIcon('ic:baseline-house', BaseLineHouse);
addIcon('ph:users-light', users);

Loading…
Cancel
Save