From 472fb5267c1b3fa8ab798ccd15bb1aac70128d41 Mon Sep 17 00:00:00 2001
From: chenyc <501753378@qq.com>
Date: 星期三, 13 五月 2026 16:00:39 +0800
Subject: [PATCH] 更新

---
 DEPLOY.md |  496 +++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 341 insertions(+), 155 deletions(-)

diff --git a/DEPLOY.md b/DEPLOY.md
index 6583d44..d0ab685 100644
--- a/DEPLOY.md
+++ b/DEPLOY.md
@@ -15,7 +15,127 @@
 │ 透析机 N  │                └─────────────────┘            └──────────────┘
 ```
 
-## 2. 环境要求
+## 2. 部署方式选择
+
+| 方式 | 适用场景 | 是否需要 Node.js |
+|------|----------|-----------------|
+| **可执行程序部署**(推荐) | 实施部署、生产环境 | **不需要** |
+| **源码部署** | 开发调试、需修改源码 | 需要 Node.js ≥ 18.x |
+
+> 两种方式效果一致。可执行程序已将 Node.js 运行时与依赖打包,省去环境安装步骤。
+
+---
+
+## 3. 可执行程序部署(推荐)
+
+### 3.1 环境要求
+
+| 项目 | 要求 |
+|------|------|
+| **操作系统** | Windows Server 2016+ / Windows 10+ 或 Linux(Ubuntu 20.04+ / CentOS 7+) |
+| **内存** | ≥ 256 MB(本服务占用 ~80 MB) |
+| **磁盘** | ≥ 1 GB(含日志滚动保留 30 天) |
+| **网络** | 需与 GC-110N 设备在同一局域网,或能通过路由访问设备 TCP 端口 |
+
+### 3.2 获取发布包
+
+发布包位于项目 `dist/` 目录(或由开发人员交付):
+
+```
+dist/
+├── jms-connection-service-windows.zip    # Windows 部署包(约 18 MB)
+├── jms-connection-service-linux/         # Linux 部署目录(可自行 tar 打包)
+└── jms-connection-service-windows/       # Windows 部署目录
+```
+
+**Windows 实施人员**:解压 `jms-connection-service-windows.zip` 到目标目录(如 `C:\JMS\`)。
+
+**Linux 实施人员**:将 `jms-connection-service-linux/` 目录整体拷贝到目标路径(如 `/opt/jms-connection-service/`)。
+
+### 3.3 目录结构(解压后)
+
+```
+jms-connection-service-windows/          # Linux 对应目录类似
+├── jms-connection-service-windows.exe   # 主程序(Linux 无 .exe 后缀)
+├── config.json                          # 配置文件 ★
+├── logs/                                # 日志目录(自动创建)
+└── README.txt                           # 简要说明
+```
+
+### 3.4 配置
+
+编辑 `config.json`,必改项:
+
+- `devices` — 填写实际设备的 IP、端口、序列号
+- `mqtt.enabled` / `aliyun.enabled` — 按需开启上传通道
+
+详细配置项说明见 [第 5 节](#5-配置说明)。
+
+### 3.5 验证连通性
+
+在启动服务前,确认服务器能连通 GC-110N 设备:
+
+```bash
+# Windows PowerShell:
+Test-NetConnection -ComputerName 192.168.160.1 -Port 10001
+
+# Linux:
+nc -zv 192.168.160.1 10001
+```
+
+### 3.6 启动服务
+
+**Windows(前台运行):**
+
+```cmd
+C:\JMS\jms-connection-service-windows.exe
+```
+
+**Windows(注册为系统服务,开机自启,以管理员身份运行):**
+
+```cmd
+sc create JMSConnection binPath= "C:\JMS\jms-connection-service-windows.exe" start= auto
+sc start JMSConnection
+
+:: 停止: sc stop JMSConnection
+:: 删除: sc delete JMSConnection
+```
+
+**Linux(前台运行):**
+
+```bash
+chmod +x jms-connection-service-linux
+./jms-connection-service-linux
+```
+
+**Linux(后台运行,使用 PM2):**
+
+```bash
+npm install -g pm2                                          # PM2 本身需要 Node.js
+pm2 start ./jms-connection-service-linux --name jms-connection-service
+pm2 save
+pm2 startup                                                 # 设置开机自启
+```
+
+**Linux(使用 systemd,见 [6.1 节](#61-systemd-服务-linux))**
+
+### 3.7 访问监控面板
+
+浏览器打开 `http://<服务器IP>:3100`。
+
+### 3.8 停止服务
+
+- **前台运行**:`Ctrl + C`
+- **Windows 服务**:`sc stop JMSConnection`
+- **PM2**:`pm2 stop jms-connection-service`
+
+---
+
+## 4. 源码部署(需 Node.js)
+
+适用于开发调试或需修改源码的场景。
+
+### 4.1 环境要求
 
 | 项目 | 要求 |
 |------|------|
