feat: 初始化项目基础架构和核心功能
- 添加项目基础结构:Cargo.toml、.gitignore、设备UID和密钥文件 - 实现前端Vue3项目结构:路由、登录页面、设备管理页面 - 添加核心协议定义(crates/protocol):设备状态、资产、USB事件等 - 实现客户端监控模块:系统状态收集、资产收集 - 实现服务端基础API和插件系统 - 添加数据库迁移脚本:设备管理、资产跟踪、告警系统等 - 实现前端设备状态展示和基本交互 - 添加使用时长统计和水印功能插件
This commit is contained in:
74
web/src/views/plugins/UsageTimer.vue
Normal file
74
web/src/views/plugins/UsageTimer.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div class="plugin-page">
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="每日使用统计" name="daily">
|
||||
<div class="toolbar">
|
||||
<el-input v-model="uidFilter" placeholder="终端UID" style="width:200px" clearable @input="fetchDaily" />
|
||||
</div>
|
||||
<el-table :data="dailyData" v-loading="loading" stripe size="small">
|
||||
<el-table-column prop="device_uid" label="终端" width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="date" label="日期" width="120" />
|
||||
<el-table-column label="活跃时间" width="120">
|
||||
<template #default="{ row }">{{ formatMinutes(row.total_active_minutes) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="空闲时间" width="120">
|
||||
<template #default="{ row }">{{ formatMinutes(row.total_idle_minutes) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="first_active_at" label="首次活跃" width="170" />
|
||||
<el-table-column prop="last_active_at" label="最后活跃" width="170" />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="应用使用详情" name="apps">
|
||||
<div class="toolbar"><el-input v-model="appUid" placeholder="终端UID" style="width:200px" clearable @input="fetchApps" /></div>
|
||||
<el-table :data="appData" v-loading="appLoading" stripe size="small">
|
||||
<el-table-column prop="app_name" label="应用名称" min-width="200" />
|
||||
<el-table-column prop="date" label="日期" width="120" />
|
||||
<el-table-column label="使用时长" width="120">
|
||||
<template #default="{ row }">{{ formatMinutes(row.usage_minutes) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="使用排行" name="leaderboard">
|
||||
<el-table :data="board" v-loading="boardLoading" stripe size="small">
|
||||
<el-table-column type="index" label="#" width="60" />
|
||||
<el-table-column prop="device_uid" label="终端" min-width="200" />
|
||||
<el-table-column label="7天总时长" width="140">
|
||||
<template #default="{ row }">{{ formatMinutes(row.total_minutes) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
const activeTab = ref('daily')
|
||||
const auth = () => ({ headers: { Authorization: `Bearer ${localStorage.getItem('token')}` } })
|
||||
const uidFilter = ref('')
|
||||
const dailyData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const appUid = ref('')
|
||||
const appData = ref<any[]>([])
|
||||
const appLoading = ref(false)
|
||||
const board = ref<any[]>([])
|
||||
const boardLoading = ref(false)
|
||||
|
||||
function formatMinutes(m: number) { if(m>=60) return `${Math.floor(m/60)}h${m%60}m`; return `${m}m` }
|
||||
|
||||
async function fetchDaily() {
|
||||
loading.value=true
|
||||
try{const params=new URLSearchParams();if(uidFilter.value)params.set('device_uid',uidFilter.value)
|
||||
const r=await fetch(`/api/plugins/usage-timer/daily?${params}`,auth()).then(r=>r.json());if(r.success)dailyData.value=r.data.daily||[]}finally{loading.value=false}
|
||||
}
|
||||
async function fetchApps() {
|
||||
appLoading.value=true
|
||||
try{const params=new URLSearchParams();if(appUid.value)params.set('device_uid',appUid.value)
|
||||
const r=await fetch(`/api/plugins/usage-timer/app-usage?${params}`,auth()).then(r=>r.json());if(r.success)appData.value=r.data.app_usage||[]}finally{appLoading.value=false}
|
||||
}
|
||||
async function fetchBoard() {
|
||||
boardLoading.value=true
|
||||
try{const r=await fetch('/api/plugins/usage-timer/leaderboard',auth()).then(r=>r.json());if(r.success)board.value=r.data.leaderboard||[]}finally{boardLoading.value=false}
|
||||
}
|
||||
onMounted(()=>{fetchDaily();fetchApps();fetchBoard()})
|
||||
</script>
|
||||
<style scoped>.plugin-page{padding:20px}.toolbar{display:flex;gap:12px;margin-bottom:16px}</style>
|
||||
Reference in New Issue
Block a user