feat: 初始化项目基础架构和核心功能

- 添加项目基础结构:Cargo.toml、.gitignore、设备UID和密钥文件
- 实现前端Vue3项目结构:路由、登录页面、设备管理页面
- 添加核心协议定义(crates/protocol):设备状态、资产、USB事件等
- 实现客户端监控模块:系统状态收集、资产收集
- 实现服务端基础API和插件系统
- 添加数据库迁移脚本:设备管理、资产跟踪、告警系统等
- 实现前端设备状态展示和基本交互
- 添加使用时长统计和水印功能插件
This commit is contained in:
iven
2026-04-05 00:57:51 +08:00
commit fd6fb5cca0
87 changed files with 19576 additions and 0 deletions

189
web/src/views/Layout.vue Normal file
View File

@@ -0,0 +1,189 @@
<template>
<el-container class="app-container">
<el-aside width="220px" class="sidebar">
<div class="logo">
<h2>CSM</h2>
<span>终端管理系统</span>
</div>
<el-menu
:default-active="currentRoute"
router
background-color="#1d1e2c"
text-color="#a0a3bd"
active-text-color="#409eff"
>
<el-menu-item index="/dashboard">
<el-icon><Monitor /></el-icon>
<span>仪表盘</span>
</el-menu-item>
<el-menu-item index="/devices">
<el-icon><Platform /></el-icon>
<span>设备管理</span>
</el-menu-item>
<el-menu-item index="/assets">
<el-icon><Box /></el-icon>
<span>资产管理</span>
</el-menu-item>
<el-menu-item index="/usb">
<el-icon><Connection /></el-icon>
<span>U盘管控</span>
</el-menu-item>
<el-menu-item index="/alerts">
<el-icon><Bell /></el-icon>
<span>告警中心</span>
</el-menu-item>
<el-sub-menu index="plugins">
<template #title>
<el-icon><Grid /></el-icon>
<span>安全插件</span>
</template>
<el-menu-item index="/plugins/web-filter">上网拦截</el-menu-item>
<el-menu-item index="/plugins/usage-timer">时长记录</el-menu-item>
<el-menu-item index="/plugins/software-blocker">软件管控</el-menu-item>
<el-menu-item index="/plugins/popup-blocker">弹窗拦截</el-menu-item>
<el-menu-item index="/plugins/usb-file-audit">U盘审计</el-menu-item>
<el-menu-item index="/plugins/watermark">水印管理</el-menu-item>
</el-sub-menu>
<el-menu-item index="/settings">
<el-icon><Setting /></el-icon>
<span>系统设置</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<el-header class="app-header">
<div class="header-left">
<span class="page-title">{{ pageTitle }}</span>
</div>
<div class="header-right">
<el-badge :value="unreadAlerts" :hidden="unreadAlerts === 0">
<el-icon :size="20"><Bell /></el-icon>
</el-badge>
<el-dropdown>
<span class="user-info">
{{ username }} <el-icon><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleLogout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
import { computed, ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
Monitor, Platform, Box, Connection, Bell, Setting, ArrowDown, Grid
} from '@element-plus/icons-vue'
import { api } from '@/lib/api'
const route = useRoute()
const router = useRouter()
const currentRoute = computed(() => route.path)
const unreadAlerts = ref(0)
const username = ref('')
function decodeUsername(): string {
try {
const token = localStorage.getItem('token')
if (!token) return ''
const payload = JSON.parse(atob(token.split('.')[1]))
return payload.username || ''
} catch {
return ''
}
}
async function fetchUnreadAlerts() {
try {
const data = await api.get<any>('/api/alerts/records?handled=0&page_size=1')
unreadAlerts.value = data.records?.length || 0
} catch {
// Silently fail
}
}
const pageTitles: Record<string, string> = {
'/dashboard': '仪表盘',
'/devices': '设备管理',
'/assets': '资产管理',
'/usb': 'U盘管控',
'/alerts': '告警中心',
'/settings': '系统设置',
'/plugins/web-filter': '上网拦截',
'/plugins/usage-timer': '时长记录',
'/plugins/software-blocker': '软件管控',
'/plugins/popup-blocker': '弹窗拦截',
'/plugins/usb-file-audit': 'U盘审计',
'/plugins/watermark': '水印管理',
}
const pageTitle = computed(() => pageTitles[route.path] || '仪表盘')
onMounted(() => {
username.value = decodeUsername()
fetchUnreadAlerts()
})
function handleLogout() {
localStorage.removeItem('token')
localStorage.removeItem('refresh_token')
router.push('/login')
}
</script>
<style scoped>
.app-container { height: 100vh; }
.sidebar {
background-color: #1d1e2c;
overflow-y: auto;
}
.logo {
padding: 20px;
text-align: center;
color: #fff;
border-bottom: 1px solid #2d2e3e;
}
.logo h2 { font-size: 24px; margin-bottom: 4px; }
.logo span { font-size: 12px; color: #a0a3bd; }
.app-header {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e4e7ed;
background: #fff;
}
.page-title { font-size: 18px; font-weight: 600; }
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.user-info {
display: flex;
align-items: center;
gap: 4px;
cursor: pointer;
color: #606266;
}
</style>