移除设备状态相关功能及页面,优化权限管理,提升代码整洁性

This commit is contained in:
yahaozhang
2025-09-16 14:46:28 +08:00
parent cac99b5c1d
commit dace987070
4 changed files with 0 additions and 138 deletions

View File

@@ -43,10 +43,6 @@
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></i> <i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></i>
<span>公告管理</span> <span>公告管理</span>
</el-menu-item> </el-menu-item>
<el-menu-item v-if="canAccessDeviceStatus" index="DeviceStatus" :route="{ name: 'DeviceStatus' }">
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M21 6h-7V4h-4v2H3c-1.1 0-2 .9-2 2v10a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2m0 12H3V8h18v10M8 10h2v6H8v-6m3 0h2v6h-2v-6m3 0h2v6h-2v-6Z"/></svg></i>
<span>设备状态</span>
</el-menu-item>
<el-menu-item v-if="canAccessSettings" index="Settings" :route="{ name: 'Settings' }"> <el-menu-item v-if="canAccessSettings" index="Settings" :route="{ name: 'Settings' }">
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="m12 8l-2 4h4l-2 4"/></svg></i> <i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="m12 8l-2 4h4l-2 4"/></svg></i>
<span>系统设置</span> <span>系统设置</span>
@@ -118,7 +114,6 @@ const pageTitleMap = {
'Links': '链接管理', 'Links': '链接管理',
'Refund': '退单管理', 'Refund': '退单管理',
'Announcements': '公告管理', 'Announcements': '公告管理',
'DeviceStatus': '设备状态',
'Settings': '系统设置' 'Settings': '系统设置'
} }
@@ -135,7 +130,6 @@ const canAccessUsers = computed(() => canAccessRoute('Users'))
const canAccessLinks = computed(() => canAccessRoute('Links')) const canAccessLinks = computed(() => canAccessRoute('Links'))
const canAccessRefund = computed(() => canAccessRoute('Refund')) const canAccessRefund = computed(() => canAccessRoute('Refund'))
const canAccessAnnouncements = computed(() => canAccessRoute('Announcements')) const canAccessAnnouncements = computed(() => canAccessRoute('Announcements'))
const canAccessDeviceStatus = computed(() => canAccessRoute('DeviceStatus'))
const canAccessSettings = computed(() => canAccessRoute('Settings')) const canAccessSettings = computed(() => canAccessRoute('Settings'))
// 获取积分余额 // 获取积分余额

View File

@@ -12,7 +12,6 @@ const AnnouncementList = () => import('@/views/announcements/AnnouncementList.vu
const RefundManagement = () => import('@/views/refund/RefundManagement.vue') const RefundManagement = () => import('@/views/refund/RefundManagement.vue')
const Play = () => import('@/views/Play.vue') const Play = () => import('@/views/Play.vue')
const NotFound = () => import('@/views/NotFound.vue') const NotFound = () => import('@/views/NotFound.vue')
const DeviceStatus = () => import('@/views/devices/DeviceStatus.vue')
export const routes = [ export const routes = [
{ path: '/login', name: 'Login', component: Login, meta: { public: true, title: '登录' } }, { path: '/login', name: 'Login', component: Login, meta: { public: true, title: '登录' } },
@@ -39,7 +38,6 @@ export const routes = [
{ path: 'links', name: 'Links', component: LinkGenerate, meta: { title: '链接管理' } }, { path: 'links', name: 'Links', component: LinkGenerate, meta: { title: '链接管理' } },
{ path: 'refund', name: 'Refund', component: RefundManagement, meta: { title: '退单管理' } }, { path: 'refund', name: 'Refund', component: RefundManagement, meta: { title: '退单管理' } },
{ path: 'announcements', name: 'Announcements', component: AnnouncementList, meta: { title: '公告管理' } }, { path: 'announcements', name: 'Announcements', component: AnnouncementList, meta: { title: '公告管理' } },
{ path: 'devices', name: 'DeviceStatus', component: DeviceStatus, meta: { title: '设备状态' } },
], ],
}, },
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound, meta: { public: true, title: '未找到' } }, { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound, meta: { public: true, title: '未找到' } },

View File

@@ -49,8 +49,6 @@ export const PERMISSIONS = {
REFUND_EXECUTE: 'refund:execute', REFUND_EXECUTE: 'refund:execute',
REFUND_VIEW: 'refund:view', REFUND_VIEW: 'refund:view',
// 设备状态查看
DEVICE_VIEW: 'device:view',
} }
// 角色权限映射 // 角色权限映射
@@ -96,7 +94,6 @@ export const ROUTE_PERMISSIONS = {
'Links': [PERMISSIONS.LINK_VIEW], 'Links': [PERMISSIONS.LINK_VIEW],
'Refund': [PERMISSIONS.REFUND_VIEW], 'Refund': [PERMISSIONS.REFUND_VIEW],
'Announcements': [PERMISSIONS.ANNOUNCEMENT_VIEW], 'Announcements': [PERMISSIONS.ANNOUNCEMENT_VIEW],
'DeviceStatus': [PERMISSIONS.DEVICE_VIEW],
} }
// 获取当前用户信息 // 获取当前用户信息

