feat(product-suite): add independent category rows
This commit is contained in:
+141
-84
@@ -57,6 +57,11 @@ ORIGINAL_DOWNLOAD_CONCURRENCY = 2
|
|||||||
ORIGINAL_CHECK_STATE_ROLE = Qt.UserRole + 1
|
ORIGINAL_CHECK_STATE_ROLE = Qt.UserRole + 1
|
||||||
_PRODUCT_SUITE_THREAD_REFS = {}
|
_PRODUCT_SUITE_THREAD_REFS = {}
|
||||||
_URL_RE = re.compile(r"https?://[^\s,,;;))\]]+", re.IGNORECASE)
|
_URL_RE = re.compile(r"https?://[^\s,,;;))\]]+", re.IGNORECASE)
|
||||||
|
FIXED_CATEGORY_HELPERS = {
|
||||||
|
"白底图": "白底主图,多角度呈现商品细节",
|
||||||
|
"场景图": "生活化场景展示商品使用方式",
|
||||||
|
"卖点图": "突出核心卖点和差异化优势",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _asset_usable(asset):
|
def _asset_usable(asset):
|
||||||
@@ -392,12 +397,116 @@ class ProductOriginalList(QListWidget):
|
|||||||
super().leaveEvent(event)
|
super().leaveEvent(event)
|
||||||
|
|
||||||
|
|
||||||
class CategoryChipButton(QPushButton):
|
class SuiteCategoryRow(QFrame):
|
||||||
doubleClicked = Signal()
|
countChangeRequested = Signal(str, int)
|
||||||
|
renameRequested = Signal(str)
|
||||||
|
deleteRequested = Signal(str)
|
||||||
|
|
||||||
def mouseDoubleClickEvent(self, event):
|
def __init__(self, name, count, *, helper="", custom=False, parent=None):
|
||||||
self.doubleClicked.emit()
|
super().__init__(parent)
|
||||||
event.accept()
|
self.category_name = str(name)
|
||||||
|
self._controls_enabled = True
|
||||||
|
self.setObjectName("suiteCategoryRow")
|
||||||
|
self.setProperty("categoryName", self.category_name)
|
||||||
|
self.setStyleSheet(
|
||||||
|
"QFrame#suiteCategoryRow { border: none; border-bottom: 1px solid #eaeef2; }"
|
||||||
|
)
|
||||||
|
|
||||||
|
layout = QGridLayout(self)
|
||||||
|
layout.setContentsMargins(6, 5, 4, 6)
|
||||||
|
layout.setHorizontalSpacing(8)
|
||||||
|
layout.setVerticalSpacing(2)
|
||||||
|
layout.setColumnStretch(0, 1)
|
||||||
|
|
||||||
|
self.name_label = QLabel(self.category_name)
|
||||||
|
self.name_label.setObjectName("suiteCategoryNameLabel")
|
||||||
|
self.name_label.setStyleSheet("font-weight: 600; color: #24292f;")
|
||||||
|
layout.addWidget(self.name_label, 0, 0)
|
||||||
|
|
||||||
|
controls_widget = QWidget()
|
||||||
|
controls = QHBoxLayout(controls_widget)
|
||||||
|
controls.setContentsMargins(0, 0, 0, 0)
|
||||||
|
controls.setSpacing(4)
|
||||||
|
|
||||||
|
self.minus_button = QToolButton()
|
||||||
|
self.minus_button.setObjectName("suiteCategoryMinusButton")
|
||||||
|
self.minus_button.setText("−")
|
||||||
|
self.minus_button.setToolTip("减少%s数量" % self.category_name)
|
||||||
|
self.minus_button.setAccessibleName("减少%s数量" % self.category_name)
|
||||||
|
self.minus_button.setMinimumSize(28, 28)
|
||||||
|
self.minus_button.clicked.connect(
|
||||||
|
lambda checked=False: self.countChangeRequested.emit(self.category_name, -1)
|
||||||
|
)
|
||||||
|
controls.addWidget(self.minus_button)
|
||||||
|
|
||||||
|
self.count_label = QLabel()
|
||||||
|
self.count_label.setObjectName("suiteCategoryCountLabel")
|
||||||
|
self.count_label.setAlignment(Qt.AlignCenter)
|
||||||
|
self.count_label.setMinimumWidth(28)
|
||||||
|
controls.addWidget(self.count_label)
|
||||||
|
|
||||||
|
self.plus_button = QToolButton()
|
||||||
|
self.plus_button.setObjectName("suiteCategoryPlusButton")
|
||||||
|
self.plus_button.setText("+")
|
||||||
|
self.plus_button.setToolTip("增加%s数量" % self.category_name)
|
||||||
|
self.plus_button.setAccessibleName("增加%s数量" % self.category_name)
|
||||||
|
self.plus_button.setMinimumSize(28, 28)
|
||||||
|
self.plus_button.clicked.connect(
|
||||||
|
lambda checked=False: self.countChangeRequested.emit(self.category_name, 1)
|
||||||
|
)
|
||||||
|
controls.addWidget(self.plus_button)
|
||||||
|
|
||||||
|
self.rename_button = None
|
||||||
|
self.delete_button = None
|
||||||
|
if custom:
|
||||||
|
self.rename_button = QToolButton()
|
||||||
|
self.rename_button.setObjectName("suiteCategoryRenameButton")
|
||||||
|
self.rename_button.setText("改名")
|
||||||
|
self.rename_button.setToolTip("重命名%s分类" % self.category_name)
|
||||||
|
self.rename_button.setAccessibleName("重命名%s分类" % self.category_name)
|
||||||
|
self.rename_button.setMinimumSize(48, 28)
|
||||||
|
self.rename_button.clicked.connect(
|
||||||
|
lambda checked=False: self.renameRequested.emit(self.category_name)
|
||||||
|
)
|
||||||
|
controls.addWidget(self.rename_button)
|
||||||
|
|
||||||
|
self.delete_button = QToolButton()
|
||||||
|
self.delete_button.setObjectName("suiteCategoryDeleteButton")
|
||||||
|
self.delete_button.setText("×")
|
||||||
|
self.delete_button.setToolTip("删除%s分类" % self.category_name)
|
||||||
|
self.delete_button.setAccessibleName("删除%s分类" % self.category_name)
|
||||||
|
self.delete_button.setMinimumSize(28, 28)
|
||||||
|
self.delete_button.clicked.connect(
|
||||||
|
lambda checked=False: self.deleteRequested.emit(self.category_name)
|
||||||
|
)
|
||||||
|
controls.addWidget(self.delete_button)
|
||||||
|
|
||||||
|
layout.addWidget(controls_widget, 0, 1, 2 if helper else 1, 1, Qt.AlignTop)
|
||||||
|
self.helper_label = None
|
||||||
|
if helper:
|
||||||
|
self.helper_label = QLabel(str(helper))
|
||||||
|
self.helper_label.setObjectName("suiteCategoryHelperLabel")
|
||||||
|
self.helper_label.setStyleSheet("color: #6b7280;")
|
||||||
|
self.helper_label.setWordWrap(True)
|
||||||
|
layout.addWidget(self.helper_label, 1, 0)
|
||||||
|
self.set_count(count)
|
||||||
|
|
||||||
|
def set_count(self, count):
|
||||||
|
normalized = max(0, int(count or 0))
|
||||||
|
self.count_label.setText(str(normalized))
|
||||||
|
self.minus_button.setEnabled(self._controls_enabled and normalized > 0)
|
||||||
|
|
||||||
|
def count(self):
|
||||||
|
return int(self.count_label.text() or 0)
|
||||||
|
|
||||||
|
def set_controls_enabled(self, enabled):
|
||||||
|
self._controls_enabled = bool(enabled)
|
||||||
|
self.minus_button.setEnabled(self._controls_enabled and self.count() > 0)
|
||||||
|
self.plus_button.setEnabled(self._controls_enabled)
|
||||||
|
if self.rename_button is not None:
|
||||||
|
self.rename_button.setEnabled(self._controls_enabled)
|
||||||
|
if self.delete_button is not None:
|
||||||
|
self.delete_button.setEnabled(self._controls_enabled)
|
||||||
|
|
||||||
|
|
||||||
class SuiteResultCard(QFrame):
|
class SuiteResultCard(QFrame):
|
||||||
@@ -511,8 +620,6 @@ class SuiteTaskState:
|
|||||||
ai_prompt_snapshot: str = ""
|
ai_prompt_snapshot: str = ""
|
||||||
pending_ai_text: str = ""
|
pending_ai_text: str = ""
|
||||||
undo_records: list = field(default_factory=list)
|
undo_records: list = field(default_factory=list)
|
||||||
active_category: str = "白底图"
|
|
||||||
|
|
||||||
def generation_running(self):
|
def generation_running(self):
|
||||||
return self.worker is not None
|
return self.worker is not None
|
||||||
|
|
||||||
@@ -848,8 +955,10 @@ class ProductSuiteTab(QWidget):
|
|||||||
layout.addLayout(title_row)
|
layout.addLayout(title_row)
|
||||||
self.category_grid = QGridLayout()
|
self.category_grid = QGridLayout()
|
||||||
self.category_grid.setContentsMargins(0, 0, 0, 0)
|
self.category_grid.setContentsMargins(0, 0, 0, 0)
|
||||||
self.category_grid.setHorizontalSpacing(4)
|
self.category_grid.setHorizontalSpacing(0)
|
||||||
self.category_grid.setVerticalSpacing(5)
|
self.category_grid.setVerticalSpacing(3)
|
||||||
|
self.category_grid.setColumnStretch(0, 1)
|
||||||
|
self.category_rows = {}
|
||||||
layout.addLayout(self.category_grid)
|
layout.addLayout(self.category_grid)
|
||||||
self.add_category_button = QPushButton("添加自定义分类")
|
self.add_category_button = QPushButton("添加自定义分类")
|
||||||
self.add_category_button.setObjectName("suiteAddCategoryButton")
|
self.add_category_button.setObjectName("suiteAddCategoryButton")
|
||||||
@@ -1650,81 +1759,24 @@ class ProductSuiteTab(QWidget):
|
|||||||
state.settings = settings
|
state.settings = settings
|
||||||
categories = settings["categories"]
|
categories = settings["categories"]
|
||||||
ordered = product_suite.category_order(settings)
|
ordered = product_suite.category_order(settings)
|
||||||
if state.active_category not in ordered:
|
self.category_rows = {}
|
||||||
state.active_category = ordered[0]
|
|
||||||
for index, name in enumerate(ordered):
|
for index, name in enumerate(ordered):
|
||||||
name_button = CategoryChipButton("%s %s" % (name, categories.get(name, 0)))
|
custom = name not in product_suite.FIXED_CATEGORIES
|
||||||
name_button.setCheckable(True)
|
row = SuiteCategoryRow(
|
||||||
name_button.setChecked(name == state.active_category)
|
name,
|
||||||
name_button.setMinimumHeight(30)
|
categories.get(name, 0),
|
||||||
name_button.setStyleSheet(
|
helper=FIXED_CATEGORY_HELPERS.get(name, ""),
|
||||||
"QPushButton { text-align: center; padding: 3px 7px; }"
|
custom=custom,
|
||||||
"QPushButton:checked { background: #eaf2ff; border-color: #2f6fed; color: #2459c4; }"
|
|
||||||
)
|
)
|
||||||
name_button.clicked.connect(
|
row.countChangeRequested.connect(self.change_category_count)
|
||||||
lambda checked=False, category=name: self.select_category(category)
|
if custom:
|
||||||
)
|
row.renameRequested.connect(self.rename_custom_category)
|
||||||
if name not in product_suite.FIXED_CATEGORIES:
|
row.deleteRequested.connect(self.delete_custom_category)
|
||||||
name_button.setToolTip("单击展开数量;双击重命名")
|
row.set_controls_enabled(not state.generation_running())
|
||||||
name_button.doubleClicked.connect(
|
self.category_rows[name] = row
|
||||||
lambda old_name=name: self.rename_custom_category(old_name)
|
self.category_grid.addWidget(row, index, 0)
|
||||||
)
|
|
||||||
else:
|
|
||||||
name_button.setToolTip("单击展开数量")
|
|
||||||
self.category_grid.addWidget(name_button, index // 3, index % 3)
|
|
||||||
|
|
||||||
detail_row = (len(ordered) + 2) // 3
|
|
||||||
active_name = state.active_category
|
|
||||||
detail = QFrame()
|
|
||||||
detail.setObjectName("suiteCategoryCounter")
|
|
||||||
detail_layout = QHBoxLayout(detail)
|
|
||||||
detail_layout.setContentsMargins(6, 3, 6, 3)
|
|
||||||
active_label = QLabel(active_name)
|
|
||||||
active_label.setStyleSheet("font-weight: 600;")
|
|
||||||
detail_layout.addWidget(active_label)
|
|
||||||
detail_layout.addStretch(1)
|
|
||||||
minus = QToolButton()
|
|
||||||
minus.setText("−")
|
|
||||||
minus.setToolTip("减少%s数量" % active_name)
|
|
||||||
minus.setAccessibleName("减少%s数量" % active_name)
|
|
||||||
minus.setMinimumSize(28, 28)
|
|
||||||
minus.clicked.connect(
|
|
||||||
lambda checked=False, category=active_name: self.change_category_count(category, -1)
|
|
||||||
)
|
|
||||||
detail_layout.addWidget(minus)
|
|
||||||
count_label = QLabel(str(categories.get(active_name, 0)))
|
|
||||||
count_label.setAlignment(Qt.AlignCenter)
|
|
||||||
count_label.setMinimumWidth(28)
|
|
||||||
detail_layout.addWidget(count_label)
|
|
||||||
plus = QToolButton()
|
|
||||||
plus.setText("+")
|
|
||||||
plus.setToolTip("增加%s数量" % active_name)
|
|
||||||
plus.setAccessibleName("增加%s数量" % active_name)
|
|
||||||
plus.setMinimumSize(28, 28)
|
|
||||||
plus.clicked.connect(
|
|
||||||
lambda checked=False, category=active_name: self.change_category_count(category, 1)
|
|
||||||
)
|
|
||||||
detail_layout.addWidget(plus)
|
|
||||||
if active_name not in product_suite.FIXED_CATEGORIES:
|
|
||||||
remove = QToolButton()
|
|
||||||
remove.setText("×")
|
|
||||||
remove.setToolTip("删除%s分类" % active_name)
|
|
||||||
remove.setAccessibleName("删除%s分类" % active_name)
|
|
||||||
remove.setMinimumSize(28, 28)
|
|
||||||
remove.clicked.connect(
|
|
||||||
lambda checked=False, category=active_name: self.delete_custom_category(category)
|
|
||||||
)
|
|
||||||
detail_layout.addWidget(remove)
|
|
||||||
self.category_grid.addWidget(detail, detail_row, 0, 1, 3)
|
|
||||||
self._refresh_totals(state)
|
self._refresh_totals(state)
|
||||||
|
|
||||||
def select_category(self, name):
|
|
||||||
state = self._displayed_state
|
|
||||||
if state is None:
|
|
||||||
return
|
|
||||||
state.active_category = str(name)
|
|
||||||
self._rebuild_categories(state)
|
|
||||||
|
|
||||||
def change_category_count(self, name, delta):
|
def change_category_count(self, name, delta):
|
||||||
state = self._displayed_state
|
state = self._displayed_state
|
||||||
if state is None:
|
if state is None:
|
||||||
@@ -1735,7 +1787,12 @@ class ProductSuiteTab(QWidget):
|
|||||||
settings["categories"] = categories
|
settings["categories"] = categories
|
||||||
state.settings = settings
|
state.settings = settings
|
||||||
self._persist_state(state)
|
self._persist_state(state)
|
||||||
self._rebuild_categories(state)
|
row = self.category_rows.get(name) if state is self._displayed_state else None
|
||||||
|
if row is None:
|
||||||
|
self._rebuild_categories(state)
|
||||||
|
else:
|
||||||
|
row.set_count(categories[name])
|
||||||
|
self._refresh_totals(state)
|
||||||
|
|
||||||
def add_custom_category(self, checked=False):
|
def add_custom_category(self, checked=False):
|
||||||
if self._displayed_state is None:
|
if self._displayed_state is None:
|
||||||
@@ -1761,7 +1818,6 @@ class ProductSuiteTab(QWidget):
|
|||||||
settings["categories"] = categories
|
settings["categories"] = categories
|
||||||
settings["custom_category_order"] = list(settings["custom_category_order"]) + [name]
|
settings["custom_category_order"] = list(settings["custom_category_order"]) + [name]
|
||||||
state.settings = product_suite.normalize_suite_settings(settings)
|
state.settings = product_suite.normalize_suite_settings(settings)
|
||||||
state.active_category = name
|
|
||||||
self._persist_state(state)
|
self._persist_state(state)
|
||||||
self.custom_category_edit.hide()
|
self.custom_category_edit.hide()
|
||||||
self.add_category_button.show()
|
self.add_category_button.show()
|
||||||
@@ -1798,7 +1854,6 @@ class ProductSuiteTab(QWidget):
|
|||||||
for value in settings["custom_category_order"]
|
for value in settings["custom_category_order"]
|
||||||
]
|
]
|
||||||
state.settings = product_suite.normalize_suite_settings(settings)
|
state.settings = product_suite.normalize_suite_settings(settings)
|
||||||
state.active_category = name
|
|
||||||
self._persist_state(state)
|
self._persist_state(state)
|
||||||
self._rebuild_categories(state)
|
self._rebuild_categories(state)
|
||||||
|
|
||||||
@@ -1814,7 +1869,6 @@ class ProductSuiteTab(QWidget):
|
|||||||
value for value in settings["custom_category_order"] if value != name
|
value for value in settings["custom_category_order"] if value != name
|
||||||
]
|
]
|
||||||
state.settings = product_suite.normalize_suite_settings(settings)
|
state.settings = product_suite.normalize_suite_settings(settings)
|
||||||
state.active_category = product_suite.FIXED_CATEGORIES[0]
|
|
||||||
self._persist_state(state)
|
self._persist_state(state)
|
||||||
self._rebuild_categories(state)
|
self._rebuild_categories(state)
|
||||||
|
|
||||||
@@ -2064,8 +2118,11 @@ class ProductSuiteTab(QWidget):
|
|||||||
self.per_image_checkbox,
|
self.per_image_checkbox,
|
||||||
self.prompt_edit,
|
self.prompt_edit,
|
||||||
self.add_category_button,
|
self.add_category_button,
|
||||||
|
self.custom_category_edit,
|
||||||
):
|
):
|
||||||
widget.setEnabled(not generation_running)
|
widget.setEnabled(not generation_running)
|
||||||
|
for row in self.category_rows.values():
|
||||||
|
row.set_controls_enabled(not generation_running)
|
||||||
self.generate_button.setEnabled(True)
|
self.generate_button.setEnabled(True)
|
||||||
if generation_running:
|
if generation_running:
|
||||||
self.generate_button.setText("停止生成")
|
self.generate_button.setText("停止生成")
|
||||||
|
|||||||
+6
-1
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: T-634
|
id: T-634
|
||||||
title: 商品套图结构配置改为纵向独立计数行
|
title: 商品套图结构配置改为纵向独立计数行
|
||||||
status: TODO
|
status: DONE
|
||||||
phase: 7
|
phase: 7
|
||||||
deps: [T-622, T-631]
|
deps: [T-622, T-631]
|
||||||
created: 2026-07-14
|
created: 2026-07-14
|
||||||
@@ -95,3 +95,8 @@ git diff --check
|
|||||||
- 不修改数据库、API、CDP 或其他标签页。
|
- 不修改数据库、API、CDP 或其他标签页。
|
||||||
|
|
||||||
## 执行记录
|
## 执行记录
|
||||||
|
- 2026-07-16:新增 `SuiteCategoryRow`,三个默认分类改为各占一行,准确显示固定用途说明与独立的减少/数量/增加控件;自定义分类同样独占一行并显示改名、删除操作。
|
||||||
|
- 2026-07-16:移除 `CategoryChipButton`、`active_category`、`select_category` 和共享详情计数器。普通数量变化只更新目标行、合计和生成按钮;新增、改名、删除时重建分类行,数量下限为 0 且减少按钮在 0 时禁用。
|
||||||
|
- 2026-07-16:生成期间统一禁用各分类步进器及自定义分类编辑;保留原有分类顺序、默认 `1/2/2`、项目设置持久化和生成 job 展开语义。
|
||||||
|
- 2026-07-16:补充纵向布局、固定说明、独立计数、0 下限、生成中禁用、自定义分类增删改、任务切换和项目重载测试;`1180x760` 离屏截图确认三行说明与控件无重叠,页面继续使用既有外层滚动区。
|
||||||
|
- 验证:当前工作区 `tests.test_product_suite_gui` 11 项、`tests.test_product_suite` 4 项通过,ruff、compileall、`git diff --check` 通过;基于 T-610 提交创建隔离 worktree 后,全仓 ruff、compileall、501 项 unittest 和 `git diff --check` 全部通过。
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
@@ -166,7 +167,161 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase):
|
|||||||
tab._commit_custom_category()
|
tab._commit_custom_category()
|
||||||
self.assertTrue(tab.custom_category_edit.isHidden())
|
self.assertTrue(tab.custom_category_edit.isHidden())
|
||||||
self.assertIn("尺寸图", tab._displayed_state.settings["categories"])
|
self.assertIn("尺寸图", tab._displayed_state.settings["categories"])
|
||||||
self.assertEqual("尺寸图", tab._displayed_state.active_category)
|
self.assertEqual(1, tab.category_rows["尺寸图"].count())
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_category_rows_are_vertical_with_helpers_and_independent_counters(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
config = self._config(temp_dir)
|
||||||
|
tab = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||||
|
self.addCleanup(tab.close)
|
||||||
|
tab.resize(1180, 760)
|
||||||
|
tab.show()
|
||||||
|
self.app.processEvents()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"白底图": (1, "白底主图,多角度呈现商品细节"),
|
||||||
|
"场景图": (2, "生活化场景展示商品使用方式"),
|
||||||
|
"卖点图": (2, "突出核心卖点和差异化优势"),
|
||||||
|
}
|
||||||
|
self.assertEqual(list(expected), list(tab.category_rows))
|
||||||
|
for row_index, (name, (count, helper)) in enumerate(expected.items()):
|
||||||
|
row = tab.category_rows[name]
|
||||||
|
layout_index = tab.category_grid.indexOf(row)
|
||||||
|
self.assertEqual(
|
||||||
|
(row_index, 0, 1, 1),
|
||||||
|
tab.category_grid.getItemPosition(layout_index),
|
||||||
|
)
|
||||||
|
self.assertEqual(name, row.name_label.text())
|
||||||
|
self.assertEqual(count, row.count())
|
||||||
|
self.assertEqual(helper, row.helper_label.text())
|
||||||
|
self.assertIsNone(row.rename_button)
|
||||||
|
self.assertIsNone(row.delete_button)
|
||||||
|
|
||||||
|
scene_row = tab.category_rows["场景图"]
|
||||||
|
scene_row.plus_button.click()
|
||||||
|
self.assertIs(scene_row, tab.category_rows["场景图"])
|
||||||
|
self.assertEqual(3, scene_row.count())
|
||||||
|
self.assertEqual(1, tab.category_rows["白底图"].count())
|
||||||
|
self.assertEqual(2, tab.category_rows["卖点图"].count())
|
||||||
|
self.assertEqual("合计 6 张", tab.category_total_label.text())
|
||||||
|
self.assertEqual("生成套图(6)", tab.generate_button.text())
|
||||||
|
|
||||||
|
white_row = tab.category_rows["白底图"]
|
||||||
|
white_row.minus_button.click()
|
||||||
|
self.assertEqual(0, white_row.count())
|
||||||
|
self.assertFalse(white_row.minus_button.isEnabled())
|
||||||
|
white_row.minus_button.click()
|
||||||
|
self.assertEqual(0, tab._displayed_state.settings["categories"]["白底图"])
|
||||||
|
self.assertEqual("合计 5 张", tab.category_total_label.text())
|
||||||
|
|
||||||
|
tab._displayed_state.worker = object()
|
||||||
|
tab._apply_running_state(tab._displayed_state)
|
||||||
|
self.assertTrue(
|
||||||
|
all(
|
||||||
|
not row.plus_button.isEnabled()
|
||||||
|
for row in tab.category_rows.values()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tab._displayed_state.worker = None
|
||||||
|
tab._apply_running_state(tab._displayed_state)
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_custom_category_row_preserves_count_and_order_when_renamed(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
config = self._config(temp_dir)
|
||||||
|
tab = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||||
|
self.addCleanup(tab.close)
|
||||||
|
|
||||||
|
fixed_counts = {
|
||||||
|
name: tab.category_rows[name].count()
|
||||||
|
for name in ("白底图", "场景图", "卖点图")
|
||||||
|
}
|
||||||
|
tab.add_custom_category()
|
||||||
|
tab.custom_category_edit.setText("尺寸图")
|
||||||
|
tab._commit_custom_category()
|
||||||
|
custom_row = tab.category_rows["尺寸图"]
|
||||||
|
self.assertEqual(1, custom_row.count())
|
||||||
|
self.assertIsNone(custom_row.helper_label)
|
||||||
|
self.assertIsNotNone(custom_row.rename_button)
|
||||||
|
self.assertIsNotNone(custom_row.delete_button)
|
||||||
|
|
||||||
|
custom_row.plus_button.click()
|
||||||
|
self.assertEqual(2, custom_row.count())
|
||||||
|
with mock.patch(
|
||||||
|
"app.gui.tabs.product_suite.QInputDialog.getText",
|
||||||
|
return_value=("规格图", True),
|
||||||
|
):
|
||||||
|
custom_row.rename_button.click()
|
||||||
|
self.assertNotIn("尺寸图", tab.category_rows)
|
||||||
|
self.assertEqual(2, tab.category_rows["规格图"].count())
|
||||||
|
self.assertEqual(
|
||||||
|
["规格图"],
|
||||||
|
tab._displayed_state.settings["custom_category_order"],
|
||||||
|
)
|
||||||
|
|
||||||
|
tab.category_rows["规格图"].delete_button.click()
|
||||||
|
self.assertNotIn("规格图", tab.category_rows)
|
||||||
|
self.assertEqual([], tab._displayed_state.settings["custom_category_order"])
|
||||||
|
self.assertEqual(
|
||||||
|
fixed_counts,
|
||||||
|
{
|
||||||
|
name: tab.category_rows[name].count()
|
||||||
|
for name in ("白底图", "场景图", "卖点图")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
def test_category_counts_restore_after_task_switch_and_project_reload(self):
|
||||||
|
with self.make_temp_dir() as temp_dir:
|
||||||
|
config = self._config(temp_dir)
|
||||||
|
account = accounts.create_account(
|
||||||
|
"主店",
|
||||||
|
"alias-a",
|
||||||
|
debug_port=9222,
|
||||||
|
config=config,
|
||||||
|
)
|
||||||
|
project = image_studio.create_or_get_project(
|
||||||
|
account,
|
||||||
|
item_id="51100639510",
|
||||||
|
path=config["db_path"],
|
||||||
|
)
|
||||||
|
first = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||||
|
state = first._displayed_state
|
||||||
|
state.account_alias = "alias-a"
|
||||||
|
state.item_id = "51100639510"
|
||||||
|
state.project_id = project.id
|
||||||
|
first.change_category_count("场景图", 1)
|
||||||
|
first.add_custom_category()
|
||||||
|
first.custom_category_edit.setText("细节图")
|
||||||
|
first._commit_custom_category()
|
||||||
|
first.category_rows["细节图"].plus_button.click()
|
||||||
|
|
||||||
|
first.add_task(inherit=False)
|
||||||
|
self.assertEqual(2, first.category_rows["场景图"].count())
|
||||||
|
first.task_tabs.setCurrentIndex(0)
|
||||||
|
self.app.processEvents()
|
||||||
|
self.assertEqual(3, first.category_rows["场景图"].count())
|
||||||
|
self.assertEqual(2, first.category_rows["细节图"].count())
|
||||||
|
first.close()
|
||||||
|
first.deleteLater()
|
||||||
|
self.app.processEvents()
|
||||||
|
|
||||||
|
second = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||||
|
self.addCleanup(second.close)
|
||||||
|
reloaded = second._displayed_state
|
||||||
|
reloaded.account_alias = "alias-a"
|
||||||
|
reloaded.item_id = "51100639510"
|
||||||
|
second._bind_project(reloaded, load_existing=True)
|
||||||
|
self.assertEqual(3, second.category_rows["场景图"].count())
|
||||||
|
self.assertEqual(2, second.category_rows["细节图"].count())
|
||||||
|
self.assertEqual(
|
||||||
|
["细节图"],
|
||||||
|
reloaded.settings["custom_category_order"],
|
||||||
|
)
|
||||||
|
|
||||||
self.assert_removed(temp_dir)
|
self.assert_removed(temp_dir)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user