# 站点中心与仪表盘调整(v0.2.1) > 依据:`00-first-version-plan`(已删除,见 git `ceb66f8`) §8(用户 2026-09-28 上午)。状态:待审阅。只读调研 + 规格,不含代码改动。 > 参考:MoviePilot v3(`/opt/moviepilot-plus/upstream`)、MovieClaw v0.27.0(`spikes/movieclaw-src/repo`)。 ## 1. 用户要求(原文要点) - 资源 → 站点页 = 添加站点 + 凭证管理(账密 / Cookie / API Key,馒头 API Key)+ 卡片/列表(上次登录时间、上传/下载、分享率、用户等级、VIP、账号状态,数据来自 `sites/user-parsers` 的 `refreshSiteUserData`)+ 手动"检测健康"与"用凭证刷新登录状态"。 - 账密登录走 NexusPHP takelogin;验证码 / 二次验证失败 → 待处理,提示改用 Cookie。 - 设置里只留全局默认(限流、快照周期)。 - 仪表盘保留 REQ 六区块,补 MP 有价值的区块(媒体库统计、存储用量、下载器实时状态、最近入库、定时任务状态),砍重复。 ## 2. 参考实现 ### 2.1 MoviePilot v3 | 方面 | 做法 | 位置 | | --- | --- | --- | | 卡片 | 名称、URL、左侧状态色条(`sitestatistic.lst_state` 成功/失败 + `seconds` 耗时,≥5s 黄)、徽标(限流 / 代理 / 浏览器仿真 / 过滤)、上传 / 下载量;按钮:测试连通、用户数据、更新 Cookie;菜单:编辑、删除;可拖拽排序(优先级) | `components/cards/SiteCard.vue`、`views/site/SiteCardListView.vue` | | 添加 / 编辑 | 名称、URL、优先级 pri、RSS 地址、Cookie、API Key、Token、UA、代理开关、浏览器仿真、超时、限流(`limit_interval` 秒内 `limit_count` 次、`limit_seconds` 间隔)、下载器、启用 | `dialog/SiteAddEditDialog.vue`、`db/models/site.py` | | 更新 Cookie | 对话框填用户名 / 密码 / 二步验证码(或 TOTP 密钥)→ `POST site/cookie/{id}`;后端 `CookieHelper` 用 Playwright 浏览器打开登录页、OCR 识别验证码、按 `two_step_code/otp` 输入框填 TOTP,拿到 Cookie + UA 写回站点。**密码不保存** | `chain/site.py update_cookie`、`application/security/cookie.py` | | 测试连通 | GET 首页,`SiteUtils.is_logged_in` 判登录;Cloudflare 挑战单独提示;结果与耗时写 `sitestatistic`(success/fail/seconds/lst_state/lst_mod_date) | `chain/site.py test/__test` | | 用户数据 | `siteuserdata` 按天一行:username、userid、user_level、join_at、bonus、upload、download、ratio、seeding、leeching、seeding_size、leeching_size、seeding_info、message_unread(+内容)、err_msg、updated_day/time;对话框看历史曲线 | `db/models/siteuserdata.py`、`dialog/SiteUserDataDialog.vue` | | 定时 | `sitedata_refresh`「站点数据刷新」,间隔 `sitedata_refresh_interval` | `scheduler/catalog.py` | | Cookie 来源 | 手填、账密换取、CookieCloud 同步(设定 → 站点:地址 / 密钥 / 间隔 / 黑名单) | `chain/site.py sync_cookies` | ### 2.2 MovieClaw v0.27.0 - 认证方式三种:`cookie` / `apikey` / `credential`(用户名 + 密码,程序模拟登录并保存)。`CredentialAuthProvider`:GET `login.php` → 正则找 `imagecode.php?...` 验证码(无识别器 → `NEEDS_CAPTCHA` 返回图片地址)→ 带隐藏字段、`imagehash`、`extra_form_data` POST 表单 → `success_css`(`a[href*='logout']`)判成功,`error_css`(`td.text`)取失败原因,验证码错最多重试。 - 账号状态 `pending / verifying / active / failed`,附 `last_verified_at`、`last_checked_at`、`last_error`(归类后的中文);启动时把卡在 verifying 的复位。保存凭证即"保存并验证",卡片有"重新验证"。 - 验证成功时顺手抓 `profile`:用户名、等级、`vip_group`(定义里 `vip_css` 命中即 VIP)、上传 / 下载字节、分享率(null 与 0 区分)、魔力(无则不显)、做种 / 下载数、`fetched_at`。 - 卡片另有同步统计(资源数、上次同步 / 成功、下次同步、连续失败、上次错误)和保护 / 刷流开关(不在本期范围)。 ## 3. 现状与缺口 | 项 | 现状 | 缺口 | | --- | --- | --- | | 入口 | 站点工作台卡片(启停、健康、账号摘要、快照);详情"账号"页签;设置 `#sites` 另有站点列表 + 登记抽屉 + 凭证表单(`components/settings/sites.tsx`,625 行) | 仍是两处可增删改,违背 IA"一个对象一个家" | | 凭证 | `PUT /sites/{id}/credentials`(cookie/passkey/api_key/password + username)与 `/site-accounts` CRUD 并存;密码只存不用 | 无账密登录实现;无 UA 字段;无 TOTP | | 用户数据 | `refreshSiteUserData` 与 20 个解析器已移植,**服务端没有调用点**;`site_account.user_info` 只存 username | 无数据、无历史、无 VIP 字段 | | 健康 | adapter 有 `healthCheck()`(首页 + `loginSuccess`),**无路由**;健康只在快照 / Feed 出错时被动更新 | 无手动检测、无检测时间与耗时 | | 登录态 | `site_account.status` = unknown/active/invalid/expired,`last_verified_at` 只在失败时写 | 没有"需验证"态、没有上次登录时间 | | 删除 | 无删除站点 / 账号接口 | 需要 | | 全局默认 | settings 无站点默认项;`snapshotIntervalSec=null` 时不做定时快照 | 需要 `sites.*` 默认 | 站点定义:23 个里 22 个有 `umt.login`(`path/usernameField/passwordField/errorCss/extraFormData/selectDefaults`),馒头只支持 `apikey`;`chdbits`、`ssd` 的 `umt.profile.vip_css` 已有。 ## 4. 站点页规格(`/console/sites`,唯一入口) ### 4.1 页面 - 页头:标题"站点"、视图切换(卡片 / 列表,写 URL `?view=`)、刷新、"添加站点"。筛选:全部 / 已启用 / 需处理(账号非正常或健康 failing)。 - 卡片与列表同字段,列表可按分享率、上传、上次登录排序。点名称进详情(整理视图 / 原站视图 / 快照与 Feed / 账号 4 页签不变,"账号"页签改为本页抽屉的完整版,含用户数据历史)。 ### 4.2 卡片字段 | 字段 | 来源 | 显示规则 | | --- | --- | --- | | 名称、域名 | `site.name`、`site.base_url` 主机名 | 域名可点,新窗口开原站 | | 启用 | `site.enabled` | 开关 | | 账号状态 | `site_account.status` | 正常(active)/ 已失效(expired、invalid)/ 需验证(challenge)/ 未验证(unknown)/ 未配置(无账号);多账号取最差 | | 凭证类型 | `auth_kind` | Cookie / API Key / 账号密码;另有 passkey 时加"Passkey"小标 | | 上次登录 | `last_login_at` | 相对时间;从未成功显示"—" | | 上传 / 下载 / 分享率 | `user_data.upload/download/ratio` | 字节格式化;分享率 null 显示"—",download=0 显示"∞" | | 等级、VIP | `user_data.userLevel`、`user_data.vip` | VIP 为 true 才显徽标 | | 做种数(体积) | `seeding`、`seedingSize` | | | 魔力 | `bonus` | 0 且站点不提供时不显 | | 未读消息 | `messageUnread` | >0 才显 | | 健康检测 | `site.last_health` + `last_health_at` | "正常 · 320 ms · 5 分钟前" / 失败原因一句 | | 快照 | `last_snapshot_at`、周期 | 过期标黄(沿用 `snapshotStale`) | | 限流 | `site.rate_limit`,空则"默认" | 例:"20 次/分" | 用户数据时间戳(`user_data_at`)显示在数据区角落:"数据 2 小时前"。 ### 4.3 操作 卡片主按钮:检测健康、刷新登录;"更多"菜单:更新 Cookie / 更新 API Key / 更新密码(按凭证类型显示一项)、编辑、快照、停用 / 启用、删除。 | 操作 | 行为 | 端点 | | --- | --- | --- | | 添加站点 | 三步对话框:① 选定义(搜索框 + 列表,已登记的置灰;"未适配站点"只能 generic_rss)② 域名覆盖(默认定义域名)+ 凭证(按定义 `authSupported` 列出可选类型)+ 可选 UA ③ "测试"=保存后立即刷新登录,显示结果(成功带用户名 / 等级),失败可返回修改;"保存"关闭 | `POST /sites` → `PUT /sites/{id}/credentials` → `POST /sites/{id}/refresh-login` | | 编辑 | 抽屉:名称、域名、限流(空 = 全局默认)、定时快照开关与周期、UA、使用代理 | `PATCH /sites/{id}` | | 检测健康 | 首页连通 + 登录态,同步返回(≤20 s,走站点限流) | `POST /sites/{id}/health-check` | | 刷新登录 | 账密:重新登录拿 Cookie;Cookie / API Key:校验;成功后拉用户数据。异步任务,返回 taskId,卡片转圈直到任务结束 | `POST /sites/{id}/refresh-login` | | 更新凭证 | 小对话框,只写,不回显;保存即触发刷新登录 | `PUT /sites/{id}/credentials` | | 删除 | 确认框写明后果:"删除站点、账号和凭证;已抓到的资源和下载任务保留。不可恢复" | `DELETE /sites/{id}` | ### 4.4 账密登录(NexusPHP takelogin) 适配器新增 `packages/adapters/src/sites/login/nexusphp.ts`,输入定义的 `umt.login` + 用户名 / 密码 / 可选 TOTP 密钥,输出 `{ ok, cookie, userAgent }` 或 `SiteLoginError{ reason }`。流程对齐 MovieClaw `CredentialAuthProvider`: 1. 用固定 UA 清空 Cookie GET `login.php`(`umt.login.path`),记下 Set-Cookie。 2. 页面匹配 `imagecode.php?…` → 验证码。本期不做 OCR:直接失败,`reason=captcha`。 3. 取登录表单(`form[action*=takelogin]`,缺省 `takelogin.php`)的隐藏字段,填 `usernameField` / `passwordField`、`selectDefaults`、`extraFormData`;有 TOTP 密钥且表单有 `two_step_code`/`otp` 字段时填当前 6 位码。 4. POST(不跟随 3xx),再 GET `index.php`;`loginSuccess` 命中 → 成功,拼 Cookie。 5. 失败分支:`errorCss` 文本归类 —— 账号或密码错(`bad_credentials`)、需要二次验证而无 TOTP(`two_factor`)、验证码(`captcha`)、账号封禁 / 未确认(`account_blocked`)、Cloudflare 挑战(`challenge`)、其它(`unknown`,原文截 200 字)。 服务端处理: - 成功:派生 Cookie 存入 `session_secret_ref`(purpose `site_cookie`,label `site_account: