Browse Source

feat(scd/deviceControl): 重构设备控制页面,新增多项功能与优化界面

1. 拆分联网模块操作按钮,新增主板升级、一键测试等多个控制入口
2. 重构详情展示区域,新增版本号、设备开关、定时模式等信息展示
3. 替换原生slider为自定义进度滑块,优化数据间隔和清虫间隔调节体验
4. 重构定时选择逻辑,新增定时模式和时长选择弹窗
5. 简化表单提交和数据初始化逻辑,优化代码可维护性
6. 调整按钮容器布局和样式细节
allen 12 giờ trước cách đây
mục cha
commit
9d61fde5fc
1 tập tin đã thay đổi với 276 bổ sung142 xóa
  1. 276 142
      pages/scd/deviceControl.vue

+ 276 - 142
pages/scd/deviceControl.vue

@@ -24,8 +24,15 @@
         <view class="device-detail-item">
           <text class="device-detail-label">联网模块</text>
           <view class="device-detail-btn-container">
-            <view class="device-detail-btn" @click="setDeviceContorl('dtu_update')">升级</view>
-            <view class="device-detail-btn" @click="setDeviceContorl('dtu_reboot')">重启</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('update_stm32')">主板升级</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('update')">物联网模块升级</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('reboot')">重启</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('test')">一键测试</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('yfwlw')">平台切换</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('paramconf1')">标配物联网</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('paramconf2')">物联网自清虫</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('paramconf3')">物联网光控</view>
+            <view class="device-detail-btn" @click="setDeviceContorl('paramconf4')">物联网光控自清虫</view>
             <!-- <view class="device-detail-btn" @click="showMqttConfig">MQTT配置</view> -->
           </view>
         </view>
@@ -47,44 +54,115 @@
         </view> -->
       </view>
       <view class="device-detail-content" style="padding-bottom: 50rpx" v-if="activeTab === 'viewImage'">
+        <!-- <view class="device-detail-viewImage">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            设备编号
+          </text>
+          <view class="clear-btn">{{ equipContrlForm.imei || '-' }}</view>
+        </view>
+        <view class="device-detail-viewImage">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            设备名称
+          </text>
+          <view class="clear-btn">{{ equipContrlForm.device_name || '-' }}</view>
+        </view> -->
         <view class="device-detail-viewImage">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            主板版本号
+          </text>
+          <view class="clear-btn">{{ equipContrlForm.stm8vs || '-' }}</view>
+        </view>
+        <view class="device-detail-viewImage">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            联网版本号
+          </text>
+          <view class="clear-btn">{{ equipContrlForm.dver || '-' }}</view>
+        </view>
+        <view class="device-detail-viewImage">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            设备开关
+          </text>
+          <u-switch
+            v-model="equipContrlForm.ds"
+            size="32"
+            :active-value="1"
+            :inactive-value="0"
+            active-color="#0bbc58"
+            style="position:absolute;right:0"
+          ></u-switch>
+        </view>
+        <view class="device-detail-viewImage">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            定时模式
+          </text>
+          <view class="clear-btn" @click="timeSet('ts')">{{ equipContrlForm.ts === '0' ? '光控' : '时控' }}</view>
+        </view>
+        <view class="device-detail-viewImage" v-if="equipContrlForm.ts !== '1'">
           <u-icon name="clock" color="#0bbc58" size="46"></u-icon>
           <text class="device-detail-label" style="margin-left: 10rpx">
-            采集开始和关闭时间
+            定时时长(h)
+          </text>
+          <view class="clear-btn" @click="timeSetLang('tt')">{{ equipContrlForm.tt == '0'?'常亮':equipContrlForm.tt || '-' }}</view>
+        </view>
+        <view v-if="equipContrlForm.ts === '1'">
+          <text class="device-detail-label" style="margin-left: 10rpx">
+            开始结束时间
           </text>
-          <view class="clear-btn" @click="clearTime">清空</view>
         </view>
-        <view class="time-container" v-for="(item,index) in coll_time" :key="index">
-          <view class="start-time" @click="showPickerHandler(index,'start_time')">{{item.start_time_label || '开始时间'}}</view>-
-          <view class="end-time" @click="showPickerHandler(index,'end_time')">{{item.end_time_label || '结束时间'}}
+        <view class="time-container" v-if="equipContrlForm.ts === '1'">
+          <view class="start-time" @click="showPickerHandler('start_time')">{{start_time_label || '开始时间'}}</view>-
+          <view class="end-time" @click="showPickerHandler('end_time')">{{end_time_label || '结束时间'}}
           </view><u-icon name="clock" color="#4E5969" size="26" style="padding-right: 20rpx"></u-icon>
         </view>
         <view class="device-detail-viewImage">
