Compare commits

...

3 Commits

Author SHA1 Message Date
afe078dd1d merge 2025-12-26 01:15:06 +08:00
5f52ac4956 视频树数据 2025-12-26 01:14:12 +08:00
Digo
092d1d1505 提交对接的接口 2025-12-26 01:13:15 +08:00
7 changed files with 126 additions and 104 deletions

View File

@@ -5,8 +5,8 @@ VITE_WS_BASE_URL ='ws://220.185.188.222:8055/api/gisWs'
# VITE_APP_BASE_URL = 'http://125.124.131.105:6811/api'
# 成彬本地
# VITE_APP_BASE_URL = 'http://100.95.157.241:6061/api'
VITE_APP_BASE_URL = 'http://100.95.236.218:6061/api'
VITE_APP_BASE_URL = 'http://100.95.157.241:6061/api'
# VITE_APP_BASE_URL = 'http://100.95.236.218:6061/api'
# VITE_APP_BASE_URL = 'http://119.167.138.11:6061/video-service'
# 智能体访问地址

View File

@@ -24,7 +24,7 @@ import { ElMessage } from 'element-plus'
import { monitors, uavs, stations, environmentals, fences, detailFences } from './js/mock.js'
import InfoWindowComponent from '@/components/Map/window/index.vue'
import TrawlerInfoWindowComponent from '@/components/Map/window/trawler.vue'
import { videoCameraFindPage, findUavPage, findEnvPage, dsVideoList } from '@/api/device.js'
import { dsVideoList, findUavPage, findEnvPage } from '@/api/device.js'
const mapStore = useMapStore()
const UAV = computed(() => mapStore.legend.UAV)
@@ -333,7 +333,7 @@ const initMonitor = () => {
pageNo: 1,
pageSize: 9999
}
videoCameraFindPage(params).then(res => {
dsVideoList(params).then(res => {
if (res.success) {
geography.monitor = res.result.records
addMonitorToMap()

View File

@@ -92,8 +92,8 @@ const getLocationSymbol = () => [
}
]
const baseConfig = {
center: [ 120.67, 28.01 ],
zoom: 12,
center: [ 120.88, 28.01 ],
zoom: 10,
maxZoom: 20,
minZoom: 5,
attribution: '',

View File

@@ -2,21 +2,45 @@
<div class="emergency-list-wrapper">
<div :class="['alarm-content', isFold ? 'fold' : '']">
<div class="tab-wrapper">
<div :class="['tab-button', current === index ? 'active' : '']" v-for="(item, index) in tabs" :key="index"
@click="toggle(index)">{{ item.label }}</div>
<div
:class="['tab-button', current === index ? 'active' : '']"
v-for="(item, index) in tabs"
:key="index"
@click="toggle(index)"
>
{{ item.label }}
</div>
</div>
<div>
<SubtitleComponent title="告警列表" :more="true" element-loading-text="拼命加载中" @handle="handle"/>
<div v-loading="isLoading" element-loading-background="rgba(0, 0, 0, 0.8)" class="list-wrapper">
<div class="list-item" v-for="(item,index) in data" :key="item.id">
<SubtitleComponent
title="告警列表"
:more="true"
element-loading-text="拼命加载中"
@handle="handle"
/>
<div
v-loading="isLoading"
element-loading-background="rgba(0, 0, 0, 0.8)"
class="list-wrapper"
>
<div
class="list-item"
:class="{ selected: isSelected(item) }"
v-for="(item, index) in data"
:key="item.id"
@click="selectItem(item)"
>
<div class="time">
{{ item.createAt }}
<img src="@/assets/images/alarm/time-more.png" alt="">
<img src="@/assets/images/alarm/time-more.png" alt="" />
</div>
<div class="content">
<div class="index">{{ (index + 1).toString().padStart(2, '0') }}</div>
<div class="index">
{{ (index + 1).toString().padStart(2, "0") }}
</div>
<div class="info">
{{ item.boatName }} - {{ item.illegalType }} ,请相关人员尽快前往协调
{{ item.boatName }} -
{{ item.illegalType }} ,请相关人员尽快前往协调
</div>
</div>
</div>
@@ -25,11 +49,11 @@
</div>
<div class="fold-button" @click="toggleFold()">
<template v-if="isFold">
<img src="@/assets/images/common/icon-arrow-right.png" alt="">
<img src="@/assets/images/common/icon-arrow-right.png" alt="" />
<div>展开</div>
</template>
<template v-else>
<img src="@/assets/images/common/icon-arrow-left.png" alt="">
<img src="@/assets/images/common/icon-arrow-left.png" alt="" />
<div>收起</div>
</template>
</div>
@@ -51,7 +75,6 @@ const tabs = [
label: '有船号',
value: 'plane'
}
]
const current = ref(1)
const data = ref([])
@@ -60,8 +83,7 @@ const isFold = ref(false)
const isLoading = ref(false)
const initData = () => {
// 为了撑起来框架
// 为了撑起来框架
data.value = [
{
id: 1,
@@ -76,15 +98,14 @@ const initData = () => {
pageNo: 1,
pageSize: 20
}
videoIdentificationPage(params).then(res => {
if(res.success) {
videoIdentificationPage(params).then((res) => {
if (res.success) {
data.value = res.result.records
}else {
} else {
ElMessage.error(res.result)
}
isLoading.value = false
})
}
const toggleFold = () => {
isFold.value = !isFold.value
@@ -103,10 +124,24 @@ const handle = (type, item) => {
break
}
}
// 在 script setup 中添加
const selectedItemId = ref(null) // 记录选中的项目ID
// 判断是否选中
const isSelected = (item) => {
return selectedItemId.value === item.id
}
// 更新选中状态的方法
const selectItem = (item) => {
selectedItemId.value = item.id === selectedItemId.value ? null : item.id
}
initData()
</script>
<style scoped lang="scss">
.emergency-list-wrapper{
.emergency-list-wrapper {
position: absolute;
top: 98px;
left: 40px;
@@ -115,10 +150,15 @@ initData()
width: 488px;
height: 100%;
padding: 20px 20px 10px;
background: linear-gradient( 90deg, #0C1929 0%, rgba(12,25,41,0.6) 100%);
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;
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;
@@ -139,7 +179,7 @@ initData()
width: 28px;
position: relative;
height: 180px;
color: #FFFFFF;
color: #ffffff;
font-size: 16px;
text-align: center;
align-items: center;
@@ -147,18 +187,18 @@ initData()
line-height: 20px;
cursor: pointer;
margin-bottom: -47px;
background-image: url('@/assets/images/alarm/tab-background-first.png');
background-image: url("@/assets/images/alarm/tab-background-first.png");
background-size: 100% 100%;
background-repeat: no-repeat;
&.active {
background-image: url('@/assets/images/alarm/tab-background-active-first.png');
background-image: url("@/assets/images/alarm/tab-background-active-first.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
&:not(:first-of-type) {
background-image: url('@/assets/images/alarm/tab-background.png');
background-image: url("@/assets/images/alarm/tab-background.png");
&.active {
background-image: url('@/assets/images/alarm/tab-background-active.png');
background-image: url("@/assets/images/alarm/tab-background-active.png");
}
}
}
@@ -176,62 +216,64 @@ initData()
width: 100%;
padding: 10px;
font-size: 14px;
color: #E1F1FAFF;
color: #e1f1faff;
box-sizing: border-box;
border: 1px solid rgba(24, 128, 254, 0);
flex-shrink: 0;
cursor: pointer;
height: 99px;
background: rgba(46,164,240,0.1);
background: rgba(46, 164, 240, 0.1);
border-radius: 6px 6px 6px 6px;
.time{
.time {
font-size: 18px;
color: #0FC8F6;
color: #0fc8f6;
line-height: 27px;
display: flex;
align-items: center;
img{
img {
margin-left: 16px;
}
}
.content{
.content {
display: flex;
gap: 4px;
.index,.info{
background: rgba(66,171,191,0.2);
.index,
.info {
background: rgba(66, 171, 191, 0.2);
font-size: 14px;
height: 52px;
&:nth-of-type(3){
background: rgba(255,145,31,0.2);
&:nth-of-type(3) {
background: rgba(255, 145, 31, 0.2);
}
}
.index{
border-left: 2px solid #3CD0ED;
.index {
border-left: 2px solid #3cd0ed;
font-family: SHSCM;
width: 32px;
text-align: center;
line-height: 52px;
}
.info{
.info {
width: calc(100% - 32px);
padding: 6px 13px;
box-sizing: border-box;
line-height: 20px;
background-image: url('@/assets/images/alarm/alarm-info-background.png');
background-image: url("@/assets/images/alarm/alarm-info-background.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
}
&:nth-of-type(3){
.content{
.index,.info{
background: rgba(255,145,31,0.2);
&.selected {
.content {
.index,
.info {
background: rgba(255, 145, 31, 0.2);
}
.index{
border-left: 2px solid #FF911F;
.index {
border-left: 2px solid #ff911f;
}
.info{
background-image: url('@/assets/images/alarm/alarm-info-background-other.png');
.info {
background-image: url("@/assets/images/alarm/alarm-info-background-other.png");
}
}
}
@@ -244,10 +286,10 @@ initData()
top: 0;
width: 17px;
height: 82px;
background-image: url('@/assets/images/common/subscript-background-vertical.png');
background-image: url("@/assets/images/common/subscript-background-vertical.png");
background-size: 100% 100%;
background-repeat: no-repeat;
color: #FFFFFFCC;
color: #ffffffcc;
font-size: 12px;
cursor: pointer;
display: flex;
@@ -260,7 +302,7 @@ initData()
cursor: not-allowed;
pointer-events: none;
}
div{
div {
width: min-content;
}
}

View File

@@ -23,10 +23,10 @@
<script setup>
import { computed, nextTick, onMounted, ref } from 'vue'
// import { useStore } from 'vuex'
const mapStore = useMapStore()
const Detail = ref(null)
// const store = useStore()
// const data = computed(() => store.state.mapStore.uavs.data)
const data = computed(() => mapStore.windowInfo.data)
const ip = '198.16.74.210'
onMounted(() => {

View File

@@ -20,14 +20,14 @@
<div style="width: 100%;height: 100%;" :class="[`video-window${item}`]">
<!-- 视频预览组件 -->
<HikPlayerComponent
v-if="deviceType === 'CCTV' && haikang[item-1]?.codes"
v-if="videoType === 'CCTV' && haikang[item-1]?.codes"
ref="videoPreview"
:id="item"
:cameraIndexCode="haikang[item-1]?.codes"
:layout="haikang[item-1]?.layout"
@close="closeVideo">
</HikPlayerComponent>
<FlvPlayerComponent v-if="deviceType === 'UAV' && haikang[item-1]?.codes" :id="'uav'+item" :url="haikang[item-1]?.codes"/>
<FlvPlayerComponent v-if="videoType === 'UAV' && haikang[item-1]?.codes" :id="'uav'+item" :url="haikang[item-1]?.codes"/>
</div>
</div>
</div>
@@ -51,7 +51,7 @@ const active = ref(4)
const haikang = ref([])
const videoPreview = ref(null)
const props = defineProps({
deviceType: {
videoType: {
type: String,
default: () => ''
}
@@ -91,14 +91,14 @@ const closeVideo = (data, item) => {
}
// 点击视频预览
const handleNodeClick = (node) => {
if(props.deviceType === 'CCTV' && node.videoCode) {
if(props.videoType === 'CCTV' && node.videoCode) {
let index = haikang.value.findIndex(i => !i)
console.log(index, haikang.value, 'value')
if(index !== -1) {
haikang.value[index] = { codes: node.videoCode }
}
}
if(props.deviceType === 'UAV' && node.droneSn) {
if(props.videoType === 'UAV' && node.droneSn) {
toggleFly(node)
}
}
@@ -113,7 +113,10 @@ const toggleFly = (data) => {
if(res.success) {
let index = haikang.value.findIndex(i => !i)
if(index !== -1) {
setTimeout(() => {
haikang.value[index] = { codes: res.result.httpUrl }
}, 10000)
h
}
}
})

View File

@@ -8,7 +8,7 @@
@node-click="handleNodeClick">
<template v-slot="{ node, data }">
<!-- <img src="@/assets/images/livePreview/icon-monitor.png" alt=""> -->
<span :class="(!data.sourceType && treeType === 'UAV') ? 'offline': ''">{{ node.label }}</span>
<span :class="(data.sourceType!=='2' && treeType === 'UAV') ? 'offline': ''">{{ node.label }}</span>
</template>
</el-tree>
</div>
@@ -29,34 +29,11 @@ const refresh = (type) => {
if(type === 'CCTV') {
const params = {}
findVideoLevelList(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 arr = []
Object.keys(res.data).forEach(i => {
arr.push({ videoName: i, children: res.data[i] })
})
// 转换为树形结构
const result = Object.keys(groupedData).map(belong => {
const children = groupedData[belong]
if (children.length === 1) {
// 只有一个子元素,直接返回该子元素
return children[0]
}
// 有多个子元素,返回分组节点
return {
videoName: belong,
longitude: children[0].longitude,
latitude: children[0].latitude,
children: children
}
})
tableData.value = result
}
tableData.value = arr
})
}else if(type === 'UAV') {
const params = {
@@ -97,10 +74,10 @@ const refresh = (type) => {
}
const handleNodeClick = (data, node) => {
if(!data.sourceType) {
if(!data.children || data.children.length === 0) {
if(treeType.value === 'UAV' && !data.sourceType) {
return false
}
if(!data.children || data.children.length === 0) {
emit('handle', node.data)
}
}