2026-07-18 20:09:26 +08:00
|
|
|
<template>
|
|
|
|
|
<div>
|
2026-07-18 23:17:53 +08:00
|
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px;">
|
|
|
|
|
<h2 style="font-size: 20px; font-weight: 700; margin: 0;">部署日志</h2>
|
|
|
|
|
<el-select v-model="statusFilter" style="width: 160px;" @change="load">
|
|
|
|
|
<el-option label="全部状态" value="" />
|
|
|
|
|
<el-option label="成功" value="success" />
|
|
|
|
|
<el-option label="失败" value="failed" />
|
|
|
|
|
<el-option label="跳过" value="skipped" />
|
|
|
|
|
</el-select>
|
2026-07-18 20:09:26 +08:00
|
|
|
</div>
|
|
|
|
|
|
2026-07-18 23:17:53 +08:00
|
|
|
<el-card>
|
|
|
|
|
<el-table :data="logs" stripe style="width: 100%;">
|
|
|
|
|
<el-table-column prop="created_at" label="时间" width="170">
|
|
|
|
|
<template #default="{ row }">{{ formatTime(row.created_at) }}</template>
|
|
|
|
|
</el-table-column>
|
2026-07-20 10:26:58 +08:00
|
|
|
<el-table-column prop="server" label="服务器" width="120" />
|
|
|
|
|
<el-table-column prop="hostname" label="设备" width="140">
|
|
|
|
|
<template #default="{ row }">{{ row.hostname || '-' }}</template>
|
|
|
|
|
</el-table-column>
|
2026-07-18 23:17:53 +08:00
|
|
|
<el-table-column prop="domain" label="域名" width="200" />
|
|
|
|
|
<el-table-column prop="status" label="状态" width="100">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-tag :type="statusType(row.status)" size="small">{{ row.status }}</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="message" label="消息" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="详情" width="80" align="center">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-button type="primary" link size="small" @click="showDetail(row)">查看</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
<el-dialog v-model="showDialog" title="日志详情" width="520px">
|
|
|
|
|
<template v-if="detailLog">
|
|
|
|
|
<el-descriptions :column="1" border size="small">
|
|
|
|
|
<el-descriptions-item label="时间">{{ formatTime(detailLog.created_at) }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="服务器">{{ detailLog.server || '-' }}</el-descriptions-item>
|
2026-07-20 10:26:58 +08:00
|
|
|
<el-descriptions-item label="设备">{{ detailLog.hostname || '-' }}</el-descriptions-item>
|
2026-07-18 23:17:53 +08:00
|
|
|
<el-descriptions-item label="域名">{{ detailLog.domain || '-' }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="状态">
|
|
|
|
|
<el-tag :type="statusType(detailLog.status)" size="small">{{ detailLog.status }}</el-tag>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="消息">
|
|
|
|
|
<span style="white-space: pre-wrap; word-break: break-all;">{{ detailLog.message || '-' }}</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dialog>
|
2026-07-18 20:09:26 +08:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, onMounted } from 'vue'
|
|
|
|
|
import { getLogs } from '../api'
|
|
|
|
|
|
|
|
|
|
const logs = ref([])
|
|
|
|
|
const statusFilter = ref('')
|
2026-07-18 23:17:53 +08:00
|
|
|
const detailLog = ref(null)
|
|
|
|
|
const showDialog = ref(false)
|
2026-07-18 20:09:26 +08:00
|
|
|
|
|
|
|
|
const formatTime = (iso) => {
|
|
|
|
|
if (!iso) return '-'
|
|
|
|
|
return new Date(iso).toLocaleString('zh-CN')
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-18 23:17:53 +08:00
|
|
|
const statusType = (status) => ({
|
|
|
|
|
success: 'success',
|
|
|
|
|
failed: 'danger',
|
|
|
|
|
skipped: 'info',
|
|
|
|
|
}[status] || 'info')
|
2026-07-18 20:09:26 +08:00
|
|
|
|
|
|
|
|
const load = async () => {
|
|
|
|
|
const { data } = await getLogs(statusFilter.value || undefined)
|
|
|
|
|
logs.value = data
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-18 23:17:53 +08:00
|
|
|
const showDetail = (row) => {
|
|
|
|
|
detailLog.value = row
|
|
|
|
|
showDialog.value = true
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-18 20:09:26 +08:00
|
|
|
onMounted(load)
|
|
|
|
|
</script>
|