-          <text class="device-detail-label">高温保护阀值(℃)
-          {{ equipContrlForm.tph }}</text>
+          <text class="device-detail-label">数据间隔(min)
+          {{ equipContrlForm.dattim }}</text>
         </view>
-        <view class="slider-container">
+        <!-- <view class="slider-container">
           <view class="slider-min-value">50</view>
-          <u-slider :value="equipContrlForm.tph" @input="e => equipContrlForm.tph = e" class="slider" :min="50" :max="70" active-color="#0bbc58"></u-slider>
+          <u-slider :value="equipContrlForm.dattim" @input="e => equipContrlForm.dattim = e" class="slider" :min="10" :max="120" active-color="#0bbc58"></u-slider>
           <view class="slider-max-value">70</view>
+        </view> -->
+        <view class="slider-container">
+          <view class="slider-min-value">10</view>
+          <view
+            class="custom-progress"
+            @touchstart.stop="onSliderTouchStart($event, 'dattim', 10, 120)"
+            @touchmove.stop.prevent="onSliderTouchMove($event, 10, 120)"
+            @touchend.stop="onSliderTouchEnd"
+            @tap.stop="onSliderTap($event, 'dattim', 10, 120)"
+          >
+            <view class="progress-track">
+              <view class="progress-fill" :style="{ width: getProgressWidth(equipContrlForm.dattim, 10, 120) + '%' }"></view>
+              <view class="progress-thumb" :style="{ left: getProgressWidth(equipContrlForm.dattim, 10, 120) + '%' }"></view>
+            </view>
+          </view>
+          <view class="slider-max-value">120</view>
         </view>
         <view class="device-detail-viewImage">
-          <text class="device-detail-label">低温保护阀值(℃)
-          {{ equipContrlForm.tpl }}</text>
+          <text class="device-detail-label">清虫间隔(min)
+          {{ equipContrlForm.clt }}</text>
         </view>
-        <view class="slider-container">
+        <!-- <view class="slider-container">
           <view class="slider-min-value">-30</view>
-          <u-slider :value="equipContrlForm.tpl" @input="e => equipContrlForm.tpl = e" class="slider" :min="-30" :max="20" active-color="#0bbc58"></u-slider>
+          <u-slider :value="equipContrlForm.clt" @input="e => equipContrlForm.clt = e" class="slider" :min="10" :max="120" active-color="#0bbc58"></u-slider>
           <view class="slider-max-value">20</view>
-        </view>
-        <view class="device-detail-viewImage">
-          <text class="device-detail-label">数据上传间隔(min)
-          {{ equipContrlForm.datt }}</text>
-        </view>
+        </view> -->
         <view class="slider-container">
           <view class="slider-min-value">10</view>
-          <u-slider :value="equipContrlForm.datt" @input="e => equipContrlForm.datt = e" :max="60" :min="10" active-color="#0bbc58" class="slider"></u-slider>
-          <view class="slider-max-value">60</view>
+          <view
+            class="custom-progress"
+            @touchstart.stop="onSliderTouchStart($event, 'clt', 10, 120)"
+            @touchmove.stop.prevent="onSliderTouchMove($event, 10, 120)"
+            @touchend.stop="onSliderTouchEnd"
+            @tap.stop="onSliderTap($event, 'clt', 10, 120)"
+          >
+            <view class="progress-track">
+              <view class="progress-fill" :style="{ width: getProgressWidth(equipContrlForm.clt, 10, 120) + '%' }"></view>
+              <view class="progress-thumb" :style="{ left: getProgressWidth(equipContrlForm.clt, 10, 120) + '%' }"></view>
+            </view>
+          </view>
+          <view class="slider-max-value">120</view>
         </view>
       </view>
     </view>
@@ -103,6 +181,8 @@
       </view>
 		</u-popup>
 		<u-select v-model="showPicker" :list="timeList" @confirm="confirmPicker"></u-select>
+		<u-select v-model="showTimePicker" :list="list" @confirm="confirmTimePicker"></u-select>
+		<u-select v-model="showTimeLangPicker" :list="list2" @confirm="confirmTimeLangPicker"></u-select>
   </view>
 </template>
 <script>
