iotsaas/deploy-all.bat
2995840376 066d374673 fix(M): 修复品类中文乱码, 子设备在线状态按父网关判定
乱码: 服务器 mysql 客户端在 C locale 下 character_set_client=latin1, 迁移脚本经 Windows type|plink 管道执行时 UTF-8 字节被按 latin1 解读, 中文双重编码。修复: V25/V26 脚本首行加 SET NAMES utf8mb4, deploy-all.bat 的 mysql 调用补 --default-character-set=utf8mb4, 新增 V26 按 code 写回正确中文(幂等)。已验证 product_category.name 的 hex 为正确 UTF-8。

子设备在线: 涂鸦 Mesh/Zigbee 子设备无独立在线通道, SDK 与云端快照对其 online 恒 false, APP 上报后被写成离线。后端新增 resolveEffectiveOnlineStatus —— 上报在线即 online; 子设备上报离线时以父网关为准(父在线则 online); 设备列表输出再做一次父网关聚合, 历史数据立即生效。前端 DeviceInfo 增报 parentDeviceId, 并按品类推断 is_gateway。

APP: 网关下挂设备不再用涂鸦 SDK 快照覆盖后端结论; 列表状态改为在线/离线/状态未知三态; uniapp 端修复状态比大写 ONLINE 导致恒离线、且把状态字符串当 DP JSON 解析的问题。生产验证: JD2BTSA/JD6BTSA 由 offline 变为 online。
2026-10-28 01:25:46 +08:00

