From 10680b0eebb883c982e8e5ab728fabd00c9d9ba7 Mon Sep 17 00:00:00 2001
From: chenyc <501753378@qq.com>
Date: 星期四, 20 八月 2026 17:41:37 +0800
Subject: [PATCH] 更新

---
 数据模型.md               |   20 ++++++++++
 src/protocol.js       |   15 +++++++
 src/tcpServer.js      |    6 +++
 src/aliyunClient.js   |   16 +++++++
 src/propertyMapper.js |    8 +++
 docs/实施部署文档.md        |    4 +-
 6 files changed, 64 insertions(+), 5 deletions(-)

diff --git "a/docs/\345\256\236\346\226\275\351\203\250\347\275\262\346\226\207\346\241\243.md" "b/docs/\345\256\236\346\226\275\351\203\250\347\275\262\346\226\207\346\241\243.md"
index c374440..338fd91 100644
--- "a/docs/\345\256\236\346\226\275\351\203\250\347\275\262\346\226\207\346\241\243.md"
+++ "b/docs/\345\256\236\346\226\275\351\203\250\347\275\262\346\226\207\346\241\243.md"
@@ -99,12 +99,12 @@
 ```json
 {
   "tcp": {
-    "host": "3.0.0.27",
+    "host": "0.0.0.0",
     "port": 10000,
     "idleTimeoutMs": 1200000
   },
   "http": {
-    "enabled": false,
+    "enabled": true,
     "host": "0.0.0.0",
     "port": 19001,
     "rateLimit": {
diff --git a/src/aliyunClient.js b/src/aliyunClient.js
index af6f19c..cb6910e 100644
--- a/src/aliyunClient.js
+++ b/src/aliyunClient.js
@@ -15,14 +15,19 @@
 
   // 设备号 -> { iotDevice, productKey, deviceName }
   const deviceMap = new Map();
+  const creatingMap = new Map();
 
   async function ensureIotDevice(deviceNumber) {
     let entry = deviceMap.get(deviceNumber);
     if (entry && entry.iotDevice) {
       return entry;
     }
+    const creating = creatingMap.get(deviceNumber);
+    if (creating) {
+      return creating;
+    }
 
-    try {
+    const creatingPromise = (async () => {
       logger.info("Request Aliyun device secret", { deviceNumber });
       // 复用旧项目的 api.js 约定:第一个参数是相对路径
       const resp = await getAliyunDeviceSecret(
@@ -80,12 +85,20 @@
       entry = { iotDevice, productKey, deviceName };
       deviceMap.set(deviceNumber, entry);
       return entry;
+    })();
+
+    creatingMap.set(deviceNumber, creatingPromise);
+
+    try {
+      return await creatingPromise;
     } catch (err) {
       logger.error("ensureIotDevice error", {
         deviceNumber,
         error: err.message || err
       });
       return null;
+    } finally {
+      creatingMap.delete(deviceNumber);
     }
   }
 
@@ -147,6 +160,7 @@
       }
       deviceMap.delete(deviceNumber);
     }
+    creatingMap.clear();
   }
 
   return {
diff --git a/src/propertyMapper.js b/src/propertyMapper.js
index 98d5692..c2395a8 100644
--- a/src/propertyMapper.js
+++ b/src/propertyMapper.js
@@ -65,7 +65,13 @@
     const result = {};
     if (!rawData || typeof rawData !== "object") return result;
     for (const [key, value] of Object.entries(rawData)) {
-      result[key] = value;
+      if (value == null) {
+        result[key] = "";
+      } else if (typeof value === "object") {
+        result[key] = JSON.stringify(value);
+      } else {
+        result[key] = String(value);
+      }
     }
     return result;
   }
diff --git a/src/protocol.js b/src/protocol.js
index 5b260b2..2440e2c 100644
--- a/src/protocol.js
+++ b/src/protocol.js
@@ -150,7 +150,20 @@
 
   buildTimeString(parts) {
     const [year, month, day, hour, minute, second] = parts;
-    if (!year) return null;
+    if (
+      !year ||
+      year < 2000 ||
+      year > 2099 ||
+      month < 1 ||
+      month > 12 ||
+      day < 1 ||
+      day > 31 ||
+      hour > 23 ||
+      minute > 59 ||
+      second > 59
+    ) {
+      return null;
+    }
     const y = year.toString().padStart(4, "0");
     const m = String(month || 0).padStart(2, "0");
     const d = String(day || 0).padStart(2, "0");
diff --git a/src/tcpServer.js b/src/tcpServer.js
index b38b734..be23a2b 100644
--- a/src/tcpServer.js
+++ b/src/tcpServer.js
@@ -25,6 +25,9 @@
       data.J ?? ""
     }`
   );
