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://125.124.131.105:6811/api'
# 成彬本地 # 成彬本地
# VITE_APP_BASE_URL = 'http://100.95.157.241: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://100.95.236.218:6061/api'
# VITE_APP_BASE_URL = 'http://119.167.138.11:6061/video-service' # 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 { monitors, uavs, stations, environmentals, fences, detailFences } from './js/mock.js'
import InfoWindowComponent from '@/components/Map/window/index.vue' import InfoWindowComponent from '@/components/Map/window/index.vue'
import TrawlerInfoWindowComponent from '@/components/Map/window/trawler.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 mapStore = useMapStore()
const UAV = computed(() => mapStore.legend.UAV) const UAV = computed(() => mapStore.legend.UAV)
@@ -333,7 +333,7 @@ const initMonitor = () => {
pageNo: 1, pageNo: 1,
pageSize: 9999 pageSize: 9999
} }
videoCameraFindPage(params).then(res => { dsVideoList(params).then(res => {
if (res.success) { if (res.success) {
geography.monitor = res.result.records geography.monitor = res.result.records
addMonitorToMap() addMonitorToMap()

View File

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

View File

@@ -2,21 +2,45 @@
<div class="emergency-list-wrapper"> <div class="emergency-list-wrapper">
<div :class="['alarm-content', isFold ? 'fold' : '']"> <div :class="['alarm-content', isFold ? 'fold' : '']">
<div class="tab-wrapper"> <div class="tab-wrapper">
<div :class="['tab-button', current === index ? 'active' : '']" v-for="(item, index) in tabs" :key="index" <div
@click="toggle(index)">{{ item.label }}</div> :class="['tab-button', current === index ? 'active' : '']"
v-for="(item, index) in tabs"
:key="index"
@click="toggle(index)"
>
{{ item.label }}
</div>
</div> </div>
<div> <div>
<SubtitleComponent title="告警列表" :more="true" element-loading-text="拼命加载中" @handle="handle"/> <SubtitleComponent
<div v-loading="isLoading" element-loading-background="rgba(0, 0, 0, 0.8)" class="list-wrapper"> title="告警列表"
<div class="list-item" v-for="(item,index) in data" :key="item.id"> :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"> <div class="time">
{{ item.createAt }} {{ item.createAt }}
<img src="@/assets/images/alarm/time-more.png" alt=""> <img src="@/assets/images/alarm/time-more.png" alt="" />
</div> </div>
<div class="content"> <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"> <div class="info">
{{ item.boatName }} - {{ item.illegalType }} ,请相关人员尽快前往协调 {{ item.boatName }} -
{{ item.illegalType }} ,请相关人员尽快前往协调
</div> </div>
</div> </div>
</div> </div>
@@ -25,11 +49,11 @@
</div> </div>
<div class="fold-button" @click="toggleFold()"> <div class="fold-button" @click="toggleFold()">
<template v-if="isFold"> <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> <div>展开</div>
</template> </template>
<template v-else> <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> <div>收起</div>
</template> </template>
</div> </div>
@@ -43,7 +67,7 @@ import { videoIdentificationPage } from '@/api/identification.js'
const mapStore = useMapStore() const mapStore = useMapStore()
const tabs = [ const tabs = [
{ {
label: '无船号', label: '无船号',
value: 'monitor' value: 'monitor'
}, },
@@ -51,7 +75,6 @@ const tabs = [
label: '有船号', label: '有船号',
value: 'plane' value: 'plane'
} }
] ]
const current = ref(1) const current = ref(1)
const data = ref([]) const data = ref([])
@@ -60,31 +83,29 @@ const isFold = ref(false)
const isLoading = ref(false) const isLoading = ref(false)
const initData = () => { const initData = () => {
// 为了撑起来框架
// 为了撑起来框架 data.value = [
data.value = [ {
{
id: 1, id: 1,
createAt: '2025-11-23 09:37:25', createAt: '2025-11-23 09:37:25',
boatName: '浙渔BHI90', boatName: '浙渔BHI90',
illegalType: '未穿救生衣预警,未封仓预警,未悬挂国旗' illegalType: '未穿救生衣预警,未封仓预警,未悬挂国旗'
} }
] ]
isLoading.value = true isLoading.value = true
const params = { const params = {
isHasBoatName: current.value == 1 ? 1 : 2, isHasBoatName: current.value == 1 ? 1 : 2,
pageNo: 1, pageNo: 1,
pageSize: 20 pageSize: 20
} }
videoIdentificationPage(params).then(res => { videoIdentificationPage(params).then((res) => {
if(res.success) { if (res.success) {
data.value = res.result.records data.value = res.result.records
}else { } else {
ElMessage.error(res.result) ElMessage.error(res.result)
} }
isLoading.value = false isLoading.value = false
}) })
} }
const toggleFold = () => { const toggleFold = () => {
isFold.value = !isFold.value isFold.value = !isFold.value
@@ -103,22 +124,41 @@ const handle = (type, item) => {
break 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() initData()
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.emergency-list-wrapper{ .emergency-list-wrapper {
position: absolute; position: absolute;
top: 98px; top: 98px;
left: 40px; left: 40px;
bottom: 42px; bottom: 42px;
.alarm-content { .alarm-content {
width: 488px; width: 488px;
height: 100%; height: 100%;
padding: 20px 20px 10px; 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-radius: 0px 0px 0px 0px;
border: 1px solid; 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; box-sizing: border-box;
display: flex; display: flex;
gap: 6px; gap: 6px;
@@ -139,7 +179,7 @@ initData()
width: 28px; width: 28px;
position: relative; position: relative;
height: 180px; height: 180px;
color: #FFFFFF; color: #ffffff;
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
align-items: center; align-items: center;
@@ -147,19 +187,19 @@ initData()
line-height: 20px; line-height: 20px;
cursor: pointer; cursor: pointer;
margin-bottom: -47px; 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-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
&.active { &.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-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
&:not(:first-of-type) { &:not(:first-of-type) {
background-image: url('@/assets/images/alarm/tab-background.png'); background-image: url("@/assets/images/alarm/tab-background.png");
&.active { &.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%; width: 100%;
padding: 10px; padding: 10px;
font-size: 14px; font-size: 14px;
color: #E1F1FAFF; color: #e1f1faff;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(24, 128, 254, 0); border: 1px solid rgba(24, 128, 254, 0);
flex-shrink: 0; flex-shrink: 0;
cursor: pointer; cursor: pointer;
height: 99px; height: 99px;
background: rgba(46,164,240,0.1); background: rgba(46, 164, 240, 0.1);
border-radius: 6px 6px 6px 6px; border-radius: 6px 6px 6px 6px;
.time{ .time {
font-size: 18px; font-size: 18px;
color: #0FC8F6; color: #0fc8f6;
line-height: 27px; line-height: 27px;
display: flex; display: flex;
align-items: center; align-items: center;
img{ img {
margin-left: 16px; margin-left: 16px;
} }
} }
.content{ .content {
display: flex; display: flex;
gap: 4px; gap: 4px;
.index,.info{ .index,
background: rgba(66,171,191,0.2); .info {
background: rgba(66, 171, 191, 0.2);
font-size: 14px; font-size: 14px;
height: 52px; height: 52px;
&:nth-of-type(3){ &:nth-of-type(3) {
background: rgba(255,145,31,0.2); background: rgba(255, 145, 31, 0.2);
} }
} }
.index{ .index {
border-left: 2px solid #3CD0ED; border-left: 2px solid #3cd0ed;
font-family: SHSCM; font-family: SHSCM;
width: 32px; width: 32px;
text-align: center; text-align: center;
line-height: 52px; line-height: 52px;
} }
.info{ .info {
width: calc(100% - 32px); width: calc(100% - 32px);
padding: 6px 13px; padding: 6px 13px;
box-sizing: border-box; box-sizing: border-box;
line-height: 20px; 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-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
} }
&:nth-of-type(3){ &.selected {
.content{ .content {
.index,.info{ .index,
background: rgba(255,145,31,0.2); .info {
background: rgba(255, 145, 31, 0.2);
} }
.index{ .index {
border-left: 2px solid #FF911F; border-left: 2px solid #ff911f;
} }
.info{ .info {
background-image: url('@/assets/images/alarm/alarm-info-background-other.png'); background-image: url("@/assets/images/alarm/alarm-info-background-other.png");
} }
} }
} }
@@ -244,10 +286,10 @@ initData()
top: 0; top: 0;
width: 17px; width: 17px;
height: 82px; 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-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
color: #FFFFFFCC; color: #ffffffcc;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
@@ -260,7 +302,7 @@ initData()
cursor: not-allowed; cursor: not-allowed;
pointer-events: none; pointer-events: none;
} }
div{ div {
width: min-content; width: min-content;
} }
} }

View File

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

View File

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

View File

@@ -8,7 +8,7 @@
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<template v-slot="{ node, data }"> <template v-slot="{ node, data }">
<!-- <img src="@/assets/images/livePreview/icon-monitor.png" alt=""> --> <!-- <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> </template>
</el-tree> </el-tree>
</div> </div>
@@ -29,34 +29,11 @@ const refresh = (type) => {
if(type === 'CCTV') { if(type === 'CCTV') {
const params = {} const params = {}
findVideoLevelList(params).then(res => { findVideoLevelList(params).then(res => {
if (res.success) { const arr = []
const data = res.result.records Object.keys(res.data).forEach(i => {
const groupedData = {} arr.push({ videoName: i, children: res.data[i] })
data.forEach(item => { })
const belong = item.videoBelong tableData.value = arr
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,
longitude: children[0].longitude,
latitude: children[0].latitude,
children: children
}
})
tableData.value = result
}
}) })
}else if(type === 'UAV') { }else if(type === 'UAV') {
const params = { const params = {
@@ -97,10 +74,10 @@ const refresh = (type) => {
} }
const handleNodeClick = (data, node) => { const handleNodeClick = (data, node) => {
if(!data.sourceType) {
return false
}
if(!data.children || data.children.length === 0) { if(!data.children || data.children.length === 0) {
if(treeType.value === 'UAV' && !data.sourceType) {
return false
}
emit('handle', node.data) emit('handle', node.data)
} }
} }