BUG 28556 28553

This commit is contained in:
aixianling
2022-03-28 14:56:24 +08:00
parent 92dfebc1d4
commit 2611a72508
4 changed files with 248 additions and 246 deletions

View File

@@ -1,6 +1,7 @@
<template> <template>
<section class="AppMonitorManage"> <section class="AppMonitorManage">
<device-slider :permissions="permissions" :show.sync="slider" :ins="instance" :dict="dict" @treeCommand="handleSliderOption" @select="handleSelectMonitor" <device-slider :permissions="permissions" :show.sync="slider" :ins="instance" :dict="dict"
@treeCommand="handleSliderOption" @select="handleSelectMonitor"
:render-item="renderTreeItem" ref="DeviceSlider"/> :render-item="renderTreeItem" ref="DeviceSlider"/>
<div class="monitorPane"> <div class="monitorPane">
<div class="headerBar"> <div class="headerBar">
@@ -12,13 +13,13 @@
</div> </div>
<div class="videoList"> <div class="videoList">
<div <div
class="videoBox" class="videoBox"
v-for="(m,i) in monitors" v-for="(m,i) in monitors"
:key="m.id" :key="m.id"
@mouseenter.stop="m.isShowPlayBtn = true" @mouseenter.stop="m.isShowPlayBtn = true"
@mouseleave.stop="m.isShowPlayBtn = false" @mouseleave.stop="m.isShowPlayBtn = false"
:style="currentSplitStyle"> :style="currentSplitStyle">
<AiMonitor :src="m.url" type="slw"></AiMonitor> <AiMonitor :src="m.url" type="slw"></AiMonitor>
<span>{{ m.name }}</span> <span>{{ m.name }}</span>
<div class="videoBox-close" @click="removeMonitor(i)" v-if="m.isShowPlayBtn"> <div class="videoBox-close" @click="removeMonitor(i)" v-if="m.isShowPlayBtn">
<i class="el-icon-circle-close"></i> <i class="el-icon-circle-close"></i>
@@ -36,181 +37,182 @@
</el-form> </el-form>
</ai-dialog> </ai-dialog>
<locate-dialog v-model="locate" :ins="instance" :latlng="latlng" @confirm="v=>handleLocate(selected,v)"/> <locate-dialog v-model="locate" :ins="instance" :latlng="latlng" @confirm="v=>handleLocate(selected,v)"/>
<ai-area custom-clicker :input-clicker="false" :hideLevel="disabledLevel" v-model="selected.areaId" :instance="instance" ref="BindArea" <ai-area custom-clicker :input-clicker="false" :hideLevel="disabledLevel" v-model="selected.areaId"
:instance="instance" ref="BindArea"
@change="handleSubmit(selected)"/> @change="handleSubmit(selected)"/>
</section> </section>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import {mapState} from 'vuex'
import DeviceSlider from "../components/deviceSlider"; import DeviceSlider from "../components/deviceSlider";
import LocateDialog from "../components/locateDialog"; import LocateDialog from "../components/locateDialog";
import AiMonitor from "../../../../../dvui/components/AiMonitor/AiMonitor"; import AiMonitor from "../../../../../dvui/components/AiMonitor/AiMonitor";
export default { export default {
name: "AppMonitorManage", name: "AppMonitorManage",
components: {LocateDialog, DeviceSlider, AiMonitor}, components: {LocateDialog, DeviceSlider, AiMonitor},
label: "监控实况", label: "监控实况",
props: { props: {
instance: Function, instance: Function,
dict: Object, dict: Object,
permissions: Function permissions: Function
},
computed: {
splitOps() {
return [
{label: "单分屏", value: 1, per: "100%"},
{label: "四分屏", value: 4, per: "49%"},
{label: "九分屏", value: 9, per: "32%"}
]
}, },
computed: { currentSplitStyle() {
splitOps() { let per = this.splitOps.find(e => e.value == this.splitScreen)?.per || "100%"
return [ return {width: per, height: per}
{label: "单分屏", value: 1, per: "100%"},
{label: "四分屏", value: 4, per: "49%"},
{label: "九分屏", value: 9, per: "32%"}
]
},
currentSplitStyle() {
let per = this.splitOps.find(e => e.value == this.splitScreen)?.per || "100%"
return {width: per, height: per}
},
...mapState(['user'])
}, },
...mapState(['user'])
},
data() { data() {
return { return {
slider: true, slider: true,
fullscreen: false, fullscreen: false,
splitScreen: 1, splitScreen: 1,
monitors: [], monitors: [],
dialog: false, dialog: false,
locate: false, locate: false,
selected: { selected: {
areaId: '' areaId: ''
}, },
videoUrl: '', videoUrl: '',
latlng: null, latlng: null,
disabledLevel: 0, disabledLevel: 0,
rules: { rules: {
name: [{required: true, message: "请填写 设备名称"}] name: [{required: true, message: "请填写 设备名称"}]
} }
}
},
created() {
this.selected.areaId = this.user.info.areaId
this.disabledLevel = this.user.info.areaList.length - 1
},
methods: {
handleFullscreen() {
this.fullscreen = !this.fullscreen
this.$fullscreen(this.fullscreen)
},
handleSelectMonitor(monitor) {
if (monitor.type !== '1') return
let {id} = monitor,
index = this.monitors.findIndex(e => e.id == id)
if (index > -1) {
this.$message.error('该监控视频已存在')
} else if (this.monitors.length >= this.splitScreen && this.splitScreen > 1) {
this.$message.error("可分屏监控已满,请先取消其他的监控")
} else {
this.showMonitor(monitor)
} }
}, },
created () { onChange(e) {
this.selected.areaId = this.user.info.areaId if (e === 1 && this.monitors.length) {
this.disabledLevel = this.user.info.areaList.length - 1 this.monitors = [this.monitors[0]]
}
}, },
methods: { removeMonitor(i) {
handleFullscreen() { this.monitors.splice(i, 1)
this.fullscreen = !this.fullscreen },
this.$fullscreen(this.fullscreen)
},
handleSelectMonitor(monitor) {
if (monitor.type !== '1') return
let {id} = monitor, showMonitor(monitor, refresh = false) {
index = this.monitors.findIndex(e => e.id == id) let {id: deviceId} = monitor
if (index > -1) { deviceId && this.instance.post("/app/appzyvideoequipment/getWebSdkUrl", null, {
this.$message.error('该监控视频已存在') params: {deviceId}
} else if (this.monitors.length >= this.splitScreen && this.splitScreen > 1) { }).then(res => {
this.$message.error("可分屏监控已满,请先取消其他的监控") if (res?.data) {
} else { this.videoUrl = res.data
this.showMonitor(monitor) let data = {
} url: res.data,
}, isShowPlayBtn: false
}
onChange (e) { if (refresh) {
if (e === 1 && this.monitors.length) { monitor.url = data.url
this.monitors = [this.monitors[0]] } else if (this.splitScreen == 1) {
} this.monitors = [{...monitor, ...data}]
}, } else {
if (this.monitors.findIndex(e => e.id == monitor.id) === -1 && this.monitors.length <= this.splitScreen) {
removeMonitor (i) { this.monitors.push({...monitor, ...data})
this.monitors.splice(i, 1)
},
showMonitor(monitor, refresh = false) {
let {id: deviceId} = monitor
deviceId && this.instance.post("/app/appzyvideoequipment/getWebSdkUrl", null, {
params: {deviceId}
}).then(res => {
if (res?.data) {
this.videoUrl = res.data
let data = {
url: res.data,
isShowPlayBtn: false
}
if (refresh) {
monitor.url = data.url
} else if (this.splitScreen == 1) {
this.monitors = [{...monitor, ...data}]
} else {
if (this.monitors.findIndex(e => e.id == monitor.id) === -1 && this.monitors.length <= this.splitScreen) {
this.monitors.push({...monitor, ...data})
}
} }
} }
}) }
}, })
renderTreeItem: function (h, {node, data}) { },
let show = data.deviceStatus==1 ? 'show' : '' renderTreeItem: function (h, {node, data}) {
if (node.isLeaf) { let show = data.deviceStatus == 1 ? 'show' : ''
return ( if (node.isLeaf) {
<div class="flexRow"> return (
<i class={['iconfont', 'iconshipinjiankong', show]}/>
<div>{node.label}</div>
</div>
)
} else return (
<div class="flexRow"> <div class="flexRow">
<i class={['iconfont', 'iconshipinjiankong', show]}/>
<div>{node.label}</div> <div>{node.label}</div>
{data.id != 'no_area' ? <div class="sta">
<p>{data.online || 0}</p>/{data.sum || 0}
</div>
: <div/>}
</div> </div>
) )
}, } else return (
handleSliderOption(e) { <div class="flexRow">
console.log(e) <div>{node.label}</div>
this.selected = { {data.id != 'no_area' ? <div class="sta">
command: e.type, <p>{data.online || 0}</p>/{data.sum || 0}
...e.node </div>
} : <div/>}
this.selected.areaId = e.node.areaId || this.user.info.areaId </div>
if (e.type == "edit") {//修改名称 )
this.dialog = true },
} else if (e.type == "area") {//绑定areaId handleSliderOption(e) {
this.$refs.BindArea?.chooseArea() console.log(e)
} else if (e.type == "locate") {//地图标绘 this.selected = {
this.latlng = e.node.lat && e.node.lng ? { command: e.type,
lat: e.node.lat, ...e.node
lng: e.node.lng }
} : '' this.selected.areaId = e.node.areaId || this.user.info.areaId
this.locate = true if (e.type == "edit") {//修改名称
} this.dialog = true
}, } else if (e.type == "area") {//绑定areaId
handleSubmit(row) { this.$refs.BindArea?.chooseArea()
delete row.createTime } else if (e.type == "locate") {//地图标绘
return this.instance.post("/app/appzyvideoequipment/addOrUpdate", { this.latlng = e.node.lat && e.node.lng ? {
...row lat: e.node.lat,
}).then(res => { lng: e.node.lng
if (res?.code == 0) { } : ''
this.$message.success("提交成功!") this.locate = true
this.dialog = false
this.$refs.DeviceSlider?.getDevices()
}
})
},
handleLocate(row, locate) {
if (locate) {
let {lat, lng} = locate.location
this.handleSubmit({...row, lat, lng}).then(() => {
this.locate = false
})
}
} }
}, },
beforeDestroy() { handleSubmit(row) {
this.monitors = [] delete row.createTime
return this.instance.post("/app/appzyvideoequipment/addOrUpdate", {
...row
}).then(res => {
if (res?.code == 0) {
this.$message.success("提交成功!")
this.dialog = false
this.$refs.DeviceSlider?.getDevices()
}
})
},
handleLocate(row, locate) {
if (locate) {
let {lat, lng} = locate.location
this.handleSubmit({...row, lat, lng}).then(() => {
this.locate = false
})
}
} }
},
beforeDestroy() {
this.monitors = []
} }
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -15,26 +15,27 @@
:label="op.dictName"/> :label="op.dictName"/>
</el-select> </el-select>
<el-input <el-input
v-model="search.name" v-model="search.name"
size="mini" size="mini"
placeholder="设备名称" placeholder="设备名称"
v-throttle="handleTreeFilter" v-throttle="handleTreeFilter"
prefix-icon="el-icon-search" prefix-icon="el-icon-search"
@clear="search.name = '', handleTreeFilter()" clearable/> @clear="search.name = '', handleTreeFilter()" clearable/>
</div> </div>
<div title>设备列表</div> <div title>设备列表</div>
<div fill class="deviceList"> <div fill class="deviceList">
<el-tree ref="deviceTree" :render-content="renderItem" :data="treeData" :props="propsConfig" @node-click="handleNodeClick" @node-contextmenu="nodeContextmenu" <el-tree ref="deviceTree" :render-content="renderItem" :data="treeData" :props="propsConfig"
:filter-node-method="handleFilter"/> @node-click="handleNodeClick" @node-contextmenu="nodeContextmenu"
<ul :filter-node-method="handleFilter"/>
v-if="isShowMenu && menuInfo.node.type === '1'" <ul
class="el-dropdown-menu el-popper" v-if="isShowMenu && menuInfo.node.type==1"
:style="{top: menuInfo.y + 'px', left: menuInfo.x + 'px', position: 'fixed', zIndex: 2023}" class="el-dropdown-menu el-popper"
x-placement="top-end"> :style="{top: menuInfo.y + 'px', left: menuInfo.x + 'px', position: 'fixed', zIndex: 2023}"
<li class="el-dropdown-menu__item" @click="handleTreeCommand('edit', menuInfo.node)">修改名称</li> x-placement="top-end">
<!-- <li class="el-dropdown-menu__item" @click="handleTreeCommand('area', menuInfo.node)">行政地区</li> --> <li class="el-dropdown-menu__item" @click="handleTreeCommand('edit', menuInfo.node)">修改名称</li>
<li class="el-dropdown-menu__item" @click="handleTreeCommand('locate', menuInfo.node)">地图标绘</li> <!-- <li class="el-dropdown-menu__item" @click="handleTreeCommand('area', menuInfo.node)">行政地区</li> -->
</ul> <li class="el-dropdown-menu__item" @click="handleTreeCommand('locate', menuInfo.node)">地图标绘</li>
</ul>
</div> </div>
</div> </div>
<div class="rightBtn" :class="{show}" @click="handleShow"> <div class="rightBtn" :class="{show}" @click="handleShow">
@@ -122,7 +123,7 @@ export default {
}) })
}, },
handleTreeCommand (e, node) { handleTreeCommand(e, node) {
this.$emit('treeCommand', { this.$emit('treeCommand', {
type: e, type: e,
node node
@@ -149,13 +150,13 @@ export default {
return !this.search.bind ? true : data.deviceStatus === this.search.bind return !this.search.bind ? true : data.deviceStatus === this.search.bind
} }
return data?.name?.indexOf(v) > -1 && (!this.search.bind ? true : data.deviceStatus === this.search.bind) return data?.name?.indexOf(v) > -1 && (!this.search.bind ? true : data.deviceStatus === this.search.bind)
}, },
handleTreeFilter() { handleTreeFilter() {
this.$refs.deviceTree?.filter(this.search.name) this.$refs.deviceTree?.filter(this.search.name)
}, },
onChange () { onChange() {
this.$refs.deviceTree?.filter(this.search.name) this.$refs.deviceTree?.filter(this.search.name)
} }
}, },
@@ -164,7 +165,7 @@ export default {
this.getDevices() this.getDevices()
}, },
mounted () { mounted() {
document.querySelector('html').addEventListener('click', this.bindEvent) document.querySelector('html').addEventListener('click', this.bindEvent)
} }
} }
@@ -192,14 +193,17 @@ export default {
width: fit-content; width: fit-content;
min-width: 100%; min-width: 100%;
} }
&::-webkit-scrollbar { &::-webkit-scrollbar {
width : 10px; width: 10px;
height: 15px; height: 15px;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.2); box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.2);
background: #535353; background: #535353;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.2); box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.2);
background: #fff; background: #fff;

