<template> <div> <el-row> <el-col :span="6" class="staticPanel"> <sup-statis-panel ref="caseStatics" @changeTimeTerm="handleTimeTermChanged" /> </el-col> <el-col :span="18" class="mapPanel"> <el-row> <el-col :span="6"> <div id="today-visitor" class="caseStatisBlock" style="margin-left: 0px;"> <span v-text="caseCounts.labelText"/>立案 <span class="bigNumber" v-text="caseCounts.register"/>件 </div> </el-col> <el-col :span="6"> <div id="total-alarm" class="caseStatisBlock"> 本日立案 <span class="bigNumber" v-text="caseCounts.todayRegister" />件 </div> </el-col> <el-col :span="6"> <div id="online-device" class="caseStatisBlock"> <span v-text="caseCounts.labelText" />处理率 <span class="bigNumber" v-text="caseCounts.oughtHandleRate" />% </div> </el-col> <el-col :span="6"> <div id="total-device" class="caseStatisBlock"> <span v-text="caseCounts.labelText" />未处理 <span class="bigNumber" v-text="caseCounts.notHandled" />件 </div> </el-col> </el-row> <el-row :gutter="20" style="margin-right: -20px"> <el-col :span="24" style="padding: 0px 20px"> <div v-loading="mapLoading" ref="mapDiv" class="baseMap" style="margin-left: -10px;"/> </el-col> </el-row> <!-- 浮层 --> <div class="mapOverLayer"> <el-row :gutter="20"> <el-col :span="6" style="margin-top: 10px; padding-left: 25px; line-height: 40px;"> <el-radio-group v-model="queryEventSwitch" size="medium" @change="switchContent"> <el-radio-button label="0">案卷</el-radio-button> <el-radio-button label="1">人员</el-radio-button> <!-- <el-radio-button label="2">部件</el-radio-button>--> </el-radio-group> </el-col> <el-col :span="18" style="margin-top: 10px;"> <el-form v-if="showCaseSelect" :label-position="labelPosition" label-width="120px"> <el-form-item label="案卷状态" class="item"> <el-select v-model="parts.caseStatusCode" size="medium" placeholder="选择案卷状态" clearable value="" class="notLastSelect" @change="changeCaseScope()"> <el-option value="toHandle" label="处置中"/> <el-option value="toVerify" label="待核实"/> <el-option value="toCheck" label="待核查"/> </el-select> <label class="customLabel">是否超期</label> <el-radio-group v-model="isOverTime" size="medium" @change="changeCaseScope()"> <el-radio-button label="">全部</el-radio-button> <el-radio-button label="Ot">超期</el-radio-button> <el-radio-button label="Not">未超期</el-radio-button> </el-radio-group> </el-form-item> </el-form> <el-form v-if="showPersonSelect" :label-position="labelPosition" label-width="120px"> <el-row :gutter="10" class="rowSelect"> <el-col :span="20"> <el-form-item label="人员分类" prop="casepersonCode" class="item"> <el-radio-group v-model="casepersonCode" size="medium" @change="queryPerson()"> <el-radio-button label="supervisor">监督员</el-radio-button> <el-radio-button label="process">处置员</el-radio-button> </el-radio-group> </el-form-item> </el-col> </el-row> </el-form> <el-form v-if="showPartsSelect" :label-position="labelPosition" label-width="120px"> <el-row :gutter="10" class="rowSelect"> <el-col :span="20"> <el-form-item label="部件大类" prop="casetypeCode" class="item"> <el-select v-model="parts.casetypeCode" size="medium" placeholder="选择部件大类" clearable class="notLastSelect"> <el-option v-for="item in caseTypeOpts" :key="item.id" :label="item.typeName" :value="item.typeCode"/> </el-select> <label class="customLabel">部件小类</label> <el-select v-model="parts.casetypeDetailCode" size="medium" placeholder="选择部件小类" clearable> <el-option v-for="item in caseDetailTypeOpts" :key="item.id" :label="item.typeDetailName" :value="item.typeDetailCode"/> </el-select> </el-form-item> </el-col> </el-row> </el-form> </el-col> </el-row> </div> </el-col> </el-row> </div> </template> <script> import request from '@/utils/request' import SupStatisPanel from '@/views/supControl/SupStatisPanel' import { getCaseType, getCaseDetailType } from '@/api/callCase/callCase' import { getUserOnLine } from '@/api/system/user' import Leaflet from 'leaflet' import { mapGetters } from 'vuex' const toHandleIcon = Leaflet.icon({ iconUrl: require('@/assets/case/status_toHandle.png'), iconSize: [19, 31], iconAnchor: [10, 31], popupAnchor: [-0, -32] }) const toVerifyIcon = Leaflet.icon({ iconUrl: require('@/assets/case/status_toVerify.png'), iconSize: [19, 31], iconAnchor: [10, 31], popupAnchor: [-0, -32] }) const toCheckIcon = Leaflet.icon({ iconUrl: require('@/assets/case/status_toCheck.png'), iconSize: [19, 31], iconAnchor: [10, 31], popupAnchor: [-0, -32] }) const redIcon = Leaflet.icon({ iconUrl: require('@/assets/case/status_overTime.png'), iconSize: [19, 31], iconAnchor: [10, 31], popupAnchor: [-0, -32] }) const offlineIcon = Leaflet.icon({ iconUrl: require('@/assets/case/offline.png'), iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [-0, -32] }) const onlineIcon = Leaflet.icon({ iconUrl: require('@/assets/case/online.png'), iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [-0, -32] }) const esri = require('esri-leaflet') export default { name: 'SupControl', components: { SupStatisPanel }, data() { return { map: '', baseLayer: [], parts: { eorc: '2', // 类别 casetypeCode: '', // 部件大类编码, casetypeDetailCode: '', // 部件小类编码 caseStatusCode: '' }, timeTerm: '1', personQuery: { roleTips: '' }, caseCounts: { labelText: '本月', register: 0, // 本期立案数 todayRegister: 0, // 当日立案数 totalCheckNum: 0, // 本期总应处置数 checkedNum: 0, // 本期处置数 oughtHandleRate: 0, // 本期应处置率 notHandled: 0 // 本期未处置数 }, casepersonCode: 'supervisor', labelPosition: 'right', caseTypeOpts: [], // 部件大类下拉框 caseDetailTypeOpts: [], // 部件小类下拉框 caseTypeCodeAuto: '', // 自动生成的案卷大类代码 caseTypeDetailCodeAuto: '', // 自动生成的案卷小类代码 mapLoading: false, queryEventSwitch: '0', // 0==查询案件;1==查询人员;2==查询部件 showPartsSelect: false, showPersonSelect: false, showCaseSelect: true, isOverTime: '', // 是否区分超时工单 toVerifyListOt: [], // 待核实超时 toVerifyListNot: [], // 待核实未超时 toCheckListOt: [], // 待核查超时 toCheckListNot: [], // 待核查 toHandleListOt: [], // 处置中超时 toHandleListNot: [], // 处置中 caseLayerGroup: [], // 案卷图层组 toVerifyCaseNot: null, toVerifyCaseOt: null, toCheckCaseNot: null, toCheckCaseOt: null, toHandleCaseNot: null, toHandleCaseOt: null, onlineList: [], // 在岗人员列表 offlineList: [], // 离线人员列表 personLayerGroup: [], // 人员图层组 offlinePerson: null, onlinePerson: null, imageBaseUrl: this.baseConfig.baseUrl + '/static/' } }, computed: { eorc() { return this.parts.eorc }, caseType() { return this.parts.casetypeCode }, caseTypeDetail() { return this.parts.casetypeDetailCode }, ...mapGetters([ 'baseUrl', 'partsUrl', 'mapUrl' ]) }, watch: { caseType(typeVal) { this.cascaderCaseDetailType(typeVal) }, caseTypeDetail(typeVal) { this.clearPoint() const obj = this.caseDetailTypeOpts.find(function(item) { return item.typeDetailCode === typeVal }) if (obj) { this.addPartsPoints(obj.typeDetailName) } } }, mounted() { this.initMap() this.switchContent() // 案卷图层 this.caseLayerGroup.push(this.toVerifyCaseNot) this.caseLayerGroup.push(this.toVerifyCaseOt) this.caseLayerGroup.push(this.toCheckCaseNot) this.caseLayerGroup.push(this.toCheckCaseOt) this.caseLayerGroup.push(this.toHandleCaseNot) this.caseLayerGroup.push(this.toHandleCaseOt) // 人员图层 this.personLayerGroup.push(this.offlinePerson) this.personLayerGroup.push(this.onlinePerson) }, methods: { handleTimeTermChanged: function(caseCounts) { this.caseCounts = caseCounts }, switchContent: function() { this.clearPoint() // 清除绘制的点 // 案卷(0)、人员(1)、部件(2), if (this.queryEventSwitch === '2') { this.showPartsSelect = true this.showPersonSelect = false this.showCaseSelect = false this.cascaderCaseType('2') } else if (this.queryEventSwitch === '1') { this.showPersonSelect = true this.showPartsSelect = false this.showCaseSelect = false // 查询人员 this.queryPerson() } else if (this.queryEventSwitch === '0') { this.showCaseSelect = true this.showPartsSelect = false this.showPersonSelect = false // 查询三个状态的案卷列表 this.queryCaseToVerify() this.queryCaseToCheck() this.queryCaseToHandle() } }, // 切换不同案卷状态的显示与否 changeCaseScope: function() { // isOverTime: ''--全部,'Ot'--超时,'Not'--未超时 // caseStatusCode: 'toHandle'--待处置,'toVerify'--待核实,'toCheck'--待核查 let filterIndex = [] const that = this if (this.parts.caseStatusCode === '') { if (this.isOverTime === 'Not') { filterIndex = [0, 2, 4] } else if (this.isOverTime === 'Ot') { filterIndex = [1, 3, 5] } else { filterIndex = [0, 1, 2, 3, 4, 5] } } else if (this.parts.caseStatusCode === 'toHandle') { if (this.isOverTime === 'Not') { filterIndex = [4] } else if (this.isOverTime === 'Ot') { filterIndex = [5] } else { filterIndex = [4, 5] } } else if (this.parts.caseStatusCode === 'toVerify') { if (this.isOverTime === 'Not') { filterIndex = [0] } else if (this.isOverTime === 'Ot') { filterIndex = [1] } else { filterIndex = [0, 1] } } else if (this.parts.caseStatusCode === 'toCheck') { if (this.isOverTime === 'Not') { filterIndex = [2] } else if (this.isOverTime === 'Ot') { filterIndex = [3] } else { filterIndex = [2, 3] } } // 清除所有的图层 this.caseLayerGroup.forEach(item => { that.map.removeLayer(item) }) // 重新添加指定状态的图层 filterIndex.forEach(i => { that.caseLayerGroup[i].addTo(that.map) }) }, queryCaseToVerify: function() { const that = this const onePageParam = { limit: 1000, offset: 1 } // 查询待核实案卷 request({ url: 'case/toVerifyListPage', method: 'get', params: onePageParam }).then(response => { if (response.code === 200) { if (response.data.total > 0) { // 查询有新结果时清除原有的列表 this.toVerifyListNot = [] this.toVerifyListOt = [] response.data.rows.forEach(item => { if (item.isOvertime === '1') { // 超时标志位为1,放入超时列表中 that.toVerifyListOt.push(item) } else { // 未超时 that.toVerifyListNot.push(item) } }) this.addCasePointOnMap(this.toVerifyListNot, this.toVerifyCaseNot, toVerifyIcon) this.addCasePointOnMap(this.toVerifyListOt, this.toVerifyCaseOt, redIcon) } } }) }, queryCaseToCheck: function() { const that = this const onePageParam = { limit: 1000, offset: 1 } // 查询待核查案卷 request({ url: 'case/toCheckListPage', method: 'get', params: onePageParam }).then(response => { if (response.code === 200) { if (response.data.total > 0) { // 查询有新结果时清除原有的列表 this.toCheckListNot = [] this.toCheckListOt = [] response.data.rows.forEach(item => { if (item.isOvertime === '1') { // 超时标志位为1,放入超时列表中 that.toCheckListOt.push(item) } else { // 未超时 that.toCheckListNot.push(item) } }) this.addCasePointOnMap(this.toCheckListNot, this.toCheckCaseNot, toCheckIcon) this.addCasePointOnMap(this.toCheckListOt, this.toCheckCaseOt, redIcon) } } }) }, queryCaseToHandle: function() { const that = this const onePageParam = { limit: 1000, offset: 1 } // 查询处理中案卷 request({ url: 'case/toHandleListPage', method: 'get', params: onePageParam }).then(response => { if (response.code === 200) { if (response.data.total > 0) { // 查询有新结果时清除原有的列表 this.toHandleListNot = [] this.toHandleListOt = [] response.data.rows.forEach(item => { if (item.isOvertime === '1') { // 超时标志位为1,放入超时列表中 that.toHandleListOt.push(item) } else { // 未超时 that.toHandleListNot.push(item) } }) this.addCasePointOnMap(this.toHandleListNot, this.toHandleCaseNot, toHandleIcon) this.addCasePointOnMap(this.toHandleListOt, this.toHandleCaseOt, redIcon) } } }) }, // 查询人员 queryPerson: function() { const that = this // 清除所有的人员图层 this.personLayerGroup.forEach(item => { that.map.removeLayer(item) }) this.personQuery.roleTips = this.casepersonCode if (this.casepersonCode !== '') { getUserOnLine(this.personQuery).then(res => { if (res.code === 200) { if (res.data.length > 0) { // 查询有新结果时清除原有的列表 this.onlineList = [] this.offlineList = [] // 清除图层组 this.onlinePerson.clearLayers() this.offlinePerson.clearLayers() res.data.forEach(item => { if (item.onLine === true) { // 在线标志位 that.onlineList.push(item) } else { that.offlineList.push(item) } }) this.addPersonPoints(this.onlineList, this.onlinePerson, onlineIcon) this.addPersonPoints(this.offlineList, this.offlinePerson, offlineIcon) } } }) } }, // 级联查询部件大类 cascaderCaseType: function(eorc) { // 前两行的作用是清除部件大类的当前值和select中的所有选项 this.caseTypeOpts = [] this.parts.casetypeCode = '' // 以下两行的作用是清除部件小类的当前值和select中的所有选项 this.caseDetailTypeOpts = [] this.parts.casetypeDetailCode = '' // 部件大类 if (eorc !== null && eorc.length > 0) { getCaseType(eorc).then(response => { for (const opt of response.data) { this.caseTypeOpts.push(opt) if (opt.typeCode === this.caseTypeCodeAuto) { this.parts.casetypeCode = opt.typeCode } } }) } }, cascaderCaseDetailType: function(typeCode) { // 以下两行的作用是清除案卷小类的当前值和select中的所有选项 this.caseDetailTypeOpts = [] this.parts.casetypeDetailCode = '' // 根据code获取ID,进行级联查询 let typeId = 0 this.caseTypeOpts.forEach(item => { if (item.typeCode === typeCode) { typeId = item.id } }) if (typeId > 0) { getCaseDetailType(typeId).then(response => { for (const opt of response.data) { this.caseDetailTypeOpts.push(opt) if (opt.typeDetailCode === this.caseTypeDetailCodeAuto) { this.parts.casetypeDetailCode = opt.typeDetailCode } } }) } }, clearPoint: function() { const that = this // 清除所有案卷的图层 this.caseLayerGroup.forEach(item => { that.map.removeLayer(item) }) // 清除所有的人员图层 this.personLayerGroup.forEach(item => { that.map.removeLayer(item) }) }, addCasePointOnMap: function(caseList, caseLayerGroup, icon) { caseList.forEach(caseDetail => { let popupStr = '<div class="popup-div">' + '<div class="popup-title">案卷概要信息</div>' + '<div class="dashed-line"></div>' + '<div class="popup-item"><label>案卷编号</label>' + caseDetail.caseid + '</div>' + '<div class="popup-item"><label>案卷状态</label>' + caseDetail.caseStateName + '</div>' + '<div class="popup-item"><label>案卷类型</label>' + caseDetail.casetypeName + ' / ' + caseDetail.casetypeDetailName + '</div>' + '<div class="popup-item"><label>发生地点</label>' + caseDetail.fieldintro + '</div>' + '<div class="popup-item"><label>案卷描述</label>' + caseDetail.description + '</div>' + '<div class="popup-item"><label>登记时间</label>' + caseDetail.reportTime + '</div>' if (caseDetail.fileIdVerify !== '') { const verifyImgs = caseDetail.fileIdVerify.split(',') const imgUrl1 = this.imageBaseUrl + verifyImgs[0] popupStr += '<div class="popup-item"><label>案卷图片</label></div>' popupStr += '<div class="popup-item"><img src="' + imgUrl1 + '" width="100" />' if (verifyImgs.length > 1) { const imgUrl2 = this.imageBaseUrl + verifyImgs[1] popupStr += '<img src="' + imgUrl2 + '" width="100" style="margin-left: 10px;" />' } popupStr += '</div>' } const popup = Leaflet.popup().setContent(popupStr) if (caseDetail.lng > 0 && caseDetail.lat > 0) { // 添加marker Leaflet.marker([caseDetail.lat, caseDetail.lng], { icon: icon }).addTo(caseLayerGroup).bindPopup(popup) } this.map.addLayer(caseLayerGroup) }) }, addPersonPoints: function(personList, personLayerGroup, icon) { personList.forEach(person => { const popupStr = '<div class="popup-div">' + '<div class="popup-title">' + person.name + '</div>' + '<div class="dashed-line"></div>' + '<div class="popup-item"><label>所在部门</label>' + person.deptName + '</div>' + '<div class="popup-item"><label>人员姓名</label>' + person.name + '</div>' + '<div class="popup-item"><label>手机号码</label>' + person.phone + '</div>' + '<div class="popup-item"><label>轨迹时间点</label>' + person.lastTimeFmt + '</div>' + '</div>' const popup = Leaflet.popup().setContent(popupStr) if (person.positionLng > 0 && person.positionLat > 0) { // 添加marker Leaflet.marker([person.positionLat, person.positionLng], { icon: icon }).addTo(personLayerGroup).bindPopup(popup) } }) this.map.addLayer(personLayerGroup) }, // 初始化地图 initMap: function() { const map = Leaflet.map(this.$refs.mapDiv, { minZoom: 14, maxZoom: 25, center: this.baseConfig.center, zoom: this.baseConfig.zoom, zoomControl: false, attributionControl: false, crs: Leaflet.CRS.EPSG3857 }) this.map = map // data上需要挂载 window.map = map // 加载天地图底图和标注 this.baseLayer.push(Leaflet.tileLayer( this.baseConfig.mapUrl ).addTo(map)) this.baseLayer.push(Leaflet.tileLayer( this.baseConfig.labelUrl ).addTo(map)) // 加载部件分层的图层 const bjfcLayer = esri.dynamicMapLayer({ url: `${this.baseUrl}${this.partsUrl}`, minZoom: 20, // 最小缩放等级, zIndex: 10 // 设置显示层级,在底图之上 }).addTo(map) bjfcLayer.bindPopup(function(error, featureCollection) { if (error || featureCollection.features.length === 0) { return false } else { const bjItem = featureCollection.features[0] // 部件对象 const popupStr = '<div class="popup-div">' + '<div class="popup-title">' + bjItem.properties.objname + '</div>' + '<div class="dashed-line"></div>' + '<div class="popup-item"><label>部件类别</label>' + bjItem.properties.dl + ' / ' + bjItem.properties.xl + '</div>' + '<div class="popup-item"><label>部件编号</label>' + bjItem.properties.objid + '</div>' + '<div class="popup-item"><label>所在网格</label>' + bjItem.properties.bgid + '</div>' + '<div class="popup-item"><label>权属部门</label>' + bjItem.properties.deptname2 + '</div>' + '<div class="popup-item"><label>责任部门</label>' + bjItem.properties.deptname1 + '</div>' + '<div class="popup-item"><label>养护部门</label>' + bjItem.properties.deptname3 + '</div>' + '</div>' return popupStr } }) // 加载自行发布的底图服务 esri.dynamicMapLayer({ url: `${this.baseUrl}${this.mapUrl}`, zIndex: 1 }).addTo(map) // 初始化图层组 /* eslint-disable new-cap */ this.toVerifyCaseNot = new Leaflet.layerGroup().addTo(map) this.toVerifyCaseOt = new Leaflet.layerGroup().addTo(map) this.toCheckCaseNot = new Leaflet.layerGroup().addTo(map) this.toCheckCaseOt = new Leaflet.layerGroup().addTo(map) this.toHandleCaseNot = new Leaflet.layerGroup().addTo(map) this.toHandleCaseOt = new Leaflet.layerGroup().addTo(map) this.offlinePerson = new Leaflet.layerGroup().addTo(map) this.onlinePerson = new Leaflet.layerGroup().addTo(map) } } } </script> <style lang="scss" scoped> .staticPanel { height: calc(100vh - 56px); overflow-y: auto; } .mapPanel { height: calc(100vh - 56px); } .baseMap { height: calc(100vh - 136px); width: 100%; border: 1px solid #DCDCDC; border-radius: 4px; } .mapOverLayer { background-color: rgba(240, 240, 240, 0.9); position: absolute; top: 76px; width: calc(75vw - 10px); /* 浮层所占的宽度 */ height: 60px; margin-left: 0px; z-index: 999; } .rowSelect { margin-bottom: 10px; } .customLabel { padding: 0 12px 0 0; color: #606266; font-size: 14px; } .item { margin-bottom: 10px; } .item .notLastSelect { margin-right: 30px; } .caseStatisBlock { text-align: center; margin: 10px; color: #fff; font-weight: bold; letter-spacing: 1px; border-radius: 4px; padding: 15px 5px 5px; .bigNumber { font-size: 2rem; } } #today-visitor { background-image: linear-gradient(to right, #ff8fdf, #ff01b4); } #total-alarm { background-image: linear-gradient(to right, #7fbbff, #0078ff); } #online-device { background-image: linear-gradient(to right, #72ff7e, #01a411); } #total-device { background-image: linear-gradient(to right, #ffa800, #ce7e00); } </style> <style> .leaflet-container a.leaflet-popup-close-button { top: 5px; /* 修改弹窗关闭按钮样式 */ right: 10px; /* 修改弹窗关闭按钮样式 */ } .leaflet-popup-content .popup-div { font-size: 15px; padding: 6px; } .leaflet-popup-content .popup-title { font-weight: bold; } .leaflet-popup-content .dashed-line { border-bottom: 1px dashed #dddddd; margin: 10px -10px; } .leaflet-popup-content .popup-item { padding-bottom: 6px; } .leaflet-popup-content .popup-item label { font-weight: bold; padding-right: 15px; } </style>