145 lines
5.8 KiB
Go
145 lines
5.8 KiB
Go
package asset
|
|
|
|
import (
|
|
"context"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
biz "kra/internal/biz/asset"
|
|
"kra/internal/data/ledger"
|
|
"time"
|
|
)
|
|
|
|
type Provider interface{ DB() *gorm.DB }
|
|
type repo struct{ data Provider }
|
|
|
|
func NewRepo(data Provider) biz.Repo { return &repo{data: data} }
|
|
func (r *repo) db(ctx context.Context) *gorm.DB { return r.data.DB().WithContext(ctx) }
|
|
|
|
type row struct {
|
|
UserID uint `gorm:"column:user_id"`
|
|
Username string
|
|
Nickname string
|
|
Avatar string
|
|
Enable int
|
|
CreatedAt time.Time
|
|
DiamondBalance, TotalRechargeCents, TotalSpentDiamonds int64
|
|
LastLoginAt *time.Time
|
|
}
|
|
|
|
func query(db *gorm.DB, f biz.Filter) *gorm.DB {
|
|
q := db.Table("sys_users").Joins("LEFT JOIN live_wallets ON live_wallets.user_id = sys_users.id").Where("sys_users.deleted_at IS NULL")
|
|
if f.Keyword != "" {
|
|
v := "%" + f.Keyword + "%"
|
|
q = q.Where("sys_users.username LIKE ? OR sys_users.nick_name LIKE ?", v, v)
|
|
}
|
|
if f.UserID > 0 {
|
|
q = q.Where("sys_users.id = ?", f.UserID)
|
|
}
|
|
if f.Enabled != nil {
|
|
if *f.Enabled {
|
|
q = q.Where("sys_users.enable = 1")
|
|
} else {
|
|
q = q.Where("sys_users.enable <> 1")
|
|
}
|
|
}
|
|
if len(f.CreatedAt) == 2 {
|
|
q = q.Where("sys_users.created_at BETWEEN ? AND ?", f.CreatedAt[0], f.CreatedAt[1])
|
|
}
|
|
return q
|
|
}
|
|
func (r *repo) List(ctx context.Context, f biz.Filter, o biz.ListOptions) ([]*biz.User, int64, error) {
|
|
q := query(r.db(ctx), f)
|
|
var total int64
|
|
if err := q.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
var rows []row
|
|
sel := "sys_users.id AS user_id,sys_users.username,sys_users.nick_name AS nickname,sys_users.header_img AS avatar,sys_users.enable,sys_users.created_at,COALESCE(live_wallets.diamond_balance,0) AS diamond_balance,COALESCE(live_wallets.total_recharge_cents,0) AS total_recharge_cents,COALESCE(live_wallets.total_spent_diamonds,0) AS total_spent_diamonds,(SELECT MAX(created_at) FROM sys_login_logs WHERE user_id=sys_users.id AND status=?) AS last_login_at"
|
|
if err := q.Select(sel, true).Order(userOrder(o.OrderBy)).Offset(o.Offset).Limit(o.Limit).Scan(&rows).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
out := make([]*biz.User, 0, len(rows))
|
|
for i := range rows {
|
|
out = append(out, toBiz(&rows[i]))
|
|
}
|
|
return out, total, nil
|
|
}
|
|
func (r *repo) Get(ctx context.Context, id uint) (*biz.User, error) {
|
|
items, _, err := r.List(ctx, biz.Filter{UserID: id}, biz.ListOptions{Limit: 1})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(items) == 0 {
|
|
return nil, biz.ErrNotFound
|
|
}
|
|
v := items[0]
|
|
var orders []ledger.RechargeOrderPO
|
|
if err := r.db(ctx).Where("user_id = ?", id).Order("created_at DESC").Limit(20).Find(&orders).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
for _, x := range orders {
|
|
status := "pending"
|
|
if x.CreditedAt != nil {
|
|
status = "paid"
|
|
}
|
|
v.RecentOrders = append(v.RecentOrders, biz.OrderRecord{OrderNo: x.OrderNo, Diamonds: x.Diamonds, AmountCents: x.AmountCents, Status: status, CreatedAt: x.CreatedAt})
|
|
}
|
|
var sends []ledger.GiftSendPO
|
|
if err := r.db(ctx).Where("user_id = ?", id).Order("created_at DESC").Limit(20).Find(&sends).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
for _, x := range sends {
|
|
v.RecentSends = append(v.RecentSends, biz.SendRecord{SerialNo: x.SerialNo, RoomName: x.RoomName, GiftName: x.GiftName, GiftIcon: x.GiftIcon, DiamondTotal: x.DiamondTotal, CreatedAt: x.CreatedAt})
|
|
}
|
|
return v, nil
|
|
}
|
|
func (r *repo) SetEnabled(ctx context.Context, id uint, enabled bool) error {
|
|
value := 2
|
|
if enabled {
|
|
value = 1
|
|
}
|
|
res := r.db(ctx).Table("sys_users").Where("id = ? AND deleted_at IS NULL", id).Update("enable", value)
|
|
if res.Error != nil {
|
|
return res.Error
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return biz.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
func (r *repo) Adjust(ctx context.Context, v *biz.Adjustment) (*biz.User, error) {
|
|
err := r.db(ctx).Transaction(func(tx *gorm.DB) error {
|
|
wallet := ledger.WalletPO{UserID: v.UserID}
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("user_id = ?", v.UserID).FirstOrCreate(&wallet).Error; err != nil {
|
|
return err
|
|
}
|
|
balance := wallet.DiamondBalance
|
|
if v.Type == "decrease" {
|
|
if balance < v.Amount {
|
|
return biz.ErrInsufficient
|
|
}
|
|
balance -= v.Amount
|
|
} else {
|
|
balance += v.Amount
|
|
}
|
|
if err := tx.Model(&wallet).Update("diamond_balance", balance).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.Create(&ledger.BalanceAdjustmentPO{UserID: v.UserID, OperatorUserID: v.OperatorUserID, Type: v.Type, Amount: v.Amount, Reason: v.Reason, BalanceAfter: balance}).Error
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return r.Get(ctx, v.UserID)
|
|
}
|
|
func toBiz(v *row) *biz.User {
|
|
return &biz.User{UserID: v.UserID, Username: v.Username, Nickname: v.Nickname, Avatar: v.Avatar, Enabled: v.Enable == 1, DiamondBalance: v.DiamondBalance, TotalRechargeCents: v.TotalRechargeCents, TotalSpentDiamonds: v.TotalSpentDiamonds, CreatedAt: v.CreatedAt, LastLoginAt: v.LastLoginAt}
|
|
}
|
|
func userOrder(v string) string {
|
|
m := map[string]string{"id_asc": "sys_users.id ASC", "id_desc": "sys_users.id DESC", "balance_asc": "diamond_balance ASC", "balance_desc": "diamond_balance DESC", "recharge_asc": "total_recharge_cents ASC", "recharge_desc": "total_recharge_cents DESC", "spent_asc": "total_spent_diamonds ASC", "spent_desc": "total_spent_diamonds DESC", "created_asc": "sys_users.created_at ASC", "created_desc": "sys_users.created_at DESC", "created_at_asc": "sys_users.created_at ASC", "created_at_desc": "sys_users.created_at DESC", "last_login_asc": "last_login_at ASC", "last_login_desc": "last_login_at DESC"}
|
|
if x := m[v]; x != "" {
|
|
return x
|
|
}
|
|
return "sys_users.id ASC"
|
|
}
|