feat: 采购详情展示 PDD 核单结果 (#125)
This commit is contained in:
@@ -84,6 +84,22 @@ func TestPddDetailRecollect_使用独立入口并可选客户端(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaskDetail_采购核单结果使用独立只读分组(t *testing.T) {
|
||||
content, err := os.ReadFile("templates/task/detail_modal.html")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
page := string(content)
|
||||
for _, want := range []string{
|
||||
"PDD 核单结果", "PDD 订单编号", "下单时间", "上报时付款状态",
|
||||
"{{if .IsPurchase}}", "{{if .HasPddOrder}}", "完整结果(result_data)",
|
||||
} {
|
||||
if !strings.Contains(page, want) {
|
||||
t.Errorf("采购任务详情缺少 %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatesAndRoutesCanBeBuiltWithoutDatabaseConnection(t *testing.T) {
|
||||
if _, err := newRouter(nil); err != nil {
|
||||
t.Fatalf("模板或路由组装失败: %v", err)
|
||||
|
||||
@@ -345,6 +345,14 @@ type TaskDetailView struct {
|
||||
QuantityText string
|
||||
PriceLimitText string
|
||||
|
||||
// PDD 核单结果只在采购任务详情显示。付款状态是 Client 核单上报时的快照,
|
||||
// 不是 Admin 对 PDD 的实时查询结果。
|
||||
HasPddOrder bool
|
||||
PddOrderNo string
|
||||
PddOrderedAt string
|
||||
PddPaymentStatusText string
|
||||
PddOrderResultText string
|
||||
|
||||
HasError bool
|
||||
ErrorCode string
|
||||
ErrorMessage string
|
||||
@@ -377,6 +385,7 @@ func GetTaskDetail(db *sql.DB, taskID string) (*TaskDetailView, error) {
|
||||
v.SpecText = specText(t.PddOptions)
|
||||
v.QuantityText = quantityText(t.Quantity)
|
||||
v.PriceLimitText = priceLimitText(t.MaxPriceCent)
|
||||
setPddOrderResult(v, *t)
|
||||
}
|
||||
|
||||
if t.ErrorCode != "" || t.ErrorMessage != "" {
|
||||
@@ -392,6 +401,61 @@ func GetTaskDetail(db *sql.DB, taskID string) (*TaskDetailView, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// purchaseResult 只声明详情页需要展示的字段,避免把 Client 的完整结果结构
|
||||
// 复制到 Admin。其余原始字段仍保存在 result_data 并可在详情底部展开查看。
|
||||
type purchaseResult struct {
|
||||
Purchase *struct {
|
||||
OrderNo string `json:"order_no"`
|
||||
OrderedAt string `json:"ordered_at"`
|
||||
PaymentStatus string `json:"payment_status"`
|
||||
MatchStatus string `json:"match_status"`
|
||||
OrderSubmitted bool `json:"order_submitted"`
|
||||
} `json:"purchase"`
|
||||
}
|
||||
|
||||
// setPddOrderResult 把采购结果翻成模板可直接显示的文字。
|
||||
// 解析失败只影响结构化摘要,不能阻止详情页打开,也不能隐藏原始 result_data。
|
||||
func setPddOrderResult(v *TaskDetailView, task model.Task) {
|
||||
raw := strings.TrimSpace(task.ResultData)
|
||||
if raw == "" {
|
||||
switch task.Status {
|
||||
case model.TaskManualReview:
|
||||
v.PddOrderResultText = "订单结果不确定,请结合错误信息人工核对。"
|
||||
case model.TaskFailed, model.TaskCancelled:
|
||||
v.PddOrderResultText = "任务未产生可展示的 PDD 核单结果。"
|
||||
default:
|
||||
v.PddOrderResultText = "等待 Client 核单上报。"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var result purchaseResult
|
||||
if err := json.Unmarshal([]byte(raw), &result); err != nil || result.Purchase == nil {
|
||||
v.PddOrderResultText = "采购结果格式异常,请展开完整结果进行诊断。"
|
||||
return
|
||||
}
|
||||
p := result.Purchase
|
||||
if p.MatchStatus != "matched" || !p.OrderSubmitted {
|
||||
v.PddOrderResultText = "本次结果没有已匹配的 PDD 订单。"
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(p.OrderNo) == "" || p.PaymentStatus != "unpaid" {
|
||||
v.PddOrderResultText = "采购结果格式异常,请展开完整结果进行诊断。"
|
||||
return
|
||||
}
|
||||
orderedAt, ok := model.ParseISO(strings.TrimSpace(p.OrderedAt))
|
||||
if !ok {
|
||||
v.PddOrderResultText = "采购结果中的下单时间格式异常,请展开完整结果进行诊断。"
|
||||
return
|
||||
}
|
||||
|
||||
v.HasPddOrder = true
|
||||
v.PddOrderNo = strings.TrimSpace(p.OrderNo)
|
||||
v.PddOrderedAt = orderedAt.Local().Format("2006-01-02 15:04")
|
||||
v.PddPaymentStatusText = "未付款(Client 上报时)"
|
||||
v.PddOrderResultText = "Admin 不会查询 PDD 实时付款状态。"
|
||||
}
|
||||
|
||||
func orPlaceholder(s string) string {
|
||||
if s == "" {
|
||||
return placeholder
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmautobuy/admin/model"
|
||||
@@ -368,6 +369,66 @@ func TestGetTaskDetail_采购任务显示专有字段(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_采购成功独立显示PDD核单结果(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
insertTestTask(t, db, testTaskParams{
|
||||
taskID: "PUR-ORDER", taskType: model.TaskPurchase, status: model.TaskSucceeded,
|
||||
resultData: `{"purchase":{"order_no":"PDD-20260810-001","ordered_at":"2026-08-10T11:12:13Z","payment_status":"unpaid","match_status":"matched","order_submitted":true}}`,
|
||||
})
|
||||
|
||||
d, err := GetTaskDetail(db, "PUR-ORDER")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !d.HasPddOrder || d.PddOrderNo != "PDD-20260810-001" {
|
||||
t.Fatalf("PDD 订单编号没有结构化显示: %+v", d)
|
||||
}
|
||||
if d.PddOrderedAt != formatLocalTime("2026-08-10T11:12:13Z") {
|
||||
t.Errorf("UTC 下单时间应转为本地时间,实际 %q", d.PddOrderedAt)
|
||||
}
|
||||
if d.PddPaymentStatusText != "未付款(Client 上报时)" ||
|
||||
d.PddOrderResultText != "Admin 不会查询 PDD 实时付款状态。" {
|
||||
t.Errorf("付款状态说明不明确: status=%q help=%q",
|
||||
d.PddPaymentStatusText, d.PddOrderResultText)
|
||||
}
|
||||
if !d.HasResult || !strings.Contains(d.ResultData, `"order_no":"PDD-20260810-001"`) {
|
||||
t.Error("结构化展示后仍必须保留原始结果")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_核单结果状态分别显示(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
tests := []struct {
|
||||
name string
|
||||
status model.TaskStatus
|
||||
resultData string
|
||||
want string
|
||||
}{
|
||||
{"等待上报", model.TaskClaimed, "", "等待 Client 核单上报。"},
|
||||
{"人工处理", model.TaskManualReview, "", "订单结果不确定,请结合错误信息人工核对。"},
|
||||
{"非法JSON", model.TaskSucceeded, `{`, "采购结果格式异常,请展开完整结果进行诊断。"},
|
||||
{"缺少purchase", model.TaskSucceeded, `{}`, "采购结果格式异常,请展开完整结果进行诊断。"},
|
||||
{"尚未匹配", model.TaskSucceeded, `{"purchase":{"match_status":"not_found"}}`, "本次结果没有已匹配的 PDD 订单。"},
|
||||
{"时间非法", model.TaskSucceeded, `{"purchase":{"order_no":"PDD-1","ordered_at":"2026-08-10 11:12","payment_status":"unpaid","match_status":"matched","order_submitted":true}}`, "采购结果中的下单时间格式异常,请展开完整结果进行诊断。"},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
taskID := fmt.Sprintf("PUR-STATE-%d", i)
|
||||
insertTestTask(t, db, testTaskParams{
|
||||
taskID: taskID, taskType: model.TaskPurchase,
|
||||
status: tc.status, resultData: tc.resultData,
|
||||
})
|
||||
d, err := GetTaskDetail(db, taskID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.HasPddOrder || d.PddOrderResultText != tc.want {
|
||||
t.Errorf("状态说明不对: HasPddOrder=%t text=%q", d.HasPddOrder, d.PddOrderResultText)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_采集任务不带采购专有字段(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
insertTestTask(t, db, testTaskParams{taskID: "COL-1", taskType: model.TaskCollect, status: model.TaskPending, pddGoodsID: "111"})
|
||||
@@ -382,6 +443,9 @@ func TestGetTaskDetail_采集任务不带采购专有字段(t *testing.T) {
|
||||
if d.SpecText != "" || d.QuantityText != "" || d.PriceLimitText != "" {
|
||||
t.Errorf("采集任务不该填充采购专有字段: spec=%q qty=%q price=%q", d.SpecText, d.QuantityText, d.PriceLimitText)
|
||||
}
|
||||
if d.HasPddOrder || d.PddOrderResultText != "" {
|
||||
t.Error("采集任务不应生成 PDD 核单结果展示")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_有错误信息时显示(t *testing.T) {
|
||||
|
||||
@@ -34,6 +34,20 @@
|
||||
{{end}}
|
||||
</dl>
|
||||
|
||||
{{if .IsPurchase}}
|
||||
<h3>PDD 核单结果</h3>
|
||||
{{if .HasPddOrder}}
|
||||
<dl class="detail">
|
||||
<dt>PDD 订单编号</dt><dd>{{.PddOrderNo}}</dd>
|
||||
<dt>下单时间</dt><dd>{{.PddOrderedAt}}</dd>
|
||||
<dt>上报时付款状态</dt><dd>{{.PddPaymentStatusText}}</dd>
|
||||
</dl>
|
||||
<p class="hint">{{.PddOrderResultText}}</p>
|
||||
{{else}}
|
||||
<p class="hint">{{.PddOrderResultText}}</p>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .HasError}}
|
||||
<h3>错误</h3>
|
||||
<dl class="detail">
|
||||
|
||||
@@ -306,6 +306,11 @@ PDD 商品之所以单独一个模块,是因为它在数据上就是**独立
|
||||
(PDD 链接,采购任务额外显示目标规格、数量、价格上限);错误信息
|
||||
(错误码、错误说明,没有错误时不显示这一段)。
|
||||
|
||||
采购任务额外显示独立的“PDD 核单结果”:PDD 订单编号、下单时间和
|
||||
“上报时付款状态”。这些字段从现有 `result_data.purchase` 读取;下单时间转换为
|
||||
Admin 本地时区,付款状态只是 Client 核单上报时的快照,Admin 不查询 PDD 实时状态。
|
||||
尚未上报、订单结果不确定和结果格式异常必须使用不同的明确文字;异常时仍保留原始结果。
|
||||
|
||||
`[必须]` 采购专有字段(数量、价格上限、目标规格)在采集任务的弹窗里
|
||||
**整段隐藏**,不显示空行。
|
||||
|
||||
|
||||
@@ -656,6 +656,12 @@ placeholder 写「任务编号 / 订单号 / 商品 ID」,**不要写全「PDD
|
||||
│ 数量 2 (采购任务才有) │
|
||||
│ 价格上限 ¥42.00 (采购任务才有) │
|
||||
├──────────────────────────────────────────────┤
|
||||
│ PDD 核单结果 (采购任务才有) │
|
||||
│ PDD 订单编号 PDD-20260810-001 │
|
||||
│ 下单时间 2026-08-10 19:12 │
|
||||
│ 上报时付款状态 未付款(Client 上报时) │
|
||||
│ Admin 不会查询 PDD 实时付款状态。 │
|
||||
├──────────────────────────────────────────────┤
|
||||
│ 错误 │
|
||||
│ 错误码 PDD_PAGE_TIMEOUT │
|
||||
│ 错误说明 商品页加载超时 │
|
||||
@@ -666,6 +672,10 @@ placeholder 写「任务编号 / 订单号 / 商品 ID」,**不要写全「PDD
|
||||
|
||||
- `[必须]` 采购专有字段(数量、价格上限、目标规格)在采集任务的弹窗里
|
||||
**整段隐藏**,不显示空行。
|
||||
- PDD 核单结果只在采购任务显示,订单编号使用可选择复制的普通文本;付款状态标签
|
||||
必须包含“上报时”,不能暗示为实时状态。
|
||||
- 尚未上报显示“等待 Client 核单上报”;需人工时显示“订单结果不确定”;结果结构或
|
||||
带时区时间非法时显示格式异常,并引导展开完整结果诊断。
|
||||
- 错误段没有错误码/说明时整段不显示。
|
||||
- `[建议]` `result_data`(Client 提交的完整结果)默认折叠,展开查看;
|
||||
过长时截断显示。
|
||||
|
||||
Reference in New Issue
Block a user