diff --git a/web/package.json b/web/package.json index 2af4ff2..2b6aa1a 100644 --- a/web/package.json +++ b/web/package.json @@ -11,6 +11,7 @@ "dependencies": { "@element-plus/icons-vue": "^2.3.1", "@kjgl77/datav-vue3": "^1.7.4", + "axios": "^1.11.0", "echarts": "^5.6.0", "echarts-liquidfill": "^3.1.0", "element-plus": "^2.10.4", diff --git a/web/src/App.vue b/web/src/App.vue index 9288dd4..e5b1e28 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -23,12 +23,17 @@
- +
- - + +
@@ -80,13 +85,57 @@ import AlgorithmCenter from './components/algorithm/AlgorithmCenter.vue' import AlarmManagement from './components/alarm/AlarmManagement.vue' import EventCenter from './components/event/EventCenter.vue' import DeviceManagement from './components/device/DeviceManagement.vue' - +import API from '@/api/index' const activeTab = ref('overview') const dashboardContainer = ref(null) const isFullscreen = ref(false) const showMonitorDetail = ref(false) +const cameraStats = ref({ + total_cameras: 0, + online_cameras: 0, + offline_cameras: 0, + by_location: [] +}) + +const algorithmStats = ref({ + total_algorithms: 0, + active_algorithms: 0, + by_type: [] +}) + +// 获取摄像头统计数据 +const fetchCameraStats = async () => { + try { + const response = await API.getCameraStats() + cameraStats.value = response + } catch (error) { + console.error('获取摄像头统计数据失败:', error) + cameraStats.value = { + total_cameras: 0, + online_cameras: 0, + offline_cameras: 0, + by_location: [] + } + } +} + +// 获取算法统计数据 +const fetchAlgorithmStats = async () => { + try { + const response = await API.getAlgorithmStats() + algorithmStats.value = response + } catch (error) { + console.error('获取算法统计数据失败:', error) + algorithmStats.value = { + total_algorithms: 0, + active_algorithms: 0, + by_type: [] + } + } +} + const currentMonitor = ref({ id: 1, name: '港口区主监控', @@ -94,91 +143,95 @@ const currentMonitor = ref({ status: 'online', videoSrc: '/videos/port-main.mp4' }) +const monitors = ref([]) +// const monitors = ref([ +// { +// id: 1, +// name: '港口区监控1', +// location: '港口A区', +// status: 'online', +// videoSrc: '/videos/port-1.mp4', +// detections: [ +// { type: 'person', x: 25, y: 35, width: 40, height: 80 } +// ] +// }, +// { +// id: 2, +// name: '港口区监控2', +// location: '港口B区', +// status: 'online', +// videoSrc: '/videos/port-2.mp4', +// detections: [ +// { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } +// ] +// }, +// { +// id: 3, +// name: '港口区监控2', +// location: '港口B区', +// status: 'online', +// videoSrc: '/videos/port-2.mp4', +// detections: [ +// { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } +// ] +// }, +// { +// id: 4, +// name: '港口区监控2', +// location: '港口B区', +// status: 'online', +// videoSrc: '/videos/port-2.mp4', +// detections: [ +// { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } +// ] +// }, +// { +// id: 5, +// name: '港口区监控1', +// location: '港口A区', +// status: 'online', +// videoSrc: '/videos/port-1.mp4', +// detections: [ +// { type: 'person', x: 25, y: 35, width: 40, height: 80 } +// ] +// }, +// { +// id: 6, +// name: '港口区监控2', +// location: '港口B区', +// status: 'online', +// videoSrc: '/videos/port-2.mp4', +// detections: [ +// { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } +// ] +// }, +// { +// id: 7, +// name: '港口区监控2', +// location: '港口B区', +// status: 'online', +// videoSrc: '/videos/port-2.mp4', +// detections: [ +// { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } +// ] +// }, +// { +// id: 8, +// name: '港口区监控2', +// location: '港口B区', +// status: 'online', +// videoSrc: '/videos/port-2.mp4', +// detections: [ +// { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } +// ] +// }, -const monitors = ref([ - { - id: 1, - name: '港口区监控1', - location: '港口A区', - status: 'online', - videoSrc: '/videos/port-1.mp4', - detections: [ - { type: 'person', x: 25, y: 35, width: 40, height: 80 } - ] - }, - { - id: 2, - name: '港口区监控2', - location: '港口B区', - status: 'online', - videoSrc: '/videos/port-2.mp4', - detections: [ - { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } - ] - }, - { - id: 3, - name: '港口区监控2', - location: '港口B区', - status: 'online', - videoSrc: '/videos/port-2.mp4', - detections: [ - { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } - ] - }, - { - id: 4, - name: '港口区监控2', - location: '港口B区', - status: 'online', - videoSrc: '/videos/port-2.mp4', - detections: [ - { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } - ] - }, - { - id: 5, - name: '港口区监控1', - location: '港口A区', - status: 'online', - videoSrc: '/videos/port-1.mp4', - detections: [ - { type: 'person', x: 25, y: 35, width: 40, height: 80 } - ] - }, - { - id: 6, - name: '港口区监控2', - location: '港口B区', - status: 'online', - videoSrc: '/videos/port-2.mp4', - detections: [ - { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } - ] - }, - { - id: 7, - name: '港口区监控2', - location: '港口B区', - status: 'online', - videoSrc: '/videos/port-2.mp4', - detections: [ - { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } - ] - }, - { - id: 8, - name: '港口区监控2', - location: '港口B区', - status: 'online', - videoSrc: '/videos/port-2.mp4', - detections: [ - { type: 'vehicle', x: 40, y: 50, width: 80, height: 60 } - ] - }, - -]) - +// ]) +// 获取列表 +const getMonitorsList = async () => { + const list = await API.getMonitorsList() + monitors.value = list.monitors || [] +} // 切换标签 const handleTabChange = (tab) => { @@ -217,6 +270,9 @@ const handleFullscreenChange = () => { // 添加事件监听 onMounted(() => { + getMonitorsList() + fetchCameraStats() + fetchAlgorithmStats() document.addEventListener('fullscreenchange', handleFullscreenChange) }) diff --git a/web/src/api/index.js b/web/src/api/index.js index 4e91c46..b29b9e2 100644 --- a/web/src/api/index.js +++ b/web/src/api/index.js @@ -1,11 +1,89 @@ import http from '../utils/http' export default { - login(username, password) { - return http.post('/user/login', { username, password }) + getKpi() { + return http.get('/dashboard/kpi') }, - - getInfo() { - return http.get('/user/info') - } + + getAlarmTrend() { + return http.get('/dashboard/alarm-trend') + }, + + getCameraStats() { + return http.get('/dashboard/camera-stats') + }, + + getAlgorithmStats() { + return http.get('/dashboard/algorithm-stats') + }, + + getMonitorsList(params) { + return http.get('/monitors/', params) + }, + getMonitorsDetail(monitor_id) { + return http.get(`/api/monitors/${monitor_id}`) + }, + // 获取场景列表 + getScenesList(params) { + return http.get('/scenes/', params) + }, + + // 添加场景 + addScenes(data) { + return http.post('/scenes/', data) + }, + + + /** + * 设备管理接口 + */ + + // 添加设备 + addDevices(data) { + return http.post('/devices/', data) + }, + // 获取设备列表 + getDevices(params) { + return http.get('/devices/', params) + }, + + /** + * 上传视频文件 + */ + + /** + * 上传视频文件(二进制格式) + * @param {File} file - 视频文件 + * @param {string} deviceId - 设备ID + * @param {string} [description] - 视频描述 + * @returns {Promise} + */ + uploadVideo (file, deviceId, description = '') { + return new Promise((resolve, reject) => { + const reader = new FileReader() + + // 读取文件为二进制字符串 + reader.readAsBinaryString(file) + + reader.onload = () => { + const binaryString = reader.result + + request({ + url: '/upload/video', + method: 'post', + data: { + file: binaryString, // 二进制字符串 + device_id: deviceId, + description: description + }, + headers: { + 'Content-Type': 'application/json' // 使用JSON格式 + } + }).then(resolve).catch(reject) + } + + reader.onerror = error => reject(error) + }) +} + } \ No newline at end of file diff --git a/web/src/components/AlarmTrend.vue b/web/src/components/AlarmTrend.vue index eda8be7..c7df3b3 100644 --- a/web/src/components/AlarmTrend.vue +++ b/web/src/components/AlarmTrend.vue @@ -10,12 +10,57 @@ \ No newline at end of file diff --git a/web/src/utils/http.js b/web/src/utils/http.js index d460686..87690a7 100644 --- a/web/src/utils/http.js +++ b/web/src/utils/http.js @@ -1,5 +1,5 @@ // src/utils/http.js -import axios from '../config/service' // 基础配置 +import axios from './service' // 基础配置 /** * 高级请求封装 diff --git a/web/src/utils/service.js b/web/src/utils/service.js index 1e71d05..808d361 100644 --- a/web/src/utils/service.js +++ b/web/src/utils/service.js @@ -2,7 +2,7 @@ import axios from 'axios'; // 创建 Axios 实例 const service = axios.create({ - baseURL: import.meta.env.VITE_API_BASE_URL || '/api', // 从环境变量读取 + baseURL: '/api', // 从环境变量读取 timeout: 10000, // 请求超时时间 }); diff --git a/web/vite.config.js b/web/vite.config.js index 69c20ad..1b67ad7 100644 --- a/web/vite.config.js +++ b/web/vite.config.js @@ -7,7 +7,13 @@ export default defineConfig({ server: { host: '0.0.0.0', // 监听所有网络接口 port: 5173, // 默认端口 - strictPort: true // 如果端口被占用则退出 + strictPort: true, // 如果端口被占用则退出 + proxy: { + '/api': { + target: 'http://36.103.203.89:6789', + changeOrigin: true, + } + } }, resolve: { alias: {