jiuling пре 11 месеци
родитељ
комит
41c4068ada

+ 176 - 0
api/services/device.js

@@ -0,0 +1,176 @@
+/**
+ * 设备管理相关API
+ */
+
+import {
+  http,
+  Method
+} from '@/utils/request.js';
+import storage from "@/utils/storage.js";
+const request = http.request;
+const userInfo = storage.getUserInfo()
+/**
+ * 获取设备概览数据
+ * @param {string} fieldId - 地块ID,可选
+ * @returns {Promise} 设备概览数据
+ */
+export function fetchDeviceOverview(fieldId) {
+  const params = {};
+  console.log("userInfo请求:",userInfo);
+  if (userInfo.userId) params.userId = userInfo.userId;
+  if (fieldId) params.fieldId = fieldId;
+  
+  return http.request({
+    url: 'uniapp/device/overview',
+    method: Method.POST,
+    data: params
+  });
+}
+
+/**
+ * 根据设备类型获取设备列表
+ * @param {string} type - 设备类型(monitor-监控设备,sensor-采集设备,control-控制设备,irrigation-灌溉设备,tractor-农机设备)
+ * @param {Object} params - 查询参数
+ * @returns {Promise} 设备列表
+ */
+export function fetchDevicesByType(params) {
+if (userInfo.userId) params.userId = userInfo.userId;
+  return http.request({
+    url: `uniapp/device/typeList`,
+    method: Method.POST,
+    data: params
+  });
+}
+
+/**
+ * 获取所有设备列表
+ * @param {Object} params - 查询参数
+ * @param {number} params.pageNum - 页码
+ * @param {number} params.pageSize - 每页数量
+ * @param {string} params.deviceName - 设备名称,可选
+ * @param {string} params.deviceTypeId - 设备类型ID,可选
+ * @param {number} params.status - 设备状态,可选
+ * @returns {Promise} 设备列表
+ */
+export function fetchDeviceList(params = {}) {
+  return http.request({
+    url: 'uniapp/device/list',
+    method: Method.GET,
+    params: params
+  });
+}
+
+/**
+ * 获取设备详情
+ * @param {number} id - 设备ID
+ * @returns {Promise} 设备详情
+ */
+export function getDeviceDetail(id) {
+  return http.request({
+    url: `uniapp/device/${id}`,
+    method: Method.GET
+  });
+}
+
+/**
+ * 获取设备采集器详情(包含气象/土壤数据和告警信息)
+ * @param {number} id - 设备编码
+ * @param {string} code - 设备编码,可选,用于判断设备类型
+ * @returns {Promise} 设备详情数据
+ */
+export function getDeviceCollectorDetail(deviceId, code) {
+  return http.request({
+    url: `uniapp/device/collector/detail/${deviceId}`,
+    method: Method.GET,
+    params: code ? { code } : {}
+  });
+}
+
+/**
+ * 添加设备
+ * @param {Object} data - 设备信息
+ * @returns {Promise} 添加结果
+ */
+export function addDevice(data) {
+  return http.request({
+    url: 'uniapp/device',
+    method: Method.POST,
+    data: data
+  });
+}
+
+/**
+ * 更新设备信息
+ * @param {Object} data - 设备信息
+ * @returns {Promise} 更新结果
+ */
+export function updateDevice(data) {
+  return http.request({
+    url: 'uniapp/device',
+    method: Method.PUT,
+    data: data
+  });
+}
+
+/**
+ * 删除设备
+ * @param {number|number[]} ids - 设备ID或ID数组
+ * @returns {Promise} 删除结果
+ */
+export function deleteDevice(ids) {
+  const idStr = Array.isArray(ids) ? ids.join(',') : ids;
+  return http.request({
+    url: `uniapp/device/${idStr}`,
+    method: Method.DELETE
+  });
+}
+
+/**
+ * 根据用户ID获取关联的设备列表
+ * @param {Object} params - 查询参数
+ * @returns {Promise} 设备列表
+ */
+export function fetchUserDeviceList(params = {}) {
+  const user = storage.getUserInfo();
+  return http.request({
+    url: 'uniapp/device/user/list',
+    method: Method.GET,
+    params: {
+      ...params,
+      userId: user.userId
+    }
+  });
+}
+
+/**
+ * 根据地块ID获取设备列表
+ * @param {string} fieldId - 地块ID
+ * @param {Object} params - 其他查询参数
+ * @returns {Promise} 设备列表
+ */
+export function fetchFieldDeviceList(fieldId, params = {}) {
+  return http.request({
+    url: 'uniapp/device/list',
+    method: Method.GET,
+    params: {
+      ...params,
+      fieldId: fieldId
+    }
+  });
+}
+
+/**
+ * 获取设备类型统计数据
+ * @param {string} fieldId - 地块ID,可选
+ * @returns {Promise} 设备类型统计数据
+ */
+export function fetchDeviceTypeStats(fieldId) {
+  const params = {};
+  if (fieldId) params.fieldId = fieldId;
+  
+  return http.request({
+    url: 'uniapp/device/stats/type',
+    method: Method.GET,
+    params: params
+  });
+} 

+ 3 - 3
pages.json

@@ -34,7 +34,7 @@
 	      }
 	    },
     {
-          "path": "pages/device-list/detail-camera",
+          "path": "pages/device/device-list/detail-camera",
           "style": {
             "navigationBarTitleText": "监控设备详情",
             "navigationBarBackgroundColor": "#ffffff",
@@ -43,7 +43,7 @@
           }
         },
         {
-          "path": "pages/device-list/detail-collector",
+          "path": "pages/device/device-list/detail-collector",
           "style": {
             "navigationBarTitleText": "采集设备详情",
             "navigationBarBackgroundColor": "#ffffff",
@@ -52,7 +52,7 @@
           }
         },
 		{
-		      "path": "pages/device-list/index",
+		      "path": "pages/device/device-list/index",
 		      "style": {
 		        "navigationBarTitleText": "设备列表",
 		        "navigationBarBackgroundColor": "#ffffff",

+ 3 - 2
pages/device-list/detail-camera.vue → pages/device/device-list/detail-camera.vue

@@ -46,7 +46,7 @@
     <view class="video-section">
       <view class="video-container">
         <image v-if="!isPlaying" src="/static/images/video-placeholder.jpg" mode="aspectFill" class="video-placeholder"></image>
-        <video 
+        <!-- <video 
           v-else
           id="videoPlayer" 
           :src="deviceInfo.streamUrl"
@@ -59,7 +59,8 @@
           :show-play-btn="false"
           :enable-progress-gesture="false"
           @error="handleVideoError"
-        ></video>
+        ></video> -->
+		<iframe v-else src="http://121.4.16.100:28080/#/play/wasm/ws%3A%2F%2F121.4.16.100%3A6080%2Frtp%2F34020000001110000001_34020000001320000012.live.flv"></iframe>
         
         <!-- 视频控制层 -->
         <view class="video-controls">

+ 233 - 336
pages/device-list/detail-collector.vue → pages/device/device-list/detail-collector.vue

@@ -7,10 +7,10 @@
           <text class="device-name">{{ deviceInfo.name }}</text>
           <view 
             class="status-tag" 
-            :class="deviceInfo.status === 'online' ? 'status-online' : 'status-offline'"
+            :class="deviceInfo.status === 1 ? 'status-online' : 'status-offline'"
           >
-            <view class="status-dot" :class="{'offline-dot': deviceInfo.status === 'offline'}"></view>
-            {{ deviceInfo.status === 'online' ? '在线' : '离线' }}
+            <view class="status-dot" :class="{'offline-dot': deviceInfo.status === 1}"></view>
+            {{ deviceInfo.status === 1 ? '在线' : '离线' }}
           </view>
         </view>
         
@@ -41,13 +41,13 @@
             <image src="/static/icons/clock_icon.png" mode="aspectFit" style="width: 36rpx; height: 36rpx;"></image>
           </view>
           <text class="meta-label">最近更新:</text>
-          <text class="meta-value">{{ deviceInfo.lastUpdate }}</text>
+          <text class="meta-value">{{ formatDate(deviceInfo.lastUpdate) }}</text>
         </view>
       </view>
     </view>
     
     <!-- 采集数据展示区域 - 气象站 -->
-    <view class="data-section" v-if="deviceInfo.deviceType === 'weather'">
+    <view class="data-section" v-if="deviceInfo.deviceTypeId === '4'">
       <view class="section-title data-title">
         <text>气象数据</text>
       </view>
@@ -65,8 +65,8 @@
               <text class="data-unit">℃</text>
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
-          </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          </view> 
+          <text class="data-time" v-if="weatherData.temperature">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 湿度 -->
@@ -82,7 +82,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          <text class="data-time" v-if="weatherData.humidity">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 降雨量 -->
@@ -98,7 +98,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          <text class="data-time" v-if="weatherData.rainfall">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 风向 -->
@@ -111,7 +111,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          <text class="data-time" v-if="weatherData.windDirection">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 风速 -->
@@ -128,7 +128,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          <text class="data-time" v-if="weatherData.windSpeed">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 气压 -->
@@ -141,7 +141,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          <text class="data-time" v-if="weatherData.pressure">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 光照 -->
@@ -154,13 +154,13 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ weatherData.updateTime || '2分钟前' }}</text>
+          <text class="data-time" v-if="weatherData.illumination">{{ formatDate(weatherData.updateTime) || '未知' }}</text>
         </view>
       </view>
     </view>
     
     <!-- 采集数据展示区域 - 土壤墒情 -->