138 lines
9.0 KiB
Batchfile
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion
title IoT SaaS 一键重新构建并部署(后端 4 服务 + 前端后台)
REM 非交互部署(CI/自动化):运行前先 set NONINTERACTIVE=1,例如
REM cmd /c "set NONINTERACTIVE=1 & f:\work\iotsaas\deploy-all.bat"
REM 可跳过末尾 pause,避免在自动化环境(非 TTY)用管道喂入干扰 plink。
:: ============ 环境配置(按本机实际路径修改) ============
set JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot
set PATH=%JAVA_HOME%\bin;D:\dev\apache-maven-3.9.16\bin;%PATH%
set PLINK="C:\Program Files\PuTTY\plink.exe"
set PLINK_OPTS=-pw Tonzou@888 -hostkey aa:01:8c:1d:95:36:68:6d:c6:ad:d1:c5:45:0b:05:46 -batch tonzou@192.168.3.3
set SRV_JARS=/opt/iotsaas/backend/jars
set SRV_DIST=/opt/iotsaas/frontend/dist
set BACKEND_DIR=f:\work\iotsaas\backend
set ADMIN_DIR=f:\work\iotsaas\frontend\admin
:: iot-device 带 exec classifier,其余为 fat jar 原名
set JAR_DEV=iot-device-1.0.0-exec.jar
set JAR_DATA=iot-data-1.0.0.jar
set JAR_RULE=iot-rule-1.0.0.jar
set JAR_ALARM=iot-alarm-1.0.0.jar
:: ============ 1) 后端构建(含共享模块 iot-common) ============
cd /d %BACKEND_DIR%
echo ============================================
echo [1/8] Maven 重新构建 4 个服务(含共享模块 iot-common)
echo ============================================
call mvn clean package -pl iot-device,iot-data,iot-rule,iot-alarm -am -DskipTests
if %ERRORLEVEL% NEQ 0 ( echo [错误] 后端构建失败,已中止。 & pause & exit /b 1 )
echo [OK] 后端构建成功。
:: ============ 2) 上传 4 个 jar ============
echo ============================================
echo [2/8] 上传 4 个 jar 到服务器 %SRV_JARS%
echo ============================================
tar cf - -C %BACKEND_DIR%\iot-device\target %JAR_DEV% -C %BACKEND_DIR%\iot-data\target %JAR_DATA% -C %BACKEND_DIR%\iot-rule\target %JAR_RULE% -C %BACKEND_DIR%\iot-alarm\target %JAR_ALARM% | %PLINK% %PLINK_OPTS% tar xf - -C %SRV_JARS%
if %ERRORLEVEL% NEQ 0 ( echo [错误] jar 上传失败。 & pause & exit /b 1 )
echo [OK] jar 上传完成。
:: ============ 2.5) 数据库迁移(Flyway 在本环境未启用,按 DB 内 tracking 表应用未执行的 V 迁移) ============
echo ============================================
echo [3/8] 应用未执行的 SQL 迁移(%BACKEND_DIR%\sql\V*.sql,按 db_migrations_applied 去重)
echo ============================================
set MIG_DIR=%BACKEND_DIR%\sql
set CHK_FILE=%TEMP%\_mig_chk.txt
%PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --default-character-set=utf8mb4 -uroot -p'IoT.p2026.Xk9Qm' iot_platform -e \"CREATE TABLE IF NOT EXISTS db_migrations_applied (name VARCHAR(80) NOT NULL PRIMARY KEY, applied_at DATETIME DEFAULT CURRENT_TIMESTAMP)\"" 2>nul
REM 首次使用(tracking 表为空)则标记当前所有 V 文件为已应用:假定目标库已手工迁移到最新。
REM 全新库请先手动执行 sql/ 下全部 V 迁移,再运行本脚本(或清空 db_migrations_applied 让其补跑,需迁移文件幂等)。
%PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --default-character-set=utf8mb4 -uroot -p'IoT.p2026.Xk9Qm' iot_platform -N -e \"SELECT COUNT(*) FROM db_migrations_applied\"" 2>nul > "%CHK_FILE%"
set /p MIG_CNT=<"%CHK_FILE%"
if "!MIG_CNT!"=="0" (
echo 首次使用:标记当前所有 V 迁移为已应用(假定库已迁移到最新)
for /f "delims=" %%F in ('dir /b /on "%MIG_DIR%\V*.sql"') do call :mig_seed "%%F"
)
REM 应用未记录的 V 迁移(新增迁移文件会自动在此补跑,无需改本脚本)
for /f "delims=" %%F in ('dir /b /on "%MIG_DIR%\V*.sql"') do call :mig_apply "%%F"
echo [OK] 迁移步骤完成。
::: ============ 3.5) 日志治理:同步 systemd 单元 + journald 限额,清理无轮转的历史 .out ============
echo ============================================
echo [4/8] 同步 systemd 单元与 journald 限额(日志轮转治理),并清理历史无轮转 .out/.err
echo ============================================
%PLINK% %PLINK_OPTS% "rm -rf /tmp/iotsaas-units && mkdir -p /tmp/iotsaas-units"
tar cf - -C %BACKEND_DIR%\deploy\systemd . | %PLINK% %PLINK_OPTS% tar xf - -C /tmp/iotsaas-units
if %ERRORLEVEL% NEQ 0 ( echo [错误] systemd 单元上传失败。 & pause & exit /b 1 )
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' cp /tmp/iotsaas-units/iot-device.service /tmp/iotsaas-units/iot-data.service /tmp/iotsaas-units/iot-rule.service /tmp/iotsaas-units/iot-alarm.service /etc/systemd/system/ && echo 'Tonzou@888' | sudo -S -p '' mkdir -p /etc/systemd/journald.conf.d && echo 'Tonzou@888' | sudo -S -p '' cp /tmp/iotsaas-units/journald-iotsaas.conf /etc/systemd/journald.conf.d/iotsaas.conf"
if %ERRORLEVEL% NEQ 0 ( echo [错误] systemd 单元安装失败。 & pause & exit /b 1 )
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl daemon-reload && echo 'Tonzou@888' | sudo -S -p '' systemctl restart systemd-journald"
REM 清理历史无轮转的 .out/.err(内容已由 journal 与滚动日志文件接管),并准备滚动日志目录
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' rm -f /opt/iotsaas/logs/*.out /opt/iotsaas/logs/*.err && echo 'Tonzou@888' | sudo -S -p '' rm -rf /opt/iotsaas/backend/jars/logs && echo 'Tonzou@888' | sudo -S -p '' mkdir -p /opt/iotsaas/logs/app && echo 'Tonzou@888' | sudo -S -p '' chown -R tonzou:tonzou /opt/iotsaas/logs"
echo [OK] systemd 单元与 journald 限额已同步,历史 .out 已清理。
:: ============ 3) 重启 4 个后端服务 ============
echo ============================================
echo [5/8] 重启 4 个后端服务(systemd)
echo ============================================
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl restart iot-device iot-data iot-rule iot-alarm" 2>nul
if %ERRORLEVEL% NEQ 0 ( echo [错误] 服务重启失败。 & pause & exit /b 1 )
echo [OK] 重启命令已下发。
:: ============ 4) 构建前端后台(admin) ============
cd /d %ADMIN_DIR%
echo ============================================
echo [6/8] 构建前端后台(admin)— 跳过 vue-tsc 类型检查,直接 vite build
echo ============================================
where node >nul 2>nul || ( echo [错误] 未找到 node,请将其加入 PATH。 & pause & exit /b 1 )
call npx vite build
if %ERRORLEVEL% NEQ 0 ( echo [错误] 前端构建失败。 & pause & exit /b 1 )
echo [OK] 前端构建成功(dist 已生成)。
:: ============ 5) 上传前端 dist(先清空旧文件再解包,避免残留旧 hash 资源) ============
echo ============================================
echo [7/8] 上传前端 dist 到服务器 %SRV_DIST%
echo ============================================
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' rm -rf %SRV_DIST% && mkdir -p %SRV_DIST%"
if %ERRORLEVEL% NEQ 0 ( echo [错误] 清空远端 dist 失败。 & pause & exit /b 1 )
tar cf - -C %ADMIN_DIR%\dist . | %PLINK% %PLINK_OPTS% tar xf - -C %SRV_DIST%
if %ERRORLEVEL% NEQ 0 ( echo [错误] dist 上传失败。 & pause & exit /b 1 )
echo [OK] dist 上传完成。
:: ============ 6) 确认状态 ============
echo ============================================
echo [8/8] 等待启动并确认服务状态
echo ============================================
timeout /t 20 /nobreak >nul
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl is-active iot-device iot-data iot-rule iot-alarm" 2>nul
echo.
echo 部署完成!冒烟测试地址:
echo http://192.168.3.3:9081/doc.html (设备/鉴权/授权对接接口)
echo http://192.168.3.3/ (后台管理,含「系统管理 - 应用管理」)
echo http://192.168.3.3/api/doc/partner.html (授权对接接入指南)
echo.
REM 非交互部署(如 CI/自动化)设 set NONINTERACTIVE=1 可跳过等待按键,避免管道喂入干扰 plink
if not defined NONINTERACTIVE pause
goto :eof
:: ============ 迁移子例程(顶层执行,避开括号块内转义问题) ============
:mig_seed
%PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --default-character-set=utf8mb4 -uroot -p'IoT.p2026.Xk9Qm' iot_platform -e \"INSERT IGNORE INTO db_migrations_applied(name) VALUES('%1')\"" 2>nul
goto :eof
:mig_apply
set CHK=0
%PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --default-character-set=utf8mb4 -uroot -p'IoT.p2026.Xk9Qm' iot_platform -N -e \"SELECT COUNT(*) FROM db_migrations_applied WHERE name='%1'\"" 2>nul > "%CHK_FILE%"
set /p CHK=<"%CHK_FILE%"
if not "!CHK!"=="0" (
echo 跳过已应用 %1
goto :eof
)
echo 应用 %1 ...
REM --force: 迁移脚本中"已存在"的 DDL(重复列/索引)属正常情况,不应中断整体部署
type "%MIG_DIR%\%1" | %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --force --default-character-set=utf8mb4 -uroot -p'IoT.p2026.Xk9Qm' iot_platform"
if !ERRORLEVEL! NEQ 0 ( echo [错误] 迁移 %1 执行失败。 & pause & exit /b 1 )
%PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --default-character-set=utf8mb4 -uroot -p'IoT.p2026.Xk9Qm' iot_platform -e \"INSERT IGNORE INTO db_migrations_applied(name) VALUES('%1')\"" 2>nul
goto :eof