@@ -26,44 +146,41 @@
 | **磁盘** | ≥ 1 GB(日志滚动保留 30 天) |
 | **网络** | 需与 GC-110N 设备在同一局域网,或能通过路由访问设备 TCP 端口 |
 
-### 2.1 检查 Node.js 版本
-
-```bash
-node -v   # 应输出 v18.x 或 v20.x
-npm -v    # 应输出 9.x 或 10.x
-```
-
-### 2.2 安装 Node.js(如未安装)
+### 4.2 安装 Node.js(如未安装)
 
 **Ubuntu/Debian:**
+
 ```bash
 curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
 sudo apt-get install -y nodejs
 ```
 
 **CentOS/RHEL:**
+
 ```bash
 curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
 sudo yum install -y nodejs
 ```
 
-**Windows:**
-从 https://nodejs.org 下载 LTS 安装包,勾选「Add to PATH」。
+**Windows:** 从 https://nodejs.org 下载 LTS 安装包,勾选「Add to PATH」。
 
-## 3. 部署步骤
-
-### 3.1 获取代码
+验证安装:
 
 ```bash
-# 将部署包解压或从 Git 拉取
-cd /opt
-tar -xzf jms-connection-service.tar.gz -C /opt/
-# 或: git clone <repo-url> /opt/jms-connection-service
+node -v   # 应输出 v18.x 或 v20.x
+npm -v    # 应输出 9.x 或 10.x
+```
 
+### 4.3 获取代码
+
+```bash
+cd /opt
+git clone <repo-url> /opt/jms-connection-service
+# 或解压源码包: tar -xzf jms-connection-service.tar.gz -C /opt/
 cd /opt/jms-connection-service
 ```
 
-### 3.2 安装依赖
+### 4.4 安装依赖
 
 ```bash
 npm install --production
@@ -71,29 +188,15 @@
 
 > 仅安装生产依赖(`dependencies`),不安装 devDependencies。
 
-### 3.3 配置
-
-复制并修改配置文件:
+### 4.5 配置
 
 ```bash
-# 如无可直接编辑 config.json(已内置在部署包中)
 vi config.json
 ```
 
-详细配置项说明见 [第 4 节](#4-配置说明)。
+详细配置项说明见 [第 5 节](#5-配置说明)。
 
-### 3.4 验证连通性
-
-在启动服务前,确认服务器能连通 GC-110N 设备:
-
-```bash
-# 测试 TCP 端口(替换为实际 IP 和端口)
-nc -zv 192.168.160.1 10001
-# 或 Windows:
-# Test-NetConnection -ComputerName 192.168.160.1 -Port 10001
-```
-
-### 3.5 启动服务
+### 4.6 启动服务
 
 ```bash
 # 前台运行(调试用)
@@ -103,10 +206,10 @@
 npm install -g pm2
 pm2 start index.js --name jms-connection-service
 pm2 save
