Commit 70b22b83 authored by 纪泽龙's avatar 纪泽龙

第二个页面完成

parent 7a99569c
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2026-01-04 10:42:29
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2026-01-09 15:21:25
* @FilePath: /huaxindd-web/public/index.html
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="">
<head>
<meta charset="utf-8"> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta charset="utf-8">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= htmlWebpackPlugin.options.title %></title> <meta name="viewport" content="width=device-width,initial-scale=1.0">
</head> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<body> <script
<noscript> src="https://webapi.amap.com/maps?v=2.0&key=49fcb156d466062435d7d33437099582&plugin=Map3D,AMap.DistrictSearch,AMap.Scale,AMap.OverView,AMap.ToolBar,AMap.MouseTool,AMap.ControlBar,AMap.CircleEditor,AMap.PolyEditor"></script>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> <title>
<div id="app"></div> <%= htmlWebpackPlugin.options.title %>
<!-- built files will be auto injected --> </title>
</body>
</html> </head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
\ No newline at end of file
/*
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2026-01-04 09:01:34
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2026-01-09 15:29:34
* @FilePath: /huaxindd-web/src/utils/deviceIconTypeConfig.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
//设备类型
export const deviceType = {
"regulatorBox": 1,
"valve": 2,
"station": 3,
"monitorDeviceAlarm": 4
}
//设备图标
export const deviceIcon = {
// 1: require("@/assets/indexImg/mapTyx.png"),
// 2: require("@/assets/indexImg/mapFmj.png"),
// 3: require("@/assets/indexImg/mapCz.png"),
// 4: require("@/assets/indexImg/monitorDeviceAlarm.gif")
}
export const pipeColor = {
1: "#2EE7E7",
2: "#FFFFFF",
3: "#18FF0F",
4: "#DE67FA",
// 运行监控-巡检巡查的线条颜色
5: "#1890FF",
};
/*
* @Author: your name
* @Date: 2022-01-11 13:45:12
* @LastEditTime: 2023-10-13 15:32:17
* @LastEditors: 纪泽龙 jizelong@qq.com
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @FilePath: /test/hello-world/src/utils/mapClass.js
*/
// import { pipeColor, svgUrl, svgAlarm } from "@/utils/mapClass/config.js";
// 编辑类
// 在地图上新增的设备可以直接编辑,
// 已经保存完成的设备需要点编辑才可以编辑
export class EditorMap {
// 地图的对象实例
map = null;
// 外部传进来的中心店
center = null;
// 父vue的实例
vue = null;
// 操作 新建,编辑,删除,编辑跟删除只对已经在图上的设备有效 默认值:0, 新建:1,编辑:2, 删除: 3。
// 新建的时候会把未保存的线条清空
control = 0;
// 鼠标事件对象,用来将点跟线上图
mousetool = null;
// 当前正在手动绘制的对象
nowMouseTarget = null;
// 当线mousetool线被按下的时候的flag 当线被按下的时候为true,就不询问是否删除了
mosueToolPolineDownFlag = false;
// 绘制marer的时候的配置,在绘制完挂载事件的时候需要使用
mouseToolMarkerOptions = null;
// 绘制poline的时候的配置,在绘制完挂载事件的时候需要使用
mouseToolPolineOptions = null;
// 存放设备图标的对象,需要new的时候传进来
devicePicData = {};
pipeColor={};
// 存放所有的设备的数组集合,这是一个对象,对象里面是各种设备的数组
allDevice = {};
// 存放所有的管道
pipeArr = {};
// 报警设备的对象
alarmObj = {};
// 当前的infowindow的组件
infowindowComponent = null;
// infowindow本身
infowindow = null;
constructor(contaienr, config = {}, vue) {
this.map = new AMap.Map(contaienr, {
viewMode: "3D",
center: [114.196007, 38.260288],
layers: [AMap.createDefaultLayer()], // layers 字段为空或者不赋值将会自动创建默认底图。
zoom: 1,
zooms: [3, 20],
...config,
});
const { center } = config;
this.center = center;
this.vue = vue;
// 将从外部传进来的图片路径挂载到对象中
this.devicePicData = config.devicePicData || {};
this.pipeColor = config.pipeColor || {};
// console.log(this.devicePicData);
this.init();
}
init() {
// 地图事件
this.mapEvent();
// 手动点线上图准备,编辑模式
this.mouseAddDevice();
// this.mouseAddMarker();
// this.mouseAddPipeline();
// 地图边界
this.map.getCity((res) => {
const district = res.district;
// console.log("citycitycitycitycitycitycitycitycitycitycitycity", res);
this.mapBound(district);
}, this.center);
window.getCenter = () => {
console.log(this.map.getCenter());
};
}
mapBound(city) {
var district = new AMap.DistrictSearch({
extensions: "all", // 返回行政区边界坐标等具体信息
level: "city", // 设置查询行政区级别为 区
});
district.search(city, (status, result) => {
// 获取朝阳区的边界信息
var bounds = result.districtList[0].boundaries;
var polygons = [];
// console.log("boundsboundsboundsboundsbounds", bounds);
// console.log("boundsboundsboundsboundsbounds", result);
if (bounds) {
for (var i = 0, l = bounds.length; i < l; i++) {
//生成行政区划polygon
// new AMap.Polygon({
// map: this.map,
// strokeWeight: 2,
// path: bounds[i],
// fillOpacity: 1,
// fillColor: "transparent",
// strokeColor: "#09f",
// });
new AMap.Polyline({
map: this.map,
strokeWeight: 4,
strokeColor: "#09f",
path: bounds[i],
});
// polygons.push(polygon);
}
}
});
}
// map的事件监听
mapEvent() {
this.map.on("click", () => {
// mousetool对象画出的对象的操作
// 如果有手动绘制对象,要手动清楚一下,因为画线的时候不好清除旧线,这其实是用来清楚旧线的
// 当画出来的线被mousedown,不删除,但是mouseToolPipeLineFlag要归位,在移出线的时候统一归位
// 如果对象是marker,直接删除
if (this.nowMouseTarget?.type == "AMap.Marker") {
this.mouseToolDrawClear();
} else {
// 当地图上已经画了线,并且没有点在线上,询问是否删除
if (this.nowMouseTarget && !this.mosueToolPolineDownFlag) {
this.confirm("是否重新绘制管道", { type: "warning" })
.then(() => {
// 删除原来的线
this.mouseToolDrawClear();
// 鼠标事件开启,并且赋值原来的属性,this.mouseToolMarkerOptions是开启绘制的时候记录的
this.mousetool.polyline(this.mouseToolPolineOptions);
})
.catch(() => {});
}
}
});
this.map.on("moveend", () => {
console.log("地图停止移动");
if (this.flag) {
console.log("弹框");
this.flag = false;
}
});
// this.map.on('zoomchange', () => {
// //获取当前最新的地图层级
// let Zoom = this.map.getZoom()
// /**
// * 地图层级发生改变后操作
// * */
// console.log(Zoom);
// })
window.panTo = () => {
this.flag = true;
this.map.panTo([116.428285, 39.886129]);
};
}
// 弹框工具
confirm(message, obj) {
return this.vue.$confirm(message, obj);
}
// 改变操作状态
changeControl(num) {
this.control = num;
}
// 点线编辑上图准备
mouseAddDevice() {
this.map.plugin(["AMap.MouseTool"], () => {
this.mousetool = new AMap.MouseTool(this.map);
});
setTimeout(() => {
this.mouseDrawEvent();
}, 2000);
// 挂载绘制结束的事件
}
// 点或者线上图结束后触发的事件
mouseDrawEvent() {
this.mousetool.on("draw", (e) => {
const target = e.obj;
// console.log([target._position.lng, target._position.lat]);
const { type: targetType } = target;
// 当这个点是marker的时候
if (targetType == "AMap.Marker") {
this.mouseToolMarkerEvent(target);
} else {
// 如果是线,挂上编辑
this.lineEditor(target);
this.mousetool.close();
this.mouseToolPolineEvent(target);
console.log(targetType, "当前对象是管道");
}
this.nowMouseTarget = target;
});
}
// 绘制marker结束后,在marker身上添加的事件
mouseToolMarkerEvent(target) {
// 由于画出来的marker点击会换位置,所以当移入的时候删除绘制事件,移出去在增加绘制事件
target.on("mouseover", (e) => {
// 鼠标事件关闭
this.mousetool.close(false);
});
target.on("mouseout", (e) => {
// 这里不方便获取原来的属性,因为position不好解决,还是设置一个值吧
// 鼠标事件开启,并且赋值原来的属性,this.mouseToolMarkerOptions是开启绘制的时候记录的
this.mousetool.marker(this.mouseToolMarkerOptions);
});
// 点
target.on("click", (e) => {
// 弹框
});
}
// 挂上线以及线的事件
lineEditor(line) {
// line.editor && line.editor.close();
// 当前点击次数,1次为编辑,2次为弹框
line.editorNum = 0;
line.editor = new AMap.PolyEditor(this.map, line);
}
// 绘制管道的时候,挂载的事件
mouseToolPolineEvent(target) {
// 线按下的时候会变成编辑,mousetool事件会清空 移出线的时候 在把polyline事件加上
target.on("mouseover", (e) => {
// 鼠标事件关闭
// this.mousetool.close(false);
});
target.on("mouseout", (e) => {
// 有时候按在线上移动地图,map点击事件中mosueToolPolineDownFlag无法归位,在这里归位
this.mosueToolPolineDownFlag = false;
// 鼠标事件开启,并且赋值原来的属性,this.mouseToolMarkerOptions是开启绘制的时候记录的
// this.mousetool.polyline(this.mouseToolPolineOptions);
});
// 线
target.on("mousedown", (e) => {
const line = e.target;
// mosueTool按下的flag,按在线上,不询问是否删除
this.mosueToolPolineDownFlag = true;
// 按下的时候要关闭事件
this.mousetool.close(false);
// 如果当前状态不是编辑,则进入编辑状态
if (line.editorNum < 1) {
// 打开并且++
line.editor.open();
line.editorNum++;
} else {
// 这里就要弹框了
console.log(line.getPath());
}
});
}
// 设备点击上图开启
mouseAddMarker(markerObj = {}) {
// 清空已经绘制完的对象
this.mousetoolClose(true);
// 记录一下配置项,在挂载点击的时候,需要使用
this.mouseToolMarkerOptions = {
draggable: true,
...markerObj,
};
this.mousetool.marker(this.mouseToolMarkerOptions);
}
// 管线点击上图开启
mouseAddPipeline(pipeObj = {}) {
this.mousetoolClose(true);
// 开始画线
this.mosuetoolPolineFlag = true;
this.mouseToolPolineOptions = {
strokeWeight: 5,
...pipeObj,
};
this.mousetool.polyline(this.mouseToolPolineOptions);
}
// 手动清除map上绘制的对象
mouseToolDrawClear() {
if (this.nowMouseTarget) {
this.map.remove(this.nowMouseTarget);
// 如果有editor,则关闭
this.nowMouseTarget.editor && this.nowMouseTarget.editor.close();
this.nowMouseTarget = null;
}
}
// 关闭点击上图事件 true清除之前绘制的图像,false 仅关闭上图事件
mousetoolClose(boolean) {
// 清空地图上的绘制对象的同时,也要清楚这个nowMouseTarget控制对象
if (this.nowMouseTarget) {
// 如果有editor,则关闭
this.nowMouseTarget.editor && this.nowMouseTarget.editor.close();
this.nowMouseTarget = null;
}
this.mousetool.close(boolean);
}
/**
*
*
*
*
*
*
* 地图上add设备
*
*
* @description:
* @param {*} deviceData marker的数据
* @param {*} compontent marker点击弹出的infowindow的组件
* @return {*}
*/
addDevice(deviceData, compontent, showBool = true) {
const { longitude: lng, latitude: lat, iconType } = deviceData;
// const icon = svgUrl[iconType];
const icon = this.devicePicData[iconType];
// console.log("icon", icon);
let device = this.createMarker({
map: this.map,
anchor: "bottom-center",
icon,
position: [lng, lat],
extData: deviceData,
label: {
content: deviceData.siteStationName || deviceData.titlename || deviceData.deviceName || '设备',
direction: "top",
},
});
document.querySelectorAll(".amap-marker-label").forEach((item) => {
item.style.opacity = "0";
});
if (!showBool) {
device.hide();
}
// 如果没有有这个公司的数组,就创建,有就直接push
if (!Array.isArray(this.allDevice[iconType])) {
this.allDevice[iconType] = [];
}
this.allDevice[iconType].push(device);
// 设备的事件函数
this.deviceEvent(device, compontent);
}
deviceEvent(device, compontent) {
device.on("click", (e) => {
const target = e.target;
// 如果control==0就是默认值,没有使用123功能,就显示infowindow
if (this.control == 0) {
this.markerClick(target, compontent);
} else if (this.control == 2) {
// 2是已经上图的设备拥有的编辑功能
} else if (this.control == 3) {
// 3是删除操作
}
});
device.on("mouseover", (e, e2) => {
const target = e.target;
const data = target.getExtData();
const name =
data.nickName ||
data.deviceName ||
data.videoName ||
data.siteStationName ||
data.time ||
data.titlename;
// target.setLabel({ content: name, direction: "top" });
target.dom.querySelector(".amap-marker-label").style.opacity = "1";
});
device.on("mouseout", (e) => {
const target = e.target;
const data = target.getExtData();
target.dom.querySelector(".amap-marker-label").style.opacity = "0";
// target.setLabel({ content: "" });
});
}
/** 点击marker出现infowindow
* @description:
* @param {*} target 点击的对象
* @param {*} compontent marker点击弹出的infowindow的组件
* @return {*}
*/
markerClick(target, compontent) {
const deviceExtData = target.getExtData();
const { longitude: lng, latitude: lat } = deviceExtData;
// 创建一个可以控制的组件,将其dom插入infowindow
this.infowindowComponent = this.createInfowindowDom(
this.vue,
this,
deviceExtData,
compontent
);
// 没恩么用,控制台测试的时候用着玩的
window.func = () => {
const { longitude: lng, latitude: lat } = target.getExtData();
const cd = {
id: 1,
name: "9",
lng,
lat,
};
this.infowindowComponentChange(cd);
target.setExtData(cd);
};
this.infowindow = new AMap.InfoWindow({
isCustom: true,
content: this.infowindowComponent.$el,
position: [lng, lat],
// anchor: "top-left",
// offset: [20, -45],
anchor: "left",
offset: [30, -160],
});
this.infowindow.open(this.map);
}
// 创建要加入到infowindow里的
createInfowindowDom(vueRoot, mapClass, deviceData, compontent) {
const Component = this.vue.$Vue.extend(compontent, {});
return new Component({
data() {
return {
// 当前vue实例
vueRoot,
// 自己写的map类
mapClass,
// 数据
deviceData,
};
},
}).$mount();
}
// 当前显示的infowindow内部的数据发生变化,一般在socket传回数据的时候使用
infowindowComponentChange(data) {
this.infowindowComponent.deviceData = data;
}
// 创建marker
createMarker(MarkerOptions) {
return new AMap.Marker(MarkerOptions);
}
// 地图上add管道
addPipeLine(objData, component) {
const { path, pipePressure, iconType } = objData;
// 根据压力获取颜色
const color = this.pipeColor[pipePressure + 1];
const pipe = this.createPipeLine({
path: eval(path),
strokeWeight: objData.strokeWeight || 4,
strokeColor: color,
extData: objData,
cursor: "pointer",
});
this.map.add(pipe);
// pipe.hide();
if (!Array.isArray(this.pipeArr[iconType])) {
this.pipeArr[iconType] = [];
}
this.pipeArr[iconType].push(pipe);
// console.log(this.pipeArr);
// this.map.panTo([path[0][0], path[0][1]]);
this.pipeEvent(pipe, component);
}
createPipeLine(pipeLineOptions) {
return new AMap.Polyline(pipeLineOptions);
}
pipeEvent(pipe, compontent) {
pipe.on("mouseover", (e) => {
const target = e.target;
// 获取当前颜色
const options = target.getOptions();
options.strokeColor = "blue";
// options.strokeWeight =4;
target.setOptions(options);
});
pipe.on("mouseout", (e) => {
const target = e.target;
// 根据管道压力获取颜色
const { pipePressure } = target.getExtData();
const color = this.pipeColor[pipePressure + 1];
// 获取当前颜色
const options = target.getOptions();
options.strokeColor = color;
// options.strokeWeight =2;
target.setOptions(options);
});
pipe.on("click", (e) => {
const target = e.target;
target.lnglat = e.lnglat;
// 如果control==0就是默认值,没有使用123功能,就显示infowindow
if (this.control == 0) {
this.pipeClick(target, compontent);
} else if (this.control == 2) {
// 2是已经上图的设备拥有的编辑功能
} else if (this.control == 3) {
// 3是删除操作
}
});
}
pipeClick(target, compontent) {
const deviceExtData = target.getExtData();
const { lng, lat } = target.lnglat;
// 创建一个可以控制的组件,将其dom插入infowindow
this.infowindowComponent = this.createInfowindowDom(
this.vue,
this,
deviceExtData,
compontent
);
// 没恩么用,控制台测试的时候用着玩的
// window.func = () => {
// const { lng, lat } = target.getExtData();
// const cd = {
// id: 1,
// name: "9",
// lng,
// lat,
// };
// this.infowindowComponentChange(cd);
// target.setExtData(cd);
// };
this.infowindow = new AMap.InfoWindow({
isCustom: true,
content: this.infowindowComponent.$el,
position: [lng, lat],
// anchor: "top-left",
// offset: [20, -15],
anchor: "middle-left",
offset: [20, 0],
});
this.infowindow.open(this.map);
}
infowindowClose() {
if (!this.infowindow) return;
this.infowindow.close();
}
// 设备以及公司过滤
allfilter(companyArr, typeArr) {
// for (let pipeItem in this.pipeArr) {
// this.pipeArr[pipeItem].forEach((pipe) => {
// const data = pipe.getExtData();
// if (companyArr.indexOf(data.companyType + "") >= 0) {
// pipe.show();
// } else {
// pipe.hide();
// }
// });
// }
for (let deviceItem in this.allDevice) {
this.allDevice[deviceItem].forEach((device) => {
const data = device.getExtData();
// 设备过滤受到bigwindow页面的的两种制约,companyArr, typeArr 两个数组制约显示隐藏
// 燃气没有公司,所以没有device.companyType不收到公司的控制
const companyHas =
companyArr.indexOf(+data.companyType) >= 0 ||
companyArr.indexOf(+data.companyType + "") >= 0;
// 设备存在 受到设备按钮限制
const deviceHas =
typeArr.indexOf(+data.iconType) >= 0 ||
typeArr.indexOf(+data.iconType + "") >= 0;
// 如果是燃气公司的话,不受按钮限制
// const enterprise = data.iconType == 7 || data.iconType == 8;
const enterprise = false;
// 必须设备存在数组里,才会显示设备 !data.companyType代表用户不受公司制约
if (enterprise || (deviceHas && (companyHas || !data.companyType))) {
device.show();
} else {
device.hide();
}
});
}
}
// 普通调用方法
// 设备报警
deviceAlarm(obj) {
// 设备的类型
const { iconType } = obj;
const publicId = obj.userId || obj.deviceId;
// 找到这个设备所属的空间
const device = this.allDevice[iconType].filter(
(item) =>
(item.getExtData().userId || item.getExtData().deviceId) == publicId
)[0];
// 更改的icon
const icon = svgAlarm[iconType];
device.setIcon(icon);
device.setzIndex(13);
// 将旧的值缓存一下
// device.oldData = device.getExtData();
// device.setExtData(obj);
// 可能出现infoWindow数据变化
this.alarmInfowindowChange(obj);
if (!this.alarmObj[iconType]) {
this.alarmObj[iconType] = [];
}
const ind = this.alarmObj[iconType].indexOf(publicId);
if (ind < 0) {
this.alarmObj[iconType].push(publicId);
}
}
// 报警时候,可能发生infowindowComponent存在,也要变化
alarmInfowindowChange(obj) {
if (!this.infowindowComponent) return;
// 如果infowindow是打开的,就改变里面的数据 必须是 调压箱2 阀门3 用户6 才会发生变化电话
const infowindowDeviceType = [2, 3, 6].includes(
this.infowindowComponent.deviceData.iconType
);
// 如果存在userId就用userId,如果存在deviceId就用deviceId
const infowindowDeviceId =
this.infowindowComponent.deviceData.userId ||
this.infowindowComponent.deviceData.deviceId;
// 如果存在userId就用userId,如果存在deviceId就用deviceId
const objId = obj.userId || obj.deviceId;
// 如果两个值匹配,才可以改变infowindow身上的组件
const infowindowComponentHas = infowindowDeviceId == objId;
if (
this.infowindowComponent &&
infowindowDeviceType &&
infowindowComponentHas
) {
// this.infowindowComponentChange(obj);
if (this.infowindowComponent.http) {
this.infowindowComponent.myHttp();
}
}
}
//如果传过来的报警设备中,有不在deviceAlarm中,就是恢复的设备恢复
relieveAlarm(alarmObj) {
// 把报警数组改变结构,如果有userId就是用户,如果有deviceId就是其他设备
const httpObj = {};
alarmObj.forEach((item) => {
const publicId = item.userId || item.deviceId;
if (!Array.isArray(httpObj[item.iconType])) {
httpObj[item.iconType] = [];
}
httpObj[item.iconType].push(publicId);
});
// 循环现有报警设备
for (let iconType in this.alarmObj) {
const arr = this.alarmObj[iconType];
// 循环现有报警设备
for (let i = 0; i < arr.length; i++) {
// 看看现有报警设备中有没有不在 报警数组中的值,有就恢复可能是userId,也可能是deviceId
const publicId = arr[i];
// 看看接口传来的数据中还有没有这些Id,如果没有了,就是修好了
const hasId = httpObj[iconType]?.includes(publicId);
// 如果已经不在报警数组中,就要去大数组中找他,利用userId
// 如果id不存在了,说明不报警了
if (!hasId) {
// 过滤出来这个要恢复的设备
const device = this.allDevice[iconType].filter(
(item) =>
(item.getExtData().userId || item.getExtData().deviceId) ==
publicId
)[0];
// 恢复
const icon = svgUrl[iconType];
device.setIcon(icon);
// 赋值
// const deviceData = { ...device.oldData };
// device.setExtData(deviceData);
// device.oldData = null;
// 如果infowindow是打开的
this.alarmInfowindowChange(device.getExtData());
// 在arr中删掉
arr.splice(i, 1);
// 由于删掉了当前,所以要--恢复位置
i--;
}
}
}
}
// ws协议方法
wsAlarm(obj) {
const { iconType, userId, userStatus } = obj;
const decice = this.allDevice[iconType].filter(
(item) => item.getExtData().userId == userId
)[0];
let icon = null;
// 2报警,1恢复
if (userStatus == 2) {
icon = svgAlarm[iconType];
device.oldData = device.getExtData();
device.setExtData(obj);
} else if (userStatus == 1) {
icon = svgUrl[iconType];
const oldData = device.oldData;
device.setExtData(oldData);
device.oldData = null;
}
decice.setIcon(icon);
}
// 卫星图切换
satellite = null;
changeMap(bool) {
// 卫星,
if (!bool) {
if (this.satellite) return;
this.satellite = new AMap.TileLayer.Satellite();
this.map.addLayer(this.satellite);
} else {
if (this.satellite) {
this.map.removeLayer(this.satellite);
this.satellite = null;
}
}
}
// 轨迹回放
/**
* @description:
* @param {*} vehicleId 设备id
* @param {*} path 轨迹回访率丼
* @return {*}
*/
backTrack(vehicleId, path, times, component) {
this.infowindowClose();
AMap.plugin("AMap.MoveAnimation", () => {
let marker = this.allDevice[9].filter(
(item) => item.getExtData().vehicleId == vehicleId
)[0];
// 绘制轨迹
marker.polyline = new AMap.Polyline({
map: this.map,
path,
showDir: true,
strokeColor: "#28F", //线颜色
// strokeOpacity: 1, //线透明度
strokeWeight: 6, //线宽
// strokeStyle: "solid" //线样式
});
marker.passedPolyline = new AMap.Polyline({
map: this.map,
strokeColor: "#AF5", //线颜色
strokeWeight: 6, //线宽
});
marker.on("moving", (e) => {
marker.passedPolyline.setPath(e.passedPath);
// this.map.setCenter(e.target.getPosition(), true);
// console.log(getPosition());
});
// 每个path的点
// marker.pointArr = [];
// carTarget
//点击的时候,先传进来一个点
const carPathData = { ...marker.getExtData(), time: times[0] };
carPathData.iconType = 14;
this.addDevice(carPathData, component);
// marker.pointArr.push(point);
marker.on("moveend", (e) => {
// this.addDevice(carPathData,carBackComponent);
// 如果不是最后一个点,就创建一个新的worderpoint,如果是就不创建,并且把自身删除
let z = {
longitude: e.pos[0],
latitude: e.pos[1],
iconType: 14,
time: times[e.index],
};
// if (e.index == path.length - 1) {
// point = this.addDevice(z, null);
// } else {
this.addDevice(z, component);
// workPoint.infoWindow.open(map,e.passedPos);
// }
console.log("定点", e);
});
marker.moveAlong(path, {
// 每一段的时长
duration: 8000, //可根据实际采集时间间隔设置
// JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
autoRotation: true,
});
});
}
clearbackTrack(vehicleId) {
// let marker = this.allDevice[9].filter(
// (item) => item.getExtData().vehicleId == vehicleId
// )[0];
this.allDevice["9"]?.forEach((item) => {
if (item) {
// 停止运动
item.stopMove();
// 删除每个点
console.log(item.pointArr);
if (item.polyline) {
this.map.remove(item.polyline);
}
if (item.passedPolyline) {
this.map.remove(item.passedPolyline);
}
this.map.remove(item);
}
});
// 最后把数组清空
this.allDevice["9"] = [];
// 把car的路径点也清空
this.allDevice["14"]?.forEach((iten) => {
this.map.remove(iten);
});
this.allDevice["14"] = [];
this.infowindowClose();
}
destroy() {
this.map.destroy();
}
}
...@@ -6,7 +6,12 @@ ...@@ -6,7 +6,12 @@
<div class="col date">安装时间</div> <div class="col date">安装时间</div>
<div class="col status">设备状态</div> <div class="col status">设备状态</div>
</div> </div>
<div class="body" ref="body" @mouseenter="isPaused = true" @mouseleave="isPaused = false"> <div
class="body"
ref="body"
@mouseenter="isPaused = true"
@mouseleave="isPaused = false"
>
<div <div
class="scroll" class="scroll"
:class="{ 'is-scrolling': shouldScroll, 'is-paused': isPaused }" :class="{ 'is-scrolling': shouldScroll, 'is-paused': isPaused }"
...@@ -17,7 +22,12 @@ ...@@ -17,7 +22,12 @@
<div class="col type">{{ row.type }}</div> <div class="col type">{{ row.type }}</div>
<div class="col date">{{ row.date }}</div> <div class="col date">{{ row.date }}</div>
<div class="col status"> <div class="col status">
<span :class="['tag', row.status === '正常' ? 'tag-blue' : 'tag-orange']"> <span
:class="[
'tag',
row.status === '正常' ? 'tag-blue' : 'tag-orange',
]"
>
{{ row.status }} {{ row.status }}
</span> </span>
</div> </div>
...@@ -32,7 +42,12 @@ ...@@ -32,7 +42,12 @@
<div class="col type">{{ row.type }}</div> <div class="col type">{{ row.type }}</div>
<div class="col date">{{ row.date }}</div> <div class="col date">{{ row.date }}</div>
<div class="col status"> <div class="col status">
<span :class="['tag', row.status === '正常' ? 'tag-blue' : 'tag-orange']"> <span
:class="[
'tag',
row.status === '正常' ? 'tag-blue' : 'tag-orange',
]"
>
{{ row.status }} {{ row.status }}
</span> </span>
</div> </div>
...@@ -57,7 +72,6 @@ export default { ...@@ -57,7 +72,6 @@ export default {
{ id: "4", type: "阀门井", date: "2014-12-10", status: "正常" }, { id: "4", type: "阀门井", date: "2014-12-10", status: "正常" },
{ id: "5", type: "调压箱", date: "2015-12-24", status: "临期" }, { id: "5", type: "调压箱", date: "2015-12-24", status: "临期" },
{ id: "6", type: "调压箱", date: "2014-12-10", status: "正常" }, { id: "6", type: "调压箱", date: "2014-12-10", status: "正常" },
]; ];
}, },
}, },
...@@ -115,7 +129,7 @@ export default { ...@@ -115,7 +129,7 @@ export default {
width: 100%; width: 100%;
color: #ffffff; color: #ffffff;
font-size: 14px; font-size: 14px;
background: #000; // background: #000;
overflow: hidden; overflow: hidden;
} }
...@@ -123,7 +137,7 @@ export default { ...@@ -123,7 +137,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
height: 42px; height: 42px;
background: #0b75d3; background: rgba(0, 124, 225, 0.4);
font-weight: 600; font-weight: 600;
} }
......
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2025-12-20 09:20:39
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2026-01-10 10:23:10
* @FilePath: /test-ranqi/src/views/Index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="ind2">
<div id="gao-map-index"></div>
<Left />
<Right />
</div>
</template>
<script>
import Left from "./components/Left.vue";
import Right from "./components/Right.vue";
import { EditorMap } from "@/utils/newMap";
import {
deviceType,
deviceIcon,
pipeColor,
} from "@/utils/deviceIconTypeConfig";
export default {
name: "",
components: {
Left,
Right,
},
data() {
return {};
},
computed: {},
watch: {},
mounted() {
this.initMap();
},
methods: {
initMap() {
// const path = eval(this.systemSetting.map_center);
this.gaoMap = new EditorMap(
"gao-map-index",
{
center: [118.09, 39.48],
// mapStyle: "amap://styles/806fa63f07c70b043867bd1f9a600981",
mapStyle: "amap://styles/f71d3a3d73e14f5b2bf5508bf1411758",
zoom: 10.5,
devicePicData: deviceIcon,
pipeColor: pipeColor,
},
this
);
},
},
};
</script>
<style lang="scss" scoped>
.ind2 {
height: 100vh;
width: 100%;
#gao-map-index{
width: 100%;
height: 100%;
}
}
</style>
<template>
<div class="hazard-overview">
<div ref="chart" class="hazard-ring"></div>
<div class="legend">
<div
v-for="item in items"
:key="item.name"
class="legend-item"
>
<span class="dot" :style="{ backgroundColor: item.color }"></span>
<span class="label">{{ item.name }}</span>
<span class="value">{{ item.value }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: "HazardOverview",
props: {
items: {
type: Array,
default() {
return [
{ name: "居民用户隐患", value: 3, color: "#4aa8ff" },
{ name: "工商用户隐患", value: 2, color: "#ffb357" },
{ name: "管线隐患", value: 4, color: "#3be6ff" },
{ name: "其他设施", value: 3, color: "#ff4a4a" },
];
},
},
},
data() {
return {
chart: null,
};
},
computed: {
totalValue() {
return this.items.reduce((sum, item) => {
const value = Number(item.value) || 0;
return sum + value;
}, 0);
},
},
mounted() {
this.initChart();
window.addEventListener("resize", this.handleResize);
},
beforeDestroy() {
window.removeEventListener("resize", this.handleResize);
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
},
watch: {
items: {
handler() {
this.updateChart();
},
deep: true,
},
},
methods: {
initChart() {
if (!this.$refs.chart) {
return;
}
this.chart = this.$echarts.init(this.$refs.chart);
this.updateChart();
},
handleResize() {
if (this.chart) {
this.chart.resize();
}
},
updateChart() {
if (!this.chart) {
return;
}
const data = this.items.map((item) => ({
name: item.name,
value: Number(item.value) || 0,
}));
this.chart.setOption({
color: this.items.map((item) => item.color),
title: {
text: String(this.totalValue),
subtext: "总数",
left: "center",
top: "center",
textStyle: {
color: "#ffffff",
fontSize: 32,
fontWeight: "bold",
},
subtextStyle: {
color: "#ffffff",
fontSize: 14,
},
},
series: [
{
type: "pie",
radius: ["68%", "86%"],
center: ["50%", "50%"],
startAngle: 90,
label: { show: false },
labelLine: { show: false },
emphasis: { scale: false },
itemStyle: {
borderWidth: 3,
borderColor: "rgba(3, 16, 28, 0.9)",
},
data,
},
],
});
},
},
};
</script>
<style lang="scss" scoped>
.hazard-overview {
width: 100%;
display: flex;
align-items: center;
}
.hazard-ring {
width: 180px;
height: 180px;
}
.legend {
flex:1;
display: flex;
flex-direction: column;
gap: 10px;
margin-left: 16px;
}
.legend-item {
display: flex;
align-items: center;
height: 34px;
padding: 0 12px;
background: linear-gradient(
90deg,
rgba(64, 156, 255, 0.35) 0%,
rgba(64, 156, 255, 0.08) 100%
);
border: 1px solid rgba(64, 156, 255, 0.5);
color: #ffffff;
box-shadow: inset 0 0 14px rgba(64, 156, 255, 0.25);
}
.dot {
width: 16px;
height: 8px;
border-radius: 2px;
margin-right: 10px;
flex-shrink: 0;
}
.label {
flex: 1;
font-size: 14px;
white-space: nowrap;
}
.value {
font-size: 16px;
font-weight: 600;
}
</style>
<template>
<div
class="issue-table"
:style="{
minWidth: minWidth + 'px',
maxHeight: maxHeight + 'px',
height: height ? height + 'px' : '100%',
}"
>
<div class="header-row">
<div class="col id">工单编号</div>
<div class="col type">类型</div>
<div class="col issue">整改问题</div>
<div class="col status">状态</div>
</div>
<div class="body" ref="body">
<div
class="scroll"
:class="{ 'is-scrolling': shouldScroll }"
:style="shouldScroll ? { animationDuration: scrollDuration + 's' } : {}"
>
<div v-for="row in rows" :key="row.id + row.issue" class="row">
<div class="col id vid">{{ row.id }}</div>
<div class="col type">{{ row.type }}</div>
<div class="col issue" :title="row.issue">{{ row.issue }}</div>
<div class="col status">
<span
:class="[
'tag',
row.status === '整改中' ? 'tag-blue' : 'tag-orange',
]"
>
{{ row.status }}
</span>
</div>
</div>
<template v-if="shouldScroll">
<div
v-for="(row, index) in rows"
:key="'clone-' + index + row.issue"
class="row"
>
<div class="col id">{{ row.id }}</div>
<div class="col type">{{ row.type }}</div>
<div class="col issue" :title="row.issue">{{ row.issue }}</div>
<div class="col status">
<span
:class="[
'tag',
row.status === '整改中' ? 'tag-blue' : 'tag-orange',
]"
>
{{ row.status }}
</span>
</div>
</div>
</template>
</div>
</div>
</div>
</template>
<script>
export default {
name: "IssueTable",
props: {
rows: {
type: Array,
default() {
return [
{ id: "1", type: "阀门井", issue: "阀门井泄漏", status: "整改中" },
{ id: "2", type: "调压箱", issue: "调压箱老化", status: "未整改" },
{ id: "3", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "4", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "5", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "6", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "7", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "8", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "9", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "10", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "11", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "12", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "13", type: "管线", issue: "管线老化", status: "整改中" },
{ id: "14", type: "管线", issue: "管线老化", status: "整改中" },
];
},
},
minWidth: {
type: Number,
default: 431,
},
maxHeight: {
type: Number,
default: 525,
},
height: {
type: Number,
default: 0,
},
speed: {
type: Number,
default: 20,
},
},
data() {
return {
shouldScroll: false,
};
},
computed: {
scrollDuration() {
const rowsCount = this.rows.length || 1;
return Math.max(6, rowsCount * this.speed * 0.1);
},
},
mounted() {
this.updateScrollState();
window.addEventListener("resize", this.updateScrollState);
},
updated() {
this.updateScrollState();
},
beforeDestroy() {
window.removeEventListener("resize", this.updateScrollState);
},
methods: {
updateScrollState() {
this.$nextTick(() => {
const body = this.$refs.body;
if (!body) {
this.shouldScroll = false;
return;
}
this.shouldScroll = body.scrollHeight > body.clientHeight;
console.log(body.scrollHeight, body.clientHeight);
});
},
},
};
</script>
<style lang="scss" scoped>
.issue-table {
width: 100%;
// background: #000;
color: #fff;
font-size: 16px;
overflow: hidden;
}
.header-row {
display: flex;
align-items: center;
height: 52px;
background: rgba(0, 124, 225, 0.4);
font-weight: 600;
}
.body {
padding: 8px 0;
// padding-left: 4px;
height: calc(100% - 42px);
overflow: hidden;
}
.scroll {
display: flex;
flex-direction: column;
}
.scroll.is-scrolling {
animation-name: tableScroll;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
.issue-table:hover .scroll.is-scrolling {
animation-play-state: paused;
}
.row {
display: flex;
align-items: center;
height: 34px;
}
.col {
padding: 0 10px;
box-sizing: border-box;
white-space: nowrap;
}
.id {
width: 28%;
text-align: left;
}
.vid{
padding-left:15px;
}
.type {
width: 18%;
}
.issue {
width: 34%;
overflow: hidden;
text-overflow: ellipsis;
}
.status {
width: 20%;
display: flex;
justify-content: flex-end;
// padding-right: 14px;
}
.tag {
display: inline-block;
min-width: 54px;
text-align: center;
padding: 4px 8px;
border-radius: 2px;
font-size: 14px;
line-height: 20px;
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.tag-blue {
background: #1e88e5;
}
.tag-orange {
background: #e85d2a;
}
@keyframes tableScroll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-50%);
}
}
</style>
<template>
<div class="left">
<div class="t">
<Title text="用户安检" />
<div class="btn">
<div
class="btn-item"
v-for="item in btnData1"
:key="item"
:class="{ active: btn1Active == item }"
>
{{ item }}
</div>
</div>
<div class="chars1">
<div><img src="@/assets/ind2Img/ind2Imga.png" alt="" /></div>
<div class="bb">
<div class="text">安检任务1进度</div>
<PressureBarChartVue />
</div>
</div>
<div class="chars2">
<UserTypeStackBarChart />
</div>
</div>
<div class="b">
<Title text="管线巡检" />
<div class="btn">
<div
class="btn-item"
v-for="item in btnData2"
:key="item"
:class="{ active: btn2Active == item }"
>
{{ item }}
</div>
</div>
<div class="text-wrapper">
<div v-for="item in textData" :key="item.t1">
<div class="text1">{{ item.t1 }}</div>
<div class="text2">{{ item.t2 }}</div>
</div>
</div>
<div class="chars3">
<PressureBarChart2 />
</div>
</div>
</div>
</template>
<script>
import Title from "@/views/PubCom/title.vue";
import PressureBarChartVue from "./PressureBarChart.vue";
import PressureBarChart2 from "./PressureBarChart2.vue";
import UserTypeStackBarChart from "./UserTypeStackBarChart.vue";
export default {
name: "",
components: {
Title,
PressureBarChartVue,
UserTypeStackBarChart,
PressureBarChart2,
},
data() {
return {
textData: [
{
t1: "2.396",
t2: "高压已巡检",
},
{
t1: "2.396",
t2: "高压已巡检",
},
{
t1: "2.396",
t2: "高压已巡检",
},
{
t1: "2.396",
t2: "高压已巡检",
},
],
btnData1: ["居民", "工商业"],
btn1Active: "居民",
btnData2: ["日", "季度", "年"],
btn2Active: "日",
};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.left {
overflow: hidden;
// width: 20%;
width: 434px;
top: 102px;
bottom: 50px;
// background: url("~@/assets/index/l.png") no-repeat center;
// background-size: 100% 100%;
// border: 1px solid red;
position: absolute;
left: 10px;
z-index: 999999;
}
.btn {
display: flex;
margin-top: 15px;
margin-bottom: 20px;
.btn-item {
width: 71px;
height: 38px;
background: rgba(25, 151, 254, 0.098);
box-sizing: border-box;
border: 0.96px solid #10b4f5;
box-shadow: inset 0px 0px 13px 0px rgba(25, 151, 254, 0.61);
margin-right: 15px;
cursor: pointer;
text-align: center;
line-height: 38px;
color:#fff;
&.active {
background: linear-gradient(180deg, #19d6fe 0%, #1684e5 100%);
border: 1px solid #72c1ff;
}
}
}
.chars1 {
display: flex;
.bb {
flex: 1;
margin-bottom: 12px;
.text {
color: #fff;
font-size: 16px;
margin-bottom: 2px;
padding-left: 10px;
padding-top: 10px;
box-sizing: border-box;
}
}
}
.b {
margin-top: 25px;
}
.text-wrapper {
width: 100%;
display: flex;
justify-content: space-between;
color: #fff;
.text1 {
font-size: 28px;
}
.text2 {
font-size: 16px;
}
}
</style>
<template>
<div class="chars-wrapper">
<!-- <div class="bg">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div> -->
<div ref="chart" class="pressure-bar-chart"></div>
</div>
</template>
<script>
export default {
name: "PressureBarChart",
props: {
value: {
type: Number,
default: 78,
},
max: {
type: Number,
default: 100,
},
},
data() {
return {
chart: null,
};
},
mounted() {
this.initChart();
window.addEventListener("resize", this.handleResize);
},
beforeDestroy() {
window.removeEventListener("resize", this.handleResize);
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
},
watch: {
value() {
this.updateChart();
},
max() {
this.updateChart();
},
},
methods: {
initChart() {
if (!this.$refs.chart) {
return;
}
this.chart = this.$echarts.init(this.$refs.chart);
this.updateChart();
},
handleResize() {
if (this.chart) {
this.chart.resize();
}
},
updateChart() {
if (!this.chart) {
return;
}
const maxValue = Math.max(this.max, 1);
const safeValue = Math.min(Math.max(this.value, 0), maxValue);
this.chart.setOption({
grid: {
left: 0,
right: 40,
top: 0,
bottom: 0,
containLabel: true,
},
xAxis: {
type: "value",
max: maxValue,
splitLine: { show: false },
axisTick: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
},
yAxis: [
{
show: false,
type: "category",
data: [""],
axisTick: { show: false },
axisLine: { show: false },
},
{
// show: false,
type: "category",
data: [`${this.value}%`],
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
color: "#ffffff",
fontSize: 18,
},
},
],
series: [
{
type: "bar",
data: [safeValue],
barWidth: 14,
barCategoryGap: 5,
showBackground: true,
backgroundStyle: {
color: "rgba(16, 180, 245, 0.22)",
borderRadius: 6,
},
itemStyle: {
borderRadius: [0, 6, 6, 0],
color: new this.$echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: "#2f7bff" },
{ offset: 0.6, color: "#31c3ff" },
{ offset: 1, color: "#2ef5ff" },
]),
},
label: {
show: false,
position: "right",
color: "#fff",
fontSize: 16,
formatter: ({ value }) => `${value}%`,
},
},
],
});
},
},
};
</script>
<style lang="scss" scoped>
.chars-wrapper {
width: 100%;
position: relative;
}
.bg {
position: absolute;
width: 100%;
// height: 152px;
// display: flex;
// flex-direction:column;
// justify-content: space-between;
padding-top: 5px;
.item {
width: 100%;
height: 40px;
// background: rgba(130, 202, 255, 0.18);
background: rgba(130, 202, 255, 0.18);
margin-bottom: 10px;
}
// width: 100%;
// height: 120px;
}
.pressure-bar-chart {
position: relative;
// position:absolute;
// background: red;
width: 100%;
height: 20px;
// overflow: hidden;
// background: red;
}
</style>
<template>
<div class="chars-wrapper">
<!-- <div class="bg">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div> -->
<div ref="chart" class="pressure-bar-chart"></div>
</div>
</template>
<script>
export default {
name: "PressureBarChart",
props: {
data: {
type: Array,
default() {
return [
{ name: "白官屯镇", value: 90 },
{ name: "七树庄镇", value: 78 },
{ name: "丰登坞镇", value: 75 },
{ name: "新军屯镇", value: 70 },
{ name: "小张各庄镇", value: 68 },
{ name: "欢喜庄乡", value: 65 },
{ name: "李钊庄镇", value: 64 },
];
},
},
},
data() {
return {
chart: null,
};
},
mounted() {
this.initChart();
window.addEventListener("resize", this.handleResize);
},
beforeDestroy() {
window.removeEventListener("resize", this.handleResize);
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
},
watch: {
data: {
deep: true,
handler() {
this.updateChart();
},
},
},
methods: {
initChart() {
if (!this.$refs.chart) {
return;
}
this.chart = this.$echarts.init(this.$refs.chart);
this.updateChart();
},
handleResize() {
if (this.chart) {
this.chart.resize();
}
},
updateChart() {
if (!this.chart) {
return;
}
const names = this.data.map((item) => item.name);
const values = this.data.map((item) => item.value);
const maxValue = Math.max(...values, 1);
this.chart.setOption({
grid: {
left: 0,
right: 20,
top: 0,
bottom: 0,
containLabel: true,
},
xAxis: {
type: "value",
max: Math.ceil(maxValue * 1.25),
splitLine: { show: false },
axisTick: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
},
yAxis: [
{
type: "category",
data: names,
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
color: "#ffffff",
fontSize: 16,
},
},
{
type: "category",
data: values.map(item=>`${item}%`),
offset:20,
axisTick: { show: false },
axisLine: { show: false },
axisLabel: {
color: "#ffffff",
fontSize: 16,
},
},
],
series: [
{
type: "bar",
data: values,
barWidth: 14,
barCategoryGap: 5,
showBackground: true,
backgroundStyle: {
color: "rgba(255,255,255,0.12)",
borderRadius: 6,
},
itemStyle: {
borderRadius: [0, 6, 6, 0],
color: new this.$echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: "#2ea6ff" },
{ offset: 1, color: "#14e0ff" },
]),
},
label: {
show: false,
position: "right",
color: "#ffffff",
fontSize: 14,
},
},
],
});
},
},
};
</script>
<style lang="scss" scoped>
.chars-wrapper{
width: 100%;
position: relative;
}
.bg {
position: absolute;
width: 100%;
height: 234px;
// display: flex;
// flex-direction:column;
// justify-content: space-between;
padding-top: 5px;
.item {
width: 100%;
height: 40px;
// background: rgba(130, 202, 255, 0.18);
background: rgba(130, 202, 255, 0.18);
margin-bottom: 10px;
}
// width: 100%;
// height: 120px;
}
.pressure-bar-chart {
position: relative;
// position:absolute;
// background: red;
width: 100%;
height: 234px;
// overflow: hidden;
// background: red;
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2026-01-09 15:10:53
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2026-01-10 15:57:06
* @FilePath: /huaxindd-web/src/views/Ind2/components/Right.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="right">
<div class="t">
<Title text="隐患统计" />
<div class="tc">
<HazardOverviewVue />
</div>
</div>
<div class="b">
<Title text="设备生命周期" />
<div class="table">
<Table/>
</div>
</div>
</div>
</template>
<script>
import Title from "@/views/PubCom/title.vue";
import HazardOverviewVue from "./HazardOverview.vue";
import Table from "./IssueTable.vue"
export default {
name: "",
components: {
Title,
HazardOverviewVue,
Table
},
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.right {
// width: 20%;
width: 434px;
position: absolute;
top: 102px;
bottom: 50px;
// background: url("~@/assets/index/r.png") no-repeat center;
// background-size: 100% 100%;
// background: red;
// border: 1px solid red;
right: 10px;
z-index: 9999;
.t {
// margin-top:25px;
.tc{
margin-top:25px;
}
}
.b{
margin-top:25px;
.table{
margin-top:10px;
width: 255px;
height: 500px;
// background: blue;
}
}
}
</style>
<template>
<div ref="chart" class="user-type-stack-bar-chart"></div>
</template>
<script>
export default {
name: "UserTypeStackBarChart",
props: {
categories: {
type: Array,
default() {
return [
"白芨屯",
"七树庄",
"王浒圳",
"新罕电",
"小张各庄",
"欢喜庄",
"李朝庄",
];
},
},
residential: {
type: Array,
default() {
return [22, 14, 24, 22, 26, 18, 28];
},
},
industrial: {
type: Array,
default() {
return [10, 8, 12, 10, 6, 16, 4];
},
},
},
data() {
return {
chart: null,
};
},
mounted() {
this.initChart();
window.addEventListener("resize", this.handleResize);
},
beforeDestroy() {
window.removeEventListener("resize", this.handleResize);
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
},
watch: {
categories() {
this.updateChart();
},
residential() {
this.updateChart();
},
industrial() {
this.updateChart();
},
},
methods: {
initChart() {
if (!this.$refs.chart) {
return;
}
this.chart = this.$echarts.init(this.$refs.chart);
this.updateChart();
},
handleResize() {
if (this.chart) {
this.chart.resize();
}
},
updateChart() {
if (!this.chart) {
return;
}
this.chart.setOption({
grid: {
left: 6,
right: 6,
top: 28,
bottom: 0,
containLabel: true,
},
legend: {
top: 0,
right: 10,
itemWidth: 16,
itemHeight: 8,
textStyle: {
color: "#ffffff",
fontSize: 16,
},
},
xAxis: {
type: "category",
data: this.categories,
axisLine: { lineStyle: { color: "rgba(19,253,245,0.19)" } },
axisTick: {
show: true,
inside: true,
length: 1.5,
width:2,
lineStyle: { color: "#2CFFFF" },
},
axisLabel: {
color: "#ffffff",
fontSize: 11,
},
},
yAxis: {
type: "value",
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false },
splitLine: {
lineStyle: { color: "rgba(19,253,245,0.19)" },
},
},
series: [
{
name: "居民用户",
type: "bar",
stack: "total",
data: this.residential,
barWidth: 14,
itemStyle: {
borderRadius: [2, 2, 0, 0],
color: "#20c8ff",
},
},
{
name: "工商业用户",
type: "bar",
stack: "total",
data: this.industrial,
barWidth: 14,
itemStyle: {
borderRadius: [2, 2, 0, 0],
color: "#ff6b3d",
},
},
],
});
},
},
};
</script>
<style lang="scss" scoped>
.user-type-stack-bar-chart {
width: 100%;
height: 200px;
}
</style>
...@@ -2,38 +2,40 @@ ...@@ -2,38 +2,40 @@
* @Author: 纪泽龙 jizelong@qq.com * @Author: 纪泽龙 jizelong@qq.com
* @Date: 2026-01-05 10:39:41 * @Date: 2026-01-05 10:39:41
* @LastEditors: 纪泽龙 jizelong@qq.com * @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2026-01-05 10:43:52 * @LastEditTime: 2026-01-09 15:34:16
* @FilePath: /huaxindd-web/src/views/Index/index.vue * @FilePath: /huaxindd-web/src/views/Index/index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->
<template> <template>
<div <div
class="ind" class="index"
:style="{ :style="{
transform: `scale(${scaleX},${scaleX})`, transform: `scale(${scaleX},${scaleX})`,
top: `-${((1 - scaleX) * innerHeight) / 2}px`, top: `-${((1 - scaleX) * innerHeight) / 2}px`,
}" }"
> >
<Top /> <Top />
<Ind /> <component :is="currentTabComponent"></component>
<!-- <Ind /> -->
</div> </div>
</template> </template>
<script> <script>
import Top from "./components/Top.vue"; import Top from "./components/Top.vue";
import Ind from "@/views/Ind/Ind.vue"; import Ind from "@/views/Ind2/Ind.vue";
export default { export default {
name: "", name: "",
components: { components: {
Top, Top,
Ind, // Ind,
}, },
data() { data() {
return { return {
scaleX: 1, scaleX: 1,
innerWidth: 0, innerWidth: 0,
innerHeight: 0, innerHeight: 0,
currentTabComponent:Ind,
}; };
}, },
created() { created() {
...@@ -46,7 +48,7 @@ export default { ...@@ -46,7 +48,7 @@ export default {
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ind { .index {
// width:2880px; // width:2880px;
width: 1920px; width: 1920px;
height: 100vh; height: 100vh;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment