- 交付界面重构:隐藏内部订单号、流水号与发货渠道,展示聚焦于买家游戏UID、角色名与交付时间 - 发货结果凭据生成:采用 Canvas 生成高清发货存证图,优化存证说明文案与自适应排版 - 一键复制图片:支持直接将结果凭证图片写入系统剪贴板,方便客服在聊天窗口快捷粘贴 - 官方图片本地化缓存:全量下载乐玩商品官方主图并建立本地持久化路由,规避外部源站跨域及破损问题 - 修复乐玩渠道角色UID提取与履约状态幂等回填逻辑
93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"affiliate_dash/internal/config"
|
|
"affiliate_dash/internal/pkg/lewan"
|
|
)
|
|
|
|
func main() {
|
|
cfg := config.Load()
|
|
client := lewan.NewClient(lewan.Config{
|
|
BaseURL: cfg.LewanBaseURL,
|
|
AccessKey: cfg.LewanAccessKey,
|
|
SecretKey: cfg.LewanSecretKey,
|
|
ApplicationID: cfg.LewanApplicationID,
|
|
}, nil)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
list, err := client.ListProducts(ctx, 1, 100, "")
|
|
if err != nil {
|
|
fmt.Printf("ListProducts error: %v\n", err)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Found %d products (total: %d)\n", len(list.Items), list.Total)
|
|
uploadDir := cfg.UploadDir
|
|
if uploadDir == "" {
|
|
uploadDir = "data/uploads"
|
|
}
|
|
cacheDir := filepath.Join(uploadDir, "products")
|
|
_ = os.MkdirAll(cacheDir, 0755)
|
|
|
|
httpClient := &http.Client{Timeout: 15 * time.Second}
|
|
|
|
for i, item := range list.Items {
|
|
fmt.Printf("[%d/%d] ID: %s, Name: %s, Thumb: %s\n", i+1, len(list.Items), item.ID, item.Name, item.ThumbnailUrl)
|
|
if item.ThumbnailUrl == "" {
|
|
continue
|
|
}
|
|
// 存储为 item.ID + 原扩展名
|
|
ext := filepath.Ext(item.ThumbnailUrl)
|
|
if ext == "" || len(ext) > 5 {
|
|
ext = ".webp"
|
|
}
|
|
destPath := filepath.Join(cacheDir, item.ID+ext)
|
|
// 同时也用 url hash 存一个软链或备份,以便 proxy 按 url 精准命中
|
|
urlHash := sha256.Sum256([]byte(item.ThumbnailUrl))
|
|
hashPath := filepath.Join(cacheDir, hex.EncodeToString(urlHash[:])+ext)
|
|
|
|
if _, err := os.Stat(destPath); err == nil {
|
|
fmt.Printf(" -> 已存在缓存: %s\n", destPath)
|
|
continue
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, item.ThumbnailUrl, nil)
|
|
if err != nil {
|
|
fmt.Printf(" -> 构建请求失败: %v\n", err)
|
|
continue
|
|
}
|
|
resp, err := httpClient.Do(req)
|
|
if err != nil {
|
|
fmt.Printf(" -> 下载失败: %v\n", err)
|
|
continue
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
fmt.Printf(" -> 状态码错误: %d\n", resp.StatusCode)
|
|
resp.Body.Close()
|
|
continue
|
|
}
|
|
data, err := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
if err != nil {
|
|
fmt.Printf(" -> 读取失败: %v\n", err)
|
|
continue
|
|
}
|
|
|
|
_ = os.WriteFile(destPath, data, 0644)
|
|
_ = os.WriteFile(hashPath, data, 0644)
|
|
fmt.Printf(" -> 成功缓存: %s (大小: %d 字节)\n", destPath, len(data))
|
|
}
|
|
}
|