-pm2 startup   # 设置开机自启
+pm2 startup
 ```
 
-启动成功后控制台输出:
+启动成功输出:
 
 ```
 配置校验通过: 1/1 台设备启用
@@ -114,70 +217,70 @@
 日志目录: /opt/jms-connection-service/logs  保留: 30 天
 轮询间隔: 10s  重连退避: 3s~60s
 Dashboard 已启动: http://0.0.0.0:3100
-
 联机服务已启动 → Dashboard: http://localhost:3100
 ```
 
-### 3.6 访问监控面板
+### 4.7 访问监控面板
 
-浏览器打开 `http://<服务器IP>:3100`,可看到设备连接状态、实时数据和上传状态。
+浏览器打开 `http://<服务器IP>:3100`。
 
-## 4. 配置说明
+---
 
-配置文件为根目录下的 `config.json`,格式如下:
+## 5. 配置说明
+
+配置文件为 `config.json`(位于程序同目录),格式:
 
 ```jsonc
 {
   // ── 全局参数 ──
-  "pollIntervalMs": 10000,       // K 轮询间隔(毫秒),默认 10000 = 10s
+  "pollIntervalMs": 10000,       // K 轮询间隔(毫秒),默认 10s
   "connectTimeoutMs": 5000,      // TCP 握手超时(毫秒)
   "reconnectBaseMs": 3000,       // 重连退避基数(毫秒)
-  "reconnectMaxMs": 60000,       // 重连退避上限(毫秒),实际延迟 = min(base*2^(n-1), max)
-  "logDir": "./logs",            // 日志目录(相对路径基于项目根目录)
+  "reconnectMaxMs": 60000,       // 重连退避上限(毫秒)
+  "logDir": "./logs",            // 日志目录(相对路径基于程序工作目录)
   "logRetentionDays": 30,        // 日志保留天数
   "dashboardPort": 3100,         // 监控大屏 HTTP 端口
 
   // ── MQTT 上传(可选) ──
   "mqtt": {
-    "enabled": false,            // 是否启用 MQTT 上传
-    "brokerUrl": "mqtt.ihemodialysis.com",  // MQTT Broker 地址(不含协议前缀)
-    "port": 62283,               // MQTT 端口
-    "username": "data",          // 认证用户名
-    "password": "data#2018",     // 认证密码
-    "reconnectPeriod": 5000,     // MQTT 重连间隔(毫秒)
-    "clientCode": "CLIENT9227100800901fcKB",  // 客户端标识
-    "defaultTopicPrefix": "touxiji",          // 默认 Topic 前缀,发布 topic = {prefix}/{deviceNo}
-    "qos": 1                     // MQTT QoS 级别
+    "enabled": false,
+    "brokerUrl": "mqtt.ihemodialysis.com",
+    "port": 62283,
+    "username": "data",
+    "password": "data#2018",
+    "reconnectPeriod": 5000,
+    "clientCode": "CLIENT9227100800901fcKB",
+    "defaultTopicPrefix": "touxiji",
+    "qos": 1
   },
 
   // ── 阿里云 IoT 上传(可选) ──
   "aliyun": {
-    "enabled": true,             // 是否启用阿里云上传
-    "autoRegister": true,        // 是否自动注册设备(三元组不存在时自动创建)
-    "tupleApiBaseUrl": "https://things.icoldchain.cn/",  // 三元组 API 地址
-    "tupleApiPath": "device/info/getAliyunDeviceSecret", // 三元组 API 路径
-    "tupleRetryCooldownMs": 60000  // 三元组请求失败后冷却时间(毫秒)
+    "enabled": true,
+    "autoRegister": true,
+    "tupleApiBaseUrl": "https://things.icoldchain.cn/",
+    "tupleApiPath": "device/info/getAliyunDeviceSecret",
+    "tupleRetryCooldownMs": 60000
   },
 
   // ── 设备列表 ──
   "devices": [
     {
-      "ip": "192.168.160.1",     // 设备 IP 地址(必填)
-      "port": 10001,             // 设备 TCP 端口(必填,GC-110N 默认 10001)
-      "serialNumber": "xy123",   // 设备序列号(必填,用于上传标识)
-      "enabled": true            // 是否启用(false 则跳过此设备)
+      "ip": "192.168.160.1",     // 设备 IP(必填)
+      "port": 10001,             // 设备端口(必填,GC-110N 默认 10001)
+      "serialNumber": "xy123",   // 序列号(必填)
+      "enabled": true            // 是否启用
     }
-    // 可添加多台设备...
   ]
 }
 ```
 
