feat(media-supply): resource cache sync and order flow refinements
Add a resource cache sync entrypoint (RunMediaResourceSyncOnce) driven by the new scheduler job, and rework the backlink/sync worker around it. Tune the meijiequan client and slow the default backlink sync interval from 10m to 30m to reduce upstream pressure. Trim unused public/transport surface (handler + router + swagger) and simplify admin-web order management and ops-web media-supply views, dropping stale shared-types fields.
This commit is contained in:
@@ -189,6 +189,7 @@ type MeijiequanPublishedArticle struct {
|
||||
Title string
|
||||
ResourceID string
|
||||
ResourceName string
|
||||
PriceCents int64
|
||||
ExternalArticleURL string
|
||||
Status string
|
||||
RejectReason string
|
||||
@@ -1600,13 +1601,18 @@ func parseMeijiequanPublishedArticleMap(item map[string]any) (MeijiequanPublishe
|
||||
if title == "" && articleURL == "" {
|
||||
return MeijiequanPublishedArticle{}, false
|
||||
}
|
||||
orderCode := strings.TrimSpace(meijiequanAnyString(firstMapValue(item, "order_code", "code", "sn", "order_sn", "dingdanhao", "order_no", "orderno", "danhao")))
|
||||
if !isLikelyMeijiequanOrderCode(orderCode) {
|
||||
orderCode = firstMeijiequanOrderCode(orderCode)
|
||||
}
|
||||
raw, _ := json.Marshal(item)
|
||||
return MeijiequanPublishedArticle{
|
||||
OrderID: strings.TrimSpace(meijiequanAnyString(firstMapValue(item, "id", "order_id", "article_id"))),
|
||||
OrderCode: strings.TrimSpace(meijiequanAnyString(firstMapValue(item, "order_code", "code", "sn", "order_sn", "dingdanhao", "order_no", "orderno", "danhao"))),
|
||||
OrderCode: orderCode,
|
||||
Title: title,
|
||||
ResourceID: normalizeMeijiequanPublishedResourceID(meijiequanAnyString(firstMapValue(item, "resource_id", "media_id", "uid", "mid"))),
|
||||
ResourceName: strings.TrimSpace(meijiequanAnyString(firstMapValue(item, "meiti", "media_name", "resource_name", "name"))),
|
||||
PriceCents: firstMeijiequanArticlePriceCents(item),
|
||||
ExternalArticleURL: articleURL,
|
||||
Status: strings.TrimSpace(meijiequanAnyString(firstMapValue(item, "status", "status_text", "state"))),
|
||||
RejectReason: strings.TrimSpace(meijiequanAnyString(firstMapValue(item, "reject_reason", "reason", "tuigao_reason", "tuigaoyuanyin", "refund_reason", "error_message"))),
|
||||
@@ -1732,6 +1738,7 @@ func parseMeijiequanPublishedArticleHTMLRow(row *nethtml.Node, cells []*nethtml.
|
||||
if status == "" {
|
||||
status = extractMeijiequanPublishedStatus(rowText)
|
||||
}
|
||||
priceCents, _ := parsePriceCents(columnValues["价格"])
|
||||
rejectReason := strings.TrimSpace(columnValues["退稿原因"])
|
||||
return MeijiequanPublishedArticle{
|
||||
OrderID: strings.TrimSpace(firstMeijiequanHTMLAttr(row, "data-id", "data-order-id", "data-article-id")),
|
||||
@@ -1739,6 +1746,7 @@ func parseMeijiequanPublishedArticleHTMLRow(row *nethtml.Node, cells []*nethtml.
|
||||
Title: strings.TrimSpace(title),
|
||||
ResourceID: resourceID,
|
||||
ResourceName: resourceName,
|
||||
PriceCents: priceCents,
|
||||
ExternalArticleURL: articleURL,
|
||||
Status: status,
|
||||
RejectReason: rejectReason,
|
||||
@@ -1814,6 +1822,8 @@ func normalizeMeijiequanHeaderName(value string) string {
|
||||
return "订单号"
|
||||
case strings.Contains(value, "资源名称"):
|
||||
return "资源名称"
|
||||
case strings.Contains(value, "价格") || strings.Contains(value, "金额"):
|
||||
return "价格"
|
||||
case strings.Contains(value, "退稿原因"):
|
||||
return "退稿原因"
|
||||
case strings.Contains(value, "状态"):
|
||||
@@ -2091,7 +2101,10 @@ func extractMeijiequanOrderCodeFromText(value string) string {
|
||||
for idx, field := range fields {
|
||||
if strings.Contains(field, "单号") || strings.Contains(strings.ToLower(field), "order") {
|
||||
if idx+1 < len(fields) {
|
||||
return strings.Trim(fields[idx+1], " ::,,;;")
|
||||
token := strings.Trim(fields[idx+1], " ::,,;;")
|
||||
if isLikelyMeijiequanOrderCode(token) {
|
||||
return token
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2115,25 +2128,21 @@ func extractMeijiequanOrderCodeFromTexts(texts []string) string {
|
||||
|
||||
func isLikelyMeijiequanOrderCode(value string) bool {
|
||||
value = strings.ToUpper(strings.TrimSpace(value))
|
||||
if len(value) < 4 || len(value) > 64 {
|
||||
if len(value) < 5 || len(value) > 64 {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(value, "HTTP") || strings.Contains(value, "://") {
|
||||
return false
|
||||
}
|
||||
hasDigit := false
|
||||
hasLetter := false
|
||||
for _, r := range value {
|
||||
switch {
|
||||
case r >= '0' && r <= '9':
|
||||
hasDigit = true
|
||||
case r >= 'A' && r <= 'Z':
|
||||
hasLetter = true
|
||||
default:
|
||||
if !strings.HasPrefix(value, "WM") {
|
||||
return false
|
||||
}
|
||||
for _, r := range strings.TrimPrefix(value, "WM") {
|
||||
if r < '0' || r > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return hasDigit && hasLetter
|
||||
return true
|
||||
}
|
||||
|
||||
func extractMeijiequanResourceNameFromTexts(texts []string) string {
|
||||
@@ -2469,6 +2478,18 @@ func extractMeijiequanPrices(item map[string]any) map[string]int64 {
|
||||
return out
|
||||
}
|
||||
|
||||
func firstMeijiequanArticlePriceCents(item map[string]any) int64 {
|
||||
for _, key := range []string{
|
||||
"price", "sale_price", "cost_price", "amount", "money", "jine", "jiage",
|
||||
"media_price", "resource_price", "order_price", "total_price",
|
||||
} {
|
||||
if cents, ok := parsePriceCents(item[key]); ok {
|
||||
return cents
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func parsePriceCents(value any) (int64, bool) {
|
||||
switch typed := value.(type) {
|
||||
case nil:
|
||||
|
||||
Reference in New Issue
Block a user