You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
8.1 KiB
Vue

3 months ago
<template>
<div class="app-container home">
<!-- 欢迎区域 -->
<el-card shadow="hover" class="welcome-card mb-4">
<div class="welcome-content">
<div class="welcome-text">
<h2>欢迎使用 RFID 中间件管理系统</h2>
<p>{{ currentTime }}</p>
</div>
</div>
</el-card>
<!-- 快捷入口 -->
<el-row :gutter="16" class="mb-4">
<el-col :xs="12" :sm="12" :md="6">
<el-card shadow="hover" class="shortcut-card" @click="$router.push('/base/rfidDevice')">
<div class="shortcut-inner">
<el-icon :size="36" color="#409eff"><Monitor /></el-icon>
<span>设备管理</span>
</div>
</el-card>
3 months ago
</el-col>
<el-col :xs="12" :sm="12" :md="6">
<el-card shadow="hover" class="shortcut-card" @click="$router.push('/base/rfidLocation')">
<div class="shortcut-inner">
<el-icon :size="36" color="#67c23a"><Location /></el-icon>
<span>位置管理</span>
</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="12" :md="6">
<el-card shadow="hover" class="shortcut-card" @click="$router.push('/base/rfidReadRecord')">
<div class="shortcut-inner">
<el-icon :size="36" color="#e6a23c"><Document /></el-icon>
<span>读取记录</span>
</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="12" :md="6">
<el-card shadow="hover" class="shortcut-card" @click="$router.push('/chart1')">
<div class="shortcut-inner">
<el-icon :size="36" color="#f56c6c"><DataAnalysis /></el-icon>
<span>监控看板</span>
</div>
</el-card>
</el-col>
</el-row>
3 months ago
<!-- 位置统计与列表 -->
<el-row :gutter="16" class="mb-4">
<!-- 位置统计卡片 -->
<el-col :xs="24" :md="8">
<el-card shadow="hover">
<template #header>
<div class="card-header"><span>位置统计</span></div>
</template>
<div class="location-stats">
<div class="stat-item">
<span class="label">位置总数</span>
<span class="value">{{ stats.locationStats?.totalLocations || 0 }}</span>
</div>
<el-divider />
<div class="stat-item">
<span class="label">车间数量</span>
<span class="value text-primary">{{ stats.locationStats?.workshopCount || 0 }}</span>
</div>
<div class="stat-item">
<span class="label">工序数量</span>
<span class="value text-success">{{ stats.locationStats?.processCount || 0 }}</span>
</div>
<div class="stat-item">
<span class="label">工位数量</span>
<span class="value text-warning">{{ stats.locationStats?.stationCount || 0 }}</span>
</div>
</div>
</el-card>
</el-col>
<!-- 顶级位置列表 -->
<el-col :xs="24" :md="16">
<el-card shadow="hover">
<template #header>
<div class="card-header">
<span>车间概览</span>
<el-button type="primary" link @click="$router.push('/base/rfidLocation')"></el-button>
</div>
</template>
<el-table :data="stats.locations || []" border stripe max-height="260" empty-text="">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="locationCode" label="位置编号" min-width="100" />
<el-table-column prop="locationAlias" label="位置名称" min-width="120" />
<el-table-column prop="locationType" label="位置类型" width="100" align="center">
<template #default="{ row }">
<dict-tag :options="location_type" :value="row.locationType" />
</template>
</el-table-column>
<el-table-column prop="childCount" label="子位置数" width="100" align="center" />
</el-table>
</el-card>
3 months ago
</el-col>
</el-row>
<!-- 系统帮助 -->
<el-card shadow="hover">
<template #header>
<div class="card-header"><span>系统使用指南</span></div>
</template>
<el-collapse>
<el-collapse-item title="1. 如何管理位置?" name="1">
<p>进入位置管理模块支持创建车间工序设备三级位置结构便于设备归属管理</p>
</el-collapse-item>
<el-collapse-item title="2. 如何管理设备?" name="2">
<p>进入设备管理模块可新增编辑删除 RFID 读写器设备并关联到指定位置</p>
</el-collapse-item>
<el-collapse-item title="3. 如何查看读取记录?" name="3">
<p>进入读取记录模块可按时间范围设备筛选历史读卡数据</p>
</el-collapse-item>
<el-collapse-item title="4. 如何进入监控看板?" name="4">
<p>点击监控看板快捷入口可实时查看设备状态成功率趋势和告警信息</p>
</el-collapse-item>
</el-collapse>
</el-card>
3 months ago
</div>
</template>
<script setup name="Index" lang="ts">
import { onMounted, ref, getCurrentInstance, toRefs, type ComponentInternalInstance, onUnmounted } from 'vue';
import { getHomeStats, type HomeStatsVO } from '@/api/rfid/statistics';
import { DataAnalysis, Document, Location, Monitor } from '@element-plus/icons-vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { location_type } = toRefs<any>(proxy?.useDict('location_type'));
const stats = ref<Partial<HomeStatsVO>>({});
const currentTime = ref('');
let timer: number | null = null;
const updateTime = () => {
const now = new Date();
currentTime.value = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
};
const loadData = async () => {
try {
const res = await getHomeStats();
stats.value = res.data;
} catch (e) {
console.error('获取首页数据失败', e);
}
};
onMounted(() => {
updateTime();
timer = window.setInterval(updateTime, 1000);
loadData();
});
onUnmounted(() => {
if (timer) clearInterval(timer);
});
3 months ago
</script>
<style lang="scss" scoped>
.home {
padding: 16px;
.mb-4 {
margin-bottom: 16px;
3 months ago
}
// 欢迎卡片
.welcome-card {
background: linear-gradient(135deg, #409eff 0%, #53a8ff 100%);
:deep(.el-card__body) {
padding: 24px 32px;
}
3 months ago
}
.welcome-content {
.welcome-text {
h2 {
color: #fff;
font-size: 22px;
margin: 0 0 8px 0;
}
p {
color: rgba(255, 255, 255, 0.85);
font-size: 14px;
margin: 0;
}
}
3 months ago
}
// 快捷入口卡片
.shortcut-card {
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
:deep(.el-card__body) {
padding: 24px 16px;
}
}
.shortcut-inner {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
span {
font-size: 14px;
font-weight: 500;
color: #303133;
}
}
3 months ago
// 位置统计
.location-stats {
.stat-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
.label {
color: #606266;
font-size: 14px;
}
.value {
font-size: 20px;
font-weight: 600;
color: #303133;
&.text-primary {
color: #409eff;
}
&.text-success {
color: #67c23a;
}
&.text-warning {
color: #e6a23c;
}
}
}
:deep(.el-divider) {
margin: 12px 0;
3 months ago
}
}
// 卡片头部样式
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
span {
font-size: 16px;
font-weight: 600;
color: #303133;
3 months ago
}
}
// 通用卡片内边距
:deep(.el-card__body) {
padding: 16px;
}
3 months ago
}
</style>