View File

@@ -1,127 +0,0 @@
<template>
<div class="device-status-view">
<el-card class="header-card">
<template #header>
<div class="header">
<h3 class="title">设备状态</h3>
<div class="actions">
<el-button type="primary" :loading="loading" @click="fetchData">
<el-icon><Refresh /></el-icon>
刷新
</el-button>
<el-switch v-model="autoRefresh" active-text="自动刷新" @change="onToggleAuto" />
</div>
</div>
</template>
<div class="stats">
<el-statistic title="设备总数" :value="stats.totalDevices" />
<el-statistic title="已占用" :value="stats.runningCount" />
<el-statistic title="使用中" :value="stats.usingCount" />
<el-statistic title="冷却空闲" :value="stats.idleCooldownCount" />
<el-statistic title="空闲" :value="stats.idleFreeCount" />
</div>
</el-card>
<el-card class="table-card">
<el-table :data="categoryRows" v-loading="loading" border style="width: 100%">
<el-table-column prop="label" label="类别" width="140" />
<el-table-column prop="count" label="数量" width="100" />
<el-table-column label="设备列表" min-width="300">
<template #default="{ row }">
<div class="devices-list" :title="row.devices.join(', ')">{{ row.preview }}</div>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, computed } from 'vue'
import { Refresh } from '@element-plus/icons-vue'
import { getAllDeviceStatus } from '@/api/devices'
import { isAdmin, canAccessRoute } from '@/utils/permission'
// 仅管理员可访问(路由守卫已做拦截,这里再次防御)
const allowed = computed(() => isAdmin() || canAccessRoute('DeviceStatus'))
const loading = ref(false)
const autoRefresh = ref(true)
const timer = ref(null)
const stats = reactive({ totalDevices: 0, runningCount: 0, usingCount: 0, idleCooldownCount: 0, idleFreeCount: 0 })
const categoryToDevices = ref({})
const categoryOrder = ['RUNNING', 'USING', 'IDLE_COOLDOWN', 'IDLE_FREE']
const categoryLabelMap = { RUNNING: '已占用', USING: '使用中', IDLE_COOLDOWN: '冷却空闲', IDLE_FREE: '空闲' }
const categoryRows = computed(() => {
const map = categoryToDevices.value || {}
return categoryOrder.map(key => {
const devices = Array.isArray(map[key]) ? map[key] : []
const preview = devices.join(', ')
return { key, label: categoryLabelMap[key] || key, count: devices.length, devices, preview }
})
})
async function fetchData() {
if (!allowed.value) return
try {
loading.value = true
const data = await getAllDeviceStatus()
categoryToDevices.value = data?.categoryToDevices || {}
stats.totalDevices = data?.totalDevices ?? 0
stats.runningCount = data?.runningCount ?? (categoryToDevices.value['RUNNING']?.length || 0)
stats.usingCount = data?.usingCount ?? (categoryToDevices.value['USING']?.length || 0)
stats.idleCooldownCount = data?.idleCooldownCount ?? (categoryToDevices.value['IDLE_COOLDOWN']?.length || 0)
stats.idleFreeCount = data?.idleFreeCount ?? (categoryToDevices.value['IDLE_FREE']?.length || 0)
} finally {
loading.value = false
}
}
function onToggleAuto(val) {
if (val) startAuto()
else stopAuto()
}
function startAuto() {
stopAuto()
timer.value = setInterval(fetchData, 2000)
}
function stopAuto() {
if (timer.value) {
clearInterval(timer.value)
timer.value = null
}
}
onMounted(() => {
fetchData()
if (autoRefresh.value) startAuto()
})
onUnmounted(() => {
stopAuto()
})
</script>
<style scoped>
.device-status-view { padding: 0; }
.header-card { margin-bottom: 16px; }
.header { display: flex; align-items: center; justify-content: space-between; }
.title { margin: 0; font-size: 18px; font-weight: 600; }
.actions { display: flex; gap: 12px; align-items: center; }
.stats { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.inline-tag { height: 24px; align-items: center; }
.devices-list { white-space: normal; word-break: break-all; line-height: 1.6; }
@media (max-width: 768px) {
.title { font-size: 20px; }
.actions { gap: 8px; }
.stats { gap: 12px; }
}
</style>