You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

735 lines
20 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="map-container">
<div class="input-search" id="targetElement">
<div class="search-box">
<input
type="text"
v-model="searchQuery.carPlate"
placeholder="请输入正确的车牌号"
/>
<i
class="el-icon-error icon-close"
v-show="searchQuery.carPlate"
@click="inputClear()"
></i>
<div class="search-btn" @click="handleSearch()">搜索</div>
</div>
<el-collapse-transition>
<div v-show="show" class="search-list">
<div
class="list-item"
v-for="item in searchList"
:key="item.carId"
@click="handelLookCar(item)"
>
{{ item.carName }}
</div>
<div class="no-data" v-show="searchText">{{ searchText }}</div>
</div>
</el-collapse-transition>
</div>
<div class="albuginea" @click="initTilesetLayer()">
{{ show3D ? "关闭" : "开启" }}三维
</div>
<mars-map @mapLoad="mapLoad" :options="options"></mars-map>
<div class="multiple">
<div
@click="toggleSelection(item)"
:class="{ checkbox: true, checked: isSelected(item) }"
v-for="(item, index) in multipleList"
:key="index"
>
<img
:src="require(`../assets/images/${item}.png`)"
alt=""
class="btn-icon"
/>
{{ item }}
</div>
</div>
<!-- <div id="carMarker" style="display: none"></div> -->
</div>
</template>
<script>
import MarsMap from "@/components/mars-map";
import { getfindByPlateNums } from "@/api/yunkun/index.js";
import { getCarPoint, getCarByCarplate } from "@/api/yunkun/yunkun.js";
import { html } from "js-beautify";
export default {
data() {
const basePathUrl = window.basePathUrl || "";
return {
timer: null,
time2: null,
searchList: [],
searchText: "",
searchQuery: {
carPlate: undefined, //车牌
plateColor: undefined, //车辆颜色
},
carQuery: {
teamId: 2, //该参数表示获取指定车队下所有层级子车队的车辆定位该参数优先级别高于carIds参数,
carIds: "", //车辆id 多个用逗号分开优先级低于teamId
},
list: [],
multipleList: ["营运线路", "维护线路", "临时任务", "枪支定位"],
selectedItems: ["枪支定位"],
graphicLayer: null,
baseUrl: basePathUrl + "lib/geoJson/tileset.json",
carUrl: basePathUrl + "static/qiche.gltf",
map: null,
mapLayer: {},
options: {
scene: {
center: {
lat: 31.019462,
lng: 120.635502,
alt: 13761.4,
heading: 357.9,
pitch: -31.5,
},
fog: false,
fxaa: false,
removeDblClick: true,
requestRenderMode: false,
scene3DOnly: false,
sceneMode: 3,
shadows: false,
showMoon: false,
showSkyAtmosphere: false,
showSkyBox: false,
showSun: false,
},
control: {
contextmenu: { preventDefault: false, hasDefault: false },
},
terrain: {
show: false,
},
basemaps: [
{
name: "影像地图",
type: "xyz",
url: process.env.VUE_APP_BASE_API2 + "/{z}/{y}/{x}.png",
minimumLevel: 1,
maximumLevel: 16,
show: true,
},
// {
// name: "mapbox影像图",
// icon: "img/basemaps/mapboxSatellite.png",
// type: "mapbox",
// username: "sharealex",
// styleId: "cly5i21fn00e901prgq643t4r",
// token:
// "pk.eyJ1Ijoic2hhcmVhbGV4IiwiYSI6ImNsaXNhZmRjbTFhbnczZmxib3h1OW05YXYifQ.PhlKv60ar3K359d8x2yBPw",
// tilesize: 256,
// scaleFactor: false,
// show: true,
// },
],
},
baimoUrl: process.env.VUE_APP_BASE_API3 + "/yunkun/tileset.json",
show: false,
showVideo: true,
show3D: false,
};
},
components: { MarsMap },
beforeDestroy() {
if (this.time) clearInterval(this.timer);
if (this.time2) clearInterval(this.time2);
// 在组件销毁之前移除事件监听,防止内存泄漏
document.removeEventListener("click", this.handleClickOutside);
this.mapLayer.car.remove();
this.mapLayer.car = null;
},
mounted() {
// 在mounted钩子中添加全局点击事件监听
document.addEventListener("click", this.handleClickOutside);
},
methods: {
// 搜索下拉框控制
handleClickOutside(event) {
if (
this.show &&
!document.getElementById("targetElement").contains(event.target)
) {
this.show = false;
}
},
/**获取车辆接口 */
async carPoint(isBoole) {
let res = await getCarPoint(this.carQuery);
res.list = res.list.filter((item) => item.stateCn.includes("在线"));
if (isBoole) {
let carPlates = res.list.map((item) => item.carPlate).toString();
let mission = await getfindByPlateNums({
plateNum: carPlates,
});
res.list = res.list.map((item) => {
let missionItem = mission.data.filter(
(it) => it.plateNum == item.carPlate
);
if (missionItem.length > 0) {
let missionType = 1;
if (missionItem[0].missionType == "临时任务") {
missionType = 3;
} else {
missionType = missionItem[0].name.includes("维护") ? 2 : 1;
}
item = {
...item,
...{
missionName: missionItem[0].name,
missionType: missionType,
missionId: missionItem[0].id,
},
};
} else {
item = {
...item,
...{
missionName: "未识别",
missionType: 1,
missionId: null,
},
};
}
return item;
});
}
return res.list;
},
/**
* 加载姑苏区三维图层
*/
initTilesetLayer() {
if (this.map) {
if (!this.mapLayer.tiles3dLayer) {
this.mapLayer.tiles3dLayer = new mars3d.layer.TilesetLayer({
name: "姑苏区建筑物",
url: this.baimoUrl,
maximumScreenSpaceError: 16,
maximumMemoryUsage: 1024 / 2,
dynamicScreenSpaceError: false,
skipLevelOfDetail: true,
preferLeaves: true,
flyTo: false,
style: {
color: {
conditions: [["true", `color("rgba(42, 160, 224, 1)")`]],
},
},
});
this.map.addLayer(this.mapLayer.tiles3dLayer);
this.show3D = true;
} else {
this.mapLayer.tiles3dLayer.show = !this.mapLayer.tiles3dLayer.show;
this.show3D = !this.show3D;
}
} else {
}
},
/**地图渲染完毕 */
mapLoad(map) {
this.map = map;
map.fixedLight = true; // 固定光照避免gltf模型随时间存在亮度不一致。
// 创建矢量图层
this.mapLayer.car = new mars3d.layer.GraphicLayer();
this.map.addLayer(this.mapLayer.car);
this.mapLayer.qiang = new mars3d.layer.GraphicLayer();
this.map.addLayer(this.mapLayer.qiang);
this.createCar();
},
/**创建车辆 苏E17360*/
async createCar(type) {
this.list = await this.carPoint(true);
this.mapLayer.car.clear();
this.mapLayer.car.enabledEvent = false; // 关闭事件大数据addGraphic时影响加载时间
for (let index = 0; index < this.list.length; index++) {
let item = this.list[index];
if (item.missionId) {
//只显示有任务的车辆
const graphic = new mars3d.graphic.ModelEntity({
id: `car${item.carId}`,
// position: new mars3d.LngLatPoint(
// parseFloat(item.lng),
// parseFloat(item.lat),
// 30
// ),
style: {
url: this.carUrl,
scale: 0.5,
minimumPixelSize: 32,
silhouette: true,
silhouetteColor: "#008cff",
pitch: 0, //俯仰角
roll: 0, //翻滚角
highlight: {
// type: "click",
silhouette: true,
silhouetteColor: "#FFB200",
},
},
circle: {
radius: 200,
fill: false,
materialType: mars3d.MaterialType.CircleWave,
materialOptions: {
color: "#FFB200",
count: 2,
speed: 6,
},
},
attr: {
index: item.carId,
missionId: item.missionId,
missionName: item.missionName,
missionType: item.missionType,
},
});
this.mapLayer.car.addGraphic(graphic);
this.mapLayer.car.enabledEvent = true; // 恢复事件
graphic.bindPopup(
() => {
let html = `<div id="car${item.carId}" class="carPlate">
<img src="${require(`../assets/images/carType${item.missionType}.png`)}" class="carType"/>
${item.carPlate}
</div>`;
return html;
},
{
closeButton: false, //去除关闭按钮
className: "car-page-popup",
pointerEvents: false, //DIV是否可以鼠标交互为false时可以穿透操作及缩放地图但无法进行鼠标交互及触发相关事件。
closeOnClick: false, //是否在单击Map地图时自动关闭当前弹窗
autoClose: false, //在打开弹窗时,是否自动关闭之前的弹窗
toggle: false, //是否打开状态下再次单击时关闭Popup
}
);
graphic.openPopup();
graphic.on(mars3d.EventType.highlightOpen, (e) => {
e.target.setOptions({
//添加圆效果
circle: {
fill: true,
},
});
this.handleCarActive({
id: e.target._id,
color: "#FFB200",
image: require(`../assets/images/carType${e.target.attr.missionType}-s.png`),
});
});
graphic.on(mars3d.EventType.highlightClose, (e) => {
e.target.setOptions({
circle: {
fill: false,
},
});
this.handleCarActive({
id: e.target._id,
color: "#008cff",
image: require(`../assets/images/carType${e.target.attr.missionType}.png`),
});
});
this.$nextTick(() => {
if (type) {
console.log(type);
// 开启高亮
graphic.openHighlight();
}
});
graphic.on(mars3d.EventType.click, (e) => {
const attr = e.target.attr;
if (!attr.missionId) {
this.$modal.msgError("该车辆暂无任务!");
return;
}
this.$router.push({
path: "/carInfo",
query: {
carId: e.target.attr.index,
missionId: attr.missionId,
missionName: item.missionName,
},
});
});
}
}
// 定时更新动态位置setInterval为演示
this.changePosition(0);
const interval = 10;
this.changePosition(interval);
//生产环境开启轮询
this.time = setInterval(() => {
this.changePosition(interval);
}, interval * 1000);
},
async changePosition(interval) {
let list = await this.carPoint();
this.mapLayer.car.eachGraphic((graphic) => {
if (!graphic.show) return;
let carItam = list.filter((car) => `car${car.carId}` == graphic.id);
if (carItam.length > 0) {
let position = Cesium.Cartesian3.fromDegrees(
parseFloat(carItam[0].lng),
parseFloat(carItam[0].lat),
30
);
graphic.addDynamicPosition(position, interval); // 按time秒运动至指定位置
}
});
},
async getPoint() {
let res = await getCarPoint({
teamId: 3,
});
res.list = res.list.filter((item) => item.stateCn.includes("在线"));
return res.list;
},
async createQ() {
const list = await this.getPoint();
this.mapLayer.qiang.clear();
this.mapLayer.qiang.enabledEvent = false; // 关闭事件大数据addGraphic时影响加载时间
list.map((item, index) => {
const graphic = new mars3d.graphic.DivGraphic({
id: `qIcon${item.carId}`,
position: new mars3d.LngLatPoint(
parseFloat(item.lng),
parseFloat(item.lat)
),
style: {
html: `
<div class="q-icon">
<div class="qiang-popup"> ${item.carName}</div>
<img src="${require("../assets/images/qiangIcon.png")}" />
</div>
`,
clampToGround: true,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
});
this.mapLayer.qiang.addGraphic(graphic);
});
// this.changeQPosition(0);
const interval = 10;
this.changeQPosition(interval);
this.time2 = setInterval(() => {
this.changeQPosition(interval);
}, interval * 1000);
},
async changeQPosition(interval) {
let list = await this.getPoint();
this.mapLayer.qiang.eachGraphic((graphic) => {
let qIcon = list.filter((car) => `qIcon${car.carId}` == graphic.id);
if (qIcon.length > 0) {
let position = Cesium.Cartesian3.fromDegrees(
parseFloat(qIcon[0].lng),
parseFloat(qIcon[0].lat),
30
);
graphic.addDynamicPosition(position, interval); // 按time秒运动至指定位置
}
});
},
/**
* 处理车辆被选中
*/
handleCarActive(data) {
let carItem = document.getElementById(data.id);
// console.log(data, carItem);
let carIcon = carItem.getElementsByClassName("carType")[0];
carIcon.src = data.image;
carItem.style.borderColor = data.color;
},
/**根据车牌号查询车辆实时定位 */
async handleSearch() {
if (!this.searchQuery.carPlate) {
this.inputClear();
return;
}
// 清除轮询定时器
if (this.timer) clearInterval(this.timer);
const result = await getCarByCarplate(this.searchQuery);
if (result.list) {
this.searchText = "";
if (result.list[0].stateCn.includes("离线")) {
this.$modal.msgError(`该车${result.list[0].stateCn}!`);
return;
}
this.searchList = result.list;
} else {
this.searchText = result.rspDesc;
}
this.show = true;
},
/**单击搜索结果 */
handelLookCar(item) {
this.carQuery.teamId = undefined;
this.carQuery.carIds = item.carId;
this.map.flyToPoint(
new mars3d.LngLatPoint(parseFloat(item.lng), parseFloat(item.lat))
);
this.createCar(true);
this.show = false;
},
/**
* 清除操作
*/
inputClear() {
if (this.timer) clearInterval(this.timer);
this.searchList = [];
this.searchText = "";
this.searchQuery = {
carPlate: undefined, //车牌
plateColor: undefined, //车辆颜色
};
this.carQuery = {
teamId: 2, //该参数表示获取指定车队下所有层级子车队的车辆定位该参数优先级别高于carIds参数,
carIds: "", //车辆id 多个用逗号分开优先级低于teamId
};
this.mapLayer.car.eachGraphic((graphic) => {
graphic.closeHighlight();
});
this.createCar();
this.show = false;
},
toggleSelection(item) {
// 切换选中状态
if (this.isSelected(item)) {
this.selectedItems = this.selectedItems.filter(
(selectedItem) => selectedItem !== item
);
} else {
this.selectedItems.push(item);
}
const active = this.selectedItems.toString();
if (this.time2) clearInterval(this.time2);
if (!active.includes("枪支")) {
//渲染枪支图标
this.createQ();
} else {
//清除枪支
this.mapLayer.qiang.clear();
}
if (this.selectedItems.length == 0) {
this.mapLayer.car.eachGraphic((graphic) => {
if (graphic.show) return;
graphic.show = true;
graphic.openPopup();
});
return;
}
this.mapLayer.car.eachGraphic((graphic) => {
let missionTetx =
graphic.attr.missionType == 1
? "营运线路"
: graphic.attr.missionType == 2
? "维护线路"
: "临时任务";
if (this.selectedItems.includes(missionTetx)) {
if (!graphic.show) return;
graphic.show = false;
graphic.closePopup();
} else {
if (graphic.show) return;
graphic.show = true;
graphic.openPopup();
}
});
},
isSelected(item) {
// 检查某个项是否被选中
return this.selectedItems.includes(item);
},
},
};
</script>
<style lang="scss" scoped>
.albuginea {
cursor: pointer;
position: absolute;
// top: 103px;
top: 15%;
// left: calc(554px + 24px);
left: 33%;
z-index: 100;
width: 80px;
height: 32px;
text-align: center;
line-height: 32px;
background: #032b57;
border-radius: 2px;
border: 1px solid #0084ff;
font-weight: 400;
font-size: 14px;
color: #ffffff;
}
.albuginea:hover {
background: #0084ff;
}
.input-search {
position: absolute;
// top: 103px;
top: 15%;
left: 50%;
transform: translateX(-50%);
z-index: 100;
.search-box {
position: relative;
display: flex;
align-items: center;
height: 32px;
.icon-close {
cursor: pointer;
position: absolute;
left: 260px;
font-size: 14px;
color: #0084ff;
}
}
.search-btn {
cursor: pointer;
line-height: 32px;
background: #0084ff;
color: #ffffff;
font-size: 14px;
padding: 0 10px;
height: 100%;
border-radius: 0 3px 3px 0;
}
input {
font-size: 14px;
width: 280px;
height: 100%;
border: 1px solid #0084ff;
border-right: 0;
background: #032b57;
padding-left: 6px;
color: #ffffff;
}
input::placeholder {
color: #7c91a8;
}
input:focus-visible {
outline: none;
}
.search-list {
position: relative;
width: 280px;
background: #032b57;
color: #fff;
border: 1px solid #0084ff;
border-top: 0;
min-height: 150px;
& > div {
cursor: pointer;
font-size: 14px;
padding: 10px;
}
& > div:hover {
background: #0084ff;
}
.no-data {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.no-data:hover {
background: transparent;
}
}
}
.video-list {
position: absolute;
bottom: 25px;
left: 50%;
transform: translateX(-50%);
z-index: 50;
padding: 10px;
display: flex;
align-items: center;
border: 1px solid #415367;
border-radius: 10px;
background: rgba(28, 31, 34, 0.6);
}
.multiple {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 100;
width: 880px;
height: 80px;
display: flex;
align-items: center;
justify-content: space-between;
background: url("../assets/images/multipleList.png");
background-size: 100% 100%;
padding: 0 180px;
.checkbox {
cursor: pointer;
width: 112px;
height: 32px;
line-height: 32px;
text-align: center;
font-size: 14px;
color: #ffffff;
background: linear-gradient(180deg, #072853 0%, #0079ff 100%);
border: 1px solid #0084ff;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
}
.checked {
opacity: 0.5;
}
.btn-icon {
width: 15px;
height: 16px;
margin-right: 10px;
}
}
</style>