-### 4.1 重连退避说明
+### 5.1 重连退避
 
-服务使用指数退避策略处理断线重连:
+断线后使用指数退避,连接成功后计数器重置:
 
-| 断开次数 | 延迟时间(base=3000, max=60000) |
-|----------|--------------------------------|
+| 断开次数 | 延迟(base=3000, max=60000) |
+|----------|---------------------------|
 | 第 1 次 | 3s |
 | 第 2 次 | 6s |
 | 第 3 次 | 12s |
@@ -185,9 +288,7 @@
 | 第 5 次 | 48s |
 | 第 6 次+ | 60s(达到上限) |
 
-连接成功后计数器重置。
-
-### 4.2 设备配置示例
+### 5.2 多设备配置示例
 
 ```json
 "devices": [
@@ -197,111 +298,160 @@
 ]
 ```
 
-## 5. 运行管理
+---
 
-### 5.1 PM2 常用命令
+## 6. 运行管理
+
+### 6.1 systemd 服务(Linux)
+
+创建 systemd 服务文件实现开机自启和进程守护:
+
+```bash
+sudo vi /etc/systemd/system/jms-connection.service
+```
+
+```ini
+[Unit]
+Description=JMS GC-110N Dialysis Connection Service
+After=network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/opt/jms-connection-service
+ExecStart=/opt/jms-connection-service/jms-connection-service-linux
+Restart=always
+RestartSec=10
+StandardOutput=journal
+StandardError=journal
+SyslogIdentifier=jms-connection
+
+[Install]
+WantedBy=multi-user.target
+```
+
+```bash
+sudo systemctl daemon-reload
+sudo systemctl enable jms-connection
+sudo systemctl start jms-connection
+
+# 常用命令
+sudo systemctl status jms-connection   # 查看状态
+sudo systemctl restart jms-connection  # 重启
+sudo systemctl stop jms-connection     # 停止
+journalctl -u jms-connection -f        # 查看日志
+```
+
+### 6.2 Windows 服务管理
+
+```cmd
+:: 创建服务(管理员权限)
+sc create JMSConnection binPath= "C:\JMS\jms-connection-service-windows.exe" start= auto
+
+:: 启动 / 停止 / 查询
+sc start JMSConnection
+sc stop JMSConnection
+sc query JMSConnection
+
+:: 删除服务(先停止)
+sc stop JMSConnection
+sc delete JMSConnection
+```
+
+### 6.3 PM2 常用命令
 
 ```bash
 pm2 status                          # 查看进程状态
 pm2 logs jms-connection-service     # 查看实时日志
-pm2 restart jms-connection-service  # 重启服务
-pm2 stop jms-connection-service     # 停止服务
-pm2 delete jms-connection-service   # 从 PM2 移除
+pm2 restart jms-connection-service  # 重启
+pm2 stop jms-connection-service     # 停止
+pm2 delete jms-connection-service   # 移除
 ```
 
-### 5.2 日志查看
+### 6.4 日志查看
 
