package asset_wallet import ( "context" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/errors" "gorm.io/gorm" ) // Service 资产钱包业务服务 // 负责管理端资产(卡/设备)钱包概况查询和流水列表查询 type Service struct { assetWalletStore *postgres.AssetWalletStore assetWalletTransactionStore *postgres.AssetWalletTransactionStore } // New 创建资产钱包服务实例 func New(assetWalletStore *postgres.AssetWalletStore, assetWalletTransactionStore *postgres.AssetWalletTransactionStore) *Service { return &Service{ assetWalletStore: assetWalletStore, assetWalletTransactionStore: assetWalletTransactionStore, } } // GetWallet 查询资产钱包概况 // assetType 为 card 或 device,映射到 resourceType = iot_card 或 device func (s *Service) GetWallet(ctx context.Context, assetType string, assetID uint) (*dto.AssetWalletResponse, error) { resourceType, err := mapAssetTypeToResourceType(assetType) if err != nil { return nil, err } wallet, err := s.assetWalletStore.GetByResourceTypeAndID(ctx, resourceType, assetID) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeNotFound, "该资产暂无钱包记录") } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询钱包失败") } statusText := walletStatusText(wallet.Status) return &dto.AssetWalletResponse{ WalletID: wallet.ID, ResourceType: wallet.ResourceType, ResourceID: wallet.ResourceID, Balance: wallet.Balance, FrozenBalance: wallet.FrozenBalance, AvailableBalance: wallet.Balance - wallet.FrozenBalance, Currency: wallet.Currency, Status: wallet.Status, StatusText: statusText, CreatedAt: wallet.CreatedAt, UpdatedAt: wallet.UpdatedAt, }, nil } // ListTransactions 查询资产钱包流水列表(分页) func (s *Service) ListTransactions(ctx context.Context, assetType string, assetID uint, req *dto.AssetWalletTransactionListRequest) (*dto.AssetWalletTransactionListResponse, error) { resourceType, err := mapAssetTypeToResourceType(assetType) if err != nil { return nil, err } page := req.Page if page < 1 { page = 1 } pageSize := req.PageSize if pageSize < 1 { pageSize = 20 } if pageSize > 100 { pageSize = 100 } offset := (page - 1) * pageSize transactions, err := s.assetWalletTransactionStore.ListByResourceIDWithFilter( ctx, resourceType, assetID, req.TransactionType, req.StartTime, req.EndTime, offset, pageSize, ) if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询流水列表失败") } total, err := s.assetWalletTransactionStore.CountByResourceIDWithFilter( ctx, resourceType, assetID, req.TransactionType, req.StartTime, req.EndTime, ) if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "统计流水数量失败") } list := make([]*dto.AssetWalletTransactionItem, 0, len(transactions)) for _, tx := range transactions { list = append(list, &dto.AssetWalletTransactionItem{ ID: tx.ID, TransactionType: tx.TransactionType, TransactionTypeText: transactionTypeText(tx.TransactionType), Amount: tx.Amount, BalanceBefore: tx.BalanceBefore, BalanceAfter: tx.BalanceAfter, ReferenceType: tx.ReferenceType, ReferenceNo: tx.ReferenceNo, Remark: tx.Remark, CreatedAt: tx.CreatedAt, }) } totalPages := int(total) / pageSize if int(total)%pageSize > 0 { totalPages++ } return &dto.AssetWalletTransactionListResponse{ List: list, Total: total, Page: page, PageSize: pageSize, TotalPages: totalPages, }, nil } // mapAssetTypeToResourceType 将路由参数 assetType(card/device)映射到数据库资源类型 func mapAssetTypeToResourceType(assetType string) (string, error) { switch assetType { case "card": return "iot_card", nil case "device": return "device", nil default: return "", errors.New(errors.CodeInvalidParam, "无效的资产类型,仅支持 card 或 device") } } // walletStatusText 翻译钱包状态文本 func walletStatusText(status int) string { switch status { case 1: return "正常" case 2: return "冻结" case 3: return "关闭" default: return "未知" } } // transactionTypeText 翻译交易类型文本 func transactionTypeText(transactionType string) string { switch transactionType { case "recharge": return "充值" case "deduct": return "扣款" case "refund": return "退款" default: return transactionType } }