业务配置页面+接口联调,弹窗修改路由跳转
This commit is contained in:
@@ -3,11 +3,8 @@ NODE_ENV = 'development'
|
|||||||
# 渔船点位
|
# 渔船点位
|
||||||
VITE_WS_BASE_URL ='ws://220.185.188.222:8055/api/gisWs'
|
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.100.2:6061/api'
|
VITE_APP_BASE_URL = 'http://100.95.196.8: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'
|
|
||||||
|
|
||||||
# 智能体访问地址
|
# 智能体访问地址
|
||||||
# 宋凯忠本地
|
# 宋凯忠本地
|
||||||
|
|||||||
@@ -6,14 +6,50 @@ import request from '@/utils/request'
|
|||||||
* @param data
|
* @param data
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const videoCameraFindPage = (data) => {
|
export const dsVideoPage = (data) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/videoCamera/findPage',
|
url: '/fishingPort/dsVideo/page',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data
|
||||||
headers: {
|
})
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 分页查询监控设备列表
|
||||||
|
* 新增
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const dsVideoSave = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/fishingPort/dsVideo/save',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 分页查询监控设备列表
|
||||||
|
* 修改
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const dsVideoUpdate = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/fishingPort/dsVideo/update',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 分页查询监控设备列表
|
||||||
|
* 删除
|
||||||
|
* @param data
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const dsVideoDelete = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/fishingPort/dsVideo/delete',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
BIN
src/assets/images/common/icon_suffix.png
Normal file
BIN
src/assets/images/common/icon_suffix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 204 B |
BIN
src/assets/images/map/devices/icon_monitor_bayonet.png
Normal file
BIN
src/assets/images/map/devices/icon_monitor_bayonet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
@@ -11,7 +11,7 @@
|
|||||||
v-model="model[item.prop]"
|
v-model="model[item.prop]"
|
||||||
:placeholder="item.placeholder ? item.placeholder : '请输入'"
|
:placeholder="item.placeholder ? item.placeholder : '请输入'"
|
||||||
:clearable="item.clearable !== false"
|
:clearable="item.clearable !== false"
|
||||||
style="width: 110px">
|
:style="{width: item.width || '110px'}">
|
||||||
</el-input>
|
</el-input>
|
||||||
<el-select
|
<el-select
|
||||||
v-if="item.type === 'select'"
|
v-if="item.type === 'select'"
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
:collapse-tags="item.collapseTags || false"
|
:collapse-tags="item.collapseTags || false"
|
||||||
:collapse-tags-tooltip="item.collapseTagsTooltip || false"
|
:collapse-tags-tooltip="item.collapseTagsTooltip || false"
|
||||||
@change="(val) => handle(item.event,val)"
|
@change="(val) => handle(item.event,val)"
|
||||||
style="width: 90px"
|
:style="{width: item.width || '90px'}"
|
||||||
poper-class="filter-select"
|
poper-class="filter-select"
|
||||||
:empty-values="item.emptyValues || [ '', undefined]"
|
:empty-values="item.emptyValues || [ '', undefined]"
|
||||||
:value-on-clear="item.valueOnClear || ''">
|
:value-on-clear="item.valueOnClear || ''">
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ const initPlayer = () => {
|
|||||||
|
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
timeoutId = null
|
timeoutId = null
|
||||||
console.log(retryCount, retryDelay, '重连次数......')
|
|
||||||
if (retryCount <= MAX_RETRIES) {
|
if (retryCount <= MAX_RETRIES) {
|
||||||
initPlayer() // 重新初始化播放器
|
initPlayer() // 重新初始化播放器
|
||||||
} else {
|
} else {
|
||||||
@@ -76,7 +75,6 @@ const initPlayer = () => {
|
|||||||
if (player) {
|
if (player) {
|
||||||
player = null
|
player = null
|
||||||
}
|
}
|
||||||
console.error('重试超过最大次数')
|
|
||||||
}
|
}
|
||||||
}, retryDelay)
|
}, retryDelay)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -69,11 +69,11 @@
|
|||||||
]
|
]
|
||||||
|
|
||||||
const navRight = [
|
const navRight = [
|
||||||
// {
|
{
|
||||||
// label: '识别记录',
|
label: '业务配置',
|
||||||
// path: '/screen/identification',
|
path: '/setting',
|
||||||
// prop: 'identification'
|
prop: 'identification'
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
label: '插件下载',
|
label: '插件下载',
|
||||||
path: '',
|
path: '',
|
||||||
@@ -101,6 +101,8 @@
|
|||||||
const toggle = (nav) => {
|
const toggle = (nav) => {
|
||||||
if(nav.prop === 'monitor') {
|
if(nav.prop === 'monitor') {
|
||||||
window.open('/plugin/VideoWebPlugin.exe', '_blank')
|
window.open('/plugin/VideoWebPlugin.exe', '_blank')
|
||||||
|
}else{
|
||||||
|
router.push(nav.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 右上角时间
|
// 右上角时间
|
||||||
@@ -250,7 +252,7 @@
|
|||||||
}
|
}
|
||||||
.datetime{
|
.datetime{
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 14px;
|
gap: 12px;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
height: 29px;
|
height: 29px;
|
||||||
@@ -284,7 +286,7 @@
|
|||||||
margin-left: 61px;
|
margin-left: 61px;
|
||||||
}
|
}
|
||||||
.right{
|
.right{
|
||||||
gap:20px;
|
gap:15px;
|
||||||
margin-right: 40px;
|
margin-right: 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,130 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="[{ 'expend-only': expend }, 'screen-map-server',toolBarStore.expand ? 'expand' : '']" @mouseenter="moveEnter" @mouseleave="moveLeave">
|
|
||||||
|
|
||||||
<img alt="ICON_MAP" class="icon-cover" :src="getAssetsFile(`icon-${active}-active.png`)">
|
|
||||||
|
|
||||||
<div v-for="(item, index) in list" class="screen-map-server-item" :key="index" :style="getStyle(item, index)"
|
|
||||||
@click="toggle(item, index)">
|
|
||||||
|
|
||||||
<img v-show="(!expend && !index) || expend" alt="ICON_MAP" class="icon-map"
|
|
||||||
:src="getAssetsFile(`icon-${item.prop}${item.prop == active ? '-active' : ''}.png`)">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { getAssetsFile } from '@/utils/common'
|
|
||||||
import useToolBarStore from '@/store/modules/toolbar'
|
|
||||||
|
|
||||||
const toolBarStore = useToolBarStore()
|
|
||||||
const emit = defineEmits([ 'toggle' ])
|
|
||||||
|
|
||||||
const active = ref('satellite')
|
|
||||||
const expend = ref(false)
|
|
||||||
|
|
||||||
const list = [
|
|
||||||
{
|
|
||||||
label: '遥感',
|
|
||||||
prop: 'satellite'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '海图',
|
|
||||||
prop: 'sea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '浅色',
|
|
||||||
prop: 'light'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动态改变当前图例的定位
|
|
||||||
* @param e 当前图例信息
|
|
||||||
* @param index 当前图例下标
|
|
||||||
*/
|
|
||||||
const getStyle = (e, index) => ({
|
|
||||||
'background-color': !expend.value && e.color ? e.color : 'transparent', // 未展开样式
|
|
||||||
'border-radius': expend.value ? '0px' : '5px', // 未展开样式
|
|
||||||
right: expend.value ? `${index * 40 + (index + 1) * 4}px` : `${(index + 1) * 4}px`,
|
|
||||||
'transition-duration': expend.value ? `${index * 0.2}s` : '0s',
|
|
||||||
'z-index': e.index
|
|
||||||
})
|
|
||||||
|
|
||||||
const moveEnter = () => {
|
|
||||||
expend.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveLeave = () => {
|
|
||||||
expend.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 底图切换
|
|
||||||
* @param e 当前图例信息
|
|
||||||
*/
|
|
||||||
const toggle = (e) => {
|
|
||||||
active.value = e.prop
|
|
||||||
emit('toggle', 'toggle-base', e.prop)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.screen-map-server {
|
|
||||||
position: absolute;
|
|
||||||
right: 30px;
|
|
||||||
bottom: 112px;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
padding: 4px;
|
|
||||||
border-radius: 5px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: transparent;
|
|
||||||
transition-duration: .3s;
|
|
||||||
cursor: pointer;
|
|
||||||
pointer-events: auto;
|
|
||||||
|
|
||||||
&.expend-only {
|
|
||||||
height: 48px;
|
|
||||||
width: 135px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(77, 151, 255, 0.5);
|
|
||||||
|
|
||||||
.icon-cover {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* COVER */
|
|
||||||
.icon-cover {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: 4px;
|
|
||||||
top: 4px;
|
|
||||||
z-index: 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ITEM */
|
|
||||||
.screen-map-server-item {
|
|
||||||
border-radius: 0;
|
|
||||||
height: 40px;
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
width: 40px;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
.icon-map {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.expand{
|
|
||||||
right: 390px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -23,14 +23,11 @@ import { monitors, uavs, stations, environmentals, fences, detailFences } from '
|
|||||||
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 { dsVideoList, findUavPage, getVideoInfo } from '@/api/device.js'
|
import { dsVideoList, findUavPage, getVideoInfo } from '@/api/device.js'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
const UAV = computed(() => mapStore.legend.UAV)
|
const legend = computed(() => mapStore.legend)
|
||||||
const monitor = computed(() => mapStore.legend.monitor)
|
|
||||||
const ais_station = computed(() => mapStore.legend.ais_station)
|
|
||||||
const environmental = computed(() => mapStore.legend.environmental)
|
|
||||||
const fence = computed(() => mapStore.legend.fence)
|
|
||||||
const sector = computed(() => mapStore.sector)
|
|
||||||
const locateData = computed(() => mapStore.locate.data)
|
const locateData = computed(() => mapStore.locate.data)
|
||||||
let globalMap = null
|
let globalMap = null
|
||||||
let vector = {}
|
let vector = {}
|
||||||
@@ -108,7 +105,7 @@ const addMonitorToMap = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: item.id,
|
id: item.id,
|
||||||
symbol: $configs.getDevicePointSymbol('_monitor', { ...item, name: item.videoName }),
|
symbol: $configs.getDevicePointSymbol('_monitor' + (item.beBayonet === 1 ? '_bayonet' : ''), { ...item, name: item.videoName }), // beBayonet 是否卡口1是 0否
|
||||||
properties: item,
|
properties: item,
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
}
|
}
|
||||||
@@ -118,21 +115,8 @@ const addMonitorToMap = () => {
|
|||||||
const pvalue = item.ptzcfg?.pValue || 0
|
const pvalue = item.ptzcfg?.pValue || 0
|
||||||
drawSector('_monitor', [ item.longitude, item.latitude ], visionDistance, item.id, (90 - pvalue) % 360)
|
drawSector('_monitor', [ item.longitude, item.latitude ], visionDistance, item.id, (90 - pvalue) % 360)
|
||||||
marker.on('click', (evt) => {
|
marker.on('click', (evt) => {
|
||||||
// 先隐藏所有扇形
|
mapStore.updateLocate({ ...item }) // 视频定位
|
||||||
changeSectorsInLayer('sectors_monitor', false)
|
mapStore.updateWindowInfo({ visible: true, type: '_monitor', data: { ...item } }) // 打开监控视频弹窗
|
||||||
|
|
||||||
// 确保扇形图层是可见的
|
|
||||||
if (!vector.sectors_monitor.isVisible()) {
|
|
||||||
vector.sectors_monitor.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示当前点击项的所有相关扇形(圆、椭圆、线)
|
|
||||||
const baseId = `sector__monitor${item.id}`
|
|
||||||
vector.sectors_monitor.getGeometryById(baseId + '_circle')?.show()
|
|
||||||
vector.sectors_monitor.getGeometryById(baseId + '_ellipse')?.show()
|
|
||||||
vector.sectors_monitor.getGeometryById(baseId + '_line')?.show()
|
|
||||||
|
|
||||||
mapStore.updateWindowInfo({ visible: true, type: '_monitor', data: { ...item } })
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -140,34 +124,17 @@ const addMonitorToMap = () => {
|
|||||||
}
|
}
|
||||||
// 要素/视频定位
|
// 要素/视频定位
|
||||||
const locateMoitor = (data) => {
|
const locateMoitor = (data) => {
|
||||||
const name = 'locate-monitor'
|
|
||||||
let layer = vector[name]
|
|
||||||
if (!layer) {
|
|
||||||
initLayerToMap('locate-monitor')
|
initLayerToMap('locate-monitor')
|
||||||
layer = vector['locate-monitor']
|
|
||||||
} else {
|
|
||||||
layer.clear()
|
|
||||||
}
|
|
||||||
const monitors = vector.monitor
|
const monitors = vector.monitor
|
||||||
const marker = monitors.getGeometryById(data.id)
|
const marker = monitors.getGeometryById(data.id)
|
||||||
if (marker) {
|
if (marker) {
|
||||||
const coordinates = marker.getCoordinates()
|
|
||||||
geography.monitor.forEach((item) => {
|
geography.monitor.forEach((item) => {
|
||||||
if (item.id === data.id) {
|
if (item.id === data.id) {
|
||||||
// globalMap.map.animateTo(
|
|
||||||
// {
|
|
||||||
// center: [ coordinates.x, coordinates.y ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// duration: 1000 * 0.5,
|
|
||||||
// easing: 'out'
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// 先隐藏所有扇形
|
// 先隐藏所有扇形
|
||||||
changeSectorsInLayer('sectors_monitor', false)
|
changeSectorsInLayer('sectors_monitor', false)
|
||||||
getVideoInfo({ id: item.id }).then(res => {
|
getVideoInfo({ id: item.id }).then(res => {
|
||||||
const visionDistance = item.visionDistance * 1000 || 5 * 1000 // 视角距离
|
const visionDistance = item.visionDistance * 1000 || 5 * 1000 // 视角距离
|
||||||
const pvalue = res.data.ptzcfg.pValue || 0 // 旋转角度
|
const pvalue = res.data.ptzcfg?.pValue || 0 // 旋转角度
|
||||||
drawSector('_monitor', [ item.longitude, item.latitude ], visionDistance, item.id, (90 - pvalue) % 360)
|
drawSector('_monitor', [ item.longitude, item.latitude ], visionDistance, item.id, (90 - pvalue) % 360)
|
||||||
|
|
||||||
// 确保扇形图层是可见的
|
// 确保扇形图层是可见的
|
||||||
@@ -369,7 +336,6 @@ const initUAV = () => {
|
|||||||
addUAVToMap()
|
addUAVToMap()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
const initMonitor = () => {
|
const initMonitor = () => {
|
||||||
const params = {}
|
const params = {}
|
||||||
@@ -394,83 +360,60 @@ const initFence = () => {
|
|||||||
addFenceToMap('detailFence')
|
addFenceToMap('detailFence')
|
||||||
}
|
}
|
||||||
const toModel = () => {
|
const toModel = () => {
|
||||||
mapStore.updateDialog({ visible: true, type: 'largeModel' })
|
router.push('/largeModel')
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initMap()
|
initMap()
|
||||||
initFence()
|
// 监控设备图层初始化
|
||||||
initUAV()
|
Object.values(layerMehods).forEach(initFunc => initFunc())
|
||||||
initMonitor()
|
|
||||||
initAisStation()
|
|
||||||
initEnvironmental()
|
|
||||||
// 渔船链接
|
// 渔船链接
|
||||||
BoatUtil.init(mapStore)
|
BoatUtil.init(mapStore)
|
||||||
BoatUtil.getShip()
|
BoatUtil.getShip()
|
||||||
// 轨迹图层
|
// 轨迹图层
|
||||||
initLayerToMap('track')
|
initLayerToMap('track')
|
||||||
})
|
})
|
||||||
watch(() => UAV.value, () => {
|
const layerMehods = {
|
||||||
if(UAV.value) {
|
UAV: initUAV,
|
||||||
initUAV()
|
monitor: initMonitor,
|
||||||
}else{
|
ais_station: initAisStation,
|
||||||
vector.UAV?.hide()
|
environmental: initEnvironmental,
|
||||||
changeSectorsInLayer('sectors_UAV', false)
|
fence: initFence
|
||||||
}
|
}
|
||||||
})
|
watch(() => Object.keys(layerMehods).reduce((obj, key) => {
|
||||||
watch(() => monitor.value, () => {
|
obj[key] = legend.value[key]
|
||||||
if(monitor.value) {
|
return obj
|
||||||
initMonitor()
|
}, {}), (newVal, oldVal) => {
|
||||||
|
Object.keys(layerMehods).forEach(key => {
|
||||||
|
// 监听值变化进行更改
|
||||||
|
if (newVal[key] !== oldVal[key]) {
|
||||||
|
if (newVal[key]) {
|
||||||
|
layerMehods[key]()
|
||||||
} else {
|
} else {
|
||||||
vector.monitor?.hide()
|
vector[key]?.hide()
|
||||||
changeSectorsInLayer('sectors_monitor', false)
|
if (key === 'UAV' || key === 'monitor') { // 无人机和监控可视区域隐藏
|
||||||
}
|
changeSectorsInLayer('sectors_' + key, false)
|
||||||
})
|
} else if (key === 'fence') {
|
||||||
watch(() => ais_station.value, () => {
|
|
||||||
if(ais_station.value) {
|
|
||||||
initAisStation()
|
|
||||||
}else{
|
|
||||||
vector.ais_station?.hide()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
watch(() => environmental.value, () => {
|
|
||||||
if(environmental.value) {
|
|
||||||
initEnvironmental()
|
|
||||||
}else{
|
|
||||||
vector.environmental?.hide()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
watch(() => fence.value, () => {
|
|
||||||
if(fence.value) {
|
|
||||||
initFence()
|
|
||||||
}else{
|
|
||||||
vector.fence?.hide()
|
|
||||||
vector.detailFence?.hide()
|
vector.detailFence?.hide()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
watch(() => sector.value.monitor, (newVal) => {
|
}, { deep: true })
|
||||||
if(vector.sectors_monitor) {
|
const watchKeys = [ 'sectors_monitor', 'sectors_UAV' ]
|
||||||
if(newVal) {
|
watch(() => ({ sectors_UAV: legend.value.sectors_UAV, sectors_monitor: legend.value.sectors_monitor }), (newVal, oldVal) => {
|
||||||
// vector.sectors_monitor.show()
|
watchKeys.forEach(key => {
|
||||||
changeSectorsInLayer('sectors_monitor', true)
|
// 监听值变化进行更改
|
||||||
|
if (newVal[key] !== oldVal[key]) {
|
||||||
|
if (newVal[key]) {
|
||||||
|
changeSectorsInLayer(key, true)
|
||||||
} else {
|
} else {
|
||||||
// vector.sectors_monitor.hide()
|
changeSectorsInLayer(key, false)
|
||||||
changeSectorsInLayer('sectors_monitor', false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
watch(() => sector.value.UAV, (newVal) => {
|
|
||||||
if(vector.sectors_UAV) {
|
|
||||||
if(newVal) {
|
|
||||||
// vector.sectors_UAV.show()
|
|
||||||
changeSectorsInLayer('sectors_UAV', true)
|
|
||||||
} else {
|
|
||||||
// vector.sectors_UAV.hide()
|
|
||||||
changeSectorsInLayer('sectors_UAV', false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}, { deep: true })
|
||||||
// 定位数据变化
|
// 定位数据变化
|
||||||
watch(() => locateData.value.videoCode, (newVal) => {
|
watch(() => locateData.value.videoCode, () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
locateMoitor(locateData.value)
|
locateMoitor(locateData.value)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -184,7 +184,6 @@ const cleanupExpiredBoats = () => {
|
|||||||
|
|
||||||
const getShip = () => {
|
const getShip = () => {
|
||||||
findByCurrent().then(res => {
|
findByCurrent().then(res => {
|
||||||
console.log('初始获取')
|
|
||||||
addBoats(res.result)
|
addBoats(res.result)
|
||||||
})
|
})
|
||||||
// ----------船只数据------------------
|
// ----------船只数据------------------
|
||||||
@@ -192,7 +191,6 @@ const getShip = () => {
|
|||||||
dynamicBoatInfoWebSocket.onopen(event => {
|
dynamicBoatInfoWebSocket.onopen(event => {
|
||||||
})
|
})
|
||||||
dynamicBoatInfoWebSocket.onmessage(event => {
|
dynamicBoatInfoWebSocket.onmessage(event => {
|
||||||
console.log('接收数据:', JSON.parse(event.data))
|
|
||||||
if(Array.isArray(JSON.parse(event.data))) {
|
if(Array.isArray(JSON.parse(event.data))) {
|
||||||
addBoats(JSON.parse(event.data))
|
addBoats(JSON.parse(event.data))
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
item.sector = !item.sector
|
item.sector = !item.sector
|
||||||
mapStore.updateSector(item.prop, item.sector)
|
mapStore.updateLegend('sectors_' + item.prop, item.sector)
|
||||||
}
|
}
|
||||||
const toggleExpand = () => {
|
const toggleExpand = () => {
|
||||||
isFold.value = !isFold.value
|
isFold.value = !isFold.value
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
mapStore.updateLegend(item.prop, item.checked)
|
mapStore.updateLegend(item.prop, item.checked)
|
||||||
if(!item.checked && (item.prop === 'monitor' || item.prop === 'UAV')) {
|
if(!item.checked && (item.prop === 'monitor' || item.prop === 'UAV')) {
|
||||||
item.sector = false
|
item.sector = false
|
||||||
mapStore.updateSector(item.prop, item.sector)
|
mapStore.updateLegend('sectors_' + item.prop, item.sector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ onUnmounted(() => {
|
|||||||
.content-wrapper{
|
.content-wrapper{
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 800px;
|
||||||
iframe{
|
iframe{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -283,8 +283,6 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
uninit() {
|
uninit() {
|
||||||
console.log(999);
|
|
||||||
|
|
||||||
let that = this;
|
let that = this;
|
||||||
if (that.oWebControl != null) {
|
if (that.oWebControl != null) {
|
||||||
that.oWebControl.JS_RequestInterface({
|
that.oWebControl.JS_RequestInterface({
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ const routes = [
|
|||||||
auth: false,
|
auth: false,
|
||||||
title: '首页'
|
title: '首页'
|
||||||
},
|
},
|
||||||
component: () => import('@/views/business/index.vue'),
|
component: () => import('@/views/business/index.vue')
|
||||||
children: [
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
|
|||||||
@@ -6,29 +6,22 @@ const useMapStore = defineStore(
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
legend: {
|
legend: {
|
||||||
UAV: true,
|
UAV: true,
|
||||||
|
sectors_UAV: false, // 无人机可视域开关
|
||||||
monitor: true,
|
monitor: true,
|
||||||
|
sectors_monitor: false, // 监控可视域开关
|
||||||
ais_station: true,
|
ais_station: true,
|
||||||
environmental: true,
|
environmental: true,
|
||||||
fence: true
|
fence: true
|
||||||
},
|
},
|
||||||
windowInfo: {
|
windowInfo: {
|
||||||
visible: false,
|
visible: false,
|
||||||
type: '',
|
type: '', // 弹窗类型 _monitor/_UAV/_trawler_dynamic
|
||||||
data: {}
|
data: {}
|
||||||
},
|
},
|
||||||
sector: {
|
|
||||||
'UAV': false, // 无人机可视域开关
|
|
||||||
'monitor': false // 监控可视域开关
|
|
||||||
},
|
|
||||||
hik: { // 海康插件设备层级
|
hik: { // 海康插件设备层级
|
||||||
level: 1,
|
level: 1,
|
||||||
data: {}
|
data: {}
|
||||||
},
|
},
|
||||||
dialog: {
|
|
||||||
visible: false,
|
|
||||||
type: '', // 弹窗类型 alarm/CCTV/UAV/largeModel
|
|
||||||
data: {}
|
|
||||||
},
|
|
||||||
// 无人机信息
|
// 无人机信息
|
||||||
uavs: {
|
uavs: {
|
||||||
data: {}
|
data: {}
|
||||||
@@ -48,20 +41,11 @@ const useMapStore = defineStore(
|
|||||||
this.windowInfo.type = type
|
this.windowInfo.type = type
|
||||||
this.windowInfo.data = data
|
this.windowInfo.data = data
|
||||||
},
|
},
|
||||||
updateSector(type, checked) {
|
|
||||||
this.sector[type] = checked
|
|
||||||
},
|
|
||||||
updateHik(option) {
|
updateHik(option) {
|
||||||
const { level = 1, data = {} } = option
|
const { level = 1, data = {} } = option
|
||||||
this.hik.level = level
|
this.hik.level = level
|
||||||
this.hik.data = data
|
this.hik.data = data
|
||||||
},
|
},
|
||||||
updateDialog(option) {
|
|
||||||
const { visible = false, type = '', data } = option
|
|
||||||
this.dialog.visible = visible
|
|
||||||
this.dialog.type = type
|
|
||||||
this.dialog.data = data
|
|
||||||
},
|
|
||||||
updateUavData(option) {
|
updateUavData(option) {
|
||||||
this.uavs.data = option
|
this.uavs.data = option
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
|
|
||||||
const useToolBarStore = defineStore(
|
|
||||||
'toolbar',
|
|
||||||
{
|
|
||||||
state: () => ({
|
|
||||||
expand: false, //地图图例位置
|
|
||||||
trawler: {
|
|
||||||
visible: false // 渔船动态详情收缩框显示
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
actions: {
|
|
||||||
toogleExpand(expand) {
|
|
||||||
this.expand = expand
|
|
||||||
},
|
|
||||||
toggleTrawlerVisible(visible) {
|
|
||||||
this.trawler.visible = visible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default useToolBarStore
|
|
||||||
@@ -5,11 +5,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import useMapStore from '@/store/modules/map'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const mapStore = useMapStore()
|
const router = useRouter()
|
||||||
const handle = (type) => {
|
const handle = (type) => {
|
||||||
mapStore.updateDialog({ visible: true, type })
|
router.push({ path: '/wall', query: { type } })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -61,12 +61,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import SubtitleComponent from '@/components/SubtItle/index.vue'
|
import SubtitleComponent from '@/components/SubtItle/index.vue'
|
||||||
import { reactive, ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import useMapStore from '@/store/modules/map'
|
|
||||||
import { videoIdentificationPage } from '@/api/identification.js'
|
import { videoIdentificationPage } from '@/api/identification.js'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const emit = defineEmits([ 'toggle-fold' ])
|
const emit = defineEmits([ 'toggle-fold' ])
|
||||||
const mapStore = useMapStore()
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
label: '无船号',
|
label: '无船号',
|
||||||
@@ -120,7 +120,7 @@ const toggle = (index) => {
|
|||||||
const handle = (type, item) => {
|
const handle = (type, item) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'more':
|
case 'more':
|
||||||
mapStore.updateDialog({ visible: true, type: 'alarm', data: { isHasBoatName: current.value == 1 ? 1 : 2 } })
|
router.push({ path: '/identification', query: { isHasBoatName: current.value == 1 ? 1 : 2 } })
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const lock = ref(false)
|
|||||||
let timer = null
|
let timer = null
|
||||||
let monitorIndex = 0
|
let monitorIndex = 0
|
||||||
const videoUrl = ref('')
|
const videoUrl = ref('')
|
||||||
|
const time = ref(10000)
|
||||||
|
|
||||||
const handle = (index) => {
|
const handle = (index) => {
|
||||||
if(index === 0) {
|
if(index === 0) {
|
||||||
@@ -57,33 +58,40 @@ const init = () => {
|
|||||||
const params = {}
|
const params = {}
|
||||||
videoUrl.value = ''
|
videoUrl.value = ''
|
||||||
dsVideoList(params).then(res => {
|
dsVideoList(params).then(res => {
|
||||||
data.value = res.data.filter(i => i.videoUrl).sort((a, b) => a.playIndex - b.playIndex)
|
data.value = res.data.filter(i => i.videoUrl && i.bePlay === 1).sort((a, b) => a.playIndex - b.playIndex)
|
||||||
videoUrl.value = data.value[monitorIndex].videoUrl
|
// 启动轮播定时器
|
||||||
mapStore.updateLocate(data.value[monitorIndex])
|
startPolling()
|
||||||
clearTimer()
|
})
|
||||||
handlePolling(true) // 开始轮询
|
|
||||||
timer = setInterval(() => {
|
|
||||||
if(lock.value) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 启动轮播
|
||||||
|
const startPolling = () => {
|
||||||
|
clearTimer()
|
||||||
|
const runPolling = () => {
|
||||||
|
if (!lock.value) {
|
||||||
|
switchToNextVideo()
|
||||||
|
}
|
||||||
|
timer = setTimeout(runPolling, time.value)
|
||||||
|
}
|
||||||
|
runPolling()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换到下一个视频
|
||||||
|
const switchToNextVideo = () => {
|
||||||
videoUrl.value = ''
|
videoUrl.value = ''
|
||||||
|
time.value = data.value[monitorIndex].playTime * 1000 || 10 * 1000
|
||||||
|
mapStore.updateLocate(data.value[monitorIndex])
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
videoUrl.value = data.value[monitorIndex].videoUrl
|
||||||
|
// 更新播放时间
|
||||||
if (monitorIndex >= data.value.length - 1) {
|
if (monitorIndex >= data.value.length - 1) {
|
||||||
handlePolling(false) // 轮询结束
|
monitorIndex = 0 // 回到第一个
|
||||||
monitorIndex = 0
|
|
||||||
handlePolling(true) // 开始轮询
|
|
||||||
} else {
|
} else {
|
||||||
monitorIndex++
|
monitorIndex++
|
||||||
}
|
}
|
||||||
videoUrl.value = data.value[monitorIndex].videoUrl
|
|
||||||
})
|
|
||||||
mapStore.updateLocate(data.value[monitorIndex])
|
|
||||||
}, 60 * 1000 * 0.5)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handlePolling = (flag) => {
|
|
||||||
console.log(flag + '---轮询')
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 拖拽事件
|
* 拖拽事件
|
||||||
* @param e
|
* @param e
|
||||||
@@ -96,8 +104,7 @@ const drag = (e) => {
|
|||||||
document.querySelector('.monitor-container').style.width = i.width + 'px'
|
document.querySelector('.monitor-container').style.width = i.width + 'px'
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
dragEvent(e, 'monitor-container', () => {
|
dragEvent(e, 'monitor-container', () => { /* empty */ })
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -45,154 +45,8 @@ onMounted(() => {
|
|||||||
drone_sn: data.value.droneSn // 飞机 sn,按实际传入
|
drone_sn: data.value.droneSn // 飞机 sn,按实际传入
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// // 使用轮询方式等待内容加载完成后再滚动
|
|
||||||
// waitForContentAndScroll()
|
|
||||||
})
|
|
||||||
const waitForContentAndScroll = () => {
|
|
||||||
let attempts = 0
|
|
||||||
let previousScrollWidth = 0
|
|
||||||
let stableCount = 0
|
|
||||||
const maxAttempts = 30
|
|
||||||
const checkAndScroll = () => {
|
|
||||||
attempts++
|
|
||||||
|
|
||||||
if (Detail.value) {
|
|
||||||
// 检查目标容器是否已加载内容
|
|
||||||
const mapContainer = document.getElementById('map-app-global')
|
|
||||||
|
|
||||||
// 判断内容是否加载完成
|
|
||||||
const isContentLoaded = mapContainer && mapContainer.children.length > 0
|
|
||||||
// console.log('Content loaded:', isContentLoaded, mapContainer)
|
|
||||||
// 获取当前尺寸
|
|
||||||
const currentScrollWidth = Detail.value.scrollWidth
|
|
||||||
const clientWidth = Detail.value.clientWidth
|
|
||||||
|
|
||||||
// console.log('Size check:', {
|
|
||||||
// attempt: attempts,
|
|
||||||
// scrollWidth: currentScrollWidth,
|
|
||||||
// clientWidth: clientWidth,
|
|
||||||
// isContentLoaded: isContentLoaded
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 检查尺寸是否稳定(连续几次尺寸相同)
|
|
||||||
if (currentScrollWidth === previousScrollWidth && currentScrollWidth > clientWidth) {
|
|
||||||
stableCount++
|
|
||||||
} else {
|
|
||||||
stableCount = 0
|
|
||||||
}
|
|
||||||
previousScrollWidth = currentScrollWidth
|
|
||||||
// 当内容加载完成且尺寸稳定,或者达到最大尝试次数时执行滚动
|
|
||||||
if (isContentLoaded && stableCount >= 2 && currentScrollWidth > clientWidth ||
|
|
||||||
attempts >= maxAttempts) {
|
|
||||||
|
|
||||||
// 强制重新计算布局
|
|
||||||
forceLayoutRecalculation(() => {
|
|
||||||
executeScroll()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 内容未加载完成或尺寸不稳定,继续等待
|
|
||||||
setTimeout(checkAndScroll, 300)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始检查
|
|
||||||
setTimeout(checkAndScroll, 300)
|
|
||||||
}
|
|
||||||
const forceLayoutRecalculation = (callback) => {
|
|
||||||
if (!Detail.value) {
|
|
||||||
if (callback) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方法1: 强制重排
|
|
||||||
Detail.value.style.display = 'none'
|
|
||||||
void Detail.value.offsetHeight // 强制重排
|
|
||||||
Detail.value.style.display = 'flex'
|
|
||||||
|
|
||||||
// 方法2: 临时修改overflow触发重新计算
|
|
||||||
const originalOverflow = Detail.value.style.overflow
|
|
||||||
Detail.value.style.overflow = 'hidden'
|
|
||||||
void Detail.value.offsetWidth
|
|
||||||
Detail.value.style.overflow = originalOverflow
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (callback) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
const executeScroll = () => {
|
|
||||||
if (!Detail.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新获取准确的尺寸
|
|
||||||
const scrollWidth = Detail.value.scrollWidth
|
|
||||||
const clientWidth = Detail.value.clientWidth
|
|
||||||
const maxScroll = scrollWidth - clientWidth
|
|
||||||
|
|
||||||
// console.log('Final size calculation:', {
|
|
||||||
// scrollWidth,
|
|
||||||
// clientWidth,
|
|
||||||
// maxScroll
|
|
||||||
// })
|
|
||||||
|
|
||||||
if (maxScroll > 0) {
|
|
||||||
const targetPosition = 1388
|
|
||||||
const scrollPosition = targetPosition > maxScroll ? maxScroll : targetPosition
|
|
||||||
|
|
||||||
// 修复:正确处理 scrollPosition 为 0 的情况
|
|
||||||
const finalPosition = typeof scrollPosition === 'number' ? scrollPosition : 645
|
|
||||||
|
|
||||||
// 激活滚动机制后再执行滚动
|
|
||||||
activateScrollMechanism(() => {
|
|
||||||
Detail.value.scrollTo({
|
|
||||||
left: finalPosition,
|
|
||||||
behavior: 'smooth'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// console.log('Scrolled to position:', finalPosition,
|
|
||||||
// 'Max scroll:', maxScroll,
|
|
||||||
// 'Container width:', clientWidth,
|
|
||||||
// 'Scroll width:', scrollWidth)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// console.log('No scrollable content, but content is loaded')
|
|
||||||
// 即使没有滚动内容,也尝试激活滚动机制
|
|
||||||
activateScrollMechanism(() => {
|
|
||||||
Detail.value.scrollTo({
|
|
||||||
left: 645,
|
|
||||||
behavior: 'smooth'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const activateScrollMechanism = (callback) => {
|
|
||||||
if (!Detail.value) {
|
|
||||||
if (callback) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 预激活滚动机制
|
|
||||||
Detail.value.scrollTo({ left: 1, behavior: 'instant' })
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
Detail.value.scrollTo({ left: 0, behavior: 'instant' })
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (callback) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}, 50)
|
|
||||||
}, 20)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.fh2-container {
|
.fh2-container {
|
||||||
|
|||||||
@@ -203,7 +203,6 @@ const rules = {
|
|||||||
model[key] = props.data[key]
|
model[key] = props.data[key]
|
||||||
if(key === 'illegalType') {
|
if(key === 'illegalType') {
|
||||||
model[key] = props.data[key].map(i => i.label)
|
model[key] = props.data[key].map(i => i.label)
|
||||||
console.log(model[key])
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,6 @@
|
|||||||
<FilterCom ref="Filter" :filter-buttons="filterButtons" :filter-items="items" :filter-model="model" @handle="handle"/>
|
<FilterCom ref="Filter" :filter-buttons="filterButtons" :filter-items="items" :filter-model="model" @handle="handle"/>
|
||||||
<!-- 多选框筛选 -->
|
<!-- 多选框筛选 -->
|
||||||
<div class="Form">
|
<div class="Form">
|
||||||
<!-- 暂时只支持单个类型的筛选 -->
|
|
||||||
<!-- <el-checkbox-group v-model="illegalType" :max="1">
|
|
||||||
<el-checkbox
|
|
||||||
v-for="item in illegalTypes"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value" />
|
|
||||||
</el-checkbox-group> -->
|
|
||||||
<el-radio-group v-model="illegalType" @change="changeRadio">
|
<el-radio-group v-model="illegalType" @change="changeRadio">
|
||||||
<el-radio v-for="item in illegalTypes"
|
<el-radio v-for="item in illegalTypes"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
@@ -98,9 +90,6 @@ import { useRoute } from 'vue-router'
|
|||||||
import DialogComponent from '@/components/Dialog/screen.vue'
|
import DialogComponent from '@/components/Dialog/screen.vue'
|
||||||
import DetailComponent from './detail.vue'
|
import DetailComponent from './detail.vue'
|
||||||
|
|
||||||
import useMapStore from '@/store/modules/map'
|
|
||||||
const mapStore = useMapStore()
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const illegalTypes = [
|
const illegalTypes = [
|
||||||
{ value: '未封舱预警', label: '未封舱预警', prop: 'warning' },
|
{ value: '未封舱预警', label: '未封舱预警', prop: 'warning' },
|
||||||
@@ -258,7 +247,6 @@ const columns = ref([
|
|||||||
])
|
])
|
||||||
const config = {
|
const config = {
|
||||||
label: '操作',
|
label: '操作',
|
||||||
// width: 60
|
|
||||||
width: 150
|
width: 150
|
||||||
}
|
}
|
||||||
const operate = [
|
const operate = [
|
||||||
@@ -344,7 +332,6 @@ const initData = () => {
|
|||||||
const params = new FormData()
|
const params = new FormData()
|
||||||
const obj = {
|
const obj = {
|
||||||
...model,
|
...model,
|
||||||
// illegalType: illegalType.value.join(','),
|
|
||||||
illegalType: illegalType.value,
|
illegalType: illegalType.value,
|
||||||
beginTime: model.time && model.time[0] ? model.time[0] : '',
|
beginTime: model.time && model.time[0] ? model.time[0] : '',
|
||||||
endTime: model.time && model.time[1] ? model.time[1] : '',
|
endTime: model.time && model.time[1] ? model.time[1] : '',
|
||||||
@@ -352,9 +339,6 @@ const initData = () => {
|
|||||||
pageSize: pagination.size
|
pageSize: pagination.size
|
||||||
}
|
}
|
||||||
delete obj.time
|
delete obj.time
|
||||||
// Object.keys(obj).forEach((key) => {
|
|
||||||
// params.append(key, obj[key])
|
|
||||||
// })
|
|
||||||
videoIdentificationPage(obj).then(res => {
|
videoIdentificationPage(obj).then(res => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
tableData.value = res.result.records.map(i => {
|
tableData.value = res.result.records.map(i => {
|
||||||
@@ -378,63 +362,6 @@ const initData = () => {
|
|||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
// tableData.value = [
|
|
||||||
// {
|
|
||||||
// 'aisStatus': '未开启',
|
|
||||||
// 'belongPort': '',
|
|
||||||
// 'boatCodePath': '',
|
|
||||||
// 'boatName': '浙周田货0998',
|
|
||||||
// 'boatNameEn': 'WUCHUANHAO',
|
|
||||||
// 'cog': '0',
|
|
||||||
// 'createAt': '2025-12-01 11:04:44',
|
|
||||||
// 'createBy': '',
|
|
||||||
// 'crossLineTime': null,
|
|
||||||
// 'delFlag': 0,
|
|
||||||
// 'distance': null,
|
|
||||||
// 'draftMarks': null,
|
|
||||||
// 'entryOut': '',
|
|
||||||
// 'height': 0.00000000,
|
|
||||||
// 'heightRange': '',
|
|
||||||
// 'hkResult': '',
|
|
||||||
// 'id': 76168,
|
|
||||||
// 'identificationType': '',
|
|
||||||
// 'illegalType': '未穿救生衣预警,未封舱预警,未悬挂国旗',
|
|
||||||
// 'isCloseDoor': '否',
|
|
||||||
// 'isHasAis': '否',
|
|
||||||
// 'jacketStatus': '',
|
|
||||||
// 'latitude': null,
|
|
||||||
// 'length': 0.00000000,
|
|
||||||
// 'longitude': null,
|
|
||||||
// 'mmsi': '413823183',
|
|
||||||
// 'shipType': '集装箱船',
|
|
||||||
// 'sourcePicPath': 'http://198.16.74.209:6060/pic/2025-12-01/198.16.74.187/20251201_110559/ship_1_20251201_110559_644.jpg',
|
|
||||||
// 'speed': null,
|
|
||||||
// 'streetName': '',
|
|
||||||
// 'sysShipName': '',
|
|
||||||
// 'sysUpdateName': '',
|
|
||||||
// 'systemResult': '',
|
|
||||||
// 'takeTime': '2025-12-23 11:06:08',
|
|
||||||
// 'takeType': '卡口',
|
|
||||||
// 'trackerPicPath': 'http://198.16.74.209:6060/pic/2025-12-01/198.16.74.187/20251201_110559/ship_1_20251201_110559_644.jpg,http://198.16.74.209:6060/pic/2025-12-01/198.16.74.187/20251201_110559/ship_2_20251201_110603_161.jpg,http://198.16.74.209:6060/pic/2025-12-01/198.16.74.187/20251201_110559/ship_3_20251201_110605_535.jpg,http://198.16.74.209:6060/pic/2025-12-01/198.16.74.187/20251201_110559/ship_4_20251201_110608_298.jpg',
|
|
||||||
// 'updateAt': '2025-12-01 11:04:44',
|
|
||||||
// 'updateBy': '',
|
|
||||||
// 'videoCode': 'fd3b45e1429a4e47bba873af602a9bed',
|
|
||||||
// 'videoName': '卧旗--雷云一体机',
|
|
||||||
// 'videoUrl': '',
|
|
||||||
// 'width': 0.00000000
|
|
||||||
// }, {}
|
|
||||||
// ].map(i => {
|
|
||||||
// return {
|
|
||||||
// ...i,
|
|
||||||
// illegalType: i.illegalType?.split(',').map(j => {
|
|
||||||
// return {
|
|
||||||
// value: illegalTypes.find(type => type.value === j)?.prop,
|
|
||||||
// label: j
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// handle('check', tableData.value.length > 0 ? tableData.value[0] : {})
|
|
||||||
}
|
}
|
||||||
const changeRadio = () => {
|
const changeRadio = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -526,17 +453,7 @@ const closeDetail = () => {
|
|||||||
initData()
|
initData()
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
model.isHasBoatName = mapStore.dialog.data.isHasBoatName
|
model.isHasBoatName = route.query.isHasBoatName
|
||||||
console.log(model)
|
|
||||||
if(Object.keys(route.query).length > 0 && route.query.type === 'alarm') {
|
|
||||||
model.takeType = route.query.takeType
|
|
||||||
illegalType.value = route.query.illegalType
|
|
||||||
nextTick(() => {
|
|
||||||
if (Filter.value && Filter.value.model) {
|
|
||||||
Filter.value.model.takeType = route.query.takeType
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
initData()
|
initData()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 识别记录页面 -->
|
<!-- 识别记录页面 -->
|
||||||
<DialogComponent :style="{ resize: 'both', overflow: 'auto' }" v-if="type === 'alarm'" title="识别记录" width="1800" :draggable="true" :modal="false" @close="close">
|
<DialogComponent :style="{ resize: 'both', overflow: 'auto' }" title="识别记录" width="1800" :draggable="true" :modal="false" @close="close">
|
||||||
<AlarmCom/>
|
<AlarmCom/>
|
||||||
</DialogComponent>
|
</DialogComponent>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
|
||||||
import DialogComponent from '@/components/Dialog/screen.vue'
|
import DialogComponent from '@/components/Dialog/screen.vue'
|
||||||
import AlarmCom from './alarm/index.vue'
|
import AlarmCom from './alarm/index.vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import useMapStore from '@/store/modules/map'
|
|
||||||
|
|
||||||
const mapStore = useMapStore()
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const type = computed(() => mapStore.dialog.type)
|
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
mapStore.updateDialog(false)
|
router.push('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,24 +6,13 @@
|
|||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
<Alarm/>
|
<Alarm/>
|
||||||
<LargeModelCom v-if="visible && type === 'largeModel'"/>
|
|
||||||
<IdentificationCom v-if="visible && type === 'alarm'"/>
|
|
||||||
<WallCom v-if="visible && (type==='CCTV'|| type==='UAV')"/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import HeaderMenuComponent from '@/components/HeaderMenu/index.vue'
|
import HeaderMenuComponent from '@/components/HeaderMenu/index.vue'
|
||||||
import MapComponent from '@/components/Map/index.vue'
|
import MapComponent from '@/components/Map/index.vue'
|
||||||
import Alarm from '@/views/business/alarm/index.vue'
|
import Alarm from '@/views/business/alarm/index.vue'
|
||||||
import LargeModelCom from '@/views/business/largeModel/index.vue'
|
|
||||||
import IdentificationCom from '@/views/business/identification/index.vue'
|
|
||||||
import WallCom from '@/views/business/wall/index.vue'
|
|
||||||
import useMapStore from '@/store/modules/map'
|
|
||||||
import { computed } from 'vue'
|
|
||||||
|
|
||||||
const mapStore = useMapStore()
|
|
||||||
const visible = computed(() => mapStore.dialog.visible)
|
|
||||||
const type = computed(() => mapStore.dialog.type)
|
|
||||||
window.name = 'business_window'
|
window.name = 'business_window'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -202,7 +191,7 @@ window.name = 'business_window'
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 7px;
|
right: 7px;
|
||||||
i:not(.el-select__clear) {
|
i:not(.el-select__clear) {
|
||||||
// background: url("@/assets/images/common/icon_suffix.png") center center no-repeat;
|
background: url("@/assets/images/common/icon_suffix.png") center center no-repeat;
|
||||||
background-size: 8px 6px;
|
background-size: 8px 6px;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
@@ -230,7 +219,7 @@ window.name = 'business_window'
|
|||||||
right: 7px;
|
right: 7px;
|
||||||
top: 13px;
|
top: 13px;
|
||||||
.el-input__suffix-inner{
|
.el-input__suffix-inner{
|
||||||
// background: url("@/assets/images/common/icon_suffix.png") center center no-repeat;
|
background: url("@/assets/images/common/icon_suffix.png") center center no-repeat;
|
||||||
background-size: 8px 6px;
|
background-size: 8px 6px;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
|
|||||||
@@ -256,13 +256,11 @@ const send = () => {
|
|||||||
additionalContent += '\n' + data.mp4_url.join(' ') + '\n'
|
additionalContent += '\n' + data.mp4_url.join(' ') + '\n'
|
||||||
}
|
}
|
||||||
if(data.rtsp_url && Array.isArray(data.rtsp_url)) {
|
if(data.rtsp_url && Array.isArray(data.rtsp_url)) {
|
||||||
console.log('data.rtsp_url', data.rtsp_url)
|
|
||||||
data.rtsp_url.forEach(item => {
|
data.rtsp_url.forEach(item => {
|
||||||
additionalContent += '\n' + JSON.stringify(item) + '\n'
|
additionalContent += '\n' + JSON.stringify(item) + '\n'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if(data.rtsp_data && Array.isArray(data.rtsp_data)) {
|
if(data.rtsp_data && Array.isArray(data.rtsp_data)) {
|
||||||
console.log('data.rtsp_data', data.rtsp_data)
|
|
||||||
data.rtsp_data.forEach(item => {
|
data.rtsp_data.forEach(item => {
|
||||||
additionalContent += '\n' + JSON.stringify(item) + '\n'
|
additionalContent += '\n' + JSON.stringify(item) + '\n'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ import { dragEvent } from '@/utils/common'
|
|||||||
import { getVideoStream, doStartOrStopUavAlgorithm } from '@/api/uav'
|
import { getVideoStream, doStartOrStopUavAlgorithm } from '@/api/uav'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import useMapStore from '@/store/modules/map'
|
import useMapStore from '@/store/modules/map'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
const uavData = computed(() => mapStore.uavs.data)
|
const uavData = computed(() => mapStore.uavs.data)
|
||||||
const ModuleLeft = ref(null)
|
const ModuleLeft = ref(null)
|
||||||
@@ -105,7 +107,7 @@ const initList = () => {
|
|||||||
History.value.initList()
|
History.value.initList()
|
||||||
}
|
}
|
||||||
const close = () => {
|
const close = () => {
|
||||||
mapStore.updateDialog({ visible: false, type: 'largeModel' })
|
router.push('/')
|
||||||
}
|
}
|
||||||
const openVideo = (data) => {
|
const openVideo = (data) => {
|
||||||
visible.value = data.visible
|
visible.value = data.visible
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ const renderMedia = (url, text) => {
|
|||||||
if (!url) {
|
if (!url) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
console.log(url, 'url')
|
|
||||||
// 监控
|
// 监控
|
||||||
if (url.startsWith('{') && url.includes('rtsp_url')) {
|
if (url.startsWith('{') && url.includes('rtsp_url')) {
|
||||||
const videoNameMatch = JSON.parse(url).video_name
|
const videoNameMatch = JSON.parse(url).video_name
|
||||||
@@ -193,7 +192,29 @@ return ''
|
|||||||
// 监控视频查看
|
// 监控视频查看
|
||||||
const openVideoHandler = (index) => {
|
const openVideoHandler = (index) => {
|
||||||
const data = videoArr.value[index]
|
const data = videoArr.value[index]
|
||||||
|
// 雷云一体机一个视频
|
||||||
|
if(data.videoName.indexOf('雷云') !== -1) {
|
||||||
|
const videos = videoArr.value.filter(i => i.videoName.indexOf('雷云') !== -1).sort((a, b) => {
|
||||||
|
const index1 = a.videoName[a.videoName.length - 1]
|
||||||
|
const index2 = b.videoName[b.videoName.length - 1]
|
||||||
|
return index1 - index2
|
||||||
|
})
|
||||||
|
|
||||||
|
codes.value = [ videos[0].videoCode ]
|
||||||
|
}else{
|
||||||
|
if(data.videoName.indexOf('球机') !== -1) {
|
||||||
|
const videos = videoArr.value.filter(i => i.videoName.indexOf('球机') !== -1).sort((a, b) => {
|
||||||
|
const index1 = a.videoName[a.videoName.length - 1]
|
||||||
|
const index2 = b.videoName[b.videoName.length - 1]
|
||||||
|
return index1 - index2
|
||||||
|
})
|
||||||
|
codes.value = videos.map((i, index) => {
|
||||||
|
return i.previewUrl
|
||||||
|
})
|
||||||
|
}else{
|
||||||
codes.value = [ data.videoCode ]
|
codes.value = [ data.videoCode ]
|
||||||
|
}
|
||||||
|
}
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
|
|||||||
85
src/views/business/setting/index.vue
Normal file
85
src/views/business/setting/index.vue
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 业务配置页面 -->
|
||||||
|
<DialogComponent :style="{ resize: 'both', overflow: 'auto' }" title="业务配置" width="1800" :draggable="true" :modal="false" @close="close">
|
||||||
|
<div class="tabs-container">
|
||||||
|
<el-tabs v-model="type" tab-position="left" class="tabs">
|
||||||
|
<el-tab-pane v-for="item in tabs"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:name="item.value">
|
||||||
|
<template #label>
|
||||||
|
<span class="custom-tabs-label">
|
||||||
|
<span>{{item.label}}</span>
|
||||||
|
<el-icon v-if="type == item.value"><CaretRight /></el-icon>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<CCTVComponent v-if="type === 'cctv'"/>
|
||||||
|
</div>
|
||||||
|
</DialogComponent>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { CaretRight } from '@element-plus/icons-vue'
|
||||||
|
import DialogComponent from '@/components/Dialog/screen.vue'
|
||||||
|
import CCTVComponent from './monitor/index.vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const tabs = ref([
|
||||||
|
{
|
||||||
|
value: 'cctv',
|
||||||
|
label: 'CCTV'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'UAV',
|
||||||
|
label: '无人机'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const type = ref('cctv')
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
router.push('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.tabs-container{
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.el-tabs {
|
||||||
|
box-sizing: border-box;
|
||||||
|
:deep(.el-tabs__header){
|
||||||
|
&.is-left{
|
||||||
|
margin-right: 20px !important;
|
||||||
|
}
|
||||||
|
.el-tabs__nav-wrap::after {
|
||||||
|
background-color: rgba(0, 192, 255, 0.2) !important;
|
||||||
|
}
|
||||||
|
.el-tabs__item {
|
||||||
|
width: 200px;
|
||||||
|
color: rgba(68, 165, 255, 1);
|
||||||
|
justify-content: center;
|
||||||
|
&.is-active{
|
||||||
|
color: #00C0FF;
|
||||||
|
background: rgba(10, 169, 255, 0.15);
|
||||||
|
.el-icon{
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-tabs__item.is-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.el-tabs__active-bar {
|
||||||
|
background-color: #00C0FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content{
|
||||||
|
width: calc(100% - 220px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
262
src/views/business/setting/monitor/detail.vue
Normal file
262
src/views/business/setting/monitor/detail.vue
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
<template>
|
||||||
|
<el-form class="detail-form" ref="form" :model="model" label-width="auto" :rules="rules" label-suffix=":">
|
||||||
|
<el-form-item v-for="(item,index) in items" :key="index" :label="item.label" :prop="item.prop" :style="`grid-column-start: span ${item.width || '1'};`">
|
||||||
|
|
||||||
|
<el-input v-if="item.type === 'input'" v-model="model[item.prop]" :readonly="type==='check'"/>
|
||||||
|
<el-input v-if="item.type === 'textarea'" autosize v-model="model[item.prop]" :rows="item.rows || 2" type="textarea" :readonly="type==='check'"/>
|
||||||
|
<el-input-number v-if="item.type === 'number'" v-model="model[item.prop]" :min="item.min || 0" style="width: 100%;" :readonly="type==='check'"/>
|
||||||
|
|
||||||
|
<el-select v-if="item.type === 'select'" v-model="model[item.prop]" :clearable="item.clearable" :disabled="type==='check'">
|
||||||
|
<el-option v-for="(opt, index) in item.options" :key="index" :label="opt.label" :value="opt.value">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<el-date-picker v-if="item.type === 'datetime'" v-model="model[item.prop]" type="datetime"
|
||||||
|
:placeholder="item.placeholder ? item.placeholder : '请选择时间'" value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
:clearable="item.clearable" style="width:100%" :readonly="type==='check'">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div class="button-wrapper" v-if="type !== 'check'">
|
||||||
|
<el-button type="primary" @click="validate">提交</el-button>
|
||||||
|
<el-button type="primary" @click="$emit('close')">取消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { dsVideoSave, dsVideoUpdate } from '@/api/device'
|
||||||
|
|
||||||
|
const emit = defineEmits([ 'close' ])
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
required: false,
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
default: '',
|
||||||
|
required: false,
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = ref(null)
|
||||||
|
|
||||||
|
const model = reactive({
|
||||||
|
videoCode: '',
|
||||||
|
videoName: '',
|
||||||
|
longitude: '',
|
||||||
|
latitude: '',
|
||||||
|
height: 0,
|
||||||
|
visionDistance: 5,
|
||||||
|
videoIp: '',
|
||||||
|
videoPort: '',
|
||||||
|
videoAccount: '',
|
||||||
|
videoPassword: '',
|
||||||
|
channelNo: '0',
|
||||||
|
videoType: '云台',
|
||||||
|
belongUnit: '',
|
||||||
|
runStatus: '正常',
|
||||||
|
beBayonet: 0,
|
||||||
|
bePlay: 0,
|
||||||
|
playIndex: 1,
|
||||||
|
playTime: 5
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = ref([
|
||||||
|
{
|
||||||
|
label: '监控编号',
|
||||||
|
prop: 'videoCode',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监控名称',
|
||||||
|
prop: 'videoName',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '经度',
|
||||||
|
prop: 'longitude',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '纬度',
|
||||||
|
prop: 'latitude',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监控安装高度(米)',
|
||||||
|
prop: 'height',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '可视距离(公里)',
|
||||||
|
prop: 'visionDistance',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备ip',
|
||||||
|
prop: 'videoIp',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备端口号',
|
||||||
|
prop: 'videoPort',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备账号',
|
||||||
|
prop: 'videoAccount',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备密码',
|
||||||
|
prop: 'videoPassword',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监控类型',
|
||||||
|
prop: 'videoType',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ value: '球机', label: '球机' },
|
||||||
|
{ value: '云台', label: '云台' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '运行状态',
|
||||||
|
prop: 'runStatus',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ value: '正常', label: '正常' },
|
||||||
|
{ value: '故障', label: '故障' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否卡口',
|
||||||
|
prop: 'beBayonet',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ value: 1, label: '是' },
|
||||||
|
{ value: 0, label: '否' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否轮询',
|
||||||
|
prop: 'bePlay',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: '是'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
label: '否'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '轮询顺序',
|
||||||
|
prop: 'playIndex',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '轮询时间(s)',
|
||||||
|
prop: 'playTime',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通道号',
|
||||||
|
prop: 'channelNo',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监管所属单位',
|
||||||
|
prop: 'belongUnit',
|
||||||
|
type: 'input'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
videoCode: [ { required: true, message: '监控编号 未填写', trigger: 'blur' } ],
|
||||||
|
videoName: [ { required: true, message: '监控名称 未填写', trigger: 'blur' } ],
|
||||||
|
longitude: [ { required: true, message: '经度 未填写', trigger: 'blur' } ],
|
||||||
|
latitude: [ { required: true, message: '纬度 未填写', trigger: 'blur' } ],
|
||||||
|
height: [ { required: true, message: '监控安装高度 未填写', trigger: 'blur' } ],
|
||||||
|
visionDistance: [ { required: true, message: '可视距离 未填写', trigger: 'blur' } ],
|
||||||
|
videoIp: [ { required: true, message: '设备ip 未填写', trigger: 'blur' } ],
|
||||||
|
videoPort: [ { required: true, message: '设备端口号 未填写', trigger: 'blur' } ],
|
||||||
|
videoAccount: [ { required: true, message: '设备账号 未填写', trigger: 'blur' } ],
|
||||||
|
videoPassword: [ { required: true, message: '设备密码 未填写', trigger: 'blur' } ],
|
||||||
|
videoType: [ { required: true, message: '监控类型 未填写', trigger: 'blur' } ],
|
||||||
|
runStatus: [ { required: true, message: '运行状态 未填写', trigger: 'blur' } ],
|
||||||
|
beBayonet: [ { required: true, message: '是否卡口 未填写', trigger: 'change' } ],
|
||||||
|
bePlay: [ { required: true, message: '是否轮询 未填写', trigger: 'change' } ]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化赋值
|
||||||
|
*/
|
||||||
|
const initData = () => {
|
||||||
|
if (props.type !== 'add') {
|
||||||
|
Object.keys(model).forEach((key) => {
|
||||||
|
model[key] = props.data[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单校验
|
||||||
|
*/
|
||||||
|
const validate = () => {
|
||||||
|
form.value.validate().then((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
submit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单校验
|
||||||
|
*/
|
||||||
|
const submit = () => {
|
||||||
|
const params = {
|
||||||
|
...model
|
||||||
|
}
|
||||||
|
if(props.type === 'add') {
|
||||||
|
dsVideoSave(params).then(() => {
|
||||||
|
ElMessage.success('提交成功!')
|
||||||
|
emit('close', true)
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
dsVideoUpdate({ ...params, id: props.data.id }).then(() => {
|
||||||
|
ElMessage.success('提交成功!')
|
||||||
|
emit('close', true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initData()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.detail-form{
|
||||||
|
display: grid;
|
||||||
|
box-sizing: border-box;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
column-gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-wrapper{
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
263
src/views/business/setting/monitor/index.vue
Normal file
263
src/views/business/setting/monitor/index.vue
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<FilterComponent :filter-buttons="filterButtons" :filter-items="items" :filter-model="model" @handle="handle"/>
|
||||||
|
<TableComponent style="height: 650px;" :loading="loading" :data="tableData" :columns="columns" :config="config" :operate="operate" @handle="handle"/>
|
||||||
|
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size"
|
||||||
|
:total="pagination.total" :page-sizes="[10, 15, 20, 50]" layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="initData" @current-change="initData"
|
||||||
|
style="margin-top: 10px; justify-content: center;" />
|
||||||
|
<DialogComponent v-if="detail.visible" :title="detail.title[detail.type]" :modal="true" width="800"
|
||||||
|
@close="closeDetail">
|
||||||
|
<DetailComponent :data="detail.data" :type="detail.type" @close="closeDetail" />
|
||||||
|
</DialogComponent>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import FilterComponent from '@/components/Filter/index.vue'
|
||||||
|
import TableComponent from '@/components/Table/index2.vue'
|
||||||
|
import DialogComponent from '@/components/Dialog/screen.vue'
|
||||||
|
import DetailComponent from './detail.vue'
|
||||||
|
import { dsVideoPage, dsVideoDelete } from '@/api/device'
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: '监控名称',
|
||||||
|
prop: 'videoName',
|
||||||
|
width: '180px',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监控编号',
|
||||||
|
prop: 'videoCode',
|
||||||
|
width: '180px',
|
||||||
|
type: 'input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否卡口',
|
||||||
|
prop: 'beBayonet',
|
||||||
|
type: 'select',
|
||||||
|
width: '180px',
|
||||||
|
options: [
|
||||||
|
{ value: 1, label: '是' },
|
||||||
|
{ value: 0, label: '否' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否轮询',
|
||||||
|
prop: 'bePlay',
|
||||||
|
type: 'select',
|
||||||
|
width: '180px',
|
||||||
|
options: [
|
||||||
|
{ value: 1, label: '是' },
|
||||||
|
{ value: 0, label: '否' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const filterButtons = ref([
|
||||||
|
{
|
||||||
|
name: '检索',
|
||||||
|
prop: 'query',
|
||||||
|
theme: 'primary',
|
||||||
|
type: 'button'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '新增',
|
||||||
|
prop: 'add',
|
||||||
|
theme: 'primary',
|
||||||
|
type: 'button'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
let model = {
|
||||||
|
videoName: '',
|
||||||
|
videoCode: '',
|
||||||
|
beBayonet: '',
|
||||||
|
bePlay: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref([])
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
label: '监控编号',
|
||||||
|
prop: 'videoCode',
|
||||||
|
width: 290
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监控名称',
|
||||||
|
prop: 'videoName',
|
||||||
|
width: 250
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '经度',
|
||||||
|
prop: 'longitude',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '纬度',
|
||||||
|
prop: 'latitude',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: '设备ip',
|
||||||
|
prop: 'videoIp',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备端口号',
|
||||||
|
prop: 'videoPort',
|
||||||
|
width: 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通道号',
|
||||||
|
prop: 'channelNo',
|
||||||
|
width: 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '监控类型',
|
||||||
|
prop: 'videoType',
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '运行状态',
|
||||||
|
prop: 'runStatus',
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否卡口',
|
||||||
|
prop: 'beBayonetF',
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '是否轮询',
|
||||||
|
prop: 'bePlayF',
|
||||||
|
width: 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
type: 'index',
|
||||||
|
width: 110,
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
|
||||||
|
const operate = [
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
prop: 'edit',
|
||||||
|
theme: 'success'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
prop: 'remove',
|
||||||
|
theme: 'danger'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const pagination = {
|
||||||
|
current: 1,
|
||||||
|
size: 15,
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const detail = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: {
|
||||||
|
add: '监控信息新增',
|
||||||
|
check: '监控信息查看',
|
||||||
|
edit: '监控信息编辑'
|
||||||
|
},
|
||||||
|
type: 'add',
|
||||||
|
data: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const initData = () => {
|
||||||
|
loading.value = true
|
||||||
|
const data = {
|
||||||
|
...model,
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.size
|
||||||
|
}
|
||||||
|
dsVideoPage(data).then(res => {
|
||||||
|
tableData.value = res.rows.map(i => {
|
||||||
|
return {
|
||||||
|
...i,
|
||||||
|
beBayonetF: i.beBayonet === 1 ? '是' : '否',
|
||||||
|
bePlayF: i.bePlay === 1 ? '是' : '否'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
pagination.total = res.total
|
||||||
|
}).finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮操作
|
||||||
|
* @param type 操作类型
|
||||||
|
* @param data 数据
|
||||||
|
*/
|
||||||
|
const handle = (type, data) => {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'query':
|
||||||
|
model = { ...data }
|
||||||
|
pagination.current = 1
|
||||||
|
initData()
|
||||||
|
break
|
||||||
|
case 'add':
|
||||||
|
detail.visible = true
|
||||||
|
detail.type = 'add'
|
||||||
|
detail.data = {}
|
||||||
|
break
|
||||||
|
case 'check':
|
||||||
|
case 'edit':
|
||||||
|
detail.visible = true
|
||||||
|
detail.type = type
|
||||||
|
detail.data = { ...data }
|
||||||
|
break
|
||||||
|
case 'remove': {
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
'是否移除该条数据?',
|
||||||
|
'提示',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
const params = {
|
||||||
|
id: data.id
|
||||||
|
}
|
||||||
|
dsVideoDelete(params).then(() => {
|
||||||
|
ElMessage.success('移除成功!')
|
||||||
|
initData()
|
||||||
|
})
|
||||||
|
}).catch(() => { /* empty */ })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭详情弹窗
|
||||||
|
* @param refresh 是否刷新数据
|
||||||
|
*/
|
||||||
|
const closeDetail = (refresh) => {
|
||||||
|
detail.visible = false
|
||||||
|
if (refresh) {
|
||||||
|
initData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initData()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
import { nextTick, onUnmounted, ref } from 'vue'
|
import { nextTick, onUnmounted, ref } from 'vue'
|
||||||
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
|
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
|
||||||
import FlvPlayerComponent from '@/components/FlvPlayer/index.vue'
|
import FlvPlayerComponent from '@/components/FlvPlayer/index.vue'
|
||||||
import { getVideoStream, doStartOrStopUavAlgorithm } from '@/api/uav'
|
import { getVideoStream } from '@/api/uav'
|
||||||
|
|
||||||
const control = ref([
|
const control = ref([
|
||||||
{ label: '1X1', value: 1 },
|
{ label: '1X1', value: 1 },
|
||||||
@@ -93,7 +93,6 @@ const closeVideo = (data, item) => {
|
|||||||
const handleNodeClick = (node) => {
|
const handleNodeClick = (node) => {
|
||||||
if(props.videoType === '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')
|
|
||||||
if(index !== -1) {
|
if(index !== -1) {
|
||||||
haikang.value[index] = { codes: node.videoCode }
|
haikang.value[index] = { codes: node.videoCode }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,12 @@ import { computed, nextTick, ref, watch } from 'vue'
|
|||||||
import DialogComponent from '@/components/Dialog/screen.vue'
|
import DialogComponent from '@/components/Dialog/screen.vue'
|
||||||
import TreeCom from './tree.vue'
|
import TreeCom from './tree.vue'
|
||||||
import GridCom from './grid.vue'
|
import GridCom from './grid.vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import useMapStore from '@/store/modules/map'
|
|
||||||
import { dragEvent, resizeEvent } from '@/utils/common'
|
import { dragEvent, resizeEvent } from '@/utils/common'
|
||||||
|
|
||||||
const mapStore = useMapStore()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const type = computed(() => mapStore.dialog.type)
|
const type = computed(() => route.query.type)
|
||||||
const Tree = ref(null)
|
const Tree = ref(null)
|
||||||
const Grid = ref(null)
|
const Grid = ref(null)
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ const handle = (node) => {
|
|||||||
Grid.value.handleNodeClick(node)
|
Grid.value.handleNodeClick(node)
|
||||||
}
|
}
|
||||||
const close = () => {
|
const close = () => {
|
||||||
mapStore.updateDialog(false)
|
router.push('/')
|
||||||
}
|
}
|
||||||
watch(() => type.value, () => {
|
watch(() => type.value, () => {
|
||||||
if(type.value) {
|
if(type.value) {
|
||||||
@@ -48,8 +47,8 @@ watch(() => type.value, () => {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const drag = (e) => {
|
const drag = (e) => {
|
||||||
if(e.target.className.includes('el-dialog-title')) {
|
if(e.target.className.includes('el-dialog-title') || e.target.className.includes('el-dialog__title')) {
|
||||||
dragEvent(e, 'el-dialog-title', () => {
|
dragEvent(e, 'el-dialog', () => {
|
||||||
if(Grid.value.videoPreview) {
|
if(Grid.value.videoPreview) {
|
||||||
Grid.value.videoPreview.forEach(i => {
|
Grid.value.videoPreview.forEach(i => {
|
||||||
i.initResize(false)
|
i.initResize(false)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { findVideoLevelList, findUavPage, findEnvPage, dsVideoList } from '@/api/device.js'
|
import { findVideoLevelList, findUavPage } from '@/api/device.js'
|
||||||
|
|
||||||
const emit = defineEmits([ 'handle' ])
|
const emit = defineEmits([ 'handle' ])
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
<div class="title">千帆智瞰</div>
|
<div class="title">千帆智瞰</div>
|
||||||
<div class="user">
|
<div class="user">
|
||||||
<!-- <el-button :icon="Monitor" @click="goBusiness">业务系统</el-button> -->
|
|
||||||
<el-button :icon="Monitor" @click="goHome">返回门户</el-button>
|
<el-button :icon="Monitor" @click="goHome">返回门户</el-button>
|
||||||
<el-avatar :icon="UserFilled" :size="28"/>
|
<el-avatar :icon="UserFilled" :size="28"/>
|
||||||
<el-dropdown @command="handle">
|
<el-dropdown @command="handle">
|
||||||
@@ -150,12 +149,6 @@ const validate = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 跳转到系统设置
|
|
||||||
*/
|
|
||||||
const goBusiness = () => {
|
|
||||||
window.open('/', 'business_window')
|
|
||||||
}
|
|
||||||
const goHome = () => {
|
const goHome = () => {
|
||||||
window.open('/', 'business_window')
|
window.open('/', 'business_window')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user