Compare commits

..

No commits in common. "3105c590bbb5b1238ff6ea8874d9ded8b10e61d2" and "20b808adc78f955ecdac721e0493bf2cca4e1ce3" have entirely different histories.

2 changed files with 196 additions and 245 deletions

View File

@ -8,39 +8,48 @@
</view>
</uni-section>
<uni-section title="实时温湿度" titleFontSize="16px" type="line" v-if="value!== 1">
<uni-section title="实时温湿度" titleFontSize="16px" type="line" v-if="value!== 1">
<template v-slot:right >
{{ temp }}
</template>
<view>
<!-- 优化温度卡片循环渲染 -->
<view class="uni-flex_control uni-row" >
<view
class="text uni-flex_control_one uni-view"
v-for="item in sensorCards.temp"
:key="item.key"
>
<text class="data" :style="fontStyle">
{{ liveData[item.key] }}
<p v-if="isEffectiveValue(liveData[item.key])" class="tempStyle"></p>
</text>
<text class="data">{{ item.label }}</text>
<view class="text uni-flex_control_one uni-view">
<text class="data" :style="fontStyle">{{ liveData.temp1 }}<p v-if=(testNumber(liveData.temp1)) class="tempStyle"></p></text>
<text class="data">温度1</text>
</view>
<view class="text uni-flex_control_one uni-view">
<text class="data" :style="fontStyle">{{ liveData.temp2 }}<p v-if=(testNumber(liveData.temp2)) class="tempStyle"></p></text>
<text class="data">温度2</text>
</view>
<view class="text uni-flex_control_one uni-view">
<text class="data" :style="fontStyle">{{ liveData.temp3 }}<p v-if=(testNumber(liveData.temp3)) class="tempStyle"></p></text>
<text class="data">温度3</text>
</view>
<view class="text uni-flex_control_one uni-view">
<text class="data" :style="fontStyle">{{ liveData.temp4 }}<p v-if=(testNumber(liveData.temp4)) class="tempStyle"></p></text>
<text class="data">温度4</text>
</view>
</view>
<!-- 优化湿度卡片循环渲染 -->
<view class="uni-flex_control uni-row" >
<view
class="text uni-flex_control_two uni-view"
v-for="item in sensorCards.humi"
:key="item.key"
>
<text class="data" :style="fontStyle">
{{ liveData[item.key] }}
<p v-if="isEffectiveValue(liveData[item.key])" class="humiStyle"> %RH</p>
</text>
<text class="data">{{ item.label }}</text>
<view class="text uni-flex_control_two uni-view">
<text class="data" :style="fontStyle">{{ liveData.humi1 }}<p v-if=(testNumber(liveData.humi1)) class="humiStyle"> %RH</p></text>
<text class="data">湿度1</text>
</view>
<view class="text uni-flex_control_two uni-view">
<text class="data" :style="fontStyle">{{ liveData.humi2 }}<p v-if=(testNumber(liveData.humi2)) class="humiStyle"> %RH</p></text>
<text class="data">湿度2</text>
</view>
<view class="text uni-flex_control_two uni-view">
<text class="data" :style="fontStyle">{{ liveData.humi3 }}<p v-if=(testNumber(liveData.humi3)) class="humiStyle"> %RH</p></text>
<text class="data">湿度3</text>
</view>
<view class="text uni-flex_control_two uni-view">
<text class="data" :style="fontStyle">{{ liveData.humi4 }}<p v-if=(testNumber(liveData.humi4)) class="humiStyle"> %RH</p></text>
<text class="data">湿度4</text>
</view>
</view>
</view>
@ -50,99 +59,147 @@
<template v-slot:right >
{{ control }}
</template>
<!-- 优化设备卡片循环渲染 -->
<!-- 卷膜/卷被卡片容器2列栅格布局 -->
<view class="card-grid">
<view
class="control-card"
v-for="card in deviceCards"
:key="card.type"
@click="openTimeModal(card)"
>
<!-- 卷被开卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jbk, 'jbk')">
<view class="card-text">
<text class="card-main">{{ card.name }}</text>
<text class="card-main">卷被开</text>
<!-- 核心修改添加限位时间与暂停/运行同行靠右 -->
<view class="card-sub-wrapper">
<text class="card-sub" v-if="showStatusText">{{ show[card.type] || '' }}</text>
<text class="limit-time">运行时间{{ limitTimes[card.type] || 0 }} s</text>
<text class="card-sub" v-if="hide">{{ show.jbk }}</text>
<text class="limit-time">运行时间{{ limitTimes.jbk }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status[card.type] === 1 }" @click.stop="handleCardClick(1 - status[card.type], card.type)">
<!-- @click.stop防止冒泡触发卡片点击的弹窗事件 -->
<uni-icons
:type="status[card.type] === 1 ? 'circle' : 'circle-filled'"
size="24"
color="#fff"
/>
<view class="card-icon" :class="{ active: status.jbk === 1 }">
<uni-icons :type=" (status.jbk === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷被关卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jbg,'jbg')">
<view class="card-text">
<text class="card-main">卷被关</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jbg }}</text>
<text class="limit-time">运行时间{{ limitTimes.jbg }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jbg === 1 }">
<uni-icons :type=" (status.jbg === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷膜1开卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jm1k, 'jm1k')">
<view class="card-text">
<text class="card-main">卷膜1开</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jm1k }}</text>
<text class="limit-time">运行时间{{ limitTimes.jm1k }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jm1k === 1 }">
<uni-icons :type="(status.jm1k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷膜1关卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jm1g, 'jm1g')">
<view class="card-text">
<text class="card-main">卷膜1关</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jm1g }}</text>
<text class="limit-time">运行时间{{ limitTimes.jm1g }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jm1g === 1 }">
<uni-icons :type="(status.jm1g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷膜2卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jm2k, 'jm2k')">
<view class="card-text">
<text class="card-main">卷膜2开</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jm2k }}</text>
<text class="limit-time">运行时间{{ limitTimes.jm2k }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jm2k === 1 }">
<uni-icons :type="(status.jm2k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷膜2关卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jm2g, 'jm2g')">
<view class="card-text">
<text class="card-main">卷膜2关</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jm2g }}</text>
<text class="limit-time">运行时间{{ limitTimes.jm2g }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jm2g === 1 }">
<uni-icons :type="(status.jm2g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷膜3开卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jm3k, 'jm3k')">
<view class="card-text">
<text class="card-main">卷膜3开</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jm3k }}</text>
<text class="limit-time">运行时间{{ limitTimes.jm3k }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jm3k === 1 }">
<uni-icons :type="(status.jm3k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
<!-- 卷膜3关卡片 -->
<view class="control-card" @click="handleCardClick(1-status.jm3g, 'jm3g')">
<view class="card-text">
<text class="card-main">卷膜3关</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="hide">{{ show.jm3g }}</text>
<text class="limit-time">运行时间{{ limitTimes.jm3g }} s</text>
</view>
</view>
<view class="card-icon" :class="{ active: status.jm3g === 1 }">
<uni-icons :type="(status.jm3g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
</view>
</view>
</view>
</uni-section>
<!-- 输入框示例 -->
<!-- <uni-popup ref="inputDialog" type="dialog">-->
<!-- <uni-popup-dialog ref="inputClose" mode="input" title="输入内容" value="对话框预置提示内容!"-->
<!-- placeholder="请输入内容" @confirm="confirmModifyTime"></uni-popup-dialog>-->
<!-- </uni-popup>-->
<uni-popup v-model="timeModalVisible" ref="inputDialog" mode="center" :z-index="99999">
<!-- 新增修改运行时间的弹窗 -->
<!-- <uni-popup v-model="timeModalVisible" mode="center">-->
<view class="modal-container">
<view class="modal-title">修改{{ currentCard.name }}运行时间</view>
<view class="modal-input-wrap">
<text class="modal-label">当前时间</text>
<text class="modal-current">{{ currentCardTime }} s</text>
</view>
<view class="modal-input-wrap">
<text class="modal-label">新时间</text>
<input
class="modal-input"
type="number"
v-model.number="newTime"
placeholder="请输入1-60的数字"
min="1"
max="60"
/>
<text class="modal-unit">s</text>
</view>
<view class="modal-btn-wrap">
<button class="modal-btn cancel" @click="">取消</button>
<button class="modal-btn confirm" @click="confirmModifyTime"></button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
//
const SENSOR_MAP = {
temp1: "201", temp2: "202", temp3: "203", temp4: "204",
humi1: "101", humi2: "102", humi3: "103", humi4: "104"
};
const MQTT_TOPIC_SUFFIX = { UP: "/up", DOWN: "/down" };
// ========== mqtt ==========
// import mqtt from 'mqtt' // mqtt
import UniDatetimePicker from "../../uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
import UniPopup from "../../uni_modules/uni-popup/components/uni-popup/uni-popup.vue"; //
import { findDtuDataByInfo } from "@/api/system/data";
import mqttUtil from '@/utils/mqtt';
import mqttUtil from '@/utils/mqtt'; // MQTT
export default {
dicts: ['sys_data_map'],
components: {
UniDatetimePicker,
UniPopup //
UniDatetimePicker
},
data() {
return {
// ========== mqttClient ==========
// mqttClient: null,
temp: "",
// ========== mqttConfig/ ==========
mqttConfig: {
subscribeTopic:'/up',
},
value: 1,
// hide: false
showStatusText: false,
hide: false,
control: '正在加载中...',
range: [{
"value": '864865085016294',
@ -158,8 +215,8 @@ export default {
publishTopic: '/down',
title:'',
message: {},
// connected
connected: false,
// ========== ==========
// connected:false,
liveData: {
temp1: '数据加载中...',
temp2: '数据加载中...',
@ -170,33 +227,7 @@ export default {
humi3: '数据加载中...',
humi4: '数据加载中...'
},
// 湿1234湿1234
sensorCards: {
temp: [
{ label: '温度1', key: 'temp1' },
{ label: '温度2', key: 'temp2' },
{ label: '温度3', key: 'temp3' },
{ label: '温度4', key: 'temp4' }
],
humi: [
{ label: '湿度1', key: 'humi1' },
{ label: '湿度2', key: 'humi2' },
{ label: '湿度3', key: 'humi3' },
{ label: '湿度4', key: 'humi4' }
]
},
//
deviceCards: [
{ type: 'jbk', name: '卷被开' },
{ type: 'jbg', name: '卷被关' },
{ type: 'jm1k', name: '卷膜1开' },
{ type: 'jm1g', name: '卷膜1关' },
{ type: 'jm2k', name: '卷膜2开' },
{ type: 'jm2g', name: '卷膜2关' },
{ type: 'jm3k', name: '卷膜3开' },
{ type: 'jm3g', name: '卷膜3关' }
],
//
//
show: {
jbk: "暂停",
jbg: "暂停",
@ -207,7 +238,7 @@ export default {
jm3k: "暂停",
jm3g: "暂停"
},
//
//
limitTimes: {
jbk: 30,
jbg: 25,
@ -229,12 +260,7 @@ export default {
jm3k: 0,
jm3g: 0
},
fontStyle: '',
//
timeModalVisible: false, //
currentCard: {}, //
currentCardTime: 0, //
newTime: 0 //
fontStyle: ''
};
},
onLoad() {
@ -254,21 +280,24 @@ export default {
});
},
onShow() {
// ========== connectMqtt ==========
// this.connectMqtt();
// MQTT
mqttUtil.setOnMessageCallback(this.ackMessage);
//
this.connected = mqttUtil.getMqttState().isConnected;
},
onUnload() {
// ========== disconnectMqtt ==========
// this.disconnectMqtt()
// MQTT
mqttUtil.removeOnMessageCallback();
},
methods: {
change(e) {
this.imei = e;
// 使MQTT
this.publishTopic = `dtu/${this.imei}${MQTT_TOPIC_SUFFIX.DOWN}`;
this.mqttConfig.subscribeTopic = `dtu/${this.imei}${MQTT_TOPIC_SUFFIX.UP}`;
this.publishTopic = "dtu/"+this.imei+"/down";
this.mqttConfig.subscribeTopic = "dtu/"+this.imei+"/up";
const selectedItem = this.range.find(item => item.value === e);
if (selectedItem) {
this.selectedText = selectedItem.text; //
@ -303,6 +332,7 @@ export default {
this.liveData[key] = '数据加载中...';
});
this.deviceType = '';
this.control = '正在加载中...';
this.message = {};
this.temp = '';
@ -353,19 +383,25 @@ export default {
//
this.message = JSON.stringify({[type]: status})
//
// this.publishMessage();
this.publishMessage();
//
this.deviceType = type;
//todo
this.$set(this.status, type, this.status[type] === 0 ? 1 : 0);
this.$set(this.show, type, this.status[type] === 0 ? "暂停" : "运行");
// this.status[type] = this.status[type] === 0 ? 1 : 0;
// this.show[type] = this.status[type] === 0 ? "" : "";
}
}
})
},
// ========== connectMqtt ==========
// connectMqtt() { ... },
// ========== disconnectMqtt ==========
// disconnectMqtt() { ... },
// ========== publishMessage ==========
publishMessage() {
if (!this.connected || !this.publishTopic || !this.message) {
uni.showToast({
@ -382,6 +418,7 @@ export default {
} else {
this.addMessage(`发布失败:设备:[${this.publishTopic}]`)
}
this.message = {};
},
@ -389,12 +426,14 @@ export default {
ackMessage(topic, payload) {
// 1. dtu/xxx/up
if (topic !== this.mqttConfig.subscribeTopic) return;
// console.log(`topic=${topic}message=${payload}`)
// 2.
let msgData = {};
// JSON
try {
msgData = JSON.parse(payload);
} catch (e) {
console.error("MQTT消息解析失败:", e, payload);
console.error("消息解析失败:", e);
return;
}
@ -405,7 +444,6 @@ export default {
this.handleOtherContent(msgData,payload)
}
},
addMessage(content) {
console.info("提示消息:" + content)
},
@ -418,17 +456,20 @@ export default {
const isSuccess = ackData.suc; // true
if (isSuccess) {
// 使$set
this.$set(this.status, type, this.status[type] === 0 ? 1 : 0);
this.$set(this.show, type, this.status[type] === 0 ? "暂停" : "运行");
this.status[type] = this.status[type] === 0 ? 1 : 0;
this.show[type] = this.status[type] === 0 ? "暂停" : "运行";
}
this.deviceType = '';
this.$modal.msgSuccess("设备操作成功!")
console.log(`指令[${commandField}=${commandValue}]执行${isSuccess ? "成功" : "失败"}`);
},
//
handleOtherContent(msgData,payload) {
//
// console.log("", msgData);
// 湿线
//
if (this.value !== 1) {
var arr = ['jbk', "jbg", "jm1k", "jm1g", "jm2k", "jm2g", "jm3k", "jm3g"]
@ -444,17 +485,17 @@ export default {
const allKeysNumeric2 = Object.keys(msgData).every(key => /^\d+$/.test(key));
if (Object.keys(msgData).length > 0 && allKeysNumeric2) {
const div10 = (v) => (v == null ? null : Math.round((Number(v)/10)*10)/10)
// 使
this.liveData = {
temp1: div10(msgData[SENSOR_MAP.temp1]) || "已离线...",
humi1: div10(msgData[SENSOR_MAP.humi1]) || "已离线...",
temp2: div10(msgData[SENSOR_MAP.temp2]) || "已离线...",
humi2: div10(msgData[SENSOR_MAP.humi2]) || "已离线...",
temp3: div10(msgData[SENSOR_MAP.temp3]) || "已离线...",
humi3: div10(msgData[SENSOR_MAP.humi3]) || "已离线...",
temp4: div10(msgData[SENSOR_MAP.temp4]) || "已离线...",
humi4: div10(msgData[SENSOR_MAP.humi4]) || "已离线...",
};
temp1: div10(msgData["201"]) || "已离线...",
humi1: div10(msgData["101"]) || "已离线...",
temp2: div10(msgData["202"]) || "已离线...",
humi2: div10(msgData["102"]) || "已离线...",
temp3: div10(msgData["203"]) || "已离线...",
humi3: div10(msgData["103"]) || "已离线...",
temp4: div10(msgData["204"]) || "已离线...",
humi4: div10(msgData["104"]) || "已离线...",
}
this.temp = "最后更新时间:" + this.getCurrentTime();
this.fontStyle = 'font-size:16px;'
}
@ -485,50 +526,19 @@ export default {
testNumber(data) {
const reg = /^-?\d+(\.\d+)?$/;
return reg.test(String(data).trim());
},
// 湿
isEffectiveValue(value) {
return this.testNumber(value);
},
//
openTimeModal(card) {
this.currentCard = card; //
this.currentCardTime = this.limitTimes[card.type]; //
this.newTime = this.currentCardTime; //
this.timeModalVisible = true; //
console.info(`this.timeModalVisible:${this.timeModalVisible}`);
this.$refs.inputDialog.open()
},
//
confirmModifyTime() {
// 1-60
if (!this.newTime || this.newTime < 1 || this.newTime > 60) {
uni.showToast({
title: '请输入1-60的有效数字',
icon: 'none'
});
return;
}
// limitTimes$set
this.$set(this.limitTimes, this.currentCard.type, this.newTime);
//
uni.showToast({
title: '运行时间修改成功',
icon: 'success'
});
//
this.$refs.inputDialog.close()
//
// this.saveLimitTimeToServer(this.currentCard.type, this.newTime);
}
},
onHide() {
// ========== App.vue ==========
// this.disconnectMqtt();
//
mqttUtil.removeOnMessageCallback();
},
beforeDestroy() {
// ========== client ==========
// if (this.client) {
// this.client.end()
// }
mqttUtil.removeOnMessageCallback();
},
};
@ -671,63 +681,4 @@ export default {
/deep/ .uni-section-header__slot-right {
color: green;
}
/* 新增:弹窗样式 */
.modal-container {
width: 600rpx;
background: #fff;
border-radius: 16rpx;
padding: 30rpx 20rpx;
}
.modal-title {
font-size: 30rpx;
font-weight: 500;
text-align: center;
margin-bottom: 30rpx;
color: #333;
}
.modal-input-wrap {
display: flex;
align-items: center;
margin-bottom: 25rpx;
font-size: 26rpx;
}
.modal-label {
width: 120rpx;
color: #666;
}
.modal-current {
color: #333;
}
.modal-input {
flex: 1;
height: 60rpx;
border: 1px solid #eee;
border-radius: 8rpx;
padding: 0 15rpx;
font-size: 26rpx;
}
.modal-unit {
margin-left: 10rpx;
color: #666;
}
.modal-btn-wrap {
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
.modal-btn {
flex: 1;
height: 70rpx;
border-radius: 8rpx;
font-size: 26rpx;
}
.modal-btn.cancel {
background: #f5f5f5;
color: #666;
}
.modal-btn.confirm {
background: #007aff;
color: #fff;
}
</style>

View File

@ -143,7 +143,7 @@
.uni-margin-wrap {
width: 690rpx;
width: 100%;
;
}
.swiper {