285 lines
7.1 KiB
Go
285 lines
7.1 KiB
Go
package main
|
||
|
||
import (
|
||
"bufio"
|
||
"context"
|
||
"flag"
|
||
"fmt"
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"bindbox-game/configs"
|
||
"bindbox-game/internal/pkg/env"
|
||
"bindbox-game/internal/pkg/logger"
|
||
"bindbox-game/internal/repository/mysql"
|
||
"bindbox-game/internal/repository/mysql/model"
|
||
usersvc "bindbox-game/internal/service/user"
|
||
welfaresvc "bindbox-game/internal/service/welfare_activity"
|
||
|
||
"github.com/eiannone/keyboard"
|
||
)
|
||
|
||
func main() {
|
||
operator := flag.String("operator", "cli", "操作人标识")
|
||
flag.Parse()
|
||
|
||
env.Active()
|
||
configs.Init()
|
||
|
||
logg, err := logger.NewCustomLogger(logger.WithOutputInConsole(), logger.WithDebugLevel())
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 初始化日志失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
repo, err := mysql.New()
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 初始化 MySQL 失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
defer repo.DbRClose()
|
||
defer repo.DbWClose()
|
||
|
||
userSvc := usersvc.New(logg, repo)
|
||
welfareSvc := welfaresvc.New(logg, repo)
|
||
ctx := context.Background()
|
||
reader := bufio.NewReader(os.Stdin)
|
||
|
||
fmt.Printf("[WARN] 当前环境: %s\n", env.Active().Value())
|
||
fmt.Println("[WARN] 该工具会写入真实已支付测试订单,仅用于 dev/fat/uat")
|
||
|
||
userID, err := promptInt64(reader, "请输入用户ID")
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 读取用户ID失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
user, err := userSvc.GetProfile(ctx, userID)
|
||
if err != nil || user == nil {
|
||
fmt.Printf("[ERR] 用户不存在: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
fmt.Println("[INFO] 用户信息")
|
||
fmt.Printf("- 用户名: %s\n", fallback(user.Nickname, "-"))
|
||
fmt.Printf("- 用户ID: %d\n", user.ID)
|
||
fmt.Printf("- 手机号: %s\n", fallback(user.Mobile, "-"))
|
||
|
||
packages, err := loadActivePackages(ctx, repo)
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 加载活动次卡套餐失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
if len(packages) == 0 {
|
||
fmt.Println("[WARN] 当前没有可用的活动次卡套餐")
|
||
return
|
||
}
|
||
|
||
selectedPackage, err := selectPackage(packages)
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 选择套餐失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
count, err := promptInt32(reader, "请输入购买次数")
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 读取购买次数失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
purchase, err := userSvc.CreatePaidGamePassOrderForTest(ctx, usersvc.CreatePaidGamePassOrderForTestInput{
|
||
UserID: user.ID,
|
||
PackageID: selectedPackage.ID,
|
||
Count: count,
|
||
Operator: *operator,
|
||
})
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 模拟消费失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
fmt.Println("[OK] 模拟消费成功")
|
||
fmt.Printf("- 订单号: %s\n", purchase.OrderNo)
|
||
fmt.Printf("- 套餐: %s\n", purchase.PackageName)
|
||
fmt.Printf("- 次数: %d\n", purchase.Count)
|
||
fmt.Printf("- 支付金额: %s\n", formatAmount(purchase.TotalAmount))
|
||
fmt.Printf("- 支付时间: %s\n", purchase.PaidAt.Format("2006-01-02 15:04:05"))
|
||
|
||
activities, err := welfareSvc.ListJoinableActivitiesForUser(ctx, user.ID)
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 加载福利活动失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
if len(activities) == 0 {
|
||
fmt.Println("[WARN] 当前没有可选的进行中福利活<E588A9><E6B4BB>")
|
||
return
|
||
}
|
||
|
||
selected, err := selectActivity(activities)
|
||
if err != nil {
|
||
fmt.Printf("[ERR] 选择活动失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
fmt.Println("[INFO] 已选择福利活动")
|
||
fmt.Printf("- 活动ID: %d\n", selected.ActivityID)
|
||
fmt.Printf("- 活动名称: %s\n", selected.Title)
|
||
fmt.Printf("- 当前消费/门槛: %s/%s\n", formatAmount(selected.CurrentPaid), formatAmount(selected.ThresholdAmount))
|
||
|
||
if err := welfareSvc.Join(ctx, selected.ActivityID, user.ID); err != nil {
|
||
fmt.Printf("[ERR] 参与失败: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
fmt.Println("[OK] 参与成功")
|
||
fmt.Printf("- 用户ID: %d\n", user.ID)
|
||
fmt.Printf("- 活动ID: %d\n", selected.ActivityID)
|
||
fmt.Printf("- 开奖时间: %s\n", selected.DrawTime.Format("2006-01-02 15:04:05"))
|
||
fmt.Println("[INFO] 后续请等待系统自动开奖,再登录验证中奖、订单、背包和中奖名单")
|
||
}
|
||
|
||
func promptInt64(reader *bufio.Reader, label string) (int64, error) {
|
||
fmt.Printf("%s: ", label)
|
||
text, err := reader.ReadString('\n')
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
return strconv.ParseInt(strings.TrimSpace(text), 10, 64)
|
||
}
|
||
|
||
func promptInt32(reader *bufio.Reader, label string) (int32, error) {
|
||
value, err := promptInt64(reader, label)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
return int32(value), nil
|
||
}
|
||
|
||
func loadActivePackages(ctx context.Context, repo mysql.Repo) ([]*model.GamePassPackages, error) {
|
||
var packages []*model.GamePassPackages
|
||
err := repo.GetDbR().WithContext(ctx).
|
||
Where("status = 1 AND deleted_at IS NULL").
|
||
Order("sort_order DESC, id ASC").
|
||
Find(&packages).Error
|
||
return packages, err
|
||
}
|
||
|
||
func selectPackage(items []*model.GamePassPackages) (*model.GamePassPackages, error) {
|
||
if err := keyboard.Open(); err != nil {
|
||
return nil, err
|
||
}
|
||
defer keyboard.Close()
|
||
|
||
index := 0
|
||
for {
|
||
fmt.Println()
|
||
fmt.Println("请选择活动次卡套餐(↑↓ 选择,Enter 确认,Esc 退出)")
|
||
for i, item := range items {
|
||
prefix := " "
|
||
if i == index {
|
||
prefix = "> "
|
||
}
|
||
activityScope := "全局"
|
||
if item.ActivityID > 0 {
|
||
activityScope = fmt.Sprintf("活动ID:%d", item.ActivityID)
|
||
}
|
||
fmt.Printf("%s%s | 套餐ID:%d | %s | %d次 | %s\n", prefix, item.Name, item.ID, activityScope, item.PassCount, formatAmount(item.Price))
|
||
}
|
||
|
||
char, key, err := keyboard.GetKey()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
switch key {
|
||
case keyboard.KeyArrowUp:
|
||
if index > 0 {
|
||
index--
|
||
}
|
||
case keyboard.KeyArrowDown:
|
||
if index < len(items)-1 {
|
||
index++
|
||
}
|
||
case keyboard.KeyEnter:
|
||
return items[index], nil
|
||
case keyboard.KeyEsc, keyboard.KeyCtrlC:
|
||
return nil, fmt.Errorf("已取消选择")
|
||
default:
|
||
if char == 0 {
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func selectActivity(items []welfaresvc.JoinableActivityItem) (*welfaresvc.JoinableActivityItem, error) {
|
||
if err := keyboard.Open(); err != nil {
|
||
return nil, err
|
||
}
|
||
defer keyboard.Close()
|
||
|
||
index := 0
|
||
for {
|
||
fmt.Println()
|
||
fmt.Println("请选择福利活动(↑↓ 选择,Enter 确认,Esc 退出)")
|
||
for i, item := range items {
|
||
prefix := " "
|
||
if i == index {
|
||
prefix = "> "
|
||
}
|
||
status := "未达标"
|
||
if item.Joined {
|
||
status = "已参与"
|
||
} else if item.CanJoin {
|
||
status = "可参与"
|
||
}
|
||
fmt.Printf("%s%s %s %s/%s %s\n", prefix, item.Title, typeLabel(item.Type), formatAmount(item.CurrentPaid), formatAmount(item.ThresholdAmount), status)
|
||
}
|
||
|
||
char, key, err := keyboard.GetKey()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
switch key {
|
||
case keyboard.KeyArrowUp:
|
||
if index > 0 {
|
||
index--
|
||
}
|
||
case keyboard.KeyArrowDown:
|
||
if index < len(items)-1 {
|
||
index++
|
||
}
|
||
case keyboard.KeyEnter:
|
||
return &items[index], nil
|
||
case keyboard.KeyEsc, keyboard.KeyCtrlC:
|
||
return nil, fmt.Errorf("已取消选择")
|
||
default:
|
||
if char == 0 {
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func formatAmount(cents int64) string {
|
||
return fmt.Sprintf("%.2f", float64(cents)/100)
|
||
}
|
||
|
||
func typeLabel(t string) string {
|
||
switch t {
|
||
case welfaresvc.TypeWeekly:
|
||
return "每周福利"
|
||
case welfaresvc.TypeMonthly:
|
||
return "每月福利"
|
||
default:
|
||
return "每日福利"
|
||
}
|
||
}
|
||
|
||
func fallback(v, d string) string {
|
||
if strings.TrimSpace(v) == "" {
|
||
return d
|
||
}
|
||
return v
|
||
}
|