daShangDao_xy_dll/http/route/routes.go

1037 lines
31 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package routes
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"runtime"
"strconv"
"strings"
"time"
"xianyv/controller"
_type "xianyv/type"
"xianyv/utils/requestUtil"
)
// 简单的全局令牌桶限速器本地测试用QPS = 10
const qpsLimit = 10
var tokenBucket chan struct{}
func init() {
tokenBucket = make(chan struct{}, qpsLimit)
// 预先填充令牌
for i := 0; i < qpsLimit; i++ {
tokenBucket <- struct{}{}
}
// 以 QPS 速率补充令牌
go func() {
ticker := time.NewTicker(time.Second / time.Duration(qpsLimit))
defer ticker.Stop()
for range ticker.C {
select {
case tokenBucket <- struct{}{}:
default:
// bucket 已满,跳过
}
}
}()
}
type routeHandler struct {
cfg *_type.Config
}
// RegisterRoutes 注册所有路由
func RegisterRoutes(cfg *_type.Config) *http.ServeMux {
r := http.NewServeMux()
handler := &routeHandler{cfg: cfg}
// 注册健康检查路由
r.HandleFunc("GET /health", healthHandler)
// 请求类目Id处理器留作备用
r.HandleFunc("POST /xianyv/getCategoryList", handler.getCategoryListHandler)
// 发布处理器
r.HandleFunc("POST /xianyv/creatGoodsBatch", handler.creatGoodsBatchHandler)
// 上架处理器
r.HandleFunc("POST /xianyv/publish", publishHandler)
// 下架处理器
r.HandleFunc("POST /xianyv/downShelf", downShelfHandler)
// 擦亮商品处理器
r.HandleFunc("POST /xianyv/flash", flashHandler)
// 改价处理器
r.HandleFunc("POST /xianyv/editPrices", editPricesHandler)
// 改库存处理器
r.HandleFunc("POST /xianyv/editStock", editStockHandler)
// 查商品处理器
r.HandleFunc("POST /xianyv/getGoodsList", getGoodsListHandler)
// 新增:跨页统计 outer_id 的处理器,返回完整统计信息
r.HandleFunc("POST /xianyv/getGoodsListAllStats", getGoodsListAllStatsHandler)
// 查店铺处理器
r.HandleFunc("POST /xianyv/getShopList", getShopListHandler)
// 查询订单列表处理器
r.HandleFunc("POST /xianyv/getOrderList", getOrderListHandler)
// 发布其他类测试(实际不使用)
r.HandleFunc("POST /xianyv/onlineTest", handler.onlineTestHandler)
// 获取商品详情处理器
r.HandleFunc("POST /xianyv/getGoodsDetail", getGoodsDetailHandler)
// 注册默认路由(处理未找到的路由)
r.HandleFunc("/", notFoundHandler)
return r
}
// 健康检查处理器
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
response := map[string]interface{}{
"status": "ok",
"timestamp": time.Now().Format(time.RFC3339),
"goroutines": runtime.NumGoroutine(),
"message": "服务运行正常",
}
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(response); err != nil {
log.Printf("错误的编码响应: %v", err)
errorMsg := fmt.Sprintf(`{"error": "错误的编码响应: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 发布处理器
func (h *routeHandler) creatGoodsBatchHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.Body
// 请求参数处理(计时)
paramsStart := time.Now()
body, err := requestUtil.RequestParams(r)
if err != nil {
log.Printf("请求参数处理失败: %v (elapsed=%v)", err, time.Since(paramsStart))
errMsg := fmt.Sprintf(`{"error": "请求参数处理失败: %v"}`, err)
http.Error(w, errMsg, http.StatusBadRequest)
return
}
log.Printf("请求参数解析完成 (elapsed=%v)", time.Since(paramsStart))
// 类目处理
goodsController := &controller.GoodsController{
ExcelPath: h.cfg.File.ExcelPath,
TxtPath: h.cfg.File.TxtPath,
SheetName: h.cfg.File.SheetName,
}
// 调用业务逻辑(计时)
handlerStart := time.Now()
createResponse, err := goodsController.GoodsCreatController(
body,
h.cfg.BatchCreatRequest.Path,
h.cfg.App.Domain,
false,
)
log.Printf("GoodsCreatController 完成 (elapsed=%v)", time.Since(handlerStart))
if err != nil {
errorMsg := fmt.Sprintf(`{"error": "请求解析或验证失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusBadRequest)
return
}
// 返回Response结果
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(createResponse)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 上架处理器
func publishHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.ListedProducts
body.SpecifyPublishTime = r.FormValue("specify_publish_time")
body.NotifyUrl = r.FormValue("notify_url")
appIdStr := r.FormValue("appId")
body.AppSecret = r.FormValue("appSecret")
body.AppId, _ = strconv.Atoi(appIdStr)
fmt.Printf("appId: %d", body.AppId)
body.NotifyUrl = "http://146.56.192.164:19095/huidiao/goofish/goofishGoods"
// 从绝对路径读取txt文件
filePath := "D:/workSpace/batchWorkSpace/josn/product_ids.txt" // 请替换为实际的绝对路径
content, err := os.ReadFile(filePath)
if err != nil {
log.Printf("读取文件失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "读取文件失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
// 按行分割文件内容
lines := strings.Split(strings.TrimSpace(string(content)), "\n")
if len(lines) == 0 {
errorMsg := `{"error": "文件为空"}`
http.Error(w, errorMsg, http.StatusBadRequest)
return
}
// 首先解析表单(只需要解析一次)
if err := r.ParseForm(); err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
var responses []string
var hasError bool
const qps = 9
const interval = time.Second / time.Duration(qps) // 100ms
// 循环处理每个productId
for i, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue // 跳过空行
}
// 添加延时(从第二个请求开始)
if i > 0 {
time.Sleep(interval)
}
productIdStr := line
body.ProductId, _ = strconv.Atoi(productIdStr)
// 获取 user_name 数组
body.UserName = r.Form["user_name[]"]
log.Printf("上架测试:%v", body)
response, err := controller.Publish(body)
if err != nil {
log.Printf("上架商品失败 (productId: %s): %v", productIdStr, err)
errorResponse := fmt.Sprintf(`{"productId": "%s", "error": "上架商品失败: %v"}`, productIdStr, err)
responses = append(responses, errorResponse)
hasError = true
continue
}
successResponse := fmt.Sprintf(`{"productId": "%s", "response": %s}`, productIdStr, string(response))
fmt.Printf("successResponse: %v\n", successResponse)
}
// 构建最终响应
if hasError {
w.WriteHeader(http.StatusMultiStatus) // 207 Multi-Status
} else {
w.WriteHeader(http.StatusOK)
}
}
// 下架处理器
func downShelfHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.DownAndFlash
productIdStr := r.FormValue("productId")
appIdStr := r.FormValue("appId")
body.AppSecret = r.FormValue("appSecret")
if i, err := strconv.ParseInt(productIdStr, 10, 64); err == nil {
body.ProductId = int64(i)
} else {
body.ProductId = 0
}
body.AppId, _ = strconv.Atoi(appIdStr)
response, err := controller.DownShelf(body)
if err != nil {
log.Printf("下架商品失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "下架商品失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 擦亮商品处理器
func flashHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.DownAndFlash
productIdStr := r.FormValue("productId")
appIdStr := r.FormValue("appId")
body.AppSecret = r.FormValue("appSecret")
if i, err := strconv.ParseInt(productIdStr, 10, 64); err == nil {
body.ProductId = int64(i)
} else {
body.ProductId = 0
}
body.AppId, _ = strconv.Atoi(appIdStr)
response, err := controller.Flash(body)
if err != nil {
log.Printf("擦亮商品失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "擦亮商品失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 改价处理器
func editPricesHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var edit _type.EditPrices
productIdStr := r.FormValue("productId")
pricesStr := r.FormValue("price")
originalPriceStr := r.FormValue("originalPrice")
appIdStr := r.FormValue("appId")
edit.AppSecret = r.FormValue("appSecret")
if i, err := strconv.ParseInt(productIdStr, 10, 64); err == nil {
edit.ProductId = int64(i)
} else {
edit.ProductId = 0
}
if i, err := strconv.ParseInt(pricesStr, 10, 64); err == nil {
edit.Price = int64(i)
} else {
edit.Price = 0
}
if i, err := strconv.ParseInt(originalPriceStr, 10, 64); err == nil {
edit.OriginalPrice = int64(i)
} else {
edit.OriginalPrice = 0
}
edit.AppId, _ = strconv.Atoi(appIdStr)
fmt.Printf("修改价格参数:%v", edit)
response, err := controller.EditPrices(edit)
if err != nil {
log.Printf("修改价格失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "修改价格失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 修改库存处理器
func editStockHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var edit _type.EditStock
productIdStr := r.FormValue("productId")
stockStr := r.FormValue("stock")
appIdStr := r.FormValue("appId")
edit.AppSecret = r.FormValue("appSecret")
if i, err := strconv.ParseInt(productIdStr, 10, 64); err == nil {
edit.ProductId = int64(i)
} else {
edit.ProductId = 0
}
if i, err := strconv.ParseInt(stockStr, 10, 32); err == nil {
edit.Stock = int32(i)
} else {
edit.Stock = 0
}
edit.AppId, _ = strconv.Atoi(appIdStr)
fmt.Printf("修改库存参数:%v", edit)
response, err := controller.EditStock(edit)
if err != nil {
log.Printf("修改库存失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "修改库存失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 获取商品列表处理器
func getGoodsListHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// 检查是否有online_time字段
onlineTimeStr := r.FormValue("online_time")
var response []byte
var err error
if onlineTimeStr != "" {
var selectGoodsList _type.SelectGoodsListWithTime
timeStrs := strings.Split(onlineTimeStr, ",")
var onlineTime []int64
for _, timeStr := range timeStrs {
if t, err := strconv.ParseInt(strings.TrimSpace(timeStr), 10, 64); err == nil {
onlineTime = append(onlineTime, t)
}
}
selectGoodsList.OfflineTime = onlineTime
productStatusStr := r.FormValue("productStatus")
appIdStr := r.FormValue("appId")
selectGoodsList.AppSecret = r.FormValue("appSecret")
pageNoStr := r.FormValue("pageNo")
pageSizeStr := r.FormValue("pageSize")
if i, err := strconv.ParseInt(productStatusStr, 10, 32); err == nil {
selectGoodsList.ProductStatus = int32(i)
}
if i, err := strconv.Atoi(appIdStr); err == nil {
selectGoodsList.AppId = i
}
if i, err := strconv.ParseInt(pageNoStr, 10, 32); err == nil {
selectGoodsList.PageNo = int32(i)
}
if i, err := strconv.ParseInt(pageSizeStr, 10, 32); err == nil {
selectGoodsList.PageSize = int32(i)
}
response, err = controller.SelectGoodsListWithTime(selectGoodsList)
} else {
var selectGoodsList _type.SelectGoodsListWithoutTime
productStatusStr := r.FormValue("productStatus")
appIdStr := r.FormValue("appId")
selectGoodsList.AppSecret = r.FormValue("appSecret")
pageNoStr := r.FormValue("pageNo")
pageSizeStr := r.FormValue("pageSize")
if i, err := strconv.ParseInt(productStatusStr, 10, 32); err == nil {
selectGoodsList.ProductStatus = int32(i)
}
if i, err := strconv.Atoi(appIdStr); err == nil {
selectGoodsList.AppId = i
}
if i, err := strconv.ParseInt(pageNoStr, 10, 32); err == nil {
selectGoodsList.PageNo = int32(i)
}
if i, err := strconv.ParseInt(pageSizeStr, 10, 32); err == nil {
selectGoodsList.PageSize = int32(i)
}
response, err = controller.SelectGoodsListWithoutTime(selectGoodsList)
}
if err != nil {
log.Printf("查询商品失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "查询商品失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
// 添加统计功能
responseWithStats, err := addOuterIDStatsToResponse(response)
if err != nil {
log.Printf("统计outer_id失败返回原始数据: %v", err)
// 统计失败时返回原始数据
responseWithStats = response
} else {
log.Printf("成功添加outer_id统计信息")
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(responseWithStats)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// getGoodsListAllStatsHandler - 在 getGoodsList 的基础上做跨页拉取并统计所有页的 outer_id 分布,
// 返回原始分页响应并在 data.outer_id_stats 中附加总体统计信息
func getGoodsListAllStatsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// 检查是否有online_time字段
onlineTimeStr := r.FormValue("online_time")
var response []byte
var err error
// 通用变量
var initialPageNo int32 = 1
var pageSize int32 = 100
var combinedList []map[string]interface{}
if onlineTimeStr != "" {
var selectGoodsList _type.SelectGoodsListWithTime
timeStrs := strings.Split(onlineTimeStr, ",")
var onlineTime []int64
for _, timeStr := range timeStrs {
if t, err := strconv.ParseInt(strings.TrimSpace(timeStr), 10, 64); err == nil {
onlineTime = append(onlineTime, t)
}
}
selectGoodsList.OfflineTime = onlineTime
productStatusStr := r.FormValue("productStatus")
appIdStr := r.FormValue("appId")
selectGoodsList.AppSecret = r.FormValue("appSecret")
pageNoStr := r.FormValue("pageNo")
pageSizeStr := r.FormValue("pageSize")
if i, err := strconv.ParseInt(productStatusStr, 10, 32); err == nil {
selectGoodsList.ProductStatus = int32(i)
}
if i, err := strconv.Atoi(appIdStr); err == nil {
selectGoodsList.AppId = i
}
if i, err := strconv.ParseInt(pageNoStr, 10, 32); err == nil {
selectGoodsList.PageNo = int32(i)
}
if i, err := strconv.ParseInt(pageSizeStr, 10, 32); err == nil {
selectGoodsList.PageSize = int32(i)
}
initialPageNo = selectGoodsList.PageNo
if selectGoodsList.PageSize > 0 {
pageSize = selectGoodsList.PageSize
}
// 第一次请求
response, err = controller.SelectGoodsListWithTime(selectGoodsList)
if err != nil {
log.Printf("查询商品失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "查询商品失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
var resp struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Count int `json:"count"`
List []map[string]interface{} `json:"list"`
PageNo int `json:"page_no"`
PageSize int `json:"page_size"`
} `json:"data"`
}
if err := json.Unmarshal(response, &resp); err != nil {
// 无法解析则返回原始响应
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
}
return
}
combinedList = append(combinedList, resp.Data.List...)
totalCount := resp.Data.Count
if resp.Data.PageSize > 0 {
pageSize = int32(resp.Data.PageSize)
}
totalPages := 1
if pageSize > 0 {
totalPages = (totalCount + int(pageSize) - 1) / int(pageSize)
}
for p := 1; p <= totalPages; p++ {
if int32(p) == initialPageNo {
continue
}
selectGoodsList.PageNo = int32(p)
pageResp, pageErr := controller.SelectGoodsListWithTime(selectGoodsList)
if pageErr != nil {
log.Printf("Warning: 获取第 %d 页失败: %v", p, pageErr)
continue
}
var pageParsed struct {
Data struct {
List []map[string]interface{} `json:"list"`
} `json:"data"`
}
if perr := json.Unmarshal(pageResp, &pageParsed); perr != nil {
log.Printf("Warning: 解析第 %d 页响应失败: %v", p, perr)
continue
}
combinedList = append(combinedList, pageParsed.Data.List...)
}
// 构造最终响应:在原始 response 的 data 中注入 outer_id_stats
finalRespMap := make(map[string]interface{})
if err := json.Unmarshal(response, &finalRespMap); err != nil {
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
}
return
}
// 计算统计
outerCount := make(map[string]int)
for _, item := range combinedList {
if v, ok := item["outer_id"].(string); ok {
if v == "" {
outerCount["(空)"]++
} else {
outerCount[v]++
}
}
}
stats := map[string]interface{}{
"total_count": len(combinedList),
"distribution": outerCount,
}
if dataMap, ok := finalRespMap["data"].(map[string]interface{}); ok {
dataMap["outer_id_stats"] = stats
finalRespMap["data"] = dataMap
}
bts, merr := json.Marshal(finalRespMap)
if merr != nil {
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
}
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(bts)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
return
} else {
// 无 time 字段的情况
var selectGoodsList _type.SelectGoodsListWithoutTime
productStatusStr := r.FormValue("productStatus")
appIdStr := r.FormValue("appId")
selectGoodsList.AppSecret = r.FormValue("appSecret")
pageNoStr := r.FormValue("pageNo")
pageSizeStr := r.FormValue("pageSize")
if i, err := strconv.ParseInt(productStatusStr, 10, 32); err == nil {
selectGoodsList.ProductStatus = int32(i)
}
if i, err := strconv.Atoi(appIdStr); err == nil {
selectGoodsList.AppId = i
}
if i, err := strconv.ParseInt(pageNoStr, 10, 32); err == nil {
selectGoodsList.PageNo = int32(i)
}
if i, err := strconv.ParseInt(pageSizeStr, 10, 32); err == nil {
selectGoodsList.PageSize = int32(i)
}
initialPageNo = selectGoodsList.PageNo
if selectGoodsList.PageSize > 0 {
pageSize = selectGoodsList.PageSize
}
response, err = controller.SelectGoodsListWithoutTime(selectGoodsList)
if err != nil {
log.Printf("查询商品失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "查询商品失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
var resp struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Count int `json:"count"`
List []map[string]interface{} `json:"list"`
PageNo int `json:"page_no"`
PageSize int `json:"page_size"`
} `json:"data"`
}
if err := json.Unmarshal(response, &resp); err != nil {
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
}
return
}
combinedList = append(combinedList, resp.Data.List...)
totalCount := resp.Data.Count
if resp.Data.PageSize > 0 {
pageSize = int32(resp.Data.PageSize)
}
totalPages := 1
if pageSize > 0 {
totalPages = (totalCount + int(pageSize) - 1) / int(pageSize)
}
for p := 1; p <= totalPages; p++ {
if int32(p) == initialPageNo {
continue
}
selectGoodsList.PageNo = int32(p)
pageResp, pageErr := controller.SelectGoodsListWithoutTime(selectGoodsList)
if pageErr != nil {
log.Printf("Warning: 获取第 %d 页失败: %v", p, pageErr)
continue
}
var pageParsed struct {
Data struct {
List []map[string]interface{} `json:"list"`
} `json:"data"`
}
if perr := json.Unmarshal(pageResp, &pageParsed); perr != nil {
log.Printf("Warning: 解析第 %d 页响应失败: %v", p, perr)
continue
}
combinedList = append(combinedList, pageParsed.Data.List...)
}
finalRespMap := make(map[string]interface{})
if err := json.Unmarshal(response, &finalRespMap); err != nil {
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
}
return
}
outerCount := make(map[string]int)
for _, item := range combinedList {
if v, ok := item["outer_id"].(string); ok {
if v == "" {
outerCount["(空)"]++
} else {
outerCount[v]++
}
}
}
stats := map[string]interface{}{
"total_count": len(combinedList),
"distribution": outerCount,
}
if dataMap, ok := finalRespMap["data"].(map[string]interface{}); ok {
dataMap["outer_id_stats"] = stats
finalRespMap["data"] = dataMap
}
bts, merr := json.Marshal(finalRespMap)
if merr != nil {
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
}
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(bts)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
return
}
}
// 获取店铺列表处理器
func getShopListHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.GetShopList
appIdStr := r.FormValue("appId")
body.AppSecret = r.FormValue("appSecret")
body.AppId, _ = strconv.Atoi(appIdStr)
response, err := controller.GetShopList(body)
if err != nil {
log.Printf("获取店铺列表失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "获取店铺列表失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 获取订单列表处理器
func getOrderListHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.GetShopList
appIdStr := r.FormValue("appId")
body.AppSecret = r.FormValue("appSecret")
body.AppId, _ = strconv.Atoi(appIdStr)
response, err := controller.GetOrderList(body)
if err != nil {
log.Printf("获取店铺列表失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "获取店铺列表失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 发布处理器
func (h *routeHandler) onlineTestHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.Body
// 请求参数处理
body, err := requestUtil.RequestParams(r)
if err != nil {
log.Printf("请求参数处理失败: %v", err)
errMsg := fmt.Sprintf(`{"error": "请求参数处理失败: %v"}`, err)
http.Error(w, errMsg, http.StatusBadRequest)
return
}
// 类目处理
goodsController := &controller.GoodsController{
ExcelPath: h.cfg.File.ExcelPath,
TxtPath: h.cfg.File.TxtPath,
SheetName: h.cfg.File.SheetName,
}
createResponse, err := goodsController.GoodsCreatController(
body,
h.cfg.BatchCreatRequest.Path,
h.cfg.App.Domain,
true,
)
if err != nil {
errorMsg := fmt.Sprintf(`{"error": "请求解析或验证失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusBadRequest)
return
}
// 返回Response结果
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(createResponse)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 获取商品详情处理器
func getGoodsDetailHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var body _type.GetGoosDetail
productIdStr := r.FormValue("productId")
appIdStr := r.FormValue("appId")
body.AppSecret = r.FormValue("appSecret")
if i, err := strconv.ParseInt(productIdStr, 10, 64); err == nil {
body.ProductId = int64(i)
} else {
body.ProductId = 0
}
body.AppId, _ = strconv.Atoi(appIdStr)
response, err := controller.GetGoosDetail(body)
if err != nil {
log.Printf("获取商品详情失败: %v", err)
errorMsg := fmt.Sprintf(`{"error": "获取商品详情失败: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if err = json.NewEncoder(w).Encode(json.RawMessage(response)); err != nil {
log.Printf("Failed to encode response: %v", err)
errorMsg := fmt.Sprintf(`{"error": "无法对响应进行编码: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 404 处理器
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
response := map[string]interface{}{
"error": "未找到路由",
"path": r.URL.Path,
"method": r.Method,
"code": 404,
"message": "请求的资源不存在",
}
if err := json.NewEncoder(w).Encode(response); err != nil {
log.Printf("错误的编码响应: %v", err)
errorMsg := fmt.Sprintf(`{"error": "错误的编码响应: %v"}`, err)
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
}
// 请求类目Id处理器
func (h *routeHandler) getCategoryListHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("开始请求商品分类列表")
// 创建或打开txt文件
file, err := os.OpenFile("category_list.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
log.Printf("创建文件失败: %v", err)
return
}
defer file.Close()
// 请求商品分类列表
fmt.Println("正在获取商品分类列表...")
categoryPath := h.cfg.CategoryListRequest.Path
categoryRequest := _type.CategoryListRequest{
ItemBizType: h.cfg.CategoryListRequest.ItemBizType, // 普通商品类型
SpBizType: h.cfg.CategoryListRequest.SpBizType, // 潮品行业类型(可选)
}
categoryResponseBody, err := requestUtil.MakeAPIRequest(h.cfg.App.AppId, h.cfg.App.AppSecret, h.cfg.App.Domain, categoryPath, categoryRequest)
if err != nil {
log.Printf("获取商品分类列表失败: %v", err)
} else {
fmt.Println("商品分类列表响应:")
fmt.Println(string(categoryResponseBody))
// 解析响应以获取分类信息
var categoryResponse _type.CategoryListResponse
if err := json.Unmarshal(categoryResponseBody, &categoryResponse); err != nil {
log.Printf("解析分类响应失败: %v", err)
} else if categoryResponse.Code == 0 {
fmt.Println("成功获取商品分类:")
// 遍历分类列表,同时打印和写入文件
for _, item := range categoryResponse.Data.List {
// 控制台打印
fmt.Printf("行业: %s, 类目: %s (ID: %s)\n",
item.SpBizName, item.ChannelCatName, item.ChannelCatId)
// 写入文件
line := fmt.Sprintf("行业: %s, 类目: %s (ID: %s)\n",
item.SpBizName, item.ChannelCatName, item.ChannelCatId)
if _, err := file.WriteString(line); err != nil {
log.Printf("写入文件失败: %v", err)
}
}
fmt.Printf("共获取 %d 个分类,已保存到 category_list.txt\n", len(categoryResponse.Data.List))
} else {
errorMsg := fmt.Sprintf("获取分类失败: %s (代码: %d)\n", categoryResponse.Msg, categoryResponse.Code)
fmt.Printf(errorMsg)
file.WriteString(errorMsg)
}
}
if err != nil {
log.Printf("获取商品分类列表失败: %v", err)
}
fmt.Println("商品分类列表获取结束")
}
// 将统计结果添加到响应中的辅助函数
func addOuterIDStatsToResponse(originalResponse []byte) ([]byte, error) {
var responseMap map[string]interface{}
if err := json.Unmarshal(originalResponse, &responseMap); err != nil {
return nil, fmt.Errorf("解析响应JSON失败: %v", err)
}
// 获取统计结果
stats := getOuterIDStats(originalResponse)
// 将统计结果添加到response的data中
if data, exists := responseMap["data"].(map[string]interface{}); exists {
data["outer_id_stats"] = stats
responseMap["data"] = data
}
return json.Marshal(responseMap)
}
// 获取outer_id统计
func getOuterIDStats(responseData []byte) map[string]interface{} {
stats := make(map[string]interface{})
var data struct {
Data struct {
List []struct {
OuterID string `json:"outer_id"`
} `json:"list"`
} `json:"data"`
}
if err := json.Unmarshal(responseData, &data); err != nil {
return stats
}
outerIDCount := make(map[string]int)
totalCount := len(data.Data.List)
for _, item := range data.Data.List {
outerID := item.OuterID
if outerID == "" {
outerID = "(空)"
}
outerIDCount[outerID]++
}
stats["total_count"] = totalCount
stats["distribution"] = outerIDCount
return stats
}