|
|
@@ -0,0 +1,242 @@
|
|
|
+<template>
|
|
|
+ <div class="ptz-overlay">
|
|
|
+ <div class="ptz-controls">
|
|
|
+ <!-- 8方向控制 -->
|
|
|
+ <div class="ptz-directions">
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('UP_LEFT')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><TopLeft /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('UP')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><Top /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('UP_RIGHT')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><TopRight /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('LEFT')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><Back /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div class="ptz-btn ptz-center">
|
|
|
+ <el-icon><Aim /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('RIGHT')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><Right /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('DOWN_LEFT')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><BottomLeft /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('DOWN')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><Bottom /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ptz-btn"
|
|
|
+ @mousedown="handleDirection('DOWN_RIGHT')"
|
|
|
+ @mouseup="handleDirectionStop"
|
|
|
+ @mouseleave="handleDirectionStop"
|
|
|
+ >
|
|
|
+ <el-icon><BottomRight /></el-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 垂直缩放滑块 -->
|
|
|
+ <div class="ptz-zoom">
|
|
|
+ <el-icon class="zoom-icon zoom-in"><ZoomIn /></el-icon>
|
|
|
+ <el-slider
|
|
|
+ v-model="zoomValue"
|
|
|
+ vertical
|
|
|
+ :min="-100"
|
|
|
+ :max="100"
|
|
|
+ :step="10"
|
|
|
+ :show-tooltip="false"
|
|
|
+ height="100px"
|
|
|
+ @input="handleZoomChange"
|
|
|
+ @change="handleZoomRelease"
|
|
|
+ />
|
|
|
+ <el-icon class="zoom-icon zoom-out"><ZoomOut /></el-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref } from 'vue'
|
|
|
+import {
|
|
|
+ Top,
|
|
|
+ Bottom,
|
|
|
+ Back,
|
|
|
+ Right,
|
|
|
+ TopLeft,
|
|
|
+ TopRight,
|
|
|
+ BottomLeft,
|
|
|
+ BottomRight,
|
|
|
+ Aim,
|
|
|
+ ZoomIn,
|
|
|
+ ZoomOut
|
|
|
+} from '@element-plus/icons-vue'
|
|
|
+import { startPTZ, stopPTZ, startZoom, stopZoom, type PTZConfig, type PTZDirectionKey } from '@/api/ptz'
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ cameraId?: string
|
|
|
+}
|
|
|
+
|
|
|
+const props = defineProps<Props>()
|
|
|
+
|
|
|
+const emit = defineEmits<{
|
|
|
+ 'ptz-action': [action: string, params?: unknown]
|
|
|
+}>()
|
|
|
+
|
|
|
+const zoomValue = ref(0)
|
|
|
+
|
|
|
+// 默认 PTZ 配置 (后续可以从摄像头配置中获取)
|
|
|
+const ptzConfig: PTZConfig = {
|
|
|
+ host: '192.168.0.64',
|
|
|
+ username: 'admin',
|
|
|
+ password: 'Wxc767718929'
|
|
|
+}
|
|
|
+
|
|
|
+const ptzSpeed = 50
|
|
|
+
|
|
|
+async function handleDirection(direction: PTZDirectionKey) {
|
|
|
+ emit('ptz-action', 'direction', { direction })
|
|
|
+ await startPTZ(ptzConfig, direction, ptzSpeed)
|
|
|
+}
|
|
|
+
|
|
|
+async function handleDirectionStop() {
|
|
|
+ emit('ptz-action', 'stop')
|
|
|
+ await stopPTZ(ptzConfig)
|
|
|
+}
|
|
|
+
|
|
|
+async function handleZoomChange(val: number) {
|
|
|
+ if (val === 0) {
|
|
|
+ await stopZoom(ptzConfig)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const direction = val > 0 ? 'IN' : 'OUT'
|
|
|
+ const speed = Math.abs(val)
|
|
|
+ emit('ptz-action', 'zoom', { direction, speed })
|
|
|
+ await startZoom(ptzConfig, direction, speed)
|
|
|
+}
|
|
|
+
|
|
|
+async function handleZoomRelease() {
|
|
|
+ zoomValue.value = 0
|
|
|
+ await stopZoom(ptzConfig)
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.ptz-overlay {
|
|
|
+ padding: 8px 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.ptz-controls {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.ptz-directions {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(3, 1fr);
|
|
|
+ gap: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.ptz-btn {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: rgba(255, 255, 255, 0.1);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
+ border-radius: var(--radius-base);
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s;
|
|
|
+ color: #fff;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: rgba(255, 255, 255, 0.2);
|
|
|
+ border-color: rgba(255, 255, 255, 0.4);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ background-color: var(--color-primary);
|
|
|
+ border-color: var(--color-primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-icon {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.ptz-center {
|
|
|
+ background-color: rgba(255, 255, 255, 0.05);
|
|
|
+ cursor: default;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: rgba(255, 255, 255, 0.05);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.ptz-zoom {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+
|
|
|
+ .zoom-icon {
|
|
|
+ color: #fff;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-slider) {
|
|
|
+ .el-slider__runway {
|
|
|
+ background-color: rgba(255, 255, 255, 0.2);
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-slider__bar {
|
|
|
+ background-color: var(--color-primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-slider__button {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ border: 2px solid var(--color-primary);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|