second commit

This commit is contained in:
2025-12-25 18:33:15 +08:00
parent 78407f1cbd
commit 6a6ddba71a
34 changed files with 527 additions and 1226 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,389 +0,0 @@
<template>
<div class="device-wrapper">
<div :class="['device-content', isFold ? 'fold' : '']">
<div class="tab-wrapper">
<div :class="['tab-button', current === index ? 'active' : '']" v-for="(item, index) in tabs" :key="index"
@click="toggleDevice(index)">{{ item.label }}</div>
</div>
<div class="list-wrapper">
<template v-if="current === 0">
<el-tree :data="tableData" ref="treeRef" :props="{ label: 'videoName', children: 'children' }" node-key="id"
@node-click="handleNodeClick">
<template v-slot="{ node }">
<img src="@/assets/images/livePreview/icon-monitor.png" alt="">
<span>{{ node.label }}</span>
</template>
</el-tree>
</template>
<template v-else>
<div class="list-item" v-for="item in tableData" :key="item.id" @click="handleDevice(item)">
<span>{{ item.videoName }}</span>
</div>
</template>
</div>
</div>
<div class="fold-button" @click="toggleFold">
<template v-if="isFold">
<span>展开</span>
<img src="@/assets/images/drone/icon-arrow-right.png" alt="">
</template>
<template v-else>
<span>收起</span>
<img src="@/assets/images/drone/icon-arrow-left.png" alt="">
</template>
</div>
</div>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import { videoCameraFindPage, findUavPage, findEnvPage } from '@/api/device.js'
import { Message } from '@element-plus/icons-vue'
const preview = reactive({
visible: false,
codes: []
})
const current = ref(1)
const isFold = ref(false)
const tabs = [
{
label: '监控设备',
value: 'monitor'
},
{
label: '无人机设备',
value: 'plane'
},
{
label: '环境监测设备',
value: 'environment'
},
{
label: '感知设备',
value: 'AIS'
}
]
const tableData = ref([])
const initMonitor = () => {
const params = new FormData()
params.append('pageNo', 1)
params.append('pageSize', 999)
videoCameraFindPage(params).then(res => {
if (res.success) {
const data = res.result.records
const groupedData = {}
data.forEach(item => {
const belong = item.videoBelong
if (!groupedData[belong]) {
groupedData[belong] = []
}
groupedData[belong].push(item)
})
// 转换为树形结构
const result = Object.keys(groupedData).map(belong => {
const children = groupedData[belong]
if (children.length === 1) {
// 只有一个子元素,直接返回该子元素
return children[0]
}
// 有多个子元素,返回分组节点
return {
videoName: belong,
children: children
}
})
tableData.value = result
} else {
Message.error(res.msg || '查询失败!')
}
})
}
const initPlane = () => {
const params = new FormData()
params.append('pageNo', 1)
params.append('pageSize', 999)
findUavPage(params).then(res => {
if (res.success) {
tableData.value = res.result.records
} else {
Message.error(res.msg || '查询失败!')
}
})
}
const initEnvironment = () => {
const params = new FormData()
params.append('pageNo', 1)
params.append('pageSize', 999)
params.append('videoType', '航道流速设备,气象观测站设备')
findEnvPage(params).then(res => {
if (res.success) {
tableData.value = res.result.records
} else {
Message.error(res.msg || '查询失败!')
}
})
}
const initAIS = () => {
const params = new FormData()
params.append('pageNo', 1)
params.append('pageSize', 999)
params.append('videoType', 'AIS基站设备')
findEnvPage(params).then(res => {
if (res.success) {
tableData.value = res.result.records
} else {
Message.error(res.msg || '查询失败!')
}
})
}
const initMap = {
'monitor': initMonitor,
'plane': initPlane,
'environment': initEnvironment,
'AIS': initAIS
}
const initData = () => {
tableData.value = []
const tabValue = tabs[current.value].value
const initFunction = initMap[tabValue]
if (initFunction) {
try {
initFunction()
} catch (error) {
console.error(error)
}
}
}
const toggleDevice = (index) => {
current.value = index
}
const handleDevice = (item) => {
preview.visible = true
}
const handleNodeClick = (node) => {
if (!node.children || node.children.length === 0) {
// 雷云一体机一个视频
if (node.videoName.indexOf('雷云') !== -1) {
preview.codes = ['0f69d447002a40629e15f8a251fc46fa']
} else {
preview.codes = ['b7f9fff8e3504e419cb2f5fad5b2845c', '9b49bdc8988e430baad9ca727fed545a', 'e0a42cd6cbf940a6a4fc0aa789d43a04']
}
preview.visible = true
}
}
const toggleFold = () => {
isFold.value = !isFold.value
}
watch(() => current.value, () => {
initData()
}, { immediate: true })
</script>
<style lang="scss" scoped>
.device-wrapper {
position: absolute;
left: 45px;
top: 89px;
bottom: 411px;
.device-content {
width: 401px;
height: 100%;
padding: 10px;
background: linear-gradient( 90deg, #0C1929 0%, rgba(12,25,41,0.6) 100%);
border-radius: 0px 0px 0px 0px;
border: 1px solid;
border-image: linear-gradient(270deg, rgba(42, 159, 255, 0.2), rgba(42, 159, 255, 0.8)) 1 1;
box-sizing: border-box;
display: flex;
gap: 6px;
opacity: 1;
visibility: visible;
transition: all 0.3s ease-in-out;
&.fold {
width: 0;
overflow: hidden;
opacity: 0;
visibility: hidden;
}
.tab-wrapper {
width: 28px;
height: 100%;
.tab-button {
position: relative;
width: 100%;
height: 25%;
// height: 130px;
color: #FFFFFF;
font-size: 12px;
text-align: center;
line-height: 28px;
writing-mode: vertical-rl;
text-orientation: upright;
background-color: #2061bd;
border-radius: 3px 0 0 28px;
cursor: pointer;
margin-bottom: -7px;
opacity: .6;
&:not(:first-of-type) {
border-radius: 0 28px 0 28px;
&::before {
content: '';
display: block;
width: 28px;
height: 28px;
position: absolute;
background: radial-gradient(circle at 28px 3px, transparent 28px, #2162bd 28px);
top: -24px;
left: 0;
}
}
&::after {
content: '';
display: block;
width: 28px;
height: 28px;
position: absolute;
background: radial-gradient(circle at 0px 25px, transparent 28px, #2061bd 28px);
bottom: -24px;
right: 0;
}
&.active {
background-color: #2061BD;
opacity: 1;
}
}
}
.list-wrapper {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
overflow: auto;
background: transparent;
.list-item {
width: 100%;
height: 44px;
padding-left: 20px;
background-color: rgba(24, 128, 254, 0.3);
border-radius: 3px 3px 3px 3px;
font-size: 14px;
color: #E1F1FAFF;
display: flex;
align-items: center;
box-sizing: border-box;
border: 1px solid rgba(24, 128, 254, 0);
flex-shrink: 0;
cursor: pointer;
&::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
background-image: url('@/assets/images/livePreview/icon-monitor.png');
background-size: 100% 100%;
background-repeat: no-repeat;
margin-right: 10px;
}
&.active,
&:hover {
color: #0EF8F8FF;
background-color: rgba(24, 128, 254, 0.5);
border: 1px solid #5FA4FF;
&::before {
background-image: url('@/assets/images/livePreview/icon-monitor-active.png');
}
}
}
.el-tree {
background: transparent;
}
:deep(.el-tree-node) {
width: 100%;
margin-bottom: 4px;
background-color: rgba(24, 128, 254, 0.3);
border-radius: 3px 3px 3px 3px;
font-size: 14px;
align-items: center;
box-sizing: border-box;
border: 1px solid rgba(24, 128, 254, 0);
flex-shrink: 0;
cursor: pointer;
.el-tree-node__content {
height: 44px;
border: 1px solid transparent;
box-sizing: border-box;
}
img {
margin-right: 10px;
}
span {
color: #E1F1FAFF;
}
&:focus>.el-tree-node__content,
.el-tree-node__content:hover {
color: #0EF8F8FF;
background-color: rgba(24, 128, 254, 0.5);
border: 1px solid #5FA4FF;
&::before {
background-image: url('@/assets/images/livePreview/icon-monitor-active.png');
}
}
}
}
}
.fold-button {
position: absolute;
right: -17px;
top: 0;
width: 17px;
height: 82px;
background-image: url('@/assets/images/drone/subscript-background-vertical.png');
background-size: 100% 100%;
background-repeat: no-repeat;
color: #FFFFFFCC;
font-size: 12px;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
visibility: visible;
}
}
</style>

View File

@@ -1,16 +0,0 @@
<template>
<div>
<DeviceComponent/>
<ControlComponent/>
</div>
</template>
<script setup>
import DeviceComponent from './device.vue'
import ControlComponent from './control.vue'
</script>
<style lang="scss" scoped>
</style>