-    <view class="data-section" v-if="deviceInfo.deviceType === 'soil'">
+    <view class="data-section" v-if="deviceInfo.deviceTypeId === '1'">
       <view class="section-title soil-title">
         <text>土壤数据</text>
       </view>
@@ -179,7 +179,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.temperature">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 土壤湿度 -->
@@ -196,7 +196,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.moisture">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 氮含量 -->
@@ -212,7 +212,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.nitrogen">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 磷含量 -->
@@ -228,7 +228,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.phosphorus">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 钾含量 -->
@@ -244,7 +244,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.potassium">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- 土壤电导率 -->
@@ -260,7 +260,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.conductivity">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
         
         <!-- PH值 -->
@@ -277,7 +277,7 @@
             </template>
             <text v-else class="data-value no-data">暂无数据</text>
           </view>
-          <text class="data-time">{{ soilData.updateTime || '5分钟前' }}</text>
+          <text class="data-time" v-if="soilData.ph">{{ formatDate(soilData.updateTime) || '未知' }}</text>
         </view>
       </view>
     </view>
@@ -295,25 +295,25 @@
           :key="index"
           class="alert-item"
           :class="{
-            'alert-urgent': item.level === 'high', 
-            'alert-warning': item.level === 'medium', 
-            'alert-info': item.level === 'low'
+            'alert-urgent': item.level === 3, 
+            'alert-warning': item.level === 2, 
+            'alert-info': item.level === 1
           }"
         >
           <view class="alert-item-icon">
-            <image v-if="item.level === 'high'" src="/static/icons/warning_icon.png" mode="aspectFit" style="width: 24px; height: 24px;"></image>
-            <image v-else-if="item.level === 'medium'" src="/static/icons/info_icon.png" mode="aspectFit" style="width: 24px; height: 24px;"></image>
+            <image v-if="item.level === 3" src="/static/icons/warning_icon.png" mode="aspectFit" style="width: 24px; height: 24px;"></image>
+            <image v-else-if="item.level === 2" src="/static/icons/info_icon.png" mode="aspectFit" style="width: 24px; height: 24px;"></image>
             <image v-else src="/static/icons/success_icon.png" mode="aspectFit" style="width: 24px; height: 24px;"></image>
           </view>
           
           <view class="alert-item-info">
             <text class="alert-item-type">{{ item.type }}</text>
             <text class="alert-item-level">
-              {{ item.level === 'high' ? '紧急' : item.level === 'medium' ? '警告' : '提示' }}
+              {{ item.level === 3 ? '紧急' : item.level === 2 ? '警告' : '提示' }}
             </text>
           </view>
           
-          <view class="alert-item-time">{{ item.time }}</view>
+          <view class="alert-item-time">{{ formatSmartTime(item.time) }}</view>
         </view>
       </view>
       
@@ -325,49 +325,47 @@
 </template>
 
 <script>
