Kaynağa Gözat

update code

yb 18 saat önce
ebeveyn
işleme
56eae999ff

+ 4 - 14
src/api/camera.ts

@@ -10,7 +10,8 @@ import type {
   CameraAddRequest,
   CameraUpdateRequest,
   CameraListRequest,
-  SwitchChannelRequest
+  SwitchChannelRequest,
+  PTZAction
 } from '@/types'
 
 // ==================== Controller APIs ====================
@@ -57,19 +58,8 @@ export function getCurrentChannel(data: GetCurrentChannelRequest): Promise<IBase
 // stop: 停止
 export interface PTZControlRequest {
   cameraId: string
-  action:
-    | 'up'
-    | 'down'
-    | 'left'
-    | 'right'
-    | 'up_left'
-    | 'up_right'
-    | 'down_left'
-    | 'down_right'
-    | 'zoom_in'
-    | 'zoom_out'
-    | 'stop'
-  speed: number
+  action: PTZAction
+  speed?: number
 }
 
 export function ptzControl(data: PTZControlRequest): Promise<BaseResponse> {

+ 26 - 20
src/components/PTZController.vue

@@ -1,6 +1,7 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 import { ptzControl } from '@/api/camera'
+import type { PTZAction } from '@/types'
 
 const props = withDefaults(
   defineProps<{
@@ -16,24 +17,28 @@ const isMoving = ref(false)
 const currentDirection = ref<string | null>(null)
 
 // 方向映射
-const directionToCommand: Record<string, string> = {
-  UP: 'up',
-  DOWN: 'down',
-  LEFT: 'left',
-  RIGHT: 'right',
-  STOP: 'stop'
+const directionToAction: Record<string, PTZAction> = {
+  up: 'up',
+  down: 'down',
+  left: 'left',
+  right: 'right',
+  up_left: 'up_left',
+  up_right: 'up_right',
+  down_left: 'down_left',
+  down_right: 'down_right',
+  zoom_in: 'zoom_in',
+  zoom_out: 'zoom_out',
+  stop: 'stop'
 }
 
 // 开始移动
-async function handleStart(
-  direction: 'UP' | 'DOWN' | 'LEFT' | 'RIGHT' | 'UP_LEFT' | 'UP_RIGHT' | 'DOWN_LEFT' | 'DOWN_RIGHT'
-) {
+async function handleStart(direction: PTZAction) {
   if (isMoving.value || !props.cameraId) return
   isMoving.value = true
   currentDirection.value = direction
 
-  const command = directionToCommand[direction] || 'stop'
-  const result = await ptzControl({ cameraId: props.cameraId, command })
+  const command = directionToAction[direction]
+  const result = await ptzControl({ cameraId: props.cameraId, action: command })
   if (!result.success) {
     console.error('PTZ 控制失败:', result.errMsg)
   }
@@ -43,7 +48,7 @@ async function handleStart(
 async function handleStop() {
   if (!isMoving.value || !props.cameraId) return
 
-  const result = await ptzControl({ cameraId: props.cameraId, command: 'stop' })
+  const result = await ptzControl({ cameraId: props.cameraId, action: 'stop' })
   if (!result.success) {
     console.error('PTZ 停止失败:', result.errMsg)
   }
@@ -57,15 +62,15 @@ async function handleStop() {
   <div class="ptz-controller">
     <div class="ptz-grid">
       <!-- 第一行 -->
-      <button class="ptz-btn corner" @mousedown="handleStart('UP_LEFT')" @mouseup="handleStop" @mouseleave="handleStop">
+      <button class="ptz-btn corner" @mousedown="handleStart('up_left')" @mouseup="handleStop" @mouseleave="handleStop">
         <el-icon><i-ep-top-left /></el-icon>
       </button>
-      <button class="ptz-btn" @mousedown="handleStart('UP')" @mouseup="handleStop" @mouseleave="handleStop">
+      <button class="ptz-btn" @mousedown="handleStart('up')" @mouseup="handleStop" @mouseleave="handleStop">
         <el-icon><i-ep-arrow-up /></el-icon>
       </button>
       <button
         class="ptz-btn corner"
-        @mousedown="handleStart('UP_RIGHT')"
+        @mousedown="handleStart('up_right')"
         @mouseup="handleStop"
         @mouseleave="handleStop"
       >
@@ -73,32 +78,32 @@ async function handleStop() {
       </button>
 
       <!-- 第二行 -->
-      <button class="ptz-btn" @mousedown="handleStart('LEFT')" @mouseup="handleStop" @mouseleave="handleStop">
+      <button class="ptz-btn" @mousedown="handleStart('left')" @mouseup="handleStop" @mouseleave="handleStop">
         <el-icon><i-ep-arrow-left /></el-icon>
       </button>
       <div class="ptz-center">
         <el-icon v-if="isMoving" class="spinning"><i-ep-loading /></el-icon>
         <span v-else>PTZ</span>
       </div>
-      <button class="ptz-btn" @mousedown="handleStart('RIGHT')" @mouseup="handleStop" @mouseleave="handleStop">
+      <button class="ptz-btn" @mousedown="handleStart('right')" @mouseup="handleStop" @mouseleave="handleStop">
         <el-icon><i-ep-arrow-right /></el-icon>
       </button>
 
       <!-- 第三行 -->
       <button
         class="ptz-btn corner"
-        @mousedown="handleStart('DOWN_LEFT')"
+        @mousedown="handleStart('down_left')"
         @mouseup="handleStop"
         @mouseleave="handleStop"
       >
         <el-icon><i-ep-bottom-left /></el-icon>
       </button>
-      <button class="ptz-btn" @mousedown="handleStart('DOWN')" @mouseup="handleStop" @mouseleave="handleStop">
+      <button class="ptz-btn" @mousedown="handleStart('down')" @mouseup="handleStop" @mouseleave="handleStop">
         <el-icon><i-ep-arrow-down /></el-icon>
       </button>
       <button
         class="ptz-btn corner"
-        @mousedown="handleStart('DOWN_RIGHT')"
+        @mousedown="handleStart('down_right')"
         @mouseup="handleStop"
         @mouseleave="handleStop"
       >
@@ -169,6 +174,7 @@ async function handleStop() {
   from {
     transform: rotate(0deg);
   }
+
   to {
     transform: rotate(360deg);
   }

+ 50 - 25
src/components/monitor/PtzOverlay.vue

@@ -9,7 +9,9 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><TopLeft /></el-icon>
+          <el-icon>
+            <TopLeft />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -17,7 +19,9 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><Top /></el-icon>
+          <el-icon>
+            <Top />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -25,7 +29,9 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><TopRight /></el-icon>
+          <el-icon>
+            <TopRight />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -33,10 +39,14 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><Back /></el-icon>
+          <el-icon>
+            <Back />
+          </el-icon>
         </div>
         <div class="ptz-btn ptz-center">
-          <el-icon><Aim /></el-icon>
+          <el-icon>
+            <Aim />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -44,7 +54,9 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><Right /></el-icon>
+          <el-icon>
+            <Right />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -52,7 +64,9 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><BottomLeft /></el-icon>
+          <el-icon>
+            <BottomLeft />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -60,7 +74,9 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><Bottom /></el-icon>
+          <el-icon>
+            <Bottom />
+          </el-icon>
         </div>
         <div
           class="ptz-btn"
@@ -68,13 +84,17 @@
           @mouseup="handleDirectionStop"
           @mouseleave="handleDirectionStop"
         >
-          <el-icon><BottomRight /></el-icon>
+          <el-icon>
+            <BottomRight />
+          </el-icon>
         </div>
       </div>
 
       <!-- 垂直缩放滑块 -->
       <div class="ptz-zoom">
-        <el-icon class="zoom-icon zoom-in"><ZoomIn /></el-icon>
+        <el-icon class="zoom-icon zoom-in">
+          <ZoomIn />
+        </el-icon>
         <el-slider
           v-model="zoomValue"
           vertical
@@ -86,7 +106,9 @@
           @input="handleZoomChange"
           @change="handleZoomRelease"
         />
-        <el-icon class="zoom-icon zoom-out"><ZoomOut /></el-icon>
+        <el-icon class="zoom-icon zoom-out">
+          <ZoomOut />
+        </el-icon>
       </div>
     </div>
   </div>
@@ -108,6 +130,7 @@ import {
   ZoomOut
 } from '@element-plus/icons-vue'
 import { ptzControl } from '@/api/camera'
+import type { PTZAction } from '@/types'
 
 interface Props {
   cameraId?: string
@@ -126,35 +149,37 @@ const zoomValue = ref(0)
 const ptzSpeed = 50
 
 // 方向映射
-const directionToCommand: Record<string, string> = {
-  UP: 'up',
-  DOWN: 'down',
-  LEFT: 'left',
-  RIGHT: 'right',
-  UP_LEFT: 'up',
-  UP_RIGHT: 'up',
-  DOWN_LEFT: 'down',
-  DOWN_RIGHT: 'down',
-  STOP: 'stop'
+const directionToAction: Record<string, PTZAction> = {
+  up: 'up',
+  down: 'down',
+  left: 'left',
+  right: 'right',
+  up_left: 'up_left',
+  up_right: 'up_right',
+  down_left: 'down_left',
+  down_right: 'down_right',
+  zoom_in: 'zoom_in',
+  zoom_out: 'zoom_out',
+  stop: 'stop'
 }
 
 async function handleDirection(direction: string) {
   if (!props.cameraId) return
   emit('ptz-action', 'direction', { direction })
-  const command = directionToCommand[direction] || 'stop'
-  await ptzControl({ cameraId: props.cameraId, command, speed: ptzSpeed })
+  const command = directionToAction[direction]
+  await ptzControl({ cameraId: props.cameraId, action: command, speed: ptzSpeed })
 }
 
 async function handleDirectionStop() {
   if (!props.cameraId) return
   emit('ptz-action', 'stop')
-  await ptzControl({ cameraId: props.cameraId, command: 'stop' })
+  await ptzControl({ cameraId: props.cameraId, action: 'stop' })
 }
 
 async function handleZoomChange(val: number) {
   if (!props.cameraId) return
   if (val === 0) {
-    await ptzControl({ cameraId: props.cameraId, command: 'stop' })
+    await ptzControl({ cameraId: props.cameraId, action: 'stop' })
     return
   }
 

+ 17 - 14
src/views/demo/cloudflareStream.vue

@@ -223,6 +223,7 @@ import {
 } from '@element-plus/icons-vue'
 import VideoPlayer from '@/components/VideoPlayer.vue'
 import { ptzControl } from '@/api/camera'
+import type { PTZAction } from '@/types'
 
 const playerRef = ref<InstanceType<typeof VideoPlayer>>()
 
@@ -362,16 +363,18 @@ function onError(error: any) {
 }
 
 // PTZ 方向映射
-const directionToCommand: Record<string, string> = {
+const directionToCommand: Record<string, PTZAction> = {
   UP: 'up',
-  DOWN: 'down',
-  LEFT: 'left',
-  RIGHT: 'right',
-  UP_LEFT: 'up',
-  UP_RIGHT: 'up',
-  DOWN_LEFT: 'down',
-  DOWN_RIGHT: 'down',
-  STOP: 'stop'
+  down: 'down',
+  left: 'left',
+  right: 'right',
+  up_left: 'up_left',
+  up_right: 'up_right',
+  down_left: 'down_left',
+  down_right: 'down_right',
+  zoom_in: 'zoom_in',
+  zoom_out: 'zoom_out',
+  stop: 'stop'
 }
 
 // PTZ 控制
@@ -382,7 +385,7 @@ async function handlePTZ(direction: string) {
   }
 
   const command = directionToCommand[direction] || 'stop'
-  const result = await ptzControl({ cameraId: ptzCameraId.value, command, speed: ptzSpeed.value })
+  const result = await ptzControl({ cameraId: ptzCameraId.value, action: command, speed: ptzSpeed.value })
 
   if (result.success) {
     addLog(`PTZ 移动: ${direction} (速度: ${ptzSpeed.value})`, 'info')
@@ -394,7 +397,7 @@ async function handlePTZ(direction: string) {
 async function handlePTZStop() {
   if (!ptzCameraId.value) return
 
-  const result = await ptzControl({ cameraId: ptzCameraId.value, command: 'stop' })
+  const result = await ptzControl({ cameraId: ptzCameraId.value, action: 'stop' })
 
   if (!result.success) {
     addLog(`PTZ 停止失败: ${result.errMsg}`, 'error')
@@ -411,20 +414,20 @@ async function handleZoomChange(val: number) {
   if (!ptzCameraId.value) return
 
   if (val === 0) {
-    await ptzControl({ cameraId: ptzCameraId.value, command: 'stop' })
+    await ptzControl({ cameraId: ptzCameraId.value, action: 'stop' })
     return
   }
 
   const command = val > 0 ? 'zoom_in' : 'zoom_out'
   const speed = Math.abs(val)
-  await ptzControl({ cameraId: ptzCameraId.value, command, speed })
+  await ptzControl({ cameraId: ptzCameraId.value, action: command, speed })
 }
 
 async function handleZoomRelease() {
   zoomValue.value = 0
   if (!ptzCameraId.value) return
 
-  await ptzControl({ cameraId: ptzCameraId.value, command: 'stop' })
+  await ptzControl({ cameraId: ptzCameraId.value, action: 'stop' })
   addLog('缩放停止', 'info')
 }
 </script>

+ 6 - 6
src/views/live-stream/composables/usePTZ.ts

@@ -74,7 +74,7 @@ export function usePTZ(
     const cameraId = currentMediaStream.value?.cameraId
     if (!cameraId) return
     try {
-      await ptzControl({ cameraId, command: 'stop' })
+      await ptzControl({ cameraId, action: 'stop' })
     } catch (error) {
       console.error('PTZ 停止失败', error)
     }
@@ -89,18 +89,18 @@ export function usePTZ(
     const cameraId = currentMediaStream.value?.cameraId
     if (!cameraId) return
     if (val === 0) {
-      await ptzControl({ cameraId, command: 'stop' })
+      await ptzControl({ cameraId, action: 'stop' })
       return
     }
     const command = val > 0 ? 'zoom_in' : 'zoom_out'
-    await ptzControl({ cameraId, command, speed: Math.abs(val) })
+    await ptzControl({ cameraId, action: command, speed: Math.abs(val) })
   }
 
   async function handleZoomRelease() {
     zoomValue.value = 0
     const cameraId = currentMediaStream.value?.cameraId
     if (!cameraId) return
-    await ptzControl({ cameraId, command: 'stop' })
+    await ptzControl({ cameraId, action: 'stop' })
   }
 
   async function handleZoomIn() {
@@ -110,7 +110,7 @@ export function usePTZ(
       return
     }
     try {
-      const res = await ptzControl({ cameraId, command: 'zoom_in', speed: ptzSpeed.value })
+      const res = await ptzControl({ cameraId, action: 'zoom_in', speed: ptzSpeed.value })
       if (!res.success) console.error('Zoom in 失败', res.errMsg)
     } catch (error) {
       console.error('Zoom in 失败', error)
@@ -124,7 +124,7 @@ export function usePTZ(
       return
     }
     try {
-      const res = await ptzControl({ cameraId, command: 'zoom_out', speed: ptzSpeed.value })
+      const res = await ptzControl({ cameraId, action: 'zoom_out', speed: ptzSpeed.value })
       if (!res.success) console.error('Zoom out 失败', res.errMsg)
     } catch (error) {
       console.error('Zoom out 失败', error)

+ 3 - 2
tests/unit/api/camera.spec.ts

@@ -10,7 +10,8 @@ import {
   adminAddCamera,
   adminUpdateCamera,
   adminDeleteCamera,
-  adminCheckCamera
+  adminCheckCamera,
+  type PTZControlRequest
 } from '@/api/camera'
 import * as request from '@/utils/request'
 import { mockCameras, mockChannels, wrapResponse } from '../../fixtures'
@@ -92,7 +93,7 @@ describe('Camera API', () => {
         const mockResponse = wrapResponse(null)
         vi.mocked(request.post).mockResolvedValue(mockResponse)
 
-        const data = { cameraId: 'cam-001', command: 'up', speed: 50 }
+        const data: PTZControlRequest = { cameraId: 'cam-001', action: 'up', speed: 50 }
         await ptzControl(data)
 
         expect(request.post).toHaveBeenCalledWith('/camera/control/cam-001/ptz/control', data)