20260126:模型排序&高德地图
This commit is contained in:
parent
652a32b797
commit
b770da12e3
@ -102,7 +102,7 @@ spring:
|
||||
redis:
|
||||
host: localhost # 地址
|
||||
port: 6379 # 端口,默认为6379
|
||||
database: 3 # 数据库索引
|
||||
database: 0 # 数据库索引
|
||||
password: fastbee # 密码
|
||||
timeout: 10s # 连接超时时间
|
||||
lettuce:
|
||||
|
||||
@ -50,8 +50,11 @@ public class TCPBootStrap {
|
||||
.setPort(port)
|
||||
//设置报文最大长度 modbus-rtu
|
||||
.setMaxFrameLength(1024)
|
||||
// 此处就是ASCII和注册包粘包了,无需strip掉 “分隔符” 即可
|
||||
.setDelimiters(new Delimiter(new byte[]{0x7e}, false))
|
||||
/*
|
||||
* 此处就是ASCII和注册包粘包了,无需strip掉 “分隔符” 即可
|
||||
* 最原始.setDelimiters(new Delimiter(new byte[]{0x7e}, true))
|
||||
*/
|
||||
.setDelimiters(new Delimiter(new byte[]{0x0A}, true))
|
||||
.setDecoder(messageAdapter)
|
||||
.setEncoder(messageAdapter)
|
||||
.setHandlerMapping(handlerMapping)
|
||||
|
||||
@ -125,13 +125,12 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
||||
if (minDelim != null) {
|
||||
int minDelimLength = minDelim.value.length;
|
||||
ByteBuf frame = null;
|
||||
boolean keepDelimiterForNextFrame = shouldKeepDelimiterForNextFrame(minDelim) && minFrameLength > 0;
|
||||
|
||||
if (discardingTooLongFrame) {
|
||||
// 如果true,将长度不符合报文丢弃
|
||||
// 初始化原来的值
|
||||
discardingTooLongFrame = false;
|
||||
buffer.skipBytes(minFrameLength + (keepDelimiterForNextFrame ? 0 : minDelimLength));
|
||||
buffer.skipBytes(minFrameLength + minDelimLength);
|
||||
|
||||
int tooLongFrameLength = this.tooLongFrameLength;
|
||||
this.tooLongFrameLength = 0;
|
||||
@ -143,16 +142,10 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
||||
/*小于最小长度帧处理*/
|
||||
if (minFrameLength > maxFrameLength) {
|
||||
//放弃读取帧
|
||||
buffer.skipBytes(minFrameLength + (keepDelimiterForNextFrame ? 0 : minDelimLength));
|
||||
buffer.skipBytes(minFrameLength + minDelimLength);
|
||||
fail(minFrameLength);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (keepDelimiterForNextFrame) {
|
||||
frame = buffer.readRetainedSlice(minFrameLength);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/*是否需要跳过某字节*/
|
||||
if (minDelim.strip) {
|
||||
//忽略长度等于0的报文
|
||||
@ -273,9 +266,6 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Modbus RTU:为了避免把请求帧(常见固定8字节)误当响应帧(第3字节是byteCount)导致截断,
|
||||
// 这里采用"候选长度 + CRC校验"方式确定帧边界,兼容:请求/回显/响应/异常响应。
|
||||
|
||||
// 异常响应:地址(1) + 功能码(1|0x80) + 异常码(1) + CRC(2) = 5字节
|
||||
if ((functionCode & 0x80) != 0) {
|
||||
int len = 5;
|
||||
@ -309,8 +299,7 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
int byteCount = buffer.getByte(readerIndex + 2) & 0xFF;
|
||||
int respLen = 3 + byteCount + 2;
|
||||
log.debug("[{}] Modbus功能码{}: byteCount={}, 预期帧长={}, 可读={}",
|
||||
deviceId, String.format("%02X", functionCode), byteCount, respLen, readable);
|
||||
log.debug("[{}] Modbus功能码{}: byteCount={}, 预期帧长={}, 可读={}", deviceId, String.format("%02X", functionCode), byteCount, respLen, readable);
|
||||
if (respLen > maxFrameLength) {
|
||||
log.warn("[{}] Modbus帧长度{}超过最大限制{}", deviceId, respLen, maxFrameLength);
|
||||
return -1;
|
||||
@ -368,13 +357,7 @@ public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
|
||||
byte[] crc = CRC16Utils.getCrc16Byte(data); // [low, high]
|
||||
int crcLo = buffer.getByte(offset + len - 2) & 0xFF;
|
||||
int crcHi = buffer.getByte(offset + len - 1) & 0xFF;
|
||||
boolean valid = ((crc[0] & 0xFF) == crcLo) && ((crc[1] & 0xFF) == crcHi);
|
||||
if (!valid && log.isDebugEnabled()) {
|
||||
log.debug("[{}] CRC校验: 计算值={}{}, 实际值={}{}", deviceId,
|
||||
String.format("%02X", crc[0] & 0xFF), String.format("%02X", crc[1] & 0xFF),
|
||||
String.format("%02X", crcLo), String.format("%02X", crcHi));
|
||||
}
|
||||
return valid;
|
||||
return ((crc[0] & 0xFF) == crcLo) && ((crc[1] & 0xFF) == crcHi);
|
||||
}
|
||||
|
||||
private void fail(long frameLength) {
|
||||
|
||||
@ -114,4 +114,10 @@ public class ThingsModelValueItem {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date ts;
|
||||
|
||||
/**
|
||||
* 创建时间(用于排序)
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
|
||||
@ -599,6 +599,7 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
||||
arrayObjectThingsModel.setIsReadonly(param.getIsReadonly());
|
||||
arrayObjectThingsModel.setDatatype(param.getDatatype());
|
||||
arrayObjectThingsModel.setModelOrder(thingsModel.getModelOrder());
|
||||
arrayObjectThingsModel.setCreateTime(thingsModel.getCreateTime());
|
||||
resultList.add(arrayObjectThingsModel);
|
||||
}
|
||||
}
|
||||
@ -617,6 +618,7 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
||||
arrayThingsModel.setIsReadonly(thingsModel.getIsReadonly());
|
||||
arrayThingsModel.setDatatype(datatype);
|
||||
arrayThingsModel.setModelOrder(thingsModel.getModelOrder());
|
||||
arrayThingsModel.setCreateTime(thingsModel.getCreateTime());
|
||||
resultList.add(arrayThingsModel);
|
||||
}
|
||||
} else if ("object".equals(datatype.getType())) {
|
||||
@ -630,6 +632,7 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
||||
newObjectThingsModel.setIsReadonly(objectThingsModel.getIsReadonly());
|
||||
newObjectThingsModel.setDatatype(objectThingsModel.getDatatype());
|
||||
newObjectThingsModel.setModelOrder(thingsModel.getModelOrder());
|
||||
newObjectThingsModel.setCreateTime(thingsModel.getCreateTime());
|
||||
resultList.add(newObjectThingsModel);
|
||||
}
|
||||
} else {
|
||||
@ -642,6 +645,7 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
||||
otherThingsModel.setIsReadonly(thingsModel.getIsReadonly());
|
||||
otherThingsModel.setDatatype(datatype);
|
||||
otherThingsModel.setModelOrder(thingsModel.getModelOrder());
|
||||
otherThingsModel.setCreateTime(thingsModel.getCreateTime());
|
||||
resultList.add(otherThingsModel);
|
||||
}
|
||||
return resultList;
|
||||
@ -686,24 +690,31 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
||||
if (null == productId) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 1、获取产品物模型
|
||||
// 排序器:按 modelOrder 降序,createTime 降序(与数据库 SQL 一致)
|
||||
Comparator<ThingsModelDTO> modelComparator = Comparator
|
||||
.comparing(ThingsModelDTO::getModelOrder, Comparator.reverseOrder())
|
||||
.thenComparing(ThingsModelDTO::getCreateTime, Comparator.nullsLast(Comparator.reverseOrder()));
|
||||
|
||||
// 1、获取产品物模型并排序
|
||||
Map<String, ThingsModelValueItem> map = itslCache.getCacheThMapByProductId(productId);
|
||||
List<ThingsModelDTO> thingsModelDTOList = new ArrayList<>();
|
||||
for (Map.Entry<String, ThingsModelValueItem> entry : map.entrySet()) {
|
||||
ThingsModel thingsModel = this.propertyDtoChangeThingsModel(entry.getValue());
|
||||
thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel));
|
||||
}
|
||||
thingsModelDTOList.sort(modelComparator);
|
||||
|
||||
// 2. 获取设备级计算物模型并合并
|
||||
if (StringUtils.isNotEmpty(serialNumber)) {
|
||||
Map<String, ThingsModelValueItem> deviceCalculatedMap = itslCache.getDeviceCalculatedModelMap(serialNumber);
|
||||
List<ThingsModelDTO> deviceModelList = new ArrayList<>();
|
||||
for (Map.Entry<String, ThingsModelValueItem> entry : deviceCalculatedMap.entrySet()) {
|
||||
ThingsModel thingsModel = this.propertyDtoChangeThingsModel(entry.getValue());
|
||||
thingsModelDTOList.addAll(this.changeObjectOrArray(thingsModel));
|
||||
deviceModelList.addAll(this.changeObjectOrArray(thingsModel));
|
||||
}
|
||||
deviceModelList.sort(modelComparator);
|
||||
thingsModelDTOList.addAll(deviceModelList);
|
||||
}
|
||||
|
||||
thingsModelDTOList.sort(Comparator.comparing(ThingsModelDTO::getModelOrder));
|
||||
if (StringUtils.isEmpty(serialNumber)) {
|
||||
return thingsModelDTOList;
|
||||
}
|
||||
@ -767,6 +778,7 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
||||
thingsModel.setSpecs(JSON.toJSONString(valueItem.getDatatype()));
|
||||
thingsModel.setType(valueItem.getType());
|
||||
thingsModel.setModelId(valueItem.getModelId());
|
||||
thingsModel.setCreateTime(valueItem.getCreateTime());
|
||||
return thingsModel;
|
||||
}
|
||||
|
||||
|
||||
14
vue/package-lock.json
generated
14
vue/package-lock.json
generated
@ -5751,6 +5751,15 @@
|
||||
"zrender": "5.6.1"
|
||||
}
|
||||
},
|
||||
"echarts-extension-leaflet": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/echarts-extension-leaflet/-/echarts-extension-leaflet-1.2.2.tgz",
|
||||
"integrity": "sha512-EKZmIQDRqxnf6DtYWqujn2PRqHmEAq3yr0gsZAwmOT9rSy0Rwt9FlXKPjK3d+EVLqT6se6IQweyJTsqMg537Gg==",
|
||||
"requires": {
|
||||
"echarts": "^5.5.0",
|
||||
"leaflet": "^1.9.4"
|
||||
}
|
||||
},
|
||||
"echarts-liquidfill": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/echarts-liquidfill/-/echarts-liquidfill-3.1.0.tgz",
|
||||
@ -8974,6 +8983,11 @@
|
||||
"launch-editor": "^2.12.0"
|
||||
}
|
||||
},
|
||||
"leaflet": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmmirror.com/leaflet/-/leaflet-1.9.4.tgz",
|
||||
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
|
||||
},
|
||||
"leven": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/leven/-/leven-2.1.0.tgz",
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
"codemirror": "^5.65.2",
|
||||
"core-js": "3.25.3",
|
||||
"echarts": "^5.4.0",
|
||||
"echarts-extension-leaflet": "^1.2.2",
|
||||
"echarts-liquidfill": "^3.0.6",
|
||||
"element-china-area-data": "^4.1.1",
|
||||
"element-ui": "2.15.10",
|
||||
|
||||
@ -1,28 +1,66 @@
|
||||
export function loadBMap() {
|
||||
// 使用OpenStreetMap和Leaflet替代百度地图
|
||||
|
||||
export function loadMap() {
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof BMap !== 'undefined') {
|
||||
resolve(BMap)
|
||||
return true
|
||||
// eslint-disable-next-line no-undef
|
||||
if (typeof L !== 'undefined') {
|
||||
// eslint-disable-next-line no-undef
|
||||
resolve(L);
|
||||
return true;
|
||||
}
|
||||
window.onBMapCallback = function() {
|
||||
resolve(BMap)
|
||||
|
||||
// 加载Leaflet CSS
|
||||
if (!document.querySelector('link[href*="leaflet.css"]')) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
|
||||
link.integrity = 'sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=';
|
||||
link.crossOrigin = '';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
// 使用https协议需要添加一下meta标签
|
||||
var protocolStr = document.location.protocol;
|
||||
if(protocolStr == "https:")
|
||||
{
|
||||
let meta = document.createElement('meta')
|
||||
meta.httpEquiv = 'Content-Security-Policy'
|
||||
meta.content ='upgrade-insecure-requests'
|
||||
meta.onerror = reject
|
||||
document.head.appendChild(meta)
|
||||
}
|
||||
// 引入百度地图
|
||||
let script = document.createElement('script')
|
||||
script.type = 'text/javascript'
|
||||
script.src =
|
||||
'http://api.map.baidu.com/api?v=2.0&ak='+ process.env.VUE_APP_BAI_DU_AK +'&s=1&__ec_v__=20190126&callback=onBMapCallback'
|
||||
script.onerror = reject
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
|
||||
// 加载Leaflet JS
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
|
||||
script.integrity = 'sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=';
|
||||
script.crossOrigin = '';
|
||||
script.onload = function() {
|
||||
// eslint-disable-next-line no-undef
|
||||
resolve(L);
|
||||
};
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// export function loadBMap() {
|
||||
// return new Promise(function(resolve, reject) {
|
||||
// if (typeof BMap !== 'undefined') {
|
||||
// resolve(BMap)
|
||||
// return true
|
||||
// }
|
||||
// window.onBMapCallback = function() {
|
||||
// resolve(BMap)
|
||||
// }
|
||||
// // 使用https协议需要添加一下meta标签
|
||||
// var protocolStr = document.location.protocol;
|
||||
// if(protocolStr == "https:")
|
||||
// {
|
||||
// let meta = document.createElement('meta')
|
||||
// meta.httpEquiv = 'Content-Security-Policy'
|
||||
// meta.content ='upgrade-insecure-requests'
|
||||
// meta.onerror = reject
|
||||
// document.head.appendChild(meta)
|
||||
// }
|
||||
// // 引入百度地图
|
||||
// let script = document.createElement('script')
|
||||
// script.type = 'text/javascript'
|
||||
// script.src =
|
||||
// 'http://api.map.baidu.com/api?v=2.0&ak='+ process.env.VUE_APP_BAI_DU_AK +'&s=1&__ec_v__=20190126&callback=onBMapCallback'
|
||||
// script.onerror = reject
|
||||
// document.head.appendChild(script)
|
||||
// })
|
||||
// }
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
<script>
|
||||
import {
|
||||
loadBMap
|
||||
loadMap
|
||||
} from '@/utils/map.js'
|
||||
//安装的是echarts完整包,里面包含百度地图扩展,路径为 echarts/extension/bmap/bmap.js,将其引入
|
||||
//ECharts的百度地图扩展,可以在百度地图上展现点图,线图,热力图等可视化
|
||||
@ -65,7 +65,7 @@ export default {
|
||||
},
|
||||
/**加载地图*/
|
||||
loadMap() {
|
||||
loadBMap().then(() => {
|
||||
loadMap().then(() => {
|
||||
this.getmap();
|
||||
});
|
||||
},
|
||||
|
||||
@ -319,10 +319,9 @@ import axios from 'axios';
|
||||
import { getDeviceStatistic } from '@/api/iot/device';
|
||||
import { listNotice, getNotice } from '@/api/system/notice';
|
||||
import CountTo from 'vue-count-to';
|
||||
import { loadBMap } from '@/utils/map.js';
|
||||
//安装的是echarts完整包,里面包含百度地图扩展,路径为 echarts/extension/bmap/bmap.js,将其引入
|
||||
//ECharts的百度地图扩展,可以在百度地图上展现点图,线图,热力图等可视化
|
||||
// 注意:bmap扩展需要在BMap加载后再引入
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import 'echarts-extension-leaflet';
|
||||
//import coordtransform from 'coordtransform';
|
||||
import { getServer } from '@/api/monitor/server';
|
||||
import { listAllDeviceShort } from '@/api/iot/device';
|
||||
import 'echarts-liquidfill';
|
||||
@ -1157,23 +1156,10 @@ export default {
|
||||
/**加载地图*/
|
||||
loadMap() {
|
||||
this.$nextTick(() => {
|
||||
loadBMap().then(() => {
|
||||
if (typeof BMap === 'undefined') {
|
||||
this.$message.error('百度地图API未正确加载');
|
||||
return;
|
||||
}
|
||||
// 确保bmap扩展已加载
|
||||
try {
|
||||
require('echarts/extension/bmap/bmap');
|
||||
} catch (e) {
|
||||
// 忽略扩展加载错误
|
||||
}
|
||||
// 使用 echarts-extension-leaflet,已在 import 时加载
|
||||
setTimeout(() => {
|
||||
this.getmap();
|
||||
}, 500);
|
||||
}).catch((error) => {
|
||||
this.$message.error('百度地图加载失败,请检查API Key配置');
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
},
|
||||
/** 查询服务器信息 */
|
||||
@ -1229,13 +1215,14 @@ export default {
|
||||
|
||||
/** 地图 */
|
||||
getmap() {
|
||||
if (typeof BMap === 'undefined') {
|
||||
this.$message.error('百度地图API未正确加载,请刷新页面重试');
|
||||
if (!this.$refs.map) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.$refs.map) {
|
||||
return;
|
||||
// 销毁旧的ECharts实例,避免多个实例叠加
|
||||
var existingChart = this.$echarts.getInstanceByDom(this.$refs.map);
|
||||
if (existingChart) {
|
||||
existingChart.dispose();
|
||||
}
|
||||
|
||||
var myChart = this.$echarts.init(this.$refs.map);
|
||||
@ -1258,8 +1245,14 @@ export default {
|
||||
let convertData = function (data, status) {
|
||||
var res = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var geoCoord = [data[i].longitude, data[i].latitude];
|
||||
if (geoCoord && data[i].status == status) {
|
||||
// 验证经纬度有效性
|
||||
var lng = parseFloat(data[i].longitude);
|
||||
var lat = parseFloat(data[i].latitude);
|
||||
if (isNaN(lng) || isNaN(lat) || lng === 0 || lat === 0) {
|
||||
continue;
|
||||
}
|
||||
var geoCoord = [lng, lat];
|
||||
if (data[i].status == status) {
|
||||
res.push({
|
||||
name: data[i].deviceName,
|
||||
value: geoCoord,
|
||||
@ -1320,14 +1313,9 @@ export default {
|
||||
return { center: [centerLng, centerLat], zoom: zoom };
|
||||
};
|
||||
|
||||
// 使用长沙作为默认中心点,如果有设备数据则使用计算的中心点
|
||||
let mapConfig = { center: [112.867037, 28.11857], zoom: 12 };
|
||||
if (this.deviceList && this.deviceList.length > 0) {
|
||||
const calculated = calculateMapCenter(this.deviceList);
|
||||
if (calculated.center && calculated.center[0] > 0) {
|
||||
mapConfig = calculated;
|
||||
}
|
||||
}
|
||||
// 使用中国长沙作为地图中心点
|
||||
// 长沙坐标:经度 112.94, 纬度 28.23
|
||||
let mapConfig = { center: [112.94, 28.23], zoom: 5 };
|
||||
|
||||
option = {
|
||||
title: {
|
||||
@ -1382,21 +1370,27 @@ export default {
|
||||
return htmlStr;
|
||||
},
|
||||
},
|
||||
bmap: {
|
||||
center: mapConfig.center,
|
||||
zoom: mapConfig.zoom,
|
||||
leaflet: {
|
||||
// echarts-extension-leaflet center 使用 [lng, lat] 格式
|
||||
// 长沙坐标:经度 112.94, 纬度 28.23
|
||||
center: [112.94, 28.23],
|
||||
zoom: 5,
|
||||
roam: true,
|
||||
// 确保地图正确初始化
|
||||
enableMapClick: true,
|
||||
// 暂时不使用自定义样式,确保地图能正常显示
|
||||
// mapStyle: {
|
||||
// styleJson: [...]
|
||||
// },
|
||||
tiles: [
|
||||
{
|
||||
// 使用高德地图瓦片(国内访问稳定)
|
||||
urlTemplate: 'https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
|
||||
options: {
|
||||
subdomains: ['1', '2', '3', '4'],
|
||||
attribution: '© 高德地图',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'bmap',
|
||||
coordinateSystem: 'leaflet',
|
||||
data: convertData(this.deviceList, 1),
|
||||
symbolSize: 15,
|
||||
itemStyle: {
|
||||
@ -1405,7 +1399,7 @@ export default {
|
||||
},
|
||||
{
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'bmap',
|
||||
coordinateSystem: 'leaflet',
|
||||
data: convertData(this.deviceList, 2),
|
||||
symbolSize: 15,
|
||||
itemStyle: {
|
||||
@ -1414,7 +1408,7 @@ export default {
|
||||
},
|
||||
{
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'bmap',
|
||||
coordinateSystem: 'leaflet',
|
||||
data: convertData(this.deviceList, 4),
|
||||
symbolSize: 15,
|
||||
itemStyle: {
|
||||
@ -1423,7 +1417,7 @@ export default {
|
||||
},
|
||||
{
|
||||
type: 'effectScatter',
|
||||
coordinateSystem: 'bmap',
|
||||
coordinateSystem: 'leaflet',
|
||||
data: convertData(this.deviceList, 3),
|
||||
symbolSize: 15,
|
||||
showEffectOn: 'render',
|
||||
@ -1465,35 +1459,10 @@ export default {
|
||||
// 设置地图配置
|
||||
myChart.setOption(option, true);
|
||||
|
||||
// 等待地图初始化后调整大小和刷新
|
||||
setTimeout(() => {
|
||||
// 等待地图初始化完成
|
||||
this.$nextTick(() => {
|
||||
myChart.resize();
|
||||
|
||||
const bmapModel = myChart.getModel().getComponent('bmap');
|
||||
if (bmapModel && bmapModel.getBMap) {
|
||||
const bmapInstance = bmapModel.getBMap();
|
||||
if (bmapInstance) {
|
||||
// 启用地图功能
|
||||
bmapInstance.enableScrollWheelZoom(true);
|
||||
bmapInstance.enableDoubleClickZoom(true);
|
||||
bmapInstance.enableDragging(true);
|
||||
|
||||
// 设置中心点和缩放级别
|
||||
const centerPoint = new BMap.Point(mapConfig.center[0], mapConfig.center[1]);
|
||||
bmapInstance.setCenter(centerPoint);
|
||||
bmapInstance.setZoom(mapConfig.zoom);
|
||||
|
||||
// 刷新地图确保瓦片加载
|
||||
setTimeout(() => {
|
||||
myChart.resize();
|
||||
bmapInstance.reset();
|
||||
bmapInstance.setCenter(centerPoint);
|
||||
bmapInstance.setZoom(mapConfig.zoom);
|
||||
myChart.resize();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}, 800);
|
||||
});
|
||||
} catch (error) {
|
||||
this.$message.error('地图初始化失败: ' + error.message);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<el-card style="margin: 6px; padding-bottom: 100px">
|
||||
<el-tabs id="deviceDetailTab" v-model="activeName" tab-position="left" @tab-click="tabChange" style="padding: 10px; min-height: 400px" lazy>
|
||||
<el-tabs id="deviceDetailTab" v-model="activeName" tab-position="left" @tab-click="tabChange"
|
||||
style="padding: 10px; min-height: 400px" lazy>
|
||||
<el-tab-pane name="basic">
|
||||
<span slot="label">{{ $t('device.device-edit.148398-0') }}</span>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
@ -8,7 +9,9 @@
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8">
|
||||
<el-form-item :label="$t('device.device-edit.148398-1')" prop="deviceName">
|
||||
<el-input v-model="form.deviceName" :placeholder="$t('device.device-edit.148398-2')">
|
||||
<el-button slot="append" @click="openSummaryDialog" v-if="form.deviceId != 0">{{ $t('device.device-edit.148398-3') }}</el-button>
|
||||
<el-button slot="append" @click="openSummaryDialog" v-if="form.deviceId != 0">
|
||||
{{ $t('device.device-edit.148398-3') }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="productName">
|
||||
@ -16,8 +19,11 @@
|
||||
<span style="color: red">*</span>
|
||||
{{ $t('device.device-edit.148398-4') }}
|
||||
</template>
|
||||
<el-input readonly v-model="form.productName" :placeholder="$t('device.device-edit.148398-5')" :disabled="form.status != 1">
|
||||
<el-button slot="append" @click="selectProduct()" :disabled="form.status != 1">{{ $t('device.device-edit.148398-6') }}</el-button>
|
||||
<el-input readonly v-model="form.productName" :placeholder="$t('device.device-edit.148398-5')"
|
||||
:disabled="form.status != 1">
|
||||
<el-button slot="append" @click="selectProduct()" :disabled="form.status != 1">
|
||||
{{ $t('device.device-edit.148398-6') }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="serialNumber">
|
||||
@ -25,11 +31,14 @@
|
||||
<span style="color: red">*</span>
|
||||
{{ $t('device.device-edit.148398-7') }}
|
||||
</template>
|
||||
<el-input v-model="form.serialNumber" :placeholder="$t('device.device-edit.148398-8')" :disabled="form.status != 1" maxlength="32">
|
||||
<el-button v-if="form.deviceType !== 3" slot="append" @click="generateNum" :loading="genDisabled" :disabled="form.status != 1" v-hasPermi="['iot:device:add']">
|
||||
<el-input v-model="form.serialNumber" :placeholder="$t('device.device-edit.148398-8')"
|
||||
:disabled="form.status != 1" maxlength="32">
|
||||
<el-button v-if="form.deviceType !== 3" slot="append" @click="generateNum" :loading="genDisabled"
|
||||
:disabled="form.status != 1" v-hasPermi="['iot:device:add']">
|
||||
{{ $t('device.device-edit.148398-9') }}
|
||||
</el-button>
|
||||
<el-button v-if="form.deviceType === 3" slot="append" @click="genSipID()" :disabled="form.status != 1" v-hasPermi="['iot:device:add']">
|
||||
<el-button v-if="form.deviceType === 3" slot="append" @click="genSipID()" :disabled="form.status != 1"
|
||||
v-hasPermi="['iot:device:add']">
|
||||
{{ $t('device.device-edit.148398-9') }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
@ -45,13 +54,15 @@
|
||||
</template>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-12')" prop="firmwareVersion">
|
||||
<el-input v-model="form.firmwareVersion" :placeholder="$t('device.device-edit.148398-13')" type="number" step="0.1" :disabled="form.status != 1 || form.deviceType === 3">
|
||||
<el-input v-model="form.firmwareVersion" :placeholder="$t('device.device-edit.148398-13')" type="number"
|
||||
step="0.1" :disabled="form.status != 1 || form.deviceType === 3">
|
||||
<template slot="prepend">Version</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<!-- 设备影子 -->
|
||||
<el-form-item :label="$t('device.device-edit.148398-15')" prop="isShadow">
|
||||
<el-switch v-model="form.isShadow" active-text="" inactive-text="" :active-value="1" :inactive-value="0" :disabled="form.deviceType === 3"></el-switch>
|
||||
<el-switch v-model="form.isShadow" active-text="" inactive-text="" :active-value="1" :inactive-value="0"
|
||||
:disabled="form.deviceType === 3"></el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.deviceType != 4" :label="$t('device.device-edit.148398-16')" prop="deviceStatus">
|
||||
@ -66,49 +77,61 @@
|
||||
></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-17')" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :placeholder="$t('device.device-edit.148398-18')" rows="1" />
|
||||
<el-input v-model="form.remark" type="textarea" :placeholder="$t('device.device-edit.148398-18')"
|
||||
rows="1"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8">
|
||||
<el-form-item :label="$t('device.device-edit.148398-19')" prop="locationWay">
|
||||
<el-select v-model="form.locationWay" :placeholder="$t('device.device-edit.148398-20')" clearable size="small" style="width: 100%" :disabled="form.deviceType === 3">
|
||||
<el-option v-for="dict in dict.type.iot_location_way" :key="dict.value" :label="dict.label" :value="Number(dict.value)" />
|
||||
<el-select v-model="form.locationWay" :placeholder="$t('device.device-edit.148398-20')" clearable
|
||||
size="small" style="width: 100%" :disabled="form.deviceType === 3">
|
||||
<el-option v-for="dict in dict.type.iot_location_way" :key="dict.value" :label="dict.label"
|
||||
:value="Number(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-21')" prop="longitude">
|
||||
<el-input v-model="form.longitude" :placeholder="$t('device.device-edit.148398-22')" type="number" :disabled="form.locationWay != 3">
|
||||
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank" :disabled="form.locationWay != 3">
|
||||
<el-input v-model="form.longitude" :placeholder="$t('device.device-edit.148398-22')" type="number"
|
||||
:disabled="form.locationWay != 3">
|
||||
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html"
|
||||
target="_blank" :disabled="form.locationWay != 3">
|
||||
{{ $t('device.device-edit.148398-23') }}
|
||||
</el-link>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-24')" prop="latitude">
|
||||
<el-input v-model="form.latitude" :placeholder="$t('device.device-edit.148398-25')" type="number" :disabled="form.locationWay != 3">
|
||||
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank" :disabled="form.locationWay != 3">
|
||||
<el-input v-model="form.latitude" :placeholder="$t('device.device-edit.148398-25')" type="number"
|
||||
:disabled="form.locationWay != 3">
|
||||
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html"
|
||||
target="_blank" :disabled="form.locationWay != 3">
|
||||
{{ $t('device.device-edit.148398-23') }}
|
||||
</el-link>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-26')" prop="networkAddress">
|
||||
<el-input v-model="form.networkAddress" :placeholder="$t('device.device-edit.148398-27')" :disabled="form.locationWay != 3" />
|
||||
<el-input v-model="form.networkAddress" :placeholder="$t('device.device-edit.148398-27')"
|
||||
:disabled="form.locationWay != 3"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-28')" prop="networkIp">
|
||||
<el-input v-model="form.networkIp" :placeholder="$t('device.device-edit.148398-29')" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-30')" prop="activeTime">
|
||||
<el-date-picker clearable v-model="form.activeTime" type="date" value-format="yyyy-MM-dd" :placeholder="$t('device.device-edit.148398-31')" disabled style="width: 100%"></el-date-picker>
|
||||
<el-date-picker clearable v-model="form.activeTime" type="date" value-format="yyyy-MM-dd"
|
||||
:placeholder="$t('device.device-edit.148398-31')" disabled
|
||||
style="width: 100%"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-32')" prop="rssi">
|
||||
<el-input v-model="form.rssi" :placeholder="$t('device.device-edit.148398-33')" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-34')" prop="remark" v-if="form.deviceId != 0">
|
||||
<dict-tag :options="dict.type.iot_device_status" :value="form.status" style="display: inline-block; margin-right: 8px" />
|
||||
<dict-tag :options="dict.type.iot_device_status" :value="form.status"
|
||||
style="display: inline-block; margin-right: 8px"/>
|
||||
<el-button size="small" @click="handleViewMqtt()">{{ $t('device.device-edit.148398-35') }}</el-button>
|
||||
<el-button size="small" @click="openCodeDialog()">{{ $t('device.device-edit.148398-36') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8" v-if="form.deviceId != 0">
|
||||
<div style="border: 1px solid #dfe4ed; border-radius: 5px; padding: 5px; text-align: center; line-height: 400px">
|
||||
<div
|
||||
style="border: 1px solid #dfe4ed; border-radius: 5px; padding: 5px; text-align: center; line-height: 400px">
|
||||
<div id="map" style="height: 435px; width: 100%">{{ $t('device.device-edit.148398-37') }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -258,7 +281,9 @@
|
||||
</el-tab-pane> -->
|
||||
<el-tab-pane name="deviceReturn" disabled>
|
||||
<span slot="label">
|
||||
<el-button type="info" size="mini" @click="goBack()">{{ $t('device.device-edit.148398-53') }}</el-button>
|
||||
<el-button type="info" size="mini" @click="goBack()">{{
|
||||
$t('device.device-edit.148398-53')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@ -351,8 +376,15 @@ import deviceFuncLog from './device-functionlog';
|
||||
import deviceSub from './device-sub';
|
||||
import deviceThingsModel from './device-things-model.vue';
|
||||
import vueQr from 'vue-qr';
|
||||
import { loadBMap } from '@/utils/map.js';
|
||||
import { deviceSynchronization, getDevice, addDevice, updateDevice, generatorDeviceNum, getMqttConnect } from '@/api/iot/device';
|
||||
import {loadMap} from '@/utils/map.js';
|
||||
import {
|
||||
deviceSynchronization,
|
||||
getDevice,
|
||||
addDevice,
|
||||
updateDevice,
|
||||
generatorDeviceNum,
|
||||
getMqttConnect
|
||||
} from '@/api/iot/device';
|
||||
import {getDeviceRunningStatus} from '@/api/iot/device';
|
||||
import {cacheJsonThingsModel} from '@/api/iot/model';
|
||||
import DeviceFunc from '@/views/iot/device/device-functionlog';
|
||||
@ -875,7 +907,7 @@ export default {
|
||||
/**加载地图*/
|
||||
loadMap() {
|
||||
this.$nextTick(() => {
|
||||
loadBMap().then(() => {
|
||||
loadMap().then(() => {
|
||||
this.getmap();
|
||||
});
|
||||
});
|
||||
@ -954,7 +986,8 @@ export default {
|
||||
//是否设备设置为禁用状态,则踢出设备
|
||||
if (this.form.status === 2) {
|
||||
const params = {clientId: this.form.serialNumber};
|
||||
clientOut(params).then((res) => {});
|
||||
clientOut(params).then((res) => {
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1033,7 +1066,8 @@ export default {
|
||||
},
|
||||
|
||||
// 获取选中的用户
|
||||
getUserData(user) {},
|
||||
getUserData(user) {
|
||||
},
|
||||
/**关闭物模型 */
|
||||
openSummaryDialog() {
|
||||
let json = {
|
||||
@ -1088,21 +1122,44 @@ export default {
|
||||
},
|
||||
// 地图定位
|
||||
getmap() {
|
||||
this.map = new BMap.Map('map');
|
||||
let point = null;
|
||||
if (this.form.longitude != null && this.form.longitude != '' && this.form.latitude != null && this.form.latitude != '') {
|
||||
point = new BMap.Point(this.form.longitude, this.form.latitude);
|
||||
} else {
|
||||
point = new BMap.Point(116.404, 39.915);
|
||||
// 清除旧地图实例
|
||||
if (this.map) {
|
||||
this.map.remove();
|
||||
this.map = null;
|
||||
}
|
||||
this.map.centerAndZoom(point, 19);
|
||||
this.map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
|
||||
this.map.addControl(new BMap.NavigationControl());
|
||||
|
||||
// 标注设备位置
|
||||
this.mk = new BMap.Marker(point);
|
||||
this.map.addOverlay(this.mk);
|
||||
this.map.panTo(point);
|
||||
// 使用Leaflet和高德地图
|
||||
let lat, lng;
|
||||
let parsedLat = parseFloat(this.form.latitude);
|
||||
let parsedLng = parseFloat(this.form.longitude);
|
||||
|
||||
// 验证坐标有效性
|
||||
if (!isNaN(parsedLat) && !isNaN(parsedLng) && parsedLat !== 0 && parsedLng !== 0) {
|
||||
lat = parsedLat;
|
||||
lng = parsedLng;
|
||||
} else {
|
||||
// 默认使用中国长沙坐标
|
||||
lat = 28.23;
|
||||
lng = 112.94;
|
||||
}
|
||||
|
||||
// 创建地图
|
||||
this.map = L.map('map').setView([lat, lng], 15);
|
||||
|
||||
// 添加高德地图图层(国内访问稳定)
|
||||
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
|
||||
subdomains: ['1', '2', '3', '4'],
|
||||
attribution: '© 高德地图',
|
||||
maxZoom: 18
|
||||
}).addTo(this.map);
|
||||
|
||||
// 添加标记点
|
||||
this.mk = L.marker([lat, lng]).addTo(this.map);
|
||||
|
||||
// 添加popup提示
|
||||
if (this.form.deviceName) {
|
||||
this.mk.bindPopup(`<b>${this.form.deviceName}</b><br>${this.form.networkAddress || ''}`).openPopup();
|
||||
}
|
||||
},
|
||||
// 生成随机字母和数字
|
||||
generateNum() {
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
<el-col :span="5" :xs="24">
|
||||
<el-card style="margin: 20px 0 20px 20px">
|
||||
<div class="menu-wrap">
|
||||
<el-input v-model="deptName" :placeholder="$t('device.device-linkage.188958-0')" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px; margin-right: 10px" />
|
||||
<el-input v-model="deptName" :placeholder="$t('device.device-linkage.188958-0')" clearable size="small"
|
||||
prefix-icon="el-icon-search" style="margin-bottom: 20px; margin-right: 10px"/>
|
||||
<el-tree
|
||||
:data="deptOptions"
|
||||
:props="defaultProps"
|
||||
@ -34,7 +35,8 @@
|
||||
style="margin-bottom: 20px; margin-right: 10px"
|
||||
@keydown.enter.native="getDeviceList"
|
||||
/>
|
||||
<el-menu class="menu-wrap" :default-active="deviceList[0] && deviceList[0].devcieId" :default-openeds="defaultOpeneds" @open="handleOpen" style="margin-right: 10px">
|
||||
<el-menu class="menu-wrap" :default-active="deviceList[0] && deviceList[0].devcieId"
|
||||
:default-openeds="defaultOpeneds" @open="handleOpen" style="margin-right: 10px">
|
||||
<el-submenu index="1" style="margin-left: -5px">
|
||||
<template slot="title">
|
||||
<i class="el-icon-menu"></i>
|
||||
@ -60,7 +62,8 @@
|
||||
<el-col :span="19" :xs="24">
|
||||
<el-card style="margin: 20px 20px 20px 0">
|
||||
<div class="head-container">
|
||||
<el-tabs v-model="activeName" tab-position="top" @tab-click="tabChange" style="min-height: 400px" v-if="devTotal > 0">
|
||||
<el-tabs v-model="activeName" tab-position="top" @tab-click="tabChange" style="min-height: 400px"
|
||||
v-if="devTotal > 0">
|
||||
<el-tab-pane name="basic">
|
||||
<span slot="label">{{ $t('device.device-edit.148398-0') }}</span>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
@ -68,7 +71,9 @@
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8">
|
||||
<el-form-item :label="$t('device.device-edit.148398-1')" prop="deviceName">
|
||||
<el-input v-model="form.deviceName" :placeholder="$t('device.device-edit.148398-2')">
|
||||
<el-button slot="append" @click="openSummaryDialog" v-if="form.deviceId != 0">{{ $t('device.device-edit.148398-3') }}</el-button>
|
||||
<el-button slot="append" @click="openSummaryDialog" v-if="form.deviceId != 0">
|
||||
{{ $t('device.device-edit.148398-3') }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="productName">
|
||||
@ -76,8 +81,12 @@
|
||||
<span style="color: red">*</span>
|
||||
{{ $t('device.device-edit.148398-4') }}
|
||||
</template>
|
||||
<el-input readonly v-model="form.productName" :placeholder="$t('device.allot-import-dialog.060657-1')" disabled>
|
||||
<el-button slot="append" @click="selectProduct()" disabled>{{ $t('device.device-edit.148398-6') }}</el-button>
|
||||
<el-input readonly v-model="form.productName"
|
||||
:placeholder="$t('device.allot-import-dialog.060657-1')" disabled>
|
||||
<el-button slot="append" @click="selectProduct()" disabled>{{
|
||||
$t('device.device-edit.148398-6')
|
||||
}}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="serialNumber">
|
||||
@ -85,11 +94,15 @@
|
||||
<span style="color: red">*</span>
|
||||
{{ $t('device.device-edit.148398-7') }}
|
||||
</template>
|
||||
<el-input v-model="form.serialNumber" :placeholder="$t('device.device-edit.148398-8')" disabled maxlength="32">
|
||||
<el-button v-if="form.deviceType !== 3" slot="append" @click="generateNum" :loading="genDisabled" disabled v-hasPermi="['iot:device:add']">
|
||||
<el-input v-model="form.serialNumber" :placeholder="$t('device.device-edit.148398-8')" disabled
|
||||
maxlength="32">
|
||||
<el-button v-if="form.deviceType !== 3" slot="append" @click="generateNum"
|
||||
:loading="genDisabled" disabled v-hasPermi="['iot:device:add']">
|
||||
{{ $t('device.device-edit.148398-9') }}
|
||||
</el-button>
|
||||
<el-button v-if="form.deviceType === 3" slot="append" @click="genSipID()" disabled v-hasPermi="['iot:device:add']">{{ $t('device.device-edit.148398-9') }}</el-button>
|
||||
<el-button v-if="form.deviceType === 3" slot="append" @click="genSipID()" disabled
|
||||
v-hasPermi="['iot:device:add']">{{ $t('device.device-edit.148398-9') }}
|
||||
</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="openServerTip">
|
||||
@ -103,18 +116,22 @@
|
||||
</template>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-12')" prop="firmwareVersion">
|
||||
<el-input v-model="form.firmwareVersion" :placeholder="$t('device.device-edit.148398-13')" type="number" step="0.1" :disabled="form.status != 1 || form.deviceType === 3">
|
||||
<el-input v-model="form.firmwareVersion" :placeholder="$t('device.device-edit.148398-13')"
|
||||
type="number" step="0.1" :disabled="form.status != 1 || form.deviceType === 3">
|
||||
<template slot="prepend">Version</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-14')" prop="isSimulate">
|
||||
<el-switch v-model="form.isSimulate" active-text="" inactive-text="" :active-value="1" :inactive-value="0" disabled></el-switch>
|
||||
<el-switch v-model="form.isSimulate" active-text="" inactive-text="" :active-value="1"
|
||||
:inactive-value="0" disabled></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-15')" prop="isShadow">
|
||||
<el-switch v-model="form.isShadow" active-text="" inactive-text="" :active-value="1" :inactive-value="0" disabled></el-switch>
|
||||
<el-switch v-model="form.isShadow" active-text="" inactive-text="" :active-value="1"
|
||||
:inactive-value="0" disabled></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-16')" prop="deviceStatus">
|
||||
<el-switch v-model="deviceStatus" active-text="" inactive-text="" disabled :active-value="1" :inactive-value="0" active-color="#F56C6C"></el-switch>
|
||||
<el-switch v-model="deviceStatus" active-text="" inactive-text="" disabled :active-value="1"
|
||||
:inactive-value="0" active-color="#F56C6C"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-edit.148398-17')" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :placeholder="$t('plzInput')" rows="1"/>
|
||||
@ -122,26 +139,35 @@
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8">
|
||||
<el-form-item :label="$t('device.device-edit.148398-19')" prop="locationWay">
|
||||
<el-select v-model="form.locationWay" :placeholder="$t('device.device-linkage.188958-25')" clearable size="small" style="width: 100%" :disabled="form.deviceType === 3">
|
||||
<el-option v-for="dict in dict.type.iot_location_way" :key="dict.value" :label="dict.label" :value="Number(dict.value)" />
|
||||
<el-select v-model="form.locationWay" :placeholder="$t('device.device-linkage.188958-25')"
|
||||
clearable size="small" style="width: 100%" :disabled="form.deviceType === 3">
|
||||
<el-option v-for="dict in dict.type.iot_location_way" :key="dict.value" :label="dict.label"
|
||||
:value="Number(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-linkage.188958-26')" prop="longitude">
|
||||
<el-input v-model="form.longitude" :placeholder="$t('device.device-linkage.188958-27')" type="number" disabled>
|
||||
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank" :disabled="form.locationWay != 3">
|
||||
<el-input v-model="form.longitude" :placeholder="$t('device.device-linkage.188958-27')"
|
||||
type="number" disabled>
|
||||
<el-link slot="append" :underline="false"
|
||||
href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank"
|
||||
:disabled="form.locationWay != 3">
|
||||
{{ $t('device.device-linkage.188958-28') }}
|
||||
</el-link>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-linkage.188958-29')" prop="latitude">
|
||||
<el-input v-model="form.latitude" :placeholder="$t('device.device-linkage.188958-30')" type="number" disabled>
|
||||
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank" :disabled="form.locationWay != 3">
|
||||
<el-input v-model="form.latitude" :placeholder="$t('device.device-linkage.188958-30')"
|
||||
type="number" disabled>
|
||||
<el-link slot="append" :underline="false"
|
||||
href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank"
|
||||
:disabled="form.locationWay != 3">
|
||||
{{ $t('device.device-linkage.188958-28') }}
|
||||
</el-link>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-linkage.188958-31')" prop="networkAddress">
|
||||
<el-input v-model="form.networkAddress" :placeholder="$t('device.device-linkage.188958-32')" disabled />
|
||||
<el-input v-model="form.networkAddress" :placeholder="$t('device.device-linkage.188958-32')"
|
||||
disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-linkage.188958-33')" prop="networkIp">
|
||||
<el-input v-model="form.networkIp" :placeholder="$t('device.device-linkage.188958-34')" disabled/>
|
||||
@ -160,14 +186,23 @@
|
||||
<el-form-item :label="$t('device.device-linkage.188958-37')" prop="rssi">
|
||||
<el-input v-model="form.rssi" :placeholder="$t('device.device-linkage.188958-38')" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('device.device-linkage.188958-39')" prop="remark" v-if="form.deviceId != 0">
|
||||
<dict-tag :options="dict.type.iot_device_status" :value="form.status" style="display: inline-block; margin-right: 8px" />
|
||||
<el-button size="small" @click="handleViewMqtt()">{{ $t('device.device-linkage.188958-40') }}</el-button>
|
||||
<el-button size="small" @click="openCodeDialog()">{{ $t('device.device-linkage.188958-41') }}</el-button>
|
||||
<el-form-item :label="$t('device.device-linkage.188958-39')" prop="remark"
|
||||
v-if="form.deviceId != 0">
|
||||
<dict-tag :options="dict.type.iot_device_status" :value="form.status"
|
||||
style="display: inline-block; margin-right: 8px"/>
|
||||
<el-button size="small" @click="handleViewMqtt()">{{
|
||||
$t('device.device-linkage.188958-40')
|
||||
}}
|
||||
</el-button>
|
||||
<el-button size="small" @click="openCodeDialog()">{{
|
||||
$t('device.device-linkage.188958-41')
|
||||
}}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8" v-if="form.deviceId != 0">
|
||||
<div style="border: 1px solid #dfe4ed; border-radius: 5px; padding: 5px; text-align: center; line-height: 400px">
|
||||
<div
|
||||
style="border: 1px solid #dfe4ed; border-radius: 5px; padding: 5px; text-align: center; line-height: 400px">
|
||||
<div id="map" style="height: 435px; width: 100%">{{ $t('device.device-linkage.188958-42') }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -230,7 +265,9 @@
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="alertUser" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3">
|
||||
<span slot="label" v-hasPermi="['iot:device:alert:user:list']">{{ $t('device.device-edit.148398-80') }}</span>
|
||||
<span slot="label" v-hasPermi="['iot:device:alert:user:list']">{{
|
||||
$t('device.device-edit.148398-80')
|
||||
}}</span>
|
||||
<alert-user ref="alertUser" :device="form"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="deviceAlert" :disabled="form.deviceId == 0">
|
||||
@ -269,7 +306,8 @@
|
||||
<instruction-parsing ref="instructionParsing" :device="form"/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="scada" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3 && isShowScada == true" lazy>
|
||||
<el-tab-pane name="scada" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3 && isShowScada == true"
|
||||
lazy>
|
||||
<span slot="label">{{ $t('device.device-edit.148398-73') }}</span>
|
||||
<device-scada ref="deviceScada" :device="form"/>
|
||||
</el-tab-pane>
|
||||
@ -294,7 +332,8 @@
|
||||
</el-tabs>
|
||||
<el-empty :description="$t('device.index.105953-41')" v-if="devTotal == 0"></el-empty>
|
||||
<!-- 设备配置JSON -->
|
||||
<el-dialog :title="$t('device.device-linkage.188958-54')" :visible.sync="openSummary" width="700px" append-to-body>
|
||||
<el-dialog :title="$t('device.device-linkage.188958-54')" :visible.sync="openSummary" width="700px"
|
||||
append-to-body>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="14">
|
||||
<div style="border: 1px solid #ccc; margin-top: -15px; height: 350px; width: 360px; overflow: scroll">
|
||||
@ -304,7 +343,8 @@
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<div style="border: 1px solid #ccc; width: 200px; text-align: center; margin-left: 20px; margin-top: -10px">
|
||||
<div
|
||||
style="border: 1px solid #ccc; width: 200px; text-align: center; margin-left: 20px; margin-top: -10px">
|
||||
<vue-qr :text="qrText" :size="200"></vue-qr>
|
||||
<div style="padding-bottom: 10px">{{ $t('device.device-linkage.188958-56') }}</div>
|
||||
</div>
|
||||
@ -321,7 +361,8 @@
|
||||
<div style="padding-bottom: 10px">{{ $t('device.device-linkage.188958-56') }}</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog :title="$t('device.device-linkage.188958-58')" :visible.sync="openViewMqtt" width="600px" append-to-body>
|
||||
<el-dialog :title="$t('device.device-linkage.188958-58')" :visible.sync="openViewMqtt" width="600px"
|
||||
append-to-body>
|
||||
<el-form ref="listQuery" :model="listQuery" :rules="rules" label-width="150px">
|
||||
<el-form-item label="clientId" prop="clientId">
|
||||
<el-input v-model="listQuery.clientId" disabled style="width: 80%"/>
|
||||
@ -337,7 +378,10 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button class="btns" type="primary" @click="doCopy(2)">{{ $t('device.device-linkage.188958-59') }}</el-button>
|
||||
<el-button class="btns" type="primary" @click="doCopy(2)">{{
|
||||
$t('device.device-linkage.188958-59')
|
||||
}}
|
||||
</el-button>
|
||||
<el-button @click="closeSummaryDialog">{{ $t('device.device-linkage.188958-57') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@ -366,8 +410,15 @@ import deviceFuncLog from './device-functionlog';
|
||||
import deviceSub from './device-sub';
|
||||
import alertUser from './alert-user';
|
||||
import vueQr from 'vue-qr';
|
||||
import { loadBMap } from '@/utils/map.js';
|
||||
import { deviceSynchronization, getDevice, addDevice, updateDevice, generatorDeviceNum, getMqttConnect } from '@/api/iot/device';
|
||||
import {loadMap} from '@/utils/map.js';
|
||||
import {
|
||||
deviceSynchronization,
|
||||
getDevice,
|
||||
addDevice,
|
||||
updateDevice,
|
||||
generatorDeviceNum,
|
||||
getMqttConnect
|
||||
} from '@/api/iot/device';
|
||||
import {getDeviceUser} from '@/api/iot/deviceuser';
|
||||
import {getUserId} from '@/utils/auth';
|
||||
import {getDeviceRunningStatus} from '@/api/iot/device';
|
||||
@ -980,7 +1031,7 @@ export default {
|
||||
/**加载地图*/
|
||||
loadMap() {
|
||||
this.$nextTick(() => {
|
||||
loadBMap().then(() => {
|
||||
loadMap().then(() => {
|
||||
this.getmap();
|
||||
});
|
||||
});
|
||||
@ -1057,7 +1108,8 @@ export default {
|
||||
//是否设备设置为禁用状态,则踢出设备
|
||||
if (this.form.status === 2) {
|
||||
const params = {clientId: this.form.serialNumber};
|
||||
clientOut(params).then((res) => {});
|
||||
clientOut(params).then((res) => {
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1145,7 +1197,8 @@ export default {
|
||||
});
|
||||
},
|
||||
// 获取选中的用户
|
||||
getUserData(user) {},
|
||||
getUserData(user) {
|
||||
},
|
||||
/**关闭物模型 */
|
||||
openSummaryDialog() {
|
||||
let json = {
|
||||
@ -1185,20 +1238,40 @@ export default {
|
||||
},
|
||||
// 地图定位
|
||||
getmap() {
|
||||
this.map = new BMap.Map('map');
|
||||
let point = null;
|
||||
if (this.form.longitude != null && this.form.longitude != '' && this.form.latitude != null && this.form.latitude != '') {
|
||||
point = new BMap.Point(this.form.longitude, this.form.latitude);
|
||||
} else {
|
||||
point = new BMap.Point(116.404, 39.915);
|
||||
// 清除旧地图实例
|
||||
if (this.map) {
|
||||
this.map.remove();
|
||||
this.map = null;
|
||||
}
|
||||
|
||||
// 使用Leaflet和OpenStreetMap
|
||||
let lat, lng;
|
||||
if (this.form.latitude != null && this.form.latitude != '' && this.form.longitude != null && this.form.longitude != '') {
|
||||
lat = parseFloat(this.form.latitude);
|
||||
lng = parseFloat(this.form.longitude);
|
||||
} else {
|
||||
// 默认使用北京天安门坐标
|
||||
lat = 39.915;
|
||||
lng = 116.404;
|
||||
}
|
||||
|
||||
// 创建地图
|
||||
this.map = L.map('map').setView([lat, lng], 15);
|
||||
|
||||
// 添加高德地图图层(国内访问稳定)
|
||||
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
|
||||
subdomains: ['1', '2', '3', '4'],
|
||||
attribution: '© 高德地图',
|
||||
maxZoom: 18
|
||||
}).addTo(this.map);
|
||||
|
||||
// 添加标记点
|
||||
this.mk = L.marker([lat, lng]).addTo(this.map);
|
||||
|
||||
// 添加popup提示
|
||||
if (this.form.deviceName) {
|
||||
this.mk.bindPopup(`<b>${this.form.deviceName}</b><br>${this.form.networkAddress || ''}`).openPopup();
|
||||
}
|
||||
this.map.centerAndZoom(point, 19);
|
||||
this.map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
|
||||
this.map.addControl(new BMap.NavigationControl());
|
||||
// 标注设备位置
|
||||
this.mk = new BMap.Marker(point);
|
||||
this.map.addOverlay(this.mk);
|
||||
this.map.panTo(point);
|
||||
},
|
||||
// 生成随机字母和数字
|
||||
generateNum() {
|
||||
@ -1256,6 +1329,7 @@ export default {
|
||||
margin-top: -10px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
@ -31,19 +31,25 @@
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<div class="content-value">
|
||||
<!-- 根据format选择显示HEX或ASCII格式 -->
|
||||
<div v-if="format === 'Hex' && item.value" class="data-format-item">
|
||||
<span class="format-label">HEX:</span>
|
||||
<span class="hex-value">{{ item.value }}</span>
|
||||
</div>
|
||||
<div v-if="format === 'ASCII' && item.valueAscii" class="data-format-item ascii-item">
|
||||
<span class="format-label">ASCII:</span>
|
||||
<pre class="ascii-value">{{ item.valueAscii }}</pre>
|
||||
</div>
|
||||
<div v-if="format === 'JSON'" class="data-format-item">
|
||||
<!-- 自动识别并展示所有可用格式 -->
|
||||
<!-- JSON格式优先展示(如果是有效JSON) -->
|
||||
<div v-if="isValidJson(item.valueAscii || item.value)" class="data-format-item json-item">
|
||||
<span class="format-label">JSON:</span>
|
||||
<pre class="json-value">{{ formatJsonValue(item.value, item.valueAscii) }}</pre>
|
||||
</div>
|
||||
<!-- 非JSON时展示HEX和ASCII -->
|
||||
<template v-else>
|
||||
<!-- HEX格式 -->
|
||||
<div v-if="item.value" class="data-format-item">
|
||||
<span class="format-label">HEX:</span>
|
||||
<span class="hex-value">{{ item.value }}</span>
|
||||
</div>
|
||||
<!-- ASCII格式(如果有可读内容) -->
|
||||
<div v-if="item.valueAscii && hasReadableAscii(item.valueAscii)" class="data-format-item ascii-item">
|
||||
<span class="format-label">ASCII:</span>
|
||||
<pre class="ascii-value">{{ item.valueAscii }}</pre>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="analysis-data" v-if="item.type != 0 && item.analysis">
|
||||
@ -564,6 +570,24 @@ export default {
|
||||
}
|
||||
// 如果都不是JSON,返回提示信息
|
||||
return '数据不是有效的JSON格式';
|
||||
},
|
||||
/**判断是否为有效的JSON */
|
||||
isValidJson(value) {
|
||||
if (!value) return false;
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
// 确保是对象或数组,而不是简单值
|
||||
return typeof parsed === 'object' && parsed !== null;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
/**判断ASCII是否包含可读内容 */
|
||||
hasReadableAscii(asciiValue) {
|
||||
if (!asciiValue) return false;
|
||||
// 检查是否有可打印字符(排除纯控制字符)
|
||||
const printableRegex = /[\x20-\x7E]/;
|
||||
return printableRegex.test(asciiValue) && asciiValue.trim().length > 0;
|
||||
},
|
||||
/**打开编辑框 */
|
||||
openEdit() {
|
||||
@ -990,6 +1014,11 @@ $right-btn-color: #1890ff;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// 高度 = 头部36px + 内容700px + 底部64px
|
||||
height: 800px;
|
||||
|
||||
.right-head {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
@ -997,19 +1026,28 @@ $right-btn-color: #1890ff;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// 覆盖通用 .content 样式
|
||||
.content.beautify-scroll-def {
|
||||
flex: 1;
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.quick-item {
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
margin: 0 auto 12px auto;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
margin-top: 12px;
|
||||
border: 1px solid $right-btn-color;
|
||||
color: $right-btn-color;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 12px;
|
||||
&:first-child {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user