feat: 增加商品颜色匹配页面 (#294)

This commit is contained in:
chengma
2026-08-24 00:04:19 +08:00
parent 3cee6cbfaa
commit 8162ae5aca
12 changed files with 697 additions and 1 deletions
+83
View File
@@ -45,6 +45,25 @@ func (h *Handler) ShopeeDetail(c *gin.Context) {
return
}
returnValues := url.Values{}
if value := strings.TrimSpace(c.Query("q")); value != "" {
returnValues.Set("q", value)
}
returnValues.Set("search_field", service.ParseShopeeSearchField(c.Query("search_field")))
if value := service.ParseShopeeStatus(c.Query("status")); value != "" {
returnValues.Set("status", value)
}
if currentUser(c).IsAdmin() && c.Query("deleted") == "1" {
returnValues.Set("deleted", "1")
}
if c.Query("unlinked") == "1" {
returnValues.Set("unlinked", "1")
}
returnValues.Set("page", strconv.Itoa(service.ParsePage(c.Query("page"))))
returnValues.Set("page_size", strconv.Itoa(service.ParsePageSize(c.Query("page_size"))))
returnValues.Set("open_id", goodsID)
colorValues := url.Values{"goods_id": {goodsID}, "return_to": {"/shopee?" + returnValues.Encode()}}
c.HTML(http.StatusOK, "shopee/detail_modal", gin.H{
"D": detail, "CSRFToken": csrfToken(c),
"Keyword": c.Query("q"), "SearchField": service.ParseShopeeSearchField(c.Query("search_field")),
@@ -53,6 +72,7 @@ func (h *Handler) ShopeeDetail(c *gin.Context) {
"UnlinkedFilter": c.Query("unlinked") == "1",
"CurrentPage": service.ParsePage(c.Query("page")),
"CurrentPageSize": service.ParsePageSize(c.Query("page_size")),
"ColorMappingURL": "/shopee/color-mappings?" + colorValues.Encode(),
})
}
@@ -126,6 +146,69 @@ func (h *Handler) renderShopeeList(c *gin.Context, keyword, searchFieldRaw, stat
"DetailURL": "/shopee/detail?" + detailValuesForShopee(values, result.Page),
"AutoOpenDetailID": strings.TrimSpace(c.Query("open_id")),
"AssignableClients": assignableClients,
"ReturnToEscaped": url.QueryEscape(c.Request.URL.RequestURI()),
}))
}
// ShopeeColorMappings 渲染当前蝦皮商品的独立颜色匹配工作区。
func (h *Handler) ShopeeColorMappings(c *gin.Context) {
h.renderShopeeColorMappings(c, strings.TrimSpace(c.Query("goods_id")),
safeNext(c.Query("return_to")), nil, c.Query("msg"), "", http.StatusOK)
}
// ShopeeColorMappingsSave 只接收发生变化的颜色键和目标值;所有业务事实都重新从数据库读取。
func (h *Handler) ShopeeColorMappingsSave(c *gin.Context) {
goodsID := strings.TrimSpace(c.PostForm("goods_id"))
returnTo := safeNext(c.PostForm("return_to"))
colorKeys, targets := c.PostFormArray("color_key"), c.PostFormArray("target_value")
overrides := make(map[string]string, len(colorKeys))
updates := make([]service.ProductColorMappingUpdate, 0, len(colorKeys))
if len(colorKeys) != len(targets) {
h.renderShopeeColorMappings(c, goodsID, returnTo, overrides, "", "提交的颜色行不完整,请刷新后重试。", http.StatusBadRequest)
return
}
for i, key := range colorKeys {
key = strings.TrimSpace(key)
overrides[key] = targets[i]
updates = append(updates, service.ProductColorMappingUpdate{ShopeeColorKey: key, TargetValue: targets[i]})
}
changed, err := service.SaveProductColorMappings(h.db, currentUser(c), goodsID,
c.PostForm("context_version"), updates)
if err != nil {
status, message := http.StatusInternalServerError, "保存颜色映射失败,数据库没有改动。请稍后重试。"
if service.IsValidationError(err) {
status, message = http.StatusConflict, err.Error()
}
h.renderShopeeColorMappings(c, goodsID, returnTo, overrides, "", message, status)
return
}
values := url.Values{"goods_id": {goodsID}, "return_to": {returnTo},
"msg": {fmt.Sprintf("已保存 %d 条颜色修改", changed)}}
c.Redirect(http.StatusSeeOther, "/shopee/color-mappings?"+values.Encode())
}
func (h *Handler) renderShopeeColorMappings(c *gin.Context, goodsID, returnTo string, overrides map[string]string, message, alert string, status int) {
if goodsID == "" {
fail(c, http.StatusBadRequest, "商品编号不对,请返回蝦皮数据页重新选择。")
return
}
context, err := service.GetProductColorMappingContext(h.db, goodsID)
if err != nil {
fail(c, http.StatusInternalServerError, "读取商品颜色匹配数据失败,数据没有被改动。")
return
}
if context == nil {
fail(c, http.StatusNotFound, "这个蝦皮商品不存在或已删除,请返回列表刷新。")
return
}
view := service.BuildProductColorMappingPageView(context, overrides)
statusText := service.ProductColorMappingStatusLine(view)
if message != "" {
statusText = message + " · " + statusText
}
c.HTML(status, "shopee/color_mappings", page(c, "shopee", "颜色匹配", gin.H{
"V": view, "ReturnTo": safeNext(returnTo), "Message": message, "Alert": alert,
"Status": statusText, "PageScript": "/static/js/color_mappings.js",
}))
}
+2
View File
@@ -63,7 +63,9 @@ func Register(r *gin.Engine, db *sql.DB, onlineThreshold time.Duration, aiSecret
// 1. 蝦皮数据
pages.GET("/shopee", h.ShopeeList)
pages.GET("/shopee/detail", h.ShopeeDetail) // 双击行时前端来取弹窗内容
pages.GET("/shopee/color-mappings", h.ShopeeColorMappings)
pages.POST("/shopee/save", h.ShopeeSave)
pages.POST("/shopee/color-mappings/save", h.ShopeeColorMappingsSave)
pages.POST("/shopee/spec/save", h.ShopeeSpecSave)
pages.POST("/shopee/collect", h.ShopeeCollect)
pages.POST("/shopee/collect-batch", h.ShopeeCollectBatch)