"""PDD 任务页的界面结构。 这一页显示**本机已领取的全部任务**(正在做的和早已做完的), 提供搜索、筛选、详情,以及启动/停止自动获取。 完整规范见 `docs/client/05-ui-specification.md`。 改动本文件前必读 `client/AGENTS.md`。以下几条最容易踩: - 本文件只负责显示和把用户操作转发出去,**不写业务逻辑**, 不发 Admin 请求、不查数据库、不碰手机。这些放 `pdd_ui_event.py`。 - 任务表格必须用**模型/视图**(`QAbstractTableModel` + `TableView`), 并用 `remote_task_id` 作为任务身份。**不要用表格行号**—— 行号会随排序和筛选变化,拿它当身份必出错。 - 不要为每个单元格创建常驻 `QWidget`(几万行会把内存吃光)。 “详情”那一列用委托绘制。 - 不要把完整的 `pdd_data` 放进表格模型,那是详情数据, 查看详情时再从数据库读。 - 表格数据只增不减(已完成任务永久保留),所以增量加载是必须的, 照抄 `docs/client/05-ui-specification.md` §5.3 的模板。 - 空状态要分情况:从没领过任务、筛选无结果、加载失败,文案不能一样。 - 图标用 `FluentIcon`,**不得用表情符号**。 - 页面 `objectName` 固定为 `pddTaskPage`,不要改。 注意:本页唯一会产生外部后果(真的去操作手机、可能下单)的命令是 “开始自动获取”。其余操作全部只读本地数据库。 """ from PyQt5.QtWidgets import ( QGridLayout, QHBoxLayout, QSizePolicy, QVBoxLayout, QWidget, ) from qfluentwidgets import ( CaptionLabel, CardWidget, FluentIcon as FIF, LineEdit, PrimaryPushButton, SubtitleLabel, TitleLabel, ) class PDDTaskPage(QWidget): """商品与规格配置页。""" def __init__(self, parent=None): super().__init__(parent) self.setObjectName("pddTaskPage") self.goodsInput = LineEdit(self) self.goodsInput.setPlaceholderText("输入拼多多商品链接或商品 ID") self.goodsInput.setClearButtonEnabled(True) self.goodsInput.setAccessibleName("商品链接或商品 ID") self.colorInput = LineEdit(self) self.colorInput.setPlaceholderText("例如:黑色") self.colorInput.setClearButtonEnabled(True) self.colorInput.setAccessibleName("目标颜色") self.sizeInput = LineEdit(self) self.sizeInput.setPlaceholderText("例如:L") self.sizeInput.setClearButtonEnabled(True) self.sizeInput.setAccessibleName("目标尺码") self.startButton = PrimaryPushButton(FIF.PLAY, "开始任务", self) self.startButton.setAccessibleName("开始自动购买任务") self.statusLabel = CaptionLabel("等待启动", self) card = CardWidget(self) card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) cardLayout = QVBoxLayout(card) cardLayout.setContentsMargins(24, 20, 24, 22) cardLayout.setSpacing(12) cardLayout.addWidget(SubtitleLabel("创建任务", card)) cardLayout.addWidget(CaptionLabel("商品链接 / ID", card)) cardLayout.addWidget(self.goodsInput) specLayout = QGridLayout() specLayout.setHorizontalSpacing(16) specLayout.setVerticalSpacing(8) specLayout.addWidget(CaptionLabel("颜色", card), 0, 0) specLayout.addWidget(CaptionLabel("尺码", card), 0, 1) specLayout.addWidget(self.colorInput, 1, 0) specLayout.addWidget(self.sizeInput, 1, 1) specLayout.setColumnStretch(0, 1) specLayout.setColumnStretch(1, 1) cardLayout.addLayout(specLayout) actionLayout = QHBoxLayout() actionLayout.setContentsMargins(0, 6, 0, 0) actionLayout.addWidget(self.statusLabel) actionLayout.addStretch(1) actionLayout.addWidget(self.startButton) cardLayout.addLayout(actionLayout) layout = QVBoxLayout(self) layout.setContentsMargins(36, 30, 36, 36) layout.setSpacing(16) layout.addWidget(TitleLabel("pdd任务", self)) # description = BodyLabel("配置商品与目标规格,然后启动自动化任务。", self) # description.setWordWrap(True) # layout.addWidget(description) layout.addWidget(card) layout.addStretch(1)