diff --git a/web/src/api/aiRoi.js b/web/src/api/aiRoi.js index 6898efdf2..a3bcbc032 100644 --- a/web/src/api/aiRoi.js +++ b/web/src/api/aiRoi.js @@ -64,9 +64,19 @@ export function updateAlgoParams(data) { } export function getSnapUrl(cameraCode, force = false) { - return request({ - method: 'get', - url: '/api/ai/roi/snap', - params: { cameraCode, force } - }) + if (force) { + // force 模式:先触发 Edge 截图(更新 DB),再返回代理 URL + return request({ + method: 'get', + url: '/api/ai/roi/snap', + params: { cameraCode, force: true } + }).then(() => { + return '/api/ai/roi/snap/image?cameraCode=' + encodeURIComponent(cameraCode) + '&t=' + Date.now() + }).catch(() => { + // 截图请求失败也返回代理 URL(可能 DB 有旧数据) + return '/api/ai/roi/snap/image?cameraCode=' + encodeURIComponent(cameraCode) + '&t=' + Date.now() + }) + } + // 非 force:直接返回代理 URL(从 DB 读取持久化截图,不触发 Edge) + return Promise.resolve('/api/ai/roi/snap/image?cameraCode=' + encodeURIComponent(cameraCode)) } diff --git a/web/src/views/cameraConfig/roiConfig.vue b/web/src/views/cameraConfig/roiConfig.vue index 48bc24e3d..a3dfc0711 100644 --- a/web/src/views/cameraConfig/roiConfig.vue +++ b/web/src/views/cameraConfig/roiConfig.vue @@ -150,20 +150,8 @@ export default { fetchSnap(force = false) { if (!this.cameraId) return this.snapLoading = true - getSnapUrl(this.cameraId, force).then(res => { - const data = res.data || res - if (data.status === 'ok' && data.url) { - // 添加时间戳防止浏览器缓存旧截图 - const url = data.url - this.snapUrl = url + (url.includes('?') ? '&' : '?') + '_t=' + Date.now() - if (data.stale) { - this.$message.warning('截图为缓存数据,边缘设备可能离线') - } - } else if (data.status === 'timeout') { - this.$message.warning(data.message || '边缘设备响应超时') - } else { - this.$message.error(data.message || '截图失败') - } + getSnapUrl(this.cameraId, force).then(url => { + this.snapUrl = url }).catch(() => { this.$message.error('截图请求失败,请检查网络') }).finally(() => { diff --git a/web/src/views/roiConfig/components/RoiCanvas.vue b/web/src/views/roiConfig/components/RoiCanvas.vue index 2bece4a42..a732b97f1 100644 --- a/web/src/views/roiConfig/components/RoiCanvas.vue +++ b/web/src/views/roiConfig/components/RoiCanvas.vue @@ -43,7 +43,8 @@ export default { currentPoint: null, polygonPoints: [], loading: true, - errorMsg: '' + errorMsg: '', + resizeObserver: null } }, watch: { @@ -57,16 +58,30 @@ export default { snapUrl() { this.loading = true this.errorMsg = '' + this.$nextTick(() => this.initCanvas()) } }, mounted() { this.$nextTick(() => { this.initCanvas() + // ResizeObserver 确保容器尺寸变化时重新初始化 canvas + if (this.$refs.wrapper && typeof ResizeObserver !== 'undefined') { + this.resizeObserver = new ResizeObserver(() => { + if (this.$refs.wrapper && this.$refs.wrapper.clientWidth > 0) { + this.initCanvas() + } + }) + this.resizeObserver.observe(this.$refs.wrapper) + } window.addEventListener('resize', this.handleResize) }) }, beforeDestroy() { window.removeEventListener('resize', this.handleResize) + if (this.resizeObserver) { + this.resizeObserver.disconnect() + this.resizeObserver = null + } }, methods: { onImageLoad() { @@ -78,6 +93,8 @@ export default { onImageError() { this.loading = false this.errorMsg = '截图加载失败,请确认摄像头正在拉流' + // 关键:截图失败也初始化 canvas,使 ROI 区域可见可操作 + this.$nextTick(() => this.initCanvas()) }, initCanvas() { const canvas = this.$refs.canvas