feat: compact cover template actions
This commit is contained in:
+20
-12
@@ -811,9 +811,16 @@ if QT_IMPORT_ERROR is None:
|
||||
self.cover_template_combo.setObjectName("coverTemplateCombo")
|
||||
self.new_cover_template_button = QPushButton("新建")
|
||||
self.save_cover_template_button = QPushButton("保存")
|
||||
self.save_cover_template_as_button = QPushButton("另存为")
|
||||
self.rename_cover_template_button = QPushButton("重命名")
|
||||
self.delete_cover_template_button = QPushButton("删除")
|
||||
self.cover_template_actions_button = QPushButton("模板操作")
|
||||
self.cover_template_actions_button.setObjectName("coverTemplateActionsButton")
|
||||
self.cover_template_actions_menu = QMenu(self)
|
||||
self.save_cover_template_as_action = self.cover_template_actions_menu.addAction("另存为")
|
||||
self.save_cover_template_as_action.setObjectName("saveCoverTemplateAsAction")
|
||||
self.rename_cover_template_action = self.cover_template_actions_menu.addAction("重命名")
|
||||
self.rename_cover_template_action.setObjectName("renameCoverTemplateAction")
|
||||
self.delete_cover_template_action = self.cover_template_actions_menu.addAction("删除")
|
||||
self.delete_cover_template_action.setObjectName("deleteCoverTemplateAction")
|
||||
self.cover_template_actions_button.setMenu(self.cover_template_actions_menu)
|
||||
self.insert_title_button = QPushButton("插入标题")
|
||||
self.preview_prompt_button = QPushButton("预览")
|
||||
self.generate_button = QPushButton("开始生成")
|
||||
@@ -834,9 +841,8 @@ if QT_IMPORT_ERROR is None:
|
||||
cover_template_layout = QHBoxLayout()
|
||||
cover_template_layout.addWidget(self.new_cover_template_button)
|
||||
cover_template_layout.addWidget(self.save_cover_template_button)
|
||||
cover_template_layout.addWidget(self.save_cover_template_as_button)
|
||||
cover_template_layout.addWidget(self.rename_cover_template_button)
|
||||
cover_template_layout.addWidget(self.delete_cover_template_button)
|
||||
cover_template_layout.addWidget(self.cover_template_actions_button)
|
||||
cover_template_layout.addStretch(1)
|
||||
left_layout.addLayout(cover_template_layout)
|
||||
left_layout.addWidget(self.cover_prompt_edit, 2)
|
||||
cover_action_layout = QHBoxLayout()
|
||||
@@ -931,9 +937,9 @@ if QT_IMPORT_ERROR is None:
|
||||
self.cover_template_combo.currentIndexChanged.connect(self.load_selected_cover_template)
|
||||
self.new_cover_template_button.clicked.connect(self.new_cover_template)
|
||||
self.save_cover_template_button.clicked.connect(self.save_cover_template)
|
||||
self.save_cover_template_as_button.clicked.connect(self.save_cover_template_as)
|
||||
self.rename_cover_template_button.clicked.connect(self.rename_cover_template)
|
||||
self.delete_cover_template_button.clicked.connect(self.delete_cover_template)
|
||||
self.save_cover_template_as_action.triggered.connect(self.save_cover_template_as)
|
||||
self.rename_cover_template_action.triggered.connect(self.rename_cover_template)
|
||||
self.delete_cover_template_action.triggered.connect(self.delete_cover_template)
|
||||
self.insert_title_button.clicked.connect(self.insert_title_placeholder)
|
||||
self.preview_prompt_button.clicked.connect(self.preview_cover_prompt)
|
||||
self.generate_button.clicked.connect(self.start_generate)
|
||||
@@ -1266,10 +1272,12 @@ if QT_IMPORT_ERROR is None:
|
||||
self.item_filter.setEnabled(not running)
|
||||
self.status_filter.setEnabled(not running)
|
||||
self.save_title_button.setEnabled(not running)
|
||||
self.new_cover_template_button.setEnabled(not running)
|
||||
self.save_cover_template_button.setEnabled(not running)
|
||||
self.save_cover_template_as_button.setEnabled(not running)
|
||||
self.rename_cover_template_button.setEnabled(not running)
|
||||
self.delete_cover_template_button.setEnabled(not running)
|
||||
self.cover_template_actions_button.setEnabled(not running)
|
||||
self.save_cover_template_as_action.setEnabled(not running)
|
||||
self.rename_cover_template_action.setEnabled(not running)
|
||||
self.delete_cover_template_action.setEnabled(not running)
|
||||
|
||||
def _forget_generate_thread(self, thread):
|
||||
if self.generate_thread is thread:
|
||||
|
||||
+2
-1
@@ -101,6 +101,7 @@
|
||||
| T-515 | 批次阶段进度总览 | T-206, T-401 | 依据 `docs/ux-review.md` P1。加轻量批次进度总览:①②③在当前批次/全部批次摘要区下方显示同一组阶段计数,按当前批次筛选聚合总数、导入、已采集、已生成、已更新、失败、略过。计数口径:失败/略过优先按 `status=failed/skipped` 统计;已更新按 `stage=applied` 且非失败/略过;已生成按 `stage=generated` 且非失败/略过;已采集按 `stage=collected` 且非失败/略过;导入按其余未进入后续阶段任务统计。数据由现有 `db.list_tasks(batch_id=...)` 聚合,不新增表;已软删除批次不计入;只做 UI 总览,不改采集/生成/更新执行流程 | DONE |
|
||||
| T-516 | ①筛选对齐②③ | T-202, T-303b | 依据 `docs/ux-review.md` P2。① 导入采集补齐与②③一致的店铺、商品ID、状态筛选,保持三个列表页筛选心智一致。筛选栏顺序为批次/店铺/商品ID/状态;当前筛选结果用于①表格显示与「采集旧标题/旧封面」作用范围;导入汇总栏、批次进度总览、未匹配数量仍按当前批次全量任务统计,未匹配按钮继续筛出当前筛选结果中的未匹配任务;不改导入、采集、回写、CDP 或 Shopee 更新逻辑 | DONE |
|
||||
| T-517 | ⑤设置分区 + 清理兼容字段 | T-506, T-507 | 依据 `docs/ux-review.md` P2。⑤ 视觉分区:将高频「Shopee 更新安全 / 执行模式」前置成独立分区,低频「基础设施(Chrome路径/端口/DB路径)」独立后置;彻底隐藏 `test_item_id`、`dry_run` 用户入口,不再占用可见表单位置,但保留 `config.json` 内部兼容字段与③「检查本轮更新」语义。只改⑤设置页 UI 分区、保存/加载展示和 GUI 测试,不改配置 schema,不改 Shopee/CDP 更新流程 | DONE |
|
||||
| T-518 | ②左栏提示词区组件密度优化 | T-302p, T-303, T-517 | 依据 `docs/ux-review.md` P2。② AI生成左栏保留高频「模板选择、编辑内容、保存当前模板/开始生成」可见入口;将封面模板低频操作「另存为、重命名、删除」收敛进一个「模板操作」菜单/小按钮,避免左栏按钮堆叠和误点。第一版不迁移到⑤设置,不改 prompts 数据结构,不改 AI 生成 HTTP、DB schema、Excel、Shopee/CDP 流程;删除仍保留现有二次确认,保存/重命名/删除行为和错误处理不变。同步 GUI 测试覆盖菜单入口、动作触发和旧低频按钮不再平铺 | DONE |
|
||||
|
||||
## 里程碑
|
||||
|
||||
@@ -116,5 +117,5 @@
|
||||
- 上传弹裁剪框商品的自动裁剪。
|
||||
- 账号登录态健康巡检。
|
||||
- AI 生成图的合规/质量自检。
|
||||
- ② 左栏提示词区组件密度优化:封面模板低频动作(另存为/重命名/删除)折叠进图标菜单或评估移入⑤(`docs/ux-review.md` P2)。
|
||||
- (已提升为 T-518)② 左栏提示词区组件密度优化:封面模板低频动作(另存为/重命名/删除)收敛进②本页「模板操作」菜单/小按钮;第一版不移入⑤,不改提示词数据结构。
|
||||
- 界面深色主题:为 `docs/ui-color-design.md` 语义色板另出深色等义映射(当前只服务浅色)。
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -97,6 +97,6 @@ Tab 排列 `①采集 → ②生成 → ③更新 → ④账号 → ⑤设置`
|
||||
| **P1** | 缺批次级总览 | 加批次阶段计数总览(聚合现有 `list_tasks`) | `app/gui.py`、`app/db.py` |
|
||||
| **P2** | ⑤设置过载 + 兼容字段技术债 | 安全开关 vs 基础设施分区;清理隐藏兼容字段 | `app/gui.py` ⑤ |
|
||||
| **P2** | ①筛选弱于②③ | ①对齐"店铺/商品ID/状态"筛选 | `app/gui.py` ① |
|
||||
| **P2** | ②左栏组件密度过高 | 封面模板低频动作折叠 / 评估移⑤ | `app/gui.py` ② |
|
||||
| **P2** | ②左栏组件密度过高 | 已由 T-518 落地:封面模板低频动作折叠进②本页「模板操作」,第一版不移入⑤ | `app/gui.py` ② |
|
||||
|
||||
> 落地顺序建议:P0 中已落地项只做回归;剩余事项以 `docs/06-tasks.md` 的 T-511 及之后任务为准,按防误操作/首次可用性/体验打磨的收益排序推进。每条落任务时补现状/方案/验收要点,并遵守 `docs/05-coding-rules.md` 验证清单。
|
||||
|
||||
+12
@@ -980,3 +980,15 @@
|
||||
- 代码:`app/gui.py` 将「Shopee 更新安全 / 执行模式」前置为独立分区,将「基础设施(路径与端口)」后置;移除 `test_item_id_edit`、`dry_run_checkbox` 这类用户入口,加载时只记录 `test_item_id` 内部兼容值,保存时保留该值并固定 `dry_run=false`。
|
||||
- 测试:`tests/test_gui.py` 更新设置页断言,覆盖分区顺序、旧入口不存在、保存设置仍同步 ApplyTab 安全配置且兼容字段不丢。
|
||||
- 验证:`python -m py_compile app\gui.py tests\test_gui.py` 通过;`python -m unittest discover -s tests -p "test_gui.py"` 通过(68 tests);`python -m compileall app main.py` 通过;`python -m unittest discover -s tests` 通过(156 tests);`git diff --check` 无空白错误,仅 LF/CRLF 提示。
|
||||
## 【2026-07-02】T-518 文档启动 · ②左栏提示词区组件密度优化
|
||||
|
||||
- 背景:Claude Code review T-511~T-517 未发现问题;下一步从 `docs/06-tasks.md` Backlog 和 `docs/ux-review.md` P2 提升②左栏组件密度优化为正式任务。
|
||||
- 文档:`docs/06-tasks.md` 新增 T-518 并标记 DOING,明确只收敛②AI生成左栏封面模板低频操作「另存为/重命名/删除」,第一版不移入⑤,不改 prompts 数据结构、AI生成、DB、Excel、Shopee/CDP 流程;同步 `docs/current-state.md` 与 `docs/ux-review.md`。
|
||||
- 验证:文档-only 更新,未运行单元测试。
|
||||
- 下一步:按 T-518 文档更新 `app/gui.py` 和 `tests/test_gui.py`。
|
||||
## 【2026-07-02】T-518 完成 · ②左栏提示词区组件密度优化
|
||||
|
||||
- 代码:`app/gui.py` 将②AI生成左栏封面模板低频操作「另存为 / 重命名 / 删除」从平铺按钮收敛进「模板操作」菜单;「新建」「保存」继续作为可见按钮,菜单 action 仍调用原有模板保存/重命名/删除方法,删除二次确认和错误处理不变。
|
||||
- 范围控制:不迁移到⑤设置,不改 prompts 数据结构,不改 AI 生成 HTTP、DB schema、Excel 或 Shopee/CDP 流程。
|
||||
- 测试:`tests/test_gui.py` 覆盖「模板操作」菜单入口、菜单 action 触发原有行为,以及旧低频按钮不再平铺。
|
||||
- 验证:`python -m py_compile app\gui.py tests\test_gui.py` 通过;`python -m unittest discover -s tests -p "test_gui.py"` 通过(68 tests);`python -m compileall app main.py` 通过;`python -m unittest discover -s tests` 通过(156 tests)。Qt 仍有本机字体目录提示,不影响测试结果。
|
||||
|
||||
+12
-3
@@ -697,6 +697,15 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertFalse(tab.stop_generate_button.isEnabled())
|
||||
self.assertEqual("进度:标题0/0 · 封面0/0 · 失败0", tab.progress_label.text())
|
||||
self.assertEqual("默认", tab.cover_template_combo.currentText())
|
||||
self.assertEqual("模板操作", tab.cover_template_actions_button.text())
|
||||
self.assertIs(tab.cover_template_actions_menu, tab.cover_template_actions_button.menu())
|
||||
self.assertEqual(
|
||||
["另存为", "重命名", "删除"],
|
||||
[action.text() for action in tab.cover_template_actions_menu.actions()],
|
||||
)
|
||||
self.assertFalse(hasattr(tab, "save_cover_template_as_button"))
|
||||
self.assertFalse(hasattr(tab, "rename_cover_template_button"))
|
||||
self.assertFalse(hasattr(tab, "delete_cover_template_button"))
|
||||
self.assertEqual(["店铺", "商品ID", "旧标题", "新标题", "状态"], tab.model.HEADERS)
|
||||
self.assertEqual("任务 0/0 条", tab.summary_label.text())
|
||||
|
||||
@@ -751,12 +760,12 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
tab.cover_prompt_edit.setPlainText("另存模板 {新标题}")
|
||||
with mock.patch("app.gui.QInputDialog.getText", return_value=("另存", True)):
|
||||
tab.save_cover_template_as()
|
||||
tab.save_cover_template_as_action.trigger()
|
||||
self.assertEqual("另存", tab.cover_template_combo.currentText())
|
||||
self.assertEqual("另存模板 {新标题}", prompts.load_cover_template("另存", cover_prompts_dir))
|
||||
|
||||
with mock.patch("app.gui.QInputDialog.getText", return_value=("改名", True)):
|
||||
tab.rename_cover_template()
|
||||
tab.rename_cover_template_action.trigger()
|
||||
self.assertEqual("改名", tab.cover_template_combo.currentText())
|
||||
self.assertIn("改名", prompts.list_cover_templates(cover_prompts_dir))
|
||||
|
||||
@@ -775,7 +784,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertTrue(tab.cover_prompt_edit.toPlainText().endswith("{新标题}"))
|
||||
|
||||
with mock.patch("app.gui.QMessageBox.question", return_value=gui.QMessageBox.Yes):
|
||||
tab.delete_cover_template()
|
||||
tab.delete_cover_template_action.trigger()
|
||||
self.assertNotIn("改名", prompts.list_cover_templates(cover_prompts_dir))
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
Reference in New Issue
Block a user