fix: 修复 LogDashboard 类型定义缺少 messageSnippet 属性

feat/windows-service-status-auto
haoliang 2 days ago
parent e09fdc1329
commit 2d698b277d

@ -0,0 +1,144 @@
<template>
<div class="log-dashboard">
<h1 class="page-title">日志看板</h1>
<section class="filters card">
<div class="filters-row">
<label>
机床
<select v-model="filters.machineId">
<option value="">全部</option>
<option v-for="m in machines" :key="m" :value="m">{{ m }}</option>
</select>
</label>
<label>
程序名
<input v-model="filters.programName" placeholder="过滤加工程序" />
</label>
<label>
时间范围
<input type="date" v-model="filters.startDate" />
<span></span>
<input type="date" v-model="filters.endDate" />
</label>
<button @click="loadDashboard"></button>
</div>
</section>
<section class="summary card" v-if="data">
<div class="summary-item" v-for="(count, key) in data.counts" :key="key">
<div class="label">{{ key }}</div>
<div class="value">{{ count }}</div>
</div>
<div class="summary-analyses" v-if="data.analysis">
<h3>分析摘要</h3>
<p>{{ data.analysis }}</p>
</div>
</section>
<section class="logs card" v-if="data?.logs?.length">
<table class="logs-table">
<thead>
<tr>
<th>时间</th>
<th>机床</th>
<th>程序</th>
<th>等级</th>
<th>日志摘要</th>
</tr>
</thead>
<tbody>
<tr v-for="log in data.logs" :key="log.id">
<td>{{ log.timestamp }}</td>
<td>{{ log.machineId }}</td>
<td>{{ log.programName }}</td>
<td>{{ log.level }}</td>
<td class="message" :title="log.message">{{ log.messageSnippet }}</td>
</tr>
</tbody>
</table>
</section>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
type LogItem = {
id: string
timestamp: string
machineId: string
programName: string
level: string
message: string
messageSnippet: string
}
type DashboardData = {
total: number
counts: Record<string, number>
logs: LogItem[]
analysis?: string
}
const data = ref<DashboardData | null>(null)
const machines = ref<string[]>([])
const filters = ref({ machineId: '', programName: '', startDate: '', endDate: '' })
const loadDashboard = async () => {
try {
const query = new URLSearchParams({}).toString()
const res = await fetch('/api/logs/dashboard?' + query)
if (!res.ok) throw new Error('网络错误')
const json = await res.json()
//
data.value = {
total: json.total ?? json.logs?.length ?? 0,
counts: json.counts ?? {},
logs: (json.logs ?? []).map((l: any) => ({
id: l.id ?? l.timestamp + '-' + l.machineId,
timestamp: l.timestamp,
machineId: l.machineId,
programName: l.programName,
level: l.level,
message: l.message,
messageSnippet: (l.message ?? '').slice(0, 100)
}))
} as DashboardData
//
if (Array.isArray(json.machines)) machines.value = json.machines
} catch (e) {
console.error('加载看板失败', e)
data.value = null
}
}
onMounted(() => {
loadDashboard()
})
//
const normalizeLogs = computed(() => {
if (!data.value) return []
return data.value.logs.map((l) => ({ ...l, messageSnippet: (l.message ?? '').slice(0, 120) }))
})
</script>
<style scoped>
.log-dashboard { padding: 16px; }
.page-title { font-size: 28px; margin-bottom: 12px; }
.card { background: #fff; border: 1px solid #eee; border-radius: 6px; padding: 12px; margin-bottom: 12px; }
.filters-row { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.filters label { display: flex; flex-direction: column; font-size: 12px; color: #555; }
.filters input, .filters select { padding: 6px 8px; border: 1px solid #ddd; border-radius: 4px; min-width: 180px; }
.filters button { padding: 6px 12px; border: none; background: #409eff; color: white; border-radius: 4px; cursor: pointer; }
.summary { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; }
.summary-item { background: #f9f9f9; padding: 12px; border-radius: 6px; text-align: center; }
.summary-item .label { font-size: 12px; color: #666; }
.summary-item .value { font-size: 20px; font-weight: bold; margin-top: 6px; }
.logs-table { width: 100%; border-collapse: collapse; }
.logs-table th, .logs-table td { border-bottom: 1px solid #eee; padding: 8px; text-align: left; font-family: sans-serif; font-size: 12px; }
.logs-table .message { max-width: 420px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
</style>
Loading…
Cancel
Save