+import { getDeviceCollectorDetail } from "@/api/services/device.js";
+
 export default {
   data() {
     return {
       deviceInfo: {
-        deviceId: 'COL1002',
-        name: '采集设备-1',
-        status: 'online',
-        location: '西区B2地块',
-        lastUpdate: '5分钟前',
-        deviceType: 'weather' // 'weather' 或 'soil'
+        deviceId: '',
+        name: '设备加载中...',
+        status: '',
+        location: '正在获取位置...',
+        lastUpdate: '',
+        deviceType: 'weather' ,// 默认类型,会根据API返回更新
+		deviceTypeId:null
       },
       
       // 气象站数据
       weatherData: {
-        temperature: '26.5',
-        humidity: '68',
-        rainfall: '0.0',
-        windDirection: '东北',
-        windSpeed: '3.2',
-        pressure: '1013.5',
-        illumination: '45000',
-        updateTime: '2分钟前更新'
+        temperature: '',
+        humidity: '',
+        rainfall: '',
+        windDirection: '',
+        windSpeed: '',
+        pressure: '',
+        illumination: '',
+        updateTime: ''
       },
       
       // 土壤墒情数据
       soilData: {
-        temperature: '22.3',
-        moisture: '35.8',
-        nitrogen: '138.5',
-        phosphorus: '42.7',
-        potassium: '185.2',
-        conductivity: '0.35',
-        ph: '6.8',
-        updateTime: '5分钟前更新'
+        temperature: '',
+        moisture: '',
+        nitrogen: '',
+        phosphorus: '',
+        potassium: '',
+        conductivity: '',
+        ph: '',
+        updateTime: ''
       },
       
-      // 模拟告警数据
-      alertHistory: [
-        { id: 1, time: '今天 13:05', type: '数据异常', status: '未处理', level: 'high' },
-        { id: 2, time: '今天 09:30', type: '设备离线', status: '未处理', level: 'medium' },
-        { id: 3, time: '昨天 15:45', type: '通信错误', status: '已处理', level: 'low' },
-        { id: 4, time: '昨天 10:20', type: '电量不足', status: '未处理', level: 'low' }
-      ],
+      // 告警数据
+      alertHistory: [],
       
       // 刷新状态
       isRefreshing: false,
@@ -376,14 +374,14 @@ export default {
       updatedFields: {
         weather: {},
         soil: {}
-      }
+      },
     }
   },
   
   computed: {
     // 获取所有未处理的告警
     getUnhandledAlerts() {
-      return this.alertHistory.filter(alert => alert.status === '未处理');
+      return this.alertHistory.filter(alert => alert.status === 0);//未处理
     }
   },
   
@@ -395,301 +393,200 @@ export default {
   },
   
   onLoad(options) {
-    // 如果有传入设备ID,则获取设备信息
-    if (options && options.id) {
-      let deviceId = options.id;
-      let deviceCode = options.code || '';
-      
-      // 如果有传入设备编码,优先使用编码判断设备类型
-      if (deviceCode) {
-        this.fetchDeviceInfoWithCode(deviceId, deviceCode);
-      } else {
-        this.fetchDeviceInfo(deviceId);
-      }
-    }
+	  uni.$once('passDeviceData', (data) => {
+	      console.log('接收到数据', data);
+		  // 如果有传入设备ID,则获取设备信息
+		  if (data && data.deviceId) {
+		    this.deviceInfo.deviceId = data.deviceId;
+		    this.deviceInfo.location = data.fieldName;
+		    this.deviceInfo.name = data.deviceName;
+		    this.deviceInfo.status = data.status;
+		    this.deviceInfo.deviceTypeId = data.deviceTypeId || '';
+		    
+		    // 加载设备详情
+		    this.fetchDeviceCollectorDetail();
+		  }
+	    });
+    
   },
   
   methods: {
-    // 获取设备信息(带编码)
-    fetchDeviceInfoWithCode(deviceId, deviceCode) {
-      // 这里应该是API请求,暂时用模拟数据
-      console.log('获取设备信息:', deviceId, deviceCode);
+    // 获取设备采集器详情
+    fetchDeviceCollectorDetail() {
+      if (!this.deviceInfo.deviceId) return;
       
-      // 模拟异步获取数据
-      setTimeout(() => {
-        // 根据设备编码判断是气象站还是土壤墒情
-        if (deviceCode.startsWith('W')) {
-          this.deviceInfo.deviceType = 'weather';
-          
-          // 保存旧数据用于比较
-          const oldData = JSON.parse(JSON.stringify(this.weatherData));
-          
-          // 模拟更新气象数据
-          this.weatherData = {
-            temperature: (Math.random() * 10 + 20).toFixed(1),
-            humidity: (Math.random() * 30 + 50).toFixed(0),
-            rainfall: Math.random() < 0.3 ? (Math.random() * 5).toFixed(1) : '0.0',
-            windDirection: ['东北', '东南', '西北', '西南', '东', '南', '西', '北'][Math.floor(Math.random() * 8)],
-            windSpeed: (Math.random() * 5 + 1).toFixed(1),
-            pressure: (Math.random() * 20 + 1000).toFixed(1),
-            illumination: Math.floor(Math.random() * 50000 + 10000).toString(),
-            updateTime: '刚刚更新'
-          };
-          
-          // 检查哪些字段发生了变化
-          this.updatedFields.weather = {};
-          Object.keys(this.weatherData).forEach(key => {
-            if (key !== 'updateTime' && this.weatherData[key] !== oldData[key]) {
-              this.updatedFields.weather[key] = true;
+      uni.showLoading({
+        title: '加载数据中...'
+      });
+      
+      getDeviceCollectorDetail(this.deviceInfo.deviceId)
+        .then(res => {
+          console.log('设备详情数据:', res);
+          if (res.data.data && res.data.code === 200) {
+            const detail = res.data.data;
+            this.deviceInfo.lastUpdate = detail.collectTime
+            // 保存旧数据用于比较
+            let oldData = null;
+            
+            // 根据设备类型更新数据
+            if (this.deviceInfo.deviceTypeId === '4') { //气象设备
+				if(this.weatherData){
+					oldData = JSON.parse(JSON.stringify(this.weatherData));
+				}
+              // 更新气象数据
+              this.weatherData = {
+                temperature: detail.temperature || '',
+                humidity: detail.humidity || '',
+                rainfall: detail.rainfall || '',
+                windDirection: detail.windDirection || '',
+                windSpeed: detail.windSpeed || '',
+                pressure: detail.pressure || '',
+                illumination: detail.illumination || '',
+                updateTime: detail.collectTime|| '暂无数据'
+              };
               
-              // 1秒后清除动画标记
-              setTimeout(() => {
-                this.$set(this.updatedFields.weather, key, false);
-              }, 1000);
-            }
-          });
-          
-        } else if (deviceCode.startsWith('S')) {
-          this.deviceInfo.deviceType = 'soil';
-          
-          // 保存旧数据用于比较
-          const oldData = JSON.parse(JSON.stringify(this.soilData));
-          
-          // 模拟更新土壤数据
-          this.soilData = {
-            temperature: (Math.random() * 10 + 18).toFixed(1),
-            moisture: (Math.random() * 30 + 20).toFixed(1),
-            nitrogen: (Math.random() * 100 + 100).toFixed(1),
-            phosphorus: (Math.random() * 50 + 20).toFixed(1),
-            potassium: (Math.random() * 100 + 150).toFixed(1),
-            conductivity: (Math.random() * 0.5 + 0.2).toFixed(2),
-            ph: (Math.random() * 2 + 5.5).toFixed(1),
-            updateTime: '刚刚更新'
-          };
-          
-          // 检查哪些字段发生了变化
-          this.updatedFields.soil = {};
-          Object.keys(this.soilData).forEach(key => {
-            if (key !== 'updateTime' && this.soilData[key] !== oldData[key]) {
-              this.updatedFields.soil[key] = true;
+              // 检查哪些字段发生了变化
+              this.updatedFields.weather = {};
+              Object.keys(this.weatherData).forEach(key => {
+                if (key !== 'updateTime' && this.weatherData[key] !== oldData[key]) {
+                  this.updatedFields.weather[key] = true;
+                  
+                  // 1秒后清除动画标记
+                  setTimeout(() => {
+                    this.$set(this.updatedFields.weather, key, false);
+                  }, 1000);
+                }
+              });
               
-              // 1秒后清除动画标记
-              setTimeout(() => {
-                this.$set(this.updatedFields.soil, key, false);
-              }, 1000);
-            }
-          });
-          
-        } else {
-          // 如果编码无法判断类型,使用原有判断逻辑
-          this.fetchDeviceInfo(deviceId);
-          return;
-        }
-        
-        // 更新设备基本信息
-        this.deviceInfo.deviceId = deviceCode;
-        this.deviceInfo.name = `采集设备-${deviceCode.slice(-4)}`;
-        this.deviceInfo.lastUpdate = '刚刚';
-        
-        // 实际应该是API请求结果
-      }, 500);
-    },
-    
-    // 获取设备信息
-    fetchDeviceInfo(deviceId) {
-      // 这里应该是API请求,暂时用模拟数据
-      console.log('获取设备信息:', deviceId)
-      
-      // 模拟异步获取数据
-      setTimeout(() => {
-        // 根据设备ID判断是气象站还是土壤墒情
-        if (deviceId.startsWith('W') || deviceId.includes('weather')) {
-          this.deviceInfo.deviceType = 'weather';
-          
-          // 保存旧数据用于比较
-          const oldData = JSON.parse(JSON.stringify(this.weatherData));
-          
-          // 模拟更新气象数据
-          this.weatherData = {
-            temperature: (Math.random() * 10 + 20).toFixed(1),
-            humidity: (Math.random() * 30 + 50).toFixed(0),
-            rainfall: Math.random() < 0.3 ? (Math.random() * 5).toFixed(1) : '0.0',
-            windDirection: ['东北', '东南', '西北', '西南', '东', '南', '西', '北'][Math.floor(Math.random() * 8)],
-            windSpeed: (Math.random() * 5 + 1).toFixed(1),
-            pressure: (Math.random() * 20 + 1000).toFixed(1),
-            illumination: Math.floor(Math.random() * 50000 + 10000).toString(),
-            updateTime: Math.floor(Math.random() * 10 + 1) + '分钟前更新'
-          };
-          
-          // 检查哪些字段发生了变化
-          this.updatedFields.weather = {};
-          Object.keys(this.weatherData).forEach(key => {
-            if (key !== 'updateTime' && this.weatherData[key] !== oldData[key]) {
-              this.updatedFields.weather[key] = true;
+            } else if (this.deviceInfo.deviceTypeId === '1') { // 土壤设备
+			if(this.soilData){
+				oldData = JSON.parse(JSON.stringify(this.soilData));
+			}
               
-              // 1秒后清除动画标记
-              setTimeout(() => {
-                this.$set(this.updatedFields.weather, key, false);
-              }, 1000);
-            }
-          });
-          
-        } else if (deviceId.startsWith('S') || deviceId.includes('soil')) {
-          this.deviceInfo.deviceType = 'soil';
-          
-          // 保存旧数据用于比较
-          const oldData = JSON.parse(JSON.stringify(this.soilData));
-          
-          // 模拟更新土壤数据
-          this.soilData = {
-            temperature: (Math.random() * 10 + 18).toFixed(1),
-            moisture: (Math.random() * 30 + 20).toFixed(1),
-            nitrogen: (Math.random() * 100 + 100).toFixed(1),
-            phosphorus: (Math.random() * 50 + 20).toFixed(1),
-            potassium: (Math.random() * 100 + 150).toFixed(1),
-            conductivity: (Math.random() * 0.5 + 0.2).toFixed(2),
-            ph: (Math.random() * 2 + 5.5).toFixed(1),
-            updateTime: Math.floor(Math.random() * 10 + 1) + '分钟前更新'
-          };
-          
-          // 检查哪些字段发生了变化
-          this.updatedFields.soil = {};
-          Object.keys(this.soilData).forEach(key => {
-            if (key !== 'updateTime' && this.soilData[key] !== oldData[key]) {
-              this.updatedFields.soil[key] = true;
+              // 更新土壤数据
+              this.soilData = {
+                temperature: detail.temperature || '',
+                moisture: detail.soilTemperature || '',
+                nitrogen: detail.soilN || '',
+                phosphorus: detail.soilP || '',
+                potassium: detail.soilK || '',
+                conductivity: detail.conductivity || '',
+                ph: detail.ph || '',
+                updateTime: detail.collectTime || '暂无数据'
+              };
               
-              // 1秒后清除动画标记
-              setTimeout(() => {
-                this.$set(this.updatedFields.soil, key, false);
-              }, 1000);
+              // 检查哪些字段发生了变化
+              this.updatedFields.soil = {};
+              Object.keys(this.soilData).forEach(key => {
+                if (key !== 'updateTime' && this.soilData[key] !== oldData[key]) {
+                  this.updatedFields.soil[key] = true;
+                  
+                  // 1秒后清除动画标记
+                  setTimeout(() => {
+                    this.$set(this.updatedFields.soil, key, false);
+                  }, 1000);
+                }
+              });
             }
-          });
-          
-        } else {
-          // 如果ID无法判断类型,根据偶数/奇数ID模拟不同类型
-          const idNum = parseInt(deviceId.replace(/\D/g, ''));
-          this.deviceInfo.deviceType = idNum % 2 === 0 ? 'weather' : 'soil';
-          
-          if (this.deviceInfo.deviceType === 'weather') {
-            // 模拟更新气象数据
-            this.weatherData = {
-              temperature: (Math.random() * 10 + 20).toFixed(1),
-              humidity: (Math.random() * 30 + 50).toFixed(0),
-              rainfall: Math.random() < 0.3 ? (Math.random() * 5).toFixed(1) : '0.0',
-              windDirection: ['东北', '东南', '西北', '西南', '东', '南', '西', '北'][Math.floor(Math.random() * 8)],
-              windSpeed: (Math.random() * 5 + 1).toFixed(1),
-              pressure: (Math.random() * 20 + 1000).toFixed(1),
-              illumination: Math.floor(Math.random() * 50000 + 10000).toString(),
-              updateTime: Math.floor(Math.random() * 10 + 1) + '分钟前更新'
-            };
+            
+            // 更新告警信息
+            if (detail.alertRecordList && detail.alertRecordList.length > 0) {
+              this.alertHistory = detail.alertRecordList.map(alert => ({
+                id: alert.alertId,
+                time: alert.alertTime,
+                type: alert.alertContent,
+                status: alert.processStatus,
+                level: alert.alertLevel
+              }));
+            }
+            
+            // 更新页面标题
+            uni.setNavigationBarTitle({
+              title: this.deviceInfo.name
+            });
           } else {
-            // 模拟更新土壤数据
-            this.soilData = {
-              temperature: (Math.random() * 10 + 18).toFixed(1),
-              moisture: (Math.random() * 30 + 20).toFixed(1),
-              nitrogen: (Math.random() * 100 + 100).toFixed(1),
-              phosphorus: (Math.random() * 50 + 20).toFixed(1),
-              potassium: (Math.random() * 100 + 150).toFixed(1),
-              conductivity: (Math.random() * 0.5 + 0.2).toFixed(2),
-              ph: (Math.random() * 2 + 5.5).toFixed(1),
-              updateTime: Math.floor(Math.random() * 10 + 1) + '分钟前更新'
-            };
+            uni.showToast({
+              title: '暂无设备信息',
+              icon: 'none'
+            });
           }
-        }
-        
-        // 更新设备基本信息
-        this.deviceInfo.deviceId = deviceId;
-        this.deviceInfo.name = `采集设备-${deviceId.slice(-4)}`;
-        this.deviceInfo.lastUpdate = (Math.floor(Math.random() * 5) + 1) + '分钟前';
-        
-        // 实际应该是API请求结果
-      }, 500)
+        })
+        .catch(error => {
+          console.error('获取设备详情失败', error);
+          uni.showToast({
+            title: '获取设备数据失败',
+            icon: 'none'
+          });
+        })
+        .finally(() => {
+          uni.hideLoading();
+          this.isRefreshing = false;
+        });
     },
+	// 格式还日期格式;返回 今天:18:00
+    formatSmartTime(timeStr) {
+      if (!timeStr) return '未知';
+    
+      // iOS兼容:将 "2025-06-19 09:15:00" 转换为 "2025-06-19T09:15:00"
+      const safeStr = timeStr.replace(' ', 'T');
+    
+      const inputDate = new Date(safeStr);
+      if (isNaN(inputDate.getTime())) return '时间格式错误';
+    
+      const now = new Date();
     
+      // 取日期差值(单位:天)
+      const inputDayStart = new Date(inputDate.getFullYear(), inputDate.getMonth(), inputDate.getDate());
+      const nowDayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+    
+      const diffTime = nowDayStart - inputDayStart;
+      const oneDay = 1000 * 60 * 60 * 24;
+    
+      const timePart = inputDate.toTimeString().slice(0, 5); // HH:mm
+    
+      if (diffTime === 0) {
+        return `今天 ${timePart}`;
+      } else if (diffTime === oneDay) {
+        return `昨天 ${timePart}`;
+      } else if (diffTime === oneDay * 2) {
+        return `前天 ${timePart}`;
+      } else {
+        return `${inputDate.getMonth() + 1}月${inputDate.getDate()}日 ${timePart}`;
+      }
+    },
+
     // 刷新数据
     refreshData() {
       if (this.isRefreshing) return;
       
       this.isRefreshing = true;
-      
-      uni.showLoading({
-        title: '数据刷新中...'
-      });
-      
-      setTimeout(() => {
-        if (this.deviceInfo.deviceType === 'weather') {
-          // 保存旧数据用于比较
-          const oldData = JSON.parse(JSON.stringify(this.weatherData));
-          
-          // 模拟更新气象数据
-          this.weatherData = {
-            temperature: (Math.random() * 10 + 20).toFixed(1),
-            humidity: (Math.random() * 30 + 50).toFixed(0),
-            rainfall: Math.random() < 0.3 ? (Math.random() * 5).toFixed(1) : '0.0',
-            windDirection: ['东北', '东南', '西北', '西南', '东', '南', '西', '北'][Math.floor(Math.random() * 8)],
-            windSpeed: (Math.random() * 5 + 1).toFixed(1),
-            pressure: (Math.random() * 20 + 1000).toFixed(1),
-            illumination: Math.floor(Math.random() * 50000 + 10000).toString(),
-            updateTime: '刚刚更新'
-          };
-          
-          // 检查哪些字段发生了变化
-          this.updatedFields.weather = {};
-          Object.keys(this.weatherData).forEach(key => {
-            if (key !== 'updateTime' && this.weatherData[key] !== oldData[key]) {
-              this.updatedFields.weather[key] = true;
-              
-              // 1秒后清除动画标记
-              setTimeout(() => {
-                this.$set(this.updatedFields.weather, key, false);
-              }, 1000);
-            }
-          });
-          
-        } else {
-          // 保存旧数据用于比较
-          const oldData = JSON.parse(JSON.stringify(this.soilData));
-          
-          // 模拟更新土壤数据
-          this.soilData = {
-            temperature: (Math.random() * 10 + 18).toFixed(1),
-            moisture: (Math.random() * 30 + 20).toFixed(1),
-            nitrogen: (Math.random() * 100 + 100).toFixed(1),
-            phosphorus: (Math.random() * 50 + 20).toFixed(1),
-            potassium: (Math.random() * 100 + 150).toFixed(1),
-            conductivity: (Math.random() * 0.5 + 0.2).toFixed(2),
-            ph: (Math.random() * 2 + 5.5).toFixed(1),
-            updateTime: '刚刚更新'
-          };
-          
-          // 检查哪些字段发生了变化
-          this.updatedFields.soil = {};
-          Object.keys(this.soilData).forEach(key => {
-            if (key !== 'updateTime' && this.soilData[key] !== oldData[key]) {
-              this.updatedFields.soil[key] = true;
-              
-              // 1秒后清除动画标记
-              setTimeout(() => {
-                this.$set(this.updatedFields.soil, key, false);
-              }, 1000);
-            }
-          });
-        }
-        
-        this.deviceInfo.lastUpdate = '刚刚';
-        
-        uni.hideLoading();
-        uni.showToast({
-          title: '数据已更新',
-          icon: 'success'
-        });
-        
-        // 停止刷新动画
-        setTimeout(() => {
-          this.isRefreshing = false;
-        }, 500);
-      }, 1500);
-    }
+      this.fetchDeviceCollectorDetail();
+    },
+	// 格式化日期
+	formatDate(dateStr) {
+	  if (!dateStr) return '未知';
+	  
+	  // 解析为 Date
+	  const parsedStr = dateStr.replace(' ', 'T'); 
+	  const date = new Date(parsedStr);
+	  if (isNaN(date)) return '无效时间';
+	  
+	  const now = new Date();
+	
+	  // 计算差时长(分钟)
+	  const diff = Math.floor((now - date) / 1000 / 60);
+	  
+	  if (diff < 1) return '刚刚更新';
+	  if (diff < 5) return '1分钟前更新';
+	  if (diff < 10) return '5分钟前更新';
+	  if (diff < 60) return `${diff}分钟前更新`;
+	  
+	  if (diff < 120) return '1小时前更新';
+	  if (diff < 24 * 60) return `${Math.floor(diff / 60)}小时前更新`;
+	  if (diff < 7 * 24 * 60) return `${Math.floor(diff / (60 * 24))}天前更新`;
+	  
+	  return parsedStr.split('T')[0] + ' 更新';
+	},
   }
 }
 </script>

+ 378 - 224
pages/device-list/index.vue → pages/device/device-list/index.vue

@@ -4,19 +4,21 @@
     <view class="search-section">
       <view class="search-box" :class="{ 'search-focus': isSearchFocused }">
         <view class="search-icon">
-          <text class="iconfont icon-search"></text>
+          <!-- <text class="iconfont icon-search"></text> -->
+		  <image src="@/static/icons/search.png" style="width: 40rpx; height: 40rpx; padding-right: 10rpx;"
+		  	mode="widthFix" />
         </view>
         <input 
           class="search-input" 
           type="text" 
-          v-model="searchKeyword" 
+          v-model="searchKey" 
           placeholder="搜索设备名称 / 编号"
           confirm-type="search"
-          @confirm="handleSearch"
+          @confirm="onSearch"
           @focus="isSearchFocused = true"
           @blur="isSearchFocused = false"
         />
-        <view class="clear-icon" v-if="searchKeyword" @click="handleClearSearch">
+        <view class="clear-icon" v-if="searchKey" @click="clearSearch">
           <text class="iconfont icon-close"></text>
         </view>
       </view>
@@ -26,34 +28,42 @@
     <view class="filter-section">
       <view 
         class="filter-item" 
-        :class="{ active: statusFilter === 'all' }" 
-        @click="setStatusFilter('all')"
+        :class="{ active: currentStatus === -1 }" 
+        @click="selectStatus(-1)"
       >
         全部
       </view>
       <view 
         class="filter-item" 
-        :class="{ active: statusFilter === 'online' }" 
-        @click="setStatusFilter('online')"
+        :class="{ active: currentStatus === 1 }" 
+        @click="selectStatus(1)"
       >
         <view class="filter-dot online-dot"></view>
-        在线 ({{ onlineCount }})
+        在线 ({{ onlineDevices }})
       </view>
       <view 
         class="filter-item" 
-        :class="{ active: statusFilter === 'offline' }" 
-        @click="setStatusFilter('offline')"
+        :class="{ active: currentStatus === 0 }" 
+        @click="selectStatus(0)"
       >
         <view class="filter-dot offline-dot"></view>
-        离线 ({{ offlineCount }})
+        离线 ({{ offlineDevices }})
       </view>
+<!--      <view 
+        class="filter-item" 
+        :class="{ active: currentStatus === 2 }" 
+        @click="selectStatus(2)"
+      >
+        <view class="filter-dot fault-dot"></view>
+        故障 ({{ getStatusCount(2) }})
+      </view> -->
     </view>
     
     <!-- 设备列表区域 -->
     <scroll-view 
       scroll-y 
       class="device-list" 
-      @scrolltolower="loadMore"
+      @scrolltolower="onReachBottom"
       :scroll-with-animation="true"
       :enable-back-to-top="true"
       :refresher-enabled="true"
@@ -63,91 +73,97 @@
       @refresherrestore="isRefreshing = false"
     >
       <!-- 无数据提示 -->
-      <view v-if="filteredDeviceList.length === 0 && !isLoading" class="empty-tips">
+      <view v-if="deviceList.length === 0 && !loading" class="empty-tips">
         <view class="empty-icon">
           <text class="iconfont icon-empty"></text>
         </view>
-        <text class="empty-text">{{ searchKeyword ? '未找到匹配的设备' : '暂无设备' }}</text>
-        <view v-if="searchKeyword" class="empty-action" @click="handleClearSearch">
+        <text class="empty-text">{{ searchKey ? '未找到匹配的设备' : '暂无设备' }}</text>
+        <view v-if="searchKey" class="empty-action" @click="clearSearch">
           <text>清除搜索条件</text>
         </view>
       </view>
       
       <!-- 首次加载中状态 -->
-      <view v-if="isLoading && deviceList.length === 0" class="loading-container">
+      <view v-if="loading && deviceList.length === 0" class="loading-container">
         <view class="loading-spinner"></view>
         <text class="loading-text">加载中...</text>
       </view>
       
       <!-- 设备列表 -->
       <view 
-        v-for="(item, index) in filteredDeviceList" 
+        v-for="(item, index) in deviceList" 
         :key="index"
         class="device-card"
         :class="{
-          'has-alert': item.alarmCount > 0,
-          'is-offline': item.status === 'offline'
+          'has-alert': item.hasAlert,
+          'is-offline': item.status === 0
         }"
         hover-class="device-card-hover"
         hover-stay-time="70"
-        @click="navigateToDetail(item)"
+        @click="navigateToDeviceDetail(item)"
       >
         <!-- 设备基本信息 -->
         <view class="device-info">
           <view class="device-icon-wrapper">
-            <!-- 告警标 -->
-            <view v-if="item.alarmCount > 0" class="alarm-badge">
-              {{ item.alarmCount }}
+            <!-- 告警标 -->
+            <view v-if="item.hasAlert" class="alarm-badge">
+              1
             </view>
             
-            <view class="device-icon-container" :class="{'offline-icon': item.status === 'offline'}">
-              <image :src="getDeviceIcon(item.type)" mode="aspectFit" class="device-icon"></image>
+            <view class="device-icon-container" :class="{'offline-icon': item.status === 0}">
+              <image :src="getDeviceTypeIcon(item.deviceTypeId)" mode="aspectFit" class="device-icon"></image>
             </view>
           </view>
           
           <view class="device-meta">
             <view class="device-name-row">
-              <text class="device-name" :class="{'offline-text': item.status === 'offline'}">{{ item.name }}</text>
+              <text class="device-name" :class="{'offline-text': item.status === 0}">{{ item.deviceName }}</text>
               <view 
                 class="status-tag" 
-                :class="item.status === 'online' ? 'status-online' : 'status-offline'"
+                :class="{
+                  'status-online': item.status === 1,
+                  'status-offline': item.status === 0,
+                  'status-fault': item.status === 2,
+                  'status-maintain': item.status === 3
+                }"
               >
