564 lines
14 KiB
Vue
564 lines
14 KiB
Vue
<template>
|
||
<div class="yqgkcCon nynj">
|
||
<!-- 轨迹地图弹窗 -->
|
||
<el-dialog
|
||
custom-class="table_dialog"
|
||
top="85px"
|
||
:show-close="false"
|
||
width="100%"
|
||
destroy-on-close
|
||
append-to-body
|
||
:visible.sync="mapDialogVisible"
|
||
v-if="mapDialogVisible"
|
||
>
|
||
<div class="inner_width" style="background: #0B2536;height:106%;">
|
||
<img class="inner-img-w" src="@/assets/image/big_background.png" alt="">
|
||
<div class="content-box" style="padding: 0;">
|
||
<div class="mapparent" id="trajectory"></div>
|
||
<div class="topdetail">
|
||
<div class="map_detail_tit">
|
||
轨迹详情
|
||
<div style="height: 40px;float:right;cursor: pointer;" @click.stop="closeMapDialog">
|
||
<div class="banrutimg">
|
||
<span>关闭</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="map-ul">
|
||
<div class="map-li">车辆:{{trajectoryVehicleName || '--'}}</div>
|
||
<div class="map-li">车牌:{{trajectoryPlate || '--'}}</div>
|
||
<div class="map-li">司机:{{formatName(trajectoryDriver)}}</div>
|
||
<div class="map-li">GPS设备:{{trajectoryGpsId || '--'}}</div>
|
||
<div class="map-li">轨迹点数:{{trajectoryPoints.length || 0}}</div>
|
||
<div class="map-li"></div>
|
||
<div class="map-li"></div>
|
||
<div class="map-li"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="bottom-box">
|
||
<div class="play" @click="jog">
|
||
<img style="width: 24px;height: 24px;margin-bottom:3px" src="@/assets/image/reduce.png" alt="">
|
||
<div>减速</div>
|
||
</div>
|
||
<div class="play" v-if="playsttus == 0 || playsttus == 2" @click="silderInput">
|
||
<img src="@/assets/image/play.png" alt="">
|
||
<div>播放</div>
|
||
</div>
|
||
<div class="play" v-if="playsttus == 1" @click="pauseAnimation">
|
||
<img style="width: 24px;height: 24px;margin-bottom:3px" src="@/assets/image/puse.png" alt="">
|
||
<div>暂停</div>
|
||
</div>
|
||
<div class="play" @click="fastforward">
|
||
<img style="width: 24px;height: 24px;margin-bottom:3px" src="@/assets/image/add.png" alt="">
|
||
<div>加速</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { gpsRecordPage } from '@/api';
|
||
|
||
export default {
|
||
name: "zhnjCov",
|
||
props: {
|
||
// 从父组件接收车辆数据(点击地图标记时传入)
|
||
vehicleData: {
|
||
type: Object,
|
||
default: null
|
||
},
|
||
// 控制弹窗显示
|
||
visible: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
},
|
||
watch: {
|
||
vehicleData: {
|
||
handler(newVal) {
|
||
if (newVal && newVal.gpsId) {
|
||
// 接收到车辆数据,打开轨迹弹窗
|
||
this.openTrajectoryDialog(newVal);
|
||
}
|
||
},
|
||
deep: true,
|
||
immediate: true
|
||
},
|
||
visible: {
|
||
handler(newVal) {
|
||
if (!newVal) {
|
||
this.mapDialogVisible = false;
|
||
this.clearMap();
|
||
}
|
||
},
|
||
immediate: true
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
mapDialogVisible: false,
|
||
|
||
// 轨迹相关
|
||
trajectoryPoints: [],
|
||
trajectoryVehicleName: '',
|
||
trajectoryPlate: '',
|
||
trajectoryDriver: '',
|
||
trajectoryGpsId: '',
|
||
allTrajectoryData: [],
|
||
|
||
// 地图相关
|
||
myMap: null,
|
||
polyline: null,
|
||
passedPolyline: null,
|
||
marker: null,
|
||
|
||
playsttus: 0,
|
||
valueTime: ''
|
||
};
|
||
},
|
||
methods: {
|
||
// 打开轨迹弹窗
|
||
openTrajectoryDialog(vehicleInfo) {
|
||
if (!vehicleInfo.gpsId) {
|
||
this.$message.warning('该车辆没有GPS设备ID');
|
||
return;
|
||
}
|
||
|
||
this.trajectoryVehicleName = vehicleInfo.veNotes || vehicleInfo.vehicleName || '车辆';
|
||
this.trajectoryPlate = vehicleInfo.vePlate || vehicleInfo.plateNumber || '--';
|
||
this.trajectoryDriver = vehicleInfo.veDriver || vehicleInfo.driverName || '--';
|
||
this.trajectoryGpsId = vehicleInfo.gpsId;
|
||
|
||
// 打开轨迹弹窗
|
||
this.mapDialogVisible = true;
|
||
// 获取轨迹数据
|
||
this.fetchAllTrajectoryData();
|
||
},
|
||
|
||
// 关闭轨迹弹窗
|
||
closeMapDialog() {
|
||
this.mapDialogVisible = false;
|
||
this.clearMap();
|
||
this.$emit('close');
|
||
},
|
||
|
||
// 清除地图
|
||
clearMap() {
|
||
if (this.marker) {
|
||
try {
|
||
this.marker.stopMove();
|
||
} catch(e) {}
|
||
this.marker = null;
|
||
}
|
||
if (this.polyline) {
|
||
this.polyline = null;
|
||
}
|
||
if (this.passedPolyline) {
|
||
this.passedPolyline = null;
|
||
}
|
||
if (this.myMap) {
|
||
try {
|
||
this.myMap.destroy();
|
||
} catch(e) {}
|
||
this.myMap = null;
|
||
}
|
||
this.playsttus = 0;
|
||
},
|
||
|
||
// 获取全部轨迹数据(不分页)
|
||
fetchAllTrajectoryData() {
|
||
const params = {
|
||
pageNo: 1,
|
||
pageSize: 1000,
|
||
gpsId: this.trajectoryGpsId
|
||
};
|
||
|
||
this.$message({
|
||
message: '正在加载轨迹数据...',
|
||
type: 'info',
|
||
duration: 1500
|
||
});
|
||
|
||
gpsRecordPage(params).then(res => {
|
||
if (res.success && res.result) {
|
||
const records = res.result.records || [];
|
||
this.allTrajectoryData = records;
|
||
|
||
// 提取经纬度点
|
||
this.trajectoryPoints = records
|
||
.filter(item => item.jingdu && item.weidu)
|
||
.map(item => [parseFloat(item.jingdu), parseFloat(item.weidu)]);
|
||
|
||
console.log('轨迹点数量:', this.trajectoryPoints.length);
|
||
|
||
if (this.trajectoryPoints.length > 0) {
|
||
this.$nextTick(() => {
|
||
this.initTrajectoryMap();
|
||
});
|
||
} else {
|
||
this.$message.warning('该车辆暂无轨迹数据');
|
||
}
|
||
} else {
|
||
this.$message.error('获取轨迹数据失败');
|
||
}
|
||
}).catch(err => {
|
||
console.error('获取轨迹数据失败:', err);
|
||
this.$message.error('获取轨迹数据失败');
|
||
});
|
||
},
|
||
|
||
// 初始化轨迹地图
|
||
initTrajectoryMap() {
|
||
if (this.trajectoryPoints.length === 0) return;
|
||
|
||
this.clearMap();
|
||
|
||
const mapContainer = document.getElementById('trajectory');
|
||
if (!mapContainer) {
|
||
console.error('地图容器不存在');
|
||
return;
|
||
}
|
||
|
||
// 初始化地图
|
||
this.myMap = new AMap.Map('trajectory', {
|
||
resizeEnable: true,
|
||
viewMode: '3D',
|
||
zoomEnable: true,
|
||
dragEnable: true,
|
||
doubleClickZoom: true,
|
||
zoom: 15,
|
||
center: this.trajectoryPoints[0]
|
||
});
|
||
|
||
// 添加地图图层
|
||
let googleLayer = new AMap.TileLayer({
|
||
tileSize: 256,
|
||
errorUrl: '',
|
||
getTileUrl: function (x, y, z) {
|
||
return 'https://map.snkoudai.com/maps/vt/lyrs=y&hl=zh-CN&gl=cn&scale=1&x=' + x + '&y=' + y + '&z=' + z + '';
|
||
},
|
||
zIndex: 2,
|
||
zooms: [16, 22],
|
||
opacity: 1,
|
||
});
|
||
googleLayer.setMap(this.myMap);
|
||
|
||
// 绘制轨迹线
|
||
this.polyline = new AMap.Polyline({
|
||
map: this.myMap,
|
||
path: this.trajectoryPoints,
|
||
showDir: true,
|
||
strokeColor: "#28F",
|
||
strokeWeight: 6,
|
||
});
|
||
this.myMap.add(this.polyline);
|
||
|
||
// 添加起点标记
|
||
this.marker = new AMap.Marker({
|
||
map: this.myMap,
|
||
position: this.trajectoryPoints[0],
|
||
icon: "https://manage.ilhzn.cn/zh-api/sys/common/static/temp/20241228154040_824e4981dff456b1bb8889.png",
|
||
offset: new AMap.Pixel(-23, -30)
|
||
});
|
||
|
||
// 已走过的路径
|
||
this.passedPolyline = new AMap.Polyline({
|
||
strokeColor: "#AF5",
|
||
strokeWeight: 6,
|
||
});
|
||
this.myMap.add(this.passedPolyline);
|
||
|
||
// 自适应视图
|
||
this.myMap.setFitView();
|
||
},
|
||
|
||
// 播放控制
|
||
silderInput() {
|
||
if (this.trajectoryPoints.length === 0) {
|
||
this.$message.warning('暂无轨迹数据');
|
||
return;
|
||
}
|
||
|
||
if (this.playsttus === 1) {
|
||
this.pauseAnimation();
|
||
return;
|
||
} else if (this.playsttus === 2) {
|
||
this.resumeAnimation();
|
||
return;
|
||
}
|
||
|
||
this.playsttus = 1;
|
||
const that = this;
|
||
|
||
AMap.plugin("AMap.MoveAnimation", () => {
|
||
that.marker.moveAlong(that.trajectoryPoints, {
|
||
duration: 5000,
|
||
autoRotation: true,
|
||
});
|
||
that.marker.on("moving", (e) => {
|
||
that.passedPolyline.setPath(e.passedPath);
|
||
that.myMap.setCenter(e.target.getPosition(), true);
|
||
if (e.passedPath.length === that.trajectoryPoints.length) {
|
||
that.playsttus = 0;
|
||
}
|
||
});
|
||
});
|
||
},
|
||
|
||
pauseAnimation() {
|
||
if (this.marker) {
|
||
this.marker.pauseMove();
|
||
this.playsttus = 2;
|
||
}
|
||
},
|
||
|
||
resumeAnimation() {
|
||
if (this.marker) {
|
||
this.marker.resumeMove();
|
||
this.playsttus = 1;
|
||
}
|
||
},
|
||
|
||
jog() {
|
||
this.$message.info('减速');
|
||
},
|
||
|
||
fastforward() {
|
||
this.$message.info('加速');
|
||
},
|
||
|
||
formatName(name) {
|
||
if (!name) return '--';
|
||
if (name.length <= 1) return name + '*';
|
||
if (name.length === 2) return name.charAt(0) + '*';
|
||
return name.charAt(0) + '*'.repeat(name.length - 1);
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
:deep.el-pagination.is-background .el-pager li:not(.disabled).active {
|
||
background: #409EFF !important;
|
||
}
|
||
</style>
|
||
|
||
<style lang="less">
|
||
.table_dialog {
|
||
width: 100%;
|
||
height: calc(100vh - 122px);
|
||
margin-bottom: 0;
|
||
background: none;
|
||
padding: 20px;
|
||
box-sizing: border-box;
|
||
}
|
||
.table_dialog .inner_width {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
}
|
||
.table_dialog .inner_width .inner-img-w {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.table_dialog .inner_width .content-box {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
padding: 15px 20px;
|
||
box-sizing: border-box;
|
||
}
|
||
.table_dialog .inner_width .bottom-box {
|
||
position: absolute;
|
||
bottom: 10px;
|
||
left: 0;
|
||
right: 0;
|
||
margin: auto;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
display: flex;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
width: 98%;
|
||
}
|
||
.table_dialog .inner_width .bottom-box .play {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
padding: 10px 0;
|
||
box-sizing: border-box;
|
||
cursor: pointer;
|
||
}
|
||
.table_dialog .inner_width .bottom-box .play img {
|
||
width: 28px;
|
||
height: 28px;
|
||
}
|
||
.table_dialog .inner_width .bottom-box .play div {
|
||
width: 100%;
|
||
font-weight: 400;
|
||
font-size: 16px;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
}
|
||
.table_dialog .inner_width .topdetail {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 0;
|
||
left: 1%;
|
||
height: 140px;
|
||
background: rgba(0, 0, 0, 0.61);
|
||
padding: 14px 30px;
|
||
box-sizing: border-box;
|
||
width: 98%;
|
||
}
|
||
.table_dialog .inner_width .topdetail .map_detail_tit {
|
||
font-weight: 500;
|
||
font-size: 18px;
|
||
color: #01fffa;
|
||
position: relative;
|
||
padding-left: 20px;
|
||
box-sizing: border-box;
|
||
line-height: 1.5;
|
||
}
|
||
.table_dialog .inner_width .topdetail .map_detail_tit:before {
|
||
content: ' ';
|
||
width: 4px;
|
||
height: 24px;
|
||
background: #01fffa;
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
}
|
||
.table_dialog .inner_width .topdetail .map-ul {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
flex-wrap: wrap;
|
||
margin-top: 10px;
|
||
}
|
||
.table_dialog .inner_width .topdetail .map-ul .map-li {
|
||
width: 25%;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #FFFFFF;
|
||
line-height: 2.5;
|
||
overflow: hidden;
|
||
display: block;
|
||
}
|
||
.table_dialog .el-dialog__header {
|
||
padding: 0;
|
||
}
|
||
.table_dialog .el-dialog__body {
|
||
height: 100%;
|
||
padding: 0;
|
||
}
|
||
.table_dialog .el-table tr {
|
||
background: none;
|
||
}
|
||
.table_dialog .el-table td.el-table__cell,
|
||
.table_dialog .el-table th.el-table__cell.is-leaf {
|
||
border-color: rgba(16, 128, 255, 0.4);
|
||
color: #fff;
|
||
}
|
||
.table_dialog .el-input__inner {
|
||
background: none;
|
||
border: none;
|
||
color: #01fffa;
|
||
height: 36px;
|
||
line-height: 36px;
|
||
}
|
||
.table_dialog .el-table th.el-table__cell {
|
||
background: none;
|
||
}
|
||
.table_dialog .el-table--border::after,
|
||
.table_dialog .el-table--group::after,
|
||
.table_dialog .el-table::before {
|
||
background-color: rgba(16, 128, 255, 0.4);
|
||
}
|
||
.table_dialog .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
|
||
background: #06111B !important;
|
||
}
|
||
.table_dialog .pagination {
|
||
margin-top: 20px;
|
||
color: #fff;
|
||
text-align: center;
|
||
}
|
||
.table_dialog .pagination .el-pager li {
|
||
background: none;
|
||
color: #fff;
|
||
}
|
||
.table_dialog .pagination .el-pagination .btn-next,
|
||
.table_dialog .pagination .el-pagination .btn-prev {
|
||
background: none;
|
||
color: #fff;
|
||
}
|
||
.table_dialog .pagination .el-pagination__jump {
|
||
color: #fff;
|
||
}
|
||
.el-select-dropdown,
|
||
.el-picker-panel {
|
||
background-color: #0b202f;
|
||
border-color: rgba(16, 128, 255, 0.4);
|
||
}
|
||
.el-table td {
|
||
padding: 4px 0px;
|
||
}
|
||
.el-date-table__row .available {
|
||
color: #fff;
|
||
}
|
||
.el-date-picker__header .el-picker-panel__icon-btn {
|
||
color: #fff;
|
||
}
|
||
.el-date-picker__header .el-date-picker__header-label {
|
||
color: #fff;
|
||
}
|
||
.el-select-dropdown__item.hover,
|
||
.el-select-dropdown__item:hover {
|
||
background-color: #0b202f;
|
||
color: #fff;
|
||
}
|
||
.popper__arrow {
|
||
border-color: #0b202f;
|
||
}
|
||
.el-button--text {
|
||
color: #01fffa;
|
||
}
|
||
.mapparent {
|
||
width: 98%;
|
||
height: 800px;
|
||
margin: 0 auto;
|
||
margin-top: 1%;
|
||
background: #0a2a3a;
|
||
border-radius: 8px;
|
||
}
|
||
.banrutimg {
|
||
width: 88px;
|
||
height: 36px;
|
||
line-height: 36px;
|
||
background: url(@/assets/image/zhnj/backreturn.png) no-repeat;
|
||
background-size: 100% 100%;
|
||
}
|
||
.banrutimg span {
|
||
float: right;
|
||
color: #fff;
|
||
font-size: 16px;
|
||
margin-right: 20px;
|
||
}
|
||
.banrutimg:hover {
|
||
width: 88px;
|
||
height: 36px;
|
||
line-height: 36px;
|
||
float: right;
|
||
color: #fff;
|
||
font-size: 16px;
|
||
background: url(@/assets/image/zhnj/backreturnhover.png) no-repeat;
|
||
background-size: 100% 100%;
|
||
}
|
||
</style> |