Files
go-taobao/services/order.go
2026-02-09 16:05:56 +08:00

165 lines
4.2 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 services
import (
"fmt"
"log"
"strings"
"time"
"github.com/go-rod/rod"
)
// OrderResult 下单结果
type OrderResult struct {
Success bool
Message string
}
// Order 订单提交服务
type Order struct {
page *rod.Page
}
// NewOrder 创建订单服务
func NewOrder(page *rod.Page) *Order {
return &Order{page: page}
}
// 提交订单按钮选择器列表
var submitSelectors = []string{
"#submitOrder > div > div.btnBox--p9CumEtE > div.btn--QDjHtErD", // 淘宝新版提交按钮
}
// WaitForConfirmPage 等待订单确认页加载
func (o *Order) WaitForConfirmPage(timeout time.Duration) error {
log.Println("[订单] 等待订单确认页加载...")
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
url := o.page.MustEval("() => window.location.href").String()
if o.isConfirmPage(url) {
log.Printf("[订单] 已进入订单确认页: %s", url)
o.page.MustWaitLoad()
time.Sleep(500 * time.Millisecond)
return nil
}
time.Sleep(100 * time.Millisecond)
}
return fmt.Errorf("等待订单确认页超时")
}
// Refresh 刷新当前订单确认页
func (o *Order) Refresh() {
log.Println("[订单] 刷新订单确认页...")
o.page.MustReload().MustWaitLoad()
o.page.MustWaitIdle()
log.Println("[订单] 刷新完成")
}
// CanSubmit 检测当前订单页是否可以提交(按钮存在且未被禁用)
func (o *Order) CanSubmit() bool {
for _, sel := range submitSelectors {
el, err := o.page.Timeout(1 * time.Second).Element(sel)
if err != nil || el == nil {
continue
}
// 检查按钮是否被禁用class 含 disabled / 属性 disabled 等)
className, _ := el.Attribute("class")
if className != nil && strings.Contains(*className, "disabled") {
log.Printf("[订单] 按钮存在但被禁用: %s", sel)
return false
}
disabledAttr, _ := el.Attribute("disabled")
if disabledAttr != nil {
log.Printf("[订单] 按钮存在但 disabled 属性: %s", sel)
return false
}
log.Printf("[订单] ✅ 按钮可点击: %s", sel)
return true
}
// 还可以检查页面上是否有"该商品暂时无法购买"之类的提示
pageText := o.page.MustEval(`() => document.body.innerText`).String()
if strings.Contains(pageText, "无法购买") ||
strings.Contains(pageText, "暂不可售") ||
strings.Contains(pageText, "已下架") ||
strings.Contains(pageText, "未开始") {
log.Println("[订单] 页面提示商品暂时无法购买")
return false
}
log.Println("[订单] 未找到提交按钮")
return false
}
// RefreshUntilCanSubmit 循环刷新订单页,直到可以提交,返回时表示可以立即点击提交
func (o *Order) RefreshUntilCanSubmit(interval time.Duration, maxAttempts int) bool {
for i := 1; i <= maxAttempts; i++ {
log.Printf("[订单] 第 %d/%d 次检测是否可购买...", i, maxAttempts)
if o.CanSubmit() {
log.Println("[订单] ✅ 商品可购买!")
return true
}
if i < maxAttempts {
time.Sleep(interval)
o.Refresh()
}
}
log.Println("[订单] 已达最大检测次数,商品仍不可购买")
return false
}
// Submit 点击"提交订单"按钮
func (o *Order) Submit() *OrderResult {
log.Println("[订单] 点击提交订单...")
for _, sel := range submitSelectors {
el, err := o.page.Timeout(2 * time.Second).Element(sel)
if err == nil && el != nil {
el.MustClick()
log.Printf("[订单] 已点击提交按钮: %s", sel)
time.Sleep(1 * time.Second)
return o.checkResult()
}
}
return &OrderResult{
Success: false,
Message: "未找到提交订单按钮",
}
}
// checkResult 检查下单结果
func (o *Order) checkResult() *OrderResult {
time.Sleep(2 * time.Second)
url := o.page.MustEval("() => window.location.href").String()
log.Printf("[订单] 提交后 URL: %s", url)
if strings.Contains(url, "cashier") ||
strings.Contains(url, "pay") ||
strings.Contains(url, "alipay") {
return &OrderResult{
Success: true,
Message: "抢购成功!请尽快完成付款",
}
}
return &OrderResult{
Success: false,
Message: fmt.Sprintf("提交后仍在: %s", url),
}
}
// isConfirmPage 判断 URL 是否为订单确认页
func (o *Order) isConfirmPage(url string) bool {
return strings.Contains(url, "buy.taobao.com") ||
strings.Contains(url, "buyertrade")
}