Files
cmbuyer/docs/tasks/T-202.md
T

76 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-202
title: 手工建单与 DRAFT 基础列表
phase: 2
deps: [T-201, T-004, T-005]
status: DONE
created: 2026-08-04
vikunja_task_id: 27
context_ref: 1c35155
work_branch: task/t-202-admin-draft
needs_device: false
needs_human_review: false
write_paths:
- docs/tasks/T-202.md
- admin/cmd/server/main.go
- admin/internal/config/**
- admin/internal/server/**
- admin/internal/tasks/**
- admin/internal/storage/sqlite/**
- admin/internal/transport/webui/**
- admin/README.md
---
<!-- BEGIN VIKUNJA EXPORT id=27 synced=2026-08-04T08:32:16Z sha256=39e3b06bab4ca86e97b961a4eb6bb0a4f1e88b29dae4d50f916779f7e761424c -->
## 问题 / 背景
T-201 已提供管理员会话;T-004 已提供 tasks 表。根据 T-010 加速门禁,T-103 尚未完成时只允许实现不启动试选的 DRAFT 手工建单与基础列表。
## 关联需求与交互
F-001、US-001、IX-002;GET /tasks、GET /tasks/new、POST /tasks;沿用已确认的传统表格与创建弹窗/直达页。
## 方案
1. 显式数据库配置并打开已迁移 SQLite;以仓储接口隔离 HTTP 和 SQL,创建事务只写 MANUAL、DRAFT、version=1。
2. 表单校验任务名称、canonical 拼多多链接、颜色分类、尺码、正整数数量和正十进制总额上限;金额只用字符串并规范为两位小数。链接只接受 HTTPS mobile.yangkeduo.com/goods.html 且 goods_id 为唯一纯数字参数,额外查询参数不进入数据库。
3. 以服务端生成的 create_key 同时作为任务 ID;重复相同 key 和相同内容返回原结果,不创建第二条,内容不同则冲突。
4. GET /tasks 默认 created_at DESC 显示 DRAFT 基础表格;创建入口用服务端渲染的 modal 状态,/tasks/new 复用同一表单作为无脚本兜底;失败保留非密码输入并显示字段错误,成功 303 回列表且新任务第一行。
5. 页面只显示需求字段、采购结果占位、DRAFT 状态与创建时间;不读取或伪造规格面板价格/证据,不提供勾选开始试选、状态推进、详情或设备接口。
## 验收要点
- 覆盖创建成功、倒序第一行、严格链接/goods_id、数量、金额、空白/长度、CSRF/未登录、幂等重放与冲突、SQL 错误 fail closed。
- 弹窗与 /tasks/new 共享校验;错误保留输入并可访问;标题只链接到由 goods_id 重建的 canonical PDD URL并使用安全新标签属性。
- go test ./...、go test -race ./...、go vet ./...、go build ./...、完整 init.ps1、上下文校验和 diff-check 通过。
## 执行记录
### 2026-08-04T08:30:47Z · ila
已完成:DRAFT 手工建单与基础列表;已验证链接、金额、CSRF、幂等、SQLite 并发和 SSR 无障碍,Go 与上下文门禁均通过。
<!-- END VIKUNJA EXPORT -->
## 边界
- 本任务只创建 `source=MANUAL`、`status=DRAFT`、`version=1` 的任务并显示 DRAFT 基础列表;不得
实现勾选、批量开始试选、`DRAFT → PENDING` 或任何其他状态流转,也不得新增设备领取接口。
- 不增加或修改数据库 schema,不读写 `spec_trials`、`order_authorizations`、`order_submissions`,
不生成或展示机器实际规格、规格面板单价、截图、证据哈希或 PDD 页面判据。
- 启动服务必须从显式 `CMBUYER_DATABASE_SOURCE` 读取 SQLite data source;缺失时明确失败,不提供
隐式内存库或仓库内默认数据库。服务不自动猜迁移目录;README 必须先给出显式迁移命令。
- 商品链接只接受 `https://mobile.yangkeduo.com/goods.html`,且必须恰有一个纯数字 `goods_id`;
拒绝 userinfo、端口、fragment、重复参数、其他 host/scheme/path 和编码绕过。数据库只保存 goods_id,
展示链接由 goods_id 重建 canonical URL;`uin` 等额外查询参数既不保存也不回显。
- 标题、颜色分类、尺码必须去除首尾空白后非空并受明确长度上限约束;数量必须是可表示的正整数;
总额上限必须是大于零、最多两位小数的十进制字符串并规范为两位小数。金额校验、保存与展示均不得
使用浮点数或从其他数字推测。
- `create_key` 由服务端用 `crypto/rand` 生成并验证格式,同时作为任务 ID;相同 key 与相同规范化内容
重放只能返回原任务,不得二次 INSERT,相同 key 携带不同内容必须冲突。SQL 必须参数化,创建失败
不得留下半条或未知状态记录。
- `GET /tasks`、`GET /tasks/new`、`POST /tasks` 都必须复用 T-201 管理会话;POST 必须验证 CSRF。
校验失败保留非敏感输入并逐字段提示,数据库内部错误只给通用响应,不泄露 SQL、路径或凭据。
- 页面只使用服务端模板转义;标题商品链接在新标签打开时必须带 `noopener noreferrer`。导入按钮只作
禁用占位;不得加载外部资源或把原型假数据、真机数据、地址、手机号带进生产页面。
- 不实现或引用试选、数量设置、订单确认、提交围栏、提交订单、付款、免密支付或先用后付能力。