-日志文件位于 `logDir` 配置的目录中(默认 `./logs`),按天滚动:
+日志按天滚动,位于 `logDir` 配置的目录(默认 `./logs`):
 
 ```
 logs/
-├── service.2026-05-10.log
 ├── service.2026-05-11.log
-└── service.2026-05-12.log    # 最多保留 30 天
+├── service.2026-05-12.log
+└── service.2026-05-13.log    # 最多保留 30 天
 ```
 
-日志中的关键符号:
+日志符号含义:
 
 | 符号 | 含义 |
 |------|------|
 | `→` | 发送 K 请求 |
-| `←` | 收到 K 响应(含原始报文) |
-| `✓` | TCP 连接成功 / 上传通道连接成功 |
+| `←` | 收到 K 响应 |
+| `✓` | TCP 连接成功 / 上传通道就绪 |
 | `✂` | TCP 断开 |
 | `↻` | 计划重连 |
 | `↑` | 上传成功 |
 | `✗` | 错误 |
 | `!` | 警告 |
 
-### 5.3 优雅停止
+### 6.5 优雅停止
+
+服务收到 SIGINT / SIGTERM 后会依次关闭:设备连接 → 上传模块 → Dashboard → 日志清理定时器。
 
 ```bash
-# PM2 方式
+# PM2
 pm2 stop jms-connection-service
 
-# 直接进程方式(发送 SIGINT)
-kill -2 $(pgrep -f "node index.js")
+# systemd
+sudo systemctl stop jms-connection
+
+# 直接进程
+kill -2 $(pgrep -f "jms-connection-service")
 ```
 
-服务会依次关闭:设备连接 → 上传模块 → Dashboard → 日志清理定时器。
+---
 
-## 6. 网络与防火墙
+## 7. 网络与防火墙
 
-### 6.1 出站连接
-
-服务作为 TCP 客户端,需要访问以下目标:
+### 7.1 出站连接
 
 | 目标 | 协议 | 端口 | 用途 |
 |------|------|------|------|
-| GC-110N 设备 IP | TCP | 10001(可配置) | K 指令轮询 |
+| GC-110N 设备 | TCP | 10001(可配置) | K 指令轮询 |
 | MQTT Broker | TCP | 62283(可配置) | MQTT 上传 |
-| 阿里云 IoT SDK | TCP | 443 (TLS) | 阿里云属性上报 |
-| 三元组 API | HTTPS | 443 | 获取设备三元组 |
+| 阿里云 IoT | TCP | 443 (TLS) | 属性上报 |
+| 三元组 API | HTTPS | 443 | 获取设备凭证 |
 
-### 6.2 入站连接
+### 7.2 入站连接
 
 | 来源 | 协议 | 端口 | 用途 |
 |------|------|------|------|
-| 浏览器(局域网) | HTTP | 3100(可配置) | 监控大屏 |
-| 浏览器(局域网) | WebSocket | 3100(同 HTTP) | 实时数据推送 |
+| 局域网浏览器 | HTTP | 3100(可配置) | 监控大屏 |
+| 局域网浏览器 | WebSocket | 3100 | 实时数据推送 |
 
-### 6.3 防火墙配置示例(Linux iptables)
+### 7.3 Linux iptables
 
 ```bash
-# 允许 Dashboard 入站(仅内网)
+# 允许内网访问 Dashboard
 iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 3100 -j ACCEPT
 iptables -A INPUT -p tcp --dport 3100 -j DROP
-
-# 出站一般默认为 ACCEPT,无需额外配置
 ```
 
-### 6.4 Windows 防火墙
+### 7.4 Windows 防火墙
 
 ```powershell
-# 允许 Dashboard 端口入站
 New-NetFirewallRule -DisplayName "JMS Dashboard" -Direction Inbound -Protocol TCP -LocalPort 3100 -Action Allow
 ```
 
-## 7. 监控面板使用
+---
 
-### 7.1 面板概览
+## 8. 监控面板使用
 
-访问 `http://<服务器IP>:3100` 进入监控大屏:
+访问 `http://<服务器IP>:3100`:
 
