From 0f0da660bad89a7985d98c25513e3900b0e49500 Mon Sep 17 00:00:00 2001 From: fuzhongyun <15339891972@163.com> Date: Mon, 29 Dec 2025 14:59:34 +0800 Subject: [PATCH] =?UTF-8?q?chore=EF=BC=9A=20=E6=9A=82=E5=AD=98=E4=B8=80?= =?UTF-8?q?=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_env.yaml | 14 ++++ internal/config/config.go | 8 ++ .../data_analytics/official_product/client.go | 70 ++++++++++++++++ .../data_analytics/official_product/types.go | 31 ++++++++ .../official_product_decline/client.go | 79 +++++++++++++++++++ .../official_product_decline/types.go | 35 ++++++++ .../ours_product_loss/client.go | 78 ++++++++++++++++++ .../data_analytics/ours_product_loss/types.go | 29 +++++++ .../data_analytics/profit_ranking/client.go | 63 +++++++++++++++ .../profit_ranking/client_test.go | 27 +++++++ .../data_analytics/profit_ranking/types.go | 29 +++++++ 11 files changed, 463 insertions(+) create mode 100644 internal/domain/tools/data_analytics/official_product/client.go create mode 100644 internal/domain/tools/data_analytics/official_product/types.go create mode 100644 internal/domain/tools/data_analytics/official_product_decline/client.go create mode 100644 internal/domain/tools/data_analytics/official_product_decline/types.go create mode 100644 internal/domain/tools/data_analytics/ours_product_loss/client.go create mode 100644 internal/domain/tools/data_analytics/ours_product_loss/types.go create mode 100644 internal/domain/tools/data_analytics/profit_ranking/client.go create mode 100644 internal/domain/tools/data_analytics/profit_ranking/client_test.go create mode 100644 internal/domain/tools/data_analytics/profit_ranking/types.go diff --git a/config/config_env.yaml b/config/config_env.yaml index 21c1faa..9757b80 100644 --- a/config/config_env.yaml +++ b/config/config_env.yaml @@ -78,6 +78,7 @@ tools: # eino tool 配置 eino_tools: + # == 货易通 hyt == # 货易通商品上传 hytProductUpload: base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/supplier/batch/add/complete" @@ -104,6 +105,19 @@ eino_tools: # 货易通商品品牌查询 hytGoodsBrandSearch: base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/brand/list" + # == 报表分析 data analytics == + # 负利润分析列表、 负利润分析详情 + daOursProductLoss: + base_url: "http://test.analysis.com/api/dataanalytics/statisOursProductLossSum" + api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzY2OTc4MTQwLCJuYmYiOjE3NjY5NzYzNDAsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.nyQw7_JZd7IfnIkPlfySGJMkFAHy_RtIL6gRqOYdku3ikp_w3x9bt7rrSBDQMi4Z8jC4jL_qxwhJ1D1DV4uLZ_cZBmuuG-gymIDN1TSJKa8hpu4E8L3tPdbT1H6hehXvg10-_ugKAYNBgnvFUbCRnpMl-sNuqCLWZKa_v63L1v3lGZOQiPPyzEGmIulNwqSF8rlzZggJneVTWEQac2BNK4181mpbz0S_m84xuFFO3Qwen2sEntBaPKeKbJ9BAfdSAQPcIlnG9FHF3mttZfxQQF5nbxU7CAGYsu_2kjpcmP-u5x3tT3gCWsF1t84lSZ8mMxIax7rh0-Y55abRoBnrwQ" + # 利润同比排行榜 + daProfitRanking: + base_url: "http://test.analysis.com/api/dataanalytics/profitRankingSum" + api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzY2OTc4MTQwLCJuYmYiOjE3NjY5NzYzNDAsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.nyQw7_JZd7IfnIkPlfySGJMkFAHy_RtIL6gRqOYdku3ikp_w3x9bt7rrSBDQMi4Z8jC4jL_qxwhJ1D1DV4uLZ_cZBmuuG-gymIDN1TSJKa8hpu4E8L3tPdbT1H6hehXvg10-_ugKAYNBgnvFUbCRnpMl-sNuqCLWZKa_v63L1v3lGZOQiPPyzEGmIulNwqSF8rlzZggJneVTWEQac2BNK4181mpbz0S_m84xuFFO3Qwen2sEntBaPKeKbJ9BAfdSAQPcIlnG9FHF3mttZfxQQF5nbxU7CAGYsu_2kjpcmP-u5x3tT3gCWsF1t84lSZ8mMxIax7rh0-Y55abRoBnrwQ" + # 销售同比分析列表 + daOfficialProduct: + base_url: "http://test.analysis.com/api/dataanalytics/statisOfficialProduct" + api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzY2OTc4MTQwLCJuYmYiOjE3NjY5NzYzNDAsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.nyQw7_JZd7IfnIkPlfySGJMkFAHy_RtIL6gRqOYdku3ikp_w3x9bt7rrSBDQMi4Z8jC4jL_qxwhJ1D1DV4uLZ_cZBmuuG-gymIDN1TSJKa8hpu4E8L3tPdbT1H6hehXvg10-_ugKAYNBgnvFUbCRnpMl-sNuqCLWZKa_v63L1v3lGZOQiPPyzEGmIulNwqSF8rlzZggJneVTWEQac2BNK4181mpbz0S_m84xuFFO3Qwen2sEntBaPKeKbJ9BAfdSAQPcIlnG9FHF3mttZfxQQF5nbxU7CAGYsu_2kjpcmP-u5x3tT3gCWsF1t84lSZ8mMxIax7rh0-Y55abRoBnrwQ" dingtalk: api_key: "dingsbbntrkeiyazcfdg" diff --git a/internal/config/config.go b/internal/config/config.go index 441d09d..713663f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -188,6 +188,14 @@ type EinoToolsConfig struct { HytGoodsCategorySearch ToolConfig `mapstructure:"hytGoodsCategorySearch"` // 货易通商品品牌查询 HytGoodsBrandSearch ToolConfig `mapstructure:"hytGoodsBrandSearch"` + // 负利润分析列表、 详情 + DaOursProductLoss ToolConfig `mapstructure:"daOursProductLoss"` + // 利润同比排行榜 + DaProfitRanking ToolConfig `mapstructure:"daProfitRanking"` + // 销售同比分析列表 + DaOfficialProduct ToolConfig `mapstructure:"daOfficialProduct"` + // 销售同比下滑详情 + DaOfficialProductDecline ToolConfig `mapstructure:"daOfficialProductDecline"` } // LoggingConfig 日志配置 diff --git a/internal/domain/tools/data_analytics/official_product/client.go b/internal/domain/tools/data_analytics/official_product/client.go new file mode 100644 index 0000000..bffb6be --- /dev/null +++ b/internal/domain/tools/data_analytics/official_product/client.go @@ -0,0 +1,70 @@ +package official_product + +import ( + "ai_scheduler/internal/config" + "ai_scheduler/internal/pkg/l_request" + "context" + "encoding/json" + "fmt" + "strings" +) + +type Client struct { + cfg config.ToolConfig +} + +func New(cfg config.ToolConfig) *Client { + return &Client{ + cfg: cfg, + } +} + +// Call 调用销售同比分析接口 +func (c *Client) Call(ctx context.Context, req OfficialProductRequest) (*OfficialProductData, error) { + // 构建 URL 参数 + var queryParams []string + + if req.Page > 0 { + queryParams = append(queryParams, fmt.Sprintf("page=%d", req.Page)) + } + if req.Limit > 0 { + queryParams = append(queryParams, fmt.Sprintf("limit=%d", req.Limit)) + } + + for _, pid := range req.OfficialProductIds { + queryParams = append(queryParams, fmt.Sprintf("official_product_id[]=%s", pid)) + } + + for _, t := range req.Ct { + queryParams = append(queryParams, fmt.Sprintf("ct[]=%s", strings.ReplaceAll(t, " ", "+"))) + } + + queryString := strings.Join(queryParams, "&") + fullURL := fmt.Sprintf("%s?%s", c.cfg.BaseURL, queryString) + + headers := map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", c.cfg.APIKey), + } + + reqObj := l_request.Request{ + Method: "GET", + Url: fullURL, + Headers: headers, + } + + res, err := reqObj.Send() + if err != nil { + return nil, fmt.Errorf("请求失败,err: %v", err) + } + + var resData OfficialProductResponse + if err := json.Unmarshal([]byte(res.Text), &resData); err != nil { + return nil, fmt.Errorf("解析响应失败,err: %v, resp: %s", err, res.Text) + } + + if resData.Code != 200 { + return nil, fmt.Errorf("业务错误,code: %d, msg: %s", resData.Code, resData.Msg) + } + + return &resData.Data, nil +} diff --git a/internal/domain/tools/data_analytics/official_product/types.go b/internal/domain/tools/data_analytics/official_product/types.go new file mode 100644 index 0000000..a0890b5 --- /dev/null +++ b/internal/domain/tools/data_analytics/official_product/types.go @@ -0,0 +1,31 @@ +package official_product + +// OfficialProductRequest 销售同比分析请求参数 +type OfficialProductRequest struct { + Page int `json:"page"` // 页码 + Limit int `json:"limit"` // 每页条数 + OfficialProductIds []string `json:"official_product_ids"` // 官方产品ID列表 + Ct []string `json:"ct"` // 时间范围 [开始时间, 结束时间] +} + +// OfficialProductResponse 销售同比分析响应结构 +type OfficialProductResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data OfficialProductData `json:"data"` +} + +type OfficialProductData struct { + OfficialProductSum []OfficialProductItem `json:"officialProductSum"` + DataCount int `json:"dataCount"` +} + +type OfficialProductItem struct { + OfficialProductId int `json:"officialProductId"` + OfficialProductName string `json:"officialProductName"` + CurrentNum int `json:"currentNum"` + HistoryOneNum int `json:"historyOneNum"` + HistoryTwoNum int `json:"historyTwoNum"` + HistoryOneDiff int `json:"historyOneDiff"` + HistoryTwoDiff int `json:"historyTwoDiff"` +} diff --git a/internal/domain/tools/data_analytics/official_product_decline/client.go b/internal/domain/tools/data_analytics/official_product_decline/client.go new file mode 100644 index 0000000..9ce9499 --- /dev/null +++ b/internal/domain/tools/data_analytics/official_product_decline/client.go @@ -0,0 +1,79 @@ +package official_product_decline + +import ( + "ai_scheduler/internal/config" + "ai_scheduler/internal/pkg/l_request" + "context" + "encoding/json" + "fmt" + "strings" +) + +type Client struct { + cfg config.ToolConfig +} + +func New(cfg config.ToolConfig) *Client { + return &Client{ + cfg: cfg, + } +} + +// Call 调用销售同比下滑详情接口 +func (c *Client) Call(ctx context.Context, req OfficialProductDeclineRequest) (*OfficialProductDeclineData, error) { + // 构建 URL 参数 + var queryParams []string + + if req.Page > 0 { + queryParams = append(queryParams, fmt.Sprintf("page=%d", req.Page)) + } + if req.Limit > 0 { + queryParams = append(queryParams, fmt.Sprintf("limit=%d", req.Limit)) + } + if req.DownwardValue > 0 { + queryParams = append(queryParams, fmt.Sprintf("downwardValue=%d", req.DownwardValue)) + } + // showTime 可能是 0,所以这里不做 > 0 判断,如果业务默认是 0 可以忽略,或者根据实际需求 + // 假设始终传递该参数如果已设置 + queryParams = append(queryParams, fmt.Sprintf("showTime=%d", req.ShowTime)) + + for _, pid := range req.OfficialProductIds { + queryParams = append(queryParams, fmt.Sprintf("official_product_id[]=%s", pid)) + } + + for _, t := range req.Ct { + queryParams = append(queryParams, fmt.Sprintf("ct[]=%s", strings.ReplaceAll(t, " ", "+"))) + } + + queryString := strings.Join(queryParams, "&") + fullURL := fmt.Sprintf("%s?%s", c.cfg.BaseURL, queryString) + + headers := map[string]string{ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", + "Accept": "application/json, text/plain, */*", + "Authorization": fmt.Sprintf("Bearer %s", c.cfg.APIKey), + "Accept-Language": "zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7", + } + + reqObj := l_request.Request{ + Method: "GET", + Url: fullURL, + Headers: headers, + } + + res, err := reqObj.Send() + if err != nil { + return nil, fmt.Errorf("请求失败,err: %v", err) + } + + var resData OfficialProductDeclineResponse + if err := json.Unmarshal([]byte(res.Text), &resData); err != nil { + return nil, fmt.Errorf("解析响应失败,err: %v, resp: %s", err, res.Text) + } + + if resData.Code != 200 { + return nil, fmt.Errorf("业务错误,code: %d, msg: %s", resData.Code, resData.Msg) + } + + return &resData.Data, nil +} diff --git a/internal/domain/tools/data_analytics/official_product_decline/types.go b/internal/domain/tools/data_analytics/official_product_decline/types.go new file mode 100644 index 0000000..3fa598d --- /dev/null +++ b/internal/domain/tools/data_analytics/official_product_decline/types.go @@ -0,0 +1,35 @@ +package official_product_decline + +// OfficialProductDeclineRequest 销售同比下滑详情请求参数 +type OfficialProductDeclineRequest struct { + Page int `json:"page"` // 页码 + Limit int `json:"limit"` // 每页条数 + Ct []string `json:"ct"` // 时间范围 [开始时间, 结束时间] + OfficialProductIds []string `json:"official_product_ids"` // 官方产品ID列表 + DownwardValue int `json:"downward_value"` // 下滑值 + ShowTime int `json:"show_time"` // 是否显示时间 (0:不显示, 1:显示) +} + +// OfficialProductDeclineResponse 销售同比下滑详情响应结构 +type OfficialProductDeclineResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data OfficialProductDeclineData `json:"data"` +} + +type OfficialProductDeclineData struct { + OfficialProductSumDecline []OfficialProductDeclineItem `json:"officialProductSumDecline"` + DataCount int `json:"dataCount"` +} + +type OfficialProductDeclineItem struct { + ResellerId int `json:"resellerId"` + OfficialProductId int `json:"officialProductId"` + OfficialProductName string `json:"officialProductName"` + ResellerName string `json:"resellerName"` + CurrentNum int `json:"currentNum"` + HistoryOneNum int `json:"historyOneNum"` + HistoryTwoNum int `json:"historyTwoNum"` + HistoryOneDiff int `json:"historyOneDiff"` + HistoryTwoDiff int `json:"historyTwoDiff"` +} diff --git a/internal/domain/tools/data_analytics/ours_product_loss/client.go b/internal/domain/tools/data_analytics/ours_product_loss/client.go new file mode 100644 index 0000000..9e145b3 --- /dev/null +++ b/internal/domain/tools/data_analytics/ours_product_loss/client.go @@ -0,0 +1,78 @@ +package ours_product_loss + +import ( + "ai_scheduler/internal/config" + "ai_scheduler/internal/pkg/l_request" + "context" + "encoding/json" + "fmt" + "strings" +) + +type Client struct { + cfg config.ToolConfig +} + +func New(cfg config.ToolConfig) *Client { + return &Client{ + cfg: cfg, + } +} + +// Call 调用负利润分析接口 +// 支持列表查询和详情查询 +// 列表查询:提供 page, limit, ct[] +// 详情查询:提供 ct[], resellerId +func (c *Client) Call(ctx context.Context, req OursProductLossRequest) (*OursProductLossData, error) { + // 处理数组参数 ct[] + // util.StructToMap 通常不支持数组到 url query array 的转换,这里手动处理查询字符串 + // 或者如果 l_request 支持 map 中的 slice 自动转换最好,假设不支持需手动拼接 + + // 构建 URL 参数 + var queryParams []string + + if req.Page > 0 { + queryParams = append(queryParams, fmt.Sprintf("page=%d", req.Page)) + } + if req.Limit > 0 { + queryParams = append(queryParams, fmt.Sprintf("limit=%d", req.Limit)) + } + if req.ResellerId != "" { + queryParams = append(queryParams, fmt.Sprintf("resellerId=%s", req.ResellerId)) + } + + for _, t := range req.Ct { + // URL 编码处理,这里简单处理,实际应使用 url.QueryEscape + // 假设输入已经是合法的格式 + queryParams = append(queryParams, fmt.Sprintf("ct[]=%s", strings.ReplaceAll(t, " ", "+"))) + } + + queryString := strings.Join(queryParams, "&") + fullURL := fmt.Sprintf("%s?%s", c.cfg.BaseURL, queryString) + + headers := map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", c.cfg.APIKey), + } + + reqObj := l_request.Request{ + Method: "GET", + Url: fullURL, + Headers: headers, + } + + res, err := reqObj.Send() + if err != nil { + return nil, fmt.Errorf("请求失败,err: %v", err) + } + + var resData OursProductLossResponse + if err := json.Unmarshal([]byte(res.Text), &resData); err != nil { + return nil, fmt.Errorf("解析响应失败,err: %v, resp: %s", err, res.Text) + } + + if resData.Code != 200 { + return nil, fmt.Errorf("业务错误,code: %d, msg: %s", resData.Code, resData.Msg) + } + + return &resData.Data, nil +} diff --git a/internal/domain/tools/data_analytics/ours_product_loss/types.go b/internal/domain/tools/data_analytics/ours_product_loss/types.go new file mode 100644 index 0000000..ceb006a --- /dev/null +++ b/internal/domain/tools/data_analytics/ours_product_loss/types.go @@ -0,0 +1,29 @@ +package ours_product_loss + +// OursProductLossRequest 负利润分析请求参数 +type OursProductLossRequest struct { + Page int `json:"page"` // 页码 + Limit int `json:"limit"` // 每页条数 + Ct []string `json:"ct"` // 时间范围 [开始时间, 结束时间] + ResellerId string `json:"reseller_id"` // 经销商ID (详情查询时使用) +} + +// OursProductLossResponse 负利润分析响应结构 +type OursProductLossResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data OursProductLossData `json:"data"` +} + +type OursProductLossData struct { + List []OursProductLossItem `json:"list"` + DataCount int `json:"dataCount"` +} + +type OursProductLossItem struct { + OursProductId int `json:"oursProductId"` + OursProductName string `json:"oursProductName"` + ResellerName string `json:"resellerName"` + ResellerId int `json:"resellerId"` + Loss float64 `json:"loss"` +} diff --git a/internal/domain/tools/data_analytics/profit_ranking/client.go b/internal/domain/tools/data_analytics/profit_ranking/client.go new file mode 100644 index 0000000..251c59e --- /dev/null +++ b/internal/domain/tools/data_analytics/profit_ranking/client.go @@ -0,0 +1,63 @@ +package profit_ranking + +import ( + "ai_scheduler/internal/config" + "ai_scheduler/internal/pkg/l_request" + "context" + "encoding/json" + "fmt" + "strings" +) + +type Client struct { + cfg config.ToolConfig +} + +func New(cfg config.ToolConfig) *Client { + return &Client{ + cfg: cfg, + } +} + +// Call 调用利润同比排行榜接口 +func (c *Client) Call(ctx context.Context, req ProfitRankingRequest) (*ProfitRankingData, error) { + // 构建 URL 参数 + var queryParams []string + + for _, t := range req.Ct { + queryParams = append(queryParams, fmt.Sprintf("ct[]=%s", strings.ReplaceAll(t, " ", "+"))) + } + + for _, rid := range req.ResellerIds { + queryParams = append(queryParams, fmt.Sprintf("resellerIds[]=%s", rid)) + } + + queryString := strings.Join(queryParams, "&") + fullURL := fmt.Sprintf("%s?%s", c.cfg.BaseURL, queryString) + + headers := map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", c.cfg.APIKey), + } + + reqObj := l_request.Request{ + Method: "GET", + Url: fullURL, + Headers: headers, + } + + res, err := reqObj.Send() + if err != nil { + return nil, fmt.Errorf("请求失败,err: %v", err) + } + + var resData ProfitRankingResponse + if err := json.Unmarshal([]byte(res.Text), &resData); err != nil { + return nil, fmt.Errorf("解析响应失败,err: %v, resp: %s", err, res.Text) + } + + if resData.Code != 200 { + return nil, fmt.Errorf("业务错误,code: %d, msg: %s", resData.Code, resData.Msg) + } + + return &resData.Data, nil +} diff --git a/internal/domain/tools/data_analytics/profit_ranking/client_test.go b/internal/domain/tools/data_analytics/profit_ranking/client_test.go new file mode 100644 index 0000000..ad5bc29 --- /dev/null +++ b/internal/domain/tools/data_analytics/profit_ranking/client_test.go @@ -0,0 +1,27 @@ +package profit_ranking + +import ( + "ai_scheduler/internal/config" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestClient_Call(t *testing.T) { + cfg := config.ToolConfig{ + BaseURL: "http://test.analysis.com/api/dataanalytics/profitRankingSum", + APIKey: "test_jwt_token", + } + + client := New(cfg) + assert.NotNil(t, client) + + req := ProfitRankingRequest{ + Ct: []string{"2025-01-01 00:00:00", "2025-01-01 23:59:59"}, + ResellerIds: []string{"1001", "1002"}, + } + + t.Logf("Testing Call with req: %+v", req) + // _, err := client.Call(context.Background(), req) + // assert.Error(t, err) +} diff --git a/internal/domain/tools/data_analytics/profit_ranking/types.go b/internal/domain/tools/data_analytics/profit_ranking/types.go new file mode 100644 index 0000000..d0d8552 --- /dev/null +++ b/internal/domain/tools/data_analytics/profit_ranking/types.go @@ -0,0 +1,29 @@ +package profit_ranking + +// ProfitRankingRequest 利润同比排行请求参数 +type ProfitRankingRequest struct { + Ct []string `json:"ct"` // 时间范围 [开始时间, 结束时间] + ResellerIds []string `json:"reseller_ids"` // 经销商ID列表 +} + +// ProfitRankingResponse 利润同比排行响应结构 +type ProfitRankingResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data ProfitRankingData `json:"data"` +} + +type ProfitRankingData struct { + List []ProfitRankingItem `json:"list"` + DataCount int `json:"dataCount"` +} + +type ProfitRankingItem struct { + ResellerId string `json:"resellerId"` + ResellerName string `json:"resellerName"` + CurrentProfit float64 `json:"currentProfit"` + HistoryOneProfit float64 `json:"historyOneProfit"` + HistoryTwoProfit float64 `json:"historyTwoProfit"` + HistoryOneDiff float64 `json:"historyOneDiff"` + HistoryTwoDiff float64 `json:"historyTwoDiff"` +}