2026-07-10 10:24:44 +08:00
|
|
|
|
---
|
|
|
|
|
|
id: T-581
|
|
|
|
|
|
title: ②AI生成增加「打开图片文件夹」按钮(级联:选中行账号图 / 批次 / 全部批次根)
|
|
|
|
|
|
phase: 7
|
|
|
|
|
|
deps: [T-566]
|
2026-07-10 10:46:52 +08:00
|
|
|
|
status: DONE
|
2026-07-10 10:24:44 +08:00
|
|
|
|
created: 2026-07-10
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 问题 / 背景
|
|
|
|
|
|
|
|
|
|
|
|
运营需要把某商品/某账号/整批的 AI 图片(旧封面、新封面、归档候选)用文件管理器打开,便于打包发给他人做文件级操作。当前②只能在画廊弹窗里看单商品候选(T-567),无法跳到文件夹做批量文件操作。
|
|
|
|
|
|
|
|
|
|
|
|
已核事实:
|
|
|
|
|
|
- 图片落盘层级 `<image_root>/<batch_id>/<slug>/{task_id}_{item_id}_{old|new|new_<ts>}.jpg`(`app/image_paths.py`)。slug 文件夹里直接是图片文件(含旧封面、新封面、归档候选);批次文件夹下一层是各账号 slug 子文件夹。
|
|
|
|
|
|
- `image_root = appconfig.image_dir(config)`(`app/appconfig.py:622`)。
|
|
|
|
|
|
- ②批次来源 = `batch_filter.currentData()`(`generate.py:1866`,None/"all" 即全部批次);行选中 = 表格 selectionModel。
|
|
|
|
|
|
- **仓库无任何"打开文件夹"实现**——净新增,需跨平台且 Linux 测试环境不崩(单测在 WSL 跑)。
|
|
|
|
|
|
|
|
|
|
|
|
## 方案(改哪个文件、改成什么)
|
|
|
|
|
|
|
|
|
|
|
|
### 级联打开规则(越具体开越深)
|
|
|
|
|
|
|
|
|
|
|
|
| 状态 | 打开目录 |
|
|
|
|
|
|
| --- | --- |
|
2026-07-10 10:39:58 +08:00
|
|
|
|
| 选中了某行 | 优先打开该行已有 `new_cover_path` / `old_cover_path` 的真实父目录;若没有已有图片路径,再回退到 `<image_root>/<batch_id>/<slug>/`(该行任务对应账号的图片,直达图片) |
|
2026-07-10 10:24:44 +08:00
|
|
|
|
| 未选行、批次筛选=具体批次 | `<image_root>/<batch_id>/`(整批,含各账号子文件夹,供整批打包) |
|
|
|
|
|
|
| 未选行、批次筛选=全部批次 | `<image_root>/`(所有批次根) |
|
|
|
|
|
|
|
2026-07-10 10:39:58 +08:00
|
|
|
|
- 选中多行时以表格当前焦点行(`currentIndex/currentRow`)为准;若当前行无效,再取 selectionModel 的第一条选中行。只打开一个目录,不同时打开多个目录。
|
|
|
|
|
|
- 选中行有历史图片路径时,优先打开真实存在图片文件的父目录,避免老数据或路径结构调整后“有图但打开空目录”。如果已有路径不存在或为空,再用规范路径回退。
|
|
|
|
|
|
- slug 目录路径复用 `image_paths.task_image_path(image_root, task, account, "new")` 取 `os.path.dirname(...)`,保证与新图片实际落盘位置一致;账号解析复用②既有 account 解析(`_account_for_task`/`account_by_alias` 同款)。
|
|
|
|
|
|
- 若选中行缺少账号 alias、或 alias 找不到账号,不能猜测 slug;直接中文提示「选中任务没有匹配账号,无法定位图片文件夹」,不打开、不创建目录。
|
|
|
|
|
|
- 未选行时只按批次筛选级联:具体批次打开 `<image_root>/<batch_id>/`,全部批次打开 `<image_root>/`,不需要账号解析。
|
2026-07-10 10:24:44 +08:00
|
|
|
|
|
|
|
|
|
|
### `app/gui/tabs/generate.py` — 按钮与布局
|
|
|
|
|
|
|
|
|
|
|
|
- 新增 `self.open_image_dir_button = QPushButton("打开图片文件夹")`,放在**筛选行**(`filter_layout`)紧挨 `refresh_button` 右侧(`generate.py:895` 后)。理由:级联依据(批次筛选、选中行)都在这一行,且它是只读导航动作,不与「开始生成/停止/重置生成结果」这类消耗点数/改数据的执行按钮混排。
|
|
|
|
|
|
- tooltip:「选中某行→打开该账号图片文件夹;未选中→打开当前批次文件夹;全部批次→打开图片根目录」。
|
2026-07-10 10:39:58 +08:00
|
|
|
|
- 点击 handler:按上表算出目标目录 → 若目录**不存在**:弹提示(如「该批次/账号还没有图片」或「图片根目录不存在,请先采集或生成图片」),**不自动创建目录**、不打开 → 存在则调用跨平台打开 helper。
|
2026-07-10 10:24:44 +08:00
|
|
|
|
|
|
|
|
|
|
### 跨平台打开 helper(可 mock)
|
|
|
|
|
|
|
2026-07-10 10:39:58 +08:00
|
|
|
|
- 新增小工具,优先放在独立模块 `app/gui/file_manager.py`,提供 `open_in_file_manager(path)`,便于单测 mock 且不把系统调用塞进通用控件模块。
|
|
|
|
|
|
- `open_in_file_manager(path)` 先把路径转为绝对路径并确认 `os.path.isdir(path)`;目录不存在时抛出可中文化处理的错误,不负责创建目录。
|
|
|
|
|
|
- Windows 用 `os.startfile(path)`;macOS 用 `subprocess.Popen(["open", path], stdout=DEVNULL, stderr=DEVNULL, shell=False)`;Linux/其它平台用 `subprocess.Popen(["xdg-open", path], stdout=DEVNULL, stderr=DEVNULL, shell=False)`。不拼 shell 字符串、不用 `shell=True`,避免路径空格/特殊字符问题;测试环境 mock 掉真实调用。
|
2026-07-10 10:24:44 +08:00
|
|
|
|
- handler 调用该 helper,单测通过 `mock.patch` 断言「用正确目标路径调用了 helper」,**不真正打开**(Linux CI/WSL 不炸)。
|
|
|
|
|
|
|
|
|
|
|
|
### 文档同步
|
|
|
|
|
|
|
|
|
|
|
|
- `docs/routes.md` / ②相关 UI 文档:登记「打开图片文件夹」按钮及级联规则。
|
|
|
|
|
|
|
|
|
|
|
|
## 验收要点
|
|
|
|
|
|
|
2026-07-10 10:39:58 +08:00
|
|
|
|
- 选中某行 → 若已有图片路径存在,优先用该图片父目录调用打开 helper;否则用 `<image_root>/<batch_id>/<slug>/`(= 该行 new 图 dirname)调用。
|
|
|
|
|
|
- 多选时以当前焦点行打开,不因 selectionModel 返回顺序导致打开到非当前行。
|
|
|
|
|
|
- 选中行账号无法匹配 → 中文提示,不调用打开 helper、不猜路径。
|
2026-07-10 10:24:44 +08:00
|
|
|
|
- 未选行 + 批次筛选具体批次 → 用 `<image_root>/<batch_id>/` 调用。
|
|
|
|
|
|
- 未选行 + 全部批次 → 用 `<image_root>/` 调用。
|
|
|
|
|
|
- 目标目录不存在 → 弹提示、**不调用打开 helper、不创建目录**。
|
2026-07-10 10:39:58 +08:00
|
|
|
|
- 打开 helper 被 mock:单测断言目标路径正确、平台分支正确;不真实执行 `os.startfile` / `open` / `xdg-open`。
|
2026-07-10 10:24:44 +08:00
|
|
|
|
- 按钮位于筛选行、不在生成/重置按钮排;tooltip 说明级联。
|
|
|
|
|
|
- 生成运行中按钮仍可用(只读动作,不必禁用)。
|
|
|
|
|
|
- 验证命令(unittest,不引入 pytest):
|
|
|
|
|
|
- `py -3.10 -m unittest tests.test_gui`
|
|
|
|
|
|
- `python -m ruff check app tests main.py`
|
|
|
|
|
|
- `py -3.10 -m compileall app main.py`
|
|
|
|
|
|
- `py -3.10 -m unittest discover -s tests`
|
|
|
|
|
|
- `git diff --check`
|
|
|
|
|
|
|
|
|
|
|
|
## 边界(不改什么)
|
|
|
|
|
|
|
|
|
|
|
|
- 不改图片落盘路径/层级、`image_paths` 生成逻辑、`image_dir` 配置。
|
|
|
|
|
|
- 不新建「打包/压缩」功能(只打开文件夹,压缩由用户在文件管理器做)。
|
|
|
|
|
|
- 不改画廊弹窗(T-567)、生成/重置链路、批次筛选逻辑本身。
|
|
|
|
|
|
- 不自动创建缺失目录、不删除任何文件。
|
|
|
|
|
|
- 不改 ③/①/CDP/DB/cmhub。
|
2026-07-10 10:39:58 +08:00
|
|
|
|
- 不把打开目录失败写成任务失败,不修改任务状态、批次状态或图片路径字段。
|
2026-07-10 10:24:44 +08:00
|
|
|
|
|
|
|
|
|
|
## 执行记录
|
|
|
|
|
|
|
2026-07-10 10:46:52 +08:00
|
|
|
|
- 2026-07-10:已实现②「打开图片文件夹」按钮,位于 AI生成筛选行刷新按钮右侧;按钮按选中行、具体批次、全部批次三级规则定位本地图片目录,运行中不禁用,不修改任何任务/批次状态。
|
|
|
|
|
|
- 2026-07-10:新增 `app/gui/file_manager.py`,封装跨平台打开目录逻辑;Windows 使用 `os.startfile`,macOS/Linux 使用 `subprocess.Popen([...], shell=False)`,helper 不创建目录。
|
|
|
|
|
|
- 2026-07-10:选中行优先打开已有 `new_cover_path` / `old_cover_path` 的真实父目录;没有真实图片文件时回退到 `image_paths.task_image_path(..., "new")` 的账号目录;账号无法匹配时中文提示,不猜 slug。
|
|
|
|
|
|
- 2026-07-10:同步 `docs/routes.md` ②AI生成说明;补 `tests/test_gui.py` 覆盖选中行当前焦点优先、规范账号目录回退、具体批次目录、图片根目录、目录缺失不创建、账号未匹配提示、平台打开 helper 分支。
|
|
|
|
|
|
- 验证通过:
|
|
|
|
|
|
- `py -3.10 -m unittest tests.test_gui.GuiTests.test_generate_tab_opens_current_row_image_directory tests.test_gui.GuiTests.test_generate_tab_open_image_directory_falls_back_to_canonical_account_dir tests.test_gui.GuiTests.test_generate_tab_opens_batch_or_root_directory_without_selected_row tests.test_gui.GuiTests.test_generate_tab_open_image_directory_warns_without_creating_missing_dir tests.test_gui.GuiTests.test_generate_tab_open_image_directory_warns_when_selected_account_unmatched tests.test_gui.GuiTests.test_open_in_file_manager_uses_platform_file_manager`
|
|
|
|
|
|
- `python -m ruff check app tests main.py`
|
|
|
|
|
|
- `py -3.10 -m compileall app main.py`
|
|
|
|
|
|
- `git diff --check`(仅输出当前工作区既有 CRLF 提示,无空白错误)
|
2026-07-10 10:49:45 +08:00
|
|
|
|
- 提交后在干净 worktree `D:\chengma\cmshopee_verify_t581` 验证本次 T-581 提交:`python -m ruff check app tests main.py` 通过,`py -3.10 -m compileall app main.py` 通过,`git diff --check` 通过,`py -3.10 -m unittest tests.test_gui` 通过 144 项,`py -3.10 -m unittest discover -s tests` 通过 324 项。
|
2026-07-10 10:46:52 +08:00
|
|
|
|
- 当前工作区直接运行 `py -3.10 -m unittest tests.test_gui` 失败 2 项,原因是本任务开始前已有未提交改动把默认封面提示词从 `papa1` 改成「默认」,导致两个旧断言仍期望 `papa1`;该提示词改名不属于 T-581,本次未处理、未提交。
|