第一版
This commit is contained in:
164
services/order.go
Normal file
164
services/order.go
Normal file
@@ -0,0 +1,164 @@
|
||||
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")
|
||||
}
|
||||
Reference in New Issue
Block a user