|
|
@@ -4,21 +4,9 @@
|
|
|
<!-- 控制设备下拉选择 -->
|
|
|
<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>
|
|
|
+ <a-select v-model:value="currentDevice" class="device-select" :options="deviceOptions" :bordered="false"
|
|
|
+ placeholder="请选择设备" :get-popup-container="(trigger) => trigger.parentNode" @change="onDeviceChange"
|
|
|
+ @dropdown-visible-change="onDeviceDropdownVisible" />
|
|
|
</div>
|
|
|
|
|
|
<!-- 功能 Tab -->
|
|
|
@@ -84,7 +72,7 @@
|
|
|
<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>
|
|
|
+ <ul v-if="openMenu === 'scan'" class="mode-dropdown drop-up" @click.stop>
|
|
|
<li v-for="item in scanModes" :key="item" @click="pickMode('scan', item)">{{ item }}</li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
@@ -95,7 +83,7 @@
|
|
|
<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>
|
|
|
+ <ul v-if="openMenu === 'color'" class="mode-dropdown drop-up" @click.stop>
|
|
|
<li v-for="item in colorModes" :key="item" @click="pickMode('color', item)">{{ item }}</li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
@@ -128,10 +116,12 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
+import { onMounted, onUnmounted, ref, watch, type PropType } from 'vue'
|
|
|
import { tabsPtz, lensControls } from '../hsqHome.data'
|
|
|
+import { duaSpeCameraControl } from '../hsqHome.api'
|
|
|
+import { useMessage } from '/@/hooks/web/useMessage';
|
|
|
|
|
|
-let props=defineProps({
|
|
|
+let props = defineProps({
|
|
|
deviceOptions: {
|
|
|
type: Array as PropType<any[]>,
|
|
|
default: () => []
|
|
|
@@ -149,18 +139,18 @@ const emit = defineEmits<{
|
|
|
(e: 'optionChange', payload: { irZoom: boolean; irControl: boolean }): void
|
|
|
}>()
|
|
|
|
|
|
-/** 当前选中的设备 */
|
|
|
+/** 当前选中的设备 value */
|
|
|
const currentDevice = ref('')
|
|
|
-/** 设备下拉菜单是否展开 */
|
|
|
-const deviceMenuOpen = ref(false)
|
|
|
+/** 当前选中的设备类型 */
|
|
|
+const currentDeviceType = ref('')
|
|
|
/** 当前激活的功能 Tab */
|
|
|
const activeTab = ref('ptz')
|
|
|
/** 云台控制速度(0-100) */
|
|
|
const speed = ref(28)
|
|
|
/** 当前扫描模式 */
|
|
|
-const scanMode = ref('')
|
|
|
+const scanMode = ref('预置位巡航')
|
|
|
/** 当前调色模式 */
|
|
|
-const colorMode = ref('')
|
|
|
+const colorMode = ref('白热')
|
|
|
/** 当前展开的下拉菜单(扫描/调色/无) */
|
|
|
const openMenu = ref<'scan' | 'color' | ''>('')
|
|
|
/** 红外变倍开关 */
|
|
|
@@ -169,32 +159,99 @@ const irZoom = ref(true)
|
|
|
const irControl = ref(false)
|
|
|
|
|
|
/** 扫描模式选项 */
|
|
|
-const scanModes = ['自动扫描', '水平扫描', '垂直扫描', '关闭']
|
|
|
+const scanModes = ['手动', '预置位巡航', '角度巡航', '角度全景图']
|
|
|
/** 调色模式选项 */
|
|
|
-const colorModes = ['白热', '黑热', '彩虹', '铁红']
|
|
|
-
|
|
|
+const colorModes = ['白热', '黑热', '铁红', '熔岩', '彩虹', '铁灰', '红热', '蓝红色']
|
|
|
+const { createMessage } = useMessage();
|
|
|
+
|
|
|
+async function sendAction(param) {
|
|
|
+ let res = await duaSpeCameraControl({ ...param })
|
|
|
+ console.log(res,'云台控制---')
|
|
|
+ if (res.code === 200) {
|
|
|
+ createMessage.success(res.msg || '操作成功')
|
|
|
+ } else {
|
|
|
+ createMessage.error(res.msg || '操作失败')
|
|
|
+ }
|
|
|
+}
|
|
|
/** 发送操作指令(云台方向/镜头控制等) */
|
|
|
function emitAction(type: string, value: string) {
|
|
|
emit('action', { type, value })
|
|
|
+ switch (value) {
|
|
|
+ case 'up':
|
|
|
+ sendAction({
|
|
|
+ deviceId: currentDevice.value,
|
|
|
+ password: '',
|
|
|
+ devicetype: currentDeviceType.value,
|
|
|
+ paramcode: '1',
|
|
|
+ cmd: 1,
|
|
|
+ stop: 0,
|
|
|
+ speed: speed.value,
|
|
|
+ })
|
|
|
+ break;
|
|
|
+ case 'down':
|
|
|
+ sendAction({
|
|
|
+ deviceId: currentDevice.value,
|
|
|
+ password: '',
|
|
|
+ devicetype: currentDeviceType.value,
|
|
|
+ paramcode: '1',
|
|
|
+ cmd: 2,
|
|
|
+ stop: 0,
|
|
|
+ speed: speed.value,
|
|
|
+ })
|
|
|
+ break;
|
|
|
+ case 'left':
|
|
|
+ sendAction({
|
|
|
+ deviceId: currentDevice.value,
|
|
|
+ password: '',
|
|
|
+ devicetype: currentDeviceType.value,
|
|
|
+ paramcode: '1',
|
|
|
+ cmd: 3,
|
|
|
+ stop: 0,
|
|
|
+ speed: speed.value,
|
|
|
+ })
|
|
|
+ break;
|
|
|
+ case 'right':
|
|
|
+ sendAction({
|
|
|
+ deviceId: currentDevice.value,
|
|
|
+ password: '',
|
|
|
+ devicetype: currentDeviceType.value,
|
|
|
+ paramcode: '1',
|
|
|
+ cmd: 4,
|
|
|
+ stop: 0,
|
|
|
+ speed: speed.value,
|
|
|
+ })
|
|
|
+ // case 'stop':
|
|
|
+ // sendAction({
|
|
|
+ // deviceId: currentDevice.value,
|
|
|
+ // password: '',
|
|
|
+ // devicetype: currentDeviceType.value,
|
|
|
+ // paramcode: '1',
|
|
|
+ // // cmd: ,
|
|
|
+ // stop: 0,
|
|
|
+ // speed: speed.value,
|
|
|
+ // })
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-/** 切换设备下拉菜单的展开/收起 */
|
|
|
-function toggleDeviceMenu() {
|
|
|
- deviceMenuOpen.value = !deviceMenuOpen.value
|
|
|
- openMenu.value = ''
|
|
|
+/** 选择设备并触发 deviceChange 事件 */
|
|
|
+function onDeviceChange(value: string) {
|
|
|
+ const item = props.deviceOptions.find((d) => d.value === value)
|
|
|
+ if (item) {
|
|
|
+ emit('deviceChange', item)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-/** 选择设备,关闭菜单并触发 deviceChange 事件 */
|
|
|
-function selectDevice(item) {
|
|
|
- currentDevice.value = item.label
|
|
|
- deviceMenuOpen.value = false
|
|
|
- emit('deviceChange', item)
|
|
|
+/** 展开设备下拉时收起扫描/调色菜单 */
|
|
|
+function onDeviceDropdownVisible(open: boolean) {
|
|
|
+ if (open) {
|
|
|
+ openMenu.value = ''
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** 切换扫描/调色模式下拉菜单(互斥展开) */
|
|
|
function toggleMenu(key: 'scan' | 'color') {
|
|
|
openMenu.value = openMenu.value === key ? '' : key
|
|
|
- deviceMenuOpen.value = false
|
|
|
}
|
|
|
|
|
|
/** 选择扫描/调色模式并触发对应事件 */
|
|
|
@@ -209,9 +266,8 @@ function pickMode(type: 'scan' | 'color', value: string) {
|
|
|
openMenu.value = ''
|
|
|
}
|
|
|
|
|
|
-/** 点击页面其他区域时关闭所有下拉菜单 */
|
|
|
+/** 点击页面其他区域时关闭扫描/调色下拉菜单 */
|
|
|
function onDocClick() {
|
|
|
- deviceMenuOpen.value = false
|
|
|
openMenu.value = ''
|
|
|
}
|
|
|
|
|
|
@@ -224,10 +280,11 @@ watch([irZoom, irControl], () => {
|
|
|
emit('optionChange', { irZoom: irZoom.value, irControl: irControl.value })
|
|
|
})
|
|
|
watch(() => props.deviceOptions, (newVal) => {
|
|
|
- if(newVal.length > 0){
|
|
|
- currentDevice.value = newVal[0].label
|
|
|
+ if (newVal.length > 0) {
|
|
|
+ currentDevice.value = newVal[0].value
|
|
|
+ currentDeviceType.value = newVal[0].deviceType
|
|
|
}
|
|
|
-},{immediate: true})
|
|
|
+}, { immediate: true })
|
|
|
|
|
|
/** 挂载时注册全局点击关闭事件 */
|
|
|
onMounted(() => {
|
|
|
@@ -278,69 +335,59 @@ onUnmounted(() => {
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
- // 自定义下拉选择框
|
|
|
.device-select {
|
|
|
- position: relative;
|
|
|
flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.zxm-select) {
|
|
|
+ width: 100%;
|
|
|
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;
|
|
|
- }
|
|
|
+ :deep(.zxm-select-selector) {
|
|
|
+ height: 38px !important;
|
|
|
+ padding: 0 28px 0 14px !important;
|
|
|
+ background: var(--image-bg) no-repeat !important;
|
|
|
+ background-size: 100% 100% !important;
|
|
|
+ border: none !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+ color: #fff !important;
|
|
|
+ }
|
|
|
|
|
|
- // 下拉箭头
|
|
|
- .select-arrow {
|
|
|
- position: absolute;
|
|
|
- right: 20px;
|
|
|
- color: #fff;
|
|
|
- display: inline-flex;
|
|
|
- transition: transform 0.2s;
|
|
|
+ :deep(.zxm-select-selection-search) {
|
|
|
+ inset-inline-start: 14px !important;
|
|
|
+ }
|
|
|
|
|
|
- &.open {
|
|
|
- transform: rotate(180deg);
|
|
|
- }
|
|
|
- }
|
|
|
+ :deep(.zxm-select-selection-item),
|
|
|
+ :deep(.zxm-select-selection-placeholder) {
|
|
|
+ line-height: 38px !important;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #fff !important;
|
|
|
+ }
|
|
|
|
|
|
- // 下拉菜单
|
|
|
- .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;
|
|
|
+ :deep(.zxm-select-arrow) {
|
|
|
+ color: #fff !important;
|
|
|
+ right: 16px;
|
|
|
+ }
|
|
|
|
|
|
- li {
|
|
|
- padding: 6px 10px;
|
|
|
- font-size: 12px;
|
|
|
- color: #cfe9ff;
|
|
|
- cursor: pointer;
|
|
|
+ :deep(.zxm-select-dropdown) {
|
|
|
+ padding: 4px 0;
|
|
|
+ background: #0a1f3a;
|
|
|
+ border: 1px solid var(--dc-accent);
|
|
|
+ box-shadow: var(--dc-glow);
|
|
|
+ }
|
|
|
|
|
|
- &:hover,
|
|
|
- &.active {
|
|
|
- background: rgba(0, 183, 255, 0.2);
|
|
|
- color: #fff;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ :deep(.zxm-select-item) {
|
|
|
+ padding: 6px 10px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #cfe9ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.zxm-select-item-option-active),
|
|
|
+ :deep(.zxm-select-item-option-selected) {
|
|
|
+ background: rgba(0, 183, 255, 0.2) !important;
|
|
|
+ color: #fff !important;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -693,7 +740,7 @@ onUnmounted(() => {
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
top: calc(100% + 2px);
|
|
|
- z-index: 20;
|
|
|
+ z-index: 30;
|
|
|
margin: 0;
|
|
|
padding: 4px 0;
|
|
|
list-style: none;
|
|
|
@@ -701,6 +748,11 @@ onUnmounted(() => {
|
|
|
border: 1px solid var(--dc-accent);
|
|
|
box-shadow: var(--dc-glow);
|
|
|
|
|
|
+ &.drop-up {
|
|
|
+ top: auto;
|
|
|
+ bottom: calc(100% + 2px);
|
|
|
+ }
|
|
|
+
|
|
|
li {
|
|
|
padding: 5px 8px;
|
|
|
font-size: 12px;
|
|
|
@@ -764,6 +816,6 @@ onUnmounted(() => {
|
|
|
|
|
|
// 隐藏滚动条
|
|
|
::-webkit-scrollbar {
|
|
|
- display: none;
|
|
|
- }
|
|
|
+ display: none;
|
|
|
+}
|
|
|
</style>
|