5958c21048
5 项新功能: - H2: 服务器搜索过滤 — 目标服务器下拉加搜索框实时过滤 - H3: 推送对比 Diff 视图 — 预览文件列表加 diff 按钮对比本地与远程差异 - H4: 推送排错面板 — 失败行加诊断按钮检查SSH/磁盘/权限 - H5: 源路径直接输入 — 支持直接输入服务器本地路径推送 - H6: 批量重试 — 一键重试所有失败服务器 新增后端端点: - POST /api/sync/validate-source-path (H5) - POST /api/sync/diagnose (H4) - POST /api/sync/file-diff (H3) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
2026-05-29 推送页面迭代 Round 3 — 设计文档
背景与目标
推送页面 Round 1(WS 进度/分组/历史/文件操作/校验)和 Round 2(同步说明/在线标识/失败重试/Telegram 通知/文件预览)已完成全部 10 项功能。基于实际运维场景,仍有 6 项体验/效率缺陷:
- 推送无法取消 — 推送 50 台发现配错,只能等全部超时,无中止机制
- 推送页无法直接调度 — 想凌晨推送需跳到调度页重新配置源路径/服务器/模式,操作割裂
- 无推送模板/收藏 — 常用推送组合每次手动选,重复劳动
- 推送历史无法筛选 — 历史只有最近 15 条无分页,无法按服务器/状态/日期过滤
- 无浏览器推送完成通知 — 用户离开页面后不知推送结果(Telegram 有但浏览器没有)
- 不支持拖拽上传 ZIP — 文件选择器不够直观
方案对比
G1 推送取消
| 方案 | 优点 | 缺点 |
|---|---|---|
| A: Redis 取消标记 + 引擎轮询 | 简单可靠,无进程间通信 | 最多延迟一个 rsync 周期(5min)才取消 |
| B: asyncio.Task.cancel() | 即时取消 | 多 worker 下无法跨进程取消 |
| C: kill rsync 子进程 | 最直接 | 需跟踪 PID,复杂且风险高 |
选定方案 A — Redis sync:cancel:{batch_id} 键,sync_engine 的 _rsync_push() 每次执行前检查。前端显示"取消推送"按钮,取消后已完成的保留结果,未启动的跳过。简单可靠,无进程间通信问题。
G2 推送页面直接调度
| 方案 | 优点 | 缺点 |
|---|---|---|
| A: 推送按钮旁加"定时推送"按钮 | 复用当前表单配置 | 需新增调度 API 调用 |
| B: 调度选择器嵌入推送页 | 更灵活 | 页面变重 |
选定方案 A — "开始推送"按钮旁增加"⏰ 定时推送"按钮,弹出时间选择器后直接调用 POST /api/schedules/。推送页已有所需全部字段(server_ids, source_path, sync_mode)。
G3 推送模板/收藏
| 方案 | 优点 | 缺点 |
|---|---|---|
| A: 浏览器 localStorage | 无后端改动 | 仅本机可见 |
| B: 后端 PushTemplate 表 | 跨设备共享 | 需 DB 迁移 + API |
选定方案 A — localStorage 存储推送模板。模板包含名称、源路径、目标路径、同步模式、服务器 ID 列表。运维人员通常固定在一台电脑操作,localStorage 足够。若未来需跨设备可迁移到后端。
G4 推送历史筛选
| 方案 | 优点 | 缺点 |
|---|---|---|
| A: 后端分页 + 前端筛选下拉 | 大数据量友好 | 需改 API |
| B: 纯前端筛选 | 无后端改动 | 15 条太少无法筛选 |
选定方案 A — 后端 GET /api/servers/logs 已有 limit 参数,增加 status/server_id/page 参数,前端加筛选控件+分页。
G5 浏览器推送完成通知
| 方案 | 优点 | 缺点 |
|---|---|---|
| A: Notification API | 系统级通知,即使页面在后台也可见 | 需用户授权 |
| B: 页面 title 闪烁 | 无需授权 | 仅标签页可见 |
选定方案 A — Web Notification API。推送开始时请求授权,完成时发浏览器通知。降级:授权拒绝时 title 闪烁。
G6 拖拽上传 ZIP
| 方案 | 优点 | 缺点 |
|---|---|---|
| A: 拖拽区域 + click 回退 | 直观 | 需前端改动 |
选定方案 A — 将文件上传区改为拖拽区 + click 选择,标准 HTML5 拖拽实现。
选定方案及理由
全部选方案 A(最简方案),理由:
- G1: Redis 标记是跨 worker 最可靠的取消方案
- G2: 复用推送表单 + 现有调度 API,零后端新端点
- G3: localStorage 模板无需 DB 迁移,符合运维单人操作场景
- G4: 后端分页是大数据量唯一正确方案
- G5: Notification API 是唯一真正"后台通知"的方案
- G6: 拖拽上传是现代标准 UX
接口/数据模型
G1: 推送取消
- Redis key:
sync:cancel:{batch_id}(SET, TTL=3600s) sync_engine_v2._rsync_push(): 执行前检查 Redis key,存在则返回{exit_code: -1, stderr: "推送已取消"}sync_engine_v2.sync_files(): 每个任务启动前检查取消标记- 前端:
POST /api/sync/cancel—{batch_id: str}→ 写 Redis key + 审计日志 - WS 消息: 取消的服务器 status=
"cancelled"
G2: 推送页面直接调度
- 无新端点,复用
POST /api/schedules/ - 前端: "⏰ 定时推送"按钮 → 弹出
datetime-local选择器 → 调用调度 API
G3: 推送模板
- localStorage key:
nexus_push_templates— JSON 数组 - 模板结构:
{name, source_path, target_path, sync_mode, server_ids[]} - 前端: 模板下拉选择 + 保存/删除按钮
G4: 历史筛选
- 后端
GET /api/servers/logs增加:status: Optional[str],server_id: Optional[int],page: int = 1,per_page: int = 20 - 返回增加:
total,page,pages - 前端: 状态/服务器筛选 + 分页控件
G5: 浏览器通知
- 推送开始时
Notification.requestPermission() - 推送完成时
new Notification("Nexus 推送完成", {body: "X 成功, Y 失败"}) - 降级: 授权拒绝时
document.title闪烁
G6: 拖拽上传
<div>拖拽区域 +dragover/drop事件- 保留原有
<input type="file">作为 click 回退 - 拖拽时高亮边框
安全与性能约束
- G1: 取消端点需 JWT 认证 + 审计日志;Redis key 有 TTL 防止泄漏
- G2: 复用调度 API,已有 JWT 认证 + 审计
- G3: localStorage 无安全风险(不含密码/密钥)
- G4: 分页查询有索引
idx_sync_logs_srv_start - G5: Notification 需用户主动授权,非强制
- G6: 拖拽文件仍走现有 upload-zip 端点校验
验收标准
- G1: 推送进行中 → 点击"取消推送" → 未启动的服务器跳过 → 已完成的保留结果
- G2: 配置推送 → 点击"定时推送" → 选择时间 → 调度页出现对应任务
- G3: 保存模板 → 刷新页面 → 下拉选择模板 → 表单自动填充
- G4: 历史区筛选状态/服务器 → 分页翻页 → 结果正确
- G5: 推送完成 → 浏览器弹出通知(页面在后台也可见)
- G6: 拖拽 ZIP 到上传区 → 文件上传解压成功