agri-app/pages/control/index.vue

1100 lines
36 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="container">
<z-paging ref="paging" refresher-only class="z-paging-container" :show-empty="false" :show-footer="false" @onRefresh="refresh">
<template #refresher="{refresherStatus}">
<!-- 此处的custom-refresh为demo中自定义的组件非z-paging的内置组件请在实际项目中自行创建这里插入什么view下拉刷新就显示什么view -->
<custom-refresher :status="refresherStatus" />
</template>
<uni-section title="请选择大棚:" :subTitle="imei" titleFontSize="18px" type="line">
<view class="uni-px-5 uni-pb-5">
<uni-data-select v-model="value" :localdata="range" @change="change"></uni-data-select>
</view>
</uni-section>
<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"
@click="openDataModal(item)"
>
<text class="data" :style="fontStyle">
{{ liveData[item.key] }}
<text v-if="isEffectiveValue(liveData[item.key])" class="tempStyle">℃</text>
</text>
<text class="data" v-if="dtu_remark[item.key]">{{ dtu_remark[item.key] }}</text>
<text class="data" v-else>{{ item.label }}</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"
@click="openDataModal(item)"
>
<text class="data" :style="fontStyle">
{{ liveData[item.key] }}
<text v-if="isEffectiveValue(liveData[item.key])" class="humiStyle"> %RH</text>
</text>
<text class="data" v-if="dtu_remark[item.key]">{{ dtu_remark[item.key] }}</text>
<text class="data" v-else>{{ item.label }}</text>
</view>
</view>
</view>
</uni-section>
<uni-section title="设备控制" titleFontSize="16px" type="line" v-if="value!== 1 && !['862538065276939','A','B','C'].includes(imei)">
<template v-slot:right >
{{ control }}
</template>
<!-- 优化:设备卡片循环渲染 -->
<view class="card-grid">
<view
class="control-card"
v-for="card in deviceCards"
:key="card.type"
@click="openTimeModal(card)"
>
<view class="card-text">
<text class="card-main" v-if="dtu_remark[card.type]">{{ dtu_remark[card.type] }}</text>
<text class="card-main" v-else>{{ card.name }}</text>
<view class="card-sub-wrapper">
<text class="card-sub" v-if="showStatusText">{{ show[card.type] || '未知' }}</text>
<text class="limit-time">
运行时间:{{ limitTimes[`${card.type}Limit`] && limitTimes[`${card.type}Limit`]!=='0' ? `${limitTimes[`${card.type}Limit`]} s` : '- -' }}
</text>
</view>
</view>
<view v-if="showFlag" 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>
</view>
</view>
</uni-section>
<uni-popup ref="inputNamelog" mode="center" >
<!-- 新增:修改运行时间的弹窗 -->
<view class="modal-container">
<view class="modal-title">{{ `【${selectedText} - 实时温湿度】别名设置` }}</view>
<view class="modal-input-wrap" >
<text class="modal-label">别名设置:</text>
<uni-easyinput style="width: 100px" v-model="remark" placeholder="不填展示默认备注" />
</view>
<view class="modal-btn-wrap">
<button class="modal-btn cancel" @click="closeModalDataName">取消</button>
<button class="modal-btn confirm" @click="confirmModifyName">确定</button>
</view>
</view>
</uni-popup>
<uni-popup ref="inputDialog" mode="center" >
<!-- 新增:修改运行时间的弹窗 -->
<view class="modal-container">
<view class="modal-title">{{ `【${selectedText} - ${currentCard.name}】设置` }}</view>
<view class="modal-input-wrap">
<text class="modal-label">当前时间:</text>
<text class="modal-current">{{ currentCardTime>0 ? `${currentCardTime} 秒` : '未设置' }}</text>
</view>
<view class="modal-input-wrap" >
<text class="modal-label">修改后时间:</text>
<input
class="modal-input"
type="number"
v-model.number="newLimitTime"
/>
<!-- <uni-number-box v-model="newLimitTime" />-->
<text class="modal-unit">秒</text>
</view>
<view class="modal-input-wrap" >
<text class="modal-label">别名设置:</text>
<uni-easyinput style="width: 100px" v-model="remark" placeholder="不填展示默认备注" />
</view>
<view class="modal-btn-wrap">
<button class="modal-btn cancel" @click="close">取消</button>
<button class="modal-btn confirm" @click="confirmModifyTime"></button>
</view>
</view>
</uni-popup>
</z-paging>
</view>
</template>
<script>
// 优化:抽离魔法值常量
import UniPopupDialog from "../../uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue";
const SENSOR_MAP = {
temp1: "201", temp2: "202", temp3: "203", temp4: "204",
humi1: "101", humi2: "102", humi3: "103", humi4: "104"
};
const MQTT_TOPIC_SUFFIX = { UP: "/+", DOWN: "/control" };
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 UniNumberBox from "../../uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue";
import {addLimit, getAgriByImei, updateLimit} from "../../api/system/assets/limit";
import {listAgri} from "../../api/system/assets/agri";
import {getNewSpecialData} from "../../api/data/specialData";
import store from "../../store";
import {addRemark, getRemarkByImei, updateRemark} from "../../api/system/assets/remark";
import CustomRefresher from "../../components/custom-refresher/custom-refresher.vue";
import ZPaging from "../../uni_modules/z-paging/components/z-paging/z-paging.vue";
export default {
dicts: ['sys_data_map'],
components: {
ZPaging,
UniNumberBox,
UniPopupDialog,
UniDatetimePicker,
CustomRefresher,
UniPopup // 注册弹窗组件
},
data() {
return {
showFlag:true,
temp: "",
mqttConfig: {
subscribeTopic:'/listener',
},
value: 1,
selectedText: '',
// 优化:语义化变量名(替换原 hide: false
showStatusText: false,
control: '正在加载中...',
range: [],
agriId:'',
imei:'',
publishTopic: '/control',
title:'',
message: {},
// 优化:声明响应式变量 connected
connected: false,
remark:'',
dtu_remark:{},
liveData: {
temp1: '数据加载中...',
temp2: '数据加载中...',
temp3: '数据加载中...',
temp4: '数据加载中...',
humi1: '数据加载中...',
humi2: '数据加载中...',
humi3: '数据加载中...',
humi4: '数据加载中...'
},
// 优化温湿度卡片配置固定顺序温度1→2→3→4湿度1→2→3→4
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' }
]
},
sensorCard:{},
// 优化:设备卡片配置(固定顺序)
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: "暂停",
jm1k: "暂停",
jm1g: "暂停",
jm2k: "暂停",
jm2g: "暂停",
jm3k: "暂停",
jm3g: "暂停"
},
// 新增:限位时间配置
limitTimes: {
jbkLimit: 0,
jbgLimit: 0,
jm1kLimit: 0,
jm1gLimit: 0,
jm2kLimit: 0,
jm2gLimit: 0,
jm3kLimit: 0,
jm3gLimit: 0
},
status: {
jbk: 0,
jbg: 0,
jm1k: 0,
jm1g: 0,
jm2k: 0,
jm2g: 0,
jm3k: 0,
jm3g: 0
},
testMsg:'由于线上为真实数据。任何操作均可影响线上功能,故仅作演示',
fontStyle: '',
// 新增:弹窗相关变量
currentCard: {}, // 当前点击的卡片信息
currentCardTime: '', // 当前卡片的运行时间
newLimitTime: 0, // 新的运行时间
};
},
onLoad() {
this.title="";
// 定义所有互斥的键对:[k键, g键]
const mutexPairs = [
['jbk', 'jbg'],
['jm1k', 'jm1g'],
['jm2k', 'jm2g'],
['jm3k', 'jm3g']
];
// 遍历处理每一组互斥规则k=1则g=0g=1则k=0
mutexPairs.forEach(([kKey, gKey]) => {
if (this.status[kKey] === 1) this.status[gKey] = 0;
if (this.status[gKey] === 1) this.status[kKey] = 0;
});
},
onShow() {
this.getAgriList();
// 注册MQTT消息回调接收设备消息
mqttUtil.setOnMessageCallback(this.ackMessage);
// 更新连接状态
this.connected = mqttUtil.getMqttState().isConnected;
this.showFlag = !((store.getters && store.getters.name !== 'admin') && this.$auth.hasRole("test"))
},
onUnload() {
// 移除MQTT消息回调避免内存泄漏
mqttUtil.removeOnMessageCallback();
},
methods: {
refresh() {
this.getAgriList()
this.change(this.imei)
mqttUtil.setOnMessageCallback(this.ackMessage);
this.$refs.paging.complete();
},
getNewSpecialData() {
getNewSpecialData().then(response => {
if (response.code === 200 && response.data) {
this.makeSpecialData(response.data,false);
this.temp = "最后更新时间:"+response.data.time;
this.fontStyle = 'font-size:16px;'
}
})
},
change(e) {
this.imei = e;
var clientId = mqttUtil.getMqttState().clientId;
this.connected = mqttUtil.getMqttState().isConnected;
if ((e === 'A' || e==='B' || e==='C')
&& store.getters && store.getters.name === 'admin' ) {
this.getNewSpecialData(e);
this.mqttConfig.subscribeTopic = `frontend/${clientId}/dtu/862538065276061`;
}
const selectedItem = this.range.find(item => item.value === e);
if (selectedItem) {
this.selectedText = selectedItem.text; // 获取展示文本
this.agriId = selectedItem.agriId;
this.title= this.selectedText;
if (e !== 'A' && e!=='B' && e!=='C') {
// 优化使用常量拼接MQTT主题
this.publishTopic = `frontend/${clientId}${MQTT_TOPIC_SUFFIX.DOWN}/${this.imei}`;
this.mqttConfig.subscribeTopic = `frontend/${clientId}/dtu/${this.imei}`;
var queryParams = {
imei: this.imei
}
// 最新温湿度数据
findDtuDataByInfo(queryParams).then(response => {
Object.keys(response.data).forEach(key => {
this.liveData[key] = response.data[key] || '已离线..';
});
this.temp = "最后更新时间:"+response.data.time;
this.fontStyle = 'font-size:16px;'
})
// 限位
this.getAgriByImei();
// 备注
this.getRemarkByImei();
if (e!=="862538065276939"){
this.message=JSON.stringify({jbk: 0,read:true})
this.publishMessage()
}
}
} else {
this.selectedText = ''; // 无匹配项时清空
this.title='';
this.value=1;
this.agriId = '';
}
this.reset();
this.style="";
},
getRemarkByImei() {
getRemarkByImei({imei:this.imei}).then(response => {
if (response.code===200 && (response.data)) {
this.dtu_remark={...response.data}
}
});
},
getAgriByImei() {
getAgriByImei(this.imei).then(response => {
if (response.code === 200) {
if (!response.data) {
return;
}
this.limitTimes = response.data;
}
})
},
getAgriList() {
listAgri().then(response => {
if (response.code === 200) {
this.range = response.rows.map(item => ({
agriId: item.id,
text: item.agriName,
value: item.imei // 提取并改名
}));
if (store.getters && store.getters.name === 'admin') {
this.range.push(
{
text:"八方南棚",
value:"A"
},
{
text:"九方春棚",
value:"B"
},
{
text:"十二方棚",
value:"C"
}
)
}
}
})
},
testFunction(content) {
uni.showModal({
title: '操作提示:',
content: content,
cancelText: '确定',
success: (res) => {
if (res.confirm) {
}
}
})
},
makeSpecialData(msgData, tag) {
const div10 = (v) => (v == null ? null : Math.round((Number(v)/10)*10)/10);
// 1. 提取B/C的tag对应键名精简重复三元
const B_KEYS = {
true: {temp1:'205',humi1:'105',temp2:'206',humi2:'106',temp3:'207',humi3:'107',temp4:'208',humi4:'108'},
false: {temp1:'temp5',humi1:'humi5',temp2:'temp6',humi2:'humi6',temp3:'temp7',humi3:'humi7',temp4:'temp8',humi4:'humi8'}
};
const C_KEYS = {
true: {temp1:'209',humi1:'109',temp2:'210',humi2:'110',temp3:'211',humi3:'111',temp4:'212',humi4:'112'},
false: {temp1:'temp9',humi1:'humi9',temp2:'temp10',humi2:'humi10',temp3:'temp11',humi3:'humi11',temp4:'temp12',humi4:'humi12'}
};
// 2. 简化传感器键名映射表
const IMEI_SENSOR_MAP = {
A: SENSOR_MAP,
B: B_KEYS[tag], // 直接取tag对应的键名替代三元
C: C_KEYS[tag]
};
// 3. 确定传感器键名(精简变量名)
const isAdmin = store.getters?.name === 'admin';
const sk = (isAdmin && ['A','B','C'].includes(this.imei)) ? IMEI_SENSOR_MAP[this.imei] : IMEI_SENSOR_MAP.A;
// 4. 简化liveData的嵌套三元核心优化
this.liveData = Object.fromEntries(
Object.entries(sk).map(([k, skVal]) => [
k,
(tag
? div10(msgData[skVal])
: (this.imei === 'A' ? msgData[k] : msgData[skVal]))
|| "已离线..."
])
);
},
reset() {
Object.keys(this.show).forEach(key => {
this.show[key] = "暂停";
});
Object.keys(this.status).forEach(key => {
this.status[key] = 0;
});
Object.keys(this.liveData).forEach(key => {
this.liveData[key] = '数据加载中...';
});
this.limitTimes= {
jbkLimit: 0,
jbgLimit: 0,
jm1kLimit: 0,
jm1gLimit: 0,
jm2kLimit: 0,
jm2gLimit: 0,
jm3kLimit: 0,
jm3gLimit: 0
};
this.control = '正在加载中...';
this.message = {};
this.temp = '';
},
// 卡片点击事件(实际项目中调用接口修改状态) 功能标识
handleCardClick(status, type) {
const funcMsg = "该功能用来开启或暂停设备,按钮亮为开启,按钮暗为暂停设备"
if ((store.getters && store.getters.name !== 'admin')
&& this.$auth.hasRole("test")) {
// this.testFunction(`${this.testMsg}\n${funcMsg}`)
return;
}
// 校验
// 定义类型与提示文案的映射关系,减少重复代码
const tipMap = {
'jbk': {opposite: 'jbg', name: '卷被关', op: '卷被开'},
'jbg': {opposite: 'jbk', name: '卷被开', op: '卷被关'},
'jm1k': {opposite: 'jm1g', name: '卷膜1关', op: '卷膜1开'},
'jm1g': {opposite: 'jm1k', name: '卷膜1开', op: '卷膜1关'},
'jm2k': {opposite: 'jm2g', name: '卷膜2关', op: '卷膜2开'},
'jm2g': {opposite: 'jm2k', name: '卷膜2开', op: '卷膜2关'},
'jm3k': {opposite: 'jm3g', name: '卷膜3关', op: '卷膜3开'},
'jm3g': {opposite: 'jm3k', name: '卷膜3开', op: '卷膜3关'}
};
// 先判断类型是否在映射表中避免无效case
if (!tipMap[type]) return;
const {opposite, name, op} = tipMap[type];
// 核心校验逻辑(只写一次,无需重复)
if (status === 1 && this.status[opposite] === 1) {
this.$modal.msgError(`${this.selectedText}${name}在运行状态,不能运行${op}操作!`);
return;
}
// ========== 修改:从全局工具类获取连接状态 ==========
this.connected = mqttUtil.getMqttState().isConnected;
if (!this.connected) {
this.$modal.msgError("设备连接异常");
return;
}
if (this.value === 1) {
this.$modal.msgError("设备控制失败!");
console.info("大棚选取失败!")
return;
}
uni.showModal({
title: '操作提示:',
content: '确定' + (status === 1 ? "运行" : "暂停") + '【' + this.selectedText + '】设备?',
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (res.confirm) {
// 组装消息
this.message = JSON.stringify({[`${type}1`]: status})
// 控制设备
this.publishMessage();
//todo
// this.testAuto(type);
}
}
})
},
// 测试专用
testAuto(type) {
this.$set(this.status, type, this.status[type] === 0 ? 1 : 0);
this.$set(this.show, type, this.status[type] === 0 ? "暂停" : "运行");
},
publishMessage() {
if (!this.connected || !this.publishTopic || !this.message) {
uni.showToast({
title: '控制异常',
icon: 'none'
})
return
}
// 调用全局MQTT工具类发布消息
const publishSuccess = mqttUtil.publishMqtt(this.publishTopic, this.message);
if (publishSuccess) {
this.addMessage(`【指令已发送】imei: ${this.publishTopic},指令: ${this.message}`);
} else {
this.addMessage(`发布失败:设备:[${this.publishTopic}]`)
}
this.message = {};
},
// 消息回调逻辑完全保留(仅依赖全局工具类转发消息)
ackMessage(topic, payload) {
// 1. 先判断是否是目标订阅主题如frontend/\\w+/control/\\w+"
if ((topic !== this.mqttConfig.subscribeTopic+"/ack")
&& (topic !== this.mqttConfig.subscribeTopic+"/listener")) return;
let msgData = {};
// 优化捕获JSON解析异常
try {
msgData = JSON.parse(payload);
} catch (e) {
console.error("MQTT消息解析失败", e, payload);
return;
}
// 3. 区分“回执”和“其他内容”
if (msgData.prop && "suc" in msgData) {
this.handleCommandAck(msgData);
} else if ("msg" in msgData && "clientId" in msgData) {
if (mqttUtil.getMqttState().clientId === msgData.clientId) {
this.$modal.msg(
`${msgData.msg}`
);
}
} else {
this.handleOtherContent(msgData,payload)
}
},
addMessage(content) {
console.info("提示消息:" + content)
},
// 处理指令回执的函数(核心修改:添加定时器+快照)
handleCommandAck(ackData) {
// 拿到指令字段如jm2k和执行状态suc
const commandField = Object.keys(ackData.prop)[0]; // 这里是"jm2k"
const commandValue = ackData.prop[commandField]; // 这里是0/1
const isSuccess = ackData.suc; // 这里是true
const type = commandField.substring(0,commandField.length -1);
if (isSuccess) {
// 优化:使用$set确保响应式更新
this.$set(this.status, type, commandValue);
this.$set(this.show, type, commandValue === 0 ? "暂停" : "运行");
console.info(`收到回执,更新功能码成功:{"${type}":${commandValue}}`)
}
// ========== 修改:自动停止指令不弹窗 ==========
if (ackData.clientId && (ackData.clientId===mqttUtil.getMqttState().clientId)) {
console.info("用户提示成功!")
this.$modal[isSuccess ? 'msgSuccess' : 'msgError'](
`设备操作${isSuccess ? "成功" : "失败"}`
);
}
console.log(`指令[${commandField}=${commandValue}]执行${isSuccess ? "成功" : "失败"}`);
},
handleOtherContent(msgData,payload) {
// 业务逻辑:处理传感器数据、设备状态等
// 设备状态展示
if (this.value !== 1) {
var arr = ['jbk', "jbg", "jm1k", "jm1g", "jm2k", "jm2g", "jm3k", "jm3g"]
const allKeysNumeric = Object.keys(msgData).some(key => arr.includes(key));
if (allKeysNumeric) {
this.status = {...msgData}
Object.keys(msgData).forEach(key => {
const value = msgData[key];
this.show[key] = value === 0 ? '暂停' : '运行';
});
this.control = '最后更新时间:' + this.getCurrentTime();
}
const allKeysNumeric2 = Object.keys(msgData).every(key => /^\d+$/.test(key));
if (Object.keys(msgData).length > 0 && allKeysNumeric2) {
this.temp = "最后更新时间:" + this.getCurrentTime();
this.fontStyle = 'font-size:16px;'
this.makeSpecialData(msgData, true);
}
}
},
/**
* 获取格式化后的当前时间
* @returns {string} 格式为 YYYY-MM-DD HH:mm:ss 的当前时间
*/
getCurrentTime() {
const now = new Date();
// 获取年、月、日(补零确保两位数)
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需 +1
const day = String(now.getDate()).padStart(2, '0');
// 获取时、分、秒(补零确保两位数)
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
// 拼接成标准格式
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
testNumber(data) {
const reg = /^-?\d+(\.\d+)?$/;
return reg.test(String(data).trim());
},
// 优化:封装温湿度单位判断函数
isEffectiveValue(value) {
return this.testNumber(value);
},
// 新增:打开修改运行时间的弹窗
openTimeModal(card) {
if ((store.getters && store.getters.name !== 'admin')
&& this.$auth.hasRole("test")) {
return;
}
this.currentCard = card; // 记录当前卡片信息
this.currentCardTime = this.limitTimes[`${card.type}Limit`]; // 记录当前时间
this.newLimitTime = this.currentCardTime; // 默认填充当前时间
this.remark = this.dtu_remark[card.type] || card.name;
this.$refs.inputDialog.open()
},
openDataModal(sensorCard) {
if ((store.getters && store.getters.name !== 'admin')
&& this.$auth.hasRole("test")) {
return;
}
this.sensorCard = sensorCard;
this.remark=this.dtu_remark[sensorCard.key] || sensorCard.label;
this.$refs.inputNamelog.open()
},
confirmModifyName() {
const funcMsg = "该功能用来设置温湿度卡片别名,如若不填则展示默认备注"
if ((store.getters && store.getters.name !== 'admin')
&& this.$auth.hasRole("test")) {
// this.testFunction(`${this.testMsg}\n${funcMsg}`)
this.$refs?.inputNamelog?.close();
return;
}
// 1. 解构赋值优化直接拆分sensorCard的key/label减少冗余
let {
selectedText,
dtu_remark,
imei,
sensorCard: { key: sensorKey, label: sensorLabel },
remark
} = this;
remark = remark || sensorLabel;
// 2. 语义化判定:别名是否修改
const isRemarkModified = remark !== (dtu_remark[sensorKey] || sensorLabel);
if (!isRemarkModified) {
// 统一关闭弹窗方式
this.$refs?.inputNamelog?.close();
return;
}
// 3. 确认弹窗async/await处理异步请求
uni.showModal({
title: '温馨提示:',
content: `确定将${selectedText}-${sensorLabel}别名设置为:${remark}`, // 修复文案冗余冒号补全remark变量
cancelText: '取消',
confirmText: '确定',
success: async (res) => {
// 关闭弹窗(无论确认/取消都关闭)
this.$refs?.inputNamelog?.close();
if (!res.confirm) return; // 取消操作直接返回
try {
// 4. 设置loading可选防止重复点击
// uni.showLoading({ title: '处理中...' });
// 5. 更新响应式数据
this.$set(dtu_remark, sensorKey, remark); // sensorKey本身是字符串无需拼接
// 补全imei字段确保非空
if (!dtu_remark.imei) {
this.$set(dtu_remark, 'imei', imei);
}
// 6. 异步请求await等待结果核心修复
const remarkRes = dtu_remark.id ? await updateRemark(dtu_remark) : await addRemark(dtu_remark);
// 7. 根据接口响应提示
const isSuccess = remarkRes.code === 200;
this.$modal[isSuccess ? 'msgSuccess' : 'msgError'](
isSuccess ? '修改成功' : '修改失败'
);
// 8. 仅成功时刷新数据(失败时不刷新,避免覆盖现有数据)
if (isSuccess) {
this.getRemarkByImei();
}
} catch (error) {
// 捕获网络异常/接口报错
console.error('别名修改失败:', error);
this.$modal.msgError('修改失败,请重试');
} finally {
// 无论成功/失败关闭loading
// uni.hideLoading();
}
}
});
},
closeModalDataName() {
this.$refs.inputNamelog.close()
},
close() {
this.$refs.inputDialog.close()
},
// 新增:确认修改运行时间
// 确认修改运行时间
confirmModifyTime() {
const funcMsg = "该功能用来设置设备运行时间及设备别名,设备运行时间即开启设备后到达运行时间自行暂停设备;设备别名不填则展示默认设备名称"
if ((store.getters && store.getters.name !== 'admin')
&& this.$auth.hasRole("test")) {
// this.testFunction(`${this.testMsg}\n${funcMsg}`)
this.$refs?.inputDialog?.close();
return;
}
// 1. 解构赋值简化频繁的this.xxx调用提升可读性
let {
newLimitTime, currentCardTime, selectedText, currentCard,
limitTimes, dtu_remark, imei, agriId, remark
} = this;
// 2. 恢复并优化数字校验(如需启用,取消注释即可)
/*if (!newLimitTime || newLimitTime < 1 || newLimitTime > 60) {
uni.showToast({ title: '请输入1-60的有效数字', icon: 'none' });
return;
}*/
// 3. 定义核心判定变量(语义化命名)
const isLimitTimeModified = newLimitTime !== currentCardTime; // 运行时间是否修改
remark = remark || currentCard.name;
const isRemarkModified = (remark !== (dtu_remark[currentCard.type] || currentCard.name)); // 别名是否修改
// 4. 无修改则直接返回,避免无效弹窗
if (!isLimitTimeModified && !isRemarkModified) {
// 关闭弹窗(无论确认/取消都关闭)
this.$refs?.inputDialog?.close();
return;
}
// 5. 简化提示文案拼接(减少嵌套判断)
let confirmContent = `确定修改${selectedText}-${currentCard.name}`;
const tips = [];
if (isLimitTimeModified) tips.push(`运行时间为:${newLimitTime}`);
if (isRemarkModified) {
tips.push(`别名设置为:${remark}`)
}
confirmContent += `\n${tips.map((tip, idx) => `${idx + 1}. ${tip}`).join('\n')}`;
// 6. 确认弹窗async/await处理异步请求
uni.showModal({
title: '温馨提示:',
content: confirmContent,
cancelText: '取消',
confirmText: '确定',
success: async (res) => {
// 关闭弹窗(无论确认/取消都关闭)
this.$refs?.inputDialog?.close();
if (!res.confirm) return; // 取消操作则直接返回
let isAllSuccess = true; // 统一判定所有请求是否成功
try {
// 7. 处理运行时间修改
if (isLimitTimeModified) {
this.$set(limitTimes, `${currentCard.type}Limit`, newLimitTime || 0);
// 补全必要字段(合并重复逻辑)
if (!limitTimes.imei) {
this.$set(limitTimes, 'imei', imei);
this.$set(limitTimes, 'agriName', selectedText);
this.$set(limitTimes, 'agriId', agriId);
}
// 发起请求并等待结果async/await确保顺序执行
const limitRes = limitTimes.id
? await updateLimit(limitTimes)
: await addLimit(limitTimes);
if (limitRes.code !== 200) isAllSuccess = false;
// 新增后刷新数据
if (!limitTimes.imei) this.getAgriByImei();
}
// 8. 处理别名修改
if (isRemarkModified) {
this.$set(dtu_remark, currentCard.type, remark);
// 补全imei字段
if (!dtu_remark.imei) {
this.$set(dtu_remark, 'imei', imei);
}
// 发起请求并等待结果
const remarkRes = dtu_remark.id
? await updateRemark(dtu_remark)
: await addRemark(dtu_remark);
if (remarkRes.code !== 200) isAllSuccess = false;
// 新增后刷新数据
if (!dtu_remark.imei) this.getRemarkByImei();
}
// 9. 正确的提示逻辑(修复原本文案反写的问题)
this.$modal[isAllSuccess ? 'msgSuccess' : 'msgError'](
isAllSuccess ? '修改成功' : '修改失败'
);
} catch (error) {
// 捕获网络异常/接口报错,避免页面卡死
console.error('修改失败:', error);
this.$modal.msgError('修改失败,请重试');
}
}
});
}
},
onHide() {
mqttUtil.removeOnMessageCallback();
},
beforeDestroy() {
mqttUtil.removeOnMessageCallback();
},
};
</script>
<style scoped>
/deep/ .z-paging-content-fixed {
padding: 20rpx !important;
/* 可选防止margin塌陷加overflow */
overflow: hidden;
}
/* 控制设置标题 */
.control-title {
font-size: 32rpx;
font-weight: 500;
text-align: center;
margin-bottom: 30rpx;
color: #333;
}
/* 2列栅格布局 */
.card-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
padding: 20rpx;
}
/* 卡片样式 */
.control-card {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2rpx 8rpx #bfbec1;
}
/* 卡片文字区域 */
.card-text {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.card-main {
font-size: 30rpx;
color: #333;
font-weight: 500;
}
.card-sub {
font-size: 24rpx;
color: #999;
}
/* 保留原有样式,仅修改/新增以下部分 */
.card-sub-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
gap: 10rpx;
/* 新增:给容器加最小宽度,确保所有卡片一致 */
min-width: 0;
}
.limit-time {
font-size: 24rpx;
color: #999;
/* 可选:加固定左边距,确保和暂停的间距统一 */
margin-left: 0rpx;
}
/* 卡片图标容器 */
.card-icon {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background-color: #e5e5e5;
display: flex;
align-items: center;
justify-content: center;
}
/* 激活状态(运行) */
.card-icon.active {
background-color: #007aff;
}
.uni-px-5 {
padding-left: 20rpx;
padding-right: 20rpx;
}
.uni-pb-5 {
padding-bottom: 15rpx;
}
.text {
width: 50rpx;
margin: 10rpx 10rpx 8rpx 0;
padding: 0;
height: 70rpx;
line-height: 70rpx;
text-align: center;
font-size: 26rpx;
box-shadow: 0 2rpx 8rpx #bfbec1
}
.tempStyle,.humiStyle {
display: inline-block;
font-size: 12px;
}
.text:first-child {
margin-left: 10rpx;
}
.uni-view {
-webkit-flex: 1;
flex: 1;
height: 150rpx;
-webkit-justify-content: center;
justify-content: center;
-webkit-align-items: center;
align-items: center;
}
.data {
font-size: 13px;
display: inline-block;
line-height: 23px;
color: #3a3a3a;
}
.data:nth-child(even) {
font-size: 12px;
margin-top: 3px;
color: #9c9c9c;
}
/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: 40rpx;
color: #333;
}
.modal-input-wrap {
display: flex;
align-items: center;
margin-bottom: 35rpx;
font-size: 26rpx;
margin-left: 20rpx;
}
.modal-label {
width: 160rpx;
color: #666;
}
.modal-current {
margin-left: 14rpx;
color: #333;
}
.modal-input {
height: 60rpx;
border: 1px solid #eee;
border-radius: 8rpx;
padding: 0 15rpx;
font-size: 26rpx;
width: 80rpx;
}
.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;
}
.icon {
margin-left: 15rpx
}
.uni-stat-tooltip {
width: 300rpx;
}
/deep/ .is-input-border {
width: 340rpx;
}
</style>