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: {