fix(ai-outfit): 货号(B列)改为可选,空货号不再跳过整行 (§19.14)

用户表的「商品id(货号)」整列为空时,行有效性判定(标题+货号+图三者非空)
把每一行都判为不完整 → read_all_rows 与 load_outfit_tasks 都返回 0:预览下拉
只剩占位符,且「开始生成」也判定无待处理行。货号不进提示词、目录行输出名沿用
源图名,对该用法是多余约束。

- excel_service.py: read_all_rows / load_outfit_tasks 完整性判定改为只要求
  标题 + 衣服图路径 非空,货号可空(状态过滤不变)
- core/ai_outfit.py: 单文件行货号为空时输出名回退 Path(garment).stem
  (货号非空仍用 货号.jpg);目录行不变
- ai_outfit_panel.py: 样本下拉标签货号为空显示「(无货号)」
- tests: 空货号行被 read_all_rows/load_outfit_tasks 收录、单文件空货号按源图名命名
- docs/11 §4(表+规则)/§9(命名回退)、tasks.md §19.14

离屏冒烟:标题填/货号空/C=目录 → 预览下拉有行、生成产出到子目录、E=完成;
全套测试在 Python 3.7 全绿(test_config_service 的失败属并行的出厂模板工作,与本次无关)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 17:15:05 +08:00
co-authored by Claude Opus 4.8
parent abe46c4aeb
commit 9a61a432d9
7 changed files with 65 additions and 13 deletions
+18
View File
@@ -108,6 +108,24 @@ class TestOutfitExcelService(unittest.TestCase):
self.assertEqual(by_idx[4].status, "失败")
self.assertEqual(by_idx[6].title, " 保留空格 ") # raw text preserved
def test_empty_product_id_rows_are_included(self):
"""货号(B)可空:只要求 标题 + 衣服图路径(docs/11 §4)。"""
from services.excel_service import load_outfit_tasks, read_all_rows
p = self.tmp / "nopid.xlsx"
wb = Workbook()
ws = wb.active
ws.append(["标题", "货号", "衣服图", "结果", "状态", "原因"])
ws.append(["有标题无货号", "", r"D:\img\a.png", "", "", ""]) # 收录
ws.append(["缺图也缺货号", "", "", "", "", ""]) # 缺图 → 仍跳过
wb.save(str(p))
wb.close()
tasks = load_outfit_tasks(p)
self.assertEqual([t.row_index for t in tasks], [2])
self.assertEqual(tasks[0].product_id, "")
self.assertEqual([r.row_index for r in read_all_rows(p)], [2])
def test_check_excel_writable_true_for_existing_workbook(self):
from services.excel_service import check_excel_writable