远程通知系统
概述
ZJT 系统作为客户端,定期从远程服务器拉取通知信息(版本更新、系统公告等),并在管理后台展示给管理员。
类似 WordPress 检查 wp.org 更新的机制:客户端定期轮询远程 API,获取最新通知并存储到本地数据库。
远程服务器 (官方) ZJT 客户端 (用户部署)
┌─────────────────┐ ┌─────────────────────┐
│ 通知 API │ ←── HTTP ──── │ 通知服务 │
│ (Swagger 文档) │ │ (定时轮询) │
│ │ ──→ JSON ────→ │ │
│ 返回: │ │ - 版本信息 → 内存缓存│
│ - 版本更新 │ │ - 通知 → DB 存储 │
│ - 系统公告 │ │ │
└─────────────────┘ │ admin.html 展示: │
│ - 通知中心 │
│ - 未读角标 │
└─────────────────────┘
远程服务器 API(Swagger 文档)
基础信息
- Base URL:
<官方地址>(可通过config.constant.NotificationConstants.REMOTE_API_BASE配置) - 认证: 无需认证(公开接口)
- 客户端标识: 通过 Header 传递客户端信息
GET /notifications/check
客户端定时调用,获取最新通知和版本更新信息。
请求 Header:
| Header | 类型 | 说明 |
|---|---|---|
X-Client-Version | string | 客户端当前版本号(如 1.5.2) |
X-Client-Env | string | 客户端环境 |
X-Client-ID | string | 客户端唯一标识(单向 hash,不可逆) |
X-Client-ID 说明: 客户端唯一标识由客户端环境信息经单向哈希生成,不可反推出原始信息:不同服务器生成不同 ID,同一服务器不同安装目录生成不同 ID。
响应 200:
{
"code": 0,
"data": {
"version_update": {
"has_update": true,
"current_version": "1.5.2",
"latest_version": "1.6.0",
"release_notes": "1. 修复了xxx问题\n2. 新增xxx功能\n3. 优化xxx性能",
"changelog_url": "https://<官方地址>/releases/tag/v1.6.0"
},
"announcements": [
{
"id": "ann_20260508_001",
"type": "announcement",
"title": "新功能上线:AI 智能分镜",
"content": "我们上线了 AI 智能分镜功能,可以自动将剧本拆分为分镜...",
"level": "info",
"start_time": "2026-05-08T00:00:00Z",
"end_time": "2026-05-15T00:00:00Z",
"link": "https://<官方地址>/feature/storyboard",
"link_text": "了解详情"
},
{
"id": "ann_20260508_002",
"type": "maintenance",
"title": "系统维护通知",
"content": "5月10日凌晨2点-4点进行系统维护,期间服务可能不可用",
"level": "warning",
"start_time": "2026-05-08T00:00:00Z",
"end_time": "2026-05-10T06:00:00Z",
"link": null,
"link_text": null
}
],
"check_interval": 3600
}
}
字段说明:
version_update — 版本更新信息(仅展示,无下载功能):
| 字段 | 类型 | 说明 |
|---|---|---|
has_update | bool | 是否有新版本 |
current_version | string | 客户端当前版本(由客户端上报,服务器回传) |
latest_version | string | 最新版本号 |
release_notes | string | 更新日志(纯文本,支持换行) |
changelog_url | string|null | 完整更新日志链接(可选) |
announcements[] — 系统公告:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 唯一 ID(客户端用于去重) |
type | string | 类型: announcement / maintenance / feature / security |
title | string | 标题 |
content | string | 正文 |
level | string | 级别: info / warning / error / success |
start_time | ISO8601 | 生效时间 |
end_time | ISO8601 | 过期时间(过期后不再返回) |
link | string|null | 外部链接(可选) |
link_text | string|null | 链接文案(可选) |
顶层字段:
| 字段 | 类型 | 说明 |
|---|---|---|
check_interval | int | 建议的下次检查间隔(秒),客户端应尊重此值 |
客户端实现
文件清单
| 文件 | 说明 |
|---|---|
config/constant.py | 通知相关常量定义 |
model/ | 相关数据表模型 |
services/ | 后台拉取服务 |
api/notifications.py | API 路由 |
server.py | 路由注册 + 服务初始化 |
web/admin.html | 前端通知中心页面 |
web/js/admin.js | 前端轮询和交互逻辑 |
web/css/admin.css | 通知样式 |
alembic/versions/ | 数据库迁移 |
数据表
通知信息存储于相关数据表,核心字段包括:远程通知 ID(唯一约束,用于去重)、通知类型、标题、正文、级别、扩展数据(JSON:link、link_text 等)、已读标记、生效/过期时间、创建/更新时间,并对已读状态与创建时间建有索引。
通知服务
后台服务,定时从远程服务器拉取通知:
- 初始化: 服务器启动时调用
initialize(),生成client_id,延迟 5 秒后首次检查 - 定时轮询: 按远程返回的
check_interval(默认 3600 秒)定时检查 - 去重: 通知按
remote_id去重(唯一约束),已存在的不重复插入 - 容错: 远程 API 不可达时静默跳过,不影响本地功能
客户端 API
| 接口 | 方法 | 说明 |
|---|---|---|
/api/notifications/poll | GET | 前端轮询,返回版本更新 + 未读通知 + 未读数量 + 缺失二进制 |
/api/notifications/{id}/read | POST | 标记单条通知为已读 |
/api/notifications/read-all | POST | 标记所有通知为已读 |
/api/notifications/admin/list | GET | 管理员查看通知列表(分页,需管理员权限) |
/api/notifications/admin/{id} | DELETE | 管理员删除通知(需管理员权限) |
Poll API 响应
/api/notifications/poll 返回示例:
{
"code": 0,
"data": {
"version_update": {
"has_update": true,
"current_version": "1.5.0",
"latest_version": "1.6.1",
"release_notes": "1.6.1 版本支持自动更新",
"changelog_url": "https://<官方地址>/releases/tag/1.6.1",
"required_binaries": []
},
"notifications": [
{
"id": 1,
"remote_id": "ann_20260508_001",
"type": "announcement",
"title": "新功能上线:版本自动更新",
"content": "我们上线了版本自动更新功能,可以自动检测并更新到最新版本...",
"level": "info",
"link": "https://<官方地址>/releases/tag/1.6.1",
"link_text": "查看更新",
"is_read": false,
"start_time": "2026-05-08T00:00:00Z",
"end_time": "2026-06-30T00:00:00Z",
"created_at": "2026-05-08T12:00:00"
}
],
"unread_count": 1,
"missing_binaries": [
{
"name": "ffmpeg",
"description": "音视频处理工具",
"download_url": "https://<官方地址>/bin/ffmpeg-6.0-win64.zip",
"check_path": "bin/ffmpeg/ffmpeg.exe"
}
]
}
}
notifications[] — 未读通知列表(从数据库读取):
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 自增 ID |
remote_id | string | 远程通知 ID(去重用) |
type | string | 类型: announcement / maintenance / feature / security |
title | string | 标题 |
content | string | 正文 |
level | string | 级别: info / warning / error / success |
link | string|null | 外部链接 |
link_text | string|null | 链接文案 |
is_read | bool | 是否已读 |
start_time | ISO8601|null | 生效时间 |
end_time | ISO8601|null | 过期时间 |
created_at | string | 创建时间 |
version_update — 版本更新信息(无更新时为 null):
| 字段 | 类型 | 说明 |
|---|---|---|
has_update | bool | 是否有新版本 |
current_version | string | 客户端当前版本 |
latest_version | string | 最新版本号 |
release_notes | string | 更新日志 |
changelog_url | string|null | 完整更新日志链接 |
required_binaries | array | 新版本需要的二进制依赖 |
missing_binaries[] — 本地缺失的二进制依赖:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 工具名称 |
description | string | 工具描述 |
download_url | string | 下载地址(可选) |
check_path | string | 需要放置的相对路径 |
前端展示
管理后台「通知中心」页面:
- 版本升级横幅: 显示新版本号和更新日志(仅信息展示,无下载按钮)
- 缺失二进制依赖提醒: 显示本地缺失的二进制工具,包括下载链接和放置路径
- 通知列表: 按类型和级别展示,支持标记已读 / 全部已读
- 未读角标: 侧边栏菜单显示未读通知数量
- 自动轮询: 每 30 秒轮询一次
/api/notifications/poll
二进制依赖配置
系统通过 config/required_binaries.yml 配置文件定义所需的二进制依赖。
配置文件格式:
binaries:
ffmpeg:
description: "音视频处理工具"
download_url: "https://<官方地址>/bin/ffmpeg-6.0-win64.zip"
check_paths:
windows: "bin/ffmpeg/ffmpeg.exe"
linux: "bin/ffmpeg/ffmpeg"
macos: "bin/ffmpeg/ffmpeg"
required_since: "2.0.0"
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 工具名称(YAML key) |
description | string | 工具描述 |
download_url | string | 下载地址(可选) |
check_paths | object | 按平台的检查路径 |
check_paths.windows | string | Windows 平台相对路径 |
check_paths.linux | string | Linux 平台相对路径 |
check_paths.macos | string | macOS 平台相对路径 |
required_since | string | 从哪个版本开始需要此依赖(语义化版本号) |
检查逻辑:
- 读取
config/required_binaries.yml配置 - 根据当前平台(Windows/Linux/macOS)选择对应的检查路径
- 比较当前版本与
required_since,只检查当前版本需要的依赖 - 检查文件是否存在,缺失的依赖会在通知中心显示