-- **顶部状态栏**:协议版本、WebSocket 连接状态、轮询间隔
-- **汇总卡片**:设备总数、在线数、数据正常数、异常数、MQTT/阿里云上传状态、最近上传结果
-- **设备列表**:每台设备的 IP、序列号、连接状态、最后数据时间、最后上传时间、字段数、重连次数、错误信息
+- **顶部**:协议版本、WebSocket 状态、轮询间隔
+- **汇总卡片**:设备总数、在线数、数据正常数、异常数、MQTT/阿里云上传状态、最近上传
+- **设备列表**:IP、序列号、状态、最后数据时间、最后上传时间、字段数、重连次数、错误信息
+- **点击设备行**:展开详情面板,显示 32 项参数的实时值及原始 K 报文
 
-### 7.2 查看设备详情
-
-点击设备行可展开详情面板,显示:
-
-- 32 项治疗参数的实时值(字段 ID、中文名称、数值、单位)
-- 原始 K 格式报文(如 `K0000A00010B00005...`)
-
-再次点击收起。
-
-### 7.3 状态指示灯
+状态指示灯:
 
 | 颜色 | 含义 |
 |------|------|
@@ -309,67 +459,70 @@
 | 🟡 黄色 | 连接中 |
 | 🔵 蓝色 | 等待轮询 |
 | 🔴 红色 | 断线 / 异常 |
-| ⚫ 灰色 | 已禁用 / 等待 |
+| ⚫ 灰色 | 已禁用 |
 
-## 8. 常见问题排查
+---
 
-### 8.1 设备显示「断线」
+## 9. 常见问题排查
 
-1. **检查网络连通性**:`ping <设备IP>` 和 `nc -zv <设备IP> <端口>`
-2. **检查设备是否开机**:GC-110N 设备需处于治疗或待机状态
-3. **检查防火墙**:确认服务器到设备的 TCP 端口未被拦截
-4. **查看日志**:`logs/service.YYYY-MM-DD.log` 搜索 `✂` 和 `✗`
+### 9.1 设备显示「断线」
 
-### 8.2 收不到数据 / 字段数为 0
+1. `ping <设备IP>` 和 `nc -zv <设备IP> <端口>` 检查连通性
+2. 确认 GC-110N 设备已开机
+3. 检查防火墙是否拦截 TCP 端口
+4. 查看 `logs/service.YYYY-MM-DD.log` 搜索 `✂` 和 `✗`
 
-1. 确认设备已进入治疗状态(待机状态下 K 指令返回数据可能有限)
-2. 查看日志中 `←` 行,检查原始报文格式是否正确(应以 `K` 开头 + 4 位状态码)
+### 9.2 收不到数据 / 字段数为 0
+
+1. 确认设备已进入治疗状态(待机状态可能返回有限数据)
+2. 查看日志中 `←` 行,确认报文以 `K` 开头 + 4 位状态码
 3. 确认设备固件支持 K 格式协议
 
-### 8.3 阿里云上传失败
+### 9.3 阿里云上传失败
 
-1. **三元组获取失败**:检查 `aliyun.tupleApiBaseUrl` 能否从服务器访问(`curl <url>`)
-2. **属性上报超时**:检查服务器到阿里云 IoT 的 443 端口连通性
-3. **设备未注册**:设置 `aliyun.autoRegister: true` 自动注册,或先在阿里云 IoT 平台创建设备
-4. **冷却期**:三元组请求失败后进入 60s 冷却期,期间不重试,查看日志 `tuple` 事件
+1. 检查 `aliyun.tupleApiBaseUrl` 可达性:`curl <url>`
+2. 检查服务器到阿里云 IoT 443 端口连通性
+3. 设置 `aliyun.autoRegister: true` 自动注册设备
+4. 三元组失败后进入 60s 冷却期,期间不重试
 
-### 8.4 MQTT 上传不工作
+### 9.4 MQTT 上传不工作
 
 1. 确认 `mqtt.enabled: true`
