381 lines
12 KiB
Vue
381 lines
12 KiB
Vue
![]() |
<template>
|
||
|
<view class="back" :style="{'backgroundColor': template.bgColor,}">
|
||
|
<image :src="template.bgImg" mode="aspectFill" class="full-screen"></image>
|
||
|
<view class="content">
|
||
|
<view v-for="(item,index) in components" :key="index"
|
||
|
:style="{ 'marginTop':item.setStyle.marginTop+'px','marginBottom':item.setStyle.marginBottom+'px' }">
|
||
|
<view
|
||
|
v-if="item.component !== 'hstoricalDataGauge' && item.component !== 'captionText' && device.thingsModels">
|
||
|
<view v-for="(param,paramindex) in item.setConfig.attributes" :key="paramindex">
|
||
|
<view v-if="item.component === 'textDisplay1'">
|
||
|
<textDisplay1Vue :backColor="item.setStyle.backColor" :nameColor="item.setStyle.nameColor"
|
||
|
:statusColor="item.setStyle.statusColor" :showIcon="item.setStyle.showIcon"
|
||
|
:iconColor="item.setStyle.iconColor" :iconBackColor="item.setStyle.iconBackColor"
|
||
|
:templateName="param.templateName" :value="param" :device="device"
|
||
|
@send-Service="handelSendService" ref="textDisplay1Vue" />
|
||
|
</view>
|
||
|
<view v-if="item.component === 'numDisplay1'">
|
||
|
<numDisplay1Vue :backColor="item.setStyle.backColor" :nameColor="item.setStyle.nameColor"
|
||
|
:numColor="item.setStyle.numColor" :showIcon="item.setStyle.showIcon"
|
||
|
:iconColor="item.setStyle.iconColor" :iconBackColor="item.setStyle.iconBackColor"
|
||
|
:templateName="param.templateName" :value="param" ref="numDisplay1Vue" />
|
||
|
</view>
|
||
|
<view v-if="item.component === 'numControl1'">
|
||
|
<numControl1Vue :backColor="item.setStyle.backColor" :nameColor="item.setStyle.nameColor"
|
||
|
:numColor="item.setStyle.numColor" :showIcon="item.setStyle.showIcon"
|
||
|
:iconColor="item.setStyle.iconColor" :iconBackColor="item.setStyle.iconBackColor"
|
||
|
:templateName="param.templateName" :value="param" :device="device" :unit="param.unit"
|
||
|
@send-Service="handelSendService" ref="numControl1Vue" />
|
||
|
</view>
|
||
|
<view v-if="item.component === 'mulStatusControl1'">
|
||
|
<mulStatusControl1Vue :rowNum="item.setStyle.rowNum" :fontSize="item.setStyle.fontSize"
|
||
|
:figureHeight="item.setStyle.figureHeight" :borderRadius="item.setStyle.borderRadius"
|
||
|
:backColor="item.setStyle.backColor" :nameColor="item.setStyle.nameColor"
|
||
|
:noColor="item.setStyle.noColor" :offColor="item.setStyle.offColor"
|
||
|
:noBackColor="item.setStyle.noBackColor" :offBackColor="item.setStyle.offBackColor"
|
||
|
:templateName="param.templateName" :enumList="param.enumList" :value="param"
|
||
|
:device="device" ref="mulStatusControl1Vue" @send-Service="handelSendService" />
|
||
|
</view>
|
||
|
<view v-if="item.component === 'btnControl1'">
|
||
|
<btnControl1Vue :backColor="item.setStyle.backColor" :nameColor="item.setStyle.nameColor"
|
||
|
:model="item.setStyle.model" :btnColor="item.setStyle.btnColor"
|
||
|
:templateName="param.templateName" :value="param" :device="device" ref="btnControl1Vue"
|
||
|
@send-Service="handelSendService" />
|
||
|
</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
|
||
|
<view v-if="item.component === 'hstoricalDataGauge' && device.thingsModels">
|
||
|
<u-grid :col="item.setStyle.rowNum">
|
||
|
<u-grid-item v-for="(param,paramindex) in item.setConfig.attributes" :key="paramindex">
|
||
|
<hstoricalDataGaugeVue :width="item.setStyle.width" :backColor="item.setStyle.backColor"
|
||
|
:nameColor="item.setStyle.nameColor" :loopColor="item.setStyle.loopColor"
|
||
|
:numColor="item.setStyle.numColor" :templateName="param.templateName" :value="param"
|
||
|
ref="hstoricalDataGaugeVue" />
|
||
|
</u-grid-item>
|
||
|
</u-grid>
|
||
|
</view>
|
||
|
<view v-if="item.component === 'captionText'">
|
||
|
<captionTextVue :name="item.setStyle.name" :description="item.setStyle.description"
|
||
|
:wordSize="item.setStyle.wordSize" :descriptionSize="item.setStyle.descriptionSize"
|
||
|
:wordWeight="item.setStyle.wordWeight" :positions="item.setStyle.positions"
|
||
|
:descriptionWeight="item.setStyle.descriptionWeight" :wordColor="item.setStyle.wordColor"
|
||
|
:descriptionColor="item.setStyle.descriptionColor" :backColor="item.setStyle.backColor"
|
||
|
:wordHeight="item.setStyle.wordHeight" />
|
||
|
</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
|
||
|
</view>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import textDisplay1Vue from '../drag/components/textDisplay1.vue';
|
||
|
import numDisplay1Vue from '../drag/components/numDisplay1.vue';
|
||
|
import numControl1Vue from '../drag/components/numControl1.vue';
|
||
|
import mulStatusControl1Vue from '../drag/components/mulStatusControl1.vue';
|
||
|
import btnControl1Vue from '../drag/components/btnControl1.vue';
|
||
|
import hstoricalDataGaugeVue from '../drag/components/hstoricalDataGauge.vue';
|
||
|
import captionTextVue from '../drag/components/captionText.vue';
|
||
|
import {
|
||
|
listThingsModel
|
||
|
} from '@/apis/modules/device.js';
|
||
|
import {
|
||
|
getOrderControl
|
||
|
} from '@/apis/modules/device.js';
|
||
|
import {
|
||
|
serviceInvoke
|
||
|
} from '@/apis/modules/runtime.js';
|
||
|
export default {
|
||
|
name: 'drag',
|
||
|
props: {
|
||
|
drag: {
|
||
|
type: Object,
|
||
|
default: null
|
||
|
},
|
||
|
device: {
|
||
|
type: Object,
|
||
|
default: null
|
||
|
}
|
||
|
},
|
||
|
watch: {
|
||
|
// 兼容小程序
|
||
|
drag: function(newVal, oldVal) {
|
||
|
this.init()
|
||
|
},
|
||
|
device: function(newVal, oldVal) {
|
||
|
if (newVal.deviceName !== '') {
|
||
|
this.deviceInfo = newVal;
|
||
|
this.mqttCallback();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
components: {
|
||
|
textDisplay1Vue,
|
||
|
numDisplay1Vue,
|
||
|
numControl1Vue,
|
||
|
mulStatusControl1Vue,
|
||
|
btnControl1Vue,
|
||
|
hstoricalDataGaugeVue,
|
||
|
captionTextVue
|
||
|
},
|
||
|
|
||
|
data() {
|
||
|
return {
|
||
|
components: [],
|
||
|
deviceInfo: {},
|
||
|
isIssue: false,
|
||
|
issueOpations: [], // 下发数据
|
||
|
loading: false,
|
||
|
model: [],
|
||
|
template: {}
|
||
|
};
|
||
|
},
|
||
|
created() {
|
||
|
// 获取设备状态(兼容H5和APP)
|
||
|
if (this.device !== null && Object.keys(this.device).length !== 0) {
|
||
|
this.deviceInfo = this.device;
|
||
|
//this.updateDeviceStatus(this.deviceInfo);
|
||
|
this.mqttCallback();
|
||
|
this.init()
|
||
|
};
|
||
|
|
||
|
|
||
|
},
|
||
|
mounted() {
|
||
|
|
||
|
|
||
|
},
|
||
|
methods: {
|
||
|
/* Mqtt回调处理 */
|
||
|
mqttCallback() {
|
||
|
this.$mqttTool.client.on('message', (topic, message, buffer) => {
|
||
|
let topics = topic.split('/');
|
||
|
let productId = topics[1];
|
||
|
let deviceNum = topics[2];
|
||
|
message = JSON.parse(message.toString());
|
||
|
if (topics[3] == 'status') {
|
||
|
console.log('接收到【设备状态-运行】主题:', topic);
|
||
|
console.log('接收到【设备状态-运行】内容:', message);
|
||
|
// 更新列表中设备的状态
|
||
|
if (this.deviceInfo.serialNumber == deviceNum) {
|
||
|
this.deviceInfo.status = message.status;
|
||
|
this.deviceInfo.isShadow = message.isShadow;
|
||
|
this.deviceInfo.rssi = message.rssi;
|
||
|
}
|
||
|
}
|
||
|
//兼容设备回复
|
||
|
if (topics[4] == 'reply') {
|
||
|
uni.showToast({
|
||
|
icon: 'none',
|
||
|
title: message,
|
||
|
})
|
||
|
}
|
||
|
if (topics[3] == 'property' || topics[3] == 'function' || topic.endsWith(
|
||
|
'ws/service')) {
|
||
|
console.log('接收到【物模型】主题:', topic);
|
||
|
console.log('接收到【物模型】内容:', message);
|
||
|
// 更新列表中设备的属性
|
||
|
if (this.deviceInfo.serialNumber == deviceNum) {
|
||
|
const newValue = new Map();
|
||
|
message.message.forEach(item => {
|
||
|
newValue.set(item.id, item.value);
|
||
|
});
|
||
|
this.components.forEach(item => {
|
||
|
if (item.component !== 'captionText') {
|
||
|
item.setConfig.attributes.forEach(param => {
|
||
|
if (newValue.has(param.identifier)) {
|
||
|
const value = newValue.get(param.identifier)
|
||
|
if (param.datatype === 'integer' || param
|
||
|
.datatype === 'bool' || param.datatype ===
|
||
|
'enum') {
|
||
|
param.value = value !== undefined ? parseInt(
|
||
|
value) :
|
||
|
null;
|
||
|
}
|
||
|
if (param.datatype === 'decimal') {
|
||
|
param.value = value !== undefined ? parseFloat(
|
||
|
value) :
|
||
|
null;
|
||
|
}
|
||
|
if (param.datatype !== 'integer' && param
|
||
|
.datatype !== 'decimal' && param
|
||
|
.datatype !== 'bool' && param.datatype !==
|
||
|
'enum') {
|
||
|
param.value = value
|
||
|
}
|
||
|
// param.value = idToValue.get(param.identifier)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
})
|
||
|
console.log("接收后修改值", this.components)
|
||
|
//this.key++
|
||
|
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
//发送指令
|
||
|
async mqttPublish(device, model) {
|
||
|
const command = {};
|
||
|
command[model.identifier] = model.shadow;
|
||
|
const params = {
|
||
|
deviceId: device.deviceId,
|
||
|
modelId: model.modelId
|
||
|
}
|
||
|
//判断是否有权限
|
||
|
const response = await getOrderControl(params);
|
||
|
if (response.code != 200) {
|
||
|
uni.$u.toast(response.msg);
|
||
|
return;
|
||
|
}
|
||
|
const data = {
|
||
|
serialNumber: device.serialNumber,
|
||
|
productId: device.productId,
|
||
|
remoteCommand: command,
|
||
|
identifier: model.identifier,
|
||
|
modelName: model.modelName,
|
||
|
isShadow: device.status != 3,
|
||
|
type: model.type,
|
||
|
}
|
||
|
serviceInvoke(data).then(response => {
|
||
|
if (response.code === 200) {
|
||
|
uni.showToast({
|
||
|
icon: 'none',
|
||
|
title: this.$tt('status.service')
|
||
|
});
|
||
|
}
|
||
|
})
|
||
|
},
|
||
|
handelSendService(value, item) {
|
||
|
const model = this.model.find(param =>
|
||
|
param.identifier === item.identifier
|
||
|
)
|
||
|
model.shadow = value;
|
||
|
this.mqttPublish(this.device, model)
|
||
|
},
|
||
|
// 获取数据采集数据
|
||
|
getValue(component) {
|
||
|
|
||
|
this.$nextTick(() => {
|
||
|
const queryParams = {
|
||
|
deviceId: this.device.deviceId,
|
||
|
pageNum: 1,
|
||
|
pageSize: 999,
|
||
|
};
|
||
|
listThingsModel(queryParams).then((res) => {
|
||
|
if (res.code === 200) {
|
||
|
this.model = res.rows
|
||
|
const idToValue = new Map();
|
||
|
res.rows.forEach(item => {
|
||
|
idToValue.set(item.identifier, item.value);
|
||
|
});
|
||
|
|
||
|
|
||
|
component.forEach(item => {
|
||
|
if (item.component !== "captionText") {
|
||
|
item.setConfig.attributes.forEach(param => {
|
||
|
if (idToValue.has(param.identifier)) {
|
||
|
const value = idToValue.get(param.identifier)
|
||
|
if (param.datatype === 'integer' || param
|
||
|
.datatype === 'bool' || param.datatype ===
|
||
|
'enum') {
|
||
|
param.value = value ? parseInt(value) :
|
||
|
null
|
||
|
}
|
||
|
if (param.datatype === 'decimal') {
|
||
|
param.value = value ? parseFloat(value) :
|
||
|
null
|
||
|
}
|
||
|
if (param.datatype !== 'integer' && param
|
||
|
.datatype !== 'decimal' && param
|
||
|
.datatype !== 'bool' && param.datatype !==
|
||
|
'enum') {
|
||
|
param.value = value
|
||
|
}
|
||
|
// param.value = idToValue.get(param.identifier)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
})
|
||
|
component = this.getIcon(component)
|
||
|
this.components = component
|
||
|
|
||
|
|
||
|
}
|
||
|
});
|
||
|
})
|
||
|
|
||
|
},
|
||
|
getIcon(component) {
|
||
|
const iconList = [{
|
||
|
id: 'el-icon-edit',
|
||
|
icon: 'edit-pen',
|
||
|
}, {
|
||
|
id: 'el-icon-s-tools',
|
||
|
icon: 'setting-fill'
|
||
|
}, {
|
||
|
id: "el-icon-view",
|
||
|
icon: 'eye'
|
||
|
}, {
|
||
|
id: 'el-icon-document',
|
||
|
icon: 'file-text'
|
||
|
}, {
|
||
|
id: 'el-icon-menu',
|
||
|
icon: 'grid-fill'
|
||
|
}]
|
||
|
const map = new Map();
|
||
|
iconList.forEach(item => {
|
||
|
map.set(item.id, item.icon);
|
||
|
});
|
||
|
component.forEach(item => {
|
||
|
if (item.component !== "captionText") {
|
||
|
item.setConfig.attributes.forEach(param => {
|
||
|
if (map.has(param.icon)) {
|
||
|
const value = map.get(param.icon)
|
||
|
if (param.icon) {
|
||
|
param.icon = value ? value : param.icon
|
||
|
}
|
||
|
// param.value = idToValue.get(param.identifier)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
})
|
||
|
return component
|
||
|
},
|
||
|
init() {
|
||
|
const component = JSON.parse(this.drag.component)
|
||
|
this.template = JSON.parse(this.drag.templateJson)
|
||
|
|
||
|
this.getValue(component)
|
||
|
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style lang="less">
|
||
|
.back {
|
||
|
width: 100%;
|
||
|
min-height: 1200rpx;
|
||
|
background-size: cover;
|
||
|
position: relative;
|
||
|
|
||
|
.full-screen {
|
||
|
position: absolute;
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
z-index: 0;
|
||
|
}
|
||
|
|
||
|
.content {
|
||
|
position: relative;
|
||
|
z-index: 1;
|
||
|
}
|
||
|
}
|
||
|
</style>
|