650 lines
18 KiB
Vue
650 lines
18 KiB
Vue
<template>
|
||
<div class="device-run-starts-wrap">
|
||
<div class="cmd-list">
|
||
<div class="cmd-title-wrap">
|
||
分组名称:
|
||
<el-select v-model="selectedGroup" placeholder="请选择">
|
||
<el-option v-for="item in groupOptions" :key="item.value" :label="item.label" :value="item.value">
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
<div v-if="filteredProperties.length <= 0" style="width:100%; padding: 100px;text-align: center">
|
||
<i class="el-icon-s-order" style="font-size: 50px;color: #999"></i>
|
||
<div style="color: #909399;margin-top: 10px">暂无数据</div>
|
||
</div>
|
||
<div v-for="(item, index) in filteredProperties" :key="index" class="param-item2">
|
||
<div class="title-top">
|
||
<span class="name-wr">{{ item.name }}</span>
|
||
<span class="type-wr" @click="handleShowData(item)">查看</span>
|
||
</div>
|
||
<div class="value-info">
|
||
<div class="value-wrap">
|
||
<span class="val-span">
|
||
{{ formatValue(item) }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="time-w">
|
||
<span class="time-warp">{{ item.valueParams.unit || '' }}</span>
|
||
<span class="time">{{ item.timestamp }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<el-dialog :close-on-click-modal="false" :visible.sync="dialogShow" append-to-body class="device-run-state-dailog"
|
||
title="查看数据" width="700px" @close="dialogCloseCell" @opened="dialogOpen">
|
||
<run-state-table ref="showChart" :deviceId="sourceId" :deviceKey="deviceInfo.deviceKey" :dialogData="dialogData"
|
||
:dialogShow="dialogShow" :pro_type="dialogData.funDataType" :prodId="prodId" />
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button size="small" @click="dialogShow = false">关 闭</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
<script>
|
||
import { getDeviceFunList, getDeviceCmdList } from "@/api/iot/device";
|
||
import { iotWebSocketBaseUrl } from "@/config/env";
|
||
import RunStateTable from "./table";
|
||
import moment from "moment";
|
||
export default {
|
||
name: "RunStartsWrap",
|
||
props: ["prodId", "sourceId", "deviceInfo", "wsUrl", "realTimeData"],
|
||
components: {
|
||
RunStateTable
|
||
},
|
||
data() {
|
||
return {
|
||
cmdList: [
|
||
{
|
||
cmdKey: "",
|
||
cmdName: "全部"
|
||
}
|
||
],
|
||
cmdObject: {},
|
||
stompClient: null,
|
||
deviceKey: "",
|
||
socket_flag: true,
|
||
dialogData: {},
|
||
dialogShow: false,
|
||
firstWsMassage: true,
|
||
prodObj: {
|
||
properties: [],
|
||
events: []
|
||
},
|
||
filterProdObj: {
|
||
properties: [],
|
||
events: []
|
||
},
|
||
runtimeProperties: [],
|
||
selectedGroup: "all",
|
||
metadata:{
|
||
properties: [],
|
||
propertyGroups: []
|
||
}
|
||
};
|
||
},
|
||
computed: {
|
||
groupOptions() {
|
||
|
||
const groups = this.metadata?.propertyGroups || [];
|
||
return [
|
||
{ label: '全部', value: 'all' },
|
||
...groups.map((group) => ({ label: group.name, value: group.id })),
|
||
];
|
||
},
|
||
filteredProperties() {
|
||
let properties = [...this.runtimeProperties];
|
||
|
||
if (this.selectedGroup !== 'all') {
|
||
const group = (this.metadata?.propertyGroups || []).find(
|
||
(g) => g.id === this.selectedGroup,
|
||
);
|
||
if (group?.properties) {
|
||
const ids = new Set(group.properties.map((p) => p.id));
|
||
properties = properties.filter((p) => ids.has(p.id));
|
||
}
|
||
}
|
||
|
||
// properties = properties.filter((p) => {
|
||
// const type = p.expands?.type || 'R';
|
||
// return selectedTypes.value.includes(type);
|
||
// });
|
||
|
||
return properties;
|
||
}
|
||
},
|
||
created() {
|
||
this.getMetaDate();
|
||
this.getProdObj();
|
||
// this.getCmdList();
|
||
|
||
// this.connection();
|
||
},
|
||
methods: {
|
||
getMetaDate(){
|
||
try {
|
||
this.metadata = JSON.parse(this.deviceInfo.metadata);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
},
|
||
changeCmd(e) {
|
||
if (e != "") {
|
||
const filterObj =
|
||
this.prodObj.properties.filter(item => item.cmdKey === e) || [];
|
||
this.$nextTick(() => {
|
||
this.$set(this.filterProdObj, "properties", filterObj);
|
||
});
|
||
} else {
|
||
this.$nextTick(() => {
|
||
this.$set(this.filterProdObj, "properties", this.prodObj.properties);
|
||
});
|
||
}
|
||
},
|
||
formatValue(property) {
|
||
const { value, valueParams } = property;
|
||
if (value === undefined || value === null) return '--';
|
||
|
||
let displayValue = value;
|
||
|
||
if (valueParams?.formType === 'input' && valueParams?.length) {
|
||
displayValue = value.slice(0, valueParams.length);
|
||
}
|
||
|
||
if (valueParams?.formType === 'switch') {
|
||
return value.toString() === valueParams.trueValue
|
||
? valueParams.trueText
|
||
: valueParams.falseText;
|
||
}
|
||
|
||
if (valueParams?.formType === 'select') {
|
||
return valueParams.enumConf.find((item) => item.value === value)?.text;
|
||
}
|
||
|
||
if (valueParams?.formType === 'time' && valueParams?.dataType !== 'string') {
|
||
return moment(value).format(valueParams.format);
|
||
}
|
||
|
||
if (
|
||
valueParams?.formType === 'number' ||
|
||
valueParams?.formType === 'progress'
|
||
) {
|
||
if (valueParams?.scale) return value.toFixed(valueParams.scale);
|
||
return value;
|
||
}
|
||
|
||
return displayValue;
|
||
},
|
||
getProdObj() {
|
||
if (this.metadata.properties) {
|
||
let list = this.metadata.properties.filter((item) => item.show === true) || [];
|
||
let properties = list.map(item => ({
|
||
...item,
|
||
value: null,
|
||
timestamp: moment().format('YYYY-MM-DD HH:mm:ss')
|
||
}));
|
||
this.runtimeProperties = properties;
|
||
this.$nextTick(() => {
|
||
this.$set(this, "runtimeProperties", properties);
|
||
|
||
});
|
||
} else {
|
||
this.runtimeProperties = [];
|
||
}
|
||
this.connection();
|
||
},
|
||
formatTime(date) {
|
||
// 检查时间戳长度
|
||
if (date && date.toString().length === 10) {
|
||
// 10 位时间戳
|
||
return moment(date * 1000).format("YYYY-MM-DD HH:mm:ss");
|
||
} else if (date && date.toString().length === 13) {
|
||
// 13 位时间戳
|
||
return moment(date).format("YYYY-MM-DD HH:mm:ss");
|
||
} else {
|
||
return date;
|
||
}
|
||
},
|
||
// 查看数据
|
||
handleShowData(row) {
|
||
row.chartDate = new Date();
|
||
this.dialogData = row;
|
||
this.dialogShow = true;
|
||
},
|
||
dialogOpen() {
|
||
this.$refs.showChart.initDialog(this.dialogData);
|
||
},
|
||
dialogCloseCell() {
|
||
this.$refs.showChart.close();
|
||
},
|
||
// 创建ws
|
||
connection() {
|
||
if (this.stompClient) {
|
||
return;
|
||
}
|
||
if (!this.wsUrl) {
|
||
return;
|
||
}
|
||
// let locahostUrl = 'ws://192.168.18.138/device/ws/dev/send/'
|
||
let headers = {
|
||
clientid: this.deviceInfo.wsClientId,
|
||
username: this.deviceInfo.wsUsername,
|
||
sign: this.deviceInfo.wsSign
|
||
};
|
||
this.stompClient = new WebSocket(
|
||
`${this.wsUrl}${headers.clientid}/${headers.username}/${headers.sign}`
|
||
);
|
||
this.stompClient.onmessage = this.socket_onmsg;
|
||
this.stompClient.onclose = this.socket_onclose;
|
||
},
|
||
socket_onmsg(evt) {
|
||
console.log("evt.data", evt.data);
|
||
this.setListData(evt.data);
|
||
},
|
||
setListData(data) {
|
||
// this.recursionSet(this.cmdList, JSON.parse(data));
|
||
this.recursionSet("", JSON.parse(data));
|
||
this.firstWsMassage = false;
|
||
this.$forceUpdate();
|
||
},
|
||
recursionSet(list, result) {
|
||
if (result.type === "result" && result.topic.endsWith('/report') && result.payload) {
|
||
// 更函数式的写法,避免直接修改
|
||
this.runtimeProperties = this.runtimeProperties.map(property => {
|
||
const propValue = result.payload.value[property.id];
|
||
if (propValue !== undefined) {
|
||
return {
|
||
...property,
|
||
value: propValue,
|
||
timestamp: moment(result.payload.timeString).format('YYYY-MM-DD HH:mm:ss')
|
||
};
|
||
}
|
||
return property;
|
||
});
|
||
// 更新实时属性数据
|
||
// Object.entries(result.payload).forEach(([propId, propValue]) => {
|
||
// const property = this.runtimeProperties.find(
|
||
// (p) => p.id === propId,
|
||
// );
|
||
// if (property) {
|
||
// property.value = propValue;
|
||
// property.timestamp = moment(data.payload.timeString).format(
|
||
// 'YYYY-MM-DD HH:mm:ss',
|
||
// );
|
||
// }
|
||
// });
|
||
}
|
||
// if (result.type === "properties") {
|
||
// if (result.tags.device_key === this.deviceInfo.deviceKey) {
|
||
// this.prodObj.properties = this.prodObj.properties.map(item => ({
|
||
// ...item,
|
||
// ...(item.funKey in result.properties && {
|
||
// lastValue: result.properties[item.funKey],
|
||
// lastTime: result.properties.timestamp
|
||
// })
|
||
// }));
|
||
// this.filterProdObj.properties = this.filterProdObj.properties.map(
|
||
// item => ({
|
||
// ...item,
|
||
// ...(item.funKey in result.properties && {
|
||
// lastValue: result.properties[item.funKey],
|
||
// lastTime: result.properties.timestamp
|
||
// })
|
||
// })
|
||
// );
|
||
// }
|
||
// }
|
||
// if (result.type === "state") {
|
||
// this.$emit("updateDeviceState", {
|
||
// deviceKey: this.deviceInfo.deviceKey,
|
||
// state: result.state
|
||
// });
|
||
// }
|
||
|
||
|
||
// for (var i = 0; i < list.length; i++) {
|
||
// // if (this.firstWsMassage) {
|
||
// // // result["cmd"] && list[i]['cmdKey'] === result["cmd"]
|
||
// // // if (result["cmd"] && list[i]['cmdKey'] === result["cmd"]) {
|
||
// // for (var v = 0; v < list[i].children.length; v++) {
|
||
// // if (
|
||
// // result.params[list[i].children[v]["funKey"]] !== null &&
|
||
// // result.params[list[i].children[v]["funKey"]] !== undefined
|
||
// // ) {
|
||
// // list[i].children[v]["lastValue"] =
|
||
// // result.params[list[i].children[v]["funKey"]];
|
||
// // list[i].children[v]["lastTime"] = result.params["timestamp"]
|
||
// // ? result.params["timestamp"]
|
||
// // : "";
|
||
// // }
|
||
// // }
|
||
// // // }
|
||
// // } else {
|
||
// if (result["cmd"] && list[i]["cmdKey"] === result["cmd"]) {
|
||
// console.log("list[i].children",list[i])
|
||
// for (var v = 0; v < list[i].children.length; v++) {
|
||
// if (
|
||
// result.params[list[i].children[v]["funKey"]] !== null &&
|
||
// result.params[list[i].children[v]["funKey"]] !== undefined
|
||
// ) {
|
||
// list[i].children[v]["lastValue"] = result.params[list[i].children[v]["funKey"]];
|
||
// list[i].children[v]["lastTime"] = result.params["timestamp"] ? result.params["timestamp"] : "";
|
||
// }
|
||
// }
|
||
// break;
|
||
// }
|
||
// // }
|
||
// }
|
||
},
|
||
socket_onclose(e) {
|
||
this.stompClient = null;
|
||
if (this.socket_flag) {
|
||
this.socket_flag = false;
|
||
let self = this;
|
||
setTimeout(function () {
|
||
self.socket_flag = true;
|
||
self.connection();
|
||
}, 10000);
|
||
}
|
||
},
|
||
async forGetParams(row, index) {
|
||
const param = {
|
||
cmdId: row.cmdId,
|
||
deviceId: this.deviceInfo.deviceId,
|
||
cmdKey: row.cmdKey,
|
||
deviceKey: this.deviceInfo.deviceKey
|
||
};
|
||
try {
|
||
const res = await getDeviceFunList(param);
|
||
if (res.data.length > 0) {
|
||
let list = res.data.filter(item => item.show === true) || [];
|
||
row.children = list.map(item => {
|
||
if (item.dataFormat) {
|
||
let dataFormat = JSON.parse(item.dataFormat);
|
||
item.dataFormatType = dataFormat.type;
|
||
if (dataFormat.list && dataFormat.type === "ENUM") {
|
||
try {
|
||
item.dataFormatObj = JSON.parse(
|
||
dataFormat.list.replace(/\\/g, "")
|
||
);
|
||
} catch (e) {
|
||
item.dataFormatObj = {};
|
||
}
|
||
}
|
||
}
|
||
return item;
|
||
});
|
||
} else {
|
||
row.children = [];
|
||
}
|
||
this.$forceUpdate();
|
||
} catch (error) {
|
||
console.error(`Error fetching data for row ${index}:`, error);
|
||
}
|
||
},
|
||
lengthReSize(str) {
|
||
if (str.toString().length < 18 && str.toString().length > 12) {
|
||
return "font-size: 18px;";
|
||
} else if (str.toString().length > 18) {
|
||
return "font-size: 18px; white-space: nowrap; display: inline-block;width: 80%; overflow: hidden; text-overflow: ellipsis;";
|
||
} else {
|
||
return "";
|
||
}
|
||
},
|
||
getCmdList() {
|
||
const params = {
|
||
deviceId: this.deviceInfo.deviceId,
|
||
cmdType: "1"
|
||
};
|
||
getDeviceCmdList(params).then(response => {
|
||
if (response.data && response.data.length > 0) {
|
||
this.cmdList = [
|
||
{
|
||
cmdKey: "",
|
||
cmdName: "全部"
|
||
},
|
||
...response.data
|
||
];
|
||
}
|
||
this.connection();
|
||
}).catch(error => {
|
||
this.connection();
|
||
});
|
||
},
|
||
closeWebscoket() {
|
||
if (this.stompClient) {
|
||
this.stompClient.close();
|
||
}
|
||
this.socket_flag = false;
|
||
this.stompClient = null;
|
||
clearTimeout(this.setTimeOut_flag);
|
||
},
|
||
async processAllRequests(data) {
|
||
try {
|
||
await Promise.all(
|
||
data.map(async (row, index) => {
|
||
await this.forGetParams(row, index);
|
||
})
|
||
);
|
||
this.connection();
|
||
} catch (error) {
|
||
console.error("Error processing all requests:", error);
|
||
}
|
||
}
|
||
},
|
||
destroyed() {
|
||
this.closeWebscoket();
|
||
},
|
||
watch: {
|
||
// cmdList(val) {
|
||
// if (val) {
|
||
// // val.forEach((v, index) => {
|
||
// // this.forGetParmas(v, index);
|
||
// // });
|
||
// // setTimeout(this.connection, 3000);
|
||
// // this.connection()
|
||
// this.processAllRequests(val);
|
||
// }
|
||
// },
|
||
realTimeData: {
|
||
handler: function () {
|
||
this.setListData(this.realTimeData);
|
||
},
|
||
deep: true
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<style lang="scss">
|
||
.device-run-starts-wrap {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
overflow: auto;
|
||
|
||
//padding: 10px;
|
||
.el-button--medium {
|
||
position: absolute;
|
||
right: 30px;
|
||
}
|
||
|
||
.cmd-list {
|
||
width: 100%;
|
||
/* height: auto; */
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
cursor: default;
|
||
padding: 10px;
|
||
|
||
&:first-child {
|
||
padding-top: 0;
|
||
}
|
||
|
||
.cmd-title-wrap {
|
||
width: 100%;
|
||
display: flex;
|
||
// border-bottom: 1px solid #bdb7b7;
|
||
font-size: 16px;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
|
||
.cmd-title {
|
||
font-size: 14px;
|
||
color: #a9a6a6;
|
||
font-size: 16px;
|
||
color: #f35151;
|
||
letter-spacing: 1px;
|
||
}
|
||
}
|
||
|
||
.param-item {
|
||
height: 130px;
|
||
// border: 1px solid #777474;
|
||
width: 250px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
margin-right: 10px;
|
||
margin-top: 10px;
|
||
border-radius: 2px;
|
||
padding: 10px;
|
||
justify-content: flex-start;
|
||
align-items: flex-start;
|
||
margin: 0;
|
||
margin-left: 15px;
|
||
margin-top: 15px;
|
||
box-shadow: 0px 0px 3px 0px #b7b4b4;
|
||
|
||
.title-top {
|
||
height: 30px;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
width: 100%;
|
||
border-bottom: 1px dotted #c5c3c3;
|
||
padding-bottom: 3px;
|
||
justify-content: space-between;
|
||
|
||
.name-wr {
|
||
font-size: 18px;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.type-wr {
|
||
font-size: 14px;
|
||
color: #1890ff;
|
||
}
|
||
}
|
||
|
||
.value-info {
|
||
height: 55px;
|
||
display: flex;
|
||
margin-top: 5px;
|
||
align-items: center;
|
||
width: 100%;
|
||
|
||
.value-wrap {}
|
||
|
||
.val-span {
|
||
color: #03a9f4;
|
||
font-size: 20px;
|
||
width: 280px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
display: inline-block;
|
||
}
|
||
}
|
||
|
||
.time-w {
|
||
margin-top: 5px;
|
||
font-size: 14px;
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #908c8c;
|
||
}
|
||
}
|
||
|
||
.param-item2 {
|
||
height: 150px;
|
||
width: 300px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
border-radius: 0px;
|
||
padding: 10px;
|
||
justify-content: flex-start;
|
||
align-items: flex-start;
|
||
margin: 0;
|
||
border: 1px solid #b7b4b4;
|
||
margin-left: -1px;
|
||
margin-top: -1px;
|
||
border-color: #e0e0e0;
|
||
|
||
.title-top {
|
||
height: 30px;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
width: 100%;
|
||
border-bottom: 1px dotted #c5c3c3;
|
||
padding-bottom: 3px;
|
||
justify-content: space-between;
|
||
|
||
.name-wr {
|
||
font-size: 18px;
|
||
// color: #1890ff;
|
||
}
|
||
|
||
.type-wr {
|
||
font-size: 14px;
|
||
// color: #606266;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.type-wr:hover {
|
||
color: #1890ff;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
|
||
.value-info {
|
||
height: 55px;
|
||
display: flex;
|
||
margin-top: 5px;
|
||
align-items: center;
|
||
width: 100%;
|
||
|
||
.value-wrap {}
|
||
|
||
.val-span {
|
||
color: #03a9f4;
|
||
font-size: 20px;
|
||
width: 280px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
display: inline-block;
|
||
}
|
||
}
|
||
|
||
.time-w {
|
||
margin-top: 5px;
|
||
font-size: 14px;
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #908c8c;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.device-run-state-dailog {
|
||
.el-dialog__header {
|
||
border-bottom: 1px solid #b6b6b6;
|
||
}
|
||
|
||
.el-dialog__footer {
|
||
border-top: 1px solid #b6b6b6;
|
||
padding-bottom: 10px;
|
||
}
|
||
}
|
||
</style>
|