Ver código fonte

feat: 添加阀门分组控制功能及相关配置调整

1. 新增分组控制页面pages/cb/zhamenFirst/controls.vue
2. 在设备列表页添加分组控制入口,仅对指定用户类型和设备类型展示
3. 调整API基础URL配置和页面路由配置
4. 注释部分无用的导航样式配置
allen 9 horas atrás
pai
commit
ec16eb89c2
4 arquivos alterados com 501 adições e 10 exclusões
  1. 9 7
      pages.json
  2. 451 0
      pages/cb/zhamenFirst/controls.vue
  3. 39 1
      pages/equipList2/index.vue
  4. 2 2
      util/api.js

+ 9 - 7
pages.json

@@ -332,7 +332,6 @@
       "style": {
         "navigationBarTitleText": "sim卡详情",
         "enablePullDownRefresh": false
-        // "navigationStyle": "custom"
       }
     },
     {
@@ -764,7 +763,6 @@
       "style": {
         "navigationBarTitleText": "设备位置",
         "enablePullDownRefresh": false
-        // "navigationStyle": "custom"
       }
     },
     {
@@ -1048,6 +1046,14 @@
       }
     },
     {
+      "path": "pages/cb/zhamenFirst/controls",
+      "style": {
+        "navigationBarTitleText": "",
+        "enablePullDownRefresh": false,
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/cb/wenshizs/detail",
       "style": {
         "navigationBarTitleText": "温室大棚系统",
@@ -1191,14 +1197,12 @@
       "path": "pages/disease/mls/mls",
       "style": {
         "navigationBarTitleText": "马铃薯晚疫病详情页"
-        // "navigationStyle": "custom"
       }
     },
     {
       "path": "pages/disease/mls/forecastResult",
       "style": {
         "navigationBarTitleText": "防控决策"
-        // "navigationStyle": "custom"
       }
     },
     {
@@ -1224,7 +1228,6 @@
       "path": "pages/cb/smallPest/xctset",
       "style": {
         "navigationBarTitleText": "设备控制"
-        // "navigationStyle": "custom"
       }
     },
     {
@@ -1403,8 +1406,7 @@
   ],
 
   "condition": {
-    //模式配置,仅开发期间生效
-    "current": 3, //当前激活的模式(list 的索引项)
+    "current": 3,
     "list": [
       {
         "name": "about",

+ 451 - 0
pages/cb/zhamenFirst/controls.vue

@@ -0,0 +1,451 @@
+<template>
+  <view class="control-container">
+    <custom-card>
+      <block slot="backText">{{ title }}</block>
+    </custom-card>
+    <view class="control-content" v-if="leftList.length > 0">
+      <view class="control-list-left">
+        <view
+          class="control-list-left-item"
+          v-for="(item, index) in leftList"
+          :key="index"
+          @click="controlClick(index)"
+          :class="{ 'control-list-left-item-active': index === activeIndex }"
+        >
+          {{ item.title }}
+        </view>
+      </view>
+      <view class="control-list-right">
+        <view class="action-container" v-if="deviceList.length > 0">
+          <view class="action-button" @click="openAll">一键开启</view>
+          <view class="action-button action-button-plain" @click="closeAll">一键关闭</view>
+        </view>
+        <view
+          v-for="(item, index) in deviceList"
+          class="control-list-right-item"
+          :key="index"
+        >
+          <view style="display: flex; align-items: center;" v-if="item.sfType != '10'">
+            <view class="control-list-right-item-icon">
+              <image
+                :src="solenoidValve"
+                class="solenoid-valve"
+              />
+            </view>
+            <view class="control-list-right-item-title">{{
+              item.device_name
+            }}</view>
+            <view class="control-list-right-item-action">
+              <u-switch
+                :value="item.device_status == 1 ? true : false"
+                activeColor="#0BBC58"
+                size="40"
+                inactiveColor="rgb(230, 230, 230)"
+              ></u-switch>
+            </view>
+          </view>
+        </view>
+        <u-empty v-if="deviceList.length === 0" text="暂无数据"></u-empty>
+      </view>
+    </view>
+    <u-empty v-else text="暂无数据"></u-empty>
+    <u-popup v-model="showPopup" mode="bottom">
+			<u-form :model="form" label-width="160rpx" :label-style="{marginLeft:'20rpx'}">
+				<u-form-item label="开启状态">
+					<u-radio-group v-model="value">
+						<u-radio 
+							@change="radioChange" 
+							v-for="(item, index) in radioList" :key="index" 
+							:name="item.value"
+							active-color="#0BBC58"
+						>
+							{{item.name}}
+						</u-radio>
+					</u-radio-group>
+				</u-form-item>
+				<u-form-item label="开阀时间" v-if="value == 1">
+					<view @click="show1 = true" class="hour">{{hour}} 小时</view>
+				</u-form-item>
+				<u-form-item label="开度数值">
+					<view class="slider-row" style="display:flex;align-items:center;"><view class="slider-container">
+          <view class="slider-min-value">10</view>
+          <view
+            class="custom-progress"
+            @touchstart.stop="onSliderTouchStart($event, 'openingValue', 10, 100)"
+            @touchmove="onSliderTouchMove($event, 10, 100)"
+            @touchend.stop="onSliderTouchEnd"
+>
+            <view class="progress-track">
+              <view class="progress-fill" :style="{ width: getProgressWidth(equipContrlForm.openingValue, 10, 100) + '%' }"></view>
+              <view class="progress-thumb" :style="{ left: getProgressWidth(equipContrlForm.openingValue, 10, 100) + '%' }"></view>
+            </view>
+          </view>
+          <view class="slider-max-value">100</view>
+        </view>
+				<text style="margin-left: 20rpx">{{equipContrlForm.openingValue}}</text></view>
+				</u-form-item>
+				<u-button type="success" style="width: 94%;margin-left: 3%;margin-bottom: 40rpx" @click="submit">提交</u-button>
+			</u-form>
+		</u-popup>
+    <u-modal v-model="show2" :title="'提示'"  :content="content" @confirm="confirmHandle" @cancel="show2 = false"></u-modal>
+    <u-select v-model="show1" :list="hours" @confirm="changeHour"></u-select>
+    <u-popup v-model="show4" mode="center" width="80%" :mask-close-able="false">
+			<view class="progress-container">
+				<u-line-progress :percent="percentage" style="width: 90%;"></u-line-progress>
+			</view>
+		</u-popup>
+  </view>
+</template>
+<script>
+import solenoidValve from './assets/solenoidValve.png';
+
+export default {
+  name: 'control',
+  data() {
+    return {
+      show1: false,
+      show2: false,
+      show4: false,
+      percentage: 0,
+      activeIndex: 0,
+      showPopup: false,
+      content:'确定一键关闭所有阀门吗?',
+      value: 0,
+      sliderField: '',
+      sliderMin: 0,
+			hours: [],
+      sliderMax: 0,
+			sliderRect: {},
+      hour: 1,
+      minute: 0,
+      form: {},
+      radioList:[{
+        name:'常开',
+        value:0
+      },
+      {
+        name:'定时',
+        value:1
+      }],
+      equipContrlForm: {
+        openingValue: 60,
+      },
+      solenoidValve,
+      title: '分组控制',
+      leftList: [],
+      deviceList: [],
+      timer: null,
+    };
+  },
+  methods: {
+    changeHour(e){
+      this.hour = e[0].value
+    },
+    setPercentage(msg){
+      this.timer = setInterval(() => {
+        this.percentage += 1;
+        if(this.percentage >= 100){
+          this.percentage = 100;
+          uni.showToast({
+            title: msg,
+            icon: 'none',
+          });
+          clearInterval(this.timer);
+          this.show4 = false;
+          this.percentage = 0;
+          this.getdeviceSfStatus();
+        }
+      }, 125);
+    },
+    getHours(){
+      for(let i = 0; i < 24; i++){
+        this.hours.push({
+          label: i + ' 时',
+          value: i,
+        })
+      }
+    },
+   async confirmHandle(){
+      const data = {
+        group_id: this.leftList[this.activeIndex].id,
+        control_type:'close',
+      };
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=irrigation_system.valvecontrol.control_huapu_valve_group',
+        method: 'post',
+        data
+      });
+      if(res.code == 0){
+        this.show4 = true;
+        this.setPercentage(res.msg);
+      }
+      this.showPopup = false;
+      this.show2 = false;
+    },
+   async submit(){
+      const data = {
+        group_id: this.leftList[this.activeIndex].id,
+        control_type:'open',
+        valve_delayed: this.value == 0 ? 0 : this.hour * 60 + this.minute,
+        var_value: this.equipContrlForm.openingValue,
+      };
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=irrigation_system.valvecontrol.control_huapu_valve_group',
+        method: 'post',
+        data
+      });
+      if(res.code == 0){
+        this.show4 = true;
+        this.setPercentage(res.msg);
+      }
+      this.showPopup = false;
+      this.show2 = false;
+    },
+    getProgressWidth(value, min, max) {
+      if (max === min) return 0
+      return ((value - min) / (max - min)) * 100
+    },
+    getModel(value){
+      return value == 0 ? false : true
+    },
+    controlClick(index) {
+      this.activeIndex = index;
+      this.deviceList = this.leftList[this.activeIndex]?.device_list || [];
+    },
+    onSliderTouchStart(e, field, min, max) {
+      const clientX = e.touches[0].clientX
+      this.sliderField = field
+      this.sliderMin = min
+      this.sliderMax = max
+      const query = uni.createSelectorQuery().in(this)
+      query.selectAll('.custom-progress').boundingClientRect(rects => {
+        const list = Array.isArray(rects) ? rects : []
+        this.sliderRect = list.find(r => r && r.width > 0) || list[0] || null
+        this.updateSliderValue(clientX, field, min, max)
+      }).exec()
+    },
+    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 || !this.sliderRect.width) 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)
+    },
+    openAll(){
+      this.showPopup = true;
+    },
+    closeAll(){
+      this.show2 = true;
+    },
+    initData(res){
+      this.deviceList = [];
+      this.leftList = [];
+      res?.forEach((item) => {
+        this.leftList.push(item);
+      });
+    },
+    async getdeviceSfStatus() {
+      this.activeIndex = 0;
+      const res = await this.$myRequest({
+        url: '/api/api_gateway?method=irrigation_system.valvecontrol.get_huapu_valve_group_list',
+        method: 'post',
+      });
+      this.initData(res?.data || []);
+    },
+  },
+  onLoad() {
+    this.getHours();
+    this.getdeviceSfStatus();
+  },
+};
+</script>
+<style scoped lang="scss">
+uni-page-body {
+  position: relative;
+  height: 100%;
+}
+.progress-container{
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height:100%;
+}
+.hour,.minute{
+  font-size: 28rpx;
+  color: #999999;
+  border-radius: 8rpx;
+  border: 2rpx solid #aaa;
+  padding: 4rpx 8rpx;
+  margin-right: 8rpx;
+  height: 40rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 160rpx;
+}
+.control-container {
+  background: linear-gradient(180deg, #ffffff00 0%, #fff 23.64%, #fff 100%),
+    linear-gradient(102deg, #bfeadd 6.77%, #b8f1e7 40.15%, #b9eef5 84.02%);
+  height: 100%;
+  width: 100%;
+  overflow-x: hidden;
+  overflow-y: hidden;
+  .control-content {
+    display: flex;
+    width: 100%;
+    height: calc(100% - 102rpx);
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 8px 0;
+    border-radius: 8px 8px 0 0;
+    background: #fff;
+    .control-list-left {
+      width: 250rpx;
+      position: fixed;
+      height: calc(100% - 90rpx);
+      overflow-x: hidden;
+      overflow-y: auto;
+      .control-list-left-item {
+        width: 240rpx;
+        height: 96rpx;
+        line-height: 96rpx;
+        background: #f5f7fa;
+        padding-left: 24rpx;
+        color: #364d46;
+        font-family: 'Source Han Sans CN VF';
+        font-size: 32rpx;
+        font-weight: 400;
+        position: relative;
+        //超出隐藏
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+      .control-list-left-item-active {
+        background: #0bbc581a;
+        color:#0BBC58;
+        font-family: "Source Han Sans CN VF";
+        font-size: 32rpx;
+        font-weight: 700;
+      }
+    }
+    .control-list-right {
+      width: calc(100% - 250rpx);
+      margin: 0 32rpx;
+      margin-left: 280rpx;
+      .action-container {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        margin-bottom: 22rpx;
+        gap: 22rpx;
+        .action-button{
+          flex:1;
+          height: 80rpx;
+          line-height: 80rpx;
+          text-align: center;
+          border-radius: 8rpx;
+          background: #0bbc58;
+          color:#ffffff;
+          font-family: "Source Han Sans CN VF";
+          font-size: 28rpx;
+          font-weight: 600;
+        }
+        .action-button-plain{
+          background: #ffffff;
+          border:2rpx solid #0bbc58;
+          color:#0bbc58;
+        }
+      }
+      .control-list-right-item {
+        height: 96rpx;
+        display: flex;
+        padding: 0rpx 16rpx;
+        align-items: center;
+        border-radius: 8rpx;
+        background: #f5f7fa;
+        margin-bottom: 22rpx;
+        position: relative;
+        .control-list-right-item-icon {
+          display: flex;
+          align-items: center;
+          .solenoid-valve {
+            width: 40rpx;
+            height: 40rpx;
+          }
+        }
+        .control-list-right-item-title {
+          margin-left: 8rpx;
+        }
+        .control-list-right-item-action {
+          position: absolute;
+          right: 16rpx;
+        }
+      }
+    }
+  }
+  
+  .slider-container{
+    position: relative;
+    margin-top: 10rpx;
+    .slider-min-value{
+      position: absolute;
+      left: 0;
+      top: -60rpx;
+    }
+    .slider{
+      width: 600rpx;
+    }
+    .slider-max-value{
+      position: absolute;
+      right: 0;
+      top: -60rpx;
+    }
+  }
+  .custom-progress{
+    width: 500rpx;
+    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;
+    }
+  }
+}
+</style>

+ 39 - 1
pages/equipList2/index.vue

@@ -133,6 +133,9 @@
 									</view>
 								</view>
 							</view>
+							<view class="action-group" v-if="type_id == 49 && myuser_type == 4">
+								<view class="action-item" @click="toControls(item)">分组控制</view>
+							</view>
 						</view>
 					</view>
 				</scroll-view>
@@ -159,7 +162,7 @@
 				</u-form-item>
 				<u-form-item label="开阀时间" v-if="value == 1">
 					<view @click="show1 = true" class="hour">{{hour}} 小时</view>
-					<view @click="show2 = true" class="minute">{{minute}} 分钟</view>
+					<!-- <view @click="show2 = true" class="minute">{{minute}} 分钟</view> -->
 				</u-form-item>
 				<u-form-item label="开度数值">
 					<view class="slider-container">
@@ -306,10 +309,16 @@ import openingDegree from '../assets/openingDegree.png';
 				sliderMin: 0,
 				sliderMax: 0,
 				timer: null,
+				myuser_type: -1,
 				valve_param_key: '',
 			};
 		},
 		methods: {
+			toControls(item){
+				uni.navigateTo({
+					url: '/pages/cb/zhamenFirst/controls?id=' + item.id,
+				});
+			},
 			getvalve_params(item){
 				return item?.valve_params || [];
 			},
@@ -1080,6 +1089,12 @@ import openingDegree from '../assets/openingDegree.png';
 			uni.$on('refreshData', (refreshData) => {
 				this.eqlist();
 			});
+			uni.getStorage({
+				key:"myuser_type",
+				success:(res)=>{
+					this.myuser_type = res?.data;
+				}
+			})
 			this.getUserlogin();
 		},
 		onShow() {
@@ -1394,6 +1409,29 @@ import openingDegree from '../assets/openingDegree.png';
 			background: linear-gradient(0deg, #0bbc580f 0%, #0bbc580f 100%), #00000005;
 		}
 	}
+	.action-group{
+		display: flex;
+		align-items: center;
+		gap: 16rpx;
+		margin-top: 24rpx;
+		.action-item{
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex:1;
+			text-align: center;
+			border-radius: 8rpx;
+			border:2rpx solid #0BBC58;
+			padding: 16rpx 0;
+			font-size: 24rpx;
+			color: #0BBC58;
+			.item-icon{
+				width: 15px;
+				height: 15px;
+				margin-right: 4px;
+			}
+		}
+	}
 	.second-tab {
 		height: 80rpx;
 		.tab-item{

+ 2 - 2
util/api.js

@@ -9,10 +9,10 @@ export const myRequest = (options) => {
     //      ? 'https://uat.hnyfwlw.com'
     //      : 'https://web.hnyfwlw.com';
     // BASE_URL = 'http://192.168.1.107:8000'
-    // BASE_URL = 'http://218.28.198.186:10508';
+    BASE_URL = 'http://218.28.198.186:10508';
     // BASE_URL = 'http://8.136.98.49:8002';
   }
-  BASE_URL = config.productAPI;
+  // BASE_URL = config.productAPI;
   // BASE_URL = config.developAPI;
   var session_key = '';
   session_key = uni.getStorageSync('session_key');