diff --git a/apps/web-antd/src/api/aiot/alarm/index.ts b/apps/web-antd/src/api/video/alarm/index.ts similarity index 77% rename from apps/web-antd/src/api/aiot/alarm/index.ts rename to apps/web-antd/src/api/video/alarm/index.ts index 8822e6a94..7c67fd0eb 100644 --- a/apps/web-antd/src/api/aiot/alarm/index.ts +++ b/apps/web-antd/src/api/video/alarm/index.ts @@ -2,7 +2,7 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; -export namespace AiotAlarmApi { +export namespace VideoAlarmApi { /** AI 告警 VO */ export interface Alert { id?: number | string; @@ -113,16 +113,16 @@ export namespace AiotAlarmApi { /** 分页查询告警列表 */ export function getAlertPage(params: PageParam) { - return requestClient.get>( - '/aiot/alarm/alert/page', + return requestClient.get>( + '/video/alarm/alert/page', { params }, ); } /** 获取告警详情 */ export function getAlert(id: number | string) { - return requestClient.get( - `/aiot/alarm/alert/get?id=${id}`, + return requestClient.get( + `/video/alarm/alert/get?id=${id}`, ); } @@ -132,69 +132,62 @@ export function handleAlert( status: string, remark?: string, ) { - return requestClient.put('/aiot/alarm/alert/handle', null, { + return requestClient.put('/video/alarm/alert/handle', null, { params: { id, status, remark }, }); } /** 删除告警 */ export function deleteAlert(id: number | string) { - return requestClient.delete(`/aiot/alarm/alert/delete?id=${id}`); + return requestClient.delete(`/video/alarm/alert/delete?id=${id}`); } /** 获取看板聚合数据(单次请求) */ export function getAlertDashboard(trendDays: number = 7) { - return requestClient.get( - '/aiot/alarm/alert/dashboard', + return requestClient.get( + '/video/alarm/alert/dashboard', { params: { trendDays } }, ); } /** 获取告警统计 */ export function getAlertStatistics(startTime?: string, endTime?: string) { - return requestClient.get( - '/aiot/alarm/alert/statistics', + return requestClient.get( + '/video/alarm/alert/statistics', { params: { startTime, endTime } }, ); } /** 获取告警趋势 */ export function getAlertTrend(days: number = 7) { - return requestClient.get( - '/aiot/alarm/alert/trend', + return requestClient.get( + '/video/alarm/alert/trend', { params: { days } }, ); } /** 获取设备告警排行 */ export function getAlertDeviceTop(limit: number = 10, days: number = 7) { - return requestClient.get( - '/aiot/alarm/alert/device-top', + return requestClient.get( + '/video/alarm/alert/device-top', { params: { limit, days } }, ); } /** 获取24小时告警分布 */ export function getAlertHourDistribution(days: number = 7) { - return requestClient.get( - '/aiot/alarm/alert/hour-distribution', + return requestClient.get( + '/video/alarm/alert/hour-distribution', { params: { days } }, ); } -/** 获取最近告警列表 */ -export function getRecentAlerts(pageSize: number = 10) { - return requestClient.get('/aiot/alarm/alert/page', { - params: { pageNo: 1, pageSize }, - }); -} - // ==================== 摄像头告警汇总 API ==================== /** 以摄像头维度获取告警汇总 */ export function getCameraAlertSummary(params: PageParam) { - return requestClient.get>( - '/aiot/alarm/device-summary/page', + return requestClient.get>( + '/video/alarm/device-summary/page', { params }, ); } diff --git a/apps/web-antd/src/api/aiot/device/index.ts b/apps/web-antd/src/api/video/device/index.ts similarity index 71% rename from apps/web-antd/src/api/aiot/device/index.ts rename to apps/web-antd/src/api/video/device/index.ts index bdb947304..7882adc45 100644 --- a/apps/web-antd/src/api/aiot/device/index.ts +++ b/apps/web-antd/src/api/video/device/index.ts @@ -1,22 +1,22 @@ /** - * AIoT 设备管理 API + * Video 模块 - 设备管理 API * * 所有请求通过 wvpRequestClient 发送到 WVP 视频平台后端, * 由 Vite 代理按路径分发并 rewrite: - * /aiot/device/proxy/* → WVP /api/proxy/* - * /aiot/device/user/* → WVP /api/user/* - * /aiot/device/server/* → WVP /api/server/media_server/* - * /aiot/device/* → WVP /api/ai/* + * /video/device/proxy/* → WVP /api/proxy/* + * /video/device/user/* → WVP /api/user/* + * /video/device/server/* → WVP /api/server/media_server/* + * /video/device/* → WVP /api/ai/* */ import { useAppConfig } from '@vben/hooks'; -import { getWvpToken, wvpRequestClient } from '#/api/aiot/request'; +import { getWvpToken, wvpRequestClient } from '#/api/video/request'; const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); // ==================== 类型定义 ==================== -export namespace AiotDeviceApi { +export namespace VideoDeviceApi { /** 分页响应结构 */ export interface PageResult { list: T[]; @@ -105,48 +105,48 @@ export function getCameraList(params: { query?: string; pulling?: boolean; }) { - return wvpRequestClient.get>( - '/aiot/device/proxy/list', + return wvpRequestClient.get>( + '/video/device/proxy/list', { params }, ); } /** 新增摄像头 */ -export function addCamera(data: Partial) { - return wvpRequestClient.post('/aiot/device/proxy/add', data); +export function addCamera(data: Partial) { + return wvpRequestClient.post('/video/device/proxy/add', data); } /** 编辑摄像头 */ -export function updateCamera(data: Partial) { - return wvpRequestClient.post('/aiot/device/proxy/update', data); +export function updateCamera(data: Partial) { + return wvpRequestClient.post('/video/device/proxy/update', data); } /** 保存摄像头(新增/编辑,有 id 为编辑) */ -export function saveCamera(data: Partial) { +export function saveCamera(data: Partial) { return data.id ? updateCamera(data) : addCamera(data); } /** 删除摄像头 */ export function deleteCamera(id: number) { - return wvpRequestClient.delete('/aiot/device/proxy/delete', { + return wvpRequestClient.delete('/video/device/proxy/delete', { params: { id }, }); } /** 开始拉流 */ export function startCamera(id: number) { - return wvpRequestClient.get('/aiot/device/proxy/start', { params: { id } }); + return wvpRequestClient.get('/video/device/proxy/start', { params: { id } }); } /** 停止拉流 */ export function stopCamera(id: number) { - return wvpRequestClient.get('/aiot/device/proxy/stop', { params: { id } }); + return wvpRequestClient.get('/video/device/proxy/stop', { params: { id } }); } /** 在线媒体服务器列表 */ export function getMediaServerList() { - return wvpRequestClient.get( - '/aiot/device/server/online/list', + return wvpRequestClient.get( + '/video/device/server/online/list', ); } @@ -154,7 +154,7 @@ export function getMediaServerList() { export function getCameraOptions() { return wvpRequestClient.get< { cameraCode: string; cameraName: string }[] - >('/aiot/device/camera/options'); + >('/video/device/camera/options'); } // ==================== ROI 区域管理 ==================== @@ -167,33 +167,33 @@ export function getRoiList(params: { deviceId?: string; query?: string; }) { - return wvpRequestClient.get>( - '/aiot/device/roi/list', + return wvpRequestClient.get>( + '/video/device/roi/list', { params }, ); } /** ROI 详情(含算法绑定) */ export function getRoiDetail(id: number) { - return wvpRequestClient.get(`/aiot/device/roi/${id}`); + return wvpRequestClient.get(`/video/device/roi/${id}`); } /** 某摄像头的所有 ROI */ export function getRoiByCameraId(cameraId: string) { - return wvpRequestClient.get( - '/aiot/device/roi/channel', + return wvpRequestClient.get( + '/video/device/roi/channel', { params: { cameraId } }, ); } /** 保存 ROI(新增/编辑) */ -export function saveRoi(data: Partial) { - return wvpRequestClient.post('/aiot/device/roi/save', data); +export function saveRoi(data: Partial) { + return wvpRequestClient.post('/video/device/roi/save', data); } /** 删除 ROI */ export function deleteRoi(roiId: string) { - return wvpRequestClient.delete(`/aiot/device/roi/delete/${roiId}`); + return wvpRequestClient.delete(`/video/device/roi/delete/${roiId}`); } /** @@ -207,15 +207,19 @@ export async function getSnapUrl(cameraCode: string, force = false): Promise( - '/aiot/device/algorithm/list', + return wvpRequestClient.get( + '/video/device/algorithm/list', { params: deviceId ? { deviceId } : {} }, ); } @@ -242,7 +246,7 @@ export function getAlgorithmList(deviceId?: string) { /** 保存算法全局参数 */ export function saveAlgoGlobalParams(algoCode: string, globalParams: string) { return wvpRequestClient.post( - `/aiot/device/algorithm/global-params/${algoCode}`, + `/video/device/algorithm/global-params/${algoCode}`, { globalParams }, ); } @@ -250,7 +254,7 @@ export function saveAlgoGlobalParams(algoCode: string, globalParams: string) { /** 批量更新设备算法参数 */ export function updateDeviceAlgoParams(deviceId: string, algoCode: string, params: string) { return wvpRequestClient.post( - `/aiot/device/algorithm/device-binds/${deviceId}/${algoCode}`, + `/video/device/algorithm/device-binds/${deviceId}/${algoCode}`, { params }, ); } @@ -259,12 +263,12 @@ export function updateDeviceAlgoParams(deviceId: string, algoCode: string, param /** 绑定算法到 ROI */ export function bindAlgo(data: { roiId: string; algoCode: string }) { - return wvpRequestClient.post('/aiot/device/roi/bindAlgo', data); + return wvpRequestClient.post('/video/device/roi/bindAlgo', data); } /** 解绑算法 */ export function unbindAlgo(bindId: string) { - return wvpRequestClient.delete('/aiot/device/roi/unbindAlgo', { + return wvpRequestClient.delete('/video/device/roi/unbindAlgo', { params: { bindId }, }); } @@ -275,14 +279,14 @@ export function updateAlgoParams(data: { params?: string; enabled?: number; }) { - return wvpRequestClient.post('/aiot/device/roi/updateAlgoParams', data); + return wvpRequestClient.post('/video/device/roi/updateAlgoParams', data); } // ==================== 配置推送 ==================== /** 推送配置到边缘端 */ export function pushConfig(cameraId: string) { - return wvpRequestClient.post('/aiot/device/config/push', null, { + return wvpRequestClient.post('/video/device/config/push', null, { params: { cameraId }, }); } @@ -290,14 +294,14 @@ export function pushConfig(cameraId: string) { /** 一次性推送全部配置到本地Edge */ export function pushAllConfig() { return wvpRequestClient.post>( - '/aiot/device/config/push-all', + '/video/device/config/push-all', ); } /** 导出摄像头配置 JSON */ export function exportConfig(cameraId: string) { return wvpRequestClient.get>( - '/aiot/device/config/export', + '/video/device/config/export', { params: { cameraId } }, ); } @@ -312,7 +316,7 @@ export async function getAlertImageUrl(imagePath: string): Promise { if (!imagePath) return ''; const token = await getWvpToken(); return ( - `${apiURL}/aiot/device/alert/image` + + `${apiURL}/video/device/alert/image` + `?imagePath=${encodeURIComponent(imagePath)}` + `&access-token=${encodeURIComponent(token)}` ); diff --git a/apps/web-antd/src/api/aiot/edge/index.ts b/apps/web-antd/src/api/video/edge/index.ts similarity index 67% rename from apps/web-antd/src/api/aiot/edge/index.ts rename to apps/web-antd/src/api/video/edge/index.ts index aa3169355..83b91602a 100644 --- a/apps/web-antd/src/api/aiot/edge/index.ts +++ b/apps/web-antd/src/api/video/edge/index.ts @@ -1,8 +1,8 @@ import type { PageParam, PageResult } from '@vben/request'; -import { wvpRequestClient } from '#/api/aiot/request'; +import { wvpRequestClient } from '#/api/video/request'; -export namespace AiotEdgeApi { +export namespace VideoEdgeApi { /** 边缘设备 VO */ export interface Device { id?: number; @@ -32,33 +32,33 @@ export namespace AiotEdgeApi { // ==================== 边缘设备 API ==================== // 数据源:WVP 数据库 wvp_ai_edge_device 表 -// 路径经 vite proxy: /admin-api/aiot/device/* → rewrite → /api/ai/* → WVP:18080 +// 路径经 vite proxy: /admin-api/video/device/* → rewrite → /api/ai/* → WVP:18080 /** 获取全部边缘设备列表 */ export function getDeviceList() { - return wvpRequestClient.get( - '/aiot/device/device/list', + return wvpRequestClient.get( + '/video/device/device/list', ); } /** 分页查询边缘设备列表 */ export function getDevicePage(params: PageParam) { - return wvpRequestClient.get>( - '/aiot/device/device/page', + return wvpRequestClient.get>( + '/video/device/device/page', { params }, ); } /** 获取设备详情 */ export function getDevice(deviceId: string) { - return wvpRequestClient.get('/aiot/device/device/get', { + return wvpRequestClient.get('/video/device/device/get', { params: { deviceId }, }); } /** 获取设备统计 */ export function getDeviceStatistics() { - return wvpRequestClient.get( - '/aiot/device/device/statistics', + return wvpRequestClient.get( + '/video/device/device/statistics', ); } diff --git a/apps/web-antd/src/api/aiot/request.ts b/apps/web-antd/src/api/video/request.ts similarity index 85% rename from apps/web-antd/src/api/aiot/request.ts rename to apps/web-antd/src/api/video/request.ts index 3ed7ee954..c46fad5f5 100644 --- a/apps/web-antd/src/api/aiot/request.ts +++ b/apps/web-antd/src/api/video/request.ts @@ -13,9 +13,17 @@ const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); // ==================== WVP Token 管理 ==================== -/** WVP 默认账号(开发环境使用,生产环境应通过环境变量配置) */ -const WVP_USERNAME = 'admin'; -const WVP_PASSWORD_MD5 = '21232f297a57a5a743894a0e4a801fc3'; // admin 的 MD5 +/** + * WVP 默认账号 + * + * 注意:前端任何 WVP 账号/密码都会打进 bundle,对懂行的人等于明文。 + * 长期方案应由后端代理 WVP 鉴权,不要把账号分发到客户端。 + * 作为过渡,至少走环境变量让生产可覆盖。 + */ +const WVP_USERNAME = import.meta.env.VITE_WVP_USERNAME || 'admin'; +const WVP_PASSWORD_MD5 = + import.meta.env.VITE_WVP_PASSWORD_MD5 || + '21232f297a57a5a743894a0e4a801fc3'; // 'admin' 的 MD5,仅作兜底 let wvpAccessToken: null | string = null; let tokenPromise: null | Promise = null; @@ -23,7 +31,7 @@ let tokenPromise: null | Promise = null; /** 登录 WVP 获取 access-token */ async function loginToWvp(): Promise { const url = - `${apiURL}/aiot/device/user/login` + + `${apiURL}/video/device/user/login` + `?username=${encodeURIComponent(WVP_USERNAME)}` + `&password=${encodeURIComponent(WVP_PASSWORD_MD5)}`; diff --git a/apps/web-antd/src/views/aiot/alarm/list/data.ts b/apps/web-antd/src/views/video/alarm/list/data.ts similarity index 98% rename from apps/web-antd/src/views/aiot/alarm/list/data.ts rename to apps/web-antd/src/views/video/alarm/list/data.ts index fbbdaaa16..cb93a2a05 100644 --- a/apps/web-antd/src/views/aiot/alarm/list/data.ts +++ b/apps/web-antd/src/views/video/alarm/list/data.ts @@ -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, diff --git a/apps/web-antd/src/views/aiot/alarm/list/index.vue b/apps/web-antd/src/views/video/alarm/list/index.vue similarity index 96% rename from apps/web-antd/src/views/aiot/alarm/list/index.vue rename to apps/web-antd/src/views/video/alarm/list/index.vue index f37949ed1..ba1c7bccf 100644 --- a/apps/web-antd/src/views/aiot/alarm/list/index.vue +++ b/apps/web-antd/src/views/video/alarm/list/index.vue @@ -1,6 +1,6 @@ diff --git a/apps/web-antd/src/views/aiot/alarm/summary/chart-options.ts b/apps/web-antd/src/views/video/alarm/summary/chart-options.ts similarity index 96% rename from apps/web-antd/src/views/aiot/alarm/summary/chart-options.ts rename to apps/web-antd/src/views/video/alarm/summary/chart-options.ts index 138e14839..97b568b6b 100644 --- a/apps/web-antd/src/views/aiot/alarm/summary/chart-options.ts +++ b/apps/web-antd/src/views/video/alarm/summary/chart-options.ts @@ -1,4 +1,4 @@ -import type { AiotAlarmApi } from '#/api/aiot/alarm'; +import type { VideoAlarmApi } from '#/api/video/alarm'; const TYPE_NAMES: Record = { leave_post: '离岗检测', @@ -29,7 +29,7 @@ const LEVEL_COLORS: Record = { }; /** 告警趋势折线图(每种类型独立一条线,都从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); diff --git a/apps/web-antd/src/views/aiot/alarm/summary/index.vue b/apps/web-antd/src/views/video/alarm/summary/index.vue similarity index 96% rename from apps/web-antd/src/views/aiot/alarm/summary/index.vue rename to apps/web-antd/src/views/video/alarm/summary/index.vue index 9ac2bc705..9f2c3bc9a 100644 --- a/apps/web-antd/src/views/aiot/alarm/summary/index.vue +++ b/apps/web-antd/src/views/video/alarm/summary/index.vue @@ -1,5 +1,5 @@