1928 lines
52 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* @Author: SunTao 328867980@qq.com
* @Date: 2024-10-17 11:34:00
* @LastEditors: SunTao 328867980@qq.com
* @LastEditTime: 2024-12-04 09:28:41
* @FilePath: \znxjxt-ui\src\views\big-screen\index.vue
* @Description: 大屏首页
-->
<template>
<div class="screen-content">
<div class="screen-header">
<div class="header-weather">
<!-- <iframe
width="150"
scrolling="no"
height="45"
frameborder="0"
allowtransparency="true"
src="https://i.tianqi.com?c=code&id=12&icon=1&color=%2389C5E8&py=shenyang&num=1&site=12"
></iframe> -->
</div>
<div class="header-time">
<!-- 消息中心 -->
<div class="header-news">
<el-popover
placement="bottom-end"
width="400"
popper-class="screen-message-popover"
trigger="hover"
>
<div class="screen-message-content">
<div class="message-content">
<fssm-scroll>
<div
class="message-item"
v-for="(item, index) in messageList"
:key="`message-item-${index}`"
>
<div
class="item-top"
@click="handleMessageItemClick(item.status)"
>
<div class="index">
<i
v-if="item.title === '成功'"
style="color: #67c23a"
class="el-icon-success"
></i>
<i
v-if="item.title === '提醒'"
style="color: #e6a23c"
class="el-icon-info"
></i>
<i
v-if="item.title === '告警'"
style="color: #909399"
class="el-icon-warning"
></i>
<i
v-if="item.title === '错误'"
style="color: #f56c6c"
class="el-icon-error"
></i>
</div>
<div class="time">
<span>{{ item.time }}</span>
</div>
<div class="carNo">
<span>{{ item.car }}</span>
</div>
</div>
<div class="item-content">
{{ item.content }}
</div>
</div>
</fssm-scroll>
</div>
<div class="message-footer">
<el-button
@click="handleMessageClick"
icon="el-icon-d-arrow-right"
type="text"
>查看更多</el-button
>
</div>
</div>
<i slot="reference" class="el-icon-message-solid">
<div class="num">48</div>
</i>
</el-popover>
</div>
<div class="header-data">{{ dataTime }}</div>
<div class="header-week">
<span>{{ weekTime }}</span>
<span>{{ yearTime }}</span>
</div>
<div class="header-home">
<div class="home" @click="goIndex"></div>
</div>
</div>
</div>
<div class="screen-middle">
<div class="screen-left">
<module-block
v-for="(item, index) in leftModuleList"
:key="`left-module-list-${index}`"
:width="item.width"
:height="item.height"
:title="item.title"
:class="item.class"
>
<template
><component
:select="item.select"
:is="item.component"
:bottomTipClick="bottomTipClick"
></component
></template>
<template slot="operation" v-if="item.selectIsShow">
<el-radio-group class="screen-checkBox" v-model="item.select">
<el-radio-button
v-for="(item, index) in selectTypeArr"
:label="item.value"
:key="`left-screen-${index}`"
>{{ item.label }}</el-radio-button
>
</el-radio-group>
</template>
</module-block>
</div>
<div class="screen-right">
<module-block
v-for="(item, index) in rightModuleList"
:key="`right-module-list-${index}`"
:width="item.width"
:height="item.height"
:title="item.title"
:class="item.class"
>
<template
><component
:select="item.select"
:is="item.component"
:bottomTipClick="bottomTipClick"
@imagePoint="getimagePoint"
></component
></template>
<template slot="operation" v-if="item.selectIsShow">
<el-radio-group class="screen-checkBox" v-model="item.select">
<el-radio-button
v-for="(item, index) in selectTypeArr"
:label="item.value"
:key="`right-screen-${index}`"
>{{ item.label }}</el-radio-button
>
</el-radio-group>
</template>
</module-block>
</div>
<div class="road-content">
<!-- 地图右上角多选框切换坐标类型 -->
<div class="road-checkBox" v-if="showIconList">
<fssm-scroll class="road-scroll">
<el-checkbox-group v-model="iconType" @change="handleChecked">
<el-checkbox
v-for="(item, index) in iconTypeList"
:label="item.value"
:key="`check-${index}`"
>{{ item.label }}</el-checkbox
>
</el-checkbox-group>
</fssm-scroll>
</div>
<!-- 地图图例 -->
<div class="map-legend"></div>
<!-- 图片背景 -->
<div class="disease-content" v-if="elementDiv === 'OverviewScreen'">
<div class="disease-title"></div>
<!-- 图背景下选择框 -->
<div class="map-image-select">
病害类型筛选
<el-cascader
v-model="mapCareSelect"
popper-class="screen-index-cascader"
:options="dieaseOptions"
:props="{
checkStrictly: true,
emitPath: true,
children: 'subTypes',
}"
@change="getMapCare"
clearable
></el-cascader>
</div>
<div class="map-care">
<div
class="map-care-div"
:class="`map-care-div-${item.status}`"
v-for="(item, index) in mapCareList"
:key="`map-care-${index}`"
:style="{ left: item.left, top: item.top }"
>
<span>{{ item.name }}</span>
</div>
</div>
</div>
<!-- 地图 -->
<fssm-map
v-if="elementDiv !== 'OverviewScreen'"
ref="roadMap"
:showChange="true"
:controlStyle="{ top: '10%', left: '26%' }"
@feature-select="featureSelect"
@map-zoom="getZoom"
></fssm-map>
<!-- @map-moveend="mapMoveend" -->
</div>
</div>
<div class="screen-footer">
<!-- 病害巡检4种类型按钮 -->
<div class="footer-change-map">
<template v-if="elementDiv === 'DiseaseScreen'">
<div
class="change-map-div"
:class="bottomTipClick === item.click ? 'change-map-click' : ''"
v-for="(item, index) in changeMapBtn"
:key="`btn-${index}`"
@click="changeIconType(item.click)"
>
{{ item.name }}
</div>
</template>
</div>
<!-- 切换3种导航栏按钮 -->
<div class="footer-change-vue">
<div
:class="
elementDiv === item.component
? `change-vue-click-${item.component}`
: `change-vue-${item.component}`
"
v-for="(item, index) in elementList"
:key="`footer-${index}`"
@click="changeElement(item)"
></div>
</div>
</div>
<!-- 详情图片弹窗 -->
<el-dialog
:title="imgTitle"
:visible.sync="imgVisible"
width="95rem"
append-to-body
fullscreen
:close-on-click-modal="false"
destroy-on-close
@close="imgCancel"
>
<img-dialog
v-if="imgTitle === '查看'"
:imageItem="imageItem"
:bottomTipClick="bottomTipClick"
></img-dialog>
</el-dialog>
<!-- 查看点位图片弹窗 -->
<el-dialog
title="查看点位"
:visible.sync="showImageDialog"
width="90rem"
append-to-body
:close-on-click-modal="false"
destroy-on-close
@close="screenImgCancel"
>
<div class="view-image-container" ref="imageContainer">
<img
:src="screenImage.imageUrl"
alt="Main Image"
ref="mainImage"
@load="updateScreenRects"
/>
<div
v-for="(rect, index) in screenRects"
:key="index"
class="rect-overlay"
:style="getScreenRectStyle(rect)"
></div>
<div class="rect-image">
采集时间:
{{ screenImage.createTime }} 起始桩号
{{ screenImage.stakeStart || "暂无数据" }} 终止桩号
{{ screenImage.stakeEnd || "暂无数据" }}
{{ `${this.elementDiv === "RoadScreen" ? "路产" : "病害"}类型:` }}
{{ screenImage.iconTypeName || "暂无数据" }}
<span v-if="this.elementDiv === 'DiseaseScreen'">
病害面积{{ screenImage.targetArea }}平方米 病害长度{{
screenImage.targetLen
}}
</span>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
// 地图
import FssmMap from "@/components/map/fssm-map.vue";
import { Feature } from "ol";
import { Point } from "ol/geom";
import { Style, Icon, Fill, Stroke, Circle, Text } from "ol/style";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import * as geomExports from "ol/geom";
import Cluster from "ol/source/Cluster";
import logo from "@/assets/xc.png";
// 组件
import ModuleBlock from "./module-block.vue";
import TodayInspection from "./overview-components/today-inspection.vue";
import DiseaseTrends from "./overview-components/disease-trends.vue";
import DiseaseCurrent from "./overview-components/disease-current.vue";
import PatrolOrder from "./overview-components/patrol-order.vue";
import InspectionVehicles from "./overview-components/inspection-vehicles.vue";
import RoadStatistic from "./road-components/road-statistic.vue";
import ManageMaintain from "./road-components/manage-maintain.vue";
import AnomalyFacilities from "./road-components/anomaly-facilities";
import AncillaryFacilities from "./road-components/ancillary-facilities.vue";
import TrafficSafety from "./disease-components/traffic-safety.vue";
import TrafficTrend from "./disease-components/traffic-trend.vue";
import TrafficStatistic from "./disease-components/traffic-statistic.vue";
import TrafficLog from "./disease-components/traffic-log.vue";
import ImgDialog from "./components/img-dialog.vue";
import FssmScroll from "@/components/scroll/fssm-scroll.vue";
// 接口
import {
selectTypeList,
mapPointList,
mapPciList,
comppanyImg,
getItemTypes,
getRoadListTypes,
getDefectTypes,
} from "@/api/xj/screen/index";
export default {
name: "BigScreen",
components: {
FssmMap,
ModuleBlock,
TodayInspection,
DiseaseTrends,
DiseaseCurrent,
PatrolOrder,
InspectionVehicles,
RoadStatistic,
ManageMaintain,
AnomalyFacilities,
AncillaryFacilities,
TrafficSafety,
TrafficTrend,
TrafficStatistic,
ImgDialog,
FssmScroll,
TrafficLog,
},
data() {
return {
// 计时器标识
timeFlag: null,
// 时间
dataTime: "",
// 星期
weekTime: "",
// 年
yearTime: "",
// 预警中心消息数据
messageList: [],
// 数据栏右上角选择框
selectTypeArr: [],
// 左侧切换模块
leftModuleList: [
{
width: "100%",
height: "27%",
title: "今日巡查",
component: TodayInspection,
selectIsShow: false,
class: "one",
},
{
width: "100%",
height: "27%",
title: "主要病害趋势",
component: DiseaseTrends,
selectIsShow: false,
class: "twe",
},
{
width: "100%",
height: "29%",
title: "病害统计",
component: DiseaseCurrent,
selectIsShow: true,
select: "",
class: "twe",
},
],
// 右侧切换模块
rightModuleList: [
{
width: "100%",
height: "18%",
title: "巡查里程",
component: PatrolOrder,
selectIsShow: false,
class: "one",
},
{
width: "100%",
height: "65%",
title: "巡检车辆",
component: InspectionVehicles,
selectIsShow: false,
class: "twe",
},
],
// 图片背景下打点坐标数据
mapCareList: [],
// 具体icon类别
iconTypeList: [],
// icon类别绑定
iconType: [],
// 地图右上角多选显隐控制
showIconList: false,
// 图片背景下病害类型下拉选择绑定
mapCareSelect: "",
// 图片背景下病害类型下拉选择数据
dieaseOptions: [],
// 路段下拉绑定
roadList: [],
// 地图打点-路段绑定
roadSelect: "",
// 图标类别切换标识
bottomTipClick: "1",
// 切换地图图标类别按钮
changeMapBtn: [
{ name: "路面", click: "1" },
{ name: "交安", click: "2" },
{ name: "桥隧", click: "3" },
{ name: "绿化", click: "4" },
],
// 中间展示的动态组件绑定
elementDiv: "OverviewScreen",
// 下方三个按钮数据
elementList: [
{ name: "总览", component: "OverviewScreen" },
{ name: "病害巡检", component: "DiseaseScreen" },
{ name: "道路资产", component: "RoadScreen" },
],
// 中心点集合(全部)
centerPiont: [],
// 中心点集合(当前)
drawPointList: [],
// 点位图标map
mapLogeList: {},
// 线段点集合
lineString: [],
// 地图放大缩小层级
mapZoom: "",
// 聚合图层
clusters: null,
// 线段图层
markLayerLines: null,
// 图片弹窗标题
imgTitle: "查看",
// 图片弹窗显隐控制
imgVisible: false,
// 传图片弹窗数据
imageItem: {},
// 查看大图点位图片数据
screenImage: {},
// 查看大图点位图片弹窗显隐控制
showImageDialog: false,
// 查看大图点位图片弹窗红框数据
screenRects: [],
// 小车地图点位数据源
carMapPointSource: null,
// 小车地图点位数组
carPointList: [],
// 小车地图点位features数组
mapPointFeatures: [],
};
},
created() {
this.setTime();
this.getSelect();
this.getMapCare();
this.getRoadList();
this.getDieaseTypeList();
this.getMessageList();
this.handleMessage();
},
mounted() {},
methods: {
/**
* @description: 获取当前时间
* @return {*}
*/
setTime() {
this.timeFlag = setInterval(() => {
const weekMap = [
"星期天",
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
];
const date = new Date();
const year = date.getFullYear();
const month =
date.getMonth() + 1 < 10
? `0${date.getMonth() + 1}`
: date.getMonth() + 1;
const day = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate();
const hours =
date.getHours() < 10 ? `0${date.getHours()}` : date.getHours();
const minutes =
date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes();
const seconds =
date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds();
const week = date.getDay();
// this.currentTime = `${year}-${month}-${day}\t\t${hours}:${minutes}:${seconds}\t\t${weekMap[week]}`;
this.yearTime = `${year}.${month}.${day}`;
this.weekTime = `${weekMap[week]}`;
this.dataTime = `${hours}:${minutes}:${seconds}`;
}, 1000);
},
/**
* @description: 获取消息中心数据
* @return {void}
*/
getMessageList() {
// getMessageList().then(({ code, data }) => {
// if (code === 200) {
// this.messageList = data;
// }
// });
this.messageList = [
{
title: "成功",
status: "SUCCESS",
time: "2024/45/62",
car: "辽jskdn",
content: "骄傲的是否哈德half绝对符合卡的法拉第",
},
{
title: "告警",
status: "WARNING",
time: "2024/45/62",
car: "辽jskdn",
content: "骄傲的是否哈德half绝对符合卡的法拉第",
},
{
title: "提醒",
status: "REMIND",
time: "2024/45/62",
car: "辽jskdn",
content: "骄傲的是否哈德half绝对符合卡的法拉第",
},
];
},
/**
* @description: 消息中心点击具体数据事件
* @return {*}
*/
handleMessageItemClick(value) {
this.$router.push({
name: "Warning-center",
params: { title: value },
});
},
/**
* @description: 消息中心查看更多事件
* @return {*}
*/
handleMessageClick() {
this.$router.push("/inspection_warn/warning-center");
},
/**
* @description: 获取数据栏右上角选项数据
* @return {void}
*/
getSelect() {
selectTypeList().then(({ code, data }) => {
if (code === 200) {
this.selectTypeArr = data;
}
});
},
/**
* @description: 获取路段下拉数据
* @return {void}
*/
getRoadList() {
getRoadListTypes().then(({ code, data }) => {
if (code === 200) {
this.roadList = data;
}
});
},
/**
* @description: 获取图片背景左上角病害类型下拉
* @return {void}
*/
getDieaseTypeList() {
getDefectTypes().then(({ code, data }) => {
if (code === 200) {
this.dieaseOptions = data;
}
});
},
/**
* @description: 获取图片背景下坐标数据
* @return {void}
*/
getMapCare(value) {
const data = {
classType: value ? value[0] : "",
type: value ? (value.length > 1 ? value[1] : "") : "",
};
comppanyImg(data).then(({ code, data }) => {
if (code === 200) {
this.mapCareList = data;
}
});
},
/**
* @description: 点击病害日志详情打开弹窗进行地图打点
* @return {void}
*/
getimagePoint(item) {
this.imgTitle = "查看";
this.imageItem = item;
this.imgVisible = true;
// 地图右上角多选按钮显示
this.getIconType();
this.showIconList = true;
// 地图打点\改变地图层级
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.getView().setCenter(item.tablePoint);
map.getView().setZoom(16);
});
this.roadSelect = item.segmentId;
this.getCenterPiont();
},
/**
* @description: 关闭图片查看弹窗
* @return {void}
*/
imgCancel() {
this.imgTitle = "";
this.imageItem = {};
this.imgVisible = false;
},
/**
* @description: 关闭查看点位大图弹窗
* @return {void}
*/
screenImgCancel() {
this.$refs.roadMap.removeSelectClick();
this.showImageDialog = false;
},
/**
* @description: 切换icon类型多选框事件
* @return {void}
*/
handleChecked(value) {
this.centerPiont = this.drawPointList.filter(
(item) => value.indexOf(item.iconType) > -1
);
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.removeLayer(this.clusters);
this.clusters = null;
this.drawPoint();
});
},
/**
* @description: 获取地图点位信息
* @return {void}
*/
getCenterPiont() {
// 如果当前已经有打点坐标
if (this.clusters) {
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.removeLayer(this.clusters);
this.clusters = null;
});
}
mapPointList({
type: this.elementDiv,
classType: this.bottomTipClick,
segmentId: this.roadSelect,
}).then(({ code, data }) => {
if (code === 200) {
this.drawPointList = data.map((item) => {
if (item.geometry) {
return {
...item,
geometry: [item.geometry[0], item.geometry[1]],
};
}
return [];
});
this.centerPiont = data.map((item) => {
if (item.geometry) {
return {
...item,
geometry: [item.geometry[0], item.geometry[1]],
};
}
return [];
});
// 如果不是病害巡检,则绘制点位
// 如果图片弹窗打开,则绘制点位
if (this.elementDiv !== "DiseaseScreen" || this.imgVisible) {
this.drawPoint();
}
}
});
},
/**
* @description: 绘制地图点位
* @return {void}
*/
drawPoint() {
const features = [];
this.centerPiont.forEach((element) => {
// 修改坐标样式
const point = new Point(element.geometry);
const feature = new Feature({
geometry: point,
data: element,
// 自己设置一个标识
type: "icon",
});
features.push(feature);
});
const clusterSource = new Cluster({
distance: this.mapZoom > 15 ? 0 : 100,
minDistance: this.mapZoom > 15 ? 0 : 100,
source: new VectorSource({
features,
}),
type: "Cluster",
});
this.clusters = new VectorLayer({
source: clusterSource,
name: "clusterLayer",
zIndex: 10,
style: (feature) => {
const count = feature.get("features").length;
if (count > 1) {
return new Style({
image: new Icon({
crossOrigin: "anonymous",
src: require(`@/assets/screen/index/龟裂.png`),
// 图标缩放比例
scale: 0.6,
displacement: [0, 30],
// 0.3为30度
// rotation: 0.3,
}),
text: new Text({
textAlign: "center", //位置
textBaseline: "middle",
font: "normal 14px 微软雅黑",
offsetY: -50,
fill: new Fill({
color: "#ffffff",
}),
text: count.toString(),
}),
});
} else {
return new Style({
image: new Icon({
crossOrigin: "anonymous",
src: require(`@/assets/screen/index/${
this.mapLogeList[
feature.getProperties().features[0].get("data").iconType
]
}.png`),
// 图标缩放比例
scale: 0.6,
displacement: [0, 30],
// 0.3为30度
// rotation: 0.3,
}),
text: new Text({
textAlign: "center", //位置
textBaseline: "middle",
font: "normal 14px 微软雅黑",
offsetY: -50,
fill: new Fill({
color: "#ffffff",
}),
text: "",
}),
});
}
},
});
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.addLayer(this.clusters);
});
},
/**
* @description: 获取地图线段点位信息
* @return {void}
*/
getLinePoint() {
if (!this.markLayerLines) {
mapPciList().then(({ code, data }) => {
if (code === 200) {
this.lineString = data.filter((item) => item.coordinates !== null);
this.drawLine();
}
});
}
},
/**
* @description: 绘制地图线段
* @return {void}
*/
drawLine() {
const features = [];
this.lineString.forEach((element) => {
const lines = element?.coordinates?.split(";")?.map((it) => {
return it.split(",").map(Number);
});
const line = new Feature({
geometry: new geomExports.LineString(lines),
type: "line",
});
line.setStyle([
new Style({
// 填充色
fill: new Fill({
color: "red",
}),
// 边线颜色
stroke: new Stroke({
color: this.getLineColor(element.pci),
width: 5,
}),
// 形状
image: new Circle({
radius: 17,
fill: new Fill({
color: "#ffffff",
}),
}),
// text: new Text({
// text: "121454",
// color: "#ffffff",
// textAlign: "center", //位置
// textBaseline: "middle",
// offsetY: 0,
// fill: new Fill({
// color: "#ffffff",
// }),
// }),
}),
]);
features.push(line);
});
const lineSource = new VectorSource({
features,
});
this.markLayerLines = new VectorLayer({
source: lineSource,
properties: {
type: "line",
},
});
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.addLayer(this.markLayerLines);
});
},
/**
* @description: 地图线段颜色区分
* @param {number} value
* @return {string}
*/
getLineColor(value) {
if (value > 92) {
return "#0ABE67";
} else if (92 >= value > 80) {
return "#03BDE7";
} else if (80 >= value > 70) {
return "#E7CA03";
} else if (70 >= value > 60) {
return "#D47F07";
} else {
return "#E64548";
}
},
/**
* @description: 地图下方4图标类别切换点击事件
* @param {string} value
* @return {void}
*/
changeIconType(value) {
if (this.bottomTipClick !== value) {
this.bottomTipClick = value;
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.removeLayer(this.clusters);
this.clusters = null;
// map.getView().setZoom(10);
// map.getView().setCenter([123.30297096718999, 41.87942945541742]);
});
// 地图右上角多选按钮隐藏
this.showIconList = false;
// this.getIconType();
// this.getCenterPiont();
}
},
/**
* @description: 获取icon多选数据
* @return {void}
*/
getIconType() {
this.mapLogeList = {};
getItemTypes({
classType: this.bottomTipClick,
type: this.elementDiv,
}).then(({ code, data }) => {
if (code === 200) {
this.iconTypeList = data;
this.iconType = data.map((item) => {
return item.value;
});
data.forEach((item) => {
this.mapLogeList[item.value] = item.label;
});
}
});
},
/**
* @description: 传回来的地图图层
* @param {number} zoom
* @return {void}
*/
getZoom(zoom) {
this.mapZoom = zoom;
if (this.clusters && zoom * 1 > 15) {
this.clusters.getSource().setDistance(0);
} else if (this.clusters && zoom * 1 <= 15) {
this.clusters.getSource().setDistance(100);
}
},
/**
* @description: 地图选中feature事件
* @param {object} e
* @return {void}
*/
featureSelect(e) {
const map = this.$refs.roadMap.instance.get("map");
const selectedFeatures = e.selected;
if (selectedFeatures.length > 0) {
let feature = selectedFeatures[0];
let features = feature.get("features");
// 点击线段事件
if (feature.getProperties().type === "line") {
console.log(feature, "线段参数");
} else if (feature.getProperties().type === "carPoint") {
console.log(feature, "小车点位");
} else {
if (features.length === 1) {
// 单个点位
// 执行之前的业务逻辑
// 获取点击的图层信息
const selectFeature = feature.getProperties().features[0];
console.log(selectFeature, "点位");
// 获取点位数据
this.screenImage = selectFeature.get("data");
this.showImageDialog = true;
// console.log(selectFeature.get("data"));
} else {
// 聚合点
// 放大地图层级
map.getView().animate({
center: feature.getGeometry().getCoordinates(),
zoom: map.getView().getZoom() + 1,
});
}
}
}
},
/**
* @description: 数据栏切换事件
* @param {object} item
* @return {void}
*/
changeElement(item) {
if (this.elementDiv !== item) {
this.elementDiv = item.component;
this.roadSelect = "";
if (item.component === "OverviewScreen") {
/* 清空线段图层 */
this.markLayerLines = null;
this.leftModuleList = [
{
width: "100%",
height: "27%",
title: "今日巡查",
component: TodayInspection,
selectIsShow: false,
class: "one",
},
{
width: "100%",
height: "27%",
title: "病害趋势",
component: DiseaseTrends,
selectIsShow: false,
class: "twe",
},
{
width: "100%",
height: "29%",
title: "病害统计",
component: DiseaseCurrent,
selectIsShow: true,
select: "",
class: "twe",
},
];
this.rightModuleList = [
{
width: "100%",
height: "18%",
title: "巡查里程",
component: PatrolOrder,
selectIsShow: false,
class: "one",
},
{
width: "100%",
height: "65%",
title: "巡检车辆",
component: InspectionVehicles,
selectIsShow: false,
class: "twe",
},
];
// 不接收小车位置消息
const data = { type: "carLocation", status: false };
this.$ws.send(data);
this.carPointList = [];
this.mapPointFeatures = [];
// 地图右上角多选按钮隐藏
this.showIconList = false;
// 图层恢复
this.mapZoom = "";
} else if (item.component === "RoadScreen") {
this.leftModuleList = [
{
width: "100%",
height: "17%",
title: "管养道路统计",
component: ManageMaintain,
selectIsShow: false,
class: "one",
},
{
width: "100%",
height: "55%",
title: "附属设施分布",
component: AncillaryFacilities,
selectIsShow: false,
class: "twe",
},
];
this.rightModuleList = [
{
width: "100%",
height: "29%",
title: "附属设施异常统计",
component: AnomalyFacilities,
selectIsShow: true,
select: "",
class: "one",
},
{
width: "100%",
height: "57%",
title: "路产统计",
component: RoadStatistic,
selectIsShow: true,
select: "",
class: "twe",
},
];
// 发送小车位置消息
const data = { type: "carLocation", status: true };
this.$ws.send(data);
// 将地图层级初始化
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.getView().setZoom(10);
map.getView().setCenter([123.30297096718999, 41.87942945541742]);
});
// 地图右上角多选按钮显示
this.getIconType();
this.showIconList = true;
// 进行地图打点
this.getCenterPiont();
this.getLinePoint();
} else if (item.component === "DiseaseScreen") {
this.leftModuleList = [
{
width: "100%",
height: "27%",
title: "今日巡查",
component: TrafficSafety,
selectIsShow: false,
class: "one",
},
{
width: "100%",
height: "27%",
title: "主要病害趋势",
component: TrafficTrend,
selectIsShow: true,
class: "twe",
},
{
width: "100%",
height: "33%",
title: "病害统计",
component: TrafficStatistic,
selectIsShow: true,
select: "",
class: "twe",
},
];
this.rightModuleList = [
{
width: "100%",
height: "85%",
title: "病害日志",
component: TrafficLog,
selectIsShow: false,
select: "",
class: "one",
},
];
// 发送小车位置消息
const data = { type: "carLocation", status: true };
this.$ws.send(data);
// 地图右上角多选按钮隐藏
this.showIconList = false;
// 图层恢复
this.mapZoom = "";
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.removeLayer(this.clusters);
this.clusters = null;
map.getView().setZoom(10);
map.getView().setCenter([123.30297096718999, 41.87942945541742]);
});
this.getLinePoint();
}
}
},
/**
* @description: 处理websocket消息
* @return {*}
*/
handleMessage() {
this.$ws.on("message", (itemMessage) => {
if (itemMessage.type === "carPosition") {
if (this.carPointList.includes(itemMessage.data.entityId)) {
// 获取当前位置和目标位置
this.carMapPointSource.getFeatures().forEach((item) => {
if (item.get("data") === itemMessage.data.entityId) {
const currentLocation = item.getGeometry().getCoordinates();
const targetLocation = itemMessage.data.location;
// 计算两点之间的差值
const dx =
(targetLocation[0] * 1 - currentLocation[0] * 1) / 100;
const dy =
(targetLocation[1] * 1 - currentLocation[1] * 1) / 100;
// 设置计数器
let count = 0;
// 创建定时器,每10ms移动一次,总共移动100次,约1秒完成
const timer = setInterval(() => {
count++;
if (count >= 100) {
clearInterval(timer);
return;
}
// 计算当前帧的位置
const x = currentLocation[0] * 1 + dx * count;
const y = currentLocation[1] * 1 + dy * count;
// 更新小车位置
// const [features] = this.carMapPointSource.getFeatures();
item.setGeometry(new Point([x, y]));
item.setStyle([
new Style({
image: new Icon({
crossOrigin: "anonymous",
src: logo,
// 图标缩放比例
scale: 0.04,
// 将角度转换为弧度,并除以180*π
rotation:
(itemMessage.data.direction - 90) * (Math.PI / 180),
}),
}),
]);
}, 10);
}
});
} else {
this.carPointList.push(itemMessage.data.entityId);
this.drawCarMapPoint(itemMessage.data);
}
}
});
},
/**
* @description: 绘制小车地图点位
* @param {object} item
* @return {void}
*/
drawCarMapPoint(item) {
// const features = [];
const feature = new Feature({
geometry: new Point(item.location),
data: item.entityId,
type: "carPoint",
});
// 可以给点位设置样式
feature.setStyle([
new Style({
image: new Icon({
crossOrigin: "anonymous",
src: logo,
// 图标缩放比例
scale: 0.03,
// 将角度转换为弧度,并除以180*π
rotation: item.direction * (Math.PI / 180),
}),
}),
]);
this.mapPointFeatures.push(feature);
this.carMapPointSource = new VectorSource({
features: this.mapPointFeatures,
});
const carMapPointLayer = new VectorLayer({
source: this.carMapPointSource,
properties: {
type: "carPoint",
},
});
this.$nextTick(() => {
const map = this.$refs.roadMap.instance.get("map");
map.addLayer(carMapPointLayer);
});
},
/**
* @description: 跳转系统首页
* @return {void}
*/
goIndex() {
this.$router.push("/index");
},
/**
* @description: 图片位置信息获取
* @return {void}
*/
updateScreenRects() {
1;
this.screenRects = [];
const image = this.$refs.mainImage;
const rects = this.screenImage?.rect?.split(",").map(Number) || [];
this.screenRects = [
{
left: rects[0],
top: rects[1],
width: rects[2],
height: rects[3],
},
];
},
/**
* @description: 图片红框位置
* @param {object} left
* @param {object} top
* @param {object} width
* @param {object} height
* @return {object}
*/
getScreenRectStyle({ left, top, width, height }) {
const image = this.$refs.mainImage;
const container = this.$refs.imageContainer;
if (!image || !container) return {};
const scaleX = container.clientWidth / image.naturalWidth;
const scaleY = container.clientHeight / image.naturalHeight;
const scale = Math.min(scaleX, scaleY);
const renderedWidth = image.naturalWidth * scale;
const renderedHeight = image.naturalHeight * scale;
const offsetX = (container.clientWidth - renderedWidth) / 2;
const offsetY = (container.clientHeight - renderedHeight) / 2;
return {
position: "absolute",
left: `${left * scale + offsetX}px`,
top: `${top * scale + offsetY}px`,
width: `${width * scale}px`,
height: `${height * scale}px`,
border: "2px solid #FF0000",
boxSizing: "border-box",
};
},
},
beforeDestroy() {
clearInterval(this.timeFlag);
// 发送停止接收小车位置
const data = { type: "carLocation", status: false };
this.$ws.send(data);
},
};
</script>
<style lang="scss" scoped>
.screen-content {
width: 100%;
height: 100%;
}
// 中间样式
.screen-middle {
width: 100%;
height: 100%;
.screen-left {
width: 25.5%;
height: calc(100% - 5rem);
padding-left: 3.5rem;
position: fixed;
top: 5rem;
z-index: 1;
background-image: url("../../assets/screen/index/bg-left.png");
background-repeat: no-repeat;
background-size: 100% 100%;
::v-deep .screen-checkBox {
.el-radio-button__inner {
background-color: transparent;
padding: 0 0.3rem;
border: none;
}
.el-radio-button__orig-radio:checked + .el-radio-button__inner {
color: #1cb6ff;
}
}
}
.screen-right {
width: 25.5%;
height: calc(100% - 5rem);
top: 5rem;
padding-right: 3.5rem;
position: fixed;
right: 0;
z-index: 1;
background-image: url("../../assets/screen/index/bg-right.png");
background-repeat: no-repeat;
background-size: 100% 100%;
::v-deep .screen-checkBox {
.el-radio-button__inner {
background-color: transparent;
padding: 0 0.3rem;
border: none;
}
.el-radio-button__orig-radio:checked + .el-radio-button__inner {
color: #1cb6ff;
}
}
}
.road-content {
width: 100%;
height: 100%;
position: relative;
// 图例
.map-legend {
height: 7rem;
width: 2rem;
position: absolute;
top: 17%;
left: 26%;
z-index: 1;
background-image: url("../../assets/screen/index/map-legend.png");
background-repeat: no-repeat;
background-size: 100% 100%;
}
// 右上角切换图标样式多选框
.road-checkBox {
width: 8rem;
height: 10rem;
position: absolute;
right: 26%;
top: 10%;
padding: 0.4rem;
border-radius: 0.4rem;
border: 1px solid #193dae;
background-color: #082843;
z-index: 1;
.road-scroll {
overflow-x: hidden;
}
::v-deep .el-checkbox__label {
color: #9aadd8;
}
}
// 图片背景样式
.disease-content {
width: 100%;
height: 100%;
background-image: url("../../assets/screen/index/map-liaoning.jpg");
background-repeat: no-repeat;
background-size: 100% 100%;
position: relative;
// 标题
.disease-title {
width: 20rem;
height: 2.8rem;
position: absolute;
// top: 5rem;
left: 50%;
transform: translate(-50%, 5rem);
background-image: url("../../assets/screen/index/disease-title.png");
background-repeat: no-repeat;
background-size: 100%;
}
// 筛选病害类型下拉
.map-image-select {
left: 28%;
top: 10%;
position: absolute;
color: #ffffff;
}
// 打点部分
.map-care {
width: 48%;
height: 73%;
position: absolute;
left: 26%;
top: 13%;
.map-care-div {
height: 8.5rem;
min-width: 3.5rem;
display: flex;
justify-content: center;
line-height: 1.6rem;
font-size: 0.7rem;
color: #ffffff;
position: absolute;
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: 50%;
span {
height: 1rem;
}
}
.map-care-div-1 {
background-image: url("../../assets/screen/index/map-care-div-1.png");
}
.map-care-div-2 {
background-image: url("../../assets/screen/index/map-care-div-2.png");
}
.map-care-div-3 {
background-image: url("../../assets/screen/index/map-care-div-3.png");
}
.map-care-div-4 {
background-image: url("../../assets/screen/index/map-care-div-4.png");
}
.map-care-div-5 {
background-image: url("../../assets/screen/index/map-care-div-5.png");
}
.map-care-div-6 {
background-image: url("../../assets/screen/index/map-care-div-6.png");
}
}
}
::v-deep .baseLayerClass {
filter: grayscale(200%) invert(200%) sepia(50%) hue-rotate(175deg)
brightness(80%) saturate(550%);
}
}
}
// 头部样式
.screen-header {
width: 100%;
height: 5rem;
padding: 1rem 3rem;
position: fixed;
top: 0;
display: flex;
justify-content: space-between;
z-index: 1;
background-image: url("../../assets/screen/index/bg-top.png");
background-repeat: no-repeat;
background-size: 100% 120%;
background-position-x: 50%;
.header-weather {
display: flex;
align-items: flex-end;
font-size: 1rem;
color: #89c5e8;
}
.header-time {
display: flex;
color: #89c5e8;
> div {
margin: 0 0.5rem;
display: flex;
align-items: flex-end;
}
// 消息中心样式
.header-news {
i {
position: relative;
cursor: pointer;
font-size: 1.5rem;
.num {
min-width: 0.9rem;
position: absolute;
top: -0.2rem;
right: -0.5rem;
padding: 0.2rem;
font-size: 0.6rem;
border-radius: 0.5rem;
color: #ffffff;
background-color: red;
}
}
}
.header-data {
font-size: 1.8rem;
}
.header-week {
display: flex;
align-items: flex-start;
justify-content: flex-end;
flex-direction: column;
}
.header-home {
.home {
cursor: pointer;
height: 1.5rem;
width: 1.2rem;
background-image: url("../../assets/screen/index/exit.png");
background-repeat: no-repeat;
background-size: 100%;
}
}
}
}
// 大屏下方样式
.screen-footer {
width: 49%;
height: 7.55rem;
position: fixed;
bottom: 0;
left: 25.5%;
background-image: url("../../assets/screen/index/bg-foot.png");
background-repeat: no-repeat;
background-size: 100.1% 99%;
.footer-change-map {
width: 100%;
height: 40%;
display: flex;
justify-content: center;
align-items: center;
color: #8deeff;
font-style: italic;
font-size: 0.7rem;
.change-map-div {
cursor: pointer;
margin: 0 2rem;
}
.change-map-click {
color: #fffed2;
}
}
.footer-change-vue {
width: 100%;
height: 60%;
display: flex;
justify-content: center;
align-items: center;
> div {
height: 100%;
width: 37.5%;
}
> div:nth-child(2) {
height: 100%;
width: 25%;
}
// 未点击样式
.change-vue-OverviewScreen {
background-image: url("../../assets//screen/index/button-overview.png");
background-repeat: no-repeat;
background-size: 95% 60%;
background-position: 75% 15%;
}
.change-vue-click-OverviewScreen {
background-image: url("../../assets//screen/index/button-overview-click.png");
background-repeat: no-repeat;
background-size: 95% 60%;
background-position: 75% 15%;
}
.change-vue-DiseaseScreen {
background-image: url("../../assets//screen/index/button-disease.png");
background-repeat: no-repeat;
background-size: 99% 60%;
background-position: 50% 13%;
}
.change-vue-click-DiseaseScreen {
background-image: url("../../assets//screen/index/button-disease-click.png");
background-repeat: no-repeat;
background-size: 99% 60%;
background-position: 50% 13%;
}
.change-vue-RoadScreen {
background-image: url("../../assets//screen/index/button-road.png");
background-repeat: no-repeat;
background-size: 93% 60%;
background-position: 15% 15%;
}
.change-vue-click-RoadScreen {
background-image: url("../../assets//screen/index/button-road-click.png");
background-repeat: no-repeat;
background-size: 93% 60%;
background-position: 15% 15%;
}
// .change-vue-click {
// color: red;
// }
}
}
/* 修改弹窗样式 */
::v-deep .el-dialog {
background-color: transparent;
}
::v-deep .el-dialog__header {
padding: 10px;
background-color: #113463;
span,
i {
color: #ffffff;
}
}
::v-deep .el-dialog__body {
padding: 0;
background-color: #113463;
/* 查看点位大图弹窗 */
.view-image-container {
position: relative;
width: 100%;
height: 80%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
}
.view-image-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.rect-overlay {
position: absolute;
// pointer-events: none;
border: 2px solid red;
}
}
// 图片信息
.rect-image {
width: 80%;
position: absolute;
top: 0;
font-size: 1.2rem;
color: #ffffff;
background-color: rgba(0, 0, 0, 0.5);
}
// 大屏下拉框样式
::v-deep .el-select {
width: 6.5rem;
.el-input .el-select__caret {
line-height: 1.5rem;
}
.el-input--medium .el-input__inner {
height: 1.5rem;
background-color: transparent;
color: #89c5e8;
border-color: #6991cd;
}
.el-select-dropdown {
background-color: #102649;
border-color: #08204f;
.el-scrollbar {
.el-select-dropdown__wrap {
.el-scrollbar__view {
.el-select-dropdown__item {
color: #aaabb8;
}
.el-select-dropdown__item:hover {
background-color: #2b4c7e;
}
.el-select-dropdown__item.selected {
background-color: #2b4c7e;
}
.el-select-dropdown__item.hover {
background-color: #2b4c7e;
}
}
.el-select-dropdown__list {
background-color: #102649;
}
}
}
}
}
// 修改级联样式
::v-deep .el-cascader {
width: 8rem;
.el-input--medium .el-input__inner {
height: 1.5rem;
background-color: transparent;
color: #89c5e8;
border-color: #6991cd;
}
}
</style>
<style lang="scss">
.screen-index-cascader {
background-color: #102649;
border-color: #08204f;
.el-cascader-node__label {
color: #aaabb8;
}
.el-cascader-node:hover {
background-color: #2b4c7e;
}
.el-cascader-node:active {
background-color: #2b4c7e;
}
.el-cascader-node:focus {
background-color: #2b4c7e;
}
}
// 大屏消息弹出框样式
.screen-message-popover {
background-color: rgba(0, 0, 0, 0.8);
border: none;
.screen-message-content {
width: 100%;
color: #ffffff;
.message-content {
width: 100%;
height: 12rem;
.message-item {
padding: 0.5rem 0;
border-bottom: 1px dashed rgb(115, 115, 116);
.item-top {
width: 100%;
display: flex;
&:hover {
span {
color: rgb(113, 179, 255);
}
}
.time {
width: 40%;
}
}
.item-content {
padding-left: 1rem;
}
}
}
.message-footer {
display: flex;
justify-content: flex-end;
}
}
}
</style>