package service import ( "context" "errors" "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" walletDao "shop-user-trade/dao/wallet" walletDto "shop-user-trade/model/dto/wallet" walletEntity "shop-user-trade/model/entity/wallet" ) type wallet struct{} // Wallet 钱包服务 var Wallet = new(wallet) // GetByUserId 根据用户ID获取钱包 func (s *wallet) GetByUserId(ctx context.Context, req *walletDto.GetWalletByUserIdReq) (*walletDto.GetWalletByUserIdResp, error) { w, err := walletDao.Wallet.GetByUserID(ctx, req.UserId) if err != nil { g.Log().Errorf(ctx, "获取用户钱包失败, userId: %d, error: %v", req.UserId, err) return nil, err } if w == nil { return nil, errors.New("钱包不存在") } return &walletDto.GetWalletByUserIdResp{ Data: walletDto.WalletInfo{ ID: w.Id, UserID: w.UserID, Balance: w.Balance, Currency: w.Currency, Status: int(w.Status), }, }, nil } // Create 创建钱包 func (s *wallet) Create(ctx context.Context, req *walletDto.CreateWalletReq) (*walletDto.CreateWalletResp, error) { // 检查钱包是否已存在 existing, err := walletDao.Wallet.GetByUserID(ctx, req.UserId) if err != nil { g.Log().Errorf(ctx, "检查用户钱包失败, userId: %d, error: %v", req.UserId, err) return nil, err } if existing != nil { return nil, errors.New("钱包已存在") } id, err := walletDao.Wallet.Create(ctx, req) if err != nil { g.Log().Errorf(ctx, "创建钱包失败, userId: %d, error: %v", req.UserId, err) return nil, err } return &walletDto.CreateWalletResp{ Data: walletDto.CreateWalletData{WalletID: id}, }, nil } // UpdateBalance 更新余额 func (s *wallet) UpdateBalance(ctx context.Context, req *walletDto.UpdateBalanceReq) (*walletDto.UpdateBalanceResp, error) { w, err := walletDao.Wallet.GetByID(ctx, req.WalletID) if err != nil { g.Log().Errorf(ctx, "获取钱包失败, walletId: %d, error: %v", req.WalletID, err) return nil, err } if w == nil { return nil, errors.New("钱包不存在") } // 检查余额是否充足 if req.Type == "expense" && w.Balance < req.Amount { return nil, errors.New("余额不足") } // 记录操作前余额 balanceBefore := w.Balance var balanceAfter int64 switch req.Type { case "income": balanceAfter = balanceBefore + req.Amount case "expense": balanceAfter = balanceBefore - req.Amount default: balanceAfter = balanceBefore } // 更新余额(乐观锁) success, err := walletDao.Wallet.UpdateBalance(ctx, req.WalletID, req.Amount, req.Type, w.Version) if err != nil { g.Log().Errorf(ctx, "更新余额失败, walletId: %d, error: %v", req.WalletID, err) return nil, err } if !success { return nil, errors.New("余额更新失败,请重试") } // 记录流水日志 logReq := &walletDto.CreateWalletLogReq{ UserID: w.UserID, WalletID: w.Id, OrderNo: req.OrderNo, TransactionNo: req.TransactionNo, Type: req.Type, Amount: req.Amount, BalanceBefore: balanceBefore, BalanceAfter: balanceAfter, Currency: w.Currency, Description: req.Description, ExtraData: req.ExtraData, } if _, err = walletDao.Wallet.CreateLog(ctx, logReq); err != nil { g.Log().Warningf(ctx, "记录钱包日志失败, walletId: %d, error: %v", req.WalletID, err) } return &walletDto.UpdateBalanceResp{ Success: true, Message: "更新成功", }, nil } // GetWalletLogs 获取钱包日志 func (s *wallet) GetWalletLogs(ctx context.Context, req *walletDto.GetWalletLogsReq) (*walletDto.GetWalletLogsResp, error) { logs, total, err := walletDao.Wallet.ListLogs(ctx, req.UserId, req.Page, req.PageSize) if err != nil { return nil, fmt.Errorf("获取钱包日志失败: %w", err) } var logInfos []walletDto.WalletLogInfo for _, log := range logs { logInfos = append(logInfos, s.logEntityToInfo(&log)) } return &walletDto.GetWalletLogsResp{ Data: walletDto.WalletLogData{ Logs: logInfos, Total: total, }, }, nil } // logEntityToInfo 日志实体转换为Info func (s *wallet) logEntityToInfo(e *walletEntity.WalletLog) walletDto.WalletLogInfo { info := walletDto.WalletLogInfo{} _ = gconv.Struct(e, &info) info.ID = e.Id info.Type = string(e.Type) if e.CreatedAt != nil { info.CreatedAt = e.CreatedAt.String() } return info }