From feb86efc4e8a8d2da00e4832bcd81825726617bf Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 04 六月 2026 13:48:25 +0800
Subject: [PATCH] feat(iot): 物联设备接口新增存放位置字段

---
 src/main/java/com/ruoyi/http/service/controller/JclyController.java    |   19 ++-
 src/main/java/com/ruoyi/stock/controller/StockInventoryController.java |    1 
 doc/20260604_物联设备接口新增存放位置字段前端联调文档.md                                   |  233 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 246 insertions(+), 7 deletions(-)

diff --git "a/doc/20260604_\347\211\251\350\201\224\350\256\276\345\244\207\346\216\245\345\217\243\346\226\260\345\242\236\345\255\230\346\224\276\344\275\215\347\275\256\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260604_\347\211\251\350\201\224\350\256\276\345\244\207\346\216\245\345\217\243\346\226\260\345\242\236\345\255\230\346\224\276\344\275\215\347\275\256\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..45b4c88
--- /dev/null
+++ "b/doc/20260604_\347\211\251\350\201\224\350\256\276\345\244\207\346\216\245\345\217\243\346\226\260\345\242\236\345\255\230\346\224\276\344\275\215\347\275\256\345\255\227\346\256\265\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,233 @@
+# 鐗╄仈璁惧鎺ュ彛鏂板瀛樻斁浣嶇疆瀛楁鍓嶇鑱旇皟鏂囨。
+
+## 鍙樻洿姒傝堪
+
+鏈鍙樻洿鍦ㄤ袱涓墿鑱旇澶囩浉鍏虫帴鍙g殑杩斿洖鏁版嵁涓柊澧炰簡 `storageLocation`锛堝瓨鏀句綅缃級瀛楁锛屼緵鍓嶇灞曠ず璁惧鎵�鍦ㄧ殑鐗╃悊浣嶇疆淇℃伅銆�
+
+---
+
+## 涓�銆佹暟閲囨帴鍙� - getRealData
+
+### 鎺ュ彛淇℃伅
+
+| 椤圭洰 | 鍊� |
+|------|-----|
+| 鎺ュ彛璺緞 | `/iot/getRealData` |
+| 璇锋眰鏂瑰紡 | GET |
+| 鎺ュ彛鎻忚堪 | 瀹炴椂鑾峰彇鐗╄仈璁惧鐨勬俯婀垮害銆佷簩姘у寲纰崇瓑鏁伴噰鏁版嵁 |
+
+### 璇锋眰鍙傛暟
+
+鏃犲弬鏁�
+
+### 杩斿洖鏁版嵁缁撴瀯
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": [
+    {
+      "guid": "璁惧澶栭儴缂栫爜",
+      "deviceName": "璁惧鍚嶇О",
+      "storageLocation": "瀛樻斁浣嶇疆銆愭柊澧炪��",
+      "status": "鍦ㄧ嚎/绂荤嚎/error",
+      "statusMessage": "鐘舵�佽鏄庯紙浠呭湪寮傚父鏃惰繑鍥烇級",
+      "light": "鍏夌収鍊�+鍗曚綅锛堝锛�150Lux锛�",
+      "temperature": "娓╁害鍊�+鍗曚綅锛堝锛�25.5鈩冿級",
+      "humidity": "婀垮害鍊�+鍗曚綅锛堝锛�60%RH锛�",
+      "co2": "浜屾哀鍖栫⒊鍊�+鍗曚綅锛堝锛�400ppm锛�",
+      "battery": "鐢垫睜鐢甸噺+鍗曚綅锛堝锛�85%锛�"
+    }
+  ]
+}
+```
+
+### 杩斿洖瀛楁璇存槑
+
+| 瀛楁鍚� | 绫诲瀷 | 璇存槑 | 鏄惁鏂板 |
+|--------|------|------|----------|
+| guid | String | 璁惧澶栭儴缂栫爜锛坋xternalCode锛� | 鍚� |
+| deviceName | String | 璁惧鍚嶇О | 鍚� |
+| **storageLocation** | String | **璁惧瀛樻斁浣嶇疆** | **鏄�** |
+| status | String | 璁惧鐘舵�侊細鍦ㄧ嚎銆佺绾裤�乪rror | 鍚� |
+| statusMessage | String | 鐘舵�佽ˉ鍏呰鏄庯紙浠呭湪寮傚父鏃跺瓨鍦級 | 鍚� |
+| light | String | 鍏夌収鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| temperature | String | 娓╁害鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| humidity | String | 婀垮害鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| co2 | String | 浜屾哀鍖栫⒊鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| battery | String | 鐢垫睜鐢甸噺锛堝甫鍗曚綅锛� | 鍚� |
+
+### 鍓嶇鑱旇皟绀轰緥
+
+```javascript
+// 璋冪敤鎺ュ彛
+axios.get('/iot/getRealData').then(res => {
+  const devices = res.data;
+  devices.forEach(device => {
+    console.log(`璁惧锛�${device.deviceName}`);
+    console.log(`瀛樻斁浣嶇疆锛�${device.storageLocation}`); // 鏂板瀛楁
+    console.log(`娓╁害锛�${device.temperature}`);
+    console.log(`婀垮害锛�${device.humidity}`);
+    console.log(`CO2锛�${device.co2}`);
+    console.log(`鐘舵�侊細${device.status}`);
+  });
+});
+```
+
+---
+
+## 浜屻�佸簱瀛樼墿鑱旇澶囨帴鍙� - iotRealtime
+
+### 鎺ュ彛淇℃伅
+
+| 椤圭洰 | 鍊� |
+|------|-----|
+| 鎺ュ彛璺緞 | `/stockInventory/iotRealtime` |
+| 璇锋眰鏂瑰紡 | POST |
+| Content-Type | application/json |
+| 鎺ュ彛鎻忚堪 | 鑾峰彇搴撳瓨缁戝畾鐨勭墿鑱旇澶囧疄鏃舵暟閲囨暟鎹� |
+
+### 璇锋眰鍙傛暟
+
+```json
+[璁惧ID1, 璁惧ID2, 璁惧ID3]
+```
+
+**鍙傛暟璇存槑锛�**
+
+| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|
+| - | List<Long> | 鏄� | 鐗╄仈璁惧ID鏁扮粍 |
+
+### 杩斿洖鏁版嵁缁撴瀯
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": {
+    "devices": [
+      {
+        "deviceId": "璁惧ID",
+        "deviceName": "璁惧鍚嶇О",
+        "deviceModel": "璁惧瑙勬牸鍨嬪彿",
+        "externalCode": "璁惧澶栭儴缂栫爜",
+        "storageLocation": "瀛樻斁浣嶇疆銆愭柊澧炪��",
+        "guid": "璁惧澶栭儴缂栫爜",
+        "status": "鍦ㄧ嚎/绂荤嚎/error",
+        "statusMessage": "鐘舵�佽鏄庯紙浠呭湪寮傚父鏃惰繑鍥烇級",
+        "light": "鍏夌収鍊�+鍗曚綅",
+        "temperature": "娓╁害鍊�+鍗曚綅",
+        "humidity": "婀垮害鍊�+鍗曚綅",
+        "co2": "浜屾哀鍖栫⒊鍊�+鍗曚綅",
+        "battery": "鐢垫睜鐢甸噺+鍗曚綅"
+      }
+    ]
+  }
+}
+```
+
+### 杩斿洖瀛楁璇存槑锛坉evices 鏁扮粍鍏冪礌锛�
+
+| 瀛楁鍚� | 绫诲瀷 | 璇存槑 | 鏄惁鏂板 |
+|--------|------|------|----------|
+| deviceId | String | 璁惧ID | 鍚� |
+| deviceName | String | 璁惧鍚嶇О | 鍚� |
+| deviceModel | String | 璁惧瑙勬牸鍨嬪彿 | 鍚� |
+| externalCode | String | 璁惧澶栭儴缂栫爜 | 鍚� |
+| **storageLocation** | String | **璁惧瀛樻斁浣嶇疆** | **鏄�** |
+| guid | String | 璁惧澶栭儴缂栫爜锛堟潵鑷暟閲囧钩鍙帮級 | 鍚� |
+| status | String | 璁惧鐘舵�侊細鍦ㄧ嚎銆佺绾裤�乪rror | 鍚� |
+| statusMessage | String | 鐘舵�佽ˉ鍏呰鏄庯紙浠呭湪寮傚父鏃跺瓨鍦級 | 鍚� |
+| light | String | 鍏夌収鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| temperature | String | 娓╁害鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| humidity | String | 婀垮害鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| co2 | String | 浜屾哀鍖栫⒊鍊硷紙甯﹀崟浣嶏級 | 鍚� |
+| battery | String | 鐢垫睜鐢甸噺锛堝甫鍗曚綅锛� | 鍚� |
+
+### 鍓嶇鑱旇皟绀轰緥
+
+```javascript
+// 璋冪敤鎺ュ彛
+const deviceIds = [1, 2, 3];
+axios.post('/stockInventory/iotRealtime', deviceIds).then(res => {
+  const result = res.data;
+  result.devices.forEach(device => {
+    console.log(`璁惧ID锛�${device.deviceId}`);
+    console.log(`璁惧鍚嶇О锛�${device.deviceName}`);
+    console.log(`瀛樻斁浣嶇疆锛�${device.storageLocation}`); // 鏂板瀛楁
+    console.log(`瑙勬牸鍨嬪彿锛�${device.deviceModel}`);
+    console.log(`娓╁害锛�${device.temperature}`);
+    console.log(`婀垮害锛�${device.humidity}`);
+    console.log(`鐘舵�侊細${device.status}`);
+  });
+});
+```
+
+---
+
+## 涓夈�佸墠绔敼閫犺鐐�
+
+### 1. 鍒楄〃/鍗$墖灞曠ず鏀归��
+
+鑻ュ墠绔湁璁惧鍒楄〃鎴栧崱鐗囧睍绀猴紝闇�鏂板瀛樻斁浣嶇疆灞曠ず鍖哄煙锛�
+
+```html
+<!-- 绀轰緥锛氳澶囦俊鎭崱鐗� -->
+<div class="device-card">
+  <div class="device-name">{{ device.deviceName }}</div>
+  <!-- 鏂板瀛樻斁浣嶇疆灞曠ず -->
+  <div class="storage-location">瀛樻斁浣嶇疆锛歿{ device.storageLocation || '鏆傛棤' }}</div>
+  <div class="device-status">鐘舵�侊細{{ device.status }}</div>
+  <div class="device-data">
+    <span>娓╁害锛歿{ device.temperature }}</span>
+    <span>婀垮害锛歿{ device.humidity }}</span>
+    <span>CO2锛歿{ device.co2 }}</span>
+  </div>
+</div>
+```
+
+### 2. 琛ㄦ牸鍒楁柊澧�
+
+鑻ュ墠绔娇鐢ㄨ〃鏍煎睍绀鸿澶囨暟鎹紝闇�鏂板瀛樻斁浣嶇疆鍒楋細
+
+| 鍒楀悕 | 瀛楁 | 璇存槑 |
+|------|------|------|
+| 璁惧鍚嶇О | deviceName | - |
+| **瀛樻斁浣嶇疆** | **storageLocation** | **鏂板鍒�** |
+| 娓╁害 | temperature | - |
+| 婀垮害 | humidity | - |
+| CO2 | co2 | - |
+| 鐘舵�� | status | - |
+
+### 3. 绌哄�煎鐞�
+
+`storageLocation` 瀛楁鍙兘涓虹┖瀛楃涓诧紝鍓嶇闇�鍋氬厹搴曞鐞嗭細
+
+```javascript
+const location = device.storageLocation || '鏆傛棤瀛樻斁浣嶇疆淇℃伅';
+```
+
+---
+
+## 鍥涖�佹暟鎹潵婧愯鏄�
+
+`storageLocation` 瀛楁鏉ユ簮浜庤澶囧彴璐﹁〃锛坄device_ledger`锛夌殑 `storage_location` 瀛楁锛岃瀛楁鍦ㄨ澶囧彴璐︾鐞嗘ā鍧楃淮鎶ゃ��
+
+---
+
+## 浜斻�佹祴璇曡鐐�
+
+1. **姝e父鍦烘櫙**锛氳澶囧彴璐︿腑宸茬淮鎶ゅ瓨鏀句綅缃紝鎺ュ彛杩斿洖搴斿寘鍚瀛楁鍊�
+2. **绌哄�煎満鏅�**锛氳澶囧彴璐︿腑瀛樻斁浣嶇疆涓虹┖锛屾帴鍙e簲杩斿洖绌哄瓧绗︿覆锛堝墠绔渶鍏滃簳灞曠ず锛�
+3. **绂荤嚎璁惧**锛氳澶囩绾挎椂锛宍storageLocation` 瀛楁浠嶅簲姝e父杩斿洖
+4. **鎵归噺鏌ヨ**锛氬涓澶嘔D鏌ヨ鏃讹紝姣忎釜璁惧閮藉簲杩斿洖 `storageLocation` 瀛楁
+
+---
+
+## 鍏�佺増鏈褰�
+
+| 鐗堟湰 | 鏃ユ湡 | 鍙樻洿鍐呭 |
+|------|------|----------|
+| v1.0 | 2026-06-04 | 鏂板 storageLocation锛堝瓨鏀句綅缃級瀛楁 |
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/http/service/controller/JclyController.java b/src/main/java/com/ruoyi/http/service/controller/JclyController.java
index 00bbb74..409fda4 100644
--- a/src/main/java/com/ruoyi/http/service/controller/JclyController.java
+++ b/src/main/java/com/ruoyi/http/service/controller/JclyController.java
@@ -41,24 +41,29 @@
                 .isNotNull(DeviceLedger::getExternalCode)
                 .ne(DeviceLedger::getExternalCode, ""));
 
