feat: improve recording automation and task workflows
This commit is contained in:
@@ -1,31 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import apiClient from "@/api/client";
|
||||
import apiClient, { getApiErrorMessage } from "@/api/client";
|
||||
import { useViewport } from "@/composables/useViewport";
|
||||
import type { SystemLog } from "@/types";
|
||||
import { logLevelLabelMap } from "@/types";
|
||||
|
||||
const loading = ref(false);
|
||||
const logs = ref<SystemLog[]>([]);
|
||||
const loadError = ref("");
|
||||
const { isMobile } = useViewport();
|
||||
|
||||
const filters = reactive({
|
||||
liveRoomId: "",
|
||||
level: undefined as number | undefined,
|
||||
recordTaskId: "",
|
||||
take: 200
|
||||
});
|
||||
|
||||
const logLevelOptions = Object.entries(logLevelLabelMap).map(([value, label]) => ({
|
||||
value: Number(value),
|
||||
label
|
||||
}));
|
||||
|
||||
async function loadLogs() {
|
||||
loading.value = true;
|
||||
loadError.value = "";
|
||||
|
||||
try {
|
||||
const { data } = await apiClient.get<SystemLog[]>("/logs", {
|
||||
params: {
|
||||
liveRoomId: filters.liveRoomId || undefined,
|
||||
level: typeof filters.level === "number" ? filters.level : undefined,
|
||||
recordTaskId: filters.recordTaskId || undefined,
|
||||
take: filters.take
|
||||
}
|
||||
});
|
||||
|
||||
logs.value = data;
|
||||
} catch (error) {
|
||||
loadError.value = getApiErrorMessage(error, "系统日志加载失败,请稍后重试。");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -55,18 +68,32 @@ onMounted(loadLogs);
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">系统日志</h1>
|
||||
<p class="page-subtitle">支持按直播间或任务过滤日志,便于定位解析失败、巡检异常和 ffmpeg 输出问题。</p>
|
||||
<p class="page-subtitle">
|
||||
支持按直播间、任务和日志级别筛选,便于快速定位解析失败、巡检异常和 ffmpeg 输出问题。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-alert v-if="loadError" class="page-error-alert" type="error" :closable="false" show-icon :title="loadError" />
|
||||
|
||||
<el-card class="surface-card filter-card" shadow="never">
|
||||
<h3 class="section-title">日志过滤</h3>
|
||||
<p class="section-subtitle">可选传入直播间 ID 或录制任务 ID,数量默认取最近 200 条。</p>
|
||||
<p class="section-subtitle">默认拉取最近 200 条日志,可按直播间 ID、任务 ID 和级别缩小范围。</p>
|
||||
|
||||
<el-form class="filter-form">
|
||||
<el-form-item label="直播间 ID">
|
||||
<el-input v-model="filters.liveRoomId" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="日志级别">
|
||||
<el-select v-model="filters.level" clearable placeholder="全部级别">
|
||||
<el-option
|
||||
v-for="option in logLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务 ID">
|
||||
<el-input v-model="filters.recordTaskId" placeholder="可选" />
|
||||
</el-form-item>
|
||||
@@ -81,30 +108,38 @@ onMounted(loadLogs);
|
||||
|
||||
<el-card class="surface-card table-card" shadow="never">
|
||||
<h3 class="section-title">日志列表</h3>
|
||||
<p class="section-subtitle">按时间倒序排列,便于快速回看最近一次异常。</p>
|
||||
<p class="section-subtitle">按时间倒序排列,优先展示最近发生的事件。</p>
|
||||
|
||||
<el-table :data="logs" v-loading="loading" height="720" class="premium-table">
|
||||
<el-table-column label="级别" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="levelTagType(row.level)">
|
||||
{{ logLevelLabelMap[row.level] }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<div class="table-scroll-shell logs-table-shell">
|
||||
<el-table
|
||||
:data="logs"
|
||||
v-loading="loading"
|
||||
:height="isMobile ? undefined : 720"
|
||||
class="premium-table logs-table"
|
||||
table-layout="auto"
|
||||
>
|
||||
<el-table-column label="级别" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="levelTagType(row.level)">
|
||||
{{ logLevelLabelMap[row.level] }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="分类" width="120" prop="category" />
|
||||
<el-table-column label="消息" min-width="240" prop="message" />
|
||||
<el-table-column label="详情" min-width="360">
|
||||
<template #default="{ row }">
|
||||
<span class="monospace log-detail">{{ row.detail || "-" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.createdAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table-column label="分类" width="128" prop="category" />
|
||||
<el-table-column label="消息" min-width="240" prop="message" />
|
||||
<el-table-column label="详情" min-width="360">
|
||||
<template #default="{ row }">
|
||||
<span class="monospace log-detail">{{ row.detail || "-" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" width="180">
|
||||
<template #default="{ row }">
|
||||
<span class="log-date-text">{{ formatDate(row.createdAt) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -115,6 +150,10 @@ onMounted(loadLogs);
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.page-error-alert {
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
.filter-card :deep(.el-card__body),
|
||||
.table-card :deep(.el-card__body) {
|
||||
padding-top: 20px;
|
||||
@@ -122,7 +161,7 @@ onMounted(loadLogs);
|
||||
|
||||
.filter-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 8px 12px;
|
||||
align-items: end;
|
||||
}
|
||||
@@ -134,6 +173,35 @@ onMounted(loadLogs);
|
||||
.log-detail {
|
||||
font-size: 12px;
|
||||
color: #6d665b;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.log-date-text {
|
||||
white-space: nowrap;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.logs-table-shell {
|
||||
margin-inline: -4px;
|
||||
padding-inline: 4px;
|
||||
}
|
||||
|
||||
.logs-table {
|
||||
min-width: 980px;
|
||||
}
|
||||
|
||||
.logs-table :deep(.el-table__cell) {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.logs-table :deep(.cell) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.filter-form {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
@@ -150,5 +218,9 @@ onMounted(loadLogs);
|
||||
.filter-form {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.filter-form :deep(.el-button) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user