-                <text class="status-dot" :class="{'offline-dot': item.status === 'offline'}"></text>
-                {{ item.status === 'online' ? '在线' : '离线' }}
+                <text class="status-dot" :class="{
+                  'offline-dot': item.status === 0,
+                  'fault-dot': item.status === 2,
+                  'maintain-dot': item.status === 3
+                }"></text>
+                {{ getStatusText(item.status) }}
               </view>
             </view>
             
             <view class="device-id">
               <text class="id-label">设备编号:</text>
-              <text class="id-value">{{ item.code }}</text>
+              <text class="id-value">{{ item.deviceId }}</text>
             </view>
             
             <view class="device-location">
               <text class="location-label">安装位置:</text>
-              <text class="location-value">{{ item.location }}</text>
+              <text class="location-value">{{ item.fieldName || '未指定位置' }}</text>
             </view>
           </view>
         </view>
         
         <!-- 底部信息栏 -->
         <view class="device-footer">
-          <text class="update-time">{{ item.updateTime }}</text>
-          <view class="device-actions">
-            <text class="iconfont icon-right"></text>
-          </view>
+          <text class="update-time">最后活跃: {{ formatDate(item.lastActiveTime) }}</text>
         </view>
       </view>
       
       <!-- 加载更多提示 -->
-      <view v-if="filteredDeviceList.length > 0" class="load-more">
+      <view v-if="deviceList.length > 0" class="load-more">
         <view class="load-more-content" v-if="loadMoreStatus === 'loading'">
           <view class="loading-icon"></view>
           <text>正在加载...</text>
         </view>
