PingWatch 网络设备离线监控系统

- FastAPI 后端 + Vue 3 前端
- Docker Compose 一键部署
- Casdoor OAuth 认证集成
- LogHive 集中式日志
- 设备批量 CSV 导入/导出
- WebSocket 实时状态推送
- 企业微信告警通知
- fping 高性能并发 Ping 检测

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 15:02:04 +08:00
commit 848f804169
55 changed files with 5941 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
<template>
<div class="settings-page">
<!-- 用户管理 -->
<el-card shadow="hover">
<template #header>
<span>用户管理</span>
</template>
<el-table :data="users" stripe v-loading="loading">
<el-table-column prop="username" label="用户名" width="140" />
<el-table-column prop="display_name" label="显示名称" width="140" />
<el-table-column prop="role" label="角色" width="100">
<template #default="{ row }">
<el-tag :type="row.role === 'admin' ? 'danger' : 'info'" size="small">
{{ row.role === 'admin' ? '管理员' : '查看者' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="last_login_at" label="最后登录" width="160">
<template #default="{ row }">
{{ row.last_login_at ? dayjs(row.last_login_at).format('YYYY-MM-DD HH:mm') : '-' }}
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template #default="{ row }">
<el-button
text
type="primary"
size="small"
@click="toggleRole(row)"
:disabled="row.id === currentUserId"
>
{{ row.role === 'admin' ? '设为查看者' : '设为管理员' }}
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 系统配置 -->
<el-card shadow="hover" style="margin-top: 20px">
<template #header>
<div class="card-header">
<span>数据保留设置</span>
</div>
</template>
<el-form label-width="150px">
<el-form-item label="Ping 记录保留">
<el-input-number v-model="pingRetention" :min="7" :max="365" />
</el-form-item>
<el-form-item label="告警记录保留">
<el-input-number v-model="alertRetention" :min="30" :max="730" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveConfig">保存设置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useAppStore } from '@/stores/app'
import { ElMessage, ElMessageBox } from 'element-plus'
import dayjs from 'dayjs'
import api from '@/api'
const store = useAppStore()
const currentUserId = computed(() => store.user?.id)
const users = ref([])
const loading = ref(false)
const pingRetention = ref(90)
const alertRetention = ref(365)
onMounted(() => {
fetchUsers()
})
async function fetchUsers() {
loading.value = true
try {
users.value = await api.get('/users')
} finally {
loading.value = false
}
}
async function toggleRole(user) {
const newRole = user.role === 'admin' ? 'viewer' : 'admin'
await ElMessageBox.confirm(
`确定将「${user.display_name || user.username}${newRole === 'admin' ? '设为管理员' : '降为查看者'}`,
'提示'
)
await api.put(`/users/${user.id}/role`, { role: newRole })
ElMessage.success('已更新')
fetchUsers()
}
function saveConfig() {
ElMessage.success('设置已保存(需要在后端更新配置)')
}
</script>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>