+  if (data.J != null) {
+    lines.push(`跨膜压J(mmHg): ${data.J}`);
+  }
   if (data.N != null || data.O != null || data.P != null || data.BPMPJDMY != null) {
     lines.push(
       `血压N/O/P/平均压(mmHg,bpm): ${data.N ?? ""} / ${data.O ?? ""} / ${
@@ -38,6 +41,9 @@
         data.bjlx ?? ""
       } / ${data.bjsj || ""}`
     );
+    if (data.bjsj) {
+      lines.push(`报警时间bjsj: ${data.bjsj}`);
+    }
   }
     if (data.pyzl != null || data.ypyzhyl != null) {
       lines.push(
diff --git "a/\346\225\260\346\215\256\346\250\241\345\236\213.md" "b/\346\225\260\346\215\256\346\250\241\345\236\213.md"
new file mode 100644
index 0000000..c0d711d
--- /dev/null
+++ "b/\346\225\260\346\215\256\346\250\241\345\236\213.md"
@@ -0,0 +1,20 @@
+55 55 55 55 31 E1 73 CB 72 01 00 26 6E 00 00 00 00 00 00 00 1B 01 00 EA 07 03 0D 14 07 08 00 00 38 00 00 00 00 00 00 00 5B 00 00 00 40 D1 0B 09 18 00 00 00 9F CF F1 AC 00 34 02 AD 10 27 00 00 14 00 00 00 03 00 00 00 03 00 00 00 00 00 00 00 38 00 00 00 9F CF F1 AC 5B 00 00 00 00 D7 0B 09 18 00 00 00 9F CF F1 AC 00 00 00 00 10 27 00 00 14 00 00 00 03 00 00 00 03 00 00 00 00 00 00 00 38 00 00 00 00 00 00 00 5B 00 00 00 18 D7 0B 09 18 00 00 00 30 34
+
+报警记录
+
+
+
+
+血压记录 143:98:80
+55 55 55 55 31 E1 73 CB 72 01 00 29 6E 02 E0 AB 17 AD 00 30 00 01 EA 07 03 0D 14 12 2A 8F 00 62 00 50 00 71 00 AC 28 00 00 00 48 00 00 00 18 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 34 02 AD 00 00 00 00 30 34 02 AD 30 34 02 AD 2C 34 02 AD CD 6B FE AC 01 00 00 00 69 F9 F1 AC F8 1F 70 AD 0C 00 00 00 50 32 70 AD 00 00 00 00 BE BE 24 AD 38 70 08 09 40 00 00 00 9B BF F1 AC 00 30 02 AD 00 34 02 AD 48 C7 00 00 00 34 02 AD D8 D0 F1 AC
+
+血压记录 129:93:86
+55 55 55 55 31 E1 73 CB 72 01 00 29 6E 02 E0 AB 17 AD 00 30 00 01 EA 07 03 0D 14 07 20 81 00 5D 00 56 00 69 00 AC 28 00 00 00 48 00 00 00 18 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 34 02 AD 00 00 00 00 30 34 02 AD 30 34 02 AD 2C 34 02 AD CD 6B FE AC 01 00 00 00 69 F9 F1 AC F8 1F 70 AD 0C 00 00 00 50 32 70 AD 00 00 00 00 BE BE 24 AD 38 70 08 09 40 00 00 00 9B BF F1 AC 00 30 02 AD 00 34 02 AD 48 C7 00 00 00 34 02 AD D8 D0 F1 AC
+血压记录 136,96,29
+55 55 55 55 31 E1 73 CB 72 01 00 29 6E 02 E0 9B 93 A7 00 20 00 01 EA 07 03 0D 15 37 2B 88 00 5C 00 45 00 6B 00 A7 28 00 00 00 48 00 00 00 18 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 24 7E A7 00 00 00 00 30 24 7E A7 30 24 7E A7 2C 24 7E A7 CD 5B 7A A7 01 00 00 00 69 E9 6D A7 F8 0F EC A7 0C 00 00 00 50 22 EC A7 00 00 00 00 BE AE A0 A7 38 70 16 0A 40 00 00 00 9B AF 6D A7 00 20 7E A7 00 24 7E A7 48 C7 00 00 00 24 7E A7 D8 C0 6D A7
+
+
+
+治疗数据
+
+55 55 55 55 31 E1 73 CB 72 01 03 1F 6E 0F 0A 10 02 00 00 30 E0 2E 00 00 7B 03 00 00 E6 00 01 00 00 00 00 1E 00 08 07 00 00 85 00 00 00 1B 02 00 00 01 00 F4 01 72 01 7A 05 98 3A 00 00 52 04 00 00 00 F1 10 F1 10 92 B8 09 00 82 FF 61 00 AD 00 E5 FF 00 00 00 00 00 00 00 30 B7 08 00 00 00 04 00 00 00 F8 44 B2 B6 08 70 0C 0A 22 1D 3F 08 F8 6F 30 B7 00 80 C2 B6 00 84 C2 B6 48 C7 00 00 48 C7 00 00 93 4F B2 B6 C0 E8 0F 0A 00 00 00 00 0C 02 00 00 C0 E8 0F 0A 00 75 48 08 88 CC DF B6 F8 6F 30 B7 00 80 C2 B6 00 00 00 00 30 77 0C 0A 00 00 00 00 F8 EF AD B6 01 00 00 00 08 02 00 00 01 00 00 00 55 82 30 B7 60 E8 0F 0A 00 B0 82 08 09 00 00 00 00 80 C2 B6 09 00 00 00 08

--
Gitblit v1.8.0