# 审计 — 文件管理服务器搜索 + 监测槽点击修复 **日期**:2026-06-12 **Changelog**: - `docs/changelog/2026-06-11-files-server-search.md`(commit `6140d68`) - `docs/changelog/2026-06-11-watch-slot-click-fix.md`(commit `6b8965a`) ## 范围(文件清单) | 文件 | 变更 | |------|------| | `frontend/src/components/files/FilesToolbar.vue` | v-select → v-autocomplete 可搜索选服 | | `frontend/src/composables/files/useFilesNavigation.ts` | 全量 loadServers、filteredServerList | | `frontend/src/composables/files/useFilesPage.ts` | 暴露搜索状态 | | `frontend/src/components/watch/WatchSlotCard.vue` | 空槽/满槽点击、hover | | `frontend/src/components/watch/WatchSlotPickDialog.vue` | 空槽选机对话框(新增) | | `frontend/src/components/watch/WatchSlotRow.vue` | 串联 pick 与 pinServer | | `frontend/src/components/watch/WatchSparkline.vue` | pointer-events 防挡点击 | | `frontend/src/composables/useWatchPins.ts` | pinServer 支持 slot_index | | `frontend/src/pages/ServersPage.vue` | 已在监测 + 提示 | ## Step 3 规则扫描 | H | 规则 | 结论 | |---|------|------| | H1 | 鉴权 / IDOR | PASS — `/servers/`、`/watch/pins` 均走 JWT;Pin 按 admin 隔离(后端已有) | | H2 | 无静默吞错 | PASS(审计中修复)— WatchSlotPickDialog 加载失败改 snackbar;pin 失败经 formatApiError | | H3 | 无新密钥 | PASS — 纯前端 UI | | H4 | XSS | PASS — 无 v-html;服务器名由 API 返回、Vuetify 文本渲染 | | H5 | 输入边界 | PASS — serverId/slotIndex 为 number;后端 Pydantic ge/le 校验 | | H6 | 性能 | RISK 接受 — 全量拉取 servers(与终端/推送一致);2000+ 台客户端 filter | ## 逐行走读(前端 5 文件) | 文件 | 行数 | Read | 结论 | |------|------|------|------| | WatchSlotPickDialog.vue | 108 | 1–108 | 逐行完成 ✓ | | WatchSlotCard.vue | 138 | 1–138 | 逐行完成 ✓ | | WatchSlotRow.vue | 98 | 1–98 | 逐行完成 ✓ | | useWatchPins.ts(pinServer 段) | 222 | 160–178 | 逐行完成 ✓ | | useFilesNavigation.ts(搜索段) | 244 | 26–47,139–170 | 逐行完成 ✓ | ### Closure | H | 判定 | 依据 | |---|------|------| | H1 | SAFE | fetchPagePerPage/http 带 auth;POST body 仅 server_id + slot_index | | H2 | SAFE | 选机对话框 load 失败 snackbar;onPickServer 409/422 均有 snackbar | | H3 | SAFE | 无 env/密钥 | | H4 | SAFE | 模板无 innerHTML | | H5 | SAFE | slot_index 0–3 后端校验;空 selectedId 禁用「加入」 | | H6 | SAFE(接受) | 与项目内终端/推送全量列表模式一致 | ### 交互验收 | 场景 | 预期 | 审计结论 | |------|------|----------| | 文件页搜索服务器 | 名称/域名/路径/ID 过滤 | PASS(type-check) | | 点击虚线空槽 | 弹出选机 → POST slot_index | PASS(代码路径完整) | | 点击满槽卡片 | 路由 WatchMetrics + query | PASS | | 列表 + 已 Pin | snackbar 槽位号 | PASS | | 满 4 槽替换对话框 | replace_slot POST | PASS(既有逻辑未改坏) | ## DoD - [x] `pytest tests/test_watch_metrics.py tests/test_watch_pins.py` — 10 passed - [x] `cd frontend && npm run type-check` - [x] 审计修复:WatchSlotPickDialog 加载失败 snackbar - [x] 生产已部署 `6b8965a`(监测槽点击);`6140d68`(文件搜索) - [ ] Gate 3 test_api.py — 需本地 API :8600 运行(审计时未起服务) ## 验证命令 ```bash .venv/bin/pytest tests/test_watch_metrics.py tests/test_watch_pins.py -q cd frontend && npm run type-check bash scripts/local_verify.sh # 含 Gate 3 bash deploy/pre_deploy_check.sh ``` ## 备注 - 监测槽空槽点击为设计文档明确要求(`2026-06-12-server-watch-slots-design.md` §信息架构),原实现遗漏,已补。 - 无后端变更;无需迁移/重启 API(仅前端)。