-        Map<String, String> guidDeviceNameMap = iotDevices.stream()
+        Map<String, DeviceLedger> guidDeviceMap = iotDevices.stream()
                 .filter(item -> StringUtils.isNotEmpty(item.getExternalCode()))
                 .collect(Collectors.toMap(
                         item -> item.getExternalCode().trim(),
-                        item -> StringUtils.isNotEmpty(item.getDeviceName()) ? item.getDeviceName().trim() : "",
-                        (oldValue, newValue) -> StringUtils.isNotEmpty(oldValue) ? oldValue : newValue,
+                        item -> item,
+                        (oldValue, newValue) -> StringUtils.isNotEmpty(oldValue.getDeviceName()) ? oldValue : newValue,
                         LinkedHashMap::new
                 ));
-        List<String> guidList = new ArrayList<>(guidDeviceNameMap.keySet());
+        List<String> guidList = new ArrayList<>(guidDeviceMap.keySet());
 
         List<Map<String, String>> maps = realTimeEnergyConsumptionService
                 .getRealData(guidList);
         for (Map<String, String> item : maps) {
             String guid = item.get("guid");
             if (StringUtils.isNotEmpty(guid)) {
-                String deviceName = guidDeviceNameMap.get(guid.trim());
-                if (StringUtils.isNotEmpty(deviceName)) {
-                    item.put("deviceName", deviceName);
+                DeviceLedger device = guidDeviceMap.get(guid.trim());
+                if (device != null) {
+                    if (StringUtils.isNotEmpty(device.getDeviceName())) {
+                        item.put("deviceName", device.getDeviceName().trim());
+                    }
+                    if (StringUtils.isNotEmpty(device.getStorageLocation())) {
+                        item.put("storageLocation", device.getStorageLocation().trim());
+                    }
                 }
             }
         }
diff --git a/src/main/java/com/ruoyi/stock/controller/StockInventoryController.java b/src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
index a04f869..bf57927 100644
--- a/src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
+++ b/src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -192,6 +192,7 @@
             data.put("deviceName", device.getDeviceName() != null ? device.getDeviceName() : "");
             data.put("deviceModel", device.getDeviceModel() != null ? device.getDeviceModel() : "");
             data.put("externalCode", device.getExternalCode() != null ? device.getExternalCode() : "");
+            data.put("storageLocation", device.getStorageLocation() != null ? device.getStorageLocation() : "");
             Map<String, String> rt = realTimeDataMap.getOrDefault(
                     device.getExternalCode() != null ? device.getExternalCode().trim() : "",
                     Collections.emptyMap());

--
Gitblit v1.9.3