重构: aiot 模块重命名为 video,WVP 凭据移至环境变量
路径重命名:
- api/aiot/{alarm,device,edge,request} → api/video/{alarm,device,edge,request}
- views/aiot/{alarm,device,edge} → views/video/{alarm,device,edge}
- vite.config.mts 代理路径 /admin-api/aiot/* → /admin-api/video/*
video/request.ts 改造:
- WVP 用户名/密码 MD5 改读 import.meta.env,不再写死在源码里
- force 截图失败时补一条 console.debug,便于回溯 COS 图片加载异常
video/alarm/index.ts 顺带清理:
- 移除无调用方的重复 API getRecentAlerts(与 getAlertPage 重叠)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
api: async () => {
|
||||
const { getCameraOptions } = await import('#/api/aiot/device');
|
||||
const { getCameraOptions } = await import('#/api/video/device');
|
||||
const list = await getCameraOptions();
|
||||
return list.map((item: { cameraCode: string; cameraName: string }) => ({
|
||||
label: item.cameraName,
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { AiotAlarmApi } from '#/api/aiot/alarm';
|
||||
import type { VideoAlarmApi } from '#/api/video/alarm';
|
||||
|
||||
import { h, ref } from 'vue';
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
getAlert,
|
||||
getAlertPage,
|
||||
handleAlert,
|
||||
} from '#/api/aiot/alarm';
|
||||
} from '#/api/video/alarm';
|
||||
|
||||
import {
|
||||
ALERT_LEVEL_OPTIONS,
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
useGridFormSchema,
|
||||
} from './data';
|
||||
|
||||
defineOptions({ name: 'AiotAlarmList' });
|
||||
defineOptions({ name: 'VideoAlarmList' });
|
||||
|
||||
/** 格式化持续时长(毫秒 → 可读文本) */
|
||||
function formatDuration(ms: number | null | undefined): string {
|
||||
@@ -43,7 +43,7 @@ function formatDuration(ms: number | null | undefined): string {
|
||||
return minutes > 0 ? `${hours} 小时 ${minutes} 分` : `${hours} 小时`;
|
||||
}
|
||||
|
||||
const currentAlert = ref<AiotAlarmApi.Alert | null>(null);
|
||||
const currentAlert = ref<VideoAlarmApi.Alert | null>(null);
|
||||
const detailVisible = ref(false);
|
||||
|
||||
/** 刷新表格 */
|
||||
@@ -108,7 +108,7 @@ function getLevelColor(level?: string) {
|
||||
}
|
||||
|
||||
/** 查看告警详情 */
|
||||
async function handleView(row: AiotAlarmApi.Alert) {
|
||||
async function handleView(row: VideoAlarmApi.Alert) {
|
||||
try {
|
||||
const alertId = row.alarmId || row.id;
|
||||
if (!alertId) {
|
||||
@@ -126,11 +126,11 @@ async function handleView(row: AiotAlarmApi.Alert) {
|
||||
|
||||
/** 处理告警 — "处理"弹窗(支持备注) */
|
||||
const handleModalVisible = ref(false);
|
||||
const handleModalRow = ref<AiotAlarmApi.Alert | null>(null);
|
||||
const handleModalRow = ref<VideoAlarmApi.Alert | null>(null);
|
||||
const handleRemark = ref('');
|
||||
const handleSubmitting = ref(false);
|
||||
|
||||
function openHandleModal(row: AiotAlarmApi.Alert) {
|
||||
function openHandleModal(row: VideoAlarmApi.Alert) {
|
||||
handleModalRow.value = row;
|
||||
handleRemark.value = '';
|
||||
handleModalVisible.value = true;
|
||||
@@ -159,7 +159,7 @@ async function submitHandle() {
|
||||
}
|
||||
|
||||
/** 处理告警 — "误报"确认弹窗 */
|
||||
function handleFalseAlarm(row: AiotAlarmApi.Alert) {
|
||||
function handleFalseAlarm(row: VideoAlarmApi.Alert) {
|
||||
Modal.confirm({
|
||||
title: '标记误报',
|
||||
content: h('div', [
|
||||
@@ -225,7 +225,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<AiotAlarmApi.Alert>,
|
||||
} as VxeTableGridOptions<VideoAlarmApi.Alert>,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AiotAlarmApi } from '#/api/aiot/alarm';
|
||||
import type { VideoAlarmApi } from '#/api/video/alarm';
|
||||
|
||||
const TYPE_NAMES: Record<string, string> = {
|
||||
leave_post: '离岗检测',
|
||||
@@ -29,7 +29,7 @@ const LEVEL_COLORS: Record<number, string> = {
|
||||
};
|
||||
|
||||
/** 告警趋势折线图(每种类型独立一条线,都从0开始) */
|
||||
export function getTrendChartOptions(data: AiotAlarmApi.TrendItem[]): any {
|
||||
export function getTrendChartOptions(data: VideoAlarmApi.TrendItem[]): any {
|
||||
const dates = data.map((d) => d.date.slice(5)); // MM-DD
|
||||
const types = Object.keys(TYPE_NAMES);
|
||||
|
||||
@@ -106,7 +106,7 @@ export function getTypePieChartOptions(
|
||||
|
||||
/** 设备告警 Top10 横向条形图 */
|
||||
export function getDeviceTopChartOptions(
|
||||
data: AiotAlarmApi.DeviceTopItem[],
|
||||
data: VideoAlarmApi.DeviceTopItem[],
|
||||
): any {
|
||||
const sorted = [...data].reverse(); // 最多的在上面
|
||||
return {
|
||||
@@ -172,7 +172,7 @@ export function getLevelBarChartOptions(
|
||||
|
||||
/** 24小时时段分布柱状图 */
|
||||
export function getHourDistChartOptions(
|
||||
data: AiotAlarmApi.HourDistItem[],
|
||||
data: VideoAlarmApi.HourDistItem[],
|
||||
): any {
|
||||
const counts = data.map((d) => d.count);
|
||||
const maxCount = Math.max(...counts, 1);
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { AiotAlarmApi } from '#/api/aiot/alarm';
|
||||
import type { VideoAlarmApi } from '#/api/video/alarm';
|
||||
|
||||
import { nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
import {
|
||||
getAlertDashboard,
|
||||
getAlertTrend,
|
||||
} from '#/api/aiot/alarm';
|
||||
} from '#/api/video/alarm';
|
||||
|
||||
import {
|
||||
getDeviceTopChartOptions,
|
||||
@@ -35,17 +35,17 @@ import {
|
||||
getTypePieChartOptions,
|
||||
} from './chart-options';
|
||||
|
||||
defineOptions({ name: 'AiotAlarmDashboard' });
|
||||
defineOptions({ name: 'VideoAlarmDashboard' });
|
||||
|
||||
const router = useRouter();
|
||||
const loading = ref(true);
|
||||
|
||||
// 数据
|
||||
const stats = ref<AiotAlarmApi.AlertStatistics>({});
|
||||
const trendData = ref<AiotAlarmApi.TrendItem[]>([]);
|
||||
const deviceTopData = ref<AiotAlarmApi.DeviceTopItem[]>([]);
|
||||
const hourDistData = ref<AiotAlarmApi.HourDistItem[]>([]);
|
||||
const recentAlerts = ref<AiotAlarmApi.Alert[]>([]);
|
||||
const stats = ref<VideoAlarmApi.AlertStatistics>({});
|
||||
const trendData = ref<VideoAlarmApi.TrendItem[]>([]);
|
||||
const deviceTopData = ref<VideoAlarmApi.DeviceTopItem[]>([]);
|
||||
const hourDistData = ref<VideoAlarmApi.HourDistItem[]>([]);
|
||||
const recentAlerts = ref<VideoAlarmApi.Alert[]>([]);
|
||||
|
||||
// 趋势天数切换
|
||||
const trendDays = ref(7);
|
||||
@@ -162,7 +162,7 @@ function formatTime(time?: string) {
|
||||
|
||||
/** 跳转到告警列表 */
|
||||
function goToAlertList() {
|
||||
router.push('/aiot/alarm/list');
|
||||
router.push('/video/alarm/list');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { AiotDeviceApi } from '#/api/aiot/device';
|
||||
import type { AiotEdgeApi } from '#/api/aiot/edge';
|
||||
import type { VideoDeviceApi } from '#/api/video/device';
|
||||
import type { VideoEdgeApi } from '#/api/video/edge';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
@@ -20,8 +20,8 @@ import {
|
||||
getAlgorithmList,
|
||||
saveAlgoGlobalParams,
|
||||
updateDeviceAlgoParams,
|
||||
} from '#/api/aiot/device';
|
||||
import { getDeviceList } from '#/api/aiot/edge';
|
||||
} from '#/api/video/device';
|
||||
import { getDeviceList } from '#/api/video/edge';
|
||||
|
||||
// 参数名中英文映射(与 AlgorithmParamEditor 保持一致)
|
||||
const paramNameMap: Record<string, string> = {
|
||||
@@ -62,7 +62,7 @@ const paramDescMap: Record<string, string> = {
|
||||
|
||||
// ==================== 设备选择器 ====================
|
||||
const selectedDeviceId = ref<string>('');
|
||||
const deviceList = ref<AiotEdgeApi.Device[]>([]);
|
||||
const deviceList = ref<VideoEdgeApi.Device[]>([]);
|
||||
|
||||
const isDeviceMode = computed(() => selectedDeviceId.value !== '');
|
||||
|
||||
@@ -76,7 +76,7 @@ const saveButtonText = computed(() => {
|
||||
});
|
||||
|
||||
// ==================== 算法数据 ====================
|
||||
const algorithms = ref<AiotDeviceApi.Algorithm[]>([]);
|
||||
const algorithms = ref<VideoDeviceApi.Algorithm[]>([]);
|
||||
const activeTab = ref<string>('');
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
@@ -189,7 +189,7 @@ async function loadAlgorithms() {
|
||||
}
|
||||
}
|
||||
|
||||
function initFormData(algo: AiotDeviceApi.Algorithm) {
|
||||
function initFormData(algo: VideoDeviceApi.Algorithm) {
|
||||
const code = algo.algoCode || '';
|
||||
let schema: Record<string, any> = {};
|
||||
let globalParams: Record<string, any> = {};
|
||||
@@ -5,7 +5,7 @@
|
||||
* 功能:摄像头列表展示、搜索筛选、新增/编辑/删除、拉流控制、ROI 配置跳转、配置导出
|
||||
* 后端:WVP 视频平台 StreamProxy API
|
||||
*/
|
||||
import type { AiotDeviceApi } from '#/api/aiot/device';
|
||||
import type { VideoDeviceApi } from '#/api/video/device';
|
||||
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -36,9 +36,9 @@ import {
|
||||
getSnapUrl,
|
||||
pushAllConfig,
|
||||
saveCamera,
|
||||
} from '#/api/aiot/device';
|
||||
} from '#/api/video/device';
|
||||
|
||||
defineOptions({ name: 'AiotDeviceCamera' });
|
||||
defineOptions({ name: 'VideoDeviceCamera' });
|
||||
|
||||
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
||||
|
||||
@@ -47,7 +47,7 @@ const router = useRouter();
|
||||
// ==================== 列表状态 ====================
|
||||
|
||||
const loading = ref(false);
|
||||
const cameraList = ref<AiotDeviceApi.Camera[]>([]);
|
||||
const cameraList = ref<VideoDeviceApi.Camera[]>([]);
|
||||
const roiCounts = ref<Record<string, number>>({});
|
||||
const cameraStatus = ref<Record<string, boolean | null>>({});
|
||||
const page = ref(1);
|
||||
@@ -70,7 +70,7 @@ const editModalOpen = ref(false);
|
||||
const editModalTitle = ref('添加摄像头');
|
||||
const saving = ref(false);
|
||||
const mediaServerOptions = ref<{ label: string; value: string }[]>([]);
|
||||
const editForm = reactive<Partial<AiotDeviceApi.Camera>>({
|
||||
const editForm = reactive<Partial<VideoDeviceApi.Camera>>({
|
||||
id: undefined,
|
||||
type: 'default',
|
||||
cameraName: '',
|
||||
@@ -148,7 +148,7 @@ async function loadCameraStatus() {
|
||||
if (!cameraCode) continue;
|
||||
// 使用 fetch HEAD 请求检测截图是否可用(/snap/image 已免认证)
|
||||
try {
|
||||
const url = `${apiURL}/aiot/device/roi/snap/image?cameraCode=${encodeURIComponent(cameraCode)}`;
|
||||
const url = `${apiURL}/video/device/roi/snap/image?cameraCode=${encodeURIComponent(cameraCode)}`;
|
||||
const res = await fetch(url, { method: 'HEAD' });
|
||||
cameraStatus.value = { ...cameraStatus.value, [cameraCode]: res.ok };
|
||||
} catch {
|
||||
@@ -238,7 +238,7 @@ function handleAdd() {
|
||||
autoFillStreamId();
|
||||
}
|
||||
|
||||
function handleEdit(row: AiotDeviceApi.Camera) {
|
||||
function handleEdit(row: VideoDeviceApi.Camera) {
|
||||
Object.assign(editForm, {
|
||||
id: row.id,
|
||||
type: row.type || 'default',
|
||||
@@ -301,7 +301,7 @@ async function handleSave() {
|
||||
|
||||
// ==================== 删除 ====================
|
||||
|
||||
function handleDelete(row: AiotDeviceApi.Camera) {
|
||||
function handleDelete(row: VideoDeviceApi.Camera) {
|
||||
Modal.confirm({
|
||||
title: '删除确认',
|
||||
content: `确定删除摄像头 ${row.cameraName || row.cameraCode || row.stream} ?`,
|
||||
@@ -320,9 +320,9 @@ function handleDelete(row: AiotDeviceApi.Camera) {
|
||||
|
||||
// ==================== ROI 配置跳转 ====================
|
||||
|
||||
function handleRoiConfig(row: AiotDeviceApi.Camera) {
|
||||
function handleRoiConfig(row: VideoDeviceApi.Camera) {
|
||||
router.push({
|
||||
path: '/aiot/device/roi',
|
||||
path: '/video/device/roi',
|
||||
query: {
|
||||
cameraCode: row.cameraCode,
|
||||
srcUrl: row.srcUrl,
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Tag,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { updateAlgoParams } from '#/api/aiot/device';
|
||||
import { updateAlgoParams } from '#/api/video/device';
|
||||
|
||||
import WorkingHoursEditor from './WorkingHoursEditor.vue';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { AiotDeviceApi } from '#/api/aiot/device';
|
||||
import type { VideoDeviceApi } from '#/api/video/device';
|
||||
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
getAlgorithmList,
|
||||
unbindAlgo,
|
||||
updateAlgoParams,
|
||||
} from '#/api/aiot/device';
|
||||
} from '#/api/video/device';
|
||||
|
||||
import AlgorithmParamEditor from './AlgorithmParamEditor.vue';
|
||||
|
||||
@@ -40,7 +40,7 @@ const DEFAULT_ALARM_LEVELS: Record<string, number> = {
|
||||
|
||||
interface Props {
|
||||
roiId: string;
|
||||
bindings: AiotDeviceApi.RoiAlgoBinding[];
|
||||
bindings: VideoDeviceApi.RoiAlgoBinding[];
|
||||
snapOk: boolean;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ const emit = defineEmits<{
|
||||
|
||||
const showAddDialog = ref(false);
|
||||
const selectedAlgoCode = ref<string | undefined>(undefined);
|
||||
const availableAlgorithms = ref<AiotDeviceApi.Algorithm[]>([]);
|
||||
const availableAlgorithms = ref<VideoDeviceApi.Algorithm[]>([]);
|
||||
const paramEditorOpen = ref(false);
|
||||
const currentParamSchema = ref('{}');
|
||||
const currentParams = ref('{}');
|
||||
@@ -123,7 +123,7 @@ function handleUnbind(bindId: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function openParamEditor(item: AiotDeviceApi.RoiAlgoBinding) {
|
||||
function openParamEditor(item: VideoDeviceApi.RoiAlgoBinding) {
|
||||
currentBindId.value = item.bind.bindId || '';
|
||||
currentParams.value = item.bind.params || '{}';
|
||||
currentParamSchema.value = item.algorithm?.paramSchema || '{}';
|
||||
@@ -137,7 +137,7 @@ function openParamEditor(item: AiotDeviceApi.RoiAlgoBinding) {
|
||||
paramEditorOpen.value = true;
|
||||
}
|
||||
|
||||
async function onToggleEnabled(bind: AiotDeviceApi.AlgoBind, val: string | number | boolean) {
|
||||
async function onToggleEnabled(bind: VideoDeviceApi.AlgoBind, val: string | number | boolean) {
|
||||
bind.enabled = val ? 1 : 0;
|
||||
try {
|
||||
await updateAlgoParams({
|
||||
@@ -165,7 +165,7 @@ function getAlgoFrameRate(algoCode: string): string {
|
||||
}
|
||||
|
||||
/** 从 params JSON 中读取告警等级 */
|
||||
function getAlarmLevel(item: AiotDeviceApi.RoiAlgoBinding): number {
|
||||
function getAlarmLevel(item: VideoDeviceApi.RoiAlgoBinding): number {
|
||||
try {
|
||||
const params = JSON.parse(item.bind.params || '{}');
|
||||
if (params.alarm_level !== undefined) return params.alarm_level;
|
||||
@@ -174,7 +174,7 @@ function getAlarmLevel(item: AiotDeviceApi.RoiAlgoBinding): number {
|
||||
}
|
||||
|
||||
/** 修改告警等级 */
|
||||
async function onAlarmLevelChange(item: AiotDeviceApi.RoiAlgoBinding, level: number) {
|
||||
async function onAlarmLevelChange(item: VideoDeviceApi.RoiAlgoBinding, level: number) {
|
||||
try {
|
||||
let params: Record<string, any> = {};
|
||||
try {
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { AiotDeviceApi } from '#/api/aiot/device';
|
||||
import type { VideoDeviceApi } from '#/api/video/device';
|
||||
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
|
||||
interface Props {
|
||||
rois: AiotDeviceApi.Roi[];
|
||||
rois: VideoDeviceApi.Roi[];
|
||||
drawMode: string | null;
|
||||
selectedRoiId: string | null;
|
||||
snapUrl: string;
|
||||
@@ -6,7 +6,7 @@
|
||||
* 算法绑定管理、配置推送到边缘端
|
||||
* 后端:WVP 视频平台 AiRoi / AiConfig API
|
||||
*/
|
||||
import type { AiotDeviceApi } from '#/api/aiot/device';
|
||||
import type { VideoDeviceApi } from '#/api/video/device';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
@@ -34,13 +34,13 @@ import {
|
||||
getSnapUrl,
|
||||
pushConfig,
|
||||
saveRoi,
|
||||
} from '#/api/aiot/device';
|
||||
import { wvpRequestClient } from '#/api/aiot/request';
|
||||
} from '#/api/video/device';
|
||||
import { wvpRequestClient } from '#/api/video/request';
|
||||
|
||||
import RoiAlgorithmBind from './components/RoiAlgorithmBind.vue';
|
||||
import RoiCanvas from './components/RoiCanvas.vue';
|
||||
|
||||
defineOptions({ name: 'AiotDeviceRoi' });
|
||||
defineOptions({ name: 'VideoDeviceRoi' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -48,11 +48,11 @@ const router = useRouter();
|
||||
// ==================== 摄像头选择 ====================
|
||||
|
||||
const cameraCode = ref('');
|
||||
const currentCamera = ref<AiotDeviceApi.Camera | null>(null);
|
||||
const currentCamera = ref<VideoDeviceApi.Camera | null>(null);
|
||||
|
||||
const showCameraSelector = ref(false);
|
||||
const cameraOptions = ref<
|
||||
{ camera: AiotDeviceApi.Camera; label: string; value: string }[]
|
||||
{ camera: VideoDeviceApi.Camera; label: string; value: string }[]
|
||||
>([]);
|
||||
const selectedCamera = ref<string | undefined>(undefined);
|
||||
const cameraLoading = ref(false);
|
||||
@@ -60,9 +60,9 @@ const cameraLoading = ref(false);
|
||||
// ==================== ROI 状态 ====================
|
||||
|
||||
const drawMode = ref<null | string>(null);
|
||||
const roiList = ref<AiotDeviceApi.Roi[]>([]);
|
||||
const roiList = ref<VideoDeviceApi.Roi[]>([]);
|
||||
const selectedRoiId = ref<null | string>(null);
|
||||
const selectedRoiBindings = ref<AiotDeviceApi.RoiAlgoBinding[]>([]);
|
||||
const selectedRoiBindings = ref<VideoDeviceApi.RoiAlgoBinding[]>([]);
|
||||
const snapUrl = ref('');
|
||||
const snapOk = ref(false);
|
||||
const panelVisible = ref(false);
|
||||
@@ -100,7 +100,7 @@ async function loadCurrentCamera() {
|
||||
try {
|
||||
const res = await getCameraList({ page: 1, count: 200 });
|
||||
const list = res.list || [];
|
||||
const camera = list.find((c: AiotDeviceApi.Camera) => c.cameraCode === cameraCode.value);
|
||||
const camera = list.find((c: VideoDeviceApi.Camera) => c.cameraCode === cameraCode.value);
|
||||
if (camera) {
|
||||
currentCamera.value = camera;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ async function loadCameraOptions() {
|
||||
try {
|
||||
const res = await getCameraList({ page: 1, count: 200 });
|
||||
const list = res.list || [];
|
||||
cameraOptions.value = list.map((cam: AiotDeviceApi.Camera) => ({
|
||||
cameraOptions.value = list.map((cam: VideoDeviceApi.Camera) => ({
|
||||
value: cam.cameraCode || '',
|
||||
label: `${cam.cameraName || cam.app || cam.stream}${cam.srcUrl ? ` (${cam.srcUrl})` : ''}`,
|
||||
camera: cam,
|
||||
@@ -138,18 +138,18 @@ async function onCameraSelected(val: string) {
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
router.push('/aiot/device/camera');
|
||||
router.push('/video/device/camera');
|
||||
}
|
||||
|
||||
// ==================== ROI 类型标签 ====================
|
||||
|
||||
function getRoiTagColor(roi: AiotDeviceApi.Roi) {
|
||||
function getRoiTagColor(roi: VideoDeviceApi.Roi) {
|
||||
if (roi.roiType === 'fullscreen') return 'orange';
|
||||
if (roi.roiType === 'rectangle') return 'blue';
|
||||
return 'green';
|
||||
}
|
||||
|
||||
function getRoiTagLabel(roi: AiotDeviceApi.Roi) {
|
||||
function getRoiTagLabel(roi: VideoDeviceApi.Roi) {
|
||||
if (roi.roiType === 'fullscreen') return '全图';
|
||||
if (roi.roiType === 'rectangle') return '矩形';
|
||||
return '自定义';
|
||||
@@ -209,7 +209,7 @@ function addFullscreen() {
|
||||
title: '新建全图选区',
|
||||
content: '将创建覆盖整张图片的选区',
|
||||
async onOk() {
|
||||
const newRoi: Partial<AiotDeviceApi.Roi> = {
|
||||
const newRoi: Partial<VideoDeviceApi.Roi> = {
|
||||
cameraId: cameraCode.value,
|
||||
name: `全图-${roiList.value.length + 1}`,
|
||||
roiType: 'fullscreen',
|
||||
@@ -262,7 +262,7 @@ function onDrawCancelled() {
|
||||
async function onRoiDrawn(data: { coordinates: string; roi_type: string }) {
|
||||
drawMode.value = null;
|
||||
const roiName = `ROI-${roiList.value.length + 1}`;
|
||||
const newRoi: Partial<AiotDeviceApi.Roi> = {
|
||||
const newRoi: Partial<VideoDeviceApi.Roi> = {
|
||||
cameraId: cameraCode.value,
|
||||
name: roiName,
|
||||
roiType: data.roi_type,
|
||||
@@ -292,7 +292,7 @@ function onRoiSelected(roiId: null | string) {
|
||||
}
|
||||
}
|
||||
|
||||
function selectRoi(roi: AiotDeviceApi.Roi) {
|
||||
function selectRoi(roi: VideoDeviceApi.Roi) {
|
||||
selectedRoiId.value = roi.roiId || null;
|
||||
loadRoiDetail();
|
||||
}
|
||||
@@ -305,7 +305,7 @@ function closePanel() {
|
||||
|
||||
// ==================== ROI 编辑 ====================
|
||||
|
||||
async function updateRoiData(roi: AiotDeviceApi.Roi) {
|
||||
async function updateRoiData(roi: VideoDeviceApi.Roi) {
|
||||
try {
|
||||
await saveRoi(roi);
|
||||
loadRois();
|
||||
@@ -326,7 +326,7 @@ function onRoiDeleted(roiId: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleDeleteRoi(roi: AiotDeviceApi.Roi) {
|
||||
function handleDeleteRoi(roi: VideoDeviceApi.Roi) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定删除该ROI?关联的算法绑定也将删除。',
|
||||
@@ -15,15 +15,15 @@ import {
|
||||
Tag,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { getDeviceList } from '#/api/aiot/edge';
|
||||
import type { AiotEdgeApi } from '#/api/aiot/edge';
|
||||
import { getDeviceList } from '#/api/video/edge';
|
||||
import type { VideoEdgeApi } from '#/api/video/edge';
|
||||
|
||||
import { formatUptime, STATUS_CONFIG } from './data';
|
||||
|
||||
defineOptions({ name: 'AiotEdgeNode' });
|
||||
defineOptions({ name: 'VideoEdgeNode' });
|
||||
|
||||
const loading = ref(false);
|
||||
const devices = ref<AiotEdgeApi.Device[]>([]);
|
||||
const devices = ref<VideoEdgeApi.Device[]>([]);
|
||||
|
||||
async function fetchDevices() {
|
||||
loading.value = true;
|
||||
Reference in New Issue
Block a user