feat: 完成T-302 AI生成页布局
新增GenerateTab和GenerateTaskTableModel,将② AI生成从占位页替换为左右布局:左侧标题/封面提示词多行输入,右侧批次、店铺、状态筛选和任务列表。 任务列表展示店铺、商品ID、旧标题、新标题、状态;筛选只读SQLite,不调用AI、不写库,生成执行留给T-303,提示词管理留给T-302p。 补充GUI测试覆盖Tab②挂载、提示词输入区、任务列表展示与批次/店铺/状态筛选;同步任务看板、API、routes、current-state和progress。
This commit is contained in:
+108
-1
@@ -14,13 +14,14 @@ from app import accounts, db
|
||||
if gui.QT_IMPORT_ERROR is not None:
|
||||
raise unittest.SkipTest("PySide6 未安装")
|
||||
|
||||
from PySide6.QtWidgets import QApplication, QLineEdit, QTableView
|
||||
from PySide6.QtWidgets import QApplication, QLineEdit, QPlainTextEdit, QTableView
|
||||
|
||||
from app.gui import (
|
||||
AccountDialog,
|
||||
AccountsTab,
|
||||
CollectWorker,
|
||||
CollectTab,
|
||||
GenerateTab,
|
||||
MainWindow,
|
||||
TAB_STYLE,
|
||||
TAB_TITLES,
|
||||
@@ -64,6 +65,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertIn("padding: 8px 18px", window.tabs.styleSheet())
|
||||
self.assertIn("margin-right: 8px", window.tabs.styleSheet())
|
||||
self.assertIsInstance(window.tabs.widget(0), CollectTab)
|
||||
self.assertIsInstance(window.tabs.widget(1), GenerateTab)
|
||||
self.assertEqual(
|
||||
"回写旧数据到 Excel",
|
||||
window.tabs.widget(0).write_back_button.text(),
|
||||
@@ -71,6 +73,111 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_generate_tab_has_prompt_editors_and_task_table(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
tab = GenerateTab(config=self.make_config(temp_dir))
|
||||
self.addCleanup(tab.close)
|
||||
|
||||
self.assertIsInstance(tab.title_prompt_edit, QPlainTextEdit)
|
||||
self.assertIsInstance(tab.cover_prompt_edit, QPlainTextEdit)
|
||||
self.assertIsInstance(tab.task_table, QTableView)
|
||||
self.assertEqual("标题提示词", tab.title_prompt_edit.placeholderText())
|
||||
self.assertEqual("封面提示词", tab.cover_prompt_edit.placeholderText())
|
||||
self.assertEqual(["店铺", "商品ID", "旧标题", "新标题", "状态"], tab.model.HEADERS)
|
||||
self.assertEqual("任务 0/0 条", tab.summary_label.text())
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_generate_tab_lists_tasks_and_filters_by_shop_status_and_batch(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
accounts.create_account("副店", "alias-b", debug_port=9223, config=cfg)
|
||||
batch_a = db.create_batch(["input-a.xlsx"], path=cfg["db_path"])
|
||||
batch_b = db.create_batch(["input-b.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_a,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input-a.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639510",
|
||||
},
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input-a.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 3,
|
||||
"account_name": "Excel副店",
|
||||
"alias": "alias-b",
|
||||
"item_id": "51100639511",
|
||||
},
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input-a.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 4,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639512",
|
||||
},
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
db.insert_tasks(
|
||||
batch_b,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input-b.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639513",
|
||||
}
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tasks_a = db.list_tasks(batch_id=batch_a, path=cfg["db_path"])
|
||||
tasks_b = db.list_tasks(batch_id=batch_b, path=cfg["db_path"])
|
||||
db.set_collected(tasks_a[0].id, "旧标题A", "old-a.jpg", path=cfg["db_path"])
|
||||
db.set_collected(tasks_a[1].id, "旧标题B", "old-b.jpg", path=cfg["db_path"])
|
||||
db.set_collected(tasks_a[2].id, "旧标题C", "old-c.jpg", path=cfg["db_path"])
|
||||
db.set_generated(tasks_a[2].id, "新标题C", "new-c.jpg", path=cfg["db_path"])
|
||||
db.mark_failed(tasks_b[0].id, "generate", "生成失败", path=cfg["db_path"])
|
||||
|
||||
tab = GenerateTab(config=cfg)
|
||||
self.addCleanup(tab.close)
|
||||
|
||||
self.assertEqual(4, tab.model.rowCount())
|
||||
self.assertEqual("主店", tab.model.index(0, 0).data())
|
||||
self.assertEqual("51100639510", tab.model.index(0, 1).data())
|
||||
self.assertEqual("旧标题A", tab.model.index(0, 2).data())
|
||||
self.assertEqual("", tab.model.index(0, 3).data())
|
||||
self.assertEqual("待生成", tab.model.index(0, 4).data())
|
||||
self.assertEqual("已生成", tab.model.index(2, 4).data())
|
||||
|
||||
tab.status_filter.setCurrentIndex(tab.status_filter.findData("to_generate"))
|
||||
self.assertEqual(2, tab.model.rowCount())
|
||||
self.assertTrue(all(tab.model.index(row, 4).data() == "待生成" for row in range(2)))
|
||||
self.assertEqual("任务 2/4 条", tab.summary_label.text())
|
||||
|
||||
tab.shop_filter.setCurrentIndex(tab.shop_filter.findData("alias-b"))
|
||||
self.assertEqual(1, tab.model.rowCount())
|
||||
self.assertEqual("副店", tab.model.index(0, 0).data())
|
||||
|
||||
tab.status_filter.setCurrentIndex(tab.status_filter.findData("all"))
|
||||
tab.batch_filter.setCurrentIndex(tab.batch_filter.findData(batch_b))
|
||||
self.assertEqual(1, tab.model.rowCount())
|
||||
self.assertEqual("失败", tab.model.index(0, 4).data())
|
||||
self.assertEqual(
|
||||
"生成失败",
|
||||
tab.model.data(tab.model.index(0, 0), gui.Qt.ToolTipRole),
|
||||
)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_tab_switch_updates_status_bar(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
window = MainWindow(config=self.make_config(temp_dir))
|
||||
|
||||
Reference in New Issue
Block a user