-2. 检查 MQTT Broker 地址和端口是否可达
-3. 确认用户名密码正确
-4. Dashboard 的 MQTT 卡片会显示当前连接状态
+2. 检查 MQTT Broker 地址端口可达性
+3. 确认认证凭据正确
+4. Dashboard 的 MQTT 卡片会显示连接状态
 
-### 8.5 Dashboard 打不开
+### 9.5 Dashboard 打不开
 
-1. 确认 `dashboardPort` 未被占用:`netstat -tlnp | grep 3100`
-2. 确认防火墙允许对应端口入站
-3. 确认服务已正常启动(查看控制台输出)
+1. 确认端口未被占用:`netstat -tlnp | grep 3100`
+2. 确认防火墙允许入站
+3. 确认服务已正常启动
 
-### 8.6 日志文件过大
+### 9.6 可执行程序启动报错
 
-服务内置了日志清理机制,每小时检查一次并删除超过保留天数的日志。如需手动清理:
+1. **Windows**:确认已安装 [Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)
+2. **Linux**:确认已赋予执行权限 `chmod +x`
+3. 确认 `config.json` 与可执行文件在同一目录
 
-```bash
-# 删除 30 天前的日志
-find ./logs -name "*.log" -mtime +30 -delete
-```
+---
 
-## 9. 目录结构
+## 10. 目录结构
 
 ```
 jms-connection-service/
 ├── index.js                       # 入口文件
 ├── config.json                    # 配置文件 ★
 ├── package.json                   # 依赖声明
+├── scripts/
+│   └── build.js                   # 打包构建脚本
 ├── lib/
-│   ├── logger.js                  # 日志模块(按天滚动,控制台彩色 + 文件纯文本)
+│   ├── logger.js                  # 日志模块(按天滚动)
 │   ├── data-cache.js              # 内存数据缓存(Map<ip, deviceData>)
-│   ├── device-manager.js          # 设备管理(遍历 config.devices 创建连接)
+│   ├── device-manager.js          # 设备管理(遍历创建连接)
 │   ├── device-connection.js       # 单设备 TCP 长连接 + K 轮询 + 重连
 │   ├── protocol.js                # GC-110N K 格式解析器
 │   └── upload/
-│       ├── index.js               # 上传总控(顺序执行 MQTT → 阿里云)
+│       ├── index.js               # 上传总控(顺序:MQTT → 阿里云)
 │       ├── mqtt-uploader.js       # MQTT 单例客户端
 │       ├── aliyun-uploader.js     # 阿里云 IoT SDK 设备实例池
 │       ├── tuple-api.js           # 三元组 API HTTP 请求
@@ -380,7 +533,40 @@
         └── index.html             # 监控大屏单页
 ```
 
-## 10. 附录:GC-110N K 格式字段表
+---
+
+## 11. 开发者打包
+
+如需从源码重新打包可执行程序:
+
+```bash
+# 安装开发依赖(含 pkg)
+npm install
+
+# 打包 Windows + Linux
+npm run build
+
+# 仅打包 Windows
+npm run build:win
+
+# 仅打包 Linux
+npm run build:linux
+```
+
+打包产物输出到 `dist/` 目录:
+
+```
+dist/
+├── jms-connection-service-windows.zip    # Windows 部署包
+├── jms-connection-service-windows/       # Windows 部署目录
+└── jms-connection-service-linux/         # Linux 部署目录
+```
+
+> 打包使用 [pkg](https://github.com/vercel/pkg) 将 Node.js 运行时与应用代码合并为独立可执行文件。首次打包需下载 Node.js 二进制(~30 MB),后续打包使用缓存。
+
+---
+
+## 12. 附录:GC-110N K 格式字段表
 
 | ID | 中文名称 | 单位 | 宽度(字节) |
 |----|----------|------|-------------|

--
Gitblit v1.8.0