210设备管控页弹框功能

This commit is contained in:
fengerli
2025-08-06 18:33:33 +08:00
parent 566fb77648
commit 77d1fdbe64
7 changed files with 250 additions and 189 deletions

18
App.vue
View File

@ -15,12 +15,9 @@
<style lang="scss">
@import 'vk-uview-ui/index.scss';
uni-slider .uni-slider-handle-wrapper {
border-radius: 20rpx;
}
uni-slider .uni-slider-thumb {
width: 66rpx !important;
height: 80rpx !important;
@ -29,7 +26,6 @@
margin-left: -72rpx !important;
}
uni-slider .uni-slider-handle-wrapper {
height: 88rpx;
position: relative;
@ -41,17 +37,21 @@
width: 180rpx;
height: 180rpx;
}
.uni-file-picker.custom-file-picker {
overflow: inherit !important;
}
.custom-file-picker .icon-add {
height: 5rpx !important;
width: 70rpx !important;
}
.custom-file-picker .file-picker__box-content {
// display: none
.uni-picker-view-mask{
background: rgba(42, 42, 42, 1);
z-index: -1;
}
.uni-picker-view-content{
position: inherit;
}
.uni-picker-view-wrapper{
background: rgba(42, 42, 42, 1);
}
</style>

View File

@ -0,0 +1,88 @@
<template>
<picker-view
class="picker-body"
:value="timeIndex"
@change="handleTimeChange"
>
<!-- 分钟列 -->
<picker-view-column>
<view
v-for="min in minutes"
:key="min"
class="item"
:class="{ active: timeIndex[0] === minutes.indexOf(min) }"
>{{ min }}</view>
</picker-view-column>
<!-- 秒数列 -->
<picker-view-column>
<view
v-for="sec in seconds"
:key="sec"
class="item"
:class="{ active: timeIndex[1] === seconds.indexOf(sec) }"
>{{ sec }}</view>
</picker-view-column>
</picker-view>
</template>
<script>
export default {
name: "TimePicker",
props: {
// 初始时间(格式:{ minutes: '02', seconds: '30' }
defaultTime: {
type: Object,
default: () => ({ minutes: '00', seconds: '00' })
}
},
data() {
return {
minutes: Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0')), // 00-59
seconds: Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0')), // 00-59
timeIndex: [0, 0], // 当前选中索引
selectedTime: { minutes: '00', seconds: '00' } // 当前选择的时间
};
},
created() {
// 初始化默认时间
const minIndex = this.minutes.indexOf(this.defaultTime.minutes);
const secIndex = this.seconds.indexOf(this.defaultTime.seconds);
this.timeIndex = [minIndex, secIndex];
this.selectedTime = { ...this.defaultTime };
},
methods: {
// 时间变化时更新选中值
handleTimeChange(e) {
this.timeIndex = e.detail.value;
const [minIdx, secIdx] = this.timeIndex;
this.selectedTime = {
minutes: this.minutes[minIdx],
seconds: this.seconds[secIdx]
};
this.$emit("change", this.selectedTime); // 实时通知父组件
},
// 提供给父组件的方法:获取当前时间
getCurrentTime() {
return this.selectedTime;
}
}
};
</script>
<style scoped>
.picker-body {
height: 180px;
background: #3A3A3A;
border-radius: 10px;
}
.item {
color: rgba(255, 255, 255, 0.7);
text-align: center;
padding: 10px 0;
}
.item.active {
color: #A3FF00; /* 选中项高亮 */
}
</style>

View File

@ -59,8 +59,7 @@
<!-- ===========主副机选择============= -->
<view class="mode-section">
<view class="radio-group">
<view v-for="(item, index) in radioList" :key="index" @click="handleRadioSelect(index)"
class="group-item">
<view v-for="(item, index) in radioList" :key="index" class="group-item">
<view class="radio-icon" :class="{ 'selected': radioSelected === index }">
{{ item }}
<view class="uni-border"></view>
@ -97,7 +96,7 @@
</view>
</view>
<view class="mode-v1">
<view class="mode-v2" @click="lasermode">
<view class="mode-v2" @click="anualAlarm">
<image src="/static/images/210/zd-HL.png" class="setIMG" mode="aspectFit"></image>
<view>
<view class="battery-v2">手动报警</view>
@ -105,7 +104,7 @@
</view>
</view>
<view class="mode-v1">
<view class="mode-v2" @click="lasermode">
<view class="mode-v2">
<image src="/static/images/210/bj.png" class="setIMG" mode="aspectFit"></image>
<view>
<view class="battery-v2">报警声音</view>
@ -114,11 +113,11 @@
</view>
</view>
<view class="mode-v1">
<view class="mode-v2" @click="lasermode">
<view class="mode-v2" @click="alarmTime">
<image src="/static/images/jg.png" class="setIMG" mode="aspectFit"></image>
<view>
<view class="battery-v2">报警时长</view>
<view class="mode-v3">2分30秒</view>
<view class="mode-v3">{{alarmTimeDisplay }}</view>
</view>
</view>
</view>
@ -187,21 +186,18 @@
</view>
<!-- 弹框 -->
<view class="agreement-mask" v-if="lightModeA" @click.stop="closePopup">
<!-- 灯光模式弹窗 -->
<!-- 报警时长弹窗 -->
<view class="agreement-popup" @click.stop>
<!-- 标题 -->
<view class="popup-title"> {{ popupTitle }}</view>
<view class="popup-title">报警时长</view>
<view class="popup-content">
<view v-for="(item, index) in items" :key="index">
<view class="item" :class="{'selected': item.selected}" @click="onItemClick(index)">
<image :src="item.image" class="setIMG"></image>
{{item.text}}
</view>
<view class="time-picker-container">
<TimePicker ref="timePicker" :defaultTime="currentAlarmTime" @change="handleTimeChange" />
</view>
</view>
<!-- 按钮组 -->
<view class="popup-buttons">
<button class="agree" @click="handleSumbit">确定</button>
<button class="agree" @click="saveAlarmTime">保存</button>
</view>
</view>
</view>
@ -213,10 +209,7 @@
<view class="popup-title">上传开机画面</view>
<view class="popup-content">
<view class="example-body">
<!-- <uni-file-picker limit="1" class="custom-file-picker"></uni-file-picker> -->
<view class="icoContent" @click="checkImgUpload">
<!-- <image mode="aspectFit" class="img" src="/static/images/6155/DeviceDetail/add.png">
</image> -->
<image v-if="selectedImage" :src="selectedImage" mode="aspectFit" class="img"
style="width: 100%; height: 100%;"></image>
<image v-else mode="aspectFit" class="img"
@ -230,51 +223,74 @@
</view>
</view>
</view>
<!--===================== 激光提示框================== -->
<view class="agreement-mask" v-if="lightModeC" @click.stop="closePopup">
<!-- 上传画面弹窗 -->
<view class="agreement-popupC" @click.stop>
<!-- 标题 -->
<view class="popup-title">确认开启激光模式</view>
<view class="popup-content">
<view class="popup-Title">
<view>注意事项</view>
<view>1.禁止直视光源或反射面</view>
<view>2.避免直射人或易燃物</view>
<view>3.需佩戴相应专业防护眼镜</view>
</view>
</view>
<!-- 按钮组 -->
<view class="popup-buttons">
<button class="btn disagree" @click="handleDisagree">取消</button>
<button class="btn agreeBtn" @click.stop="handleBtn">确定</button>
</view>
</view>
</view>
<!-- 人员信息成功提示弹框 -->
<CustomPopup v-if="popupType === 'person'" :show="showPopupFlag" :message="popupMessage"
icon="/static/images/common/sendSucc.png" :confirm-text="popupConfirmText" :show-cancel="false"
@confirm="onPopupConfirm" />
<!-- 开机log上传成功的弹框提示 -->
<CustomPopup v-if="popupType === 'logo'" :show="showPopupFlag" :message="popupMessage"
icon="/static/images/common/upload.png" :confirm-text="popupConfirmText" :show-cancel="false"
@confirm="onPopupConfirm" />
<!--============= 电量低于提示弹框=========== -->
<CustomPopup v-if="popupType === 'bettery'" :show="showPopupFlag"
popupBorder="1rpx solid rgba(224, 52, 52, 0.3)" :message="popupMessage" title="设备电量低于20%"
titleColor="rgba(224, 52, 52, 1)" icon="/static/images/common/path.png" :confirm-text="popupConfirmText"
:show-cancel="true" @cancel="onPopupConfirm" @confirm="onPopupConfirm"
confirmBtnBg="rgba(224, 52, 52, 1)" confirmBtnColor="#fff" />
<!-- 解除报警 -->
<CustomPopup v-if="popupType === 'cancel'" :show="showPopupFlag"
popupBorder="1rpx solid rgba(224, 52, 52, 0.3)" :message="popupMessage"
icon="/static/images/6170/svg.png" :confirm-text="popupConfirmText" :show-cancel="false"
@confirm="onPopupConfirm" confirmBtnBg="rgba(224, 52, 52, 1)" confirmBtnColor="#fff" />
<!-- ======各个弹框类型======= -->
<CustomPopup :show="currentPopup.show" v-bind="currentPopup.config" @confirm="handleConfirm"
@cancel="handleCancel" />
</view>
</view>
</template>
<script>
// 弹框配置中心
const POPUP_CONFIGS = {
person: {
config: {
icon: '/static/images/common/sendSucc.png',
message: '信息发送成功',
showCancel: false
},
},
// 开机log
logo: {
config: {
icon: '/static/images/common/upload.png',
message: '上传成功',
showCancel: false
},
},
bettery: {
config: {
title: '设备电量低于20%',
titleColor: 'rgba(224, 52, 52, 1)',
message: '请及时充电',
icon: '/static/images/common/path.png',
popupBorder: '1rpx solid rgba(224, 52, 52, 0.3)',
confirmBtnBg: 'rgba(224, 52, 52, 1)',
showCancel: true
},
onConfirm() {
console.log('确认按钮');
return true; // 直接关闭
}
},
cancel: {
config: {
titleColor: 'rgba(224, 52, 52, 1)',
icon: '/static/images/common/svg.png',
popupBorder: '1rpx solid rgba(224, 52, 52, 0.3)',
confirmBtnBg: 'rgba(224, 52, 52, 1)',
showCancel: true //取消按钮
},
onConfirm() {
console.log('解除报警确认');
}
},
del: {
config: {
message: '确定开启报警?',
icon: '/static/images/210/bj_1.png',
popupBorder: '1rpx solid rgba(255, 200, 78, 1)',
confirmBtnBg: 'rgba(255, 200, 78, 1)',
showCancel: true
},
onConfirm() {
console.log('删除确认');
}
}
}
import MqttClient from '@/utils/mqtt.js';
import {
deviceDetail,
@ -296,6 +312,11 @@
export default {
data() {
return {
currentPopup: {
show: false,
config: {},
callback: null
},
pageLoading: true,
mainMode: 'string',
secondaryMode: 'string',
@ -303,11 +324,14 @@
navTitle: "",
lightModeA: false,
lightModeB: false,
lightModeC: false, //激光提示框
items: [],
isFormExpanded: true, // 默认展开
deviceID: '',
itemInfo: {},
alarmTimeDisplay: '',
currentAlarmTime: {
minutes: '0',
seconds: '30'
},
mqttClient: null,
messageToSend: '',
personnelInfo: {
@ -330,7 +354,7 @@
radioList: ['M', 'S'],
radioSelected: 0, // -1表示未选中任何项
deviceType: '',
popupType:'popupType' //弹框类型
popupType: '', //弹框类型
}
},
methods: {
@ -338,7 +362,26 @@
closePopup() {
this.lightModeA = false;
this.lightModeB = false;
this.lightModeC = false;
},
// 打开弹框
showPopup(type) {
this.currentPopup = {
show: true,
config: POPUP_CONFIGS[type].config,
callback: POPUP_CONFIGS[type].onConfirm
}
},
handleConfirm(){
this.currentPopup.show = false;
console.log('这是点击了确认');
},
// 统一处理取消
handleCancel() {
this.currentPopup.show = false;
},
// 手动报警
anualAlarm() {
this.showPopup('del');
},
handleRadioSelect(index) {
this.radioSelected = index;
@ -369,78 +412,6 @@
toggleForm() {
this.isFormExpanded = !this.isFormExpanded;
},
onItemClick(index) {
const selectedItem = this.items[index];
if (selectedItem.text === '激光') {
this.lightModeC = true;
} else {
// 更新选中状态
this.items = this.items.map((item, i) => ({
...item,
selected: i === index
}));
this.currentMainMode = selectedItem.text;
this.selectedItemIndex = index;
// 强制更新视图(如果需要)
this.$forceUpdate();
}
},
// 灯光模式的确认
handleSumbit() {
if (this.selectedItemIndex === null) return;
const selectedItem = this.items[this.selectedItemIndex];
console.log(selectedItem, 'selectedItemselectedItem');
// 修正这里的赋值错误,应该保存索引而不是文本
this.selectedItemIndex = this.selectedItemIndex;
let data = {
deviceId: this.deviceID,
instructValue: selectedItem.instructValue
}
lightModeSettings(data).then((res) => {
if (res.code == 200) {
uni.showToast({
icon: 'none',
title: res.msg
})
this.lightModeA = false;
} else {
uni.showToast({
icon: 'none',
title: res.msg
})
}
})
},
// 激光模式
lasermode() {
this.lightModeC = true
},
// 激光确认框提交
handleBtn() {
let data = {
deviceId: this.deviceID,
instructValue: 1
}
laserModeSettings(data).then((res) => {
if (res.code == 200) {
uni.showToast({
icon: 'none',
title: res.msg
})
this.lightModeC = false
} else {
uni.showToast({
icon: 'none',
title: res.msg
})
}
})
},
//激光取消
handleDisagree() {
this.lightModeC = false
},
// 上传开机画面
uploadStartup() {
this.lightModeB = true
@ -508,9 +479,7 @@
try {
const responseData = JSON.parse(res.data);
if (responseData.code === 200) {
this.popupType = 'logo'; //弹框类型
this.showPopupFlag = true;
this.popupMessage = '上传成功';
this.showPopup('logo');
this.selectedImage = '';
this.file = null;
this.lightModeB = false
@ -531,6 +500,21 @@
}
})
},
// 报警时长
alarmTime() {
this.lightModeA = true
},
handleTimeChange(time) {
this.currentAlarmTime = time;
},
// 保存时间
saveAlarmTime() {
const time = this.$refs.timePicker.getCurrentTime();
this.alarmTimeDisplay = `${time.minutes}${time.seconds}`;
this.lightModeA = false;
console.log("保存的时间:", time);
},
// 分享
shareUp() {
uni.navigateTo({
@ -610,9 +594,7 @@
registerPersonInfo(data).then((res) => {
if (res.code == 200) {
uni.hideLoading()
this.popupType = 'person'; //弹框类型
this.showPopupFlag = true;
this.popupMessage = '人员信息发送成功'
this.showPopup('person');
} else {
uni.showToast({
title: res.msg,
@ -621,10 +603,6 @@
}
})
},
onPopupConfirm() {
this.showPopupFlag = false
console.log('用户点击了确定')
},
// 发送文本消息
sendTextMessage() {
if (!this.messageToSend) {
@ -645,9 +623,7 @@
deviceSendMessage(data).then((res) => {
if (res.code == 200) {
uni.hideLoading()
this.popupType = 'person'; //弹框类型
this.showPopupFlag = true;
this.popupMessage = '发送信息成功'
this.showPopup('person');
} else {
uni.showToast({
title: res.msg,
@ -1142,7 +1118,7 @@
/* 弹窗主体 */
.agreement-popup {
width: 100%;
height: 50%;
height: 40%;
background-color: rgb(42, 42, 42);
border-radius: 60rpx 60rpx 0rpx 0rpx;
padding: 40rpx;

View File

@ -294,7 +294,7 @@
secondaryMode: 'string',
navBarHeight: 70 + uni.getSystemInfoSync().statusBarHeight,
navTitle: "",
sliderValue: 30,
sliderValue: 25,
lightModeA: false,
currentMainMode: '强光',
lightModeB: false,

View File

@ -507,29 +507,29 @@
this.getData(this.deviceType); // 重新加载第一页数据
},
updateDeviceStatus(data) {
// 只更新 communicationMode == 0 的设备
this.deviceList = this.deviceList.map(item => {
console.log(item,'item444');
if (item.communicationMode == 0) {
console.log(item, 'item2222');
let messageData;
try {
messageData = data.message; // 双重解析(如果消息被转义)
} catch (e) {
return item; // 解析失败则不更新
this.deviceList = this.deviceList
.map(item => {
if (!item) return null; // 如果 item 是 undefined/null返回 null
if (item.communicationMode == 0) {
let messageData;
try {
messageData = data.message;
} catch (e) {
return item; // 解析失败则返回原 item
}
const [deviceId, onlineStatus, battery] = messageData.state || [];
console.log('我收到消息了没',item.battery);
return {
...item,
battery: battery ?? item.battery,
onlineStatus: onlineStatus ?? item.onlineStatus,
lastUpdate: data.timestamp,
};
}
const [deviceId, onlineStatus, batteryPercentage] = messageData.state || [];
// 只更新电量 & 在线状态(避免覆盖其他字段)
return {
...item,
batteryPercentage: batteryPercentage ?? item.batteryPercentage, // 如果新电量有效则更新,否则保留旧值
onlineStatus: onlineStatus ?? item.onlineStatus, // 如果新状态有效则更新,否则保留旧值
lastUpdate: data.timestamp // 更新时间戳
};
return item;
}
});
}
})
.filter(Boolean);
},
},
onLoad() {
this.getTab()
@ -539,22 +539,19 @@
this.getTab() // 刷新数据
this.onIntall()
});
// 监听设备状态更新事件
uni.$on('deviceStatusUpdate', (data) => {
console.log('收到设备状态更新通知:', data);
this.onIntall()
});
},
beforeDestroy() {
// 组件销毁前移除监听器
uni.$off('refreshDeviceList');
},
onShow() {
// 监听设备状态更新事件
uni.$on('deviceStatusUpdate', (data) => {
console.log('收到设备状态更新通知:', data);
this.updateDeviceStatus(data);
});
},
onHide() {
// 页面隐藏时取消监听,避免内存泄漏
onUnload() {
uni.$off('deviceStatusUpdate');
},
}
}
</script>

BIN
static/images/210/bj_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,5 +1,5 @@
import config from '../config/index.js';
const env = 'development'; //production development //开发of线上 改这里就行
const env = 'production'; //production development //开发of线上 改这里就行
const BASE = config[env];
const request = (options) => {
console.log("options"+JSON.stringify(options),BASE.BASE_URL)