1176 lines
31 KiB
Vue
1176 lines
31 KiB
Vue
<template>
|
||
<view class="device-detail-box">
|
||
<view class="menu-list">
|
||
<view class="menu-item" @click="goDeviceAbility">
|
||
<view class="iconfont icon-appstore"></view>
|
||
<view class="menu-txt">
|
||
设备功能
|
||
</view>
|
||
</view>
|
||
<view class="menu-item" @click="goDeviceAlarm">
|
||
<view class="iconfont icon-bell"></view>
|
||
<view class="menu-txt">
|
||
设备报警
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="device-title-box">
|
||
<view class="title-box-left">
|
||
<view class="title-txt" @click="openDeviceModel">
|
||
<text>{{deviceName}}</text>
|
||
<text class="title-name-detail">详情</text>
|
||
</view>
|
||
<view class="time-txt">
|
||
{{deviceTime?deviceTime:''}}
|
||
</view>
|
||
</view>
|
||
<view v-if="wsStatus" class="title-right color-blue" @click="refreshSocket">
|
||
<view class="iconfont icon-reload"></view>点击刷新
|
||
</view>
|
||
<view v-else class="title-right color-red" @click="refreshSocket">
|
||
<view class="iconfont icon-disconnect"></view>点击重连
|
||
</view>
|
||
<!-- <view class="title-right" @click="refreshSocket">
|
||
<view class="iconfont icon-reload"></view>{{wsStatus?'刷新':'已断连'}}
|
||
</view> -->
|
||
</view>
|
||
<!-- <view class="group-list">
|
||
<view class="group-list-label">
|
||
属性分组:
|
||
</view>
|
||
<uni-data-select
|
||
style="min-width: 200rpx;max-width: 500rpx;"
|
||
v-model="selectGroup"
|
||
:localdata="groupList"
|
||
:clear="false"
|
||
@change="changeGroup"
|
||
></uni-data-select>
|
||
</view> -->
|
||
<view class="attr-list">
|
||
<view class="attr-list-item" v-for="(item,index) in dataList" :key="index">
|
||
<!-- 选择器 -->
|
||
<iots-select
|
||
v-if="item.viewType == 'select'"
|
||
:disabled="true"
|
||
:name="item.name"
|
||
v-model="item.value"
|
||
:selectList="item.ioObj.enums"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-select>
|
||
<!-- 时间选择器 -->
|
||
<iots-select-time
|
||
v-else-if="item.viewType == 'text' && item.formType == 'time_picker'"
|
||
:disabled="true"
|
||
:name="item.name"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-select-time>
|
||
<!-- 颜色选择 -->
|
||
<iots-color-select
|
||
v-else-if="item.viewType == 'color-select'"
|
||
:name="item.name"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-color-select>
|
||
<!-- 开关 -->
|
||
<iots-switch
|
||
v-else-if="item.viewType == 'switch'"
|
||
:name="item.name"
|
||
:disabled="true"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-switch>
|
||
<!-- 开关按钮 -->
|
||
<iots-switch-btn
|
||
v-else-if="item.viewType == 'switch-btn'"
|
||
:name="item.name"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-switch-btn>
|
||
<!-- 滑块 -->
|
||
<iots-slider
|
||
v-else-if="item.viewType == 'slider'"
|
||
:disabled="true"
|
||
:name="item.name"
|
||
:min="parseFloat(item.ioObj.IoDeployForm.min || 0)"
|
||
:max="parseFloat(item.ioObj.IoDeployForm.max || 100)"
|
||
:step="parseFloat(item.ioObj.IoDeployForm.step || 1)"
|
||
:unit="item.ioObj.unit"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-slider>
|
||
<!-- 文字展示 -->
|
||
<!-- <iots-text
|
||
v-else-if="item.viewType == 'text'"
|
||
:name="item.name"
|
||
:value="getParseText(item.value)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-text> -->
|
||
<!-- 柱状图 -->
|
||
<iots-bar
|
||
v-else-if="item.viewType == 'bar'"
|
||
:name="item.name"
|
||
:dataList="item.dataList"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-bar>
|
||
<!-- 折线图 -->
|
||
<iots-line
|
||
v-else-if="item.viewType == 'charts_line'"
|
||
:name="item.name"
|
||
:time="item.time"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-line>
|
||
<!-- 饼图 -->
|
||
<!-- <iots-pie
|
||
v-else-if="item.viewType == 'charts_pie'"
|
||
:name="item.name"
|
||
:dataList="item.dataList"
|
||
:value="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-pie> -->
|
||
<!-- 仪表盘 -->
|
||
<iots-gauge
|
||
v-else-if="item.viewType == 'charts_dashboard'"
|
||
:name="item.name"
|
||
:dataList="getChartData('charts_dashboard',item)"
|
||
v-model="item.value"
|
||
:min="parseFloat(item.ioObj.IoDeployForm.min || 0)"
|
||
:max="parseFloat(item.ioObj.IoDeployForm.max || 100)"
|
||
:unit="item.ioObj.unit"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-gauge>
|
||
<!-- 步进器 -->
|
||
<iots-number-box
|
||
v-else-if="item.viewType == 'text' && item.formType == 'number'"
|
||
:disabled="true"
|
||
:name="item.name"
|
||
:min="parseFloat(item.ioObj.IoDeployForm.min || 0)"
|
||
:max="parseFloat(item.ioObj.IoDeployForm.max || 100)"
|
||
:step="parseFloat(item.ioObj.IoDeployForm.step || 1)"
|
||
:unit="item.ioObj.unit"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-number-box>
|
||
<!-- 输入框 -->
|
||
<iots-input
|
||
v-else-if="item.viewType == 'text'"
|
||
:disabled="true"
|
||
:name="item.name"
|
||
v-model="item.value"
|
||
:unit="item.ioObj?item.ioObj.unit?item.ioObj.unit:'':''"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-input>
|
||
<iots-img
|
||
v-else-if="item.viewType == 'image'"
|
||
:disabled="true"
|
||
:name="item.name"
|
||
v-model="item.value"
|
||
@change="downData($event,index)"
|
||
@clickLog="clickLog(index)"
|
||
></iots-img>
|
||
|
||
<view v-else class="attr-item">
|
||
<view class="attr-item-left">
|
||
<view class="iconfont" :class="item.icon?item.icon:'icon-file-unknown2'"></view>
|
||
<view class="attr-name">{{item.name}}</view>
|
||
<view class="iconfont icon-unordered-list" @click="clickLog(index)"></view>
|
||
</view>
|
||
<view class="attr-item-right">
|
||
<view class="">
|
||
<!-- 未适配属性 -->
|
||
</view>
|
||
<!-- <view v-if="item.viewType == 'img'" class="attr-value item-border item-img-box" >
|
||
<u-upload ref="uPloadimgRef" width="120" height="120" :action="imgUploadUrl" :file-list="imgList" max-count="1" @on-change="changeUploadImg"></u-upload>
|
||
<view class="iconfont icon-xiangyou1"></view>
|
||
</view> -->
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view v-if="dataList.length == 0" class="attr-empty">
|
||
<u-empty text="设备属性为空,请添加属性" src="setting"></u-empty>
|
||
</view>
|
||
<!-- 数据日志 -->
|
||
<!-- <view class="iconfont icon-shuaxin" @click="resetLog"></view> -->
|
||
<!-- <view class="attr-value item-border item-log">
|
||
<view class="item-log-header">
|
||
<text class="item-log-header-label">数据日志</text>
|
||
<view class="item-log-header-right">
|
||
<view class="iconfont icon-shanchu" @click="clearLog"></view>
|
||
</view>
|
||
</view>
|
||
<scroll-view scroll-y="true" :scroll-top="scrollTop" class="item-log-box" :scroll-with-animation="true">
|
||
<view id="scroll-view-content">
|
||
<view class="log-item" v-for="(logItem,index) in logList" :key="index">
|
||
<view v-if="logItem.type == 'up'" class="iconfont icon-arrow-up color-red"></view>
|
||
<view v-else class="iconfont icon-arrow-down color-green"></view>
|
||
<view class="log-item-content">
|
||
<text class="log-item-time">
|
||
{{logItem.time}}
|
||
</text>
|
||
<text class="log-item-txt">
|
||
{{logItem.txt}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
<view v-if="logList.length==0" class="log-item">
|
||
数据日志监听中···
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view> -->
|
||
<view class="btn-box" @click="goDeviceControl">
|
||
<button>设备控制</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- <u-select mode="single-column" :default-value="selectDefaultValue" v-model="selectShow" :list="selectList" @confirm="confirm"></u-select>
|
||
<u-popup v-model="colorShow" closeable="true" mode="bottom" border-radius="10" safe-area-inset-bottom="true">
|
||
<view class="">
|
||
<view class="" style="display: flex;justify-content: center;align-items: center;height: 40rpx;margin: 24rpx 0;font-weight: bold;font-size: 34rpx;">
|
||
选择颜色
|
||
</view>
|
||
<zebra-color-picker v-model="colors" @input="inputColor"></zebra-color-picker>
|
||
</view>
|
||
</u-popup> -->
|
||
<u-modal v-model="detailShow" title="设备详情" :mask-close-able="true">
|
||
<view class="detail-model">
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
设备ID:
|
||
</view>
|
||
<view class="item-value">
|
||
{{deviceInfo.devId}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
设备名称:
|
||
</view>
|
||
<view class="item-value">
|
||
{{deviceInfo.devName}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
产品名称:
|
||
</view>
|
||
<view class="item-value">
|
||
{{deviceInfo.product.prodName}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
设备类型:
|
||
</view>
|
||
<view class="item-value">
|
||
{{getDeviceTypeName('deviceType',deviceInfo.product.prodType)}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
在线状态:
|
||
</view>
|
||
<view class="item-value" :style="{color:deviceInfo.devState==1?'#10CC70':deviceInfo.devState==2?'#FF2B38':'#999999'}">
|
||
{{getDeviceTypeName('deviceStatus',deviceInfo.devState)}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
创建时间:
|
||
</view>
|
||
<view class="item-value">
|
||
{{deviceInfo.createdAt}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
激活时间:
|
||
</view>
|
||
<view class="item-value">
|
||
{{deviceInfo.activateTime}}
|
||
</view>
|
||
</view>
|
||
<view class="content-item">
|
||
<view class="item-label">
|
||
最后上线时间:
|
||
</view>
|
||
<view class="item-value">
|
||
{{deviceInfo.lastOnlineTime}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-modal>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import IotsSelect from '@/components/iot-components/select/iots-select.vue'
|
||
import IotsNumberBox from "@/components/iot-components/number-box/iots-number-box.vue"
|
||
import IotsColorSelect from "@/components/iot-components/color/iots-color-select.vue"
|
||
import IotsSwitch from '@/components/iot-components/switch/iots-switch.vue'
|
||
import IotsSlider from '@/components/iot-components/slider/iots-slider.vue'
|
||
import IotsSwitchBtn from '@/components/iot-components/switch-btn/iots-switch-btn.vue'
|
||
import IotsText from '@/components/iot-components/text/iots-text.vue'
|
||
import IotsBar from '@/components/iot-components/chart/bar/iots-bar.vue'
|
||
import IotsLine from '@/components/iot-components/chart/line/iots-line.vue'
|
||
import IotsPie from '@/components/iot-components/chart/pie/iots-pie.vue'
|
||
import IotsGauge from '@/components/iot-components/chart/gauge/iots-gauge.vue'
|
||
import IotsInput from '@/components/iot-components/input/iots-input.vue'
|
||
import IotsSelectTime from '@/components/iot-components/select-time/iots-select-time.vue'
|
||
import IotsImg from '@/components/iot-components/img/iots-img.vue'
|
||
import uniDataSelect from "@/components/iot-components/uni-data-select/uni-data-select.vue"
|
||
|
||
export default{
|
||
data(){
|
||
return{
|
||
wsUrl:null,
|
||
socketTask: null,
|
||
wsStatus:false,
|
||
deviceId:null,
|
||
deviceName:null,
|
||
deviceTime:null,
|
||
deviceInfo:{
|
||
devId:'',
|
||
devName:'',
|
||
devState:'',
|
||
createdAt:'',
|
||
activateTime:'',
|
||
lastOnlineTime:'',
|
||
token:'',
|
||
tokenTs:'',
|
||
pk:'',
|
||
product:{
|
||
prodName:'',
|
||
prodType:'',
|
||
},
|
||
|
||
},
|
||
scrollTop:0,
|
||
selectGroup:0,
|
||
// 属性分组
|
||
groupList:[{
|
||
value:0,
|
||
label:'全部',
|
||
groupKey:'all',
|
||
groupName:'全部',
|
||
ioRelKey:[]
|
||
}],
|
||
// 全部设备属性用于属性分组(不变)
|
||
dataAllData:[],
|
||
// 设备属性用于属性分组后数据(会变)
|
||
dataList:[],
|
||
dataIndex: 0,
|
||
// 设备功能
|
||
abilityList:[],
|
||
|
||
selectShow: false,
|
||
selectList: [{
|
||
value: '0',
|
||
label: '正常'
|
||
},
|
||
{
|
||
value: '1',
|
||
label: '异常'
|
||
}
|
||
],
|
||
selectDefaultValue:[0],
|
||
selectIndex: 0,
|
||
selectItemIndex: 0,
|
||
imgUploadUrl: 'http://www.example.com/upload',
|
||
imgList: [],
|
||
logList:[],
|
||
colors:{
|
||
hex: '#7ED321'
|
||
},
|
||
colorShow:false,
|
||
detailShow:false,
|
||
deviceTypeList:[
|
||
{
|
||
label: '直连设备',
|
||
value: 'dev',
|
||
},
|
||
{
|
||
label: '网关子设备',
|
||
value: 'childrenDevice',
|
||
},
|
||
{
|
||
label: '网关设备',
|
||
value: 'gateway',
|
||
}
|
||
],
|
||
deviceStatusList:[
|
||
{
|
||
label: '未激活',
|
||
value: 0
|
||
},
|
||
{
|
||
label: '在线',
|
||
value: 1,
|
||
},
|
||
{
|
||
label: '离线',
|
||
value: 2,
|
||
}
|
||
],
|
||
}
|
||
},
|
||
components: {
|
||
IotsSelect,
|
||
IotsSelectTime,
|
||
IotsNumberBox,
|
||
IotsColorSelect,
|
||
IotsSwitch,
|
||
IotsSlider,
|
||
IotsSwitchBtn,
|
||
IotsText,
|
||
IotsBar,
|
||
IotsLine,
|
||
IotsPie,
|
||
IotsGauge,
|
||
IotsInput,
|
||
IotsImg,
|
||
uniDataSelect
|
||
},
|
||
onLoad(option) {
|
||
console.log("option",option)
|
||
this.deviceId = option.id;
|
||
this.deviceName = option.devName;
|
||
if(option.devName){
|
||
// 修改页面标题
|
||
uni.setNavigationBarTitle({
|
||
title: option.devName
|
||
});
|
||
}
|
||
this.getDeviceInfo(option.id);
|
||
// this.logList = logList;
|
||
let configList = uni.getStorageSync('configList');
|
||
let configIndex = uni.getStorageSync('configIndex');
|
||
this.wsUrl = (configList[configIndex].protocol == 'http://' ?'ws://':'wss://' ) + configList[configIndex].address
|
||
},
|
||
// 关闭websocket【必须在实例销毁之前关闭,否则会是underfined错误】
|
||
beforeDestroy() {
|
||
this.closeSocket();
|
||
},
|
||
watch:{
|
||
logList(){
|
||
this.scrollToBottom();
|
||
}
|
||
},
|
||
methods:{
|
||
goDeviceControl(){
|
||
console.log("设备值",this.dataList);
|
||
let dataList = encodeURIComponent(JSON.stringify(this.dataList).replace(/%/g, '%25'))
|
||
uni.navigateTo({
|
||
url:'./device-control?dataList=' + dataList + '&devId=' + this.deviceInfo.devId + '&pk=' + this.deviceInfo.pk + '&devName=' + this.deviceInfo.devName
|
||
})
|
||
},
|
||
// 选择分组
|
||
changeGroup(e){
|
||
console.log("选择分组",e)
|
||
},
|
||
getChartData(type,data){
|
||
if(type == 'charts_dashboard'){
|
||
let min = 0;
|
||
let max = 100;
|
||
if(data.ioObj.IoDeployForm.min != undefined){
|
||
min = parseFloat(data.ioObj.IoDeployForm.min);
|
||
}
|
||
if(data.ioObj.IoDeployForm.max != undefined){
|
||
max = parseFloat(data.ioObj.IoDeployForm.max);
|
||
}
|
||
let percentage = (data.value/(max - min)).toFixed(2);
|
||
return {series: [{name: data.name,data: percentage}]}
|
||
|
||
}
|
||
},
|
||
getDeviceTypeName(type,key){
|
||
// console.log("getDeviceTypeName",type,key)
|
||
let label = '';
|
||
if(type == 'deviceType'){
|
||
this.deviceTypeList.forEach(item=>{
|
||
if(key === item.value){
|
||
label = item.label;
|
||
}
|
||
})
|
||
}else if(type == 'deviceStatus'){
|
||
this.deviceStatusList.forEach(item=>{
|
||
if(key == item.value){
|
||
label = item.label;
|
||
}
|
||
})
|
||
}
|
||
return label;
|
||
},
|
||
getDeviceInfo(deviceId){
|
||
this.$api.iotsApi.getDeviceInfo({id:deviceId}).then(res => {
|
||
console.log("获取设备详情",res)
|
||
if(res.code == 0 && res.data){
|
||
this.deviceInfo = res.data;
|
||
|
||
if(res.data.product.thingModel){
|
||
let thingModel = JSON.parse(res.data.product.thingModel);
|
||
if(thingModel.contents.prop.length){
|
||
this.dataList = thingModel.contents.prop.map(item=>{
|
||
if(item.dataType=='int'){
|
||
|
||
if(item.ioObj.IoDeployForm.min!=undefined){
|
||
item.value = parseFloat(item.ioObj.IoDeployForm.min);
|
||
}else{
|
||
item.ioObj.IoDeployForm.min = 0;
|
||
item.value = 0;
|
||
}
|
||
}else if(item.viewType == 'slider' || item.viewType == 'charts_dashboard' || (item.viewType == 'text' && item.formType == 'number')){
|
||
console.log("item.ioObj.IoDeployForm.min",item.ioObj);
|
||
if(item.ioObj && item.ioObj.IoDeployForm && item.ioObj.IoDeployForm.min!=undefined && item.ioObj.IoDeployForm.min!= null){
|
||
item.value = parseFloat(item.ioObj.IoDeployForm.min);
|
||
}else{
|
||
// 确保ioObj对象存在于item内
|
||
if (!item.ioObj) {
|
||
item.ioObj = {};
|
||
}
|
||
// 确保IoDeployForm对象存在于item.ioObj内
|
||
if (!item.ioObj.IoDeployForm) {
|
||
item.ioObj.IoDeployForm = {};
|
||
}
|
||
// 现在可以安全地给min赋值
|
||
item.ioObj.IoDeployForm.min = 0;
|
||
if(item.ioObj.IoDeployForm.max == undefined){
|
||
item.ioObj.IoDeployForm.max = 100;
|
||
}
|
||
item.value = 0;
|
||
}
|
||
}else{
|
||
item.value = '';
|
||
}
|
||
item.time = 0;
|
||
return item;
|
||
})
|
||
this.dataAllData = this.dataList;
|
||
}else{
|
||
this.dataList = [];
|
||
this.dataAllData = [];
|
||
}
|
||
if(thingModel.contents.groups.length){
|
||
let groupList = [{
|
||
value:0,
|
||
label:'全部',
|
||
groupKey:'all',
|
||
groupName:'全部',
|
||
ioRelKey:[]
|
||
}];
|
||
thingModel.contents.groups.forEach((item,index)=>{
|
||
groupList.push({
|
||
value:index+1,
|
||
label:item.groupName,
|
||
...item
|
||
})
|
||
})
|
||
this.groupList = groupList;
|
||
// this.$nextTick(()=>{
|
||
// this.$set(this,'groupList',groupList)
|
||
// })
|
||
}else{
|
||
this.groupList = [{
|
||
value:0,
|
||
label:'全部',
|
||
groupKey:'all',
|
||
groupName:'全部',
|
||
ioRelKey:[]
|
||
}];
|
||
}
|
||
if(thingModel.contents.server.length){
|
||
this.abilityList = thingModel.contents.server;
|
||
}else{
|
||
this.abilityList = [];
|
||
}
|
||
if(thingModel.contents.server.length){
|
||
this.abilityList = thingModel.contents.server;
|
||
}else{
|
||
this.abilityList = [];
|
||
}
|
||
console.log("属性列表",this.dataList)
|
||
this.connectSocketInit()
|
||
}else{
|
||
this.$u.toast('获取设备属性失败');
|
||
}
|
||
|
||
}else{
|
||
this.$u.toast(res.message);
|
||
}
|
||
}, error => {
|
||
})
|
||
},
|
||
openDeviceModel(){
|
||
this.detailShow = true;
|
||
},
|
||
goDeviceAbility(){
|
||
let abilityList = encodeURIComponent(JSON.stringify(this.abilityList))
|
||
uni.navigateTo({
|
||
url:'./device-ability-list?abilityList=' + abilityList + '&deviceName=' + this.deviceName + '&devId=' + this.deviceInfo.devId + '&pk=' + this.deviceInfo.pk
|
||
})
|
||
},
|
||
goDeviceAlarm(){
|
||
// this.$u.toast('功能未完成')
|
||
uni.navigateTo({
|
||
url:'/pages/iots/notice/list?devId=' + this.deviceInfo.devId + '&devName=' + this.deviceName
|
||
})
|
||
},
|
||
clickLog(index){
|
||
console.log("当前点击日志",this.dataList[index]);
|
||
let obj = this.dataList[index];
|
||
let devState = this.getDeviceTypeName('deviceStatus',this.deviceInfo.devState);
|
||
uni.navigateTo({
|
||
url:'./device-data?devId=' + this.deviceInfo.devId + '&devName=' + this.deviceInfo.devName + '&devState=' + devState + '&fields=' + obj.identifier
|
||
})
|
||
// h5 页不刷新
|
||
// #ifdef H5
|
||
location.reload()
|
||
// #endif
|
||
},
|
||
downData(e,index){
|
||
let params = {
|
||
ac:'write',
|
||
d:this.deviceInfo.devId,
|
||
pk:this.deviceInfo.pk,
|
||
p:{
|
||
[this.dataList[index].identifier]:e
|
||
}
|
||
}
|
||
console.log("下发数据JSON",params)
|
||
// this.addLog('down',params);
|
||
this.$api.iotsApi.downDeviceProp(params).then(res => {
|
||
console.log("下发数据成功",res)
|
||
if(res.code !=0){
|
||
this.$u.toast(res.message)
|
||
}
|
||
}, error => {
|
||
})
|
||
},
|
||
// 解析显示字段
|
||
getParseText(e){
|
||
// let textList = [];
|
||
// try {
|
||
// if(e){
|
||
// textList = JSON.parse(e)
|
||
// return textList;
|
||
// }else{
|
||
// return textList;
|
||
// }
|
||
// } catch (error) {
|
||
// // 捕获异常并处理
|
||
// console.log("文字列表解析失败" + error.message);
|
||
// return textList;
|
||
// }
|
||
return [{"name":"今日用电","value":e,"unit":""}];
|
||
},
|
||
// 格式化select数据
|
||
formatSelect(value, index){
|
||
// 先格式化数据
|
||
let reg = /\\/g;
|
||
let str = value.funObj.replace(reg, '');
|
||
let obj = JSON.parse(str)
|
||
let selectList = [];
|
||
for (let i in obj) {
|
||
var obj1 = {
|
||
value: i,
|
||
label: obj[i]
|
||
}
|
||
selectList.push(obj1)
|
||
}
|
||
return selectList;
|
||
},
|
||
// 颜色选择变化
|
||
inputColor(color){
|
||
console.log("当前选择颜色为",color)
|
||
},
|
||
// 样式转换
|
||
getVlaue(value) {
|
||
let reg = /\\/g;
|
||
let str = value.funObj.replace(reg, '');
|
||
let obj = JSON.parse(str)
|
||
if (value.funDataType == 'TEXT') {
|
||
return value.lastValue;
|
||
}else {
|
||
return obj[value.lastValue];
|
||
}
|
||
},
|
||
// 点击选择框
|
||
changeSelect(value, index) {
|
||
this.selectIndex = index;
|
||
// 先格式化数据
|
||
let reg = /\\/g;
|
||
let str = value.funObj.replace(reg, '');;
|
||
let obj = JSON.parse(str)
|
||
this.selectList = [];
|
||
for (let i in obj) {
|
||
var obj1 = {
|
||
value: i,
|
||
label: obj[i]
|
||
}
|
||
this.selectList.push(obj1)
|
||
}
|
||
this.selectShow = true;
|
||
// console.log("格式化之后的数据",this.selectList)
|
||
},
|
||
// 选择完成
|
||
confirm(e) {
|
||
if(this.dataList[this.selectIndex].funDataType=="TEXT"){
|
||
this.$nextTick(() => {
|
||
this.dataList[this.selectIndex].lastValue = e[0].label;
|
||
this.selectDefaultValue = [this.selectList.findIndex(item => item.value === e[0].value)] || [0];
|
||
})
|
||
}else{
|
||
this.$nextTick(() => {
|
||
this.dataList[this.selectIndex].lastValue = e[0].value;
|
||
this.selectDefaultValue = [this.selectList.findIndex(item => item.value === e[0].value)] || [0];
|
||
})
|
||
}
|
||
},
|
||
// 点击步进器
|
||
changeNumber(e, index) {
|
||
this.dataList[index].lastValue = e;
|
||
},
|
||
// 上传图片完成
|
||
changeUploadImg(e){
|
||
console.log("上传图片",e);
|
||
},
|
||
upLoadImg(){
|
||
this.$refs.uPloadimgRef.upload();
|
||
},
|
||
scrollToBottom(){
|
||
this.$nextTick(()=>{
|
||
uni.createSelectorQuery().in(this).select('#scroll-view-content').boundingClientRect((res)=>{
|
||
if(res){
|
||
let top = res.height-195;
|
||
if(top>0){
|
||
this.scrollTop=top;
|
||
}
|
||
}
|
||
}).exec()
|
||
})
|
||
},
|
||
// 添加日志
|
||
addLog(type,txt){
|
||
this.logList.push({
|
||
id:this.$u.guid(20),
|
||
time:this.$u.timeFormat(new Date(), 'hh:MM:ss'),
|
||
type,
|
||
txt:JSON.stringify(txt),
|
||
})
|
||
},
|
||
// 刷新数据日志
|
||
resetLog(){
|
||
this.logList = logList;
|
||
},
|
||
// 清理日志
|
||
clearLog(){
|
||
this.logList=[]
|
||
},
|
||
refresh(){
|
||
console.log("点击刷新")
|
||
},
|
||
// 进入这个页面的时候创建websocket连接【整个页面随时使用】
|
||
connectSocketInit() {
|
||
// let ip = uni.getStorageSync('ipAddress');
|
||
// 创建一个this.socketTask对象【发送、接收、关闭socket都由这个对象操作】
|
||
this.socketTask = uni.connectSocket({
|
||
// 【非常重要】必须确保你的服务器是成功的,如果是手机测试千万别使用ws://127.0.0.1:9099【特别容易犯的错误】
|
||
url: this.wsUrl + '/iot/device/ws/prop/' + this.deviceInfo.devId + '/' + this
|
||
.deviceInfo.token + '?ts=' + this.deviceInfo.tokenTs,
|
||
success(data) {
|
||
console.log("websocket连接成功", data);
|
||
|
||
},
|
||
});
|
||
|
||
// 消息的发送和接收必须在正常连接打开中,才能发送或接收【否则会失败】
|
||
this.socketTask.onOpen((res) => {
|
||
console.log("WebSocket连接正常打开中...!");
|
||
this.wsStatus = true;
|
||
// 注:只有连接正常打开中 ,才能正常成功发送消息
|
||
// this.socketTask.send({
|
||
// data: "uni-app发送一条消息",
|
||
// async success() {
|
||
// console.log("消息发送成功");
|
||
// },
|
||
// });
|
||
// 注:只有连接正常打开中 ,才能正常收到消息
|
||
this.socketTask.onMessage((res) => {
|
||
console.log("收到服务器内容:" + res.data);
|
||
let obj = JSON.parse(res.data)
|
||
// this.addLog('up',obj);
|
||
this.deviceTime = this.$u.timeFormat(obj.fg_device_ts, 'yyyy-mm-dd hh:MM:ss');
|
||
if (obj) {
|
||
let dataList = JSON.parse(JSON.stringify(this.dataList));
|
||
// 这是连接的第一次获取,虽然进页面已经获取一次最新数据,但是可能存在断开之后的请求,所以需要遍历覆盖
|
||
for (let i = 0; i < dataList.length; i++) {
|
||
for (let key in obj) {
|
||
if (key == dataList[i].identifier) {
|
||
if(dataList[i].viewType == 'slider' || (dataList[i].viewType == 'text' && dataList[i].formType == 'number')){
|
||
dataList[i].value = parseFloat(obj[key]);
|
||
}else{
|
||
dataList[i].value = obj[key];
|
||
}
|
||
dataList[i].time = obj.fg_device_ts;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
this.$nextTick(()=>{
|
||
this.$set(this,'dataList',dataList)
|
||
this.$forceUpdate()
|
||
})
|
||
}
|
||
});
|
||
})
|
||
// 这里仅是事件监听【如果socket关闭了会执行】
|
||
this.socketTask.onClose(() => {
|
||
this.wsStatus = false;
|
||
console.log("已经被关闭了")
|
||
})
|
||
},
|
||
// 关闭websocket【离开这个页面的时候执行关闭】
|
||
closeSocket() {
|
||
let that = this;
|
||
if(this.wsStatus){
|
||
this.socketTask.close({
|
||
success(res) {
|
||
that.wsStatus = false;
|
||
console.log("关闭成功", res)
|
||
},
|
||
fail(err) {
|
||
console.log("关闭失败", err)
|
||
}
|
||
})
|
||
}
|
||
},
|
||
refreshSocket(){
|
||
if(this.wsStatus){
|
||
this.closeSocket();
|
||
setTimeout(()=>{
|
||
this.connectSocketInit();
|
||
},500)
|
||
}else if(this.dataList.length == 0){
|
||
this.$u.toast('设备属性为空,无法刷新')
|
||
}else{
|
||
this.connectSocketInit();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
page{
|
||
background: #f5f5f5;
|
||
}
|
||
</style>
|
||
|
||
<style lang="scss" scoped>
|
||
.device-detail-box{
|
||
padding-bottom: 160rpx;
|
||
}
|
||
.menu-list{
|
||
display: flex;
|
||
.menu-item{
|
||
flex: 1;
|
||
margin: 20rpx;
|
||
background-color: #fff;
|
||
border-radius: 20rpx;
|
||
height: 130rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-around;
|
||
padding: 0 30rpx;
|
||
box-shadow: 0px 0px 15rpx 0px rgba(201,201,201,0.4);
|
||
.iconfont{
|
||
font-size: 60rpx;
|
||
background-image: -webkit-linear-gradient(90deg, #3BBCFF, #006CFF);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
.menu-txt{
|
||
font-size: 46rpx;
|
||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
|
||
.attr-empty{
|
||
margin: 20rpx 0;
|
||
background-color: #fff;
|
||
border-radius: 20rpx;
|
||
padding: 250rpx 0;
|
||
}
|
||
|
||
.device-title-box{
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin: 0 20rpx;
|
||
padding: 20rpx;
|
||
background-color: #fff;
|
||
border-radius: 20rpx;
|
||
|
||
.title-box-left{
|
||
.title-txt{
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
.title-name-detail{
|
||
padding: 4rpx 12rpx;
|
||
color: #006CFF;
|
||
border: 1px solid #006CFF;
|
||
border-radius: 10rpx;
|
||
font-size: 26rpx;
|
||
margin-left: 10rpx;
|
||
}
|
||
}
|
||
.time-txt{
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
.title-right{
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 30rpx;
|
||
.iconfont{
|
||
margin-right: 10rpx;
|
||
}
|
||
}
|
||
}
|
||
.group-list{
|
||
display: flex;
|
||
// justify-content: space-between;
|
||
align-items: center;
|
||
margin: 0 20rpx;
|
||
margin-top: 20rpx;
|
||
padding: 20rpx;
|
||
background-color: #fff;
|
||
border-radius: 20rpx;
|
||
.group-list-label{
|
||
margin-right: 10rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
// 设备详情弹窗
|
||
.detail-model{
|
||
padding: 30rpx;
|
||
.content-item{
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 10rpx;
|
||
font-size: 28rpx;
|
||
.item-label{
|
||
margin-right: 10rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.attr-list{
|
||
padding: 0 20rpx 30rpx 20rpx;
|
||
.attr-item{
|
||
padding: 20rpx 20rpx;
|
||
background: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-top: 20rpx;
|
||
border-radius: 10rpx;
|
||
.attr-item-left{
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
color: #000;
|
||
.iconfont{
|
||
margin-right: 20rpx;
|
||
font-size: 40rpx;
|
||
}
|
||
.icon-unordered-list{
|
||
margin-left: 16rpx;
|
||
margin-right: 0rpx;
|
||
font-size: 36rpx;
|
||
color: #0b7bff;
|
||
}
|
||
}
|
||
.attr-item-right{
|
||
flex: 1;
|
||
// height: 70rpx;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
.attr-value{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
height: 70rpx;
|
||
flex: 1;
|
||
&.item-select {
|
||
padding: 0 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
color: #ccc;
|
||
.iconfont{
|
||
margin-left: 10rpx;
|
||
}
|
||
}
|
||
&.item-input{
|
||
// width: 250rpx;
|
||
// border: 1px solid #dcdfe6;
|
||
// border-radius: 8rpx;
|
||
// background: #fafafa;
|
||
input{
|
||
flex: 1;
|
||
height: 70rpx;
|
||
}
|
||
}
|
||
&.item-img-box{
|
||
height: 120rpx;
|
||
color: #ccc;
|
||
}
|
||
&.item-number{
|
||
flex: 0 1 auto;
|
||
width: 250rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
color: #ccc;
|
||
border: 1px solid #dcdfe6;
|
||
border-radius: 8rpx;
|
||
/deep/.number-box {
|
||
.minus {
|
||
border: none;
|
||
border-right: 1px solid #dcdfe6;
|
||
}
|
||
|
||
.plus {
|
||
border: none;
|
||
border-left: 1px solid #dcdfe6;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
// 数据日志
|
||
.item-log{
|
||
background: #fff;
|
||
margin-top: 20rpx;
|
||
border-radius: 10rpx;
|
||
overflow: hidden;
|
||
.item-log-header{
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0 20rpx;
|
||
line-height: 50rpx;
|
||
background: $mainColor;
|
||
color: #fff;
|
||
.item-log-header-right{
|
||
display: flex;
|
||
align-items: center;
|
||
.iconfont{
|
||
padding: 10rpx 15rpx;
|
||
// margin-left: 30rpx;
|
||
font-size: 30rpx;
|
||
}
|
||
}
|
||
}
|
||
.item-log-box{
|
||
height: 200px;
|
||
padding: 10rpx;
|
||
box-sizing: border-box;
|
||
.log-item{
|
||
position: relative;
|
||
margin-bottom: 10rpx;
|
||
// display: flex;
|
||
.iconfont{
|
||
position: absolute;
|
||
top:2rpx;
|
||
left:0;
|
||
font-weight: bold;
|
||
}
|
||
.log-item-content{
|
||
// display: inline-block;
|
||
padding-right: 10rpx;
|
||
word-wrap: break-word;
|
||
white-space: pre-line;
|
||
.log-item-time{
|
||
color: $mainColor;
|
||
margin: 0 10rpx 0 36rpx;
|
||
}
|
||
.log-item-txt{
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
/deep/ .u-add-btn{
|
||
display: none;
|
||
}
|
||
/deep/ .u-add-tips{
|
||
margin-top: 0 !important;
|
||
}
|
||
// 设置颜色选择器宽为100%
|
||
/deep/ .zebra-chrome{
|
||
width: 100%;
|
||
}
|
||
.color-red{
|
||
color: red;
|
||
}
|
||
.color-green{
|
||
color: green;
|
||
}
|
||
.color-blue{
|
||
color: #006CFF;
|
||
}
|
||
.btn-box{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #fff;
|
||
height: 140rpx;
|
||
padding-bottom: 10rpx;
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 99;
|
||
button{
|
||
width: 690rpx;
|
||
height: 90rpx;
|
||
background: #3683FD;
|
||
border-radius: 43rpx;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
}
|
||
</style> |