feat: 支持采购任务追溯并安全重新创建 (#186)

This commit is contained in:
chengma
2026-08-12 16:26:22 +08:00
parent 836aad5c26
commit 69bcf6116a
13 changed files with 298 additions and 57 deletions
+41 -6
View File
@@ -12,6 +12,7 @@ import (
"database/sql"
"encoding/json"
"fmt"
"net/url"
"sort"
"strings"
@@ -456,7 +457,8 @@ const resultDataLimit = 4000
// TaskDetailView 是双击弹窗要显示的全部内容。
//
// `[必须]` 只读——本工单不做改派、重试、取消,弹窗里不应该有对应的表单。
// `[必须]` 字段只读——弹窗不直接改派、重试、取消或创建任务;安全恢复只导航
// 回原顺运宝明细,真正创建仍走原确认表单和服务端门禁。
type TaskDetailView struct {
TaskID string
TypeText string
@@ -471,12 +473,20 @@ type TaskDetailView struct {
PddGoodsURL string
PddShopText string
// IsPurchase 为 false 时,模板要把下面四个采购专有字段整段隐藏,
// IsPurchase 为 false 时,模板要把下面的采购专有字段整段隐藏,
// 不能显示空行——见 #19。
IsPurchase bool
SpecText string
QuantityText string
PriceLimitText string
IsPurchase bool
ShopeeOrderNo string
SybID string
ShopeeGoodsID string
PddGoodsID string
HasSybSource bool
ViewSybURL string
CanRecreatePurchase bool
RecreatePurchaseURL string
SpecText string
QuantityText string
PriceLimitText string
// PDD 核单结果只在采购任务详情显示。付款状态是 Client 核单上报时的快照,
// 不是 Admin 对 PDD 的实时查询结果。
@@ -522,6 +532,18 @@ func GetTaskDetail(db *sql.DB, taskID string) (*TaskDetailView, error) {
IsPurchase: t.TaskType == model.TaskPurchase,
}
if v.IsPurchase {
v.ShopeeOrderNo = orPlaceholder(t.OrderNo)
v.SybID = orPlaceholder(t.SybID)
v.ShopeeGoodsID = orPlaceholder(t.GoodsID)
v.PddGoodsID = orPlaceholder(t.PddGoodsID)
v.HasSybSource = strings.TrimSpace(t.SybID) != ""
if v.HasSybSource {
v.ViewSybURL = taskSybURL(*t, false)
v.CanRecreatePurchase = t.Status == model.TaskFailed || t.Status == model.TaskCancelled
if v.CanRecreatePurchase {
v.RecreatePurchaseURL = taskSybURL(*t, true)
}
}
v.SpecText = specText(t.PddOptions)
v.QuantityText = quantityText(t.Quantity)
v.PriceLimitText = priceLimitText(t.MaxPriceCent)
@@ -541,6 +563,19 @@ func GetTaskDetail(db *sql.DB, taskID string) (*TaskDetailView, error) {
return v, nil
}
// taskSybURL 生成采购任务来源的稳定深链接。syb_id 用于精确定位;订单号只负责
// 让跳转后的列表保留有意义的上下文,不能拿它代替明细主键。
func taskSybURL(task model.Task, purchaseIntent bool) string {
values := url.Values{"open_syb_id": {task.SybID}}
if strings.TrimSpace(task.OrderNo) != "" {
values.Set("order_no", task.OrderNo)
}
if purchaseIntent {
values.Set("purchase_intent", "1")
}
return "/syb?" + values.Encode()
}
// GetTaskDetailForUser 对采购员隐藏其他人和历史任务,统一表现为不存在。
func GetTaskDetailForUser(db *sql.DB, actor *model.User, taskID string) (*TaskDetailView, error) {
visibleUserID, err := visibleClientUserID(actor)