fix(aiot): 回退告警 API 到 Service 后端,修复截图 URL 端点

告警问题:
- 告警数据存储在 FastAPI Service 的 alert_platform.db 中
- 之前错误地切换到 wvpRequestClient(WVP 后端的 wvp_ai_alert 表)
- 回退到 requestClient + /aiot/alarm/alert/* 路径恢复数据

截图问题:
- /snap/image 代理端点在 Redis+DB 都无缓存时返回 404
- 回退到 /snap 端点,利用其 Accept: image/* 自动 302 重定向逻辑
- 保留 force 参数支持手动刷新截图

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 11:05:03 +08:00
parent 0d56b2f221
commit 284f2b8d87
3 changed files with 37 additions and 59 deletions

View File

@@ -2,7 +2,7 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { AiotAlarmApi } from '#/api/aiot/alarm';
import { h, onMounted, ref } from 'vue';
import { h, ref } from 'vue';
import { Page } from '@vben/common-ui';
@@ -10,7 +10,6 @@ import { Button, Image, message, Modal, Tag } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getAlert, getAlertPage, handleAlert } from '#/api/aiot/alarm';
import { getAlertImageUrl } from '#/api/aiot/device';
import {
ALERT_LEVEL_OPTIONS,
@@ -22,21 +21,6 @@ import {
defineOptions({ name: 'AiotAlarmList' });
/** 告警图片 URL 缓存imagePath → 代理 URL */
const imageUrlCache = ref<Record<string, string>>({});
/** 获取告警图片代理 URL异步构造后缓存 */
function getImageProxyUrl(row: AiotAlarmApi.Alert): string {
const imagePath = row.imagePath || row.ossUrl || row.snapshotUrl;
if (!imagePath) return '';
if (imageUrlCache.value[imagePath]) return imageUrlCache.value[imagePath]!;
// 异步构造并缓存
getAlertImageUrl(imagePath).then((url) => {
imageUrlCache.value[imagePath] = url;
});
return '';
}
/** 格式化持续时长(毫秒 → 可读文本) */
function formatDuration(ms: number | null | undefined): string {
// 当 duration_ms 为 null 时,说明告警仍在进行中
@@ -263,12 +247,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
<!-- 截图缩略图列 -->
<template #snapshot="{ row }">
<Image
v-if="getImageProxyUrl(row)"
:src="getImageProxyUrl(row)"
v-if="row.snapshotUrl || row.ossUrl"
:src="row.ossUrl || row.snapshotUrl"
:width="40"
:height="40"
:preview="{ src: getImageProxyUrl(row) }"
:fallback="`data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40'><rect width='40' height='40' fill='%23f0f0f0'/><text x='50%25' y='55%25' dominant-baseline='middle' text-anchor='middle' fill='%23bbb' font-size='12'>-</text></svg>`"
:preview="{ src: row.ossUrl || row.snapshotUrl }"
style="object-fit: cover; border-radius: 4px; cursor: pointer"
/>
<span v-else class="text-gray-400">-</span>
@@ -366,16 +349,25 @@ const [Grid, gridApi] = useVbenVxeGrid({
</div>
<!-- 告警截图 -->
<div v-if="getImageProxyUrl(currentAlert)">
<div v-if="currentAlert.ossUrl || currentAlert.snapshotUrl">
<span class="text-gray-500">告警截图</span>
<div class="mt-2">
<Image
:src="getImageProxyUrl(currentAlert)"
:src="currentAlert.ossUrl || currentAlert.snapshotUrl"
:width="300"
:preview="{ src: getImageProxyUrl(currentAlert) }"
:fallback="`data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='200'><rect width='300' height='200' fill='%23f5f5f5'/><text x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%23bbb' font-size='14'>图片加载失败</text></svg>`"
:preview="{ src: currentAlert.ossUrl || currentAlert.snapshotUrl }"
/>
</div>
<div class="mt-1">
<a
:href="currentAlert.ossUrl || currentAlert.snapshotUrl"
target="_blank"
rel="noopener noreferrer"
class="text-blue-500 text-xs hover:underline"
>
{{ currentAlert.ossUrl || currentAlert.snapshotUrl }}
</a>
</div>
</div>
<!-- 检测区域 -->