功能:新增云管API与Web控制台并完成现场接入
This commit is contained in:
1 parent
18a9ce995d
commit
3fb7b4da8c
79 files changed
+17367
-3
No files matched your search
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { usePlatform } from '../stores/platform'
|
||||
import StatusTag from '../components/StatusTag.vue'
|
||||
import { api, errorMessage } from '../api'
|
||||
import { useAuth } from '../stores/auth'
|
||||
import { ElMessage } from 'element-plus'
|
||||
const auth = useAuth()
|
||||
async function downloadDiagnostics(id: string) {
|
||||
try {
|
||||
const diagnostic = await api.taskDiagnostics(id)
|
||||
const url = URL.createObjectURL(new Blob([JSON.stringify(diagnostic, null, 2)], { type: 'application/json' }))
|
||||
const link = document.createElement('a'); link.href = url; link.download = `${id}-diagnostics.json`; link.click(); URL.revokeObjectURL(url)
|
||||
} catch(e) { ElMessage.error(errorMessage(e)) }
|
||||
}
|
||||
const data = usePlatform(), tab = ref('tasks'), keyword = ref(''), status = ref(''), page = ref(1), selectedId = ref('')
|
||||
const selected = computed(() => data.tasks.find(t => t.id === selectedId.value))
|
||||
const labels: Record<string, string> = { start: '开机', shutdown: '正常关机', reboot: '重启', 'reset-session': '重置会话', 'collect-logs': '收集日志', sync: '同步资源', login: '登录', logout: '退出登录', create_user: '创建用户', enroll_terminal: '登记终端', update_bindings: '更新授权', import_desktop: '纳管桌面' }
|
||||
const filtered = computed(() => data.tasks.filter(t => `${t.targetName} ${t.id} ${t.actor}`.toLowerCase().includes(keyword.value.toLowerCase()) && (!status.value || t.status === status.value)))
|
||||
const rows = computed(() => filtered.value.slice((page.value - 1) * 10, page.value * 10))
|
||||
const auditFiltered = computed(() => data.audits.filter(a => `${a.actor} ${a.target} ${a.action}`.toLowerCase().includes(keyword.value.toLowerCase())))
|
||||
const auditRows = computed(() => auditFiltered.value.slice((page.value - 1) * 10, page.value * 10))
|
||||
</script>
|
||||
<template>
|
||||
<div class="page-heading"><div><h1>任务与审计</h1><p class="subtext">提交记录、执行回执和最终结果分开显示</p></div><el-button @click="data.refresh">刷新</el-button></div>
|
||||
<section class="panel">
|
||||
<el-tabs v-model="tab" @tab-change="page = 1; keyword = ''; status = ''"><el-tab-pane label="执行任务" name="tasks" /><el-tab-pane label="操作审计" name="audit" /></el-tabs><div class="toolbar"><el-input v-model="keyword" placeholder="搜索目标 / 操作者 / 标识" aria-label="搜索任务" clearable @input="page = 1" /><el-select v-if="tab === 'tasks'" v-model="status" aria-label="任务状态筛选" placeholder="全部任务状态" clearable @change="page = 1"><el-option v-for="s in [{ value: 'queued', label: '排队中' }, { value: 'running', label: '执行中' }, { value: 'success', label: '成功' }, { value: 'failed', label: '失败' }, { value: 'timeout', label: '结果未确认' }]" :key="s.value" :label="s.label" :value="s.value" /></el-select></div>
|
||||
<el-table v-if="tab === 'tasks'" :data="rows" empty-text="尚无执行任务"><el-table-column label="操作目标 / 任务" min-width="200"><template #default="{ row }"><el-button link type="primary" @click="selectedId = row.id">{{ row.targetName }}</el-button><div class="mono secondary">{{ row.id.slice(0, 18) }}…</div></template></el-table-column><el-table-column label="操作" width="110"><template #default="{ row }">{{ labels[row.action] || row.action }}</template></el-table-column><el-table-column label="状态" width="125"><template #default="{ row }"><StatusTag :value="row.status === 'running' ? '执行中' : row.status" /></template></el-table-column><el-table-column prop="actor" label="操作者" width="110" /><el-table-column label="提交时间" min-width="170"><template #default="{ row }">{{ new Date(row.createdAt).toLocaleString('zh-CN') }}</template></el-table-column><el-table-column prop="message" label="执行结果" min-width="240" /></el-table>
|
||||
<el-table v-else :data="auditRows" empty-text="尚无审计记录"><el-table-column prop="actor" label="操作者" width="100" /><el-table-column label="操作" min-width="130"><template #default="{ row }">{{ labels[row.action] || row.action }}</template></el-table-column><el-table-column prop="target" label="对象" min-width="180" /><el-table-column label="结果" width="125"><template #default="{ row }"><StatusTag :value="row.result" /></template></el-table-column><el-table-column label="时间" min-width="175"><template #default="{ row }">{{ new Date(row.createdAt).toLocaleString('zh-CN') }}</template></el-table-column><el-table-column prop="requestId" label="请求标识" min-width="180" show-overflow-tooltip /></el-table>
|
||||
<el-pagination v-model:current-page="page" :total="tab === 'tasks' ? filtered.length : auditFiltered.length" :page-size="10" layout="total, prev, pager, next" />
|
||||
</section>
|
||||
<el-drawer :model-value="!!selected" title="任务详情" size="580px" @close="selectedId = ''"><el-descriptions v-if="selected" :column="1" border><el-descriptions-item label="任务 ID"><span class="mono">{{ selected.id }}</span></el-descriptions-item><el-descriptions-item label="目标">{{ selected.targetName }}</el-descriptions-item><el-descriptions-item label="操作">{{ labels[selected.action] || selected.action }}</el-descriptions-item><el-descriptions-item label="状态"><StatusTag :value="selected.status === 'running' ? '执行中' : selected.status" /></el-descriptions-item><el-descriptions-item label="结果">{{ selected.message }}</el-descriptions-item><el-descriptions-item label="操作者">{{ selected.actor }}</el-descriptions-item><el-descriptions-item label="PVE 任务标识"><span class="mono">{{ selected.providerRef || '无' }}</span></el-descriptions-item><el-descriptions-item label="更新时间">{{ new Date(selected.updatedAt).toLocaleString('zh-CN') }}</el-descriptions-item></el-descriptions><el-button v-if="selected && auth.canOperate && selected.action === 'collect-logs' && selected.status === 'success'" style="margin-top:20px" @click="downloadDiagnostics(selected.id)">下载诊断日志</el-button><p class="subtext" style="margin-top:22px">结果未确认时先核对实际设备状态,再决定是否重新提交。系统不会自动重放操作。</p></el-drawer>
|
||||
</template>
|
||||
Reference in new issue
Block a user