View File

@@ -3,9 +3,14 @@
<ai-dialog :visible.sync="dialog" title="标绘" @closed="$emit('visible',false),selected={}" <ai-dialog :visible.sync="dialog" title="标绘" @closed="$emit('visible',false),selected={}"
@opened="$nextTick(()=>initMap())" @opened="$nextTick(()=>initMap())"
@onConfirm="handleConfirm"> @onConfirm="handleConfirm">
<div id="amap" v-if="dialog"/> <ai-t-map :map.sync="map" :lib.sync="TMap"/>
<div class="poi"> <div class="poi">
<el-input ref="poiInput" v-model="search" size="small" clearable v-throttle="handleSearch" placeholder="请输入地点"/> <el-autocomplete ref="poiInput" v-model="search" size="small" clearable :fetch-suggestions="handleSearch"
placeholder="请输入地点" @select="handleSelect" :trigger-on-focus="false">
<template slot-scope="{item}">
<span style="direction: rtl" v-text="`${item.title}(${item.address})`"/>
</template>
</el-autocomplete>
</div> </div>
<el-form class="selected" v-if="!!selected.location" id="result" size="mini" label-suffix="" <el-form class="selected" v-if="!!selected.location" id="result" size="mini" label-suffix=""
label-position="left"> label-position="left">
@@ -22,7 +27,7 @@
</template> </template>
<script> <script>
import AMapLoader from '@amap/amap-jsapi-loader' import {mapState} from "vuex";
export default { export default {
name: "locateDialog", name: "locateDialog",
@@ -35,66 +40,54 @@ export default {
return { return {
dialog: false, dialog: false,
search: "", search: "",
poi: null,
map: null, map: null,
AMap: null,
selected: {}, selected: {},
geo: null TMap: null
} }
}, },
computed: {
...mapState(['user'])
},
watch: { watch: {
visible(v) { visible(v) {
this.dialog = v this.dialog = v
} }
}, },
methods: { methods: {
initMap() { initMap(count = 0) {
AMapLoader.load({ let {map, TMap} = this
key: "b553334ba34f7ac3cd09df9bc8b539dc", if (map) {
version: '2.0', if (!!this.latlng?.lat) {
plugins: ['AMap.PlaceSearch', 'AMap.Marker', 'AMap.Geolocation'], let position = new TMap.LatLng(this.latlng.lat, this.latlng.lng)
}).then(AMap => { map.setCenter(position)
this.AMap = AMap this.selected.marker = new TMap.MultiMarker({map, geometries: [{position}]})
this.map = new AMap.Map('amap', {
zoom: 14,
center: this.latlng ? [this.latlng.lng, this.latlng.lat] : ''
}).on('click', res => {
this.map.clearMap()
this.selected = {location: res.lnglat}
this.poi?.searchNearBy('', res.lnglat, 100)
});
if (this.latlng) {
let marker = new AMap.Marker({
position: [this.latlng.lng, this.latlng.lat]
})
this.map.add(marker)
} }
this.poi = new AMap.PlaceSearch().on('complete', ({poiList}) => { map.on('click', res => {
this.map.clearMap() let {poi, latLng: location} = res, name = poi?.name || ""
if (poiList?.length > 0) { this.selected.marker?.setMap(null)
poiList?.pois?.map(e => { this.selected = {location, name}
let marker = new AMap.Marker({ this.selected.marker = new TMap.MultiMarker({map, geometries: [{position: location}]})
position: e.location,
}).on('click', () => this.selected = e)
this.map.add(marker)
})
} else {
let marker = new AMap.Marker({
position: this.selected.location,
})
this.map.add(marker)
}
}) })
this.geo = new AMap.Geolocation({ } else {
enableHighAccuracy: true,//是否使用高精度定位 if (count < 5) {
zoomToAccuracy: true//定位成功后是否自动调整地图视野到定位点 count++
}) setTimeout(() => this.initMap(count), 500)
this.map.addControl(this.geo) } else {
}) console.error("地图渲染失败")
}
}
}, },
handleSearch() { handleSearch(keyword, cb) {
if (this.search) { let {TMap} = this
this.poi.searchNearBy(this.search, this.map.getCenter(), 50000) if (keyword && TMap) {
let poi = new TMap.service.Search({pageSize: 10})
poi.searchRegion({
keyword, radius: 5000, cityName: this.user.info?.areaId?.substring(0, 6) || ""
}).then(res => {
if (res?.data?.length > 0) {
cb(res.data)
} else this.$message.error("未查到有效地点")
})
} }
}, },
handleConfirm() { handleConfirm() {
@@ -103,7 +96,16 @@ export default {
} else { } else {
this.$message.error('请先选择坐标位置') this.$message.error('请先选择坐标位置')
} }
},
handleSelect(res) {
let {map, TMap} = this
if (map) {
let {title: name, location} = res
this.selected.marker?.setMap(null)
this.selected = {location, name}
this.selected.marker = new TMap.MultiMarker({map, geometries: [{position: location}]})
map.setCenter(location)
}
} }
}, },
created() { created() {
@@ -114,6 +116,10 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.locateDialog { .locateDialog {
.color-999 {
color: #999;
}
::v-deep .el-dialog__body { ::v-deep .el-dialog__body {
padding: 0; padding: 0;
height: 480px; height: 480px;
@@ -123,20 +129,6 @@ export default {
padding: 0 !important; padding: 0 !important;
} }
#amap {
width: 100%;
height: 480px;
.amap-logo, .amap-copyright {
display: none !important;
}
.amap-marker-label {
border-color: transparent;
box-shadow: 1px 1px 0 0 rgba(#999, .2);
}
}
.poi { .poi {
position: absolute; position: absolute;
left: 10px; left: 10px;
@@ -144,6 +136,8 @@ export default {
display: flex; display: flex;
height: 32px; height: 32px;
flex-direction: column; flex-direction: column;
z-index: 202203281016;
width: 400px;
div { div {
flex-shrink: 0; flex-shrink: 0;
@@ -178,4 +172,6 @@ export default {
} }
} }
} }
</style> </style>

View File

@@ -64,7 +64,7 @@ module.exports = {
proxy: { proxy: {
//设置代理,可解决跨5 //设置代理,可解决跨5
'/lan': { '/lan': {
target: 'https://sdtestweb.sdvillage.cn', target: 'http://192.168.1.87:9000',
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
//地址重写 //地址重写