76 lines
5.0 KiB
Markdown
76 lines
5.0 KiB
Markdown
---
|
||
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`。导入按钮只作
|
||
禁用占位;不得加载外部资源或把原型假数据、真机数据、地址、手机号带进生产页面。
|
||
- 不实现或引用试选、数量设置、订单确认、提交围栏、提交订单、付款、免密支付或先用后付能力。
|