-        <view class="load-more-content" v-if="loadMoreStatus === 'nomore'">
+        <view class="load-more-content" v-if="loadMoreStatus === 'noMore'">
           <text>没有更多了</text>
         </view>
-        <view class="load-more-content" v-if="loadMoreStatus === 'loadmore'" @click="loadMore">
+        <view class="load-more-content" v-if="loadMoreStatus === 'more'" @click="onReachBottom">
           <text>点击加载更多</text>
         </view>
       </view>
@@ -156,225 +172,335 @@
 </template>
 
 <script>
+import { fetchDevicesByType } from "@/api/services/device.js";
+import storage from "@/utils/storage.js";
+
 export default {
   data() {
     return {
-      deviceType: '',
-      searchKeyword: '',
-      isSearchFocused: false,
-      statusFilter: 'all', // 'all', 'online', 'offline'
+      deviceType: '', // monitor, sensor, control, irrigation, tractor
+      deviceTypeName: '',
       deviceList: [],
-      page: 1,
-      limit: 10,
-      loadMoreStatus: 'loading', // 'loadmore', 'loading', 'nomore'
-      isLoading: true,
-      isRefreshing: false
-    }
+      searchKey: '',
+      isSearchFocused: false,
+      currentStatus: -1, // -1代表全部
+      pageNum: 1,
+      pageSize: 10,
+      total: 0,
+      loading: false,
+      isRefreshing: false,
+      loadMoreStatus: 'more', // 加载更多状态: more-加载更多 loading-加载中 noMore-没有更多了
+      deviceTypeMap: {
+        'monitor': { name: '监控设备', icon: '/static/icons/camera.png', class: 'type-monitor' },
+        'sensor': { name: '采集设备', icon: '/static/icons/sensor.png', class: 'type-sensor' },
+        'control': { name: '控制设备', icon: '/static/icons/control.png', class: 'type-control' },
+        'irrigation': { name: '灌溉设备', icon: '/static/icons/water.png', class: 'type-irrigation' },
+        'tractor': { name: '农机设备', icon: '/static/icons/tractor.png', class: 'type-tractor' }
+      },
+      currentFieldId: null,
+	  onlineDevices:0,
+	  offlineDevices:0
+    };
   },
   
   computed: {
-    // 过滤后的设备列表
-    filteredDeviceList() {
-      let result = this.deviceList;
-      
-      // 按状态筛选
-      if (this.statusFilter !== 'all') {
-        result = result.filter(device => device.status === this.statusFilter);
-      }
-      
-      // 按关键词搜索
-      if (this.searchKeyword) {
-        const keyword = this.searchKeyword.toLowerCase();
-        result = result.filter(device => 
-          device.name.toLowerCase().includes(keyword) || 
-          device.code.toLowerCase().includes(keyword)
-        );
-      }
-      
-      return result;
-    },
-    
-    // 在线设备数量
-    onlineCount() {
-      return this.deviceList.filter(device => device.status === 'online').length;
-    },
-    
-    // 离线设备数量
-    offlineCount() {
-      return this.deviceList.filter(device => device.status === 'offline').length;
+    // 设备类型对应的样式类
+    deviceTypeClass() {
+      return this.deviceTypeMap[this.deviceType]?.class || '';
     }
   },
   
   onLoad(options) {
-    // 获取路由参数
-    if (options.type) {
-      this.deviceType = options.type;
-      this.setPageTitle();
+    // 获取传递的设备类型
+    console.log("options类型:", options);
+    const { type, typeOnline, typeOffline } = options;
+	// 处理传递过来的统计数量
+	this.offlineDevices = typeOffline
+	this.onlineDevices = typeOnline
+    if (type && this.deviceTypeMap[type]) {
+      this.deviceType = type;
+      this.deviceTypeName = this.deviceTypeMap[type].name;
     }
     
-    // 加载设备数据
-    this.loadDeviceData();
+    // 获取当前地块ID
+    this.initFieldInfo();
+    
+    // 加载设备列表
+    this.loadDeviceList();
   },
   
   methods: {
-    // 设置页面标题
-    setPageTitle() {
-      const titleMap = {
-        'monitor': '监控设备列表',
-        'sensor': '采集设备列表',
-        'control': '控制设备列表',
-        'irrigation': '灌溉设备列表',
-        'tractor': '农机设备列表'
+    // 初始化地块信息
+    initFieldInfo() {
+      const currentPlots = JSON.parse(storage.getPlots() || '{}');
+      if (currentPlots) {
+        this.currentFieldId = currentPlots.id;
+      }
+    },
+    
+    // 获取特定状态的设备数量
+    getStatusCount(status) {
+      return this.deviceList.filter(device => device.status === status).length;
+    },
+    
+    // 加载设备列表
+    loadDeviceList(reset = true) {
+      if (this.loading) return;
+      
+      if (reset) {
+        this.pageNum = 1;
+        this.deviceList = [];
+      }
+      
+      this.loading = true;
+      this.loadMoreStatus = 'loading';
+      
+      // 构建查询参数
+      const params = {
+        pageNum: this.pageNum,
+        pageSize: this.pageSize,
+        deviceQueryParams: this.searchKey || undefined,
+        deviceType: this.deviceType || undefined,
+        fieldId: this.currentFieldId || undefined
       };
       
-      const title = titleMap[this.deviceType] || '设备列表';
-      uni.setNavigationBarTitle({
-        title: title
+      // 如果状态不是全部,添加状态筛选
+      if (this.currentStatus !== -1) {
+        params.status = this.currentStatus;
+      }
+      
+      // 调用API获取设备列表
+      fetchDevicesByType(params)
+        .then(res => {
+          console.log("res", res);
+          if (res.data.code === 200 && res.data.rows) {
+            const { rows, total } = res.data;
+            
+            // 更新设备列表
+            if (reset) {
+              this.deviceList = rows;
+            } else {
+              this.deviceList = [...this.deviceList, ...rows];
+            }
+            
+            this.total = total;
+            
+            // 标记有告警的设备
+            this.deviceList.forEach(device => {
+              // 这里可以根据实际情况设置hasAlert属性
+              device.hasAlert = false; // 示例,实际应该根据后台数据判断
+            });
+            
+            // 更新加载更多状态
+            if (this.deviceList.length >= total) {
+              this.loadMoreStatus = 'noMore';
+            } else {
+              this.loadMoreStatus = 'more';
+            }
+          } else {
+            this.handleApiError(res);
+          }
+        })
+        .catch(error => {
+          console.error('获取设备列表失败', error);
+          uni.showToast({
+            title: '获取设备列表失败',
+            icon: 'none'
+          });
+          this.loadMoreStatus = 'more';
+        })
+        .finally(() => {
+          this.loading = false;
+          this.isRefreshing = false;
+          uni.hideLoading();
+        });
+    },
+    
+    // 处理API错误
+    handleApiError(res) {
+      console.error('API错误', res);
+      uni.showToast({
+        title: res.msg || '获取数据失败',
+        icon: 'none'
       });
     },
     
-    // 获取设备图标
-    getDeviceIcon(type) {
-      const iconMap = {
-        'monitor': '/static/icons/camera.png',
-        'sensor': '/static/icons/sensor.png',
-        'control': '/static/icons/control.png',
-        'irrigation': '/static/icons/water.png',
-        'tractor': '/static/icons/tractor.png'
-      };
-      
-      return iconMap[type] || '/static/icons/device-default.png';
+    // 搜索
+    onSearch() {
+      this.loadDeviceList();
     },
     
-    // 设置状态筛选
-    setStatusFilter(status) {
-      this.statusFilter = status;
+    // 清除搜索
+    clearSearch() {
+      this.searchKey = '';
+      this.loadDeviceList();
     },
     
-    // 加载设备数据
-    loadDeviceData() {
-      this.isLoading = true;
-      
-      // 模拟API请求数据
-      setTimeout(() => {
-        // 这里应该是真实的API请求
-        // 模拟一些设备数据用于展示
-        const newDevices = this.generateMockDevices();
-        this.deviceList = [...this.deviceList, ...newDevices];
-        
-        if (this.deviceList.length >= 30) {
-          this.loadMoreStatus = 'nomore';
-        } else {
-          this.loadMoreStatus = 'loadmore';
-        }
-        
-        this.isLoading = false;
-        this.isRefreshing = false;
-      }, 1000);
+    // 选择状态
+    selectStatus(value) {
+      this.currentStatus = value;
+      this.loadDeviceList();
     },
     
-    // 生成模拟设备数据
-    generateMockDevices() {
-      const devices = [];
-      const locations = ['东区A1地块', '西区B2地块', '南区C3地块', '北区D4地块'];
-      const updateTimes = ['刚刚更新', '1分钟前更新', '5分钟前更新', '10分钟前更新', '1小时前更新'];
-      
-      // 根据当前页码和限制数量生成对应数量的模拟数据
-      const startIndex = (this.page - 1) * this.limit;
-      for (let i = 0; i < this.limit; i++) {
-        const index = startIndex + i;
-        
-        // 如果已经生成了30条数据,则停止
-        if (index >= 30) break;
-        
-        // 对于采集设备类型,生成随机的气象或土壤设备
-        let deviceType = this.deviceType;
-        let deviceCode = `DEV${String(index + 1001).padStart(4, '0')}`;
-        
-        // 如果是采集设备,随机生成气象站或土壤墒情设备
-        if (this.deviceType === 'sensor') {
-          // 随机分配采集设备子类型:气象站或土壤墒情
-          const sensorSubType = Math.random() > 0.5 ? 'weather' : 'soil';
-          deviceCode = sensorSubType === 'weather' ? `W${deviceCode}` : `S${deviceCode}`;
-        }
-        
-        devices.push({
-          id: `device-${index + 1}`,
-          name: `${this.getDeviceTypeName(this.deviceType)}-${index + 1}`,
-          code: deviceCode,
-          type: deviceType,
-          status: Math.random() > 0.3 ? 'online' : 'offline', // 70% 概率在线
-          location: locations[Math.floor(Math.random() * locations.length)],
-          updateTime: updateTimes[Math.floor(Math.random() * updateTimes.length)],
-          alarmCount: Math.random() > 0.7 ? Math.floor(Math.random() * 3) + 1 : 0 // 30% 概率有告警
-        });
+    // 处理下拉刷新
+    handleRefresh() {
+      this.isRefreshing = true;
+      this.loadDeviceList();
+    },
+    
+    // 跳转到设备详情页
+    navigateToDeviceDetail(device) {
+		console.log("device",device);
+      // 根据设备类型跳转到不同的详情页
+      let url = '';
+      // 先发送事件
+      uni.$emit('passDeviceData', {
+        deviceId: device.deviceId,
+        deviceTypeId: device.deviceTypeId,
+        fieldName: device.fieldName,
+        deviceName: device.deviceName
+      });
+      if (device.deviceTypeId === '2') {
+        url = `/pages/device/device-list/detail-camera?id=${device.id}`;
+      } else if (device.deviceTypeId === '1') {
+        // 采集设备跳转到采集设备详情页,同时传递设备编码,便于判断设备子类型
+        // url = `/pages/device/device-list/detail-collector?id=${device.deviceId}&deviceTypeId=${device.deviceTypeId}&fieldName=${device.fieldName}&deviceName=${device.deviceName}`;
+		url = `/pages/device/device-list/detail-collector`;
+     
+	  } else {
+        // 其他类型设备暂时使用通用详情页
+        url = `/pages/device/device-detail/index?id=${device.id}&type=${device.type}`;
       }
       
-      return devices;
+      // 先跳转
+        uni.navigateTo({
+          url: url,
+          success: () => {
+            // 跳转成功后再发送事件,延迟一点确保页面onLoad注册完成
+            setTimeout(() => {
+              uni.$emit('passDeviceData', {
+                deviceId: device.deviceId,
+                deviceTypeId: device.deviceTypeId,
+                fieldName: device.fieldName,
+                deviceName: device.deviceName,
+				status:device.status
+              });
+            }, 100); // 100ms 通常足够,必要时可加到 200
+          }
+        });
     },
     
-    // 获取设备类型名称
-    getDeviceTypeName(type) {
-      const nameMap = {
-        'monitor': '监控设备',
-        'sensor': '采集设备',
-        'control': '控制设备',
-        'irrigation': '灌溉设备',
-        'tractor': '农机设备'
+    // 获取设备类型图标
+    getDeviceTypeIcon(typeId) {
+      // 根据后端设备类型ID获取对应前端类型的图标
+      const typeMapping = {
+        '1': 'sensor', // 传感器
+        '2': 'monitor', // 摄像头
+        '3': 'control', // 控制器
+        '4': 'irrigation', // 气象设备/灌溉设备
+        '5': 'tractor'  // 农机设备
       };
       
-      return nameMap[type] || '未知设备';
+      const frontendType = typeMapping[typeId] || this.deviceType;
+      return this.deviceTypeMap[frontendType]?.icon || '/static/icons/device.png';
     },
     
-    // 处理搜索
-    handleSearch() {
-      // 执行搜索逻辑
-      console.log('搜索关键词:', this.searchKeyword);
+    // 获取设备类型名称
+    getDeviceTypeName(typeId) {
+      const typeNames = {
+        '1': '采集设备',
+        '2': '监控设备',
+        '3': '控制设备',
+        '4': '灌溉设备',
+        '5': '农机设备'
+      };
+      
+      return typeNames[typeId] || '未知类型';
     },
     
-    // 处理清空搜索
-    handleClearSearch() {
-      this.searchKeyword = '';
+    // 获取状态文本
+    getStatusText(status) {
+      const statusMap = {
+        0: '离线',
+        1: '在线',
+        2: '故障',
+        3: '维护中'
+      };
+      
+      return statusMap[status] || '未知状态';
     },
     
-    // 加载更多数据
-    loadMore() {
-      if (this.loadMoreStatus !== 'nomore') {
-        this.loadMoreStatus = 'loading';
-        this.page += 1;
-        this.loadDeviceData();
+    // 格式化日期
+	formatDate(dateStr) {
+	  if (!dateStr) return '未知';
+	  
+	  // 解析为 Date
+	  const parsedStr = dateStr.replace(' ', 'T'); 
+	  const date = new Date(parsedStr);
+	  if (isNaN(date)) return '无效时间';
+	  
+	  const now = new Date();
+	
+	  // 计算差时长(分钟)
+	  const diff = Math.floor((now - date) / 1000 / 60);
+	  
+	  if (diff < 1) return '刚刚更新';
+	  if (diff < 5) return '1分钟前更新';
+	  if (diff < 10) return '5分钟前更新';
+	  if (diff < 60) return `${diff}分钟前更新`;
+	  
+	  if (diff < 120) return '1小时前更新';
+	  if (diff < 24 * 60) return `${Math.floor(diff / 60)}小时前更新`;
+	  if (diff < 7 * 24 * 60) return `${Math.floor(diff / (60 * 24))}天前更新`;
+	  
+	  return parsedStr.split('T')[0] + ' 更新';
+	},
+/*    formatDate(dateStr) {
+      if (!dateStr) return '未知';
+      
+      const date = new Date(dateStr);
+      const now = new Date();
+      
+      // 今天的日期
+      if (date.toDateString() === now.toDateString()) {
+        return `今天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
       }
-    },
-    
-    // 跳转到设备详情页
-    navigateToDetail(device) {
-      // 根据设备类型跳转到不同的详情页
-      let url = '';
       
-      if (device.type === 'monitor') {
-        url = `/pages/device-list/detail-camera?id=${device.id}`;
-      } else if (device.type === 'sensor') {
-        // 采集设备跳转到采集设备详情页,同时传递设备编码,便于判断设备子类型
-        url = `/pages/device-list/detail-collector?id=${device.id}&code=${device.code}`;
-      } else {
-        // 其他类型设备暂时使用通用详情页
-        url = `/pages/device-detail/index?id=${device.id}&type=${device.type}`;
+      // 一周内
+      const days = ['日', '一', '二', '三', '四', '五', '六'];
+      const dayDiff = Math.floor((now - date) / (24 * 60 * 60 * 1000));
+      if (dayDiff < 7) {
+        return `周${days[date.getDay()]} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
       }
       
-      uni.navigateTo({
-        url: url
-      });
-    },
+      // 超过一周
+      return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
+    }, */
     
-    // 处理刷新
-    handleRefresh() {
-      this.isRefreshing = true;
-      this.page = 1;
-      this.deviceList = [];
-      this.loadDeviceData();
+    // 页面上拉触底事件
+    onReachBottom() {
+      if (this.loadMoreStatus === 'more') {
+        this.pageNum++;
+        this.loadDeviceList(false);
+      }
     }
+  },
+  
+  // 下拉刷新
+  onPullDownRefresh() {
+    this.loadDeviceList();
+    setTimeout(() => {
+      uni.stopPullDownRefresh();
+    }, 1000);
+  },
+  
+  // 页面显示
+  onShow() {
+    uni.setNavigationBarTitle({
+      title: this.deviceTypeName || '设备列表'
+    });
   }
-}
+};
 </script>
 
 <style scoped>
@@ -412,8 +538,6 @@ export default {
   font-size: 80rpx;
 }
 
-
-
 /* 容器样式 */
 .container {
   display: flex;
@@ -478,12 +602,13 @@ export default {
 /* 状态筛选区域 */
 .filter-section {
   display: flex;
-  padding: 24rpx 30rpx;
+  padding: 24rpx 24rpx;
   background-color: #FFFFFF;
   margin-bottom: 20rpx;
   box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
   position: relative;
   z-index: 4;
+  flex-wrap: wrap;
 }
 
 .filter-item {
@@ -496,6 +621,7 @@ export default {
   border-radius: 30rpx;
   transition: all 0.2s ease;
   position: relative;
+  margin-bottom: 10rpx;
 }
 
 .filter-item.active {
@@ -504,8 +630,6 @@ export default {
   font-weight: 500;
 }
 
-
-
 .filter-dot {
   width: 14rpx;
   height: 14rpx;
@@ -523,6 +647,16 @@ export default {
   box-shadow: 0 0 6rpx rgba(245, 108, 108, 0.5);
 }
 
+.fault-dot {
+  background-color: #FF9800;
+  box-shadow: 0 0 6rpx rgba(255, 152, 0, 0.5);
+}
+
+.maintain-dot {
+  background-color: #2196F3;
+  box-shadow: 0 0 6rpx rgba(33, 150, 243, 0.5);
+}
+
 /* 设备列表区域 */
 .device-list {
   flex: 1;
@@ -531,6 +665,7 @@ export default {
   width: 100%;
   position: relative;
   z-index: 3;
+  height: calc(100vh - 220rpx);
 }
 
 /* 空数据提示 */
@@ -756,6 +891,24 @@ export default {
   border-color: rgba(76, 175, 80, 0.3);
 }
 
+.status-offline {
+  background-color: rgba(245, 108, 108, 0.1);
+  color: #F56C6C;
+  border-color: rgba(245, 108, 108, 0.3);
+}
+
+.status-fault {
+  background-color: rgba(255, 152, 0, 0.1);
+  color: #FF9800;
+  border-color: rgba(255, 152, 0, 0.3);
+}
+
+.status-maintain {
+  background-color: rgba(33, 150, 243, 0.1);
+  color: #2196F3;
+  border-color: rgba(33, 150, 243, 0.3);
+}
+
 .status-dot {
   position: absolute;
   width: 8rpx;
@@ -775,11 +928,14 @@ export default {
   box-shadow: 0 0 4rpx rgba(245, 108, 108, 0.8);
 }
 
-.status-offline {
-  background-color: rgba(245, 108, 108, 0.1);
-  color: #F56C6C;
-  border-color: rgba(245, 108, 108, 0.3);
-  padding-left: 32rpx;
+.status-dot.fault-dot {
+  background-color: #FF9800;
+  box-shadow: 0 0 4rpx rgba(255, 152, 0, 0.8);
+}
+
+.status-dot.maintain-dot {
+  background-color: #2196F3;
+  box-shadow: 0 0 4rpx rgba(33, 150, 243, 0.8);
 }
 
 @keyframes blink {
@@ -864,6 +1020,4 @@ export default {
   0% { transform: rotate(0deg); }
   100% { transform: rotate(360deg); }
 }
-
-
 </style> 

+ 96 - 100
pages/device/index.vue

@@ -84,136 +84,132 @@
 </template>
 
 <script>
+// 导入API服务
+import { forEach } from "../../utils/lib/request/utils";
+import { fetchDeviceOverview } from "@/api/services/device.js";
+import storage from "@/utils/storage.js";
+
 export default {
   data() {
     return {
-      deviceList: [
-        { 
-          name: '监控设备', 
-          online: 8, 
-          offline: 2, 
-          type: 'monitor',
-          icon: '/static/icons/camera.png',
-          alerts: 1,
-          onlineRate: 80
-        },
-        { 
-          name: '采集设备', 
-          online: 14, 
-          offline: 1, 
-          type: 'sensor',
-          icon: '/static/icons/sensor.png',
-          alerts: 2,
-          onlineRate: 93
-        },
-        { 
-          name: '控制设备', 
-          online: 10, 
-          offline: 1, 
-          type: 'control',
-          icon: '/static/icons/control.png',
-          alerts: 0,
-          onlineRate: 91
-        },
-        { 
-          name: '灌溉设备', 
-          online: 6, 
-          offline: 0, 
-          type: 'irrigation',
-          icon: '/static/icons/water.png',
-          alerts: 0,
-          onlineRate: 100
-        },
-        { 
-          name: '农机设备', 
-          online: 3, 
-          offline: 1, 
-          type: 'tractor',
-          icon: '/static/icons/tractor.png',
-          alerts: 0,
-          onlineRate: 75
-        }
-      ],
-      currentPlot: '东区智慧农场'
+      deviceList: [],
+      currentPlot: "加载中...",
+      totalDevices: 0,
+      onlineDevices: 0,
+      offlineDevices: 0,
+      alertDevices: 0,
+      loading: false,
+      currentFieldId: null, // 当前选中的地块ID
+	  typeOnline: 0,
+	  typeOffline: 0
     }
   },
   
-  computed: {
-    totalDevices() {
-      return this.deviceList.reduce((sum, device) => sum + device.online + device.offline, 0)
-    },
-    
-    onlineDevices() {
-      return this.deviceList.reduce((sum, device) => sum + device.online, 0)
-    },
-    
-    offlineDevices() {
-      return this.deviceList.reduce((sum, device) => sum + device.offline, 0)
+  methods: {
+    // 初始化地块信息
+    initFieldInfo() {
+      const fieldInfo = storage.getPlots();
+	  console.log("ggg ");
+      if (fieldInfo) {
+		  const plotData = JSON.parse(fieldInfo);
+        this.currentFieldId = plotData.id;
+        this.currentPlot = plotData.name || "未选择地块";
+      } else {
+        this.currentPlot = "未选择地块";
+      }
     },
     
-    alertDevices() {
-      return this.deviceList.reduce((sum, device) => sum + device.alerts, 0)
-    }
-  },
-  
-  onLoad() {
-    // 页面加载时获取设备数据
-    this.fetchDeviceData()
-  },
-  
-  methods: {
     // 获取设备数据
     fetchDeviceData() {
-      // 实际开发中替换为API请求
-      // 模拟异步请求
-      setTimeout(() => {
-        // 这里只是示例,实际开发中应从API获取数据
-        console.log('设备数据加载完成')
-        this.calculateOnlineRates()
-      }, 500)
+      if (this.loading) return;
+      this.loading = true;
+      
+      uni.showLoading({
+        title: '加载中...'
+      });
+      
+      // 调用API获取设备概览数据
+      fetchDeviceOverview(this.currentFieldId)
+        .then(res => {
+          if (res.data.code === 200 && res.data.data) {
+            const data = res.data.data;
+            // 更新设备总览数据
+            this.totalDevices = data.totalDevices || 0;
+            this.onlineDevices = data.onlineDevices || 0;
+            this.offlineDevices = data.offlineDevices || 0;
+            this.alertDevices = data.alertDevices || 0;
+            
+            // 更新设备类型列表
+            if (data.deviceList && data.deviceList.length > 0) {
+              this.deviceList = data.deviceList;
+            }
+            
+            console.log('设备概览数据加载成功');
+          } else {
+            this.handleApiError(res);
+          }
+        })
+        .catch(error => {
+          console.error('获取设备概览数据失败', error);
+          uni.showToast({
+            title: '获取设备数据失败',
+            icon: 'none'
+          });
+        })
+        .finally(() => {
+          this.loading = false;
+          uni.hideLoading();
+        });
     },
     
-    // 计算在线率
-    calculateOnlineRates() {
-      this.deviceList.forEach(item => {
-        const total = item.online + item.offline
-        if (total > 0) {
-          item.onlineRate = Math.round((item.online / total) * 100)
-        } else {
-          item.onlineRate = 0
-        }
-      })
+    // 处理API错误
+    handleApiError(res) {
+      console.error('API错误', res);
+      uni.showToast({
+        title: res.data.msg || '获取数据失败',
+        icon: 'none'
+      });
     },
     
     // 跳转到对应设备列表页面
     navigateToDeviceList(type) {
+		// 传递指定设备类型的在线、离线数量
+		this.deviceList.forEach((item, index) => {
+			if(item.type === type){
+				this.typeOnline = item.online
+				this.typeOffline =  item.offline
+			}
+		});
       uni.navigateTo({
-        url: '/pages/device-list/index?type=' + type
-      })
+        url: `/pages/device/device-list/index?type=${type}&typeOnline=${this.typeOnline}&typeOffline=${this.typeOffline}`
+      });
     },
     
     // 切换地块
     changePlot() {
-      // 暂时仅展示UI,后续实现地块切换逻辑
-      uni.showToast({
-        title: '地块切换功能开发中',
-        icon: 'none'
-      })
+      uni.navigateTo({
+        url: '/pages/field-selector/index?callback=deviceCenter'
+      });
     }
   },
-
+  
   // 页面导航配置
   onShow() {
-    uni.setNavigationBarTitle({
-      title: '设备中心'
-    })
+	this.initFieldInfo();
+	this.fetchDeviceData();
+  },
+  
+  // 下拉刷新
+  onPullDownRefresh() {
+    this.fetchDeviceData();
+    setTimeout(() => {
+      uni.stopPullDownRefresh();
+    }, 1000);
   }
 }
 </script>
 
 <style scoped>
-
-
 .container {
   padding: 30rpx;
   background-color: #F9FCFA;