|
@@ -0,0 +1,769 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <!-- 设备控制组件:左侧面板下方,包含设备选择、云台控制、扫描/调色模式、红外选项等 -->
|
|
|
|
|
+ <div class="device-control">
|
|
|
|
|
+ <!-- 控制设备下拉选择 -->
|
|
|
|
|
+ <div class="device-select-row">
|
|
|
|
|
+ <span class="select-label">控制设备</span>
|
|
|
|
|
+ <div class="device-select" @click.stop="toggleDeviceMenu">
|
|
|
|
|
+ <span class="select-text" :title="currentDevice">{{ currentDevice }}</span>
|
|
|
|
|
+ <span :class="['select-arrow', { open: deviceMenuOpen }]">
|
|
|
|
|
+ <svg viewBox="0 0 10 10" width="10" height="10">
|
|
|
|
|
+ <path d="M1 3.2 L5 7.2 L9 3.2" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"
|
|
|
|
|
+ stroke-linejoin="round" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <ul v-if="deviceMenuOpen" class="select-dropdown" @click.stop>
|
|
|
|
|
+ <li v-for="item in deviceOptions" :key="item.value" :class="{ active: item.label=== currentDevice }"
|
|
|
|
|
+ @click="selectDevice(item)">
|
|
|
|
|
+ {{ item.label }}
|
|
|
|
|
+ </li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 功能 Tab -->
|
|
|
|
|
+ <div class="control-tabs">
|
|
|
|
|
+ <div v-for="tab in tabsPtz" :key="tab.key" :class="['tab-item', { active: activeTab === tab.key }]"
|
|
|
|
|
+ @click="activeTab = tab.key">
|
|
|
|
|
+ {{ tab.label }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 云台控制主体 -->
|
|
|
|
|
+ <div class="ptz-panel">
|
|
|
|
|
+ <!-- 左侧:变焦 / 聚焦 / 光圈 -->
|
|
|
|
|
+ <div class="lens-controls">
|
|
|
|
|
+ <div v-for="row in lensControls" :key="row.key" class="lens-row">
|
|
|
|
|
+ <button class="lens-btn" type="button" @mousedown="emitAction(row.key, 'plus')"
|
|
|
|
|
+ @mouseup="emitAction(row.key, 'stop')" @mouseleave="emitAction(row.key, 'stop')">+</button>
|
|
|
|
|
+ <span class="lens-icon" v-html="row.icon"></span>
|
|
|
|
|
+ <button class="lens-btn" type="button" @mousedown="emitAction(row.key, 'minus')"
|
|
|
|
|
+ @mouseup="emitAction(row.key, 'stop')" @mouseleave="emitAction(row.key, 'stop')">−</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 右侧:方向盘 -->
|
|
|
|
|
+ <div class="direction-pad">
|
|
|
|
|
+ <button class="dir-btn up" type="button" @mousedown="emitAction('pan', 'up')"
|
|
|
|
|
+ @mouseup="emitAction('pan', 'stop')" @mouseleave="emitAction('pan', 'stop')" aria-label="上">
|
|
|
|
|
+ <span class="dir-arrow"></span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button class="dir-btn left" type="button" @mousedown="emitAction('pan', 'left')"
|
|
|
|
|
+ @mouseup="emitAction('pan', 'stop')" @mouseleave="emitAction('pan', 'stop')" aria-label="左">
|
|
|
|
|
+ <span class="dir-arrow"></span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button class="dir-btn right" type="button" @mousedown="emitAction('pan', 'right')"
|
|
|
|
|
+ @mouseup="emitAction('pan', 'stop')" @mouseleave="emitAction('pan', 'stop')" aria-label="右">
|
|
|
|
|
+ <span class="dir-arrow"></span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button class="dir-btn down" type="button" @mousedown="emitAction('pan', 'down')"
|
|
|
|
|
+ @mouseup="emitAction('pan', 'stop')" @mouseleave="emitAction('pan', 'stop')" aria-label="下">
|
|
|
|
|
+ <span class="dir-arrow"></span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <div class="pad-center"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 速度 -->
|
|
|
|
|
+ <div class="param-row speed-row">
|
|
|
|
|
+ <span class="param-label">速度:</span>
|
|
|
|
|
+ <div class="speed-slider">
|
|
|
|
|
+ <input v-model.number="speed" type="range" min="0" max="100" />
|
|
|
|
|
+ <div class="slider-track">
|
|
|
|
|
+ <div class="slider-fill" :style="{ width: speed + '%' }"></div>
|
|
|
|
|
+ <div class="slider-thumb" :style="{ left: speed + '%' }"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="speed-value">{{ speed }}%</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 扫描模式 / 调色模式 -->
|
|
|
|
|
+ <div class="param-row mode-row">
|
|
|
|
|
+ <span class="param-label">扫描模式:</span>
|
|
|
|
|
+ <div class="mode-select" @click.stop="toggleMenu('scan')">
|
|
|
|
|
+ <span class="mode-value">{{ scanMode || '' }}</span>
|
|
|
|
|
+ <span class="mode-line"></span>
|
|
|
|
|
+ <span :class="['mode-arrow', { open: openMenu === 'scan' }]">▼</span>
|
|
|
|
|
+ <ul v-if="openMenu === 'scan'" class="mode-dropdown" @click.stop>
|
|
|
|
|
+ <li v-for="item in scanModes" :key="item" @click="pickMode('scan', item)">{{ item }}</li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="param-row mode-row">
|
|
|
|
|
+ <span class="param-label">调色模式:</span>
|
|
|
|
|
+ <div class="mode-select" @click.stop="toggleMenu('color')">
|
|
|
|
|
+ <span class="mode-value">{{ colorMode || '' }}</span>
|
|
|
|
|
+ <span class="mode-line"></span>
|
|
|
|
|
+ <span :class="['mode-arrow', { open: openMenu === 'color' }]">▼</span>
|
|
|
|
|
+ <ul v-if="openMenu === 'color'" class="mode-dropdown" @click.stop>
|
|
|
|
|
+ <li v-for="item in colorModes" :key="item" @click="pickMode('color', item)">{{ item }}</li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 底部勾选 -->
|
|
|
|
|
+ <div class="footer-checks">
|
|
|
|
|
+ <label class="check-item">
|
|
|
|
|
+ <input v-model="irZoom" type="checkbox" />
|
|
|
|
|
+ <span class="check-box">
|
|
|
|
|
+ <svg v-if="irZoom" viewBox="0 0 12 12" width="10" height="10">
|
|
|
|
|
+ <path d="M2 6.2 L4.8 9 L10 3.2" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round"
|
|
|
|
|
+ stroke-linejoin="round" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="check-label">红外变倍</span>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ <label class="check-item">
|
|
|
|
|
+ <input v-model="irControl" type="checkbox" />
|
|
|
|
|
+ <span class="check-box">
|
|
|
|
|
+ <svg v-if="irControl" viewBox="0 0 12 12" width="10" height="10">
|
|
|
|
|
+ <path d="M2 6.2 L4.8 9 L10 3.2" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round"
|
|
|
|
|
+ stroke-linejoin="round" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="check-label">红外控制</span>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
|
+import { onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
|
|
+import { tabsPtz, lensControls } from '../hsqHome.data'
|
|
|
|
|
+
|
|
|
|
|
+let props=defineProps({
|
|
|
|
|
+ deviceOptions: {
|
|
|
|
|
+ type: Array as PropType<any[]>,
|
|
|
|
|
+ default: () => []
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+/** 组件自定义事件 */
|
|
|
|
|
+const emit = defineEmits<{
|
|
|
|
|
+ (e: 'deviceChange', device: string): void
|
|
|
|
|
+ (e: 'tabChange', key: string): void
|
|
|
|
|
+ (e: 'action', payload: { type: string; value: string }): void
|
|
|
|
|
+ (e: 'speedChange', value: number): void
|
|
|
|
|
+ (e: 'scanModeChange', value: string): void
|
|
|
|
|
+ (e: 'colorModeChange', value: string): void
|
|
|
|
|
+ (e: 'optionChange', payload: { irZoom: boolean; irControl: boolean }): void
|
|
|
|
|
+}>()
|
|
|
|
|
+
|
|
|
|
|
+/** 当前选中的设备 */
|
|
|
|
|
+const currentDevice = ref('')
|
|
|
|
|
+/** 设备下拉菜单是否展开 */
|
|
|
|
|
+const deviceMenuOpen = ref(false)
|
|
|
|
|
+/** 当前激活的功能 Tab */
|
|
|
|
|
+const activeTab = ref('ptz')
|
|
|
|
|
+/** 云台控制速度(0-100) */
|
|
|
|
|
+const speed = ref(28)
|
|
|
|
|
+/** 当前扫描模式 */
|
|
|
|
|
+const scanMode = ref('')
|
|
|
|
|
+/** 当前调色模式 */
|
|
|
|
|
+const colorMode = ref('')
|
|
|
|
|
+/** 当前展开的下拉菜单(扫描/调色/无) */
|
|
|
|
|
+const openMenu = ref<'scan' | 'color' | ''>('')
|
|
|
|
|
+/** 红外变倍开关 */
|
|
|
|
|
+const irZoom = ref(true)
|
|
|
|
|
+/** 红外控制开关 */
|
|
|
|
|
+const irControl = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+/** 扫描模式选项 */
|
|
|
|
|
+const scanModes = ['自动扫描', '水平扫描', '垂直扫描', '关闭']
|
|
|
|
|
+/** 调色模式选项 */
|
|
|
|
|
+const colorModes = ['白热', '黑热', '彩虹', '铁红']
|
|
|
|
|
+
|
|
|
|
|
+/** 发送操作指令(云台方向/镜头控制等) */
|
|
|
|
|
+function emitAction(type: string, value: string) {
|
|
|
|
|
+ emit('action', { type, value })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 切换设备下拉菜单的展开/收起 */
|
|
|
|
|
+function toggleDeviceMenu() {
|
|
|
|
|
+ deviceMenuOpen.value = !deviceMenuOpen.value
|
|
|
|
|
+ openMenu.value = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 选择设备,关闭菜单并触发 deviceChange 事件 */
|
|
|
|
|
+function selectDevice(item) {
|
|
|
|
|
+ currentDevice.value = item.label
|
|
|
|
|
+ deviceMenuOpen.value = false
|
|
|
|
|
+ emit('deviceChange', item)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 切换扫描/调色模式下拉菜单(互斥展开) */
|
|
|
|
|
+function toggleMenu(key: 'scan' | 'color') {
|
|
|
|
|
+ openMenu.value = openMenu.value === key ? '' : key
|
|
|
|
|
+ deviceMenuOpen.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 选择扫描/调色模式并触发对应事件 */
|
|
|
|
|
+function pickMode(type: 'scan' | 'color', value: string) {
|
|
|
|
|
+ if (type === 'scan') {
|
|
|
|
|
+ scanMode.value = value
|
|
|
|
|
+ emit('scanModeChange', value)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ colorMode.value = value
|
|
|
|
|
+ emit('colorModeChange', value)
|
|
|
|
|
+ }
|
|
|
|
|
+ openMenu.value = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 点击页面其他区域时关闭所有下拉菜单 */
|
|
|
|
|
+function onDocClick() {
|
|
|
|
|
+ deviceMenuOpen.value = false
|
|
|
|
|
+ openMenu.value = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 监听 Tab 切换 */
|
|
|
|
|
+watch(activeTab, (key) => emit('tabChange', key))
|
|
|
|
|
+/** 监听速度变化 */
|
|
|
|
|
+watch(speed, (val) => emit('speedChange', val))
|
|
|
|
|
+/** 监听红外选项变化 */
|
|
|
|
|
+watch([irZoom, irControl], () => {
|
|
|
|
|
+ emit('optionChange', { irZoom: irZoom.value, irControl: irControl.value })
|
|
|
|
|
+})
|
|
|
|
|
+watch(() => props.deviceOptions, (newVal) => {
|
|
|
|
|
+ if(newVal.length > 0){
|
|
|
|
|
+ currentDevice.value = newVal[0].label
|
|
|
|
|
+ }
|
|
|
|
|
+},{immediate: true})
|
|
|
|
|
+
|
|
|
|
|
+/** 挂载时注册全局点击关闭事件 */
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ document.addEventListener('click', onDocClick)
|
|
|
|
|
+})
|
|
|
|
|
+/** 卸载时移除全局点击事件 */
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ document.removeEventListener('click', onDocClick)
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="less" scoped>
|
|
|
|
|
+@import '/@/design/theme.less';
|
|
|
|
|
+
|
|
|
|
|
+// 设备控制主容器
|
|
|
|
|
+.device-control {
|
|
|
|
|
+ --image-bg: url('@/assets/images/home-container/configurable/hsq/2-6.png');
|
|
|
|
|
+ --image-bg1: url('@/assets/images/home-container/configurable/hsq/7-3.png');
|
|
|
|
|
+ --image-bg2: url('@/assets/images/home-container/configurable/hsq/7-4.png');
|
|
|
|
|
+ --dc-accent: #00b7ff;
|
|
|
|
|
+ --dc-accent-soft: rgba(0, 183, 255, 0.35);
|
|
|
|
|
+ --dc-text: #eaf6ff;
|
|
|
|
|
+ --dc-muted: #8ea8c0;
|
|
|
|
|
+ --dc-panel: rgba(4, 28, 55, 0.55);
|
|
|
|
|
+ --dc-glow: 0 0 8px rgba(0, 183, 255, 0.45);
|
|
|
|
|
+
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ color: var(--dc-text);
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ user-select: none;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 设备下拉选择行
|
|
|
|
|
+.device-select-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+
|
|
|
|
|
+ .select-label {
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 自定义下拉选择框
|
|
|
|
|
+ .device-select {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 38px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 0 28px 0 14px;
|
|
|
|
|
+ background: var(--image-bg) no-repeat;
|
|
|
|
|
+ background-size: 100% 100%;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ .select-text {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 下拉箭头
|
|
|
|
|
+ .select-arrow {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ right: 20px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ transition: transform 0.2s;
|
|
|
|
|
+
|
|
|
|
|
+ &.open {
|
|
|
|
|
+ transform: rotate(180deg);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 下拉菜单
|
|
|
|
|
+ .select-dropdown {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ top: calc(100% + 2px);
|
|
|
|
|
+ z-index: 20;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ padding: 4px 0;
|
|
|
|
|
+ list-style: none;
|
|
|
|
|
+ background: #0a1f3a;
|
|
|
|
|
+ border: 1px solid var(--dc-accent);
|
|
|
|
|
+ box-shadow: var(--dc-glow);
|
|
|
|
|
+ max-height: 140px;
|
|
|
|
|
+ overflow: auto;
|
|
|
|
|
+
|
|
|
|
|
+ li {
|
|
|
|
|
+ padding: 6px 10px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #cfe9ff;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover,
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ background: rgba(0, 183, 255, 0.2);
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 功能 Tab 切换栏(云台控制/红外控制/激光/透雾)
|
|
|
|
|
+.control-tabs {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: stretch;
|
|
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ background-color: #15517b;
|
|
|
|
|
+
|
|
|
|
|
+ .tab-item {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 26px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ color: #7f9bb5;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ transition: color 0.2s, background 0.2s;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #d7efff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ background-color: #1d73a8;
|
|
|
|
|
+
|
|
|
|
|
+ &::after {
|
|
|
|
|
+ content: '';
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: -1px;
|
|
|
|
|
+ height: 2px;
|
|
|
|
|
+ background: #36c7ff;
|
|
|
|
|
+ box-shadow: 0 0 8px rgba(78, 200, 255, 0.85);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 云台控制面板(镜头控制 + 方向键)
|
|
|
|
|
+.ptz-panel {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+ padding: 10px 14px;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ background: var(--image-bg1) no-repeat;
|
|
|
|
|
+ background-size: 100% 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 镜头控制区域(变焦/聚焦/光圈)
|
|
|
|
|
+.lens-controls {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ max-width: 180px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 单行镜头控制(+ 按钮 / 图标 / - 按钮)
|
|
|
|
|
+.lens-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ height: 28px;
|
|
|
|
|
+ padding: 0 10px;
|
|
|
|
|
+ background: var(--image-bg2) no-repeat;
|
|
|
|
|
+ background-size: 100% 100%;
|
|
|
|
|
+
|
|
|
|
|
+ .lens-btn {
|
|
|
|
|
+ width: 22px;
|
|
|
|
|
+ height: 22px;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ text-shadow: 0 0 6px rgba(0, 200, 255, 0.6);
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: var(--dc-accent);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ transform: scale(0.92);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .lens-icon {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ filter: drop-shadow(0 0 3px rgba(0, 200, 255, 0.55));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 云台方向键(圆形方向盘)
|
|
|
|
|
+.direction-pad {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 108px;
|
|
|
|
|
+ height: 108px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ background: radial-gradient(circle at center, rgba(10, 40, 75, 0.95) 0%, rgba(4, 22, 48, 0.98) 70%);
|
|
|
|
|
+ border: 1px solid rgba(0, 183, 255, 0.35);
|
|
|
|
|
+ box-shadow: inset 0 0 18px rgba(0, 80, 140, 0.45), 0 0 8px rgba(0, 183, 255, 0.2);
|
|
|
|
|
+
|
|
|
|
|
+ // 方向盘中心圆点
|
|
|
|
|
+ .pad-center {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 50%;
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ width: 28px;
|
|
|
|
|
+ height: 28px;
|
|
|
|
|
+ margin: -14px 0 0 -14px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ background: rgba(0, 40, 70, 0.8);
|
|
|
|
|
+ border: 1px solid rgba(0, 183, 255, 0.25);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 方向按钮通用样式
|
|
|
|
|
+ .dir-btn {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ width: 36px;
|
|
|
|
|
+ height: 36px;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+
|
|
|
|
|
+ .dir-arrow {
|
|
|
|
|
+ width: 0;
|
|
|
|
|
+ height: 0;
|
|
|
|
|
+ opacity: 0.92;
|
|
|
|
|
+ filter: drop-shadow(0 0 5px rgba(160, 220, 255, 0.95));
|
|
|
|
|
+ transition: opacity 0.15s, filter 0.15s;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover .dir-arrow {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ filter: drop-shadow(0 0 8px rgba(0, 220, 255, 1));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:active .dir-arrow {
|
|
|
|
|
+ opacity: 0.7;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 上方向键
|
|
|
|
|
+ &.up {
|
|
|
|
|
+ left: 50%;
|
|
|
|
|
+ top: 6px;
|
|
|
|
|
+ margin-left: -18px;
|
|
|
|
|
+
|
|
|
|
|
+ .dir-arrow {
|
|
|
|
|
+ border-left: 10px solid transparent;
|
|
|
|
|
+ border-right: 10px solid transparent;
|
|
|
|
|
+ border-bottom: 14px solid rgba(230, 245, 255, 0.95);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 下方向键
|
|
|
|
|
+ &.down {
|
|
|
|
|
+ left: 50%;
|
|
|
|
|
+ bottom: 6px;
|
|
|
|
|
+ margin-left: -18px;
|
|
|
|
|
+
|
|
|
|
|
+ .dir-arrow {
|
|
|
|
|
+ border-left: 10px solid transparent;
|
|
|
|
|
+ border-right: 10px solid transparent;
|
|
|
|
|
+ border-top: 14px solid rgba(230, 245, 255, 0.95);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 左方向键
|
|
|
|
|
+ &.left {
|
|
|
|
|
+ left: 6px;
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ margin-top: -18px;
|
|
|
|
|
+
|
|
|
|
|
+ .dir-arrow {
|
|
|
|
|
+ border-top: 10px solid transparent;
|
|
|
|
|
+ border-bottom: 10px solid transparent;
|
|
|
|
|
+ border-right: 14px solid rgba(230, 245, 255, 0.95);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 右方向键
|
|
|
|
|
+ &.right {
|
|
|
|
|
+ right: 6px;
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ margin-top: -18px;
|
|
|
|
|
+
|
|
|
|
|
+ .dir-arrow {
|
|
|
|
|
+ border-top: 10px solid transparent;
|
|
|
|
|
+ border-bottom: 10px solid transparent;
|
|
|
|
|
+ border-left: 14px solid rgba(230, 245, 255, 0.95);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 参数行通用样式(速度/扫描模式/调色模式)
|
|
|
|
|
+.param-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+
|
|
|
|
|
+ .param-label {
|
|
|
|
|
+ width: 68px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 速度滑块行
|
|
|
|
|
+.speed-row {
|
|
|
|
|
+ .speed-slider {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 18px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-right: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ // 隐藏原生 range 控件,显示自定义滑块
|
|
|
|
|
+ input[type='range'] {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ inset: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ z-index: 2;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 滑块轨道
|
|
|
|
|
+ .slider-track {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 4px;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ background: rgba(20, 60, 100, 0.9);
|
|
|
|
|
+ border: 1px solid rgba(0, 183, 255, 0.25);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 滑块已填充部分
|
|
|
|
|
+ .slider-fill {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ background: linear-gradient(90deg, #0090e0, #00d0ff);
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ box-shadow: 0 0 6px rgba(0, 200, 255, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 滑块拖拽圆点
|
|
|
|
|
+ .slider-thumb {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ width: 14px;
|
|
|
|
|
+ height: 14px;
|
|
|
|
|
+ margin: -7px 0 0 -7px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ background: radial-gradient(circle at center, #fff 0 35%, #1a9fe0 40% 100%);
|
|
|
|
|
+ border: 1px solid #7ad8ff;
|
|
|
|
|
+ box-shadow: 0 0 8px rgba(0, 200, 255, 0.85);
|
|
|
|
|
+ pointer-events: none;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .speed-value {
|
|
|
|
|
+ width: 40px;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 模式选择行(扫描模式/调色模式)
|
|
|
|
|
+.mode-row {
|
|
|
|
|
+ .mode-select {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 22px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ .mode-value {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 16px;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #cfe9ff;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ line-height: 16px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 下划线装饰
|
|
|
|
|
+ .mode-line {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 14px;
|
|
|
|
|
+ bottom: 2px;
|
|
|
|
|
+ height: 1px;
|
|
|
|
|
+ background: var(--dc-accent);
|
|
|
|
|
+ box-shadow: 0 0 4px rgba(0, 183, 255, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 下拉箭头
|
|
|
|
|
+ .mode-arrow {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ font-size: 9px;
|
|
|
|
|
+ color: var(--dc-accent);
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+ transition: transform 0.2s;
|
|
|
|
|
+
|
|
|
|
|
+ &.open {
|
|
|
|
|
+ transform: rotate(180deg);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 模式下拉菜单
|
|
|
|
|
+ .mode-dropdown {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ top: calc(100% + 2px);
|
|
|
|
|
+ z-index: 20;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ padding: 4px 0;
|
|
|
|
|
+ list-style: none;
|
|
|
|
|
+ background: #0a1f3a;
|
|
|
|
|
+ border: 1px solid var(--dc-accent);
|
|
|
|
|
+ box-shadow: var(--dc-glow);
|
|
|
|
|
+
|
|
|
|
|
+ li {
|
|
|
|
|
+ padding: 5px 8px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #cfe9ff;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background: rgba(0, 183, 255, 0.2);
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 底部勾选框区域(红外变倍/红外控制)
|
|
|
|
|
+.footer-checks {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 28px;
|
|
|
|
|
+ margin-top: auto;
|
|
|
|
|
+ padding-top: 4px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+
|
|
|
|
|
+ .check-item {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 6px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+
|
|
|
|
|
+ input {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 自定义复选框
|
|
|
|
|
+ .check-box {
|
|
|
|
|
+ width: 14px;
|
|
|
|
|
+ height: 14px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ border: 1px solid rgba(0, 183, 255, 0.85);
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ background: rgba(0, 30, 55, 0.85);
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ input:checked+.check-box {
|
|
|
|
|
+ background: #1aa0e0;
|
|
|
|
|
+ border-color: #4ec8ff;
|
|
|
|
|
+ box-shadow: 0 0 6px rgba(0, 183, 255, 0.55);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .check-label {
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 隐藏滚动条
|
|
|
|
|
+::-webkit-scrollbar {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+ }
|
|
|
|
|
+</style>
|