package youngee_talent_service import ( "context" "fmt" "github.com/chromedp/chromedp" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" douyinUser "github.com/lin-jim-leon/douyin/open/user" "github.com/lin-jim-leon/kuaishou/open/merchant" "github.com/lin-jim-leon/kuaishou/open/user" "log" "strings" "time" "youngmini_server/app/model/youngee_talent_model" "youngmini_server/app/service/youngee_sectask_service" "youngmini_server/app/utils" ) const ( //快手电商 ClientKey = "ks651333097154138217" ClientSecret = "dBt0rVRhTpUqcrOYGGpv0A" SignSecret = "bf6393dce0a2b669ee348bebb837b0da" //快手平台 ClientKey1 = "ks671599294546520767" ClientSecret1 = "8VSrp3O09nunjLMXR1uotg" //SignSecret1 = "bf6393dce0a2b669ee348bebb837b0da" //抖音平台 ClientKey2 = "awi77xl5kpl16hmi" ClientSecret2 = "7ce6d2531bd4489122d89658063fd76e" //SignSecret1 = "bf6393dce0a2b669ee348bebb837b0da" ) // 清理上下文的函数,用于关闭浏览器和取消上下文 func CleanupChromedpContext(cancel context.CancelFunc) { if cancel != nil { cancel() fmt.Println("Chromedp 上下文已关闭") } } func GetQrcode(r *ghttp.Request) *TalentHttpResult { //达人id获取 tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) fmt.Println("tid:", tid, "err:", err) if err != nil { return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} } // 记录开始时间 startTime := time.Now() // 创建一个新的上下文 // 确保 chromedp 上下文已初始化 //initChromedpContext() ctx, cancel := chromedp.NewContext(context.Background()) //每个请求有独立的上下文,而不是共享的 fmt.Println("上下文初始化成功") // 构建包含 tid 的 urlstr var urlstr string typePlatform := r.GetInt("platform_id") if typePlatform == 8 { //快手平台 urlstr = fmt.Sprintf("https://open.kuaishou.com/oauth2/connect?state=%s&app_id=ks671599294546520767&redirect_uri=https://younggee.com/kuaishouVideo&scope=user_video_info,user_info&response_type=code", tid) } else if typePlatform == 2 { //抖音平台 urlstr = fmt.Sprintf("https://open.douyin.com/platform/oauth/connect/?state=%s&client_key=awi77xl5kpl16hmi&response_type=code&scope=user_info,data.external.user,video.list.bind&redirect_uri=https://www.younggee.com/douyinauth", tid) } else { return &TalentHttpResult{Code: -1, Msg: "platform_id值不合法"} } // 执行任务 //var buf []byte var text string var ok bool var tasks chromedp.Tasks if typePlatform == 2 { //抖音 tasks = chromedp.Tasks{ chromedp.Navigate(urlstr), // chromedp.WaitVisible(`#semiTabPanelqr > div > div > div.qr-container > img`, chromedp.ByQuery), chromedp.AttributeValue(`#semiTabPanelqr > div > div > div.qr-container > img`, "src", &text, &ok), } } else { //快手 tasks = chromedp.Tasks{ chromedp.Navigate(urlstr), // chromedp.WaitVisible(`body > div > div > div > div.qr-code-main > img:nth-child(1)`, chromedp.ByQuery), chromedp.AttributeValue(`body > div > div > div > div.qr-code-main > img:nth-child(1)`, "src", &text, &ok), } } //浏览器启动! err = chromedp.Run(ctx, tasks) if err != nil { log.Fatal(err) } println("text----->", text) println("ok----->", ok) println("url----->", urlstr) fmt.Println("代码运行时间:", time.Since(startTime)) // 设置定时器,100秒后关闭上下文 go func() { <-time.After(100 * time.Second) CleanupChromedpContext(cancel) }() return &TalentHttpResult{Code: 0, Msg: "success", Data: text} } func GetKsEcomQrcode(r *ghttp.Request) *TalentHttpResult { //达人id获取 tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) fmt.Println("tid:", tid, "err:", err) if err != nil { return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} } // 记录开始时间 startTime := time.Now() // 创建一个新的上下文 ctx, cancel := chromedp.NewContext(context.Background()) //ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithDebugf(log.Printf)) // 设置定时器,100秒后关闭上下文 //go func() { // <-time.After(100 * time.Second) // CleanupChromedpContext(cancel) //}() //需要访问的网址,无state,扫码后跳转到订购页面 urlstr := fmt.Sprintf("https://login.kwaixiaodian.com/?biz=fuwu&redirect_url=https://fuwu.kwaixiaodian.com/new/detail?id=22328015871939") // 执行任务 var text string var ok bool var tasks chromedp.Tasks //快手小店授权码 tasks = chromedp.Tasks{ chromedp.Navigate(urlstr), //点击出现二维码 chromedp.Click(`#root > div > div.UqM2VqEDB3qdOFvSOHAB > div > div > div > div.container__content > div:nth-child(1) > div`), // 获取二维码 chromedp.AttributeValue(`#root > div > div.UqM2VqEDB3qdOFvSOHAB > div > div > div > div.Kmu1OHb3un0JBPZDkGa8 > div.JAc4fjotOx_h8lOtGzuB > div.dIaAe1BsCdQL6GtURkNI > img`, "src", &text, &ok), } //浏览器启动! err = chromedp.Run(ctx, tasks) if err != nil { fmt.Println("errInfo---", err.Error()) } fmt.Println("代码运行时间:", time.Since(startTime)) // 返回二维码的操作已经完成,后续操作(go fun)在后台继续进行 // 启动后台 goroutine 监听重定向并处理 go HandleAfterRedirect(r, ctx, cancel) return &TalentHttpResult{Code: 0, Msg: "二维码已生成", Data: text} } // 此函数执行完毕后 func HandleAfterRedirect(r *ghttp.Request, ctx context.Context, cancel context.CancelFunc) *TalentHttpResult { fmt.Println("HandleAfterRedirect-----") //达人id获取 tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) fmt.Println("tid:", tid, "err:", err) var isChecked1, isChecked2 bool //var isChecked1 bool var currentURL string var subscribeURL string authURL := fmt.Sprintf("https://open.kwaixiaodian.com/oauth/authorize?app_id=ks651333097154138217&redirectUri=https://younggee.com/kuaishouauth&scope=merchant_distribution,merchant_refund,merchant_item,merchant_order,user_info,merchant_servicemarket,merchant_user,merchant_logistics&state=%s", tid) // 执行任务 fmt.Println("扫码跳转成功,正在提交订单...") err = chromedp.Run(ctx, chromedp.Tasks{ // 等待用户扫码并跳转后,点击“立即购买”按钮,在这识别用户是否扫码完成 chromedp.WaitVisible(`#main_root > div > div.yPXHTHq9cx_6vEhWohw_ > div.Jb15b0XMeXvmyWfEfrvq > div.m5IIGVbmvqsfZdb00GFO > div.JktibAFTihy_wzOaJXHl > div.Cbz2c2xjrwvEPJnVK4iA > div.KY1LeQ_L_xVgT9RzkLow.cgxWbYdA4fs28QuNN36F > button`, chromedp.ByQuery), chromedp.Click(`#main_root > div > div.yPXHTHq9cx_6vEhWohw_ > div.Jb15b0XMeXvmyWfEfrvq > div.m5IIGVbmvqsfZdb00GFO > div.JktibAFTihy_wzOaJXHl > div.Cbz2c2xjrwvEPJnVK4iA > div.KY1LeQ_L_xVgT9RzkLow.cgxWbYdA4fs28QuNN36F > button`, chromedp.ByQuery), // 等待第一个 checkbox 元素可见 chromedp.WaitVisible(`#app > div > section > main > div.cart-container > div.price-content > div.checkbox > label > span.ant-checkbox > input`, chromedp.ByQuery), // 检查第一个 checkbox 是否已选中 chromedp.EvaluateAsDevTools(`document.querySelector('#app > div > section > main > div.cart-container > div.price-content > div.checkbox > label > span.ant-checkbox > input').checked`, &isChecked1), chromedp.Location(&subscribeURL), }) if err != nil { log.Fatalf("任务1执行失败:%v", err) } fmt.Println("订阅页面---->", subscribeURL) if !isChecked1 { fmt.Println("第一个 Checkbox 未选中。现在选中...") err = chromedp.Run(ctx, chromedp.Click(`#app > div > section > main > div.cart-container > div.price-content > div.checkbox > label > span.ant-checkbox > input`, chromedp.ByQuery)) fmt.Println("选中成功") if err != nil { log.Fatalf("点击第一个 checkbox 失败:%v", err) } } else { fmt.Println("第一个 Checkbox 已经选中。") } // 确认订单 拆分 fmt.Println("这一步进行服务的订阅...") err = chromedp.Run(ctx, chromedp.Tasks{ chromedp.Click(`#app > div > section > main > div.cart-container > div.price-content > div.checkout > button`, chromedp.ByQuery), chromedp.Navigate(authURL), chromedp.Location(¤tURL), }) //出现点击服务订阅,失败的问题,等不到下一个页面的出现 //// Step 1: 点击按钮 //fmt.Println("1") //err = chromedp.Run(ctx, chromedp.Tasks{ // chromedp.Click(`#app > div > section > main > div.cart-container > div.price-content > div.checkout > button`, chromedp.ByQuery), // 点击按钮 //}) //fmt.Println("2") //if err != nil { // log.Fatalf("获取 afterbuyURL 失败: %v", err) //} // Step 4: 跳转到授权页面 //err = chromedp.Run(ctx, chromedp.WaitVisible(`#app > div > section > main > div.paid-container > div.title`, chromedp.ByQuery)) //if err != nil { // log.Fatalf("跳转到授权页面失败:%v", err) //} //fmt.Println("3") // Step 4: 跳转到授权页面 //err = chromedp.Run(ctx, chromedp.Navigate(authURL)) //if err != nil { // log.Fatalf("跳转到授权页面失败:%v", err) //} // Step 5: 获取授权页面 URL err = chromedp.Run(ctx, chromedp.Location(¤tURL)) if err != nil { log.Fatalf("获取 currentURL 失败:%v", err) } if err != nil { fmt.Println("提交订单失败---", err.Error()) } fmt.Println("当前授权地址url---》:", currentURL) fmt.Println("服务的订阅成功...") //提交订单需要时间处理 //time.Sleep(3 * time.Second) //跳转到授权页面 //err = chromedp.Run(ctx, chromedp.Tasks{ // chromedp.Navigate(authURL), // chromedp.Location(¤tURL), //}) //期望含code //不管是否订购过 , 肯定会包含 ,需要手动点击则点击, 不需要手动点击直接授权成功 if strings.Contains(currentURL, "https://open.kwaixiaodian.com/oauth/authorize") { log.Println("into https://open.kwaixiaodian.com/oauth/authorize") err = chromedp.Run(ctx, chromedp.WaitVisible(`#root > div > div > div > div > div.flex.f-jc-c.UcUNDIrRp1R3a9EnEbQE > div > div.f-1.f-fs-0.Zcms9k6vZGxKICWMIrdG > div.wNrvV7C_9L5FB2oxmyLe > div > div:nth-child(2) > label > span.ant-checkbox > input`, chromedp.ByQuery)) if err != nil { log.Println("WaitVisible执行失败:%v", err) } log.Println("等待第二个 checkbox 元素可见") // 检查第二个 checkbox 获得选中情况 err = chromedp.Run(ctx, chromedp.EvaluateAsDevTools(`document.querySelector('#root > div > div > div > div > div.flex.f-jc-c.UcUNDIrRp1R3a9EnEbQE > div > div.f-1.f-fs-0.Zcms9k6vZGxKICWMIrdG > div.wNrvV7C_9L5FB2oxmyLe > div > div:nth-child(2) > label > span.ant-checkbox > input').checked`, &isChecked2)) if err != nil { log.Println("EvaluateAsDevTools执行失败:%v", err) } log.Println("检查第二个 checkbox 获得选中情况") // 如果第二个 checkbox 没有选中,则点击选中 if !isChecked2 { //选中同意 err = chromedp.Run(ctx, chromedp.Click(`#root > div > div > div > div > div.flex.f-jc-c.UcUNDIrRp1R3a9EnEbQE > div > div.f-1.f-fs-0.Zcms9k6vZGxKICWMIrdG > div.wNrvV7C_9L5FB2oxmyLe > div > div:nth-child(2) > label > span.ant-checkbox > input`, chromedp.ByQuery)) //点击授权按钮,肯定重定向过去了 } else { fmt.Println("第二个 Checkbox 已经选中。") } //点击后授权成功 err = chromedp.Run(ctx, chromedp.Click(`#root > div > div > div > div > div.flex.f-jc-c.UcUNDIrRp1R3a9EnEbQE > div > div.f-1.f-fs-0.Zcms9k6vZGxKICWMIrdG > div.wNrvV7C_9L5FB2oxmyLe > button`, chromedp.ByQuery)) //等待跳转并且授权 time.Sleep(10 * time.Second) CleanupChromedpContext(cancel) fmt.Println("ok") } // 输出执行完成的日志 fmt.Println("授权完成") return &TalentHttpResult{Code: 0, Msg: "已重定向到kuaishouauth接口", Data: nil} } // 检查数据库表中是否有达人对应的数据 且 token未过期 func CheckAccount(r *ghttp.Request) *TalentHttpResult { fmt.Println("into check") //达人id获取 tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) if err != nil { return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} } userInfo := &youngee_talent_model.KuaishouUserInfo{} err = g.DB().Model(userInfo).Where("talent_id", tid).Scan(&userInfo) fmt.Println("userInfo*********", userInfo) if err != nil { // 查询失败(未找到结果),返回失败结果 return &TalentHttpResult{Code: -1, Msg: "Query failed", Data: nil} } //有查询结果,看是否accessToken是否有效 key, err1 := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ?", tid).Value() if err1 != nil { return &TalentHttpResult{Code: -1, Msg: "query database fail"} } AccessToken := key.String() _, err2 := user.GetUserinfo(ClientKey, AccessToken) if err2 != nil { //前端接收code=-2表示token过期 return &TalentHttpResult{Code: -2, Msg: "accessToken过期", Data: nil} } // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "success", Data: userInfo} } // / 抖音二维码绑定,轮询此接口, //func CheckDyNewAccount(r *ghttp.Request) *TalentHttpResult { // //check到了更新时间在两秒内的插入的数据。则说明已绑定。弹窗消失。 // tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) // redisDyBindStatusKey := fmt.Sprintf("Bind:%s", tid) // bindStatus, err := g.Redis().DoVar("GET", redisDyBindStatusKey) // if bindStatus.String() == "bound_to_other" { // return &TalentHttpResult{Code: -1, Msg: "此账号已被其他达人绑定", Data: nil} // } // if err != nil { // return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} // } // // 获取当前时间 // currentTime := gtime.Now() // // 查询数据库中符合条件的所有记录 // var userInfos []youngee_talent_model.KuaishouUserInfo // err = g.DB().Model("platform_kuaishou_user_info"). // Where("talent_id = ?", tid). // Scan(&userInfos) // if err != nil { // return &TalentHttpResult{Code: -4, Msg: "Database query failed"} // } // // if len(userInfos) == 0 { // // 如果没有符合条件的数据,返回失败 // return &TalentHttpResult{Code: -5, Msg: "No valid data found"} // } // // // 找到 CreateTime 最新的记录 // latestUserInfo := userInfos[0] // for _, info := range userInfos[1:] { // if info.CreateTime.After(latestUserInfo.CreateTime) { // latestUserInfo = info // } // } // // // 计算创建时间与当前时间的差值 // timeDiff := currentTime.Sub(latestUserInfo.CreateTime) // if timeDiff <= 3*time.Second { // return &TalentHttpResult{Code: 0, Msg: "success"} // } // // // 超过时间差,返回失败 // return &TalentHttpResult{Code: -6, Msg: "Time difference exceeds 3 seconds"} //} // 用于轮询,检查数据库表中是否有达人对应的数据,有就删掉,/kuaishouath中会插入。 func CheckNewAccount(r *ghttp.Request) *TalentHttpResult { //check到了更新时间在两秒内的插入的数据。则说明已绑定。弹窗消失。 tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) platformId := r.GetQueryInt("platform_id", 0) if platformId == 0 { return &TalentHttpResult{Code: -1, Msg: "参数格式有误", Data: nil} } if platformId == 4 || platformId == 8 || platformId == 2 { redisKsBindStatusKey := fmt.Sprintf("Bind:%s", tid) bindStatus, err := g.Redis().DoVar("GET", redisKsBindStatusKey) if bindStatus != nil && bindStatus.String() == "bound_to_other" { return &TalentHttpResult{Code: -1, Msg: "此快手账号已被其他达人绑定", Data: nil} } if err != nil { return &TalentHttpResult{Code: -3, Msg: "Get talent id failed"} } // 获取当前时间 currentTime := gtime.Now() // 查询数据库中符合条件的所有记录 var userInfos []youngee_talent_model.KuaishouUserInfo err = g.DB().Model("platform_kuaishou_user_info"). Where("talent_id = ? AND platform_id=?", tid, platformId). Scan(&userInfos) if err != nil { return &TalentHttpResult{Code: -4, Msg: "Database query failed"} } //当前达人没有绑定过账号 if len(userInfos) == 0 { // 如果没有符合条件的数据,返回失败 // 如果没有符合条件的数据,返回继续轮询的提示 return &TalentHttpResult{Code: -5, Msg: "没有数据,继续轮询"} } // 找到 CreateTime 最新的记录 latestUserInfo := userInfos[0] for _, info := range userInfos[1:] { if info.CreateTime.After(latestUserInfo.CreateTime) { latestUserInfo = info } } // 计算创建时间与当前时间的差值 timeDiff := currentTime.Sub(latestUserInfo.CreateTime) if timeDiff <= 5*time.Second { return &TalentHttpResult{Code: 0, Msg: "授权完成,数据已入库"} } // 超过时间差,返回失败 return &TalentHttpResult{Code: -2, Msg: "数据还没进来,继续轮训"} } else { return &TalentHttpResult{Code: -2, Msg: "platform_id只能是2,4,8"} } } func CheckTokenExp(openId string, platformId int, talentId string) int { fmt.Println("into checktoken") //检查平台8 if platformId == 8 { key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ? & platform_id = ? & open_id = ? ", talentId, platformId, openId).Value() if err != nil { fmt.Println("query database fail") return -1 } AccessToken := key.String() _, err = user.GetUserinfo(ClientKey1, AccessToken) if err != nil { //过期 fmt.Println("平台accessToken过期") //前端接收code=-2表示token过期 return 0 } else { fmt.Println("平台AT未过期") return 1 } //检查电商授权4 } else { key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ? & platform_id = ? & open_id = ? ", talentId, platformId, openId).Value() if err != nil { fmt.Println("query database fail") return 2 } AccessToken := key.String() _, err = user.GetUserinfo(ClientKey, AccessToken) if err != nil { //过期 //前端接收code=-2表示token过期 fmt.Println("电商accessToken过期") return 3 } else { fmt.Println("电商accessToken未过期") return 4 } } } // func CheckTokenExp(r *ghttp.Request) *TalentHttpResult { // //达人id获取 // tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) // //平台id获取 // platformId := r.GetInt("platform_id") // //openId获取 // openId := r.GetString("open_id") // //检查平台授权 // if platformId == 8 { // key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ? & platform_id = ? & open_id = ? ", tid, platformId, openId).Value() // if err != nil { // return &TalentHttpResult{Code: -1, Msg: "query database fail"} // } // AccessToken := key.String() // res_info1, err := user.GetUserinfo(ClientKey1, AccessToken) // if err != nil { //过期 // //前端接收code=-2表示token过期 // return &TalentHttpResult{Code: -2, Msg: "平台accessToken过期", Data: nil} // } else { // return &TalentHttpResult{Code: 0, Msg: "平台accessToken未过期", Data: res_info1} // } // //检查电商授权 // } else { // key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ? & platform_id = ? & open_id = ? ", tid, platformId, openId).Value() // if err != nil { // return &TalentHttpResult{Code: -1, Msg: "query database fail"} // } // AccessToken := key.String() // res_info, err := user.GetUserinfo(ClientKey, AccessToken) // if err != nil { //过期 // //前端接收code=-2表示token过期 // return &TalentHttpResult{Code: -2, Msg: "电商accessToken过期", Data: nil} // } else { // return &TalentHttpResult{Code: 0, Msg: "平台accessToken未过期", Data: res_info} // } // } // // if err != nil { // return &TalentHttpResult{Code: -3, Msg: "Get talent id failed"} // } // key, err1 := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ? & platform_id = ? & open_id = ? ", tid, platformId, openId).Value() // if err1 != nil { // return &TalentHttpResult{Code: -1, Msg: "query database fail"} // } // AccessToken := key.String() // res_info, err2 := user.GetUserinfo(ClientKey, AccessToken) // if err2 != nil { // //前端接收code=-2表示token过期 // return &TalentHttpResult{Code: -2, Msg: "accessToken过期", Data: nil} // } // // 查询成功,返回成功结果和数据 // return &TalentHttpResult{Code: 0, Msg: "success", Data: res_info} // } func AddWindowKuaishouList(r *ghttp.Request) *TalentHttpResult { // 定义用于存储查询结果的结构体切片 var results []*youngee_talent_model.KuaishouUserInfo // 获取talent_id tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) // 查询此达人下,platform_id 为 8 或 4 的所有数据,并将结果扫描到结构体切片中 err := g.DB().Model(&youngee_talent_model.KuaishouUserInfo{}). Where("talent_id = ?", tid). Where("platform_id IN (?, ?)", 4, 8). Order("open_id ASC, platform_id DESC"). // 按 open_id 排序,确保每组的数据连续,并且 platform_id=4 的数据排在前面 Scan(&results) if err != nil { return &TalentHttpResult{Code: 1, Msg: "查询失败", Data: nil} } // 创建一个 map,用于记录每个 open_id 对应的记录 //key是openid,value是数组,从而实现一对多 openIdMap := make(map[string][]*youngee_talent_model.KuaishouUserInfo) // 将查询结果按 open_id 分组 for _, record := range results { openIdMap[record.OpenId] = append(openIdMap[record.OpenId], record) } //筛选出 open_id 对应两条数据且 platform_id = 4 的记录 var resInfo []*youngee_talent_model.KuaishouUserInfo for _, records := range openIdMap { if len(records) == 2 { // 确保有两条数据,排除只有一个 platform_id 的情况 for _, record := range records { if record.PlatformId == 4 { // 选取 platform_id = 4(电商) 的记录,含有粉丝数就好,因为需要加入橱窗 resInfo = append(resInfo, record) break } } } } // 遍历 resInfo 检查过期和是否报名 for _, record := range resInfo { // 调用 CheckKuaishouTokenExp 函数,检查 openId 是否过期 expired := CheckKuaishouTokenExp(record.OpenId) fmt.Println() // 将过期检查结果赋值给 expired 属性 ,过期则不能被选中用于加入橱窗 record.Expired = expired } return &TalentHttpResult{Code: 0, Msg: "快手列表展示成功", Data: resInfo} } func SignUpSecKuaishouList(r *ghttp.Request) *TalentHttpResult { selectionId := r.GetString("selection_id") //判断是否满足领样条件 var freeStrategies []*youngee_talent_model.FreeStrategy err := g.DB().Model("free_strategy").Where("selection_id = ?", selectionId).Scan(&freeStrategies) var results []*youngee_talent_model.KuaishouUserInfo tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) // 查询此达人下,platform_id 为 8 或 4 的所有数据,并将结果扫描到结构体切片中 err = g.DB().Model(&youngee_talent_model.KuaishouUserInfo{}). Where("talent_id = ?", tid). Where("platform_id IN (?, ?)", 4, 8). Order("open_id ASC, platform_id DESC"). // 按 open_id 排序,确保每组的数据连续,并且 platform_id=4 的数据排在前面 Scan(&results) if err != nil { return &TalentHttpResult{Code: 1, Msg: "查询失败", Data: nil} } // 创建一个 map,用于记录每个 open_id 对应的记录 //key是openid,value是数组,从而实现一对多 openIdMap := make(map[string][]*youngee_talent_model.KuaishouUserInfo) // 将查询结果按 open_id 分组 for _, record := range results { openIdMap[record.OpenId] = append(openIdMap[record.OpenId], record) } // 筛选出 open_id 对应两条数据且 platform_id = 4 的记录 var resInfo []*youngee_talent_model.KuaishouUserInfo for _, records := range openIdMap { if len(records) == 2 { // 确保有两条数据,排除只有一个 platform_id 的情况 for _, record := range records { if record.PlatformId == 4 { // 选取 platform_id = 4(电商) 的记录,含有粉丝数就好,因为需要加入橱窗 resInfo = append(resInfo, record) break } } } } // 遍历 resInfo 检查过期、是否报名、是否满足领养条件 for _, record := range resInfo { // 调用 CheckKuaishouTokenExp 函数,检查 openId 是否过期 expired := CheckKuaishouTokenExp(record.OpenId) // 将过期检查结果赋值给 expired 属性 ,过期则不能被选中用于加入橱窗 record.Expired = expired //是否报名 isSignResult, err := g.DB().Model("younggee_sec_task_info").Where("selection_id=? AND open_id=? AND talent_id=? AND sample_mode=?", selectionId, record.OpenId, tid, 1).One() // 根据查询结果设置 IsSign 属性 if err != nil || isSignResult.IsEmpty() { record.IsSign = 0 // 没有查到数据,设置为 0 } else { record.IsSign = 1 // 查到数据,设置为 1 } // fanNum := record.Fan fmt.Println("我的粉丝数", fanNum) saleNum30 := record.SaleNum30day for _, strategy := range freeStrategies { // 判断粉丝数是否满足当前策略的要求 if fanNum >= strategy.FollowersLow && saleNum30 >= strategy.SaleNum { // 如果粉丝数满足策略的范围,设置 is_fit 为 1 record.IsOk = 1 break } else { // 否则设置 is_fit 为 0 record.IsOk = 0 } } } return &TalentHttpResult{Code: 0, Msg: "列表展示成功", Data: resInfo} } // 只有绑定两个快手,且快手电商没有过期,才能访问到这 func AddWindowWithKsAccount(r *ghttp.Request) *TalentHttpResult { // 获取talent_id tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) var signSecTaskReq *youngee_talent_model.SignSecTaskFromWindowReq err := r.ParseForm(&signSecTaskReq) if err != nil { return &TalentHttpResult{Code: -1, Msg: "POST参数解析失败", Data: err.Error()} } value, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id=? AND open_id = ? AND platform_id = 4 ", tid, signSecTaskReq.OpenId).Value() if err != nil { fmt.Println("query db fail") } accessToken := value.String() fmt.Println("access_token:--->", accessToken) pIdSlice := []string{signSecTaskReq.KSProductId} httpResult := youngee_sectask_service.IsCreateSecTask(r) fmt.Println("httpResult--->", httpResult) if httpResult.Code == 1 { //存在报名信息,仅添加橱窗 _, err := merchant.AddItemsToShelf(ClientKey, SignSecret, accessToken, pIdSlice) if err != nil { //表示添加失敗,沒有開通 fmt.Println("假如橱窗错误信息为---", err.Error()) return &TalentHttpResult{Code: -1, Msg: "存在报名信息,未开通橱窗、商品不存在或已下线", Data: err.Error()} } // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "无需创建任务,加入橱窗成功", Data: nil} } else { //不存在报名信息 _, err := merchant.AddItemsToShelf(ClientKey, SignSecret, accessToken, pIdSlice) if err != nil { //表示添加失敗,沒有開通 fmt.Println("假如橱窗错误信息为---", err.Error()) return &TalentHttpResult{Code: -1, Msg: "不存在报名信息,未开通橱窗、商品不存在或已下线", Data: err.Error()} } code := youngee_sectask_service.SignUpSecTaskFromWindow(r).Code fmt.Println("滴滴答答啦放假啦", code) if code != 0 { return &TalentHttpResult{Code: -1, Msg: "创建报名信息失败", Data: nil} } //报名人数加一 _, err = g.DB().Model("younggee_selection_info"). Where("selection_id=?", signSecTaskReq.SelectionId). Increment("enroll_num", 1) if err != nil { // 错误处理 fmt.Println(err.Error()) } return &TalentHttpResult{Code: 0, Msg: "创建了任务,加入橱窗成功", Data: nil} } } func AddWindow(r *ghttp.Request) *TalentHttpResult { pId := r.GetString("product_id") //通过pId获取kuaishou_product_id pIdSlice := []string{pId} //达人id获取 tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) //加入橱窗-条件不满足的快手账号不能被选中 //条件1. 没有开通橱窗 //判断此快手账号是否绑定了两 openId := r.GetString("open_id") // 执行数据库查询 count, err := g.DB().Model("platform_kuaishou_user_info"). Where("talent_id = ? AND open_id = ?", tid, openId). Count() if err != nil { // 处理错误 return &TalentHttpResult{Code: -4, Msg: "出错了"} } if count != 2 { return &TalentHttpResult{Code: -5, Msg: "达人需要授权两个码"} } if err != nil { return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} } key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ?", tid).Value() if err != nil { return &TalentHttpResult{Code: -2, Msg: "query database fail"} } AccessToken := key.String() res_info, err := merchant.AddItemsToShelf(ClientKey, SignSecret, AccessToken, pIdSlice) if err != nil { //前端接收code=-3表示添加失敗,沒有開通 return &TalentHttpResult{Code: -3, Msg: "未開通、商品不存在或已下线", Data: nil} } // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "加入橱窗成功", Data: res_info} } func GetKuaishouFansNum(r *ghttp.Request) *TalentHttpResult { //达人id获取 tid, err := utils.SessionTalentInfo.GetTalentIdFromSession(r) fmt.Println("********&&&&&&&&&&,tid", tid) if err != nil { return &TalentHttpResult{Code: -1, Msg: "Get talent id failed"} } key, err1 := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("talent_id = ? ", tid).Value() if err1 != nil { return &TalentHttpResult{Code: -2, Msg: "query database fail"} } AccessToken := key.String() res_user, err2 := user.GetUserinfo(ClientKey, AccessToken) if err2 != nil { //前端接收code=-3表示添加失敗,沒有開通 return &TalentHttpResult{Code: -3, Msg: "获取快手用户信息出错", Data: nil} } // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "获取快手用户信息成功", Data: res_user.Data} } func QuerySalesFor30Days(r *ghttp.Request) *TalentHttpResult { fmt.Println("into querySalesFor30Days") ClientKey := "ks651333097154138217" //ClientSecret := "dBt0rVRhTpUqcrOYGGpv0A" SignSecret := "bf6393dce0a2b669ee348bebb837b0da" tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) // 创建一个 KuaishouUserInfo 结构体的实例 userInfo := &youngee_talent_model.KuaishouUserInfo{} // 查询数据库中的 access_token 字段 // 使用 g.DB() 获取数据库连接,并执行查询 key, err := g.DB().Model(userInfo).Fields("access_token").Where("talent_id = ?", tid).Value() AccessToken := key.String() if err != nil { // 处理错误 fmt.Println("Error querying access_token:", err) } // 输出查询到的 access_token 值 fmt.Println("Access Token:", AccessToken) // 获取当前时间的时间戳(毫秒) currentTime := time.Now().UnixNano() / int64(time.Millisecond) // 30天前的时间戳(毫秒) beginTime30DaysAgo := currentTime - 30*24*60*60*1000 // 定义每段查询的天数 intervalDays := 7 intervalMillis := int64(intervalDays * 24 * 60 * 60 * 1000) // 初始化 beginTime 和 endTime beginTime := beginTime30DaysAgo endTime := beginTime + intervalMillis saleNum := 0 //30天总销量 // 循环查询,先处理四个7天的时间段 for i := 0; i < 4; i++ { // 调整 endTime,确保不会超过当前时间 if endTime > currentTime { endTime = currentTime } saleNum += GetSaleNumByDayInterval(ClientKey, SignSecret, AccessToken, beginTime, endTime) // 更新时间段 beginTime = endTime endTime = beginTime + intervalMillis } // 最后处理剩余的2天时间段 endTime = currentTime saleNum += GetSaleNumByDayInterval(ClientKey, SignSecret, AccessToken, beginTime, endTime) // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "获取30天销售量成功", Data: saleNum} } func QueryOkSaleNum(r *ghttp.Request) *TalentHttpResult { tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) openID := r.GetString("open_id") // 创建一个 KuaishouUserInfo 结构体的实例 userInfo := &youngee_talent_model.KuaishouUserInfo{} // 查询数据库中的 access_token 字段 // 使用 g.DB() 获取数据库连接,并执行查询 key, err := g.DB().Model(userInfo).Fields("access_token").Where("talent_id = ? AND open_id= ? AND platform_id = ?", tid, openID, 4).Value() AccessToken := key.String() if err != nil { // 处理错误 fmt.Println("Error querying access_token:", err) } if key == nil { // 处理错误 fmt.Println("can not find talentId's bindinfo :", err) } //循环使用接口 // // 获取当前时间的时间戳(毫秒) currentTime := time.Now().UnixNano() / int64(time.Millisecond) // 90天前的时间戳(毫秒) beginTime90DaysAgo := currentTime - 90*24*60*60*1000 // 定义每段查询的天数 intervalDays := 7 intervalMillis := int64(intervalDays * 24 * 60 * 60 * 1000) // 初始化 beginTime 和 endTime beginTime := beginTime90DaysAgo endTime := beginTime + intervalMillis saleNum := 0 //90天总销量 // 循环查询,先处理四个7天的时间段 for i := 0; i < 12; i++ { // 调整 endTime,确保不会超过当前时间 if endTime > currentTime { endTime = currentTime } saleNum += GetSaleNumByDayInterval_Ok(ClientKey, SignSecret, AccessToken, beginTime, endTime) // 更新时间段 beginTime = endTime endTime = beginTime + intervalMillis } // 最后处理剩余的6天时间段 endTime = currentTime saleNum += GetSaleNumByDayInterval_Ok(ClientKey, SignSecret, AccessToken, beginTime, endTime) // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "获取90天销售量成功", Data: saleNum} } //func VideoCount(r *ghttp.Request) *TalentHttpResult { // tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) // // 创建一个 KuaishouUserInfo 结构体的实例 // userInfo := &youngee_talent_model.KuaishouUserInfo{} // // // 查询数据库中的 access_token 字段 // // 使用 g.DB() 获取数据库连接,并执行查询 // key, err := g.DB().Model(userInfo).Fields("access_token").Where("talent_id = ? AND platform_id = ?", tid, 8).Value() // AccessToken := key.String() // if err != nil { // // 处理错误 // fmt.Println("Error querying access_token:", err) // } // if key == nil { // // 处理错误 // fmt.Println("can not find talentId's bindinfo :", err) // } // // count, err := GetVideoCount(ClientKey1, AccessToken) // return &TalentHttpResult{Code: 0, Msg: "获取总作品数成功", Data: count} //} // //func LikeCount(r *ghttp.Request) *TalentHttpResult { // tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) // // 创建一个 KuaishouUserInfo 结构体的实例 // userInfo := &youngee_talent_model.KuaishouUserInfo{} // // // 查询数据库中的 access_token 字段 // // 使用 g.DB() 获取数据库连接,并执行查询 // key, err := g.DB().Model(userInfo).Fields("access_token").Where("talent_id = ? AND platform_id = ?", tid, 8).Value() // AccessToken := key.String() // if err != nil { // // 处理错误 // fmt.Println("Error querying access_token:", err) // } // if key == nil { // // 处理错误 // fmt.Println("can not find talentId's bindinfo :", err) // } // count, err := GetLikeCount(ClientKey1, AccessToken) // return &TalentHttpResult{Code: 0, Msg: "获取总点赞数成功", Data: count} //} // 获取用户快手平台账号列表 func GetKuaishouList(r *ghttp.Request) *TalentHttpResult { // 从 session 中获取 talent_id tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) userInfo := &youngee_talent_model.KuaishouUserInfo{} // 查询 platformId 为 8 或 4 的所有数据 results, err := g.DB().Model(userInfo).Where("talent_id = ?", tid). Where("platform_id IN (?, ?)", 4, 8). Order("platform_Id DESC"). All() if err != nil { fmt.Println("Error querying access_token:", err) return &TalentHttpResult{Code: -1, Msg: "查询出错", Data: nil} } // 检查查询结果是否为空 if len(results) == 0 { return &TalentHttpResult{Code: -2, Msg: "此达人无快手账号绑定", Data: nil} } // 使用集合来存储唯一的 open_id,并计算不同的 open_id 的个数 openIDSet := make(map[string]struct{}) //key--openId value--对应的信息 userInfoMap := make(map[string]*youngee_talent_model.KuaishouUserInfo) for _, record := range results.List() { openID := gconv.String(record["open_id"]) platformID := record["platform_id"] //int类型 status := 0 //初始化 //检查 userInfoMap 中是否已经存在 openID //肯定会先处理8,所以遇到重复情况肯定是两个都授权了 _, exists := userInfoMap[openID] if exists { status = 1 //同时授权了两个码 userInfoMap[openID] = &youngee_talent_model.KuaishouUserInfo{ OpenId: openID, HeadUri: gconv.String(record["head_uri"]), NickName: gconv.String(record["nick_name"]), // 添加其他需要的字段 Fan: gconv.Int(record["fan"]), //这两个值默认为0 LikeNum: gconv.Int(record["like_num"]), VideoNum: gconv.Int(record["video_num"]), Status: status, } } //若同时有8和4的平台。处理了8就不会处理4了 if !exists { //只有一个且为4 if platformID == 4 { status = 2 //仅授权了电商 } else { status = 3 //仅授权了平台 } openIDSet[openID] = struct{}{} // 根据 platformID 赋值 userInfoMap[openID] = &youngee_talent_model.KuaishouUserInfo{ OpenId: openID, HeadUri: gconv.String(record["head_uri"]), NickName: gconv.String(record["nick_name"]), Skill: gconv.String(record["skill"]), Gender: gconv.String(record["gender"]), // 添加其他需要的字段 Fan: gconv.Int(record["fan"]), //这两个值默认为0 LikeNum: gconv.Int(record["like_num"]), VideoNum: gconv.Int(record["video_num"]), Status: status, } } } // 构建 UserInfo 列表 参数分别表示初始长度和容量 userInfoList := make([]*youngee_talent_model.KuaishouUserInfo, 0, len(userInfoMap)) for _, info := range userInfoMap { expStatus := CheckKuaishouTokenExp(info.OpenId) info.Status = expStatus //将 info 添加到 userInfoList 列表的末尾。 userInfoList = append(userInfoList, info) } // 计算不同的 open_id 的个数 uniqueOpenIDCount := len(openIDSet) // 创建 KSListResult 变量并赋值 ksListResult := &youngee_talent_model.KSListResult{ Count: uniqueOpenIDCount, UserInfo: userInfoList, } // 返回结果 return &TalentHttpResult{Code: 1, Msg: "返回快手列表成功", Data: ksListResult} } // 获取用户快手电商过期信息 肯定绑定两个码,因为只是用于加入橱窗---我只检查电商是否过期 func CheckKuaishouTokenExp(openId string) int { fmt.Println("into checktoken") //一个openId同时对应了8和4,才进行过期检查,两个都检查,有一个过期则过期 key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("open_id = ? ", openId).Value() if err != nil { fmt.Println("query database fail") return -1 } AccessToken := key.String() _, err = user.GetUserinfo(ClientKey, AccessToken) if err != nil { //过期 fmt.Println("平台accessToken过期", err.Error()) return 1 } else { fmt.Println("未过期") return 0 } } func CheckDouyinTokenExp(openId string) int { fmt.Println("into checktoken") key, err := g.DB().Model("platform_kuaishou_user_info").Fields("access_token").Where("open_id = ? ", openId).Value() if err != nil { fmt.Println("query database fail") return -1 } AccessToken := key.String() _, err = douyinUser.GetUserInfo(openId, AccessToken) if err != nil { //过期 fmt.Println("平台accessToken过期") return 1 } else { fmt.Println("未过期") return 0 } } func GetDouyinList(r *ghttp.Request) *TalentHttpResult { // 获取达人对应的平台为2的列表,含基本信息 tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) userInfo := &youngee_talent_model.KuaishouUserInfo{} results, err := g.DB().Model(userInfo).Where("talent_id = ? AND platform_Id = ? ", tid, 2). All() if err != nil { fmt.Println("Error querying ", err) return &TalentHttpResult{Code: 0, Msg: "查询抖音列表失败", Data: nil} } // 创建一个存储用户信息的切片 UserInfoList := []*youngee_talent_model.KuaishouUserInfo{} // 遍历列表,判断是否过期并更新 Expired 属性 for _, record := range results.List() { openID := gconv.String(record["open_id"]) // 调用 CheckDouyinTokenExp 函数,获取过期状态 0/1 expiredStatus := CheckDouyinTokenExp(openID) // 更新 record 中的 Expired 字段值 record["Expired"] = expiredStatus err := gconv.Struct(record, userInfo) if err != nil { return nil } // 将 map 转换为 KuaishouUserInfo 结构体 // 添加到用户信息列表 UserInfoList = append(UserInfoList, userInfo) } // 返回 DYListResult 类型 return &TalentHttpResult{Code: 1, Msg: "返回抖音列表成功", Data: &youngee_talent_model.DYListResult{ Count: len(UserInfoList), UserInfo: UserInfoList, }} } func GetMyAccountList(r *ghttp.Request) *TalentHttpResult { // 获取达人对应的平台为2的列表,含基本信息 tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) pId := r.GetQueryInt("platform_id", 0) fmt.Println("PlatformId:", pId) if pId != 1 && pId != 3 && pId != 5 { return &TalentHttpResult{Code: -1, Msg: "platform_id无效"} } AccountList := []*youngee_talent_model.KuaishouUserInfo{} g.Model("platform_kuaishou_user_info").Where("talent_id=? AND platform_id=? AND is_delete = ?", tid, pId, 0).Scan(&AccountList) if len(AccountList) == 0 { return &TalentHttpResult{Code: 0, Msg: "无内容", Data: nil} } return &TalentHttpResult{Code: 1, Msg: "返回列表成功", Data: &youngee_talent_model.AccountListResult{ Count: len(AccountList), UserInfo: AccountList, }} } func QuerySalesFor90Days(r *ghttp.Request) *TalentHttpResult { tid, _ := utils.SessionTalentInfo.GetTalentIdFromSession(r) // 创建一个 KuaishouUserInfo 结构体的实例 userInfo := &youngee_talent_model.KuaishouUserInfo{} // 查询数据库中的 access_token 字段 // 使用 g.DB() 获取数据库连接,并执行查询 key, err := g.DB().Model(userInfo).Fields("access_token").Where("talent_id = ?", tid).Value() AccessToken := key.String() if err != nil { // 处理错误 fmt.Println("Error querying access_token:", err) } if key == nil { // 处理错误 fmt.Println("can not find talentId's bindinfo :", err) } //循环使用接口 // // 获取当前时间的时间戳(毫秒) currentTime := time.Now().UnixNano() / int64(time.Millisecond) // 30天前的时间戳(毫秒) beginTime90DaysAgo := currentTime - 90*24*60*60*1000 // 定义每段查询的天数 intervalDays := 7 intervalMillis := int64(intervalDays * 24 * 60 * 60 * 1000) // 初始化 beginTime 和 endTime beginTime := beginTime90DaysAgo endTime := beginTime + intervalMillis saleNum := 0 //90天总销量 // 循环查询,先处理四个7天的时间段 for i := 0; i < 12; i++ { // 调整 endTime,确保不会超过当前时间 if endTime > currentTime { endTime = currentTime } saleNum += GetSaleNumByDayInterval(ClientKey, SignSecret, AccessToken, beginTime, endTime) // 更新时间段 beginTime = endTime endTime = beginTime + intervalMillis } // 最后处理剩余的6天时间段 endTime = currentTime saleNum += GetSaleNumByDayInterval(ClientKey, SignSecret, AccessToken, beginTime, endTime) // 查询成功,返回成功结果和数据 return &TalentHttpResult{Code: 0, Msg: "获取30天销售量成功", Data: saleNum} } func GetSaleNumByDayInterval(ClientKey string, SignSecret string, AccessToken string, beginTime int64, endTime int64) int { pageSize := 100 totalSaleNum := 0 // 定义要查询的订单状态 // [30:已付款] [50:已收货] [60:已结算] [80:已失效] statuses := []int{30, 50, 60} // 遍历所有订单状态并调用 Corderlist 函数 for _, status := range statuses { // 初始化 pcursor pcursor := "" for { // 调用 Corderlist 函数获取订单列表 response, err := merchant.Corderlist(ClientKey, SignSecret, AccessToken, status, pageSize, beginTime, endTime, pcursor) fmt.Println("response********", response) if err != nil { fmt.Printf("Error calling Corderlist: %v\n", err) break } // 检查响应代码 if response.Code != "1" { fmt.Printf("Corderlist response error: %s\n", response.Msg) break } // 累加订单中商品的数量 for _, order := range response.Data.OrderViews { for _, product := range order.CPSOrderProductViews { totalSaleNum += product.Num } } // 检查分页指针 pcursor //100个订单以内的情况 if response.Data.Cursor == "nomore" { break } //大于等于100个订单 // 更新 pcursor 以获取下一页数据 pcursor = response.Data.Cursor // 处理分页后的数据 // 如果 pcursor 不是 "nomore",我们需要累加最后一条订单的数量 if len(response.Data.OrderViews) > 0 { lastOrder := response.Data.OrderViews[len(response.Data.OrderViews)-1] if len(lastOrder.CPSOrderProductViews) > 0 { lastProduct := lastOrder.CPSOrderProductViews[len(lastOrder.CPSOrderProductViews)-1] totalSaleNum += lastProduct.Num } } } } return totalSaleNum } func GetSaleNumByDayInterval_Ok(ClientKey string, SignSecret string, AccessToken string, beginTime int64, endTime int64) int { pageSize := 100 totalSaleNum := 0 // 定义要查询的订单状态 // [30:已付款] [50:已收货] [60:已结算] [80:已失效] statuses := []int{60} // 遍历所有订单状态并调用 Corderlist 函数 for _, status := range statuses { // 初始化 pcursor pcursor := "" for { // 调用 Corderlist 函数获取订单列表 response, err := merchant.Corderlist(ClientKey, SignSecret, AccessToken, status, pageSize, beginTime, endTime, pcursor) fmt.Println("response********", response) if err != nil { fmt.Printf("Error calling Corderlist: %v\n", err) break } // 检查响应代码 if response.Code != "1" { fmt.Printf("Corderlist response error: %s\n", response.Msg) break } // 累加订单中商品的数量 for _, order := range response.Data.OrderViews { for _, product := range order.CPSOrderProductViews { totalSaleNum += product.Num } } // 检查分页指针 pcursor //100个订单以内的情况 if response.Data.Cursor == "nomore" { break } //大于等于100个订单 // 更新 pcursor 以获取下一页数据 pcursor = response.Data.Cursor // 处理分页后的数据 // 如果 pcursor 不是 "nomore",我们需要累加最后一条订单的数量 if len(response.Data.OrderViews) > 0 { lastOrder := response.Data.OrderViews[len(response.Data.OrderViews)-1] if len(lastOrder.CPSOrderProductViews) > 0 { lastProduct := lastOrder.CPSOrderProductViews[len(lastOrder.CPSOrderProductViews)-1] totalSaleNum += lastProduct.Num } } } } return totalSaleNum }