<template> <app-container id="overview"> <!--筛选条件--> <search-area size="small" @search="search"> <search-item> <el-input v-model.trim="listQuery.description" placeholder="车辆描述" size="small" clearable/> </search-item> <search-item> <el-input v-model="listQuery.carCode" placeholder="车牌号" size="small" clearable/> </search-item> <search-item> <el-select v-model="listQuery.carType" filterable placeholder="车辆类型" size="small" clearable value="" @change="fetchData()"> <el-option v-for="item in cartypelist" :key="item.value" :label="item.name" :value="item.value"/> </el-select> </search-item> <search-item> <dept-select v-model="listQuery.deptId" :dept-show="deptShow" placeholder="使用单位" size="small" clearable value=""/> </search-item> </search-area> <div id="map"> <!--查询结果Table显示--> <div slot="header" class="rightcard" > <el-row> <el-col :span="3"> <div style="font-size: 14px;padding-top: 10px;">在线:{{ online }}</div> </el-col> <el-col :span="3"> <div style="font-size: 14px;padding-top: 10px">离线:{{ offline }}</div> </el-col> <el-col :span="3"> <div style="font-size: 14px;padding-top: 10px;padding-left: 5px">刷新时间</div> </el-col> <el-col :span="9" style="padding-top: 12px;padding-left: 10px"> <el-radio-group v-model="refresh" @change="clicktime"> <el-radio label="10">10秒</el-radio> <el-radio label="30">30秒</el-radio> <el-radio label="60">60秒</el-radio> </el-radio-group> </el-col> <el-col :span="4" style="padding-top: 10px"> <label style="font-size: 14px;padding-left: 5px;color: red">{{ sec }}</label> <label style="font-size: 14px">秒后刷新</label> </el-col> <el-col :span="2" style="padding-top: 4px;padding-left: 5px"> <el-button type="primary" size="small" @click="fetchData">立即刷新</el-button> </el-col> </el-row> </div> <div slot="header" class="table-title" @click="tableclick"> <div class="table-name"> 车辆列表 </div> <i v-if="showtable==true" class="el-icon-arrow-down" style="position:absolute; right:20px;top:20px;margin-top:-8px;"/> <i v-if="showtable==false" class="el-icon-arrow-right" style="position:absolute; right:20px;top:20px;margin-top:-8px;"/> </div> <el-table v-if="showtable==true" :row-style="{height: '33px'}" :cell-style="{padding: '0px'}" :header-cell-style="{background: '#ffffff'}" :data="list" max-height="300" class="table" border @row-dblclick="dbSelected" @selection-change="handleSelectionChange"> <el-table-column :index="indexMethod" align="center" type="index" label="序号" width="55"/> <el-table-column v-for="column in columns" :key="column.value" :label="column.text" :width="column.width" :align="column.align" show-overflow-tooltip> <template slot-scope="scope"> <span :class="column.class">{{ scope.row[column.value] }}</span> </template> </el-table-column> <el-table-column label="更多" width="110" align="center"> <template slot-scope="scope"> <el-button type="text" size="mini" @click="track(scope.row.carId)">跟踪</el-button> <el-button type="text" size="mini" @click="trail(scope.row.carId,scope.row)">轨迹</el-button> </template> </el-table-column> </el-table> <div v-if="showtable==true" class="pagination-container"> <el-pagination v-show="total>listQuery.limit" :current-page="listQuery.offset" :page-sizes="[15,20,30]" :page-size="listQuery.limit" :total="total" class="table-bottom" align="center" layout="total, sizes, prev, pager, next" @size-change="handleSizeChange" @current-change="handleCurrentChange"/> </div> </div> <edit-car-info v-show="dialogFormVisible" ref="editCarInfo" @watchChild="fetchData"/> </app-container> </template> <script> import editCarInfo from '@/views/carinfo/editCarInfo' import { getOverviewList, offlineCount, getOverviewAllList } from '@/api/overview' import { getDictCode } from '@/api/dict' import DeptSelect from '@/components/DeptSelect' import L from 'leaflet' import 'leaflet/dist/leaflet.css' import 'leaflet-rotatedmarker/leaflet.rotatedMarker.js' export default { name: 'ListOverview', components: { DeptSelect, editCarInfo }, data() { return { dialogFormVisible: false, // 是否显示编辑框 refresh: '30', online: 0, offline: 0, showtable: true, deptShow: true, listQuery: { description: '', carCode: '', carType: '', deptId: '', offset: 1, limit: 15 }, // 查询条件 columns: [ { text: '车辆描述', value: 'description', align: 'center' }, { text: '车牌号', value: 'carCode', align: 'center', width: 90 }, { text: '状态', value: 'status', align: 'center', width: 70 } ], // 动态加载的表头 TianDiTu: { Normal: { Map: 'https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8', Annotion: 'https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8' }, Satellite: { Map: 'https://t{s}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8', Annotion: 'https://t{s}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8' }, Terrain: { Map: 'https://t{s}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8', Annotion: 'https://t{s}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8' }, Subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'] }, baselayer: [], list: [], // 列表数据 alllist: [], // 列表数据 map: null, total: 0, // 数据总数 sec: 10, // 数据总数 // listLoading: true, // 加载动画 fullscreenLoading: false, // 全屏加载动画 cartypelist: [], // 类型列表 deptlist: [] // 类型列表 } }, watch: { sec(val) { if (val === 0) { this.sec = Number(this.refresh) this.fetchCar() } } }, mounted() { getDictCode('carType').then(response => { this.cartypelist = response.data }) this.initMap() this.fetchData() setInterval(() => { this.sec-- }, 1000) }, methods: { dbSelected(row) { this.map.setView({ lat: Number(row.lat), lng: Number(row.lng) }, 18) }, tableclick() { this.showtable = !this.showtable }, detail(id) { this.dialogFormVisible = true var item = { id: id } this.$refs.editCarInfo.initDialog('detail', this.dialogFormVisible, item) }, track(id) { this.$router.push({ name: 'Track', query: { id: id } }) }, trail(id, row) { this.$router.push({ name: 'Trail', query: { id: id, name: row.carCode + '-' + row.carTypeName } }) }, initMap() { const map = L.map('map', { minZoom: 3, maxZoom: 18, center: [27.75962, 116.06021], zoom: 11, zoomControl: false, attributionControl: false, crs: L.CRS.EPSG3857 }) map.doubleClickZoom.disable() this.map = map // data上需要挂载 window.map = map this.baselayer.push(L.tileLayer( 'https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8', { subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'] } ).addTo(map)) this.baselayer.push(L.tileLayer( 'https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8', { subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'] } ).addTo(map)) }, search() { this.fetchData(false) }, clicktime() { this.sec = Number(this.refresh) }, setZoom(points) { // console.log(points) if (points.length > 0) { var maxLng = points[0][1] var minLng = points[0][1] var maxLat = points[0][0] var minLat = points[0][0] var res for (var i = points.length - 1; i >= 0; i--) { res = points[i] if (res[1] > maxLng) maxLng = res[1] if (res[1] < minLng) minLng = res[1] if (res[0] > maxLat) maxLat = res[0] if (res[0] < minLat) minLat = res[0] } var cenLng = (parseFloat(maxLng) + parseFloat(minLng)) / 2 var cenLat = (parseFloat(maxLat) + parseFloat(minLat)) / 2 var zoom = this.getZoom(maxLng, minLng, maxLat, minLat) this.map.setView({ lat: cenLat, lng: cenLng }, zoom) } else { // 没有坐标,显示全中国 this.map.setView({ lat: 103.388611, lng: 35.563611 }, 5) } }, getZoom(maxLng, minLng, maxLat, minLat) { var zoom = ['50', '100', '200', '500', '1000', '2000', '5000', '10000', '20000', '25000', '50000', '100000', '200000', '500000', '1000000', '2000000']// 级别18到3。 var latlng = L.latLng(maxLat, maxLng) var distance = latlng.distanceTo(L.latLng(minLat, minLng)) // var distance = pointA.distanceTo(pointB)// 获取两点距离,保留小数点后两位 for (var i = 0, zoomLen = zoom.length; i < zoomLen; i++) { if (zoom[i] - distance > 0) { return 18 - i + 2 // 之所以会多2,是因为地图范围常常是比例尺距离的10倍以上。所以级别会增加3。 } } }, setCenter(points) { // 获取折线中心点坐标 if (points.length > 0) { let maxLng = points[0][1] let minLng = points[0][1] let maxLat = points[0][0] let minLat = points[0][0] let res for (let i = points.length - 1; i >= 0; i--) { res = points[i] if (res[1] > maxLng) maxLng = res[1] if (res[1] < minLng) minLng = res[1] if (res[0] > maxLat) maxLat = res[0] if (res[0] < minLat) minLat = res[0] } const cenLng = (parseFloat(maxLng) + parseFloat(minLng)) / 2 const cenLat = (parseFloat(maxLat) + parseFloat(minLat)) / 2 this.map.setView({ lat: cenLat, lng: cenLng }) } }, fetchData(isNowPage = true) { // this.listLoading = true offlineCount(this.listQuery).then(response => { this.online = response.data.online this.offline = response.data.offline }) this.sec = Number(this.refresh) if (!isNowPage) { this.listQuery.offset = 1 } getOverviewList(this.listQuery).then(response => { this.list = response.data.rows this.total = parseInt(response.data.total) // this.listLoading = false }) getOverviewAllList(this.listQuery).then(response => { this.alllist = response.data var base = this.baselayer this.map.eachLayer(function(layer) { if (layer !== base[0] && layer !== base[1]) { layer.remove() } }) var list = [] for (i = 0; i < this.alllist.length; i++) { if (Number(this.alllist[i].lat) === 0 && Number(this.alllist[i].lng) === 0) { continue } var item = [Number(this.alllist[i].lat), Number(this.alllist[i].lng)] list.push(item) } if (list.length !== 0) { this.setZoom(list) } var Icon for (var i = 0; i < this.alllist.length; i++) { if (this.alllist[i].status === '离线') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-offline.png'), // 灰 iconSize: [40, 40] }) } else if (this.alllist[i].status === '超时') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-timeout.png'), // 橙 iconSize: [40, 40] }) } else if (this.alllist[i].status === '停车') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-stop.png'), // 黄 iconSize: [40, 40] }) } else if (this.alllist[i].status === '行驶') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-online.png'), // 绿 iconSize: [40, 40] }) } else if (this.alllist[i].status === '报警') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-alarm.png'), // 红 iconSize: [40, 40] }) } var myIcon = L.divIcon({ html: '<div style="font-size: 13px;font-weight: bold;padding-top: 17px;text-align:center;"> ' + this.alllist[i].deptName + '_' + this.alllist[i].description + '</div>', className: '', iconSize: [100, 15] }) L.marker([this.alllist[i].lat, this.alllist[i].lng], { icon: myIcon }).addTo(this.map) var str = '<div style="font-size: 15px;padding: 6px"> <div style="font-weight: bold;padding-bottom: 10px">车辆位置概要信息</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">描述</label>' + this.alllist[i].description + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">类型</label>' + this.alllist[i].carTypeName + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">单位</label>' + this.alllist[i].deptName + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">状态</label>' + this.alllist[i].status + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">定位</label>' + this.alllist[i].lng + ' , ' + this.alllist[i].lat + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">时间</label>' + this.alllist[i].upTime + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">速度</label>' + this.alllist[i].speed + '(km/h)</div>' + '<div style="padding-top: 8px"><button style="margin-left: 80px;background-color: #42b983;border-color: #42b983;color: white;padding: 5px 8px;font-size: 12px;border-radius: 4px" id="btndetail">详情</button>' + '<button style="margin-right: 5px;margin-left: 5px;background-color: #409eff;border-color: #409eff;' + 'color: white;padding: 5px 8px;font-size: 12px;border-radius: 4px" id="btntrack">跟踪</button>' + '<button style="background-color: #e6a23c;border-color: #e6a23c;color: white;padding: 5px 8px;font-size: 12px;border-radius: 4px" id="btntrail">轨迹</button></div></div>' var popup = L.popup().setContent(str) var marker = L.marker([this.alllist[i].lat, this.alllist[i].lng], { icon: Icon, slug: this.alllist[i], rotationAngle: this.alllist[i].direction, zIndexOffset: 100000 }).addTo(this.map).bindPopup(popup) var that = this marker.on('click', function(e) { document.getElementById('btndetail').onclick = function() { that.detail(e.sourceTarget.options.slug.carId) } document.getElementById('btntrack').onclick = function() { that.track(e.sourceTarget.options.slug.carId) } document.getElementById('btntrail').onclick = function() { that.trail(e.sourceTarget.options.slug.carId, e.sourceTarget.options.slug) } }) } }) }, fetchCar(isNowPage = true) { // this.listLoading = true offlineCount(this.listQuery).then(response => { this.online = response.data.online this.offline = response.data.offline }) this.sec = Number(this.refresh) if (!isNowPage) { this.listQuery.offset = 1 } getOverviewList(this.listQuery).then(response => { this.list = response.data.rows this.total = parseInt(response.data.total) // this.listLoading = false }) getOverviewAllList(this.listQuery).then(response => { this.alllist = response.data var base = this.baselayer this.map.eachLayer(function(layer) { if (layer !== base[0] && layer !== base[1]) { layer.remove() } }) var list = [] for (i = 0; i < this.alllist.length; i++) { if (Number(this.alllist[i].lat) === 0 && Number(this.alllist[i].lng) === 0) { continue } var item = [Number(this.alllist[i].lat), Number(this.alllist[i].lng)] list.push(item) } var Icon for (var i = 0; i < this.alllist.length; i++) { if (this.alllist[i].status === '离线') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-offline.png'), // 灰 iconSize: [40, 40] }) } else if (this.alllist[i].status === '超时') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-timeout.png'), // 橙 iconSize: [40, 40] }) } else if (this.alllist[i].status === '停车') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-stop.png'), // 黄 iconSize: [40, 40] }) } else if (this.alllist[i].status === '行驶') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-online.png'), // 绿 iconSize: [40, 40] }) } else if (this.alllist[i].status === '报警') { Icon = L.icon({ iconUrl: require('../../assets/global_images/car-alarm.png'), // 红 iconSize: [40, 40] }) } var myIcon = L.divIcon({ html: '<div style="font-size: 13px;font-weight: bold;padding-top: 17px;text-align:center;"> ' + this.alllist[i].deptName + '_' + this.alllist[i].description + '</div>', className: '', iconSize: [100, 15] }) L.marker([this.alllist[i].lat, this.alllist[i].lng], { icon: myIcon }).addTo(this.map) var str = '<div style="font-size: 15px;padding: 6px"> <div style="font-weight: bold;padding-bottom: 10px">车辆位置概要信息</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">描述</label>' + this.alllist[i].description + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">类型</label>' + this.alllist[i].carTypeName + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">单位</label>' + this.alllist[i].deptName + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">状态</label>' + this.alllist[i].status + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">定位</label>' + this.alllist[i].lng + ' , ' + this.alllist[i].lat + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">时间</label>' + this.alllist[i].upTime + '</div>' + '<div style="padding-bottom: 6px"><label style="font-weight: bold;padding-right: 15px">速度</label>' + this.alllist[i].speed + '(km/h)</div>' + '<div style="padding-top: 8px"><button style="margin-left: 80px;background-color: #42b983;border-color: #42b983;color: white;padding: 5px 8px;font-size: 12px;border-radius: 4px" id="btndetail">详情</button>' + '<button style="margin-right: 5px;margin-left: 5px;background-color: #409eff;border-color: #409eff;' + 'color: white;padding: 5px 8px;font-size: 12px;border-radius: 4px" id="btntrack">跟踪</button>' + '<button style="background-color: #e6a23c;border-color: #e6a23c;color: white;padding: 5px 8px;font-size: 12px;border-radius: 4px" id="btntrail">轨迹</button></div></div>' var popup = L.popup().setContent(str) var marker = L.marker([this.alllist[i].lat, this.alllist[i].lng], { icon: Icon, slug: this.alllist[i], rotationAngle: this.alllist[i].direction, zIndexOffset: 100000 }).addTo(this.map).bindPopup(popup) var that = this marker.on('click', function(e) { document.getElementById('btndetail').onclick = function() { that.detail(e.sourceTarget.options.slug.carId) } document.getElementById('btntrack').onclick = function() { that.track(e.sourceTarget.options.slug.carId) } document.getElementById('btntrail').onclick = function() { that.trail(e.sourceTarget.options.slug.carId, e.sourceTarget.options.slug) } }) } }) }, indexMethod(index) { return this.listQuery.limit * (this.listQuery.offset - 1) + index + 1 }, // 改变页容量 handleSizeChange(val) { this.listQuery.limit = val this.fetchData() }, // 改变当前页 handleCurrentChange(val) { this.listQuery.offset = val this.fetchData() }, // 多选触发方法 handleSelectionChange(val) { this.multipleSelection = val } } } </script> <style rel="stylesheet/scss" lang="scss" > .el-table__header tr, .el-table__header th { padding: 0; height: 40px; background-color: #f8f8f8; } .table{ margin-bottom: 20px; } .pagination-container{ margin-bottom: 100px; } </style> <style rel="stylesheet/scss" lang="scss" scoped> .table{ width: 460px; /*height: 60vh;*/ z-index: 10000; margin-top: 40px; position: relative; left:20px; top:30px; /*padding-bottom: 20px;*/ } .rightcard{ /*width: 750px;*/ height: 40px; z-index: 10000; position: absolute; /*left:500px;*/ top:20px; right: 0; background-color: #ffffff; padding-left: 20px; padding-right: 50px; } .table-bottom{ position: relative; left: 21px; /*top: 20px;*/ z-index: 10001; float: left; width: 458px; background-color: #ffffff; /* margin-top: 20px; */ padding-top: 20px; padding-bottom: 10px; } .table-name{ position:relative; width: 100px; top:20px; margin:-10px auto; //外面的div高度的一半 z-index: 100001; } .table-title{ font-size: 15px; text-align:center; width: 460px; height: 40px; background-color: #ffffff; z-index: 10000; position: absolute; left:20px; top:20px; font-weight: bold; } #map { width:100%; height: 80vh; border-top: 12px solid #ebebeb; } /deep/ .el-table--scrollable-y .el-table__body-wrapper{ padding-bottom: 11px !important; } /*/deep/ .el-radio__input.is-checked+.el-radio__label {*/ /*color: red;*/ /*}*/ /*/deep/ .el-radio__input.is-checked .el-radio__inner {*/ /*border-color: #e91e63;*/ /*background: #e91e63;*/ /*}*/ /deep/ .el-radio{ margin-right: 5px; } /deep/ .el-radio__label{ padding-left: 5px; } </style>