@@ -114,26 +194,57 @@ export default {
       value: 10,
       timeList: [],
       imageList: [],
+      start_time_label: '',
+      end_time_label: '',
+      start_time: '',
+      end_time: '',
+      list: [{
+        value: '0',
+        label: '光控'
+      },
+      {
+        value: '1',
+        label: '时控'
+      }],
+      list2: [{
+        value: '0',
+        label: '常亮'
+      },
+      {
+        value: '1',
+        label: '1'
+      },
+      {
+        value: '2',
+        label: '2'
+      },
+      {
+        value: '3',
+        label: '3'
+      },
+      {
+        value: '4',
+        label: '4'
+      },
+      {
+        value: '5',
+        label: '5'
+      },
+      {
+        value: '6',
+        label: '6'
+      },
+      {
+        value: '7',
+        label: '7'
+      }],
       coll_time:[{
         start_time: '',
         start_time_label: '',
         end_time: '',
         end_time_label: '',
-      },{
-        start_time: '',
-        start_time_label: '',
-        end_time: '',
-        end_time_label: '',
-      },{
-        start_time: '',
-        start_time_label: '',
-        end_time: '',
-        end_time_label: '',
       }],
       equipContrlForm: {
-        tph: 0,
-        tpl: 0,
-        datt: 0,
       },
       time: '',
       activeTab: 'pestAnalysis',
@@ -143,6 +254,8 @@ export default {
       d_id: '',
       show: false,
       checked: false,
+      showTimePicker: false,
+      showTimeLangPicker: false,
       currentIndex: -1,
       myuser_type: false,
       currentType: ''
@@ -171,6 +284,55 @@ export default {
     })
   },
   methods: {
+    getProgressWidth(value, min, max) {
+      if (max === min) return 0
+      return ((value - min) / (max - min)) * 100
+    },
+    onSliderTouchStart(e, field, min, max) {
+      this.sliderField = field
+      this.sliderMin = min
+      this.sliderMax = max
+      const query = uni.createSelectorQuery().in(this)
+      query.select('.custom-progress').boundingClientRect(rect => {
+        this.sliderRect = rect
+      }).exec()
+      this.updateSliderValue(e.touches[0].clientX, field, min, max)
+    },
+    onSliderTouchMove(e, min, max) {
+      if (!this.sliderField || !this.sliderRect) return
+      this.updateSliderValue(e.touches[0].clientX, this.sliderField, min, max)
+    },
+    onSliderTouchEnd() {
+      this.sliderField = ''
+    },
+    onSliderTap(e, field, min, max) {
+      const query = uni.createSelectorQuery().in(this)
+      query.select('.custom-progress').boundingClientRect(rect => {
+        this.sliderRect = rect
+        this.updateSliderValue(e.detail.x + rect.left, field, min, max)
+      }).exec()
+    },
+    updateSliderValue(clientX, field, min, max) {
+      if (!this.sliderRect) return
+      let ratio = (clientX - this.sliderRect.left) / this.sliderRect.width
+      ratio = Math.max(0, Math.min(1, ratio))
+      const value = Math.round(min + ratio * (max - min))
+      this.$set(this.equipContrlForm, field, value)
+    },
+    confirmTimePicker(e){
+      const value = e[0].value;
+      this.equipContrlForm.ts = value;
+    },
+    confirmTimeLangPicker(e){
+      const value = e[0].value;
+      this.equipContrlForm.tt = value;
+    },
+    timeSet(){
+      this.showTimePicker = true;
+    },
+    timeSetLang(type){
+      this.showTimeLangPicker = true;
+    },
     clearTime(){
       this.coll_time.forEach(item => {
         item.start_time = '';
@@ -182,58 +344,17 @@ export default {
     confirmPicker(e){
       const value = e[0].value;
       const label = e[0].label;
-      if(this.currentType == 'end_time'){
-        if(this.coll_time[this.currentIndex]['start_time'] > value){
-          uni.showToast({
-            title: '结束时间不能早于开始时间',
-            icon: 'none',
-          })
-          return
-        }
-      }
-      if(this.currentType == 'start_time' && this.currentIndex > 0){
-        if(this.coll_time[this.currentIndex-1]['end_time'] > value){
-          uni.showToast({
-            title: '开始时间不能早于前面采集时间的结束时间',
-            icon: 'none',
-          })
-          return
-        }
-      }
-      if(this.currentType == 'start_time' && this.coll_time[this.currentIndex]['end_time'] !== ''){
-        if(value > this.coll_time[this.currentIndex]['end_time']){
-          uni.showToast({
-            title: '开始时间不能晚于结束时间',
-            icon: 'none',
-          })
-          return
-        }
+      if(this.currentType == 'start_time'){
+        this.start_time_label = label
+        this.start_time = value
+      }else{
+        this.end_time_label = label
+        this.end_time = value
       }
-      this.coll_time[this.currentIndex][this.currentType] = value;
-      this.coll_time[this.currentIndex][this.currentType + '_label'] = label;
     },
-    showPickerHandler(index,type){
-      if(type == 'end_time'){
-        if(this.coll_time[index]['start_time'] === ''){
-          uni.showToast({
-            title: '请先选择开始时间',
-            icon: 'none',
-          })
-          return
-        }
-      }
-      if(index != 0){
-        if(this.coll_time[index-1]['start_time_label'] === '' || this.coll_time[index-1]['end_time_label'] === ''){
-          uni.showToast({
-            title: '请先选择前面采集时间的开始和结束时间',
-            icon: 'none',
-          })
-          return
-        }
-      }
-      this.showPicker = true;
-      this.currentIndex = index
+    showPickerHandler(type){
       this.currentType = type
+      this.showPicker = true;
     },
     closePicker(){
       this.showPicker = false;
@@ -254,21 +375,15 @@ export default {
     closeMqttConfig(){
       this.show = false;
     },
-    async setDeviceContorl(type){
-      const data = {
-        device_type_id: 2,
-        d_id: this.d_id,
-        cmd: type,
-      }
-      if(type === 'imei'){
-        data.imei = this.equipContrlForm.imei
-      }else{
-        delete data.imei
-      }
+    async setDeviceContorl(cmd){
       this.$myRequest({
         url: '/api/api_gateway?method=forecast.send_control.admin_device_control',
         method: 'POST',
-        data
+        data: {
+          device_type_id: 2,
+          d_id: this.d_id,
+          cmd
+        }
       }).then(res => {
         this.closeMqttConfig()
         if (res) {
@@ -286,31 +401,9 @@ export default {
     },
     saveSettings(){
       let newForm = Object.assign({}, this.equipContrlForm) // 深拷贝
-      newForm.st = newForm.st + ''
-      newForm.et = newForm.et + ''
-      newForm.st && newForm.st.slice(0, 2).charAt(0) != '0'
-        ? newForm.st.slice(0, 2)
-        : newForm.st.slice(1, 2)
-      newForm.et =
-        newForm.et && newForm.et.slice(0, 2).charAt(0) != '0'
-          ? newForm.et.slice(0, 2)
-          : newForm.et.slice(1, 2)
-
-      for (let k in newForm) {
-        if (typeof newForm[k] === 'number') {
-          newForm[k] = newForm[k] + ''
-        }
-      }
-      newForm.st = newForm.st.replace(':00', '')
-      console.log(this.coll_time,'coll_timecoll_timecoll_time')
-      const coll_time = [];
-      for(let i = 0;i< this.coll_time.length;i++){
-        const coll_item = this.coll_time[i];
-        if(String(coll_item.start_time) && String(coll_item.end_time)){
-          coll_time.push(String(coll_item.start_time) + '-' + String(coll_item.end_time))
-        }
-      }
-      newForm.coll_time = coll_time
+      newForm.ds = newForm.ds ? 1 : 0
+      newForm.st = this.start_time
+      newForm.et = this.end_time
       this.$myRequest({
         url: '/api/api_gateway?method=forecast.send_control.device_control',
         method: 'POST',
@@ -343,22 +436,33 @@ export default {
           cmd:'paramconf'
         },
       });
-      this.equipContrlForm = res
-      const coll_time = res?.coll_time || [];
-      for(let i = 0;i< coll_time.length;i++){
-        const coll_item = coll_time[i];
-        const start_time = coll_item.split('-')[0];
-        const end_time = coll_item.split('-')[1];
-        this.coll_time[i]['start_time'] = start_time;
-        this.coll_time[i]['end_time'] = end_time;
-        this.coll_time[i]['start_time_label'] = start_time >= 10 ? start_time + ':00' : '0' + start_time + ':00';
-        this.coll_time[i]['end_time_label'] = end_time >= 10 ? end_time + ':00' : '0' + end_time + ':00';
-      }
-      console.log(this.coll_time,'coll_timecoll_timecoll_time')
+
+      this.equipContrlForm = {
+        st: res.st,
+        et: res.et,
+        ds: res.ds,
+        ts: res.ts,
+        tt: res.tt,
+        dver: res.dver,
+        dattim: res.dat_f,
+        clt: res.clt_t,
+        stm8vs: res.stm8vs
+      };
+      this.start_time = res?.st || ''
+      this.end_time = res?.et || ''
+      this.start_time_label = this.start_time >= 10 ? this.start_time + ':00' : '0' + this.start_time + ':00'
+      this.end_time_label = this.end_time >= 10 ? this.end_time + ':00' : '0' + this.end_time + ':00'
+      // const coll_time = res?.coll_time || [];
+      // for(let i = 0;i< coll_time.length;i++){
+      //   const coll_item = coll_time[i];
+      //   const start_time = coll_item.split('-')[0];
+      //   const end_time = coll_item.split('-')[1];
+      //   this.coll_time[i]['start_time'] = start_time;
+      //   this.coll_time[i]['end_time'] = end_time;
+      //   this.coll_time[i]['start_time_label'] = start_time >= 10 ? start_time + ':00' : '0' + start_time + ':00';
+      //   this.coll_time[i]['end_time_label'] = end_time >= 10 ? end_time + ':00' : '0' + end_time + ':00';
+      // }
       // 确保值是数字类型,并且使用默认值时也要在合理范围内
-      this.equipContrlForm.tph = this.equipContrlForm.tph !== undefined && this.equipContrlForm.tph !== '' && !isNaN(this.equipContrlForm.tph) ? Number(this.equipContrlForm.tph) : 50;
-      this.equipContrlForm.tpl = this.equipContrlForm.tpl !== undefined && this.equipContrlForm.tpl !== '' && !isNaN(this.equipContrlForm.tpl) ? Number(this.equipContrlForm.tpl) : 0;
-      this.equipContrlForm.datt = this.equipContrlForm.datt !== undefined && this.equipContrlForm.datt !== '' && !isNaN(this.equipContrlForm.datt) ? Number(this.equipContrlForm.datt) : 10;
     },
   }
 }
@@ -468,7 +572,7 @@ export default {
   }
   .device-detail-content{
     display: flex;
-    padding: 24rpx 32rpx;
+    padding: 24rpx;
     flex-direction: column;
     align-items: flex-start;
     gap: 20rpx;
@@ -482,13 +586,14 @@ export default {
         font-weight: 400;
       }
       .device-detail-btn-container{
-        display: flex;
+        display: grid;
+        grid-template-columns: repeat(3, 1fr);
         gap: 24rpx;
         margin-top: 12rpx;
       }
       .device-detail-btn{
         display: flex;
-        padding: 10rpx 16rpx;
+        padding: 10rpx;
         justify-content: center;
         align-items: center;
         gap: 16rpx;
@@ -512,11 +617,9 @@ export default {
       .clear-btn{
         position: absolute;
         right: 0rpx;
-        border: 1rpx solid #0bbc58;
         border-radius: 8rpx;
         padding: 4rpx 12rpx;
-        font-size: 24rpx;
-        color: #0bbc58;
+        font-size: 26rpx;
         font-family: 'Source Han Sans CN VF';
         font-weight: 400;
       }
@@ -539,6 +642,37 @@ export default {
       top: -50rpx;
     }
   }
+  .custom-progress{
+    width: 600rpx;
+    padding: 0;
+    .progress-track{
+      position: relative;
+      height: 12rpx;
+      background-color: #ebedf0;
+      border-radius: 6rpx;
+    }
+    .progress-fill{
+      position: absolute;
+      left: 0;
+      top: 0;
+      height: 100%;
+      background-color: #0BBC58;
+      border-radius: 6rpx;
+      transition: width 0.2s;
+    }
+    .progress-thumb{
+      position: absolute;
+      top: 50%;
+      width: 28rpx;
+      height: 28rpx;
+      margin-left: -14rpx;
+      margin-top: -14rpx;
+      border-radius: 50%;
+      background-color: #fff;
+      box-shadow: 0 1px 4px rgba(0,0,0,0.3);
+      transition: left 0.2s;
+    }
+  }
   .device-detail-btn-footer{
     position: fixed;
     bottom: 0;