1229 lines
34 KiB
Vue
1229 lines
34 KiB
Vue
<template>
|
||
<view>
|
||
<u-navbar :is-back="true" :title="$t('dingshi.title')" title-color="#000" :border-bottom="false" :background="bgc" id="navbar">
|
||
</u-navbar>
|
||
<image class="bj" src="https://api.ccttiot.com/smartmeter/img/static/urqUoIyCCEBykZ2oG8eO" mode=""></image>
|
||
|
||
<!-- 加载提示 -->
|
||
<u-loading-page :loading="isLoading" :loading-text="$t('dingshi.loadingSync')"></u-loading-page>
|
||
|
||
<view class="" v-if="['WATER', 'DATER', 'TATER', 'SATER'].includes(pre)">
|
||
<!-- SATER:双通道(A/B)切换 -->
|
||
<view class="channel-switch" v-if="pre === 'SATER'">
|
||
<view class="channel-btn" :class="{ active: stareChannel === 'A' }" @click="setStareChannel('A')">A</view>
|
||
<view class="channel-btn" :class="{ active: stareChannel === 'B' }" @click="setStareChannel('B')">B</view>
|
||
</view>
|
||
<view class="list" v-if="list.length > 0 || list != null">
|
||
<view class="list_val" v-for="(values, key, index) in list" :key="key">
|
||
<view class="lt" @click="btnitem(key,index,values)">
|
||
<view class="one">{{ formattedTime(values[0], values[1]) }}</view>
|
||
<view class="two">P{{ index + 1 }} <text></text> {{ formatTime(values[2]) }}</view>
|
||
<view class="two">{{ formatInterval(values[4]) }}</view>
|
||
</view>
|
||
<view class="rt">
|
||
<u-switch v-model="values[3]" @change="btnchange(key,index,values)" active-color="#48893B"
|
||
inactive-color="#BDBCBC"></u-switch>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 设置浇水时间弹窗 -->
|
||
<view class="jiaoshui" v-if="timeflag">
|
||
<view class="top">
|
||
{{ $t('dingshi.setWater') }}
|
||
</view>
|
||
<view class="jssc">
|
||
{{ $t('dingshi.setWaterHint') }}
|
||
</view>
|
||
<view class="shifen" @click="btnshowone">
|
||
<text>{{hour}}{{ $t('dingshi.hourUnit') }}</text> <text>{{minutekq}}{{ $t('dingshi.clockMinUnit') }}</text>
|
||
</view>
|
||
<view class="jssc">
|
||
{{ $t('dingshi.waterDur') }}
|
||
</view>
|
||
<view class="shifen" @click="btnshowtwo">
|
||
<text>{{minute}}{{ $t('common.min') }}</text> <text>{{second}}{{ $t('common.sec') }}</text>
|
||
</view>
|
||
<view class="jiange">
|
||
<text>{{ $t('dingshi.everyNDaysWater') }}</text>
|
||
<view class="number-input">
|
||
<text class="btn-minus" @click="changeDays(-1)">-</text>
|
||
<text class="days">{{jgtian || 1}}</text>
|
||
<text class="btn-plus" @click="changeDays(1)">+</text>
|
||
</view>
|
||
</view>
|
||
<view class="anniu">
|
||
<view class="qx" @click="btnqx">
|
||
{{ $t('common.cancel') }}
|
||
</view>
|
||
<view class="qd" @click="btnqd">
|
||
{{ $t('common.confirm') }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="mask" v-if="timeflag"></view>
|
||
<!-- 定时时间 -->
|
||
<u-picker v-model="show" mode="time" :params="paramss" :defaultTime="defaultTime" @confirm="confirm"></u-picker>
|
||
<!-- 定时时长 -->
|
||
<u-picker v-model="shows" mode="time" :params="params" :defaultTime="defaultTimeLength" @confirm="confirms"></u-picker>
|
||
|
||
<view class="mask" style="z-index: 9999;" v-if="kgflag"></view>
|
||
</view>
|
||
<view class="choushuiben" v-else>
|
||
<view class="tit">
|
||
{{ $t('dingshi.pumpSettings') }}
|
||
</view>
|
||
<view class="name" @click="showtime = true">
|
||
<text>{{ $t('dingshi.startTime') }}</text>
|
||
<view class="">
|
||
{{formatStartTime(shi, fen)}} <u-icon name="arrow-right" color="#7C7C7C" size="28"></u-icon>
|
||
</view>
|
||
</view>
|
||
<view class="name">
|
||
<text>{{ $t('dingshi.workDur') }}</text>
|
||
<view class="">
|
||
<input type="number" v-model="miao" @input="handleMiaoInput" @blur="handleMiaoBlur"/>
|
||
{{ $t('common.sec') }}
|
||
</view>
|
||
</view>
|
||
<view class="name" style="border: 0;">
|
||
<text>{{ $t('dingshi.interval') }}</text>
|
||
<view class="">
|
||
<input type="number" v-model="tian"/>
|
||
{{ $t('common.day') }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="baocun" v-if="pre == 'SMSJ:'" @click="btnbc">
|
||
{{ $t('dingshi.save') }}
|
||
</view>
|
||
<u-picker v-model="showtime" mode="time" :params="paramstime" :default-time="'00:00'" @confirm="confirmtime"></u-picker>
|
||
<view class="" v-if="['WATER', 'DATER', 'TATER', 'SATER'].includes(pre)" style="width: 100%;padding-top: 80rpx;text-align: center;color: #000;font-size: 36rpx;">
|
||
{{ $t('dingshi.noMore') }}
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
var xBlufi = require("@/components/blufi/xBlufi.js")
|
||
export default {
|
||
data() {
|
||
return {
|
||
showtime: false,
|
||
paramstime: {
|
||
year: false,
|
||
month: false,
|
||
day: false,
|
||
hour: true,
|
||
minute: true,
|
||
second: false
|
||
},
|
||
bgc: {
|
||
backgroundColor: "#fff",
|
||
},
|
||
active: 1,
|
||
flag: false,
|
||
checked: false,
|
||
timeflag: false,
|
||
show: false,
|
||
params: {
|
||
year: false,
|
||
month: false,
|
||
day: false,
|
||
hour: false,
|
||
minute: true,
|
||
second: true,
|
||
},
|
||
shows: false,
|
||
paramss: {
|
||
year: false,
|
||
month: false,
|
||
day: false,
|
||
hour: true,
|
||
minute: true,
|
||
second: false,
|
||
},
|
||
minute: '--',
|
||
second: '--',
|
||
hour: '--',
|
||
minutekq: '--',
|
||
list: {},
|
||
checkedStatus: {},
|
||
deviceindex: '',
|
||
devicemiao: '',
|
||
deviceflag: '',
|
||
devicehour: '',
|
||
deviceminute: '',
|
||
kgflag: false,
|
||
xctime: '',
|
||
csbobj:{},
|
||
pre:'',
|
||
shi:'',
|
||
fen:'',
|
||
miao:'',
|
||
tian: '',
|
||
isLoading: false, // 加载状态
|
||
retryCount: 0, // 重试次数
|
||
maxRetries: 3, // 最大重试次数
|
||
lastOperation: null, // 最后一次操作
|
||
// 添加默认时间设置
|
||
defaultTime:'',
|
||
defaultTimeLength: '',
|
||
jgtian: '',
|
||
shebid:'',
|
||
zaixianobj:{},
|
||
mac:''
|
||
,
|
||
// SATER 双通道(A/B)
|
||
stareChannel: 'A',
|
||
saterListA: {},
|
||
saterListB: {},
|
||
saterRawPayload: '',
|
||
// SATER 按类型缓存:pA/pB/ver 三组数据不定序到达,存各自最新值
|
||
saterDataByType: { pA: '', pB: '', ver: '' }
|
||
}
|
||
},
|
||
// 分享到好友(会话)
|
||
onShareAppMessage: function() {
|
||
return {
|
||
title: this.$t('app.name'),
|
||
path: '/pages/index/index'
|
||
}
|
||
},
|
||
// 分享到朋友圈
|
||
onShareTimeline: function() {
|
||
return {
|
||
title: this.$t('app.name'),
|
||
query: '',
|
||
path: '/pages/index/index'
|
||
}
|
||
},
|
||
onLoad(option) {
|
||
this.pre = option.pre
|
||
if (option.channel) {
|
||
this.stareChannel = option.channel === 'B' ? 'B' : 'A'
|
||
}
|
||
if(option.shebid){
|
||
this.shebid = option.shebid
|
||
this.getxq()
|
||
}else{
|
||
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
|
||
xBlufi.notifySendCustomData({
|
||
customData: "11get"
|
||
})
|
||
if (option.list && option.list.length > 0) { //判断有无数据 有数据直接拿 无数据则发送命令获取数据
|
||
if (option.pre == 'WATER' || option.pre == 'TATER' || option.pre == 'DATER' || option.pre == 'SATER') {
|
||
let listStr = option.list
|
||
try { listStr = decodeURIComponent(option.list) } catch(e) {}
|
||
const parsedList = JSON.parse(listStr)
|
||
if (option.pre === 'SATER') {
|
||
if (option.raw) {
|
||
try {
|
||
this.saterRawPayload = decodeURIComponent(option.raw)
|
||
} catch (e) {
|
||
this.saterRawPayload = option.raw
|
||
}
|
||
} else {
|
||
this.saterRawPayload = ''
|
||
}
|
||
if (this.saterRawPayload) {
|
||
const parsedAB = this.parseSaterRawToAB(this.saterRawPayload)
|
||
this.saterListA = parsedAB.A
|
||
this.saterListB = parsedAB.B
|
||
this.applySaterChannelList()
|
||
} else {
|
||
// 兼容没有 raw 时至少展示当前通道列表
|
||
const normalized = this.normalizeListSwitch(parsedList)
|
||
if (this.stareChannel === 'B') {
|
||
this.saterListB = normalized
|
||
} else {
|
||
this.saterListA = normalized
|
||
}
|
||
this.applySaterChannelList()
|
||
}
|
||
} else {
|
||
this.list = this.normalizeListSwitch(parsedList)
|
||
}
|
||
console.log(this.list,'listlistlist')
|
||
} else {
|
||
this.csbobj = JSON.parse(option.list)
|
||
console.log(this.csbobj,'chobjchobj')
|
||
this.shi = this.csbobj.hour
|
||
this.fen = this.csbobj.minute
|
||
this.miao = this.csbobj.second
|
||
this.tian = this.csbobj.day
|
||
}
|
||
} else {
|
||
xBlufi.notifySendCustomData({
|
||
customData: "11get"
|
||
})
|
||
}
|
||
}
|
||
},
|
||
onShow() {
|
||
|
||
},
|
||
onUnload() {
|
||
// 离开页面前取消蓝牙监听,避免重复回调;首页 onShow 会重新注册并同步 store 中的数据
|
||
xBlufi.listenDeviceMsgEvent(false, this.funListenDeviceMsgEvent)
|
||
if (this.pre === 'SATER') {
|
||
this.saterDataByType = { pA: '', pB: '', ver: '' }
|
||
}
|
||
},
|
||
methods: {
|
||
normalizeListSwitch(obj){
|
||
const out = {}
|
||
if (!obj || typeof obj !== 'object') return out
|
||
Object.keys(obj).forEach((k) => {
|
||
const arr = Array.isArray(obj[k]) ? [...obj[k]] : [0, 0, 0, 0, 0]
|
||
while (arr.length < 5) arr.push(0)
|
||
arr[3] = arr[3] === 1 || arr[3] === true
|
||
out[k] = arr
|
||
})
|
||
return out
|
||
},
|
||
parseSaterRawToAB(rawInput){
|
||
const raw = String(rawInput || '')
|
||
const src = raw.replace(/@/g, ';')
|
||
const resultA = {}
|
||
const resultB = {}
|
||
for(let i = 1; i <= 6; i++){
|
||
resultA[`p_set${i}`] = [0, 0, 0, false, 0]
|
||
resultB[`p_set${i}`] = [0, 0, 0, false, 0]
|
||
}
|
||
const reg = /p([AB])(\d+):([^;]+)/g
|
||
let m
|
||
while((m = reg.exec(src)) !== null){
|
||
const ch = m[1]
|
||
const idx = Number(m[2])
|
||
if (!idx || idx < 1 || idx > 6) continue
|
||
const nums = m[3].split(',').map(v => {
|
||
const n = parseInt(v, 10)
|
||
return isNaN(n) ? 0 : n
|
||
})
|
||
while (nums.length < 5) nums.push(0)
|
||
nums[3] = nums[3] === 1
|
||
const key = `p_set${idx}`
|
||
if (ch === 'A') resultA[key] = nums
|
||
if (ch === 'B') resultB[key] = nums
|
||
}
|
||
return { A: resultA, B: resultB }
|
||
},
|
||
applySaterChannelList(){
|
||
if (this.pre !== 'SATER') return
|
||
const target = this.stareChannel === 'B' ? this.saterListB : this.saterListA
|
||
this.list = this.normalizeListSwitch(target)
|
||
},
|
||
buildBleTimerCmd(index1Based, hour, minute, second, enabled, intervalDays){
|
||
if (this.pre === 'SATER') {
|
||
const ch = this.stareChannel === 'B' ? 'B' : 'A'
|
||
return `11p${ch}${index1Based}:${hour},${minute},${second},${enabled},${intervalDays};`
|
||
}
|
||
return `11p_set${index1Based}:${hour},${minute},${second},${enabled},${intervalDays};`
|
||
},
|
||
formatStartTime(h, m){
|
||
if (h == null || h === '') return ''
|
||
const hh = String(h).length < 2 ? ('0' + h) : String(h)
|
||
const mm = String(m).length < 2 ? ('0' + m) : String(m)
|
||
return `${hh}:${mm}`
|
||
},
|
||
setStareChannel(ch){
|
||
this.stareChannel = ch === 'B' ? 'B' : 'A'
|
||
this.applySaterChannelList()
|
||
},
|
||
// SATER:给 BLE 定时命令追加 A/B(如 11p_set1A:... 或 11psetA,...)
|
||
applyChannelToBleCmd(cmd){
|
||
if (this.pre !== 'SATER') return cmd
|
||
const s = String(cmd || '')
|
||
if (s.startsWith('11p_set')) {
|
||
return s.replace(/^11p_set(\d+):/, `11p_set$1${this.stareChannel}:`)
|
||
}
|
||
if (s.startsWith('11pset,')) {
|
||
return s.replace(/^11pset,/, `11pset${this.stareChannel},`)
|
||
}
|
||
return cmd
|
||
},
|
||
// 请求浇花器数据
|
||
getxq(){
|
||
this.$u.get(`/app/device/getDetail?deviceId=${this.shebid}`).then(res => {
|
||
if (res.code == 200) {
|
||
if(this.pre == 'SMSJ:'){
|
||
this.shi = res.data.iotData.h.length < 10 ? '0' + res.data.iotData.h.value : res.data.iotData.h.value
|
||
this.fen = res.data.iotData.m.length < 10 ? '0' + res.data.iotData.m.value : res.data.iotData.m.value
|
||
this.miao = res.data.iotData.t.value
|
||
this.tian = res.data.iotData.d.value
|
||
} else {
|
||
this.mac = res.data.mac
|
||
const params = res.data.iotData
|
||
if (this.pre === 'SATER' && (params.pA || params.pB)) {
|
||
// SATER 双阀:从 pA、pB 解析六组定时
|
||
const parsed = this.parseSaterFromApiParams(params)
|
||
this.saterListA = parsed.A
|
||
this.saterListB = parsed.B
|
||
this.applySaterChannelList()
|
||
} else {
|
||
// 单阀 WATER,从后台字段 h1/m1/s1/o1...(以及可选 d1..d6) 组装展示结构
|
||
const mapped = this.buildListFromBackend(params)
|
||
this.list = mapped
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
// SATER:从 getDetail 的 pA、pB 解析为六组定时 { A: {p_set1..p_set6}, B: {...} }
|
||
parseSaterFromApiParams(params){
|
||
const getVal = (obj) => {
|
||
if (!obj) return ''
|
||
const v = (obj && typeof obj === 'object' && 'value' in obj) ? obj.value : obj
|
||
return String(v == null ? '' : v).replace(/^["\s]+|["\s]+$/g, '')
|
||
}
|
||
const pAStr = getVal(params.pA)
|
||
const pBStr = getVal(params.pB)
|
||
const raw = (pAStr ? pAStr + ';' : '') + (pBStr || '')
|
||
return this.parseSaterRawToAB(raw)
|
||
},
|
||
// 后台 -> 定时列表结构(与蓝牙解析一致)
|
||
buildListFromBackend(params){
|
||
const result = {}
|
||
for(let i = 1; i <= 6; i++){
|
||
const h = Number(params?.[`h${i}`]?.value)
|
||
const m = Number(params?.[`m${i}`]?.value)
|
||
const s = Number(params?.[`s${i}`]?.value)
|
||
const o = Number(params?.[`o${i}`]?.value)
|
||
const d = Number(params?.[`d${i}`]?.value)
|
||
const hour = isNaN(h) ? 0 : h
|
||
const minute = isNaN(m) ? 0 : m
|
||
const second = isNaN(s) ? 0 : s
|
||
const onoff = !isNaN(o) && o === 1
|
||
const interval = isNaN(d) || d <= 0 ? 1 : d
|
||
result[`p_set${i}`] = [hour, minute, second, onoff, interval]
|
||
}
|
||
return result
|
||
},
|
||
// 选择启动时间
|
||
confirmtime(e){
|
||
console.log(e);
|
||
this.shi = e.hour
|
||
this.fen = e.minute
|
||
},
|
||
// 点击选择浇水时间
|
||
btnshowone(){
|
||
this.defaultTime = (this.hour.length < 10 ? '0' + this.hour : this.hour) + ':' + (this.minutekq.length < 10 ? '0' + this.minutekq : this.minutekq)
|
||
this.show = true
|
||
},
|
||
// 点击选择浇水时长
|
||
btnshowtwo(){
|
||
console.log(this.defaultTimeLength,this.minute,this.second,'111')
|
||
this.defaultTimeLength = '00' + ':' + this.minute + ':' + this.second
|
||
console.log(this.defaultTimeLength,this.minute,this.second,'222')
|
||
this.shows = true
|
||
},
|
||
// 显示加载
|
||
showLoading() {
|
||
this.isLoading = true
|
||
},
|
||
// 格式化间隔天数显示
|
||
formatInterval(days) {
|
||
const d = Number(days) || 0
|
||
return d <= 1 ? this.$t('dingshi.waterDaily') : this.$t('dingshi.waterEvery', { n: days })
|
||
},
|
||
|
||
// 隐藏加载
|
||
hideLoading() {
|
||
this.isLoading = false
|
||
setTimeout(() => {
|
||
this.isLoading = false
|
||
}, 500)
|
||
},
|
||
|
||
// 重试机制
|
||
async retryOperation() {
|
||
if (this.retryCount < this.maxRetries) {
|
||
this.retryCount++
|
||
await this.delay(1000)
|
||
if (this.lastOperation) {
|
||
this.lastOperation()
|
||
}
|
||
} else {
|
||
this.hideLoading()
|
||
uni.showToast({
|
||
title: this.$t('dingshi.opFail'),
|
||
icon: 'none'
|
||
})
|
||
this.retryCount = 0
|
||
}
|
||
},
|
||
|
||
// 延时函数
|
||
delay(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
},
|
||
|
||
// 点击开关是否开启
|
||
async btnchange(key, index, values) {
|
||
uni.showLoading({
|
||
title: this.$t('dingshi.operating')
|
||
})
|
||
try {
|
||
this.showLoading()
|
||
// 保持 UI 不变,等待请求成功后再更新
|
||
this.deviceindex = index
|
||
this.devicehour = values[0] || 0
|
||
this.deviceminute = values[1] || 0
|
||
this.devicemiao = values[2] || 0
|
||
const prevSwitch = !!values[3]
|
||
const nextSwitch = !prevSwitch
|
||
const intervalDays = parseInt(this.jgtian) || 1
|
||
const flag = nextSwitch ? 1 : 0
|
||
const cmdIndex = Number(this.deviceindex) + 1
|
||
let cucun = this.buildBleTimerCmd(cmdIndex, this.devicehour, this.deviceminute, this.devicemiao, flag, intervalDays)
|
||
if(this.shebid == ''){
|
||
this.lastOperation = () => {
|
||
xBlufi.notifySendCustomData({
|
||
customData: cucun
|
||
})
|
||
}
|
||
this.lastOperation()
|
||
await this.delay(1000)
|
||
xBlufi.notifySendCustomData({
|
||
customData: "11get"
|
||
})
|
||
// BLE 下不立即改 UI,等待设备返回数据刷新
|
||
setTimeout(() => {
|
||
uni.hideLoading()
|
||
this.hideLoading()
|
||
}, 1000)
|
||
}else{
|
||
let parameters = {
|
||
date:cucun
|
||
}
|
||
const deviceTime = (String(this.devicehour).length < 2 ? '0' + this.devicehour : this.devicehour) + ':' + (String(this.deviceminute).length < 2 ? '0' + this.deviceminute : this.deviceminute);
|
||
let data = {
|
||
deviceId:this.shebid,
|
||
index:(Number(this.deviceindex) + 1),
|
||
enabled:flag,
|
||
wateringTime:deviceTime,
|
||
duration:this.devicemiao,
|
||
interval:intervalDays
|
||
// instructionKey:'date',
|
||
// parameters:parameters
|
||
}
|
||
this.$u.post(`/app/device/timedWatering`,data).then(res => {
|
||
if (res.code == 200) {
|
||
// 网关成功:仅本地更新开关状态
|
||
const keyName = `p_set${Number(this.deviceindex) + 1}`
|
||
if (this.list[keyName]) {
|
||
this.$set(this.list[keyName], 3, nextSwitch)
|
||
}
|
||
uni.showToast({
|
||
title: this.$t('index.setOk'),
|
||
icon: 'success',
|
||
duration:2000
|
||
})
|
||
// 不再请求新数据
|
||
}else{
|
||
// 失败则保持原状态
|
||
values[3] = prevSwitch
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('btnchange error:', error)
|
||
this.retryOperation()
|
||
}
|
||
},
|
||
|
||
// 点击设置定时时间
|
||
btnitem(key, index, values) {
|
||
// 从 key 中提取索引号,例如从 'p_set1' 提取 '1'
|
||
const indexMatch = key.match(/p_set(\d+)/)
|
||
this.deviceindex = indexMatch ? indexMatch[1] : index
|
||
this.timeflag = true
|
||
this.hour = values[0]
|
||
this.minutekq = values[1]
|
||
const totalSeconds = values[2]
|
||
const minutes = Math.floor(totalSeconds / 60)
|
||
const seconds = totalSeconds % 60
|
||
const formattedMinutes = minutes < 10 ? '0' + minutes : minutes.toString()
|
||
const formattedSeconds = seconds < 10 ? '0' + seconds : seconds.toString()
|
||
this.minute = formattedMinutes
|
||
this.second = formattedSeconds
|
||
// 添加间隔天数的处理,确保为数字
|
||
this.jgtian = parseInt(values[4]) || 0
|
||
// 设置设备相关值
|
||
this.devicehour = values[0]
|
||
this.deviceminute = values[1]
|
||
this.devicemiao = values[2]
|
||
if (this.list.hasOwnProperty(key)) {
|
||
const array = this.list[key]
|
||
// 只转换开关状态为布尔值
|
||
this.deviceflag = array[3] ? 1 : 0
|
||
}
|
||
},
|
||
|
||
formattedTime(minutes, seconds) {
|
||
// 将数字转换为字符串并补零
|
||
const formattedMinutes = String(minutes).padStart(2, '0')
|
||
const formattedSeconds = String(seconds).padStart(2, '0')
|
||
// 返回格式化后的时间字符串
|
||
return `${formattedMinutes}:${formattedSeconds}`
|
||
},
|
||
|
||
formatTime(seconds) {
|
||
const minutes = Math.floor(seconds / 60)
|
||
const remainingSeconds = seconds % 60
|
||
const s = (remainingSeconds < 10 ? '0' : '') + remainingSeconds
|
||
return this.$t('dingshi.durationMinSec', { m: minutes, s })
|
||
},
|
||
|
||
// 取消选择设置定时时间
|
||
btnqx() {
|
||
this.timeflag = false
|
||
this.hour = '--'
|
||
this.minutekq = '--'
|
||
this.minute = '--'
|
||
this.second = '--'
|
||
},
|
||
// 确定选择设置定时时间
|
||
async btnqd() {
|
||
try {
|
||
this.showLoading()
|
||
this.timeflag = false
|
||
this.hour = '--'
|
||
this.minutekq = '--'
|
||
this.minute = '--'
|
||
this.second = '--'
|
||
|
||
// 确保间隔天数为数字
|
||
const intervalDays = parseInt(this.jgtian) || 0;
|
||
|
||
let cucun = this.buildBleTimerCmd(this.deviceindex, this.devicehour, this.deviceminute, this.devicemiao, 1, intervalDays)
|
||
if(this.shebid == ''){
|
||
this.lastOperation = () => {
|
||
xBlufi.notifySendCustomData({
|
||
customData: cucun
|
||
})
|
||
}
|
||
this.lastOperation()
|
||
|
||
await this.delay(1000)
|
||
xBlufi.notifySendCustomData({
|
||
customData: "11get"
|
||
})
|
||
// BLE 下设置后计时刷新由设备推送完成
|
||
this.hideLoading()
|
||
}else{
|
||
let parameters = {
|
||
date:cucun
|
||
}
|
||
const deviceTime = (String(this.devicehour).length < 2 ? '0' + this.devicehour : this.devicehour) + ':' + (String(this.deviceminute).length < 2 ? '0' + this.deviceminute : this.deviceminute);
|
||
let data = {
|
||
deviceId:this.shebid,
|
||
index:this.deviceindex,
|
||
enabled:1,
|
||
wateringTime:deviceTime,
|
||
duration:this.devicemiao,
|
||
interval:intervalDays
|
||
// instructionKey:'date',
|
||
// parameters:parameters
|
||
}
|
||
this.$u.post(`/app/device/timedWatering`,data).then(res => {
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: this.$t('index.setOk'),
|
||
icon: 'success',
|
||
duration:2000
|
||
})
|
||
// 网关成功:本地立即更新列表,避免再次请求
|
||
const key = `p_set${this.deviceindex}`
|
||
if (!this.list[key]) {
|
||
this.$set(this.list, key, [0,0,0,false,1])
|
||
}
|
||
// 更新为本次设置的值(使用 $set 保证响应式)
|
||
this.$set(this.list[key], 0, Number(this.devicehour) || 0)
|
||
this.$set(this.list[key], 1, Number(this.deviceminute) || 0)
|
||
this.$set(this.list[key], 2, Number(this.devicemiao) || 0)
|
||
this.$set(this.list[key], 3, true)
|
||
this.$set(this.list[key], 4, Number(intervalDays) || 1)
|
||
|
||
const now = new Date()
|
||
const at = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
|
||
let shuju = {}
|
||
shuju[`d${this.deviceindex}`] = { value: String(this.jgtian), at }
|
||
shuju[`h${this.deviceindex}`] = { value: String(this.devicehour), at }
|
||
shuju[`m${this.deviceindex}`] = { value: String(this.deviceminute), at }
|
||
shuju[`o${this.deviceindex}`] = { value: '1', at }
|
||
shuju[`s${this.deviceindex}`] = { value: String(this.devicemiao), at }
|
||
let data = {
|
||
mac: this.mac,
|
||
params: shuju
|
||
}
|
||
this.$u.put(`/app/updateDeviceParam`, data).then(res => {})
|
||
}else{
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
}
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('btnqd error:', error)
|
||
this.retryOperation()
|
||
}
|
||
},
|
||
// 保存抽水泵设置
|
||
async btnbc() {
|
||
try {
|
||
if(this.shi >= 24){
|
||
uni.showToast({
|
||
title: this.$t('dingshi.maxHour'),
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
return
|
||
} else if(this.fen >= 60){
|
||
uni.showToast({
|
||
title: this.$t('dingshi.maxMin'),
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
return
|
||
}
|
||
// 限制工作时长不能超过9999秒
|
||
if(this.miao > 9999){
|
||
uni.showToast({
|
||
title: this.$t('dingshi.maxWorkSec'),
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
this.miao = 9999
|
||
}
|
||
|
||
this.showLoading();
|
||
this.timeflag = false;
|
||
if(this.tian > 99){
|
||
uni.showToast({
|
||
title: this.$t('dingshi.maxInterval'),
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
}
|
||
let tian = this.tian > 99 ? 99 : this.tian
|
||
let cucun = '11pset' + ',' + this.shi + ',' + this.fen + ',' + this.miao + ',' + tian + '@'
|
||
cucun = this.applyChannelToBleCmd(cucun)
|
||
if(this.shebid == ''){
|
||
this.lastOperation = () => {
|
||
xBlufi.notifySendCustomData({
|
||
customData: cucun
|
||
})
|
||
};
|
||
this.lastOperation()
|
||
await this.delay(1000)
|
||
xBlufi.notifySendCustomData({
|
||
customData: "11get"
|
||
})
|
||
uni.showToast({
|
||
title: this.$t('common.saveOk'),
|
||
icon: 'success',
|
||
duration: 2000
|
||
})
|
||
this.hideLoading()
|
||
}else{
|
||
let parameters = {
|
||
date:cucun
|
||
}
|
||
let data = {
|
||
deviceId:this.shebid,
|
||
wateringTime:this.shi + ':' + this.fen,
|
||
duration:this.miao,
|
||
interval:tian
|
||
// instructionKey:'date',
|
||
// parameters:parameters
|
||
}
|
||
this.$u.post(`/app/device/timedWatering`,data).then(res => {
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: this.$t('common.saveOk'),
|
||
icon: 'success',
|
||
duration:2000
|
||
})
|
||
}else{
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration:2000
|
||
})
|
||
}
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('btnbc error:', error)
|
||
this.retryOperation()
|
||
}
|
||
},
|
||
// 定时浇水时间
|
||
confirm(e) {
|
||
this.hour = e.hour || '00'
|
||
this.minutekq = e.minute || '00'
|
||
this.devicehour = e.hour || '00'
|
||
this.deviceminute = e.minute || '00'
|
||
},
|
||
// 定时浇水时长
|
||
confirms(e) {
|
||
this.minute = e.minute || '00'
|
||
this.second = e.second || '00'
|
||
this.devicemiao = (Number(this.minute) * 60 + Number(this.second)) || 0
|
||
console.log(this.devicemiao)
|
||
},
|
||
|
||
funListenDeviceMsgEvent: function(options) {
|
||
switch (options.type) {
|
||
case xBlufi.XBLUFI_TYPE.TYPE_STATUS_CONNECTED:
|
||
if (!options.result) {
|
||
uni.showToast({
|
||
title: this.$t('dingshi.bleAbnormal'),
|
||
icon: 'none'
|
||
});
|
||
}
|
||
break;
|
||
case xBlufi.XBLUFI_TYPE.TYPE_RECIEVE_CUSTON_DATA:
|
||
try {
|
||
console.log("收到设备发来的自定义数据结果:", options.data);
|
||
const inputString = options.data.slice(0, -1) + ";";
|
||
if (this.pre == 'WATER' || this.pre == 'TATER' || this.pre == 'DATER' || this.pre == 'SATER') {
|
||
if (this.pre === 'SATER') {
|
||
// SATER 设备分 3 种类型不定序推送:pA(pA1:...)、pB(pB1:...)、ver(ver...@show:...)
|
||
// 按类型存最新值,集齐后解析并展示
|
||
let chunk = String(options.data || '')
|
||
if (chunk) chunk = chunk.slice(0, -1)
|
||
if (chunk) {
|
||
if (!chunk.endsWith(';')) chunk += ';'
|
||
if (chunk.includes('pA1:')) {
|
||
this.saterDataByType.pA = chunk
|
||
} else if (chunk.includes('pB1:')) {
|
||
this.saterDataByType.pB = chunk
|
||
} else if (chunk.startsWith('ver')) {
|
||
this.saterDataByType.ver = chunk
|
||
}
|
||
}
|
||
const { pA, pB, ver } = this.saterDataByType
|
||
if (pA && pB && ver) {
|
||
this.saterRawPayload = [ver, pA, pB].join('')
|
||
const parsedAB = this.parseSaterRawToAB(this.saterRawPayload)
|
||
this.saterListA = parsedAB.A
|
||
this.saterListB = parsedAB.B
|
||
this.applySaterChannelList()
|
||
if (this.$store) {
|
||
this.$store.commit('setBleWaterData', { raw: this.saterRawPayload })
|
||
}
|
||
}
|
||
} else {
|
||
const pairs = inputString.split(';');
|
||
const pSetObjects = {};
|
||
pairs.forEach(pair => {
|
||
if (!pair) return;
|
||
const [key, value] = pair.split(':');
|
||
if (key && key.startsWith('p_set') && value) {
|
||
try {
|
||
const numbers = value.split(',').map(num => {
|
||
const parsed = parseInt(num);
|
||
return isNaN(parsed) ? 0 : parsed;
|
||
});
|
||
// 只转换开关状态为布尔值
|
||
numbers[3] = numbers[3] === 1;
|
||
pSetObjects[key] = numbers;
|
||
} catch (e) {
|
||
console.error('数据解析错误:', e);
|
||
}
|
||
}
|
||
});
|
||
if (Object.keys(pSetObjects).length > 0) {
|
||
this.list = pSetObjects;
|
||
}
|
||
}
|
||
// 同步到全局 store(SATER 已在上面集齐时同步 saterRawPayload,此处仅处理 WATER/TATER/DATER)
|
||
if (this.$store && this.pre !== 'SATER') {
|
||
this.$store.commit('setBleWaterData', { raw: options.data })
|
||
}
|
||
} else {
|
||
const input = options.data.slice(0, -1) + ";"
|
||
// 去除末尾的分号并分割字符串
|
||
const parts = input.replace(";", "").split(":")
|
||
// 获取时间部分并分割
|
||
const timeParts = parts[1].split(",")
|
||
// 解析为对象
|
||
console.log(timeParts,'timePartstimePartstimeParts');
|
||
this.csbobj = {
|
||
hour: parseInt(timeParts[0]), // 小时
|
||
minute: parseInt(timeParts[1]), // 分钟
|
||
second: parseInt(timeParts[2]), // 秒
|
||
day: parseInt(timeParts[3]) // 天数
|
||
}
|
||
console.log(this.csbobj);
|
||
this.shi = this.csbobj.hour < 10 ? '0' + this.csbobj.hour : this.csbobj.hour
|
||
this.fen = this.csbobj.minute < 10 ? '0' + this.csbobj.minute : this.csbobj.minute
|
||
this.miao = this.csbobj.second
|
||
this.tian = this.csbobj.day
|
||
}
|
||
|
||
this.hideLoading();
|
||
} catch (error) {
|
||
console.error('数据处理错误:', error);
|
||
this.retryOperation();
|
||
}
|
||
break
|
||
}
|
||
},
|
||
// 处理工作时长输入
|
||
handleMiaoInput(e) {
|
||
// 在uni-app中,直接使用e.detail.value获取输入值
|
||
let value = e.detail.value || e.target.value || '';
|
||
console.log('输入值:', value); // 调试用
|
||
|
||
// 转换为数字
|
||
let numValue = parseInt(value) || 0;
|
||
console.log('转换后数值:', numValue); // 调试用
|
||
|
||
// 限制最大值为9999
|
||
if (numValue > 9999) {
|
||
numValue = 9999;
|
||
uni.showToast({
|
||
title: this.$t('dingshi.maxWorkSec'),
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
|
||
// 更新数据
|
||
this.miao = numValue;
|
||
console.log('最终miao值:', this.miao); // 调试用
|
||
},
|
||
|
||
// 处理工作时长失去焦点时的验证
|
||
handleMiaoBlur(e) {
|
||
// 再次验证并限制
|
||
if (this.miao > 9999) {
|
||
this.miao = 9999;
|
||
uni.showToast({
|
||
title: this.$t('dingshi.maxWorkSec'),
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
},
|
||
// 改变天数
|
||
changeDays(change) {
|
||
let newValue = (parseInt(this.jgtian) || 1) + change;
|
||
// 确保天数不小于1
|
||
this.jgtian = Math.max(1, newValue);
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="less">
|
||
::v-deep .u-title {
|
||
margin-bottom: 22rpx;
|
||
}
|
||
|
||
::v-deep .uicon-nav-back {
|
||
margin-bottom: 22rpx;
|
||
}
|
||
|
||
.channel-switch{
|
||
width: 680rpx;
|
||
margin: 22rpx auto 6rpx;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding: 8rpx;
|
||
border-radius: 999rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
.channel-btn{
|
||
min-width: 110rpx;
|
||
height: 56rpx;
|
||
line-height: 56rpx;
|
||
padding: 0 24rpx;
|
||
text-align: center;
|
||
border-radius: 999rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: #6E7C70;
|
||
margin-left: 10rpx;
|
||
background: transparent;
|
||
border: 2rpx solid transparent;
|
||
transition: all .2s ease;
|
||
}
|
||
.channel-btn:first-child{
|
||
margin-left: 0;
|
||
}
|
||
.channel-btn.active{
|
||
color: #fff;
|
||
background: linear-gradient(135deg, #5CA74D 0%, #48893B 100%);
|
||
border-color: #4F9741;
|
||
box-shadow: 0 8rpx 18rpx rgba(72, 137, 59, 0.28);
|
||
transform: translateY(-1rpx);
|
||
}
|
||
.baocun{
|
||
margin: auto;
|
||
width: 680rpx;
|
||
height: 94rpx;
|
||
background: #48893B;
|
||
border-radius: 14rpx 14rpx 14rpx 14rpx;
|
||
margin-top: 50rpx;
|
||
text-align: center;
|
||
line-height: 100rpx;
|
||
border-radius: 20rpx;
|
||
color: #fff;
|
||
font-size: 32rpx;
|
||
}
|
||
.choushuiben{
|
||
width: 680rpx;
|
||
height: 426rpx;
|
||
background: #FFFFFF;
|
||
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0,0,0,0.08);
|
||
border-radius: 20rpx;
|
||
padding: 36rpx 34rpx;
|
||
box-sizing: border-box;
|
||
.tit{
|
||
font-weight: 600;
|
||
font-size: 36rpx;
|
||
color: #3D3D3D;
|
||
}
|
||
.name{
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: 34rpx;
|
||
border-bottom: 1px solid #D8D8D8;
|
||
padding-bottom: 34rpx;
|
||
box-sizing: border-box;
|
||
view{
|
||
display: flex;
|
||
}
|
||
text{
|
||
font-size: 32rpx;
|
||
color: #3D3D3D;
|
||
}
|
||
input{
|
||
width: 100rpx;
|
||
}
|
||
}
|
||
}
|
||
.jiaoshui {
|
||
position: fixed;
|
||
top: 366rpx;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 678rpx;
|
||
max-height: 1200rpx;
|
||
padding-bottom: 30rpx;
|
||
box-sizing: border-box;
|
||
background: #FFFFFF;
|
||
border-radius: 24rpx 24rpx 24rpx 24rpx;
|
||
z-index: 99;
|
||
|
||
.top {
|
||
margin-top: 42rpx;
|
||
width: 100%;
|
||
text-align: center;
|
||
font-size: 44rpx;
|
||
color: #3D3D3D;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.ts {
|
||
margin-top: 30rpx;
|
||
width: 100%;
|
||
text-align: center;
|
||
font-size: 32rpx;
|
||
color: #808080;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.shifen {
|
||
width: 512rpx;
|
||
height: 128rpx;
|
||
background: #F0F0F0;
|
||
border-radius: 16rpx 16rpx 16rpx 16rpx;
|
||
margin: auto;
|
||
margin-top: 30rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
line-height: 128rpx;
|
||
padding: 0 102rpx;
|
||
box-sizing: border-box;
|
||
|
||
text {
|
||
font-size: 44rpx;
|
||
color: #3D3D3D;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.jssc {
|
||
font-size: 32rpx;
|
||
color: #808080;
|
||
font-weight: 600;
|
||
margin-top: 58rpx;
|
||
margin-left: 96rpx;
|
||
}
|
||
|
||
.jiange {
|
||
width: 512rpx;
|
||
margin: 30rpx auto 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
text {
|
||
font-size: 32rpx;
|
||
color: #808080;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.number-input {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #F0F0F0;
|
||
border-radius: 16rpx;
|
||
padding: 0 20rpx;
|
||
height: 80rpx;
|
||
|
||
.btn-minus, .btn-plus {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
line-height: 60rpx;
|
||
text-align: center;
|
||
font-size: 40rpx;
|
||
color: #48893B;
|
||
font-weight: bold;
|
||
background: #fff;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.days {
|
||
margin: 0 30rpx;
|
||
min-width: 60rpx;
|
||
text-align: center;
|
||
font-size: 32rpx;
|
||
color: #3D3D3D;
|
||
}
|
||
}
|
||
}
|
||
|
||
.anniu {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 58rpx;
|
||
padding: 0 44rpx;
|
||
box-sizing: border-box;
|
||
|
||
.qx {
|
||
width: 278rpx;
|
||
height: 80rpx;
|
||
border-radius: 10rpx 10rpx 10rpx 10rpx;
|
||
border: 2rpx solid #7FAD76;
|
||
font-size: 36rpx;
|
||
color: #7FAD76;
|
||
font-weight: 600;
|
||
line-height: 80rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.qd {
|
||
width: 278rpx;
|
||
height: 80rpx;
|
||
background: #7FAD76;
|
||
border-radius: 10rpx 10rpx 10rpx 10rpx;
|
||
font-size: 36rpx;
|
||
color: #fff;
|
||
font-weight: 600;
|
||
line-height: 80rpx;
|
||
text-align: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
.mask {
|
||
width: 100%;
|
||
height: 100vh;
|
||
background-color: #000;
|
||
opacity: .6;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 98;
|
||
}
|
||
|
||
.list {
|
||
.list_val {
|
||
width: 678rpx;
|
||
height: 248rpx;
|
||
background: #FFFFFF;
|
||
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08);
|
||
border-radius: 20rpx;
|
||
padding-top: 16rpx;
|
||
padding-left: 42rpx;
|
||
padding-right: 42rpx;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 30rpx;
|
||
|
||
.lt {
|
||
width: 100%;
|
||
|
||
.one {
|
||
font-size: 72rpx;
|
||
color: #50565A;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.two {
|
||
font-size: 32rpx;
|
||
color: #50565A;
|
||
margin-top: 12rpx;
|
||
|
||
text {
|
||
display: inline-block;
|
||
width: 1rpx;
|
||
height: 28rpx;
|
||
background: #3D3D3D;
|
||
margin-left: 26rpx;
|
||
margin-right: 26rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.rt {
|
||
padding-top: 70rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
}
|
||
}
|
||
|
||
page {
|
||
width: 100%;
|
||
padding: 20rpx 30rpx;
|
||
box-sizing: border-box;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.bj {
|
||
width: 100%;
|
||
height: 100vh;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: -1;
|
||
}
|
||
</style> |