feat: 完成Tab④账号管理

- 新增 accounts 服务层,封装账号 CRUD、目录创建、端口分配与登录检测

- 接入 PySide6 账号管理 Tab:表格、账号弹窗、启动登录、后台检测登录

- 密码仅本地保存并在 UI 打码,表格不展示明文;不自动登录或填密码

- 增加顶部 Tab 栏防误点样式,扩大点击区域并高亮当前 Tab

- 补充账号服务和 GUI 单元测试,并同步架构、API、路由、任务和进度文档
This commit is contained in:
chengma
2026-06-27 10:30:45 +08:00
parent 479ab5c41d
commit 598df5f20b
11 changed files with 970 additions and 40 deletions
+44 -2
View File
@@ -121,6 +121,37 @@ ensure_user_data_dir(slug, root=None, config=None) -> str
`make_slug()` 使用可读 ASCII 前缀 + 8 位 SHA1 后缀,保证稳定且降低别名冲突;非 ASCII 别名使用 `account_<hash>`。`ensure_user_data_dir()` 拒绝非 `[a-z0-9_]` slug,防止路径穿越。
## accounts 模块(`app/accounts.py`,已建)
账号管理服务层,供 ④ Tab 调用;不操作 QWidget,不自动登录/填密码。
```python
class AccountError(RuntimeError): ...
normalize_region_host(value=None) -> str
normalize_debug_port(value) -> int
preview_user_data_dir(alias, config=None) -> str
mask_password(password) -> str # 展示用,永不返回明文
next_debug_port(config=None, path=None) -> int
list_accounts(path=None, config=None) -> list[db.Account]
get_account(alias, path=None, config=None) -> db.Account
create_account(account_name, alias, region_host=None, debug_port=None,
password=None, note=None, path=None, config=None) -> db.Account
update_account(original_alias, account_name, alias, region_host=None, debug_port=None,
password=None, note=None, path=None, config=None) -> db.Account
delete_account(alias, path=None, config=None) -> None
launch_for_login(account_or_alias, path=None, config=None) -> subprocess.Popen
detect_login(account_or_alias, timeout=8, path=None, config=None) -> dict
login_status_text(status) -> str
```
规则:
- `create_account()` / `update_account()` 负责生成 slug、创建 `chrome_user_data_dir/<slug>` 并写 DB;编辑别名会生成新 slug/目录,但不删除旧 user-data-dir。
- `debug_port` 在账号服务层按账号唯一校验;默认端口取 `debug_port_range` 中第一个未占用端口。
- `delete_account()` 只删除 DB 账号记录,不删除本地 user-data-dir,避免误删登录态。
- `launch_for_login()` 只启动带该账号 user-data-dir 和 CDP 端口的 Chrome;不会读取、填写或提交密码。
- `detect_login()` 复用 `editor.login_status()`;检测为已登录时更新 `last_login_at`。
## chrome 模块(`app/chrome.py`,已建)
```python
@@ -219,11 +250,22 @@ render_prompt(template_text, task) -> str
```python
# GUI 入口
main() -> int # 创建 QApplication + MainWindow
class MainWindow(QMainWindow) # QTabWidget: ①②③④⑤
class MainWindow(QMainWindow) # QTabWidget: ①②③④⑤;支持注入 db_path/config 便于测试
class AccountsTab(QWidget) # ④ 账号管理:表格 + 增删改 + 启动登录 + 检测登录
class AccountDialog(QDialog) # 账号编辑弹窗;密码 QLineEdit.Password
TAB_TITLES: list[str] # 固定 Tab 顺序
TAB_STYLE: str # 顶层 Tab 栏防误点样式:最小宽度/padding/间距/当前态
```
`MainWindow` 目前只实现五 Tab 空壳与基础状态栏;业务控件按后续 Tab 任务逐步填充。缺 PySide6 时 `main()` 返回 1 并输出明确提示。
`MainWindow` 已实现五 Tab 与 ④ 账号管理;①②③⑤ 仍为空壳,业务控件按后续 Tab 任务逐步填充。缺 PySide6 时 `main()` 返回 1 并输出明确提示。
主 Tab 栏必须在 `MainWindow` 初始化时应用 `TAB_STYLE`:5 个 Tab 不使用 Qt 默认紧凑宽度,需保证点击区域稳定、间距清晰、当前 Tab 高亮明显。该样式属于全局导航基础,不归后续业务 Tab 任务重复实现。
④ 账号管理要点:
- 表格列:账号名、别名、地区、端口、登录状态、备注;不展示密码。
- 弹窗字段:账号名、别名、地区、调试端口、密码、备注、slug、数据目录;密码框使用打码显示。
- 「启动登录」只启动 Chrome,人工登录;「检测登录」用 worker 跑 `accounts.detect_login()` 并刷新状态列。
## workers 模块(`app/workers.py`,已建,PySide6)