|
@@ -0,0 +1,1185 @@
|
|
|
|
|
+<!DOCTYPE html>
|
|
|
|
|
+<html lang="zh-CN">
|
|
|
|
|
+<head>
|
|
|
|
|
+<meta charset="UTF-8">
|
|
|
|
|
+<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
|
+<title>帮助手册 - 车牌识别系统</title>
|
|
|
|
|
+<style>
|
|
|
|
|
+*{box-sizing:border-box;margin:0;padding:0}
|
|
|
|
|
+body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#f0f2f5;color:#333}
|
|
|
|
|
+.navbar{background:#1a1a2e;color:#fff;padding:12px 20px;display:flex;align-items:center;gap:20px;box-shadow:0 2px 8px rgba(0,0,0,0.15)}
|
|
|
|
|
+.navbar a{color:#ccc;text-decoration:none;padding:6px 12px;border-radius:4px;font-size:14px}
|
|
|
|
|
+.navbar a:hover,.navbar a.active{background:rgba(255,255,255,0.15);color:#fff}
|
|
|
|
|
+.navbar .brand{font-size:16px;font-weight:bold;color:#4fc3f7;margin-right:10px}
|
|
|
|
|
+.container{max-width:960px;margin:20px auto;padding:0 16px}
|
|
|
|
|
+.card{background:#fff;border-radius:8px;margin-bottom:16px;box-shadow:0 1px 4px rgba(0,0,0,0.08);overflow:hidden}
|
|
|
|
|
+.card-title{background:#263238;color:#fff;padding:10px 16px;font-size:14px;font-weight:600;display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}
|
|
|
|
|
+.card-title:hover{background:#37474f}
|
|
|
|
|
+.card-title .arrow{transition:transform 0.2s;font-size:12px}
|
|
|
|
|
+.card-title.collapsed .arrow{transform:rotate(-90deg)}
|
|
|
|
|
+.card-body{padding:16px 20px;line-height:1.8;font-size:14px}
|
|
|
|
|
+.card-body.hidden{display:none}
|
|
|
|
|
+h3{color:#1a1a2e;margin:16px 0 8px;font-size:15px;border-left:3px solid #667eea;padding-left:10px}
|
|
|
|
|
+h4{color:#333;margin:12px 0 6px;font-size:14px}
|
|
|
|
|
+table{width:100%;border-collapse:collapse;margin:8px 0 16px;font-size:13px}
|
|
|
|
|
+th{background:#f5f5f5;padding:8px 10px;text-align:left;font-weight:600;border-bottom:2px solid #e0e0e0;white-space:nowrap}
|
|
|
|
|
+td{padding:8px 10px;border-bottom:1px solid #f0f0f0;vertical-align:top}
|
|
|
|
|
+td:first-child{font-family:monospace;color:#d32f2f;white-space:nowrap;font-size:12px}
|
|
|
|
|
+code{background:#f5f5f5;padding:2px 6px;border-radius:3px;font-size:12px;color:#d32f2f;font-family:monospace}
|
|
|
|
|
+pre{background:#1e1e2e;color:#cdd6f4;padding:14px 18px;border-radius:6px;font-size:12px;overflow-x:auto;margin:8px 0 16px;line-height:1.6}
|
|
|
|
|
+pre code{background:none;color:#cdd6f4;padding:0;font-size:12px}
|
|
|
|
|
+.tip{background:#e8f5e9;border-left:4px solid #4caf50;padding:10px 14px;margin:8px 0;border-radius:0 4px 4px 0;font-size:13px}
|
|
|
|
|
+.warn{background:#fff3e0;border-left:4px solid #ff9800;padding:10px 14px;margin:8px 0;border-radius:0 4px 4px 0;font-size:13px}
|
|
|
|
|
+.note{background:#e3f2fd;border-left:4px solid #2196f3;padding:10px 14px;margin:8px 0;border-radius:0 4px 4px 0;font-size:13px}
|
|
|
|
|
+ul{padding-left:20px;margin:6px 0}
|
|
|
|
|
+li{margin:4px 0;font-size:13px;line-height:1.7}
|
|
|
|
|
+.toc{background:#fff;border-radius:8px;padding:16px 24px;margin-bottom:16px;box-shadow:0 1px 4px rgba(0,0,0,0.08)}
|
|
|
|
|
+.toc h2{font-size:16px;color:#1a1a2e;margin-bottom:10px;border-bottom:2px solid #667eea;padding-bottom:6px}
|
|
|
|
|
+.toc ol{padding-left:20px;columns:2;column-gap:30px}
|
|
|
|
|
+.toc li{margin:4px 0;font-size:13px;break-inside:avoid}
|
|
|
|
|
+.toc a{color:#667eea;text-decoration:none}
|
|
|
|
|
+.toc a:hover{text-decoration:underline}
|
|
|
|
|
+@media(max-width:768px){
|
|
|
|
|
+.navbar{flex-wrap:wrap;gap:8px;padding:10px 14px}
|
|
|
|
|
+.navbar .brand{font-size:14px;width:100%}
|
|
|
|
|
+.navbar a{font-size:12px;padding:4px 8px}
|
|
|
|
|
+.container{padding:0 10px;margin:10px auto}
|
|
|
|
|
+.toc ol{columns:1}
|
|
|
|
|
+table{font-size:12px;display:block;overflow-x:auto}
|
|
|
|
|
+th,td{padding:6px 8px}
|
|
|
|
|
+td:first-child{font-size:11px}
|
|
|
|
|
+}
|
|
|
|
|
+@media(max-width:480px){
|
|
|
|
|
+.navbar .brand{font-size:13px}
|
|
|
|
|
+.navbar a{font-size:11px;padding:3px 6px}
|
|
|
|
|
+.card-body{padding:12px 14px}
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
|
|
+</head>
|
|
|
|
|
+<body>
|
|
|
|
|
+<nav class="navbar">
|
|
|
|
|
+ <span class="brand">🚛 车牌识别系统</span>
|
|
|
|
|
+ <a href="/">监控首页</a>
|
|
|
|
|
+ <a href="/video">视频预览</a>
|
|
|
|
|
+ <a href="/locks">锁定管理</a>
|
|
|
|
|
+ <a href="/help" class="active">帮助手册</a>
|
|
|
|
|
+</nav>
|
|
|
|
|
+
|
|
|
|
|
+<div class="container">
|
|
|
|
|
+
|
|
|
|
|
+<div class="toc">
|
|
|
|
|
+<h2>📋 目录</h2>
|
|
|
|
|
+<ol>
|
|
|
|
|
+ <li><a href="#sec1">系统概述</a></li>
|
|
|
|
|
+ <li><a href="#sec2">快速部署指南</a></li>
|
|
|
|
|
+ <li><a href="#sec3">config.ini 完整配置说明</a></li>
|
|
|
|
|
+ <li><a href="#sec4">RTSP 摄像头配置</a></li>
|
|
|
|
|
+ <li><a href="#sec5">车牌识别上传流程</a></li>
|
|
|
|
|
+ <li><a href="#sec6">MQTT 数据上报配置</a></li>
|
|
|
|
|
+ <li><a href="#sec7">称重系统对接</a></li>
|
|
|
|
|
+ <li><a href="#sec8">ROI 区域识别配置</a></li>
|
|
|
|
|
+ <li><a href="#sec9">交替锁定机制</a></li>
|
|
|
|
|
+ <li><a href="#sec10">登录认证与权限</a></li>
|
|
|
|
|
+ <li><a href="#sec11">frpc.toml 内网穿透配置详解</a></li>
|
|
|
|
|
+ <li><a href="#sec12">Nginx 反向代理配置详解</a></li>
|
|
|
|
|
+ <li><a href="#sec13">SSL/HTTPS 证书配置</a></li>
|
|
|
|
|
+ <li><a href="#sec14">系统监控与日志</a></li>
|
|
|
|
|
+ <li><a href="#sec15">Web 管理功能</a></li>
|
|
|
|
|
+ <li><a href="#sec16">数据库与备份</a></li>
|
|
|
|
|
+ <li><a href="#sec17">常见问题 FAQ</a></li>
|
|
|
|
|
+</ol>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 1. 系统概述 -->
|
|
|
|
|
+<div class="card" id="sec1">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">1. 系统概述 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>系统简介</h3>
|
|
|
|
|
+<p>车牌识别系统(PlateRecApp)是一款基于 HyperLPR3 的实时车牌识别应用,运行在树莓派 5 (aarch64) 上,支持:</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>多路 RTSP 摄像头实时抓拍识别(进场/出场/侧面进/侧面出)</li>
|
|
|
|
|
+ <li>车牌识别结果自动上传至云端 API</li>
|
|
|
|
|
+ <li>称重系统对接(TCP 协议),自动关联车牌与称重数据</li>
|
|
|
|
|
+ <li>MQTT 协议实时推送识别结果</li>
|
|
|
|
|
+ <li>飞书群消息通知(异常报警)</li>
|
|
|
|
|
+ <li>Web 管理界面(监控首页、视频预览、系统配置、锁定管理等)</li>
|
|
|
|
|
+ <li>frpc 内网穿透管理 + Nginx stream + ssl_preread 协议分流(HTTP 自动跳 HTTPS)</li>
|
|
|
|
|
+ <li>登录认证与角色权限控制</li>
|
|
|
|
|
+ <li>SD 卡写入寿命保护(内存缓冲 + 每日定时写盘)</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>运行环境</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>项目</th><th>要求</th></tr>
|
|
|
|
|
+ <tr><td>硬件</td><td>树莓派 5 8GB(推荐)</td></tr>
|
|
|
|
|
+ <tr><td>系统</td><td>Debian 13 (trixie) / Ubuntu 24.04 aarch64</td></tr>
|
|
|
|
|
+ <tr><td>依赖</td><td>HyperLPR3 SDK、FFmpeg、libcurl、OpenSSL、cJSON、Mosquitto、Nginx</td></tr>
|
|
|
|
|
+ <tr><td>内网穿透</td><td>frpc(通过 systemctl 管理)</td></tr>
|
|
|
|
|
+ <tr><td>协议分流</td><td>Nginx stream + ssl_preread(TCP 层 HTTP/HTTPS 自动检测分流)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>网络架构总览(v2 — nginx stream + ssl_preread 方案)</h3>
|
|
|
|
|
+<pre>外网客户端 frps 服务器 本机(树莓派5)
|
|
|
|
|
+───────── ───────── ─────────────
|
|
|
|
|
+ ┌─ TLS → nginx stream → C++ HTTPS:8080 (透传)
|
|
|
|
|
+https://mqtt.zhonjin.com:40963/ ─TCP─→ discover.zhonjin.com:9443 ─TCP─→ frpc ─→ nginx:40963 (stream+ssl_preread)
|
|
|
|
|
+http://mqtt.zhonjin.com:40963/ ─TCP─→ ↑ ─TCP─→ frpc ─→└─ HTTP → nginx:8081 (301→HTTPS)
|
|
|
|
|
+https://mqtt.zhonjin.com:40964/ ─TCP─→ ↑ ─TCP─→ frpc ─→ nginx:8082 (HTTPS代理) → ttyd:7681</pre>
|
|
|
|
|
+<div class="tip"><strong>v2 方案优势:</strong>公网只需一个端口 40963,nginx stream 在 TCP 层自动检测协议类型并分流。HTTP 自动跳 HTTPS,HTTPS 透传到 C++ 应用处理。用户只需记住一个地址。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>目录结构</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>路径</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>PlateRecApp</td><td>主程序二进制</td></tr>
|
|
|
|
|
+ <tr><td>config.ini</td><td>主配置文件</td></tr>
|
|
|
|
|
+ <tr><td>config.txt</td><td>MD5 校验配置</td></tr>
|
|
|
|
|
+ <tr><td>hyperlpr3/</td><td>HyperLPR3 SDK 模型文件</td></tr>
|
|
|
|
|
+ <tr><td>assets/web/</td><td>Web 页面文件(HTML/CSS/JS)</td></tr>
|
|
|
|
|
+ <tr><td>data/</td><td>数据库目录(auth.db、upload_records.db、system_metrics.db)</td></tr>
|
|
|
|
|
+ <tr><td>photos/</td><td>抓拍图片存储目录</td></tr>
|
|
|
|
|
+ <tr><td>scripts/</td><td>运维脚本(sudoers 配置、密码重置等)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 2. 快速部署指南 -->
|
|
|
|
|
+<div class="card" id="sec2">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">2. 快速部署指南 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>编译部署</h3>
|
|
|
|
|
+<ol>
|
|
|
|
|
+ <li>解压代码包:<code>tar xzf fix24_vXX.tar.gz</code></li>
|
|
|
|
|
+ <li>编译:<code>cd fix24/build && cmake .. && make -j4</code></li>
|
|
|
|
|
+ <li>部署文件到安装目录(如 <code>/opt/openAI/project/003.PlateRecAPP/</code>)</li>
|
|
|
|
|
+ <li>复制 HTML 文件:<code>cp -r assets/web/ /安装目录/assets/web/</code></li>
|
|
|
|
|
+ <li>配置 sudoers(frpc 管理需要):<code>sudo bash scripts/setup_frpc_sudoers.sh</code></li>
|
|
|
|
|
+ <li>安装 nginx stream 模块:<code>sudo apt install libnginx-mod-stream</code></li>
|
|
|
|
|
+ <li>部署 nginx stream 配置文件(详见第 12 章)</li>
|
|
|
|
|
+ <li>部署 SSL 证书(C++ 应用自管理,详见第 13 章)</li>
|
|
|
|
|
+ <li>修改 <code>config.ini</code> 配置(参考下文各节)</li>
|
|
|
|
|
+ <li>启动服务:<code>sudo systemctl restart nginx && sudo systemctl restart PlateRecApp</code></li>
|
|
|
|
|
+</ol>
|
|
|
|
|
+
|
|
|
|
|
+<h3>一键部署脚本(推荐)</h3>
|
|
|
|
|
+<p>代码包内置 <code>scripts/deploy.sh</code>,覆盖编译→备份→部署→服务安装→启动→健康检查全流程,默认部署目录 <code>/opt/openAI/project/003.PlateRecAPP</code>、运行用户 <code>stevenroc</code>、服务名 <code>PlateRecApp</code>(均可用环境变量 <code>APP_DIR</code>/<code>RUN_USER</code>/<code>SVC_NAME</code> 覆盖):</p>
|
|
|
|
|
+<pre># 首次:安装编译/运行依赖(需 root)
|
|
|
|
|
+sudo bash scripts/deploy.sh deps
|
|
|
|
|
+
|
|
|
|
|
+# 一键编译+部署+重启(部署前自动备份当前版本到 backup/,保留最近 5 个)
|
|
|
|
|
+sudo bash scripts/deploy.sh deploy # 或直接 sudo bash scripts/deploy.sh
|
|
|
|
|
+
|
|
|
|
|
+# 日常运维
|
|
|
|
|
+bash scripts/deploy.sh status # 服务状态 + 8080/8079 端口 + 进程 + 磁盘
|
|
|
|
|
+bash scripts/deploy.sh logs # 跟踪 PlateRecApp.log
|
|
|
|
|
+bash scripts/deploy.sh journal # 跟踪 systemd journal
|
|
|
|
|
+bash scripts/deploy.sh restart # 重启服务
|
|
|
|
|
+sudo bash scripts/deploy.sh rollback # 回滚到上一次备份
|
|
|
|
|
+sudo bash scripts/deploy.sh sudoers # 配置 frpc 管理 sudoers 权限</pre>
|
|
|
|
|
+<div class="tip">脚本安全策略:<b>config.ini 已存在时永不覆盖</b>(首次部署才从模板生成);每次部署自动备份二进制+配置+Web资源+SDK;服务文件由脚本自动安装到 /etc/systemd/system/ 并设置开机自启。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>systemd 服务配置</h3>
|
|
|
|
|
+<p>PlateRecApp 服务文件路径:<code>/etc/systemd/system/PlateRecApp.service</code>(由 deploy.sh 自动生成,内容等价于):</p>
|
|
|
|
|
+<pre>Unit]
|
|
|
|
|
+Description=PlateRecApp License Plate Recognition System
|
|
|
|
|
+After=network.target frpc.service
|
|
|
|
|
+
|
|
|
|
|
+[Service]
|
|
|
|
|
+User=stevenroc
|
|
|
|
|
+Group=stevenroc
|
|
|
|
|
+WorkingDirectory=/opt/openAI/project/003.PlateRecAPP
|
|
|
|
|
+ExecStartPre=/bin/sleep 10
|
|
|
|
|
+ExecStart=/opt/openAI/project/003.PlateRecAPP/PlateRecApp
|
|
|
|
|
+TimeoutStartSec=30
|
|
|
|
|
+TimeoutStopSec=10
|
|
|
|
|
+Restart=on-failure
|
|
|
|
|
+RestartSec=5
|
|
|
|
|
+StandardOutput=append:/opt/openAI/project/003.PlateRecAPP/PlateRecApp.log
|
|
|
|
|
+LimitNOFILE=1048576
|
|
|
|
|
+
|
|
|
|
|
+[Install]
|
|
|
|
|
+WantedBy=multi-user.target</pre>
|
|
|
|
|
+<div class="tip">PlateRecApp 以非 root 用户运行(stevenroc),frpc 管理通过 sudoers 授权。日志输出由 v36 内存缓冲系统接管,systemd 的 StandardOutput 仅作备份。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>密码重置</h3>
|
|
|
|
|
+<p>如忘记管理员密码,运行:<code>python3 reset_passwords.py</code></p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Nginx 服务配置(v2 — stream 方案)</h3>
|
|
|
|
|
+<p>安装 stream 模块并部署配置:</p>
|
|
|
|
|
+<pre># 安装 stream 模块(必须)
|
|
|
|
|
+sudo apt install -y libnginx-mod-stream
|
|
|
|
|
+
|
|
|
|
|
+# 验证模块
|
|
|
|
|
+nginx -V 2>&1 | grep stream
|
|
|
|
|
+
|
|
|
|
|
+# 替换 nginx.conf(详见第 12 章)
|
|
|
|
|
+sudo cp nginx-stream.conf /etc/nginx/nginx.conf
|
|
|
|
|
+
|
|
|
|
|
+# 验证配置
|
|
|
|
|
+sudo nginx -t
|
|
|
|
|
+
|
|
|
|
|
+# 启动/重载
|
|
|
|
|
+sudo systemctl enable nginx
|
|
|
|
|
+sudo systemctl restart nginx</pre>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 3. config.ini 完整配置 -->
|
|
|
|
|
+<div class="card" id="sec3">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">3. config.ini 完整配置说明 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<p>配置文件路径:<code><安装目录>/config.ini</code>,ini 格式,section 和 key 均不区分大小写。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[config] 核心识别配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>project_name</td><td>string</td><td>-</td><td>项目名称</td></tr>
|
|
|
|
|
+ <tr><td>point_number</td><td>string</td><td>-</td><td>站点编号</td></tr>
|
|
|
|
|
+ <tr><td>throughway</td><td>string</td><td>-</td><td>通道名称</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_front_in</td><td>string</td><td>-</td><td>前侧进场摄像头 RTSP 地址</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_front_out</td><td>string</td><td>-</td><td>前侧出场摄像头 RTSP 地址</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_side_in</td><td>string</td><td>-</td><td>侧面进场摄像头 RTSP 地址</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_side_out</td><td>string</td><td>-</td><td>侧面出场摄像头 RTSP 地址</td></tr>
|
|
|
|
|
+ <tr><td>app_api</td><td>string</td><td>-</td><td>云端上传 API 地址</td></tr>
|
|
|
|
|
+ <tr><td>app_key</td><td>string</td><td>-</td><td>API 认证 Key</td></tr>
|
|
|
|
|
+ <tr><td>app_secret</td><td>string</td><td>-</td><td>API 认证 Secret</td></tr>
|
|
|
|
|
+ <tr><td>DEBUG_LOG</td><td>int</td><td>0</td><td>调试日志开关(0=关闭,1=开启)</td></tr>
|
|
|
|
|
+ <tr><td>TestFlag</td><td>int</td><td>0</td><td>测试模式开关</td></tr>
|
|
|
|
|
+ <tr><td>wType</td><td>int</td><td>0</td><td>称重类型(0=禁用,1=启用)</td></tr>
|
|
|
|
|
+ <tr><td>TIME_WINDOW</td><td>int</td><td>5</td><td>识别时间窗口(分钟),同一车牌在窗口内不重复上传</td></tr>
|
|
|
|
|
+ <tr><td>MAX_PHOTO_GROUPS</td><td>int</td><td>100</td><td>最大照片组数缓存</td></tr>
|
|
|
|
|
+ <tr><td>in_out_interval</td><td>int</td><td>5</td><td>⚠️ 单位是<strong>分钟</strong>!交替锁定间隔(同一车牌进出最短时间),内部转为秒存储</td></tr>
|
|
|
|
|
+ <tr><td>PLATE_CONFIDENCE_THRESHOLD</td><td>float</td><td>0.7</td><td>车牌识别置信度阈值(0~1),低于此值不上传</td></tr>
|
|
|
|
|
+ <tr><td>PLATE_LOG_THRESHOLD</td><td>float</td><td>0.5</td><td>日志记录置信度阈值</td></tr>
|
|
|
|
|
+ <tr><td>AlternatingMerge</td><td>int</td><td>0</td><td>交替合并开关(0=关闭,1=开启)</td></tr>
|
|
|
|
|
+ <tr><td>hw_decode_mode</td><td>string</td><td>auto</td><td>硬件解码模式:auto/soft/drm</td></tr>
|
|
|
|
|
+ <tr><td>hw_decode_device</td><td>string</td><td>/dev/dri/renderD128</td><td>硬件解码设备路径</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_transport</td><td>string</td><td>tcp</td><td>RTSP 传输协议:tcp/udp</td></tr>
|
|
|
|
|
+ <tr><td>PhotoMaxCapacityMB</td><td>int</td><td>1024</td><td>照片目录最大容量(MB),超限自动清理旧照片</td></tr>
|
|
|
|
|
+ <tr><td>LogRetentionDays</td><td>int</td><td>30</td><td>日志保留天数</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[server] Web 服务配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>ip</td><td>Web 服务监听地址(含端口),如 <code>0.0.0.0:8080</code>。v2 方案下 PlateRecApp 提供 HTTPS 服务(SSL 自管理),nginx stream 透传 TLS 流量到此处</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[mqtt] MQTT 上报配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>MQTT_HOST</td><td>-</td><td>MQTT Broker 地址(填写后自动启用 MQTT)</td></tr>
|
|
|
|
|
+ <tr><td>MQTT_PORT</td><td>1883</td><td>MQTT Broker 端口</td></tr>
|
|
|
|
|
+ <tr><td>MQTT_USER</td><td>-</td><td>MQTT 用户名</td></tr>
|
|
|
|
|
+ <tr><td>MQTT_PASS</td><td>-</td><td>MQTT 密码</td></tr>
|
|
|
|
|
+ <tr><td>MQTT_TOPIC</td><td>-</td><td>推送主题</td></tr>
|
|
|
|
|
+ <tr><td>MQTT_CLIENT_ID</td><td>-</td><td>客户端 ID</td></tr>
|
|
|
|
|
+ <tr><td>PLATE_COLOR</td><td>-</td><td>车牌颜色标识(随 MQTT 消息上报)</td></tr>
|
|
|
|
|
+ <tr><td>VEHICLE_TYPE</td><td>-</td><td>车辆类型标识(随 MQTT 消息上报)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[auth] 登录认证配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>enabled</td><td>1</td><td>认证开关(0=关闭,1=开启)</td></tr>
|
|
|
|
|
+ <tr><td>db_path</td><td>data/auth.db</td><td>认证数据库路径</td></tr>
|
|
|
|
|
+ <tr><td>session_idle_timeout</td><td>1800</td><td>Session 空闲超时(秒)</td></tr>
|
|
|
|
|
+ <tr><td>session_max_timeout</td><td>28800</td><td>Session 最大超时(秒)</td></tr>
|
|
|
|
|
+ <tr><td>session_remember_timeout</td><td>604800</td><td>记住登录超时(秒)</td></tr>
|
|
|
|
|
+ <tr><td>max_failed_attempts</td><td>5</td><td>最大登录失败次数</td></tr>
|
|
|
|
|
+ <tr><td>lockout_duration</td><td>900</td><td>锁定时长(秒)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[ssl] HTTPS 配置(v2 — C++ 应用自管理)</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>enabled</td><td>1</td><td>HTTPS 开关。v2 方案下必须设为 1(C++ 应用直接处理 TLS)</td></tr>
|
|
|
|
|
+ <tr><td>cert_path</td><td>ssl/plate_fullchain.pem</td><td>SSL 证书路径(相对于安装目录)</td></tr>
|
|
|
|
|
+ <tr><td>key_path</td><td>ssl/plate_privkey.pem</td><td>SSL 私钥路径(相对于安装目录)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+<div class="note">v2 方案变更:nginx stream 只做 TCP 分流,不解密 TLS。SSL 证书由 C++ 应用自己管理,<code>enabled</code> 必须为 1。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[sync] 车牌称重并行同步配置(v43 新增)</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>enabled</td><td>0</td><td>并行同步开关。<code>0</code>=串行v41模式(重量在照片上传成功后入队);<code>1</code>=并行v43模式(tb_num确定后立即并行触发重量读取+上传)</td></tr>
|
|
|
|
|
+ <tr><td>reporter_timeout_sec</td><td>30</td><td>重量上报API超时(秒),最小5</td></tr>
|
|
|
|
|
+ <tr><td>weight_retry_max</td><td>5</td><td>重量上传最大重试次数,最小0</td></tr>
|
|
|
|
|
+ <tr><td>weight_retry_interval_sec</td><td>10</td><td>重量上传重试间隔(秒),最小1</td></tr>
|
|
|
|
|
+ <tr><td>tb_num_dedup_sec</td><td>300</td><td>同联单编号去重窗口(秒),最小10。同一 tb_num 在此时间内只触发一次重量读取</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+<div class="tip"><b>v43 核心变更</b>:并行模式下,车牌识别成功并获取到 tb_num 后,照片上传和重量读取<strong>同时进行</strong>,互不阻塞。重量上报延迟从 v41 的 25~50s 降至 ≤5s,捕获率从 72% 提升至 ≥98%。</div>
|
|
|
|
|
+<div class="warn"><b>灰度策略</b>:首次部署建议保持 <code>enabled=0</code>(完全兼容v41行为),验证系统稳定后再改为 <code>enabled=1</code> 开启并行模式。修改 enabled 无需重启,秒级生效。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[system] 系统监控配置(v38 内存缓冲)</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>monitor_interval</td><td>2</td><td>监控采集间隔(秒),delta 法计算 CPU 使用率</td></tr>
|
|
|
|
|
+ <tr><td>temp_alert_threshold</td><td>70</td><td>温度告警阈值(°C)</td></tr>
|
|
|
|
|
+ <tr><td>cpu_alert_threshold</td><td>90</td><td>CPU 告警阈值(%)</td></tr>
|
|
|
|
|
+ <tr><td>db_path</td><td>data/system_metrics.db</td><td>监控数据库路径</td></tr>
|
|
|
|
|
+ <tr><td>history_retention_days</td><td>7</td><td>原始数据保留天数</td></tr>
|
|
|
|
|
+ <tr><td>aggregation_retention_days</td><td>365</td><td>聚合数据保留天数</td></tr>
|
|
|
|
|
+ <tr><td>flush_time</td><td>23:20</td><td>每日定时刷盘时间(HH:MM)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[frpc] 内网穿透配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>config_path</td><td>-</td><td>frpc.toml 配置文件路径</td></tr>
|
|
|
|
|
+ <tr><td>protected_tunnels</td><td>-</td><td>受保护隧道名称(逗号分隔)</td></tr>
|
|
|
|
|
+ <tr><td>auto_rollback</td><td>1</td><td>重启失败自动回滚(0/1)</td></tr>
|
|
|
|
|
+ <tr><td>admin_addr</td><td>127.0.0.1</td><td>frpc Admin API 地址</td></tr>
|
|
|
|
|
+ <tr><td>admin_port</td><td>7400</td><td>frpc Admin API 端口</td></tr>
|
|
|
|
|
+ <tr><td>admin_user</td><td>-</td><td>frpc Admin 用户名</td></tr>
|
|
|
|
|
+ <tr><td>admin_password</td><td>-</td><td>frpc Admin 密码</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[log] 日志配置(v36 内存缓冲)</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>enabled</td><td>1</td><td>内存缓冲模式(1=内存缓冲,0=直写文件)</td></tr>
|
|
|
|
|
+ <tr><td>log_file</td><td>PlateRecApp.log</td><td>日志文件路径</td></tr>
|
|
|
|
|
+ <tr><td>buffer_size_mb</td><td>20</td><td>内存缓冲区上限(MB)</td></tr>
|
|
|
|
|
+ <tr><td>flush_time</td><td>23:20</td><td>每日定时刷盘时间(HH:MM)</td></tr>
|
|
|
|
|
+ <tr><td>retention_days</td><td>30</td><td>日志文件保留天数</td></tr>
|
|
|
|
|
+ <tr><td>redirect_stdout</td><td>1</td><td>捕获 stdout/stderr(0/1)</td></tr>
|
|
|
|
|
+ <tr><td>auto_flush_on_exit</td><td>1</td><td>退出时立即刷盘(0/1)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[feishu] 飞书通知配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>APP_ID</td><td>飞书应用 App ID</td></tr>
|
|
|
|
|
+ <tr><td>APP_SECRET</td><td>飞书应用 App Secret</td></tr>
|
|
|
|
|
+ <tr><td>CHAT_ID</td><td>飞书群聊 ID</td></tr>
|
|
|
|
|
+ <tr><td>TIMEOUT_SECOND</td><td>请求超时时间(秒)</td></tr>
|
|
|
|
|
+ <tr><td>WarningSigns</td><td>抑制紧急报警(1=抑制,0=正常)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[weight] 称重系统配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>flagWeight</td><td>0</td><td>称重系统开关(0/1)</td></tr>
|
|
|
|
|
+ <tr><td>weight_server_ip</td><td>-</td><td>称重服务器 IP</td></tr>
|
|
|
|
|
+ <tr><td>weight_server_port</td><td>-</td><td>称重服务器端口</td></tr>
|
|
|
|
|
+ <tr><td>weight_threshold_in</td><td>0</td><td>进场称重阈值(吨)</td></tr>
|
|
|
|
|
+ <tr><td>weight_threshold_out</td><td>0</td><td>出场称重阈值(吨)</td></tr>
|
|
|
|
|
+ <tr><td>default_entry_weight</td><td>0</td><td>默认进场重量</td></tr>
|
|
|
|
|
+ <tr><td>default_exit_weight</td><td>0</td><td>默认出场重量</td></tr>
|
|
|
|
|
+ <tr><td>weight_detection_time</td><td>5000</td><td>称重检测时间(毫秒)</td></tr>
|
|
|
|
|
+ <tr><td>tcp_connect_timeout</td><td>3000</td><td>TCP 连接超时(毫秒)</td></tr>
|
|
|
|
|
+ <tr><td>MAX_WEIGHT</td><td>100</td><td>最大称重值(吨)</td></tr>
|
|
|
|
|
+ <tr><td>STABLE_SAMPLE_COUNT</td><td>5</td><td>稳定采样次数</td></tr>
|
|
|
|
|
+ <tr><td>STABLE_THRESHOLD_KG</td><td>50</td><td>稳定判定阈值(公斤)</td></tr>
|
|
|
|
|
+ <tr><td>CANDIDATE_DATA_COUNT</td><td>3</td><td>候选数据次数</td></tr>
|
|
|
|
|
+ <tr><td>MAX_UPLOAD_RETRIES</td><td>3</td><td>上传最大重试次数</td></tr>
|
|
|
|
|
+ <tr><td>RETRY_DELAY_MS</td><td>1000</td><td>重试延迟(毫秒)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>[terminal] 终端/SSH 配置</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>ttyd_port</td><td>7681</td><td>ttyd Web 终端端口</td></tr>
|
|
|
|
|
+ <tr><td>ttyd_credential</td><td>-</td><td>ttyd 登录凭据(user:password)</td></tr>
|
|
|
|
|
+ <tr><td>ttyd_max_clients</td><td>5</td><td>ttyd 最大客户端数</td></tr>
|
|
|
|
|
+ <tr><td>ssh_keys_path</td><td>-</td><td>SSH 公钥存储路径</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 4. RTSP 摄像头配置 -->
|
|
|
|
|
+<div class="card" id="sec4">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">4. RTSP 摄像头配置 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>摄像头地址格式</h3>
|
|
|
|
|
+<p>标准 RTSP 地址格式:</p>
|
|
|
|
|
+<pre>rtsp://用户名:密码@摄像头IP:554/stream</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h3>四路摄像头说明</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>方向</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_front_in</td><td>前→进</td><td>前方摄像头,捕捉进场车辆</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_front_out</td><td>前→出</td><td>前方摄像头,捕捉出场车辆</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_side_in</td><td>侧→进</td><td>侧面摄像头,捕捉进场车辆</td></tr>
|
|
|
|
|
+ <tr><td>rtsp_url_side_out</td><td>侧→出</td><td>侧面摄像头,捕捉出场车辆</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>硬件解码(树莓派5推荐配置)</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>模式</th><th>值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>自动</td><td>auto</td><td>优先硬件解码,不可用则回退软件</td></tr>
|
|
|
|
|
+ <tr><td>软件解码</td><td>soft</td><td>CPU 解码,兼容性最好</td></tr>
|
|
|
|
|
+ <tr><td>DRM 硬件</td><td>drm</td><td>DRM 硬件加速(树莓派5推荐)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+<div class="tip">树莓派 5 推荐:<code>hw_decode_mode=drm</code>,<code>hw_decode_device=/dev/dri/renderD128</code>,<code>rtsp_transport=tcp</code></div>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 5. 车牌识别上传流程 -->
|
|
|
|
|
+<div class="card" id="sec5">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">5. 车牌识别上传完整流程 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>识别流程</h3>
|
|
|
|
|
+<ol>
|
|
|
|
|
+ <li><strong>摄像头抓拍</strong>:RTSP 视频流实时解码,检测到车辆运动时触发抓拍</li>
|
|
|
|
|
+ <li><strong>车牌识别</strong>:HyperLPR3 引擎识别车牌号,返回车牌文本 + 置信度</li>
|
|
|
|
|
+ <li><strong>置信度过滤</strong>:低于 <code>PLATE_CONFIDENCE_THRESHOLD</code> 则丢弃</li>
|
|
|
|
|
+ <li><strong>时间窗口去重</strong>:同一车牌在 <code>TIME_WINDOW</code> 分钟内不重复上传</li>
|
|
|
|
|
+ <li><strong>交替锁定检查</strong>:同一车牌进出间隔低于 <code>in_out_interval</code> 分钟则锁定</li>
|
|
|
|
|
+ <li><strong>ROI 过滤</strong>:如启用 ROI,只识别指定区域内的车牌</li>
|
|
|
|
|
+ <li><strong>数据上传</strong>:HTTP POST 将识别结果 + 照片上传至 <code>app_api</code></li>
|
|
|
|
|
+ <li><strong>MQTT 推送</strong>:如启用 MQTT,同步推送识别结果</li>
|
|
|
|
|
+ <li><strong>飞书通知</strong>:异常报警发送飞书群消息</li>
|
|
|
|
|
+</ol>
|
|
|
|
|
+
|
|
|
|
|
+<h3>照片存储与自动清理</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>照片保存在 <code>PlateJPG/</code> 目录下,文件名格式:<code>车牌号_时间戳_方向.jpg</code>(如 <code>沪FQ7108_1787365677_side_out.jpg</code>)</li>
|
|
|
|
|
+ <li>系统每日凌晨 <strong>2:00</strong> 自动执行照片清理任务(间隔 24 小时)</li>
|
|
|
|
|
+ <li>清理策略:当 <code>PlateJPG/</code> 目录下所有 .jpg 文件总大小超过 <code>PhotoMaxCapacityMB</code>(默认 1024MB)时,按文件修改时间从旧到新逐个删除,直到总大小降至阈值以下</li>
|
|
|
|
|
+ <li>删除照片后递归清理空子目录</li>
|
|
|
|
|
+ <li>清理日志输出示例:
|
|
|
|
|
+<pre>[照片清理] PlateJPG/ 当前 1156 MB / 1024 MB 阈值,共 8234 个文件
|
|
|
|
|
+[照片清理] 删除 1523 张照片(按时间从旧到新),释放 156 MB,当前 1000 MB
|
|
|
|
|
+[照片清理] 同步清空DB路径字段: 2847 个字段已更新</pre>
|
|
|
|
|
+ </li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h4>照片清理与数据库同步(v41 修复)</h4>
|
|
|
|
|
+<p>照片被物理删除后,系统同步清空 <code>upload_records</code> 表中对应的 <code>lo_photo_path</code> / <code>hi_photo_path</code> 字段(设为 NULL):</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>业务记录(车牌号、联单编号、抓拍时间、上传状态等)<strong>完整保留</strong>,仅清空路径字段</li>
|
|
|
|
|
+ <li>Web 前端路径为 NULL 时显示灰色斜体「已清理」占位,不再显示 broken image</li>
|
|
|
|
|
+ <li>即使 DB 清理与页面加载存在竞态,<code><img onerror></code> 也会自动替换为「已清理」</li>
|
|
|
|
|
+ <li>程序启动时自动执行一次孤儿路径扫描(<code>db_purge_missing_photo_paths</code>),修复历史遗留数据</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+<div class="tip">💡 调整容量阈值:修改 <code>config.ini</code> 中 <code>PhotoMaxCapacityMB</code> 的值并重启服务。例如设为 2048 表示允许 2GB 照片存储。</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 6. MQTT -->
|
|
|
|
|
+<div class="card" id="sec6">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">6. MQTT 数据上报配置 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>启用条件</h3>
|
|
|
|
|
+<p>在 <code>[mqtt]</code> 段中填写 <code>MQTT_HOST</code> 即自动启用 MQTT 推送。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>配置示例</h3>
|
|
|
|
|
+<pre>[mqtt]
|
|
|
|
|
+MQTT_HOST=mqtt.example.com
|
|
|
|
|
+MQTT_PORT=1883
|
|
|
|
|
+MQTT_USER=username
|
|
|
|
|
+MQTT_PASS=password
|
|
|
|
|
+MQTT_TOPIC=plate/recognition
|
|
|
|
|
+MQTT_CLIENT_ID=plate_rec_station_01</pre>
|
|
|
|
|
+<div class="warn">MQTT 连接失败时系统会自动重连,不影响识别和上传功能。</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 7. 称重系统 -->
|
|
|
|
|
+<div class="card" id="sec7">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">7. 称重系统对接 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>工作原理</h3>
|
|
|
|
|
+<p>称重系统通过 TCP 协议与称重地磅通信,车牌识别成功后自动读取称重数据并关联上传。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>重量判定逻辑</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>连续 <code>STABLE_SAMPLE_COUNT</code> 次读数变化 < <code>STABLE_THRESHOLD_KG</code> 公斤,视为稳定</li>
|
|
|
|
|
+ <li>稳定后取 <code>CANDIDATE_DATA_COUNT</code> 次读数的中值作为最终重量</li>
|
|
|
|
|
+ <li>重量超过 <code>MAX_WEIGHT</code> 吨视为异常,丢弃</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>阈值说明</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><code>weight_threshold_in</code>:进场最低重量(吨),低于此值可能表示空车</li>
|
|
|
|
|
+ <li><code>weight_threshold_out</code>:出场最低重量(吨)</li>
|
|
|
|
|
+ <li><code>default_entry_weight</code>:无法获取称重数据时的默认进场重量</li>
|
|
|
|
|
+ <li><code>default_exit_weight</code>:无法获取称重数据时的默认出场重量</li>
|
|
|
|
|
+ <li><code>weight_detection_time</code>:称重检测时间(毫秒,默认 5000)</li>
|
|
|
|
|
+ <li><code>tcp_connect_timeout</code>:TCP 连接超时(毫秒,默认 3000)</li>
|
|
|
|
|
+ <li><code>MAX_UPLOAD_RETRIES</code>:上传最大重试次数(默认 3)</li>
|
|
|
|
|
+ <li><code>RETRY_DELAY_MS</code>:重试延迟(毫秒,默认 1000)</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 8. ROI -->
|
|
|
|
|
+<div class="card" id="sec8">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">8. ROI 区域识别配置 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>配置方式</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><strong>Web 可视化</strong>:首页连接状态面板中拖拽设置 ROI 区域</li>
|
|
|
|
|
+ <li><strong>手动配置</strong>:在 config.ini 的 <code>[config]</code> 段填写坐标值</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+<h3>参数说明</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>roi_in_x/y/w/h</td><td>进场 ROI 区域坐标和尺寸(像素)</td></tr>
|
|
|
|
|
+ <tr><td>roi_in_enabled</td><td>1=启用进场 ROI</td></tr>
|
|
|
|
|
+ <tr><td>roi_out_x/y/w/h</td><td>出场 ROI 区域坐标和尺寸</td></tr>
|
|
|
|
|
+ <tr><td>roi_out_enabled</td><td>1=启用出场 ROI</td></tr>
|
|
|
|
|
+ <tr><td>roi_debug_enabled</td><td>1=在抓拍图上绘制 ROI 框(调试用)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 9. 交替锁定 -->
|
|
|
|
|
+<div class="card" id="sec9">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">9. 交替锁定机制 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>机制说明</h3>
|
|
|
|
|
+<p>防止同一车牌短时间内进出频繁触发(如车辆在门口调头)。同一车牌从"进"切换到"出"必须间隔 <code>in_out_interval</code> 分钟以上。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>工作流程</h3>
|
|
|
|
|
+<ol>
|
|
|
|
|
+ <li>车牌 A 被识别为"进"方向</li>
|
|
|
|
|
+ <li>5 分钟内(默认)车牌 A 再次被识别为"出"方向</li>
|
|
|
|
|
+ <li>系统判定为异常,创建交替锁定记录</li>
|
|
|
|
|
+ <li>锁定期间该车牌不会被上传</li>
|
|
|
|
|
+ <li>超过 2 小时锁定自动清零,或手动在"锁定管理"页面清除</li>
|
|
|
|
|
+</ol>
|
|
|
|
|
+
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>in_out_interval</td><td>5</td><td>交替锁定间隔(⚠️ 单位分钟),小于此间隔的进/出切换会被锁定</td></tr>
|
|
|
|
|
+ <tr><td>AlternatingMerge</td><td>0</td><td>交替合并开关</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+<div class="warn"><code>in_out_interval</code> 单位是<strong>分钟</strong>,不是秒!填 5 表示 5 分钟 = 300 秒。</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 10. 认证与权限 -->
|
|
|
|
|
+<div class="card" id="sec10">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">10. 登录认证与权限 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>角色定义</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>角色</th><th>Role值</th><th>可访问页面</th></tr>
|
|
|
|
|
+ <tr><td>普通用户</td><td>0</td><td>首页、视频、称重、锁定管理</td></tr>
|
|
|
|
|
+ <tr><td>管理员</td><td>1</td><td>普通用户 + 系统配置</td></tr>
|
|
|
|
|
+ <tr><td>超级管理员</td><td>2</td><td>所有页面(含系统监控、frpc管理、SSH密钥、日志、帮助)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>默认账号</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>用户名</th><th>密码</th><th>角色</th></tr>
|
|
|
|
|
+ <tr><td>admin</td><td>zhongjin188A</td><td>超级管理员</td></tr>
|
|
|
|
|
+ <tr><td>zhonjin</td><td>zhonjin</td><td>普通用户</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>安全特性</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>密码 bcrypt 加密存储(cost=12)</li>
|
|
|
|
|
+ <li>连续登录失败锁定账号</li>
|
|
|
|
|
+ <li>CSRF Token 防护</li>
|
|
|
|
|
+ <li>Session 超时自动失效</li>
|
|
|
|
|
+ <li>登录速率限制</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 11. frpc.toml 详解 -->
|
|
|
|
|
+<div class="card" id="sec11">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">11. frpc.toml 内网穿透配置详解 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+
|
|
|
|
|
+<h3>配置文件位置</h3>
|
|
|
|
|
+<p>frpc 配置文件路径由 <code>config.ini</code> 的 <code>[frpc] config_path</code> 指定,通常为安装目录下的 <code>frpc.toml</code>。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>v2 方案 — nginx stream 分流(推荐)</h3>
|
|
|
|
|
+<p>使用 nginx stream + ssl_preread 方案,<strong>只需一个公网端口 40963</strong> 即可同时处理 HTTP 和 HTTPS:</p>
|
|
|
|
|
+<pre># frpc.toml — v2 方案(nginx stream 分流)
|
|
|
|
|
+
|
|
|
|
|
+serverAddr = "discover.zhonjin.com"
|
|
|
|
|
+serverPort = 9443
|
|
|
|
|
+auth.method = "token"
|
|
|
|
|
+auth.token = "你的frps认证Token"
|
|
|
|
|
+transport.tls.enable = true
|
|
|
|
|
+clientID = "ssd_40960"
|
|
|
|
|
+
|
|
|
|
|
+# frpc Admin HTTP API
|
|
|
|
|
+webServer.addr = "127.0.0.1"
|
|
|
|
|
+webServer.port = 7400
|
|
|
|
|
+webServer.user = "admin"
|
|
|
|
|
+webServer.password = "你的管理密码"
|
|
|
|
|
+
|
|
|
|
|
+# 隧道1:主服务(外网40963→本机nginx:40963,stream自动分流HTTP/HTTPS)
|
|
|
|
|
+[[proxies]]
|
|
|
|
|
+name = "plate_web"
|
|
|
|
|
+type = "tcp"
|
|
|
|
|
+localIP = "127.0.0.1"
|
|
|
|
|
+localPort = 40963 # ← 转发到 nginx stream,不是 C++ 的 8080
|
|
|
|
|
+remotePort = 40963
|
|
|
|
|
+
|
|
|
|
|
+# 隧道2:ttyd终端(外网40964→本机nginx:8082→ttyd:7681)
|
|
|
|
|
+[[proxies]]
|
|
|
|
|
+name = "ttyd_web"
|
|
|
|
|
+type = "tcp"
|
|
|
|
|
+localIP = "127.0.0.1"
|
|
|
|
|
+localPort = 8082 # ← nginx HTTPS 反向代理(SSL 终止 + WebSocket)
|
|
|
|
|
+remotePort = 40964</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h3>隧道说明(v2)</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>隧道名</th><th>外网端口</th><th>本机端口</th><th>用途</th></tr>
|
|
|
|
|
+ <tr><td>plate_web</td><td>40963</td><td>nginx stream:40963</td><td>HTTP/HTTPS 合一,stream 自动分流</td></tr>
|
|
|
|
|
+ <tr><td>ttyd_web</td><td>40964</td><td>nginx HTTPS:8082</td><td>Web 终端(nginx SSL→ttyd:7681)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>v2 数据流向</h3>
|
|
|
|
|
+<pre>HTTP 流量: 公网:40963 → frpc → nginx:40963 (stream) → $ssl_preread="" → 127.0.0.1:8081 (nginx HTTP) → 301 重定向到 HTTPS
|
|
|
|
|
+HTTPS 流量: 公网:40963 → frpc → nginx:40963 (stream) → $ssl_preread≠"" → 127.0.0.1:8080 (C++ HTTPS) → 直接处理
|
|
|
|
|
+Web SSH: 公网:40964 → frpc → nginx:8082 (HTTPS反向代理, SSL终止) → 127.0.0.1:7681 (ttyd HTTP)</pre>
|
|
|
|
|
+
|
|
|
|
|
+<div class="tip"><strong>v1→v2 迁移注意:</strong>不再需要 40965 端口。HTTPS 主服务统一使用 <code>https://mqtt.zhonjin.com:40963/</code>。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>参数详解</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>参数</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>serverAddr</td><td>frps 服务器域名或 IP</td></tr>
|
|
|
|
|
+ <tr><td>serverPort</td><td>frps 服务端口(默认 7000,本项目用 9443)</td></tr>
|
|
|
|
|
+ <tr><td>auth.method</td><td>认证方式,固定为 <code>token</code></td></tr>
|
|
|
|
|
+ <tr><td>auth.token</td><td>与 frps 约定的认证 Token</td></tr>
|
|
|
|
|
+ <tr><td>webServer.addr/port</td><td>frpc Admin API 监听地址,PlateRecApp 通过此接口获取隧道状态</td></tr>
|
|
|
|
|
+ <tr><td>webServer.user/password</td><td>Admin API 认证凭据(需与 config.ini [frpc] 段一致)</td></tr>
|
|
|
|
|
+ <tr><td>[[proxies]] name</td><td>隧道唯一名称,PlateRecApp Web 界面按名称识别</td></tr>
|
|
|
|
|
+ <tr><td>[[proxies]] type</td><td>隧道类型,本项目全部使用 <code>tcp</code>(透传 TCP 流)</td></tr>
|
|
|
|
|
+ <tr><td>[[proxies]] localPort</td><td>本机目标端口,frpc 将外网流量转发到此端口</td></tr>
|
|
|
|
|
+ <tr><td>[[proxies]] remotePort</td><td>frps 服务器暴露的外网端口,客户端通过此端口访问</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>隧道保护</h3>
|
|
|
|
|
+<p>在 <code>config.ini [frpc]</code> 段配置受保护隧道,防止 Web 界面误删关键隧道:</p>
|
|
|
|
|
+<pre>protected_tunnels = plate_web,ttyd_web</pre>
|
|
|
|
|
+<div class="warn">受保护的隧道无法通过 Web 管理界面删除。如需删除,必须先修改 config.ini 中的 <code>protected_tunnels</code> 字段。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>frpc 管理命令</h3>
|
|
|
|
|
+<pre># 查看 frpc 状态
|
|
|
|
|
+systemctl status frpc
|
|
|
|
|
+
|
|
|
|
|
+# 重启 frpc
|
|
|
|
|
+sudo systemctl restart frpc
|
|
|
|
|
+
|
|
|
|
|
+# 查看 frpc 日志
|
|
|
|
|
+tail -f /var/log/frpc.log
|
|
|
|
|
+
|
|
|
|
|
+# 通过 Admin API 查看隧道状态
|
|
|
|
|
+curl -u admin:密码 http://127.0.0.1:7400/api/status/tcp</pre>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 12. Nginx 反向代理详解 -->
|
|
|
|
|
+<div class="card" id="sec12">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">12. Nginx stream + ssl_preread 配置详解(v2) <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+
|
|
|
|
|
+<h3>架构说明</h3>
|
|
|
|
|
+<p>v2 方案使用 nginx 的 <code>stream</code> 模块 + <code>ssl_preread</code> 功能,在 <strong>TCP 层面</strong>检测流量类型并自动分流:</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><strong>端口 40963</strong>:nginx stream 监听,检测协议类型(TLS / HTTP)</li>
|
|
|
|
|
+ <li><strong>TLS 流量</strong> → 透传到 C++ HTTPS 服务(127.0.0.1:8080)</li>
|
|
|
|
|
+ <li><strong>HTTP 流量</strong> → nginx HTTP 模块(127.0.0.1:8081)→ 301 重定向到 HTTPS</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+<div class="tip"><strong>关键区别:</strong>stream 模块是 TCP 层代理,不解密 TLS 流量。SSL 证书由 C++ 应用自己管理,nginx 只做协议检测和分流。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>nginx.conf 完整配置</h3>
|
|
|
|
|
+<p>文件路径:<code>/etc/nginx/nginx.conf</code>(替换整个文件)</p>
|
|
|
|
|
+<pre># 加载 stream 动态模块
|
|
|
|
|
+load_module modules/ngx_stream_module.so;
|
|
|
|
|
+
|
|
|
|
|
+events {
|
|
|
|
|
+ worker_connections 1024;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# ============================================================
|
|
|
|
|
+# stream 块 — TCP 层协议分流(在 http 块外面)
|
|
|
|
|
+# ============================================================
|
|
|
|
|
+stream {
|
|
|
|
|
+ # 根据 ssl_preread 检测结果选择后端
|
|
|
|
|
+ # $ssl_preread_protocol 的可能值:
|
|
|
|
|
+ # "" → HTTP 流量(非 TLS)
|
|
|
|
|
+ # "TLSv1.2" → TLS 1.2
|
|
|
|
|
+ # "TLSv1.3" → TLS 1.3
|
|
|
|
|
+ map $ssl_preread_protocol $backend {
|
|
|
|
|
+ "" http_backend; # HTTP → nginx HTTP 8081
|
|
|
|
|
+ default tls_backend; # TLS → C++ HTTPS 8080
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # TLS 后端 — C++ HTTPS 服务
|
|
|
|
|
+ upstream tls_backend {
|
|
|
|
|
+ server 127.0.0.1:8080;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # HTTP 后端 — nginx HTTP 301 重定向
|
|
|
|
|
+ upstream http_backend {
|
|
|
|
|
+ server 127.0.0.1:8081;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # 主服务器 — 监听公网端口
|
|
|
|
|
+ server {
|
|
|
|
|
+ listen 40963;
|
|
|
|
|
+ proxy_pass $backend;
|
|
|
|
|
+ ssl_preread on; # 启用 SSL 预读检测协议
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# ============================================================
|
|
|
|
|
+# http 块 — HTTP → HTTPS 301 重定向
|
|
|
|
|
+# ============================================================
|
|
|
|
|
+http {
|
|
|
|
|
+ sendfile on;
|
|
|
|
|
+ tcp_nopush on;
|
|
|
|
|
+ tcp_nodelay on;
|
|
|
|
|
+ keepalive_timeout 65;
|
|
|
|
|
+
|
|
|
|
|
+ include /etc/nginx/mime.types;
|
|
|
|
|
+ default_type application/octet-stream;
|
|
|
|
|
+
|
|
|
|
|
+ access_log /var/log/nginx/access.log;
|
|
|
|
|
+ error_log /var/log/nginx/error.log;
|
|
|
|
|
+
|
|
|
|
|
+ # HTTP → HTTPS 301 重定向
|
|
|
|
|
+ server {
|
|
|
|
|
+ listen 8081;
|
|
|
|
|
+ server_name _;
|
|
|
|
|
+ return 301 https://$host:40963$request_uri;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # ============================================================
|
|
|
|
|
+ # ttyd Web 终端 HTTPS 反向代理(端口 8082)
|
|
|
|
|
+ # ============================================================
|
|
|
|
|
+ # frpc 隧道:外网 40964 → nginx:8082 → ttyd:7681
|
|
|
|
|
+ # nginx 做 SSL 终止,再通过 HTTP 代理到 ttyd(含 WebSocket 支持)
|
|
|
|
|
+ server {
|
|
|
|
|
+ listen 8082 ssl;
|
|
|
|
|
+ server_name _;
|
|
|
|
|
+
|
|
|
|
|
+ ssl_certificate /etc/nginx/ssl/plate_fullchain.pem;
|
|
|
|
|
+ ssl_certificate_key /etc/nginx/ssl/plate_privkey.pem;
|
|
|
|
|
+ ssl_protocols TLSv1.2 TLSv1.3;
|
|
|
|
|
+ ssl_ciphers HIGH:!aNULL:!MD5:!RC4;
|
|
|
|
|
+ ssl_prefer_server_ciphers on;
|
|
|
|
|
+ ssl_session_cache shared:SSL_Ttyd:5m;
|
|
|
|
|
+ ssl_session_timeout 1h;
|
|
|
|
|
+
|
|
|
|
|
+ location / {
|
|
|
|
|
+ proxy_pass http://127.0.0.1:7681;
|
|
|
|
|
+ proxy_set_header Host $host;
|
|
|
|
|
+ proxy_set_header X-Real-IP $remote_addr;
|
|
|
|
|
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
|
|
|
+ proxy_set_header X-Forwarded-Proto $scheme;
|
|
|
|
|
+
|
|
|
|
|
+ # WebSocket 支持(ttyd 核心通信方式)
|
|
|
|
|
+ proxy_http_version 1.1;
|
|
|
|
|
+ proxy_set_header Upgrade $http_upgrade;
|
|
|
|
|
+ proxy_set_header Connection "upgrade";
|
|
|
|
|
+
|
|
|
|
|
+ # ttyd 长连接超时
|
|
|
|
|
+ proxy_read_timeout 86400s;
|
|
|
|
|
+ proxy_send_timeout 86400s;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h3>核心原理</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>组件</th><th>作用</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>stream 块</td><td>TCP 层代理</td><td>与 http 块平级,不处理 HTTP 协议,只做 TCP 转发</td></tr>
|
|
|
|
|
+ <tr><td>ssl_preread on</td><td>SSL 预读</td><td>在 TLS 握手阶段读取 ClientHello,获取协议版本,不解密</td></tr>
|
|
|
|
|
+ <tr><td>map $ssl_preread_protocol</td><td>协议分流</td><td>空字符串 = HTTP,非空 = TLS</td></tr>
|
|
|
|
|
+ <tr><td>upstream tls_backend</td><td>TLS 后端</td><td>透传到 C++ 应用(8080),C++ 自己处理 TLS 握手</td></tr>
|
|
|
|
|
+ <tr><td>upstream http_backend</td><td>HTTP 后端</td><td>转发到 nginx HTTP 8081,返回 301 重定向</td></tr>
|
|
|
|
|
+ <tr><td>server 8082 ssl</td><td>ttyd HTTPS 代理</td><td>SSL 终止后代理到 ttyd:7681,支持 WebSocket</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>部署步骤</h3>
|
|
|
|
|
+<ol>
|
|
|
|
|
+ <li>安装 stream 模块:<code>sudo apt install -y libnginx-mod-stream</code></li>
|
|
|
|
|
+ <li>验证模块:<code>ls -l /usr/lib/nginx/modules/ngx_stream_module.so</code></li>
|
|
|
|
|
+ <li>备份原配置:<code>sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak</code></li>
|
|
|
|
|
+ <li>替换配置:<code>sudo cp nginx-stream.conf /etc/nginx/nginx.conf</code></li>
|
|
|
|
|
+ <li>删除默认站点(如有):<code>sudo rm -f /etc/nginx/sites-enabled/default</code></li>
|
|
|
|
|
+ <li>验证配置:<code>sudo nginx -t</code></li>
|
|
|
|
|
+ <li>启动 nginx:<code>sudo systemctl enable nginx && sudo systemctl restart nginx</code></li>
|
|
|
|
|
+</ol>
|
|
|
|
|
+
|
|
|
|
|
+<h3>前置条件</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>项目</th><th>要求</th></tr>
|
|
|
|
|
+ <tr><td>nginx 版本</td><td>≥ 1.11.5(支持 stream 模块)</td></tr>
|
|
|
|
|
+ <tr><td>stream 模块</td><td>libnginx-mod-stream(Debian)或 nginx-mod-stream(CentOS)</td></tr>
|
|
|
|
|
+ <tr><td>C++ 应用</td><td>必须启用 HTTPS,监听 127.0.0.1:8080</td></tr>
|
|
|
|
|
+ <tr><td>SSL 证书</td><td>C++ 应用自行管理(config.ini 的 [ssl] 段)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>验证方法</h3>
|
|
|
|
|
+<pre># 检查端口监听
|
|
|
|
|
+ss -tlnp | grep -E '40963|8080|8081'
|
|
|
|
|
+# 预期输出:
|
|
|
|
|
+# LISTEN 0.0.0.0:40963 nginx (stream)
|
|
|
|
|
+# LISTEN 127.0.0.1:8081 nginx (http 301)
|
|
|
|
|
+# LISTEN 0.0.0.0:8080 PlateRecApp (HTTPS)
|
|
|
|
|
+
|
|
|
|
|
+# 测试 HTTP 重定向(应返回 301)
|
|
|
|
|
+curl -I http://localhost:40963/
|
|
|
|
|
+# 预期:HTTP/1.1 301 Moved Permanently
|
|
|
|
|
+# Location: https://localhost:40963/
|
|
|
|
|
+
|
|
|
|
|
+# 测试 HTTPS(应返回 200)
|
|
|
|
|
+curl -kI https://localhost:40963/
|
|
|
|
|
+# 预期:HTTP/1.1 200 OK
|
|
|
|
|
+
|
|
|
|
|
+# 浏览器测试(清除缓存或用无痕模式)
|
|
|
|
|
+# 访问 http://mqtt.zhonjin.com:40963/ → 自动跳转到 https://mqtt.zhonjin.com:40963/</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h3>端口规划总结</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>端口</th><th>服务</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td><strong>40963</strong></td><td>nginx stream</td><td>公网入口,TLS/HTTP 分流</td></tr>
|
|
|
|
|
+ <tr><td>8081</td><td>nginx http</td><td>HTTP 301 重定向(仅内部)</td></tr>
|
|
|
|
|
+ <tr><td>8080</td><td>C++ HTTPS</td><td>PlateRecApp Web 服务(SSL 自管理)</td></tr>
|
|
|
|
|
+ <tr><td><strong>40964</strong></td><td>nginx HTTPS→ttyd</td><td>Web 终端(nginx:8082 SSL终止→ttyd:7681)</td></tr>
|
|
|
|
|
+ <tr><td>8082</td><td>nginx HTTPS 代理</td><td>ttyd Web 终端 HTTPS 反向代理(仅内部)</td></tr>
|
|
|
|
|
+ <tr><td>7400</td><td>frpc Admin</td><td>隧道状态查询(仅 127.0.0.1)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 13. SSL/HTTPS 证书配置 -->
|
|
|
|
|
+<div class="card" id="sec13">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">13. SSL/HTTPS 证书配置(v2 — C++ 应用自管理) <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+
|
|
|
|
|
+<div class="note"><strong>v2 方案变更:</strong>nginx stream 只做 TCP 层协议分流,不解密 TLS 流量。SSL 证书由 C++ 应用(PlateRecApp)自己管理,通过 config.ini 的 <code>[ssl]</code> 段配置。nginx 不再需要 SSL 证书。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>config.ini [ssl] 段配置</h3>
|
|
|
|
|
+<pre>[ssl]
|
|
|
|
|
+enabled=1
|
|
|
|
|
+cert_path=ssl/plate_fullchain.pem
|
|
|
|
|
+key_path=ssl/plate_privkey.pem</pre>
|
|
|
|
|
+<div class="tip">v2 方案下 SSL 证书文件放在安装目录的 <code>ssl/</code> 子目录下(或任意自定义路径),不再需要 <code>/etc/nginx/ssl/</code>。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>方式一:Let's Encrypt 证书 — 阿里云 DNS 验证(推荐)</h3>
|
|
|
|
|
+<p>本项目使用 frpc 内网穿透,<strong>无公网 80 端口</strong>,因此不能使用传统的 HTTP-01 验证。推荐使用 <strong>DNS-01 验证</strong>,通过阿里云 DNS API 自动完成,<strong>不需要任何端口</strong>。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h4>方案对比</h4>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>验证方式</th><th>端口要求</th><th>通配符</th><th>自动续期</th><th>本项目适用</th></tr>
|
|
|
|
|
+ <tr><td>HTTP-01 (standalone)</td><td>公网 80</td><td>❌</td><td>✅</td><td>❌ 80 端口不可用</td></tr>
|
|
|
|
|
+ <tr><td>TLS-ALPN-01</td><td>公网 443</td><td>❌</td><td>✅</td><td>❌ 443 端口不可用</td></tr>
|
|
|
|
|
+ <tr><td><strong>DNS-01 (dns-aliyun)</strong></td><td><strong>无</strong></td><td><strong>✅</strong></td><td><strong>✅</strong></td><td><strong>✅ 推荐</strong></td></tr>
|
|
|
|
|
+ <tr><td>手动 DNS</td><td>无</td><td>✅</td><td>❌ 手动</td><td>⚠️ 每 90 天手动操作</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h4>一键部署</h4>
|
|
|
|
|
+<pre># 1. 安装 certbot + 阿里云 DNS 插件
|
|
|
|
|
+sudo apt update
|
|
|
|
|
+sudo apt install -y certbot python3-pip
|
|
|
|
|
+sudo pip3 install certbot-dns-aliyun
|
|
|
|
|
+
|
|
|
|
|
+# 2. 配置阿里云 AccessKey(RAM 子账号,需 AliyunDNSFullAccess 权限)
|
|
|
|
|
+sudo mkdir -p /etc/letsencrypt
|
|
|
|
|
+sudo vim /etc/letsencrypt/aliyun.ini
|
|
|
|
|
+# 内容:
|
|
|
|
|
+# dns_aliyun_access_key = 你的AccessKeyID
|
|
|
|
|
+# dns_aliyun_access_key_secret = 你的AccessKeySecret
|
|
|
|
|
+sudo chmod 600 /etc/letsencrypt/aliyun.ini
|
|
|
|
|
+
|
|
|
|
|
+# 3. 一键申请通配符证书(自动通过 DNS API 验证)
|
|
|
|
|
+sudo certbot certonly \
|
|
|
|
|
+ --authenticator dns-aliyun \
|
|
|
|
|
+ --dns-aliyun-credentials /etc/letsencrypt/aliyun.ini \
|
|
|
|
|
+ --dns-aliyun-propagation-seconds 30 \
|
|
|
|
|
+ --server https://acme-v02.api.letsencrypt.org/directory \
|
|
|
|
|
+ --agree-tos --no-eff-email \
|
|
|
|
|
+ --email admin@zhonjin.com \
|
|
|
|
|
+ -d mqtt.zhonjin.com \
|
|
|
|
|
+ -d "*.zhonjin.com"
|
|
|
|
|
+
|
|
|
|
|
+# 4. 部署证书到 PlateRecApp
|
|
|
|
|
+mkdir -p ssl/
|
|
|
|
|
+sudo cp /etc/letsencrypt/live/mqtt.zhonjin.com/fullchain.pem ssl/plate_fullchain.pem
|
|
|
|
|
+sudo cp /etc/letsencrypt/live/mqtt.zhonjin.com/privkey.pem ssl/plate_privkey.pem
|
|
|
|
|
+sudo chown stevenroc:stevenroc ssl/*.pem
|
|
|
|
|
+chmod 644 ssl/plate_fullchain.pem
|
|
|
|
|
+chmod 600 ssl/plate_privkey.pem
|
|
|
|
|
+
|
|
|
|
|
+# 5. 配置自动续期(每天 3:00 检查,续期后自动部署)
|
|
|
|
|
+(crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet --deploy-hook /opt/openAI/project/003.PlateRecAPP/scripts/renew_ssl.sh") | crontab -
|
|
|
|
|
+
|
|
|
|
|
+# 6. 重启 PlateRecApp
|
|
|
|
|
+sudo systemctl restart PlateRecApp</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h4>续期部署脚本 renew_ssl.sh</h4>
|
|
|
|
|
+<pre>#!/bin/bash
|
|
|
|
|
+# /opt/openAI/project/003.PlateRecAPP/scripts/renew_ssl.sh
|
|
|
|
|
+DOMAIN="mqtt.zhonjin.com"
|
|
|
|
|
+SSL_DIR="/opt/openAI/project/003.PlateRecAPP/ssl"
|
|
|
|
|
+
|
|
|
|
|
+cp /etc/letsencrypt/live/${DOMAIN}/fullchain.pem ${SSL_DIR}/plate_fullchain.pem
|
|
|
|
|
+cp /etc/letsencrypt/live/${DOMAIN}/privkey.pem ${SSL_DIR}/plate_privkey.pem
|
|
|
|
|
+chown stevenroc:stevenroc ${SSL_DIR}/*.pem
|
|
|
|
|
+chmod 644 ${SSL_DIR}/plate_fullchain.pem
|
|
|
|
|
+chmod 600 ${SSL_DIR}/plate_privkey.pem
|
|
|
|
|
+systemctl restart PlateRecApp
|
|
|
|
|
+echo "$(date) SSL 证书续期部署成功" >> /opt/openAI/project/003.PlateRecAPP/ssl_renew.log</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h4>阿里云 RAM 权限配置</h4>
|
|
|
|
|
+<ol>
|
|
|
|
|
+ <li>登录 <a href="https://ram.console.aliyun.com/" target="_blank">RAM 控制台</a> → 用户 → 创建用户</li>
|
|
|
|
|
+ <li>勾选 <strong>OpenAPI 调用访问</strong>,保存 AccessKey ID 和 Secret</li>
|
|
|
|
|
+ <li>添加权限:<code>AliyunDNSFullAccess</code>(云解析 DNS 管理)</li>
|
|
|
|
|
+</ol>
|
|
|
|
|
+<div class="tip">DNS 验证原理:certbot 通过阿里云 API 自动添加 <code>_acme-challenge.mqtt.zhonjin.com</code> TXT 记录,Let's Encrypt CA 查询 DNS 验证域名所有权,全程无需开放任何端口。</div>
|
|
|
|
|
+<div class="warn"><strong>前提:</strong>域名 mqtt.zhonjin.com 的 DNS 解析必须使用阿里云(<code>dns9.hichina.com</code>)。如果 DNS 在其他服务商,需先迁移到阿里云,或改用对应插件(如 <code>certbot-dns-cloudflare</code>、<code>certbot-dns-dnspod</code>)。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>方式二:自签名证书</h3>
|
|
|
|
|
+<p>无公网域名时使用自签名证书,浏览器会显示警告但加密通信正常:</p>
|
|
|
|
|
+<pre># 创建证书目录
|
|
|
|
|
+mkdir -p ssl/
|
|
|
|
|
+
|
|
|
|
|
+# 生成自签名证书(10年有效期)
|
|
|
|
|
+openssl req -x509 -newkey rsa:2048 -nodes \
|
|
|
|
|
+ -keyout ssl/plate_privkey.pem \
|
|
|
|
|
+ -out ssl/plate_fullchain.pem \
|
|
|
|
|
+ -days 3650 \
|
|
|
|
|
+ -subj "/CN=mqtt.zhonjin.com/O=PlateRecApp/C=CN"
|
|
|
|
|
+
|
|
|
|
|
+# 设置权限
|
|
|
|
|
+chmod 600 ssl/plate_privkey.pem
|
|
|
|
|
+chmod 644 ssl/plate_fullchain.pem
|
|
|
|
|
+
|
|
|
|
|
+# 重启 PlateRecApp 加载证书
|
|
|
|
|
+sudo systemctl restart PlateRecApp</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h3>证书文件说明</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>文件</th><th>用途</th><th>config.ini 参数</th></tr>
|
|
|
|
|
+ <tr><td>plate_fullchain.pem</td><td>完整证书链(含中间 CA)</td><td>cert_path</td></tr>
|
|
|
|
|
+ <tr><td>plate_privkey.pem</td><td>私钥文件(严禁泄露)</td><td>key_path</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>v1→v2 迁移说明</h3>
|
|
|
|
|
+<div class="warn"><strong>v1 方案:</strong>SSL 证书由 nginx 管理(<code>/etc/nginx/ssl/</code>),nginx 做 HTTPS 终止后转发 HTTP 到 C++。<br>
|
|
|
|
|
+<strong>v2 方案:</strong>SSL 证书由 C++ 应用管理,nginx stream 只做 TCP 分流,不解密 TLS。不再需要 <code>/etc/nginx/ssl/</code> 目录。</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 14. 系统监控与日志 -->
|
|
|
|
|
+<div class="card" id="sec14">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">14. 系统监控与日志 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>系统监控(实时)</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>CPU 使用率(delta 法计算,含每核使用率、负载均值)</li>
|
|
|
|
|
+ <li>内存使用率(总量/已用/可用)</li>
|
|
|
|
|
+ <li>磁盘使用率(根分区容量/已用/可用)</li>
|
|
|
|
|
+ <li>CPU 温度监控,超阈值告警(阈值由 <code>temp_alert_threshold</code> 配置)</li>
|
|
|
|
|
+ <li>CPU 使用率告警(阈值由 <code>cpu_alert_threshold</code> 配置)</li>
|
|
|
|
|
+ <li>PlateRecApp 进程资源占用(RSS 内存、CPU 占用)</li>
|
|
|
|
|
+ <li>frpc 运行状态、MQTT 连接状态、称重系统连接状态</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+<p>数据来源:通过读取 <code>/proc</code>、<code>/sys</code>、<code>statvfs</code> 等系统接口实时采集,页面每 2 秒自动刷新。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>历史监控数据(v37+)</h3>
|
|
|
|
|
+<p>系统自动采集并存储监控数据到 SQLite 数据库(<code>data/system_metrics.db</code>),支持历史趋势查询:</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><strong>采集间隔</strong>:<code>monitor_interval</code>(默认 2 秒),delta 法计算 CPU 使用率,不阻塞采集线程</li>
|
|
|
|
|
+ <li><strong>定时刷盘</strong>:每日 <code>flush_time</code>(默认 23:20)将内存监控数据批量写入 <code>system_metrics.db</code>,减少 SD 卡写入次数(v38 起)</li>
|
|
|
|
|
+ <li><strong>三级存储</strong>:原始数据(2秒间隔)→ 小时聚合 → 日聚合,自动降采样</li>
|
|
|
|
|
+ <li><strong>自动清理</strong>:原始数据保留 <code>history_retention_days</code> 天(默认 7 天),聚合数据保留 <code>aggregation_retention_days</code> 天(默认 365 天)</li>
|
|
|
|
|
+ <li><strong>历史查询 API</strong>:<code>/api/monitor/history?range=1h|6h|24h|7d|30d</code>,自动选择合适的数据粒度</li>
|
|
|
|
|
+ <li><strong>统计接口</strong>:<code>/api/monitor/stats</code> 返回数据库记录数和运行状态</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>SD 卡写入保护策略(v38)</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><strong>系统监控</strong>:内存缓冲,每日 23:20 一次写入,SD 卡写入从 2880 次/天降至 1 次</li>
|
|
|
|
|
+ <li><strong>运行日志</strong>:内存环形缓冲区,Web 日志页面零磁盘 I/O,每日 23:20 写入 <code>PlateRecApp_YYYYMMDD.log</code></li>
|
|
|
|
|
+ <li><strong>旧版日志清理</strong>:内存模式启用时自动跳过旧版 copytruncate,避免无意义读写</li>
|
|
|
|
|
+ <li><strong>退出安全刷盘</strong>:SIGTERM/SIGINT 时立即执行最后一次刷盘</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>日志管理(v36 内存缓冲)</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><strong>内存缓冲模式</strong>(<code>enabled=1</code>,默认):所有日志写入内存环形缓冲区,Web 日志页面直接从内存读取,零磁盘 I/O</li>
|
|
|
|
|
+ <li><strong>直写文件模式</strong>(<code>enabled=0</code>):传统模式,日志直接写入文件</li>
|
|
|
|
|
+ <li><strong>定时刷盘</strong>:每日 <code>flush_time</code>(默认 23:20)自动将内存日志批量写入 <code>PlateRecApp_YYYYMMDD.log</code></li>
|
|
|
|
|
+ <li><strong>退出刷盘</strong>:<code>auto_flush_on_exit=1</code> 时,收到 SIGTERM/SIGINT 信号立即刷盘,防止日志丢失</li>
|
|
|
|
|
+ <li><strong>stdout 捕获</strong>:<code>redirect_stdout=1</code> 时,stdout/stderr 通过 pipe 重定向到内存缓冲区统一收集</li>
|
|
|
|
|
+ <li>Web 界面实时查看日志(支持 Tail 模式),显示内存使用率和缓冲状态</li>
|
|
|
|
|
+ <li>超期日志文件自动清理(由 <code>retention_days</code> 控制),支持手动触发刷盘</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+<div class="note">两个子系统的 <code>flush_time</code> 均配置为 23:20,分别在 <code>[log]</code> 和 <code>[system]</code> 段中设置,可独立调整。</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 15. Web管理 -->
|
|
|
|
|
+<div class="card" id="sec15">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">15. Web 管理功能 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>页面</th><th>路径</th><th>权限</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>监控首页</td><td>/</td><td>所有用户</td><td>实时监控、识别记录、连接状态、ROI设置</td></tr>
|
|
|
|
|
+ <tr><td>视频预览</td><td>/video</td><td>所有用户</td><td>实时视频流</td></tr>
|
|
|
|
|
+ <tr><td>称重记录</td><td>/weight</td><td>所有用户</td><td>称重数据</td></tr>
|
|
|
|
|
+ <tr><td>锁定管理</td><td>/locks</td><td>所有用户</td><td>交替锁定记录</td></tr>
|
|
|
|
|
+ <tr><td>帮助手册</td><td>/help</td><td>超级管理员</td><td>本文档</td></tr>
|
|
|
|
|
+ <tr><td>系统配置</td><td>/config</td><td>管理员+</td><td>config.ini 在线编辑</td></tr>
|
|
|
|
|
+ <tr><td>系统监控</td><td>/system</td><td>超级管理员</td><td>CPU/内存/温度/磁盘</td></tr>
|
|
|
|
|
+ <tr><td>frpc 管理</td><td>/frpc</td><td>超级管理员</td><td>内网穿透状态和配置</td></tr>
|
|
|
|
|
+ <tr><td>SSH 密钥</td><td>/ssh-keys</td><td>超级管理员</td><td>SSH 公钥管理</td></tr>
|
|
|
|
|
+ <tr><td>日志管理</td><td>/logs</td><td>超级管理员</td><td>系统日志查看</td></tr>
|
|
|
|
|
+ <tr><td>登录</td><td>/login</td><td>公开</td><td>用户登录页面</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Tab 分离:实时数据 + 历史查询(v41 新增)</h3>
|
|
|
|
|
+<p>首页和称重页均改为 Tab 分离结构,自动刷新与手动查询完全独立:</p>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>Tab</th><th>数据来源</th><th>刷新方式</th></tr>
|
|
|
|
|
+ <tr><td>📡 实时数据 / 实时称重</td><td>固定最新 20 条,无条件加载</td><td>每 30 秒自动刷新</td></tr>
|
|
|
|
|
+ <tr><td>🔍 历史查询</td><td>按筛选条件查询,支持完整分页</td><td>手动触发,不自动刷新</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+<p>两个 Tab 使用独立的状态和函数,互不干扰。切换 Tab 时自动加载对应数据;重试操作后根据当前 Tab 智能刷新对应数据源。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>分类查询筛选条件(v41)</h3>
|
|
|
|
|
+<p>历史查询 Tab 支持多维度组合筛选(所有条件 AND 组合):</p>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>筛选条件</th><th>首页</th><th>称重页</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>车牌号</td><td>✅</td><td>✅</td><td>模糊匹配,如"沪A"</td></tr>
|
|
|
|
|
+ <tr><td>联单编号</td><td>✅</td><td>✅</td><td>模糊匹配</td></tr>
|
|
|
|
|
+ <tr><td>方向</td><td>✅</td><td>✅</td><td>全部 / 进站 / 出站</td></tr>
|
|
|
|
|
+ <tr><td>上传状态</td><td>✅</td><td>✅</td><td>首页:成功/失败;称重页多一个"待上传"(status=0)</td></tr>
|
|
|
|
|
+ <tr><td>飞书状态</td><td>✅</td><td>—</td><td>全部 / 已发送 / 失败 / 未发送</td></tr>
|
|
|
|
|
+ <tr><td>日期范围</td><td>✅</td><td>✅</td><td>按抓拍时间过滤(YYYY-MM-DD)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>分页控件(v41)</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li><strong>每页条数</strong>:可选 20 / 50 / 100 条</li>
|
|
|
|
|
+ <li><strong>页码导航</strong>:首页 / 上一页 / 页码(当前页前后各 2 页,含首末页和省略号)/ 下一页 / 末页</li>
|
|
|
|
|
+ <li><strong>跳转</strong>:输入页码 + GO 按钮快速跳转</li>
|
|
|
|
|
+ <li><strong>信息栏</strong>:显示"第 X/Y 页 · 共 Z 条"</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 16. 数据库 -->
|
|
|
|
|
+<div class="card" id="sec16">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">16. 数据库与备份 <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+<h3>数据库文件</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>文件</th><th>路径</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>认证数据库</td><td>data/auth.db</td><td>用户账号、密码、Session</td></tr>
|
|
|
|
|
+ <tr><td>识别记录</td><td>data/upload_records.db</td><td>车牌识别上传记录</td></tr>
|
|
|
|
|
+ <tr><td>系统监控</td><td>data/system_metrics.db</td><td>性能监控时序数据(原始+小时聚合+日聚合)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+<div class="tip">v29 版本起,所有数据库统一存放在 <code>data/</code> 目录下。系统首次启动时自动将旧路径数据库迁移到新位置(旧文件保留为备份)。</div>
|
|
|
|
|
+
|
|
|
|
|
+<h3>upload_records 表结构</h3>
|
|
|
|
|
+<table>
|
|
|
|
|
+ <tr><th>字段</th><th>说明</th></tr>
|
|
|
|
|
+ <tr><td>id</td><td>自增主键</td></tr>
|
|
|
|
|
+ <tr><td>create_time</td><td>记录创建时间</td></tr>
|
|
|
|
|
+ <tr><td>capture_time</td><td>抓拍时间(用于时间对齐)</td></tr>
|
|
|
|
|
+ <tr><td>plate_number</td><td>车牌号</td></tr>
|
|
|
|
|
+ <tr><td>tb_num</td><td>联单编号</td></tr>
|
|
|
|
|
+ <tr><td>station_type</td><td>方向:1=进站,2=出站</td></tr>
|
|
|
|
|
+ <tr><td>lo_photo_path / hi_photo_path</td><td>照片文件名(相对 PlateJPG/),清理后为 NULL</td></tr>
|
|
|
|
|
+ <tr><td>lo_upload_status / hi_upload_status</td><td>上传状态:0=待传,1=成功,2=失败</td></tr>
|
|
|
|
|
+ <tr><td>feishu_status</td><td>飞书通知:1=已发送,2=失败,3=未发送</td></tr>
|
|
|
|
|
+ <tr><td>retry_count</td><td>重试次数(上限 5 次)</td></tr>
|
|
|
|
|
+</table>
|
|
|
|
|
+
|
|
|
|
|
+<h3>备份建议</h3>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>定期备份 <code>data/</code> 目录和 <code>config.ini</code></li>
|
|
|
|
|
+ <li>nginx SSL 证书和配置文件备份:<code>/etc/nginx/ssl/</code>、<code>/etc/nginx/conf.d/</code></li>
|
|
|
|
|
+ <li>frpc 配置修改时系统自动备份</li>
|
|
|
|
|
+ <li>照片数据在 <code>PhotoMaxCapacityMB</code> 限制内自动管理,重要照片建议另行备份</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<!-- 17. FAQ -->
|
|
|
|
|
+<div class="card" id="sec17">
|
|
|
|
|
+<div class="card-title" onclick="toggleCard(this)">17. 常见问题 FAQ <span class="arrow">▼</span></div>
|
|
|
|
|
+<div class="card-body">
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: HTTP 访问没有跳转到 HTTPS?</h3>
|
|
|
|
|
+<p>A: 检查以下几点:</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>确认 nginx stream 模块已安装:<code>nginx -V 2>&1 | grep stream</code></li>
|
|
|
|
|
+ <li>确认 nginx 配置正确:<code>sudo nginx -t</code></li>
|
|
|
|
|
+ <li>确认 8081 端口正在监听:<code>ss -tlnp | grep 8081</code></li>
|
|
|
|
|
+ <li>确认 frpc 隧道 <code>plate_web</code> 正常运行(localPort 为 40963)</li>
|
|
|
|
|
+ <li>浏览器可能缓存了旧的重定向,尝试清除缓存或无痕模式</li>
|
|
|
|
|
+ <li>测试本机重定向:<code>curl -I http://localhost:40963/</code>,应返回 301</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: HTTPS 访问返回错误?</h3>
|
|
|
|
|
+<p>A: v2 方案下 TLS 由 C++ 应用处理,检查:</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>PlateRecApp 是否正在运行:<code>systemctl status PlateRecApp</code></li>
|
|
|
|
|
+ <li>PlateRecApp 是否启用了 HTTPS:<code>config.ini [ssl] enabled=1</code></li>
|
|
|
|
|
+ <li>SSL 证书文件是否存在:<code>ls -l ssl/plate_fullchain.pem ssl/plate_privkey.pem</code></li>
|
|
|
|
|
+ <li>nginx stream 是否正常监听:<code>ss -tlnp | grep 40963</code></li>
|
|
|
|
|
+ <li>nginx 错误日志:<code>sudo tail -f /var/log/nginx/error.log</code></li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: <code>unknown directive "stream"</code>?</h3>
|
|
|
|
|
+<p>A: stream 模块未加载。执行:<code>sudo apt install -y libnginx-mod-stream</code>,确认 nginx.conf 顶部有 <code>load_module modules/ngx_stream_module.so;</code></p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: frpc 重启后隧道不生效?</h3>
|
|
|
|
|
+<p>A: 检查 frpc.toml 配置语法:</p>
|
|
|
|
|
+<pre>frpc verify -c /path/to/frpc.toml</pre>
|
|
|
|
|
+<p>常见错误:TOML 格式问题(缺少引号、缩进错误)。通过 Web 管理界面编辑配置时系统会自动校验。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 自签名证书浏览器警告怎么消除?</h3>
|
|
|
|
|
+<p>A: 自签名证书无法消除浏览器警告(这是正常安全行为)。解决方案:</p>
|
|
|
|
|
+<ul>
|
|
|
|
|
+ <li>方式1:使用 Let's Encrypt 免费证书(需域名解析到公网 IP)</li>
|
|
|
|
|
+ <li>方式2:在客户端将自签名 CA 证书添加到受信任的根证书列表</li>
|
|
|
|
|
+ <li>方式3:忽略警告,继续使用(加密通信正常,仅证书不受信任)</li>
|
|
|
|
|
+</ul>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 摄像头连接失败怎么办?</h3>
|
|
|
|
|
+<p>A: 确认 RTSP 地址格式正确,在 VLC 中测试播放。尝试 <code>rtsp_transport=tcp</code>。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: in_out_interval 填 5 是 5 秒还是 5 分钟?</h3>
|
|
|
|
|
+<p>A: <strong>5 分钟</strong>。单位是分钟,系统内部自动 ×60 转为秒。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 照片被自动清理后,Web 页面看到"已清理"怎么办?</h3>
|
|
|
|
|
+<p>A: 这是正常现象。当 <code>PlateJPG/</code> 目录总大小超过 <code>PhotoMaxCapacityMB</code>(默认 1024MB)时,系统每日凌晨 2:00 自动删除最旧的照片释放空间。被删除照片对应的数据库记录仍保留(业务数据不丢失),Web 页面显示灰色「已清理」占位。如需保留更多照片,调大该配置值。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 日志中出现 <code>[路径校验] 转换绝对路径失败</code> 错误?</h3>
|
|
|
|
|
+<p>A: 此错误在旧版本(v41 修复前)出现,原因是照片被物理删除后 DB 路径字段未同步清空,前端仍请求已删除文件。v41 已修复:删除照片时通过 basename 匹配同步清空 DB 路径字段,启动时自动扫描孤儿路径,且 <code>/photo</code> 接口对缺失文件静默返回 404 不再打 ERROR 日志。升级后此错误不再出现。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 如何调整照片存储上限?</h3>
|
|
|
|
|
+<p>A: 修改 <code>config.ini</code> 的 <code>[config]</code> 段中 <code>PhotoMaxCapacityMB</code> 值并重启服务。例如:</p>
|
|
|
|
|
+<pre>[config]
|
|
|
|
|
+PhotoMaxCapacityMB=2048 # 调整为 2GB</pre>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 称重页的"待上传"状态是什么意思?</h3>
|
|
|
|
|
+<p>A: 称重记录上传状态筛选比首页多一个「待上传」选项,对应数据库中 <code>upload_status = 0</code> 的记录,即称重数据尚未成功上传到云端 API,可通过此筛选快速定位需重试的记录。</p>
|
|
|
|
|
+
|
|
|
|
|
+<h3>Q: 如何重置管理员密码?</h3>
|
|
|
|
|
+<pre>cd /opt/openAI/project/003.PlateRecAPP
|
|
|
|
|
+python3 reset_passwords.py</pre>
|
|
|
|
|
+</div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+function toggleCard(el) {
|
|
|
|
|
+ el.classList.toggle('collapsed');
|
|
|
|
|
+ var body = el.nextElementSibling;
|
|
|
|
|
+ body.classList.toggle('hidden');
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+</body>
|
|
|
|
|
+</html>
|