基础架构

This commit is contained in:
2025-07-13 16:36:20 +08:00
parent e3d64e7485
commit 807004f78d
128 changed files with 17232 additions and 11396 deletions

View File

@@ -3,6 +3,7 @@ package entities
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
@@ -65,3 +66,11 @@ func (u *UserSecrets) Deactivate() {
func (u *UserSecrets) Activate() {
u.IsActive = true
}
// BeforeCreate GORM钩子创建前自动生成UUID
func (u *UserSecrets) BeforeCreate(tx *gorm.DB) error {
if u.ID == "" {
u.ID = uuid.New().String()
}
return nil
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"time"
"github.com/google/uuid"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
@@ -69,3 +70,11 @@ func (w *Wallet) SubtractBalance(amount decimal.Decimal) error {
func (w *Wallet) GetFormattedBalance() string {
return w.Balance.String()
}
// BeforeCreate GORM钩子创建前自动生成UUID
func (w *Wallet) BeforeCreate(tx *gorm.DB) error {
if w.ID == "" {
w.ID = uuid.New().String()
}
return nil
}

View File

@@ -1,336 +0,0 @@
package handlers
import (
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"tyapi-server/internal/domains/finance/dto"
"tyapi-server/internal/domains/finance/services"
"tyapi-server/internal/shared/interfaces"
)
// FinanceHandler 财务HTTP处理器
type FinanceHandler struct {
financeService *services.FinanceService
responseBuilder interfaces.ResponseBuilder
logger *zap.Logger
}
// NewFinanceHandler 创建财务HTTP处理器
func NewFinanceHandler(
financeService *services.FinanceService,
responseBuilder interfaces.ResponseBuilder,
logger *zap.Logger,
) *FinanceHandler {
return &FinanceHandler{
financeService: financeService,
responseBuilder: responseBuilder,
logger: logger,
}
}
// CreateWallet 创建钱包
// @Summary 创建钱包
// @Description 为用户创建钱包
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.CreateWalletRequest true "创建钱包请求"
// @Success 201 {object} dto.CreateWalletResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Router /finance/wallet [post]
func (h *FinanceHandler) CreateWallet(c *gin.Context) {
var req dto.CreateWalletRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("创建钱包参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
response, err := h.financeService.CreateWallet(c.Request.Context(), &req)
if err != nil {
h.logger.Error("创建钱包失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Created(c, response, "钱包创建成功")
}
// GetWallet 获取钱包信息
// @Summary 获取钱包信息
// @Description 获取用户钱包信息
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param user_id query string true "用户ID"
// @Success 200 {object} dto.WalletInfo
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/wallet [get]
func (h *FinanceHandler) GetWallet(c *gin.Context) {
userID := c.Query("user_id")
if userID == "" {
h.responseBuilder.BadRequest(c, "用户ID不能为空")
return
}
wallet, err := h.financeService.GetWallet(c.Request.Context(), userID)
if err != nil {
h.logger.Error("获取钱包信息失败", zap.Error(err))
h.responseBuilder.NotFound(c, err.Error())
return
}
h.responseBuilder.Success(c, wallet, "获取钱包信息成功")
}
// UpdateWallet 更新钱包
// @Summary 更新钱包
// @Description 更新用户钱包信息
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.UpdateWalletRequest true "更新钱包请求"
// @Success 200 {object} interfaces.SuccessResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/wallet [put]
func (h *FinanceHandler) UpdateWallet(c *gin.Context) {
var req dto.UpdateWalletRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("更新钱包参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
err := h.financeService.UpdateWallet(c.Request.Context(), &req)
if err != nil {
h.logger.Error("更新钱包失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "钱包更新成功")
}
// Recharge 充值
// @Summary 钱包充值
// @Description 为用户钱包充值
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.RechargeRequest true "充值请求"
// @Success 200 {object} dto.RechargeResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/wallet/recharge [post]
func (h *FinanceHandler) Recharge(c *gin.Context) {
var req dto.RechargeRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("充值参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
response, err := h.financeService.Recharge(c.Request.Context(), &req)
if err != nil {
h.logger.Error("充值失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, response, "充值成功")
}
// Withdraw 提现
// @Summary 钱包提现
// @Description 从用户钱包提现
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.WithdrawRequest true "提现请求"
// @Success 200 {object} dto.WithdrawResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/wallet/withdraw [post]
func (h *FinanceHandler) Withdraw(c *gin.Context) {
var req dto.WithdrawRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("提现参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
response, err := h.financeService.Withdraw(c.Request.Context(), &req)
if err != nil {
h.logger.Error("提现失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, response, "提现成功")
}
// CreateUserSecrets 创建用户密钥
// @Summary 创建用户密钥
// @Description 为用户创建访问密钥
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.CreateUserSecretsRequest true "创建密钥请求"
// @Success 201 {object} dto.CreateUserSecretsResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Router /finance/secrets [post]
func (h *FinanceHandler) CreateUserSecrets(c *gin.Context) {
var req dto.CreateUserSecretsRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("创建密钥参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
response, err := h.financeService.CreateUserSecrets(c.Request.Context(), &req)
if err != nil {
h.logger.Error("创建密钥失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Created(c, response, "密钥创建成功")
}
// GetUserSecrets 获取用户密钥
// @Summary 获取用户密钥
// @Description 获取用户访问密钥信息
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param user_id query string true "用户ID"
// @Success 200 {object} dto.UserSecretsInfo
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/secrets [get]
func (h *FinanceHandler) GetUserSecrets(c *gin.Context) {
userID := c.Query("user_id")
if userID == "" {
h.responseBuilder.BadRequest(c, "用户ID不能为空")
return
}
secrets, err := h.financeService.GetUserSecrets(c.Request.Context(), userID)
if err != nil {
h.logger.Error("获取密钥失败", zap.Error(err))
h.responseBuilder.NotFound(c, err.Error())
return
}
h.responseBuilder.Success(c, secrets, "获取密钥成功")
}
// RegenerateAccessKey 重新生成访问密钥
// @Summary 重新生成访问密钥
// @Description 重新生成用户的访问密钥
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.RegenerateAccessKeyRequest true "重新生成密钥请求"
// @Success 200 {object} dto.RegenerateAccessKeyResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/secrets/regenerate [post]
func (h *FinanceHandler) RegenerateAccessKey(c *gin.Context) {
var req dto.RegenerateAccessKeyRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("重新生成密钥参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
response, err := h.financeService.RegenerateAccessKey(c.Request.Context(), &req)
if err != nil {
h.logger.Error("重新生成密钥失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, response, "密钥重新生成成功")
}
// DeactivateUserSecrets 停用用户密钥
// @Summary 停用用户密钥
// @Description 停用用户的访问密钥
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.DeactivateUserSecretsRequest true "停用密钥请求"
// @Success 200 {object} interfaces.SuccessResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/secrets/deactivate [post]
func (h *FinanceHandler) DeactivateUserSecrets(c *gin.Context) {
var req dto.DeactivateUserSecretsRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("停用密钥参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
err := h.financeService.DeactivateUserSecrets(c.Request.Context(), &req)
if err != nil {
h.logger.Error("停用密钥失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "密钥停用成功")
}
// WalletTransaction 钱包交易
// @Summary 钱包交易
// @Description 用户间钱包转账
// @Tags 财务系统
// @Accept json
// @Produce json
// @Param request body dto.WalletTransactionRequest true "交易请求"
// @Success 200 {object} dto.WalletTransactionResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Failure 404 {object} interfaces.ErrorResponse
// @Router /finance/wallet/transaction [post]
func (h *FinanceHandler) WalletTransaction(c *gin.Context) {
var req dto.WalletTransactionRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Warn("交易参数验证失败", zap.Error(err))
h.responseBuilder.BadRequest(c, "请求参数错误")
return
}
response, err := h.financeService.WalletTransaction(c.Request.Context(), &req)
if err != nil {
h.logger.Error("交易失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, response, "交易成功")
}
// GetWalletStats 获取钱包统计
// @Summary 获取钱包统计
// @Description 获取钱包系统统计信息
// @Tags 财务系统
// @Accept json
// @Produce json
// @Success 200 {object} dto.WalletStatsResponse
// @Failure 400 {object} interfaces.ErrorResponse
// @Router /finance/wallet/stats [get]
func (h *FinanceHandler) GetWalletStats(c *gin.Context) {
stats, err := h.financeService.GetWalletStats(c.Request.Context())
if err != nil {
h.logger.Error("获取钱包统计失败", zap.Error(err))
h.responseBuilder.InternalError(c, "获取统计信息失败")
return
}
h.responseBuilder.Success(c, stats, "获取统计信息成功")
}

View File

@@ -1,46 +0,0 @@
package repositories
import (
"context"
"tyapi-server/internal/domains/finance/entities"
"tyapi-server/internal/shared/interfaces"
)
// WalletRepository 钱包仓储接口
type WalletRepository interface {
interfaces.Repository[entities.Wallet]
// 钱包管理
FindByUserID(ctx context.Context, userID string) (*entities.Wallet, error)
ExistsByUserID(ctx context.Context, userID string) (bool, error)
// 余额操作
UpdateBalance(ctx context.Context, userID string, balance interface{}) error
AddBalance(ctx context.Context, userID string, amount interface{}) error
SubtractBalance(ctx context.Context, userID string, amount interface{}) error
// 统计查询
GetTotalBalance(ctx context.Context) (interface{}, error)
GetActiveWalletCount(ctx context.Context) (int64, error)
}
// UserSecretsRepository 用户密钥仓储接口
type UserSecretsRepository interface {
interfaces.Repository[entities.UserSecrets]
// 密钥管理
FindByUserID(ctx context.Context, userID string) (*entities.UserSecrets, error)
FindByAccessID(ctx context.Context, accessID string) (*entities.UserSecrets, error)
ExistsByUserID(ctx context.Context, userID string) (bool, error)
ExistsByAccessID(ctx context.Context, accessID string) (bool, error)
// 密钥操作
UpdateLastUsedAt(ctx context.Context, accessID string) error
DeactivateByUserID(ctx context.Context, userID string) error
RegenerateAccessKey(ctx context.Context, userID string, accessID, accessKey string) error
// 过期密钥清理
GetExpiredSecrets(ctx context.Context) ([]entities.UserSecrets, error)
DeleteExpiredSecrets(ctx context.Context) error
}

View File

@@ -0,0 +1,57 @@
package repositories
import (
"context"
"tyapi-server/internal/domains/finance/entities"
"tyapi-server/internal/domains/finance/repositories/queries"
"tyapi-server/internal/shared/interfaces"
)
// FinanceStats 财务统计信息
type FinanceStats struct {
TotalWallets int64
ActiveWallets int64
TotalBalance string
TodayTransactions int64
}
// WalletRepository 钱包仓储接口
type WalletRepository interface {
interfaces.Repository[entities.Wallet]
// 基础查询 - 直接使用实体
GetByUserID(ctx context.Context, userID string) (*entities.Wallet, error)
GetByWalletAddress(ctx context.Context, walletAddress string) (*entities.Wallet, error)
GetByWalletType(ctx context.Context, userID string, walletType string) (*entities.Wallet, error)
// 复杂查询 - 使用查询参数
ListWallets(ctx context.Context, query *queries.ListWalletsQuery) ([]*entities.Wallet, int64, error)
// 业务操作
UpdateBalance(ctx context.Context, walletID string, balance string) error
AddBalance(ctx context.Context, walletID string, amount string) error
SubtractBalance(ctx context.Context, walletID string, amount string) error
ActivateWallet(ctx context.Context, walletID string) error
DeactivateWallet(ctx context.Context, walletID string) error
// 统计信息
GetStats(ctx context.Context) (*FinanceStats, error)
GetUserWalletStats(ctx context.Context, userID string) (*FinanceStats, error)
}
// UserSecretsRepository 用户密钥仓储接口
type UserSecretsRepository interface {
interfaces.Repository[entities.UserSecrets]
// 基础查询 - 直接使用实体
GetByUserID(ctx context.Context, userID string) (*entities.UserSecrets, error)
GetBySecretType(ctx context.Context, userID string, secretType string) (*entities.UserSecrets, error)
// 复杂查询 - 使用查询参数
ListUserSecrets(ctx context.Context, query *queries.ListUserSecretsQuery) ([]*entities.UserSecrets, int64, error)
// 业务操作
UpdateSecret(ctx context.Context, userID string, secretType string, secretValue string) error
DeleteSecret(ctx context.Context, userID string, secretType string) error
ValidateSecret(ctx context.Context, userID string, secretType string, secretValue string) (bool, error)
}

View File

@@ -1,410 +0,0 @@
package repositories
import (
"context"
"time"
"github.com/shopspring/decimal"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/finance/entities"
"tyapi-server/internal/shared/interfaces"
)
// GormWalletRepository 钱包GORM仓储实现
type GormWalletRepository struct {
db *gorm.DB
logger *zap.Logger
}
// NewGormWalletRepository 创建钱包GORM仓储
func NewGormWalletRepository(db *gorm.DB, logger *zap.Logger) *GormWalletRepository {
return &GormWalletRepository{
db: db,
logger: logger,
}
}
// Create 创建钱包
func (r *GormWalletRepository) Create(ctx context.Context, wallet entities.Wallet) error {
r.logger.Info("创建钱包", zap.String("user_id", wallet.UserID))
return r.db.WithContext(ctx).Create(&wallet).Error
}
// GetByID 根据ID获取钱包
func (r *GormWalletRepository) GetByID(ctx context.Context, id string) (entities.Wallet, error) {
var wallet entities.Wallet
err := r.db.WithContext(ctx).Where("id = ?", id).First(&wallet).Error
return wallet, err
}
// Update 更新钱包
func (r *GormWalletRepository) Update(ctx context.Context, wallet entities.Wallet) error {
r.logger.Info("更新钱包", zap.String("id", wallet.ID))
return r.db.WithContext(ctx).Save(&wallet).Error
}
// Delete 删除钱包
func (r *GormWalletRepository) Delete(ctx context.Context, id string) error {
r.logger.Info("删除钱包", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.Wallet{}, "id = ?", id).Error
}
// SoftDelete 软删除钱包
func (r *GormWalletRepository) SoftDelete(ctx context.Context, id string) error {
r.logger.Info("软删除钱包", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.Wallet{}, "id = ?", id).Error
}
// Restore 恢复钱包
func (r *GormWalletRepository) Restore(ctx context.Context, id string) error {
r.logger.Info("恢复钱包", zap.String("id", id))
return r.db.WithContext(ctx).Unscoped().Model(&entities.Wallet{}).Where("id = ?", id).Update("deleted_at", nil).Error
}
// Count 统计钱包数量
func (r *GormWalletRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.Wallet{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("user_id LIKE ?", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查钱包是否存在
func (r *GormWalletRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.Wallet{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建钱包
func (r *GormWalletRepository) CreateBatch(ctx context.Context, wallets []entities.Wallet) error {
r.logger.Info("批量创建钱包", zap.Int("count", len(wallets)))
return r.db.WithContext(ctx).Create(&wallets).Error
}
// GetByIDs 根据ID列表获取钱包
func (r *GormWalletRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.Wallet, error) {
var wallets []entities.Wallet
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&wallets).Error
return wallets, err
}
// UpdateBatch 批量更新钱包
func (r *GormWalletRepository) UpdateBatch(ctx context.Context, wallets []entities.Wallet) error {
r.logger.Info("批量更新钱包", zap.Int("count", len(wallets)))
return r.db.WithContext(ctx).Save(&wallets).Error
}
// DeleteBatch 批量删除钱包
func (r *GormWalletRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除钱包", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.Wallet{}, "id IN ?", ids).Error
}
// List 获取钱包列表
func (r *GormWalletRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.Wallet, error) {
var wallets []entities.Wallet
query := r.db.WithContext(ctx).Model(&entities.Wallet{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("user_id LIKE ?", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return wallets, query.Find(&wallets).Error
}
// WithTx 使用事务
func (r *GormWalletRepository) WithTx(tx interface{}) interfaces.Repository[entities.Wallet] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormWalletRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// FindByUserID 根据用户ID查找钱包
func (r *GormWalletRepository) FindByUserID(ctx context.Context, userID string) (*entities.Wallet, error) {
var wallet entities.Wallet
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&wallet).Error
if err != nil {
return nil, err
}
return &wallet, nil
}
// ExistsByUserID 检查用户钱包是否存在
func (r *GormWalletRepository) ExistsByUserID(ctx context.Context, userID string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Count(&count).Error
return count > 0, err
}
// UpdateBalance 更新余额
func (r *GormWalletRepository) UpdateBalance(ctx context.Context, userID string, balance interface{}) error {
return r.db.WithContext(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Update("balance", balance).Error
}
// AddBalance 增加余额
func (r *GormWalletRepository) AddBalance(ctx context.Context, userID string, amount interface{}) error {
return r.db.WithContext(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Update("balance", gorm.Expr("balance + ?", amount)).Error
}
// SubtractBalance 减少余额
func (r *GormWalletRepository) SubtractBalance(ctx context.Context, userID string, amount interface{}) error {
return r.db.WithContext(ctx).Model(&entities.Wallet{}).Where("user_id = ?", userID).Update("balance", gorm.Expr("balance - ?", amount)).Error
}
// GetTotalBalance 获取总余额
func (r *GormWalletRepository) GetTotalBalance(ctx context.Context) (interface{}, error) {
var total decimal.Decimal
err := r.db.WithContext(ctx).Model(&entities.Wallet{}).Select("COALESCE(SUM(balance), 0)").Scan(&total).Error
return total, err
}
// GetActiveWalletCount 获取激活钱包数量
func (r *GormWalletRepository) GetActiveWalletCount(ctx context.Context) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.Wallet{}).Where("is_active = ?", true).Count(&count).Error
return count, err
}
// GormUserSecretsRepository 用户密钥GORM仓储实现
type GormUserSecretsRepository struct {
db *gorm.DB
logger *zap.Logger
}
// NewGormUserSecretsRepository 创建用户密钥GORM仓储
func NewGormUserSecretsRepository(db *gorm.DB, logger *zap.Logger) *GormUserSecretsRepository {
return &GormUserSecretsRepository{
db: db,
logger: logger,
}
}
// Create 创建用户密钥
func (r *GormUserSecretsRepository) Create(ctx context.Context, secrets entities.UserSecrets) error {
r.logger.Info("创建用户密钥", zap.String("user_id", secrets.UserID))
return r.db.WithContext(ctx).Create(&secrets).Error
}
// GetByID 根据ID获取用户密钥
func (r *GormUserSecretsRepository) GetByID(ctx context.Context, id string) (entities.UserSecrets, error) {
var secrets entities.UserSecrets
err := r.db.WithContext(ctx).Where("id = ?", id).First(&secrets).Error
return secrets, err
}
// Update 更新用户密钥
func (r *GormUserSecretsRepository) Update(ctx context.Context, secrets entities.UserSecrets) error {
r.logger.Info("更新用户密钥", zap.String("id", secrets.ID))
return r.db.WithContext(ctx).Save(&secrets).Error
}
// Delete 删除用户密钥
func (r *GormUserSecretsRepository) Delete(ctx context.Context, id string) error {
r.logger.Info("删除用户密钥", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.UserSecrets{}, "id = ?", id).Error
}
// SoftDelete 软删除用户密钥
func (r *GormUserSecretsRepository) SoftDelete(ctx context.Context, id string) error {
r.logger.Info("软删除用户密钥", zap.String("id", id))
return r.db.WithContext(ctx).Delete(&entities.UserSecrets{}, "id = ?", id).Error
}
// Restore 恢复用户密钥
func (r *GormUserSecretsRepository) Restore(ctx context.Context, id string) error {
r.logger.Info("恢复用户密钥", zap.String("id", id))
return r.db.WithContext(ctx).Unscoped().Model(&entities.UserSecrets{}).Where("id = ?", id).Update("deleted_at", nil).Error
}
// Count 统计用户密钥数量
func (r *GormUserSecretsRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&entities.UserSecrets{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("user_id LIKE ? OR access_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
return count, query.Count(&count).Error
}
// Exists 检查用户密钥是否存在
func (r *GormUserSecretsRepository) Exists(ctx context.Context, id string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.UserSecrets{}).Where("id = ?", id).Count(&count).Error
return count > 0, err
}
// CreateBatch 批量创建用户密钥
func (r *GormUserSecretsRepository) CreateBatch(ctx context.Context, secrets []entities.UserSecrets) error {
r.logger.Info("批量创建用户密钥", zap.Int("count", len(secrets)))
return r.db.WithContext(ctx).Create(&secrets).Error
}
// GetByIDs 根据ID列表获取用户密钥
func (r *GormUserSecretsRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.UserSecrets, error) {
var secrets []entities.UserSecrets
err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&secrets).Error
return secrets, err
}
// UpdateBatch 批量更新用户密钥
func (r *GormUserSecretsRepository) UpdateBatch(ctx context.Context, secrets []entities.UserSecrets) error {
r.logger.Info("批量更新用户密钥", zap.Int("count", len(secrets)))
return r.db.WithContext(ctx).Save(&secrets).Error
}
// DeleteBatch 批量删除用户密钥
func (r *GormUserSecretsRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.logger.Info("批量删除用户密钥", zap.Strings("ids", ids))
return r.db.WithContext(ctx).Delete(&entities.UserSecrets{}, "id IN ?", ids).Error
}
// List 获取用户密钥列表
func (r *GormUserSecretsRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.UserSecrets, error) {
var secrets []entities.UserSecrets
query := r.db.WithContext(ctx).Model(&entities.UserSecrets{})
if options.Filters != nil {
for key, value := range options.Filters {
query = query.Where(key+" = ?", value)
}
}
if options.Search != "" {
query = query.Where("user_id LIKE ? OR access_id LIKE ?", "%"+options.Search+"%", "%"+options.Search+"%")
}
if options.Sort != "" {
order := "ASC"
if options.Order != "" {
order = options.Order
}
query = query.Order(options.Sort + " " + order)
}
if options.Page > 0 && options.PageSize > 0 {
offset := (options.Page - 1) * options.PageSize
query = query.Offset(offset).Limit(options.PageSize)
}
return secrets, query.Find(&secrets).Error
}
// WithTx 使用事务
func (r *GormUserSecretsRepository) WithTx(tx interface{}) interfaces.Repository[entities.UserSecrets] {
if gormTx, ok := tx.(*gorm.DB); ok {
return &GormUserSecretsRepository{
db: gormTx,
logger: r.logger,
}
}
return r
}
// FindByUserID 根据用户ID查找密钥
func (r *GormUserSecretsRepository) FindByUserID(ctx context.Context, userID string) (*entities.UserSecrets, error) {
var secrets entities.UserSecrets
err := r.db.WithContext(ctx).Where("user_id = ?", userID).First(&secrets).Error
if err != nil {
return nil, err
}
return &secrets, nil
}
// FindByAccessID 根据访问ID查找密钥
func (r *GormUserSecretsRepository) FindByAccessID(ctx context.Context, accessID string) (*entities.UserSecrets, error) {
var secrets entities.UserSecrets
err := r.db.WithContext(ctx).Where("access_id = ?", accessID).First(&secrets).Error
if err != nil {
return nil, err
}
return &secrets, nil
}
// ExistsByUserID 检查用户密钥是否存在
func (r *GormUserSecretsRepository) ExistsByUserID(ctx context.Context, userID string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.UserSecrets{}).Where("user_id = ?", userID).Count(&count).Error
return count > 0, err
}
// ExistsByAccessID 检查访问ID是否存在
func (r *GormUserSecretsRepository) ExistsByAccessID(ctx context.Context, accessID string) (bool, error) {
var count int64
err := r.db.WithContext(ctx).Model(&entities.UserSecrets{}).Where("access_id = ?", accessID).Count(&count).Error
return count > 0, err
}
// UpdateLastUsedAt 更新最后使用时间
func (r *GormUserSecretsRepository) UpdateLastUsedAt(ctx context.Context, accessID string) error {
return r.db.WithContext(ctx).Model(&entities.UserSecrets{}).Where("access_id = ?", accessID).Update("last_used_at", time.Now()).Error
}
// DeactivateByUserID 停用用户密钥
func (r *GormUserSecretsRepository) DeactivateByUserID(ctx context.Context, userID string) error {
return r.db.WithContext(ctx).Model(&entities.UserSecrets{}).Where("user_id = ?", userID).Update("is_active", false).Error
}
// RegenerateAccessKey 重新生成访问密钥
func (r *GormUserSecretsRepository) RegenerateAccessKey(ctx context.Context, userID string, accessID, accessKey string) error {
return r.db.WithContext(ctx).Model(&entities.UserSecrets{}).Where("user_id = ?", userID).Updates(map[string]interface{}{
"access_id": accessID,
"access_key": accessKey,
"updated_at": time.Now(),
}).Error
}
// GetExpiredSecrets 获取过期的密钥
func (r *GormUserSecretsRepository) GetExpiredSecrets(ctx context.Context) ([]entities.UserSecrets, error) {
var secrets []entities.UserSecrets
err := r.db.WithContext(ctx).Where("expires_at IS NOT NULL AND expires_at < ?", time.Now()).Find(&secrets).Error
return secrets, err
}
// DeleteExpiredSecrets 删除过期的密钥
func (r *GormUserSecretsRepository) DeleteExpiredSecrets(ctx context.Context) error {
return r.db.WithContext(ctx).Where("expires_at IS NOT NULL AND expires_at < ?", time.Now()).Delete(&entities.UserSecrets{}).Error
}

View File

@@ -0,0 +1,24 @@
package queries
// ListWalletsQuery 钱包列表查询参数
type ListWalletsQuery struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
UserID string `json:"user_id"`
WalletType string `json:"wallet_type"`
WalletAddress string `json:"wallet_address"`
IsActive *bool `json:"is_active"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
}
// ListUserSecretsQuery 用户密钥列表查询参数
type ListUserSecretsQuery struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
UserID string `json:"user_id"`
SecretType string `json:"secret_type"`
IsActive *bool `json:"is_active"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
}

View File

@@ -1,35 +0,0 @@
package routes
import (
"github.com/gin-gonic/gin"
"tyapi-server/internal/domains/finance/handlers"
)
// RegisterFinanceRoutes 注册财务路由
func RegisterFinanceRoutes(router *gin.Engine, financeHandler *handlers.FinanceHandler) {
// 财务路由组
financeGroup := router.Group("/api/finance")
{
// 钱包相关路由
walletGroup := financeGroup.Group("/wallet")
{
walletGroup.POST("", financeHandler.CreateWallet) // 创建钱包
walletGroup.GET("", financeHandler.GetWallet) // 获取钱包信息
walletGroup.PUT("", financeHandler.UpdateWallet) // 更新钱包
walletGroup.POST("/recharge", financeHandler.Recharge) // 充值
walletGroup.POST("/withdraw", financeHandler.Withdraw) // 提现
walletGroup.POST("/transaction", financeHandler.WalletTransaction) // 钱包交易
walletGroup.GET("/stats", financeHandler.GetWalletStats) // 获取钱包统计
}
// 用户密钥相关路由
secretsGroup := financeGroup.Group("/secrets")
{
secretsGroup.POST("", financeHandler.CreateUserSecrets) // 创建用户密钥
secretsGroup.GET("", financeHandler.GetUserSecrets) // 获取用户密钥
secretsGroup.POST("/regenerate", financeHandler.RegenerateAccessKey) // 重新生成访问密钥
secretsGroup.POST("/deactivate", financeHandler.DeactivateUserSecrets) // 停用用户密钥
}
}
}

View File

@@ -1,470 +1,24 @@
package services
import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"time"
"github.com/shopspring/decimal"
"go.uber.org/zap"
"tyapi-server/internal/domains/finance/dto"
"tyapi-server/internal/domains/finance/entities"
"tyapi-server/internal/domains/finance/repositories"
"tyapi-server/internal/shared/interfaces"
)
// FinanceService 财务服务
// FinanceService 财务领域服务
type FinanceService struct {
walletRepo repositories.WalletRepository
userSecretsRepo repositories.UserSecretsRepository
responseBuilder interfaces.ResponseBuilder
logger *zap.Logger
walletRepo repositories.WalletRepository
logger *zap.Logger
}
// NewFinanceService 创建财务服务
// NewFinanceService 创建财务领域服务
func NewFinanceService(
walletRepo repositories.WalletRepository,
userSecretsRepo repositories.UserSecretsRepository,
responseBuilder interfaces.ResponseBuilder,
logger *zap.Logger,
) *FinanceService {
return &FinanceService{
walletRepo: walletRepo,
userSecretsRepo: userSecretsRepo,
responseBuilder: responseBuilder,
logger: logger,
walletRepo: walletRepo,
logger: logger,
}
}
// CreateWallet 创建钱包
func (s *FinanceService) CreateWallet(ctx context.Context, req *dto.CreateWalletRequest) (*dto.CreateWalletResponse, error) {
s.logger.Info("创建钱包", zap.String("user_id", req.UserID))
// 检查用户是否已有钱包
exists, err := s.walletRepo.ExistsByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("检查钱包存在性失败: %w", err)
}
if exists {
return nil, fmt.Errorf("用户已存在钱包")
}
// 创建钱包
wallet := entities.Wallet{
ID: s.generateID(),
UserID: req.UserID,
IsActive: true,
Balance: decimal.Zero,
}
if err := s.walletRepo.Create(ctx, wallet); err != nil {
return nil, fmt.Errorf("创建钱包失败: %w", err)
}
// 构建响应
walletInfo := dto.WalletInfo{
ID: wallet.ID,
UserID: wallet.UserID,
IsActive: wallet.IsActive,
Balance: wallet.Balance,
CreatedAt: wallet.CreatedAt,
UpdatedAt: wallet.UpdatedAt,
}
s.logger.Info("钱包创建成功", zap.String("wallet_id", wallet.ID))
return &dto.CreateWalletResponse{Wallet: walletInfo}, nil
}
// GetWallet 获取钱包信息
func (s *FinanceService) GetWallet(ctx context.Context, userID string) (*dto.WalletInfo, error) {
s.logger.Info("获取钱包信息", zap.String("user_id", userID))
wallet, err := s.walletRepo.FindByUserID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("钱包不存在")
}
walletInfo := dto.WalletInfo{
ID: wallet.ID,
UserID: wallet.UserID,
IsActive: wallet.IsActive,
Balance: wallet.Balance,
CreatedAt: wallet.CreatedAt,
UpdatedAt: wallet.UpdatedAt,
}
return &walletInfo, nil
}
// UpdateWallet 更新钱包
func (s *FinanceService) UpdateWallet(ctx context.Context, req *dto.UpdateWalletRequest) error {
s.logger.Info("更新钱包", zap.String("user_id", req.UserID))
wallet, err := s.walletRepo.FindByUserID(ctx, req.UserID)
if err != nil {
return fmt.Errorf("钱包不存在")
}
// 更新字段
if !req.Balance.IsZero() {
wallet.Balance = req.Balance
}
if req.IsActive != nil {
wallet.IsActive = *req.IsActive
}
if err := s.walletRepo.Update(ctx, *wallet); err != nil {
return fmt.Errorf("更新钱包失败: %w", err)
}
s.logger.Info("钱包更新成功", zap.String("user_id", req.UserID))
return nil
}
// Recharge 充值
func (s *FinanceService) Recharge(ctx context.Context, req *dto.RechargeRequest) (*dto.RechargeResponse, error) {
s.logger.Info("钱包充值", zap.String("user_id", req.UserID), zap.String("amount", req.Amount.String()))
// 验证金额
if req.Amount.LessThanOrEqual(decimal.Zero) {
return nil, fmt.Errorf("充值金额必须大于0")
}
// 获取钱包
wallet, err := s.walletRepo.FindByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("钱包不存在")
}
// 检查钱包状态
if !wallet.IsActive {
return nil, fmt.Errorf("钱包已被禁用")
}
// 增加余额
if err := s.walletRepo.AddBalance(ctx, req.UserID, req.Amount); err != nil {
return nil, fmt.Errorf("充值失败: %w", err)
}
// 获取更新后的余额
updatedWallet, err := s.walletRepo.FindByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("获取更新后余额失败: %w", err)
}
s.logger.Info("充值成功", zap.String("user_id", req.UserID), zap.String("amount", req.Amount.String()))
return &dto.RechargeResponse{
WalletID: updatedWallet.ID,
Amount: req.Amount,
Balance: updatedWallet.Balance,
}, nil
}
// Withdraw 提现
func (s *FinanceService) Withdraw(ctx context.Context, req *dto.WithdrawRequest) (*dto.WithdrawResponse, error) {
s.logger.Info("钱包提现", zap.String("user_id", req.UserID), zap.String("amount", req.Amount.String()))
// 验证金额
if req.Amount.LessThanOrEqual(decimal.Zero) {
return nil, fmt.Errorf("提现金额必须大于0")
}
// 获取钱包
wallet, err := s.walletRepo.FindByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("钱包不存在")
}
// 检查钱包状态
if !wallet.IsActive {
return nil, fmt.Errorf("钱包已被禁用")
}
// 检查余额是否足够
if wallet.Balance.LessThan(req.Amount) {
return nil, fmt.Errorf("余额不足")
}
// 减少余额
if err := s.walletRepo.SubtractBalance(ctx, req.UserID, req.Amount); err != nil {
return nil, fmt.Errorf("提现失败: %w", err)
}
// 获取更新后的余额
updatedWallet, err := s.walletRepo.FindByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("获取更新后余额失败: %w", err)
}
s.logger.Info("提现成功", zap.String("user_id", req.UserID), zap.String("amount", req.Amount.String()))
return &dto.WithdrawResponse{
WalletID: updatedWallet.ID,
Amount: req.Amount,
Balance: updatedWallet.Balance,
}, nil
}
// CreateUserSecrets 创建用户密钥
func (s *FinanceService) CreateUserSecrets(ctx context.Context, req *dto.CreateUserSecretsRequest) (*dto.CreateUserSecretsResponse, error) {
s.logger.Info("创建用户密钥", zap.String("user_id", req.UserID))
// 检查用户是否已有密钥
exists, err := s.userSecretsRepo.ExistsByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("检查密钥存在性失败: %w", err)
}
if exists {
return nil, fmt.Errorf("用户已存在密钥")
}
// 生成访问ID和密钥
accessID := s.generateAccessID()
accessKey := s.generateAccessKey()
// 创建密钥
secrets := entities.UserSecrets{
ID: s.generateID(),
UserID: req.UserID,
AccessID: accessID,
AccessKey: accessKey,
IsActive: true,
ExpiresAt: req.ExpiresAt,
}
if err := s.userSecretsRepo.Create(ctx, secrets); err != nil {
return nil, fmt.Errorf("创建密钥失败: %w", err)
}
// 构建响应
secretsInfo := dto.UserSecretsInfo{
ID: secrets.ID,
UserID: secrets.UserID,
AccessID: secrets.AccessID,
AccessKey: secrets.AccessKey,
IsActive: secrets.IsActive,
LastUsedAt: secrets.LastUsedAt,
ExpiresAt: secrets.ExpiresAt,
CreatedAt: secrets.CreatedAt,
UpdatedAt: secrets.UpdatedAt,
}
s.logger.Info("用户密钥创建成功", zap.String("user_id", req.UserID))
return &dto.CreateUserSecretsResponse{Secrets: secretsInfo}, nil
}
// GetUserSecrets 获取用户密钥
func (s *FinanceService) GetUserSecrets(ctx context.Context, userID string) (*dto.UserSecretsInfo, error) {
s.logger.Info("获取用户密钥", zap.String("user_id", userID))
secrets, err := s.userSecretsRepo.FindByUserID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("密钥不存在")
}
secretsInfo := dto.UserSecretsInfo{
ID: secrets.ID,
UserID: secrets.UserID,
AccessID: secrets.AccessID,
AccessKey: secrets.AccessKey,
IsActive: secrets.IsActive,
LastUsedAt: secrets.LastUsedAt,
ExpiresAt: secrets.ExpiresAt,
CreatedAt: secrets.CreatedAt,
UpdatedAt: secrets.UpdatedAt,
}
return &secretsInfo, nil
}
// RegenerateAccessKey 重新生成访问密钥
func (s *FinanceService) RegenerateAccessKey(ctx context.Context, req *dto.RegenerateAccessKeyRequest) (*dto.RegenerateAccessKeyResponse, error) {
s.logger.Info("重新生成访问密钥", zap.String("user_id", req.UserID))
// 检查密钥是否存在
secrets, err := s.userSecretsRepo.FindByUserID(ctx, req.UserID)
if err != nil {
return nil, fmt.Errorf("密钥不存在")
}
// 生成新的访问ID和密钥
newAccessID := s.generateAccessID()
newAccessKey := s.generateAccessKey()
// 更新密钥
if err := s.userSecretsRepo.RegenerateAccessKey(ctx, req.UserID, newAccessID, newAccessKey); err != nil {
return nil, fmt.Errorf("重新生成密钥失败: %w", err)
}
// 更新过期时间
if req.ExpiresAt != nil {
secrets.ExpiresAt = req.ExpiresAt
if err := s.userSecretsRepo.Update(ctx, *secrets); err != nil {
s.logger.Error("更新密钥过期时间失败", zap.Error(err))
}
}
s.logger.Info("访问密钥重新生成成功", zap.String("user_id", req.UserID))
return &dto.RegenerateAccessKeyResponse{
AccessID: newAccessID,
AccessKey: newAccessKey,
}, nil
}
// DeactivateUserSecrets 停用用户密钥
func (s *FinanceService) DeactivateUserSecrets(ctx context.Context, req *dto.DeactivateUserSecretsRequest) error {
s.logger.Info("停用用户密钥", zap.String("user_id", req.UserID))
// 检查密钥是否存在
if _, err := s.userSecretsRepo.FindByUserID(ctx, req.UserID); err != nil {
return fmt.Errorf("密钥不存在")
}
// 停用密钥
if err := s.userSecretsRepo.DeactivateByUserID(ctx, req.UserID); err != nil {
return fmt.Errorf("停用密钥失败: %w", err)
}
s.logger.Info("用户密钥停用成功", zap.String("user_id", req.UserID))
return nil
}
// WalletTransaction 钱包交易
func (s *FinanceService) WalletTransaction(ctx context.Context, req *dto.WalletTransactionRequest) (*dto.WalletTransactionResponse, error) {
s.logger.Info("钱包交易",
zap.String("from_user_id", req.FromUserID),
zap.String("to_user_id", req.ToUserID),
zap.String("amount", req.Amount.String()))
// 验证金额
if req.Amount.LessThanOrEqual(decimal.Zero) {
return nil, fmt.Errorf("交易金额必须大于0")
}
// 验证用户不能给自己转账
if req.FromUserID == req.ToUserID {
return nil, fmt.Errorf("不能给自己转账")
}
// 获取转出钱包
fromWallet, err := s.walletRepo.FindByUserID(ctx, req.FromUserID)
if err != nil {
return nil, fmt.Errorf("转出钱包不存在")
}
// 获取转入钱包
toWallet, err := s.walletRepo.FindByUserID(ctx, req.ToUserID)
if err != nil {
return nil, fmt.Errorf("转入钱包不存在")
}
// 检查钱包状态
if !fromWallet.IsActive {
return nil, fmt.Errorf("转出钱包已被禁用")
}
if !toWallet.IsActive {
return nil, fmt.Errorf("转入钱包已被禁用")
}
// 检查余额是否足够
if fromWallet.Balance.LessThan(req.Amount) {
return nil, fmt.Errorf("余额不足")
}
// 执行交易(使用事务)
// 这里简化处理,实际应该使用数据库事务
if err := s.walletRepo.SubtractBalance(ctx, req.FromUserID, req.Amount); err != nil {
return nil, fmt.Errorf("扣款失败: %w", err)
}
if err := s.walletRepo.AddBalance(ctx, req.ToUserID, req.Amount); err != nil {
return nil, fmt.Errorf("入账失败: %w", err)
}
// 获取更新后的余额
updatedFromWallet, err := s.walletRepo.FindByUserID(ctx, req.FromUserID)
if err != nil {
return nil, fmt.Errorf("获取转出后余额失败: %w", err)
}
updatedToWallet, err := s.walletRepo.FindByUserID(ctx, req.ToUserID)
if err != nil {
return nil, fmt.Errorf("获取转入后余额失败: %w", err)
}
s.logger.Info("钱包交易成功",
zap.String("from_user_id", req.FromUserID),
zap.String("to_user_id", req.ToUserID),
zap.String("amount", req.Amount.String()))
return &dto.WalletTransactionResponse{
TransactionID: s.generateID(),
FromUserID: req.FromUserID,
ToUserID: req.ToUserID,
Amount: req.Amount,
FromBalance: updatedFromWallet.Balance,
ToBalance: updatedToWallet.Balance,
Notes: req.Notes,
CreatedAt: time.Now(),
}, nil
}
// GetWalletStats 获取钱包统计
func (s *FinanceService) GetWalletStats(ctx context.Context) (*dto.WalletStatsResponse, error) {
s.logger.Info("获取钱包统计")
// 获取总钱包数
totalWallets, err := s.walletRepo.Count(ctx, interfaces.CountOptions{})
if err != nil {
return nil, fmt.Errorf("获取总钱包数失败: %w", err)
}
// 获取激活钱包数
activeWallets, err := s.walletRepo.GetActiveWalletCount(ctx)
if err != nil {
return nil, fmt.Errorf("获取激活钱包数失败: %w", err)
}
// 获取总余额
totalBalance, err := s.walletRepo.GetTotalBalance(ctx)
if err != nil {
return nil, fmt.Errorf("获取总余额失败: %w", err)
}
// 这里简化处理,实际应该查询交易记录表
todayTransactions := int64(0)
todayVolume := decimal.Zero
return &dto.WalletStatsResponse{
TotalWallets: totalWallets,
ActiveWallets: activeWallets,
TotalBalance: totalBalance.(decimal.Decimal),
TodayTransactions: todayTransactions,
TodayVolume: todayVolume,
}, nil
}
// generateID 生成ID
func (s *FinanceService) generateID() string {
bytes := make([]byte, 16)
rand.Read(bytes)
return hex.EncodeToString(bytes)
}
// generateAccessID 生成访问ID
func (s *FinanceService) generateAccessID() string {
bytes := make([]byte, 20)
rand.Read(bytes)
return hex.EncodeToString(bytes)
}
// generateAccessKey 生成访问密钥
func (s *FinanceService) generateAccessKey() string {
bytes := make([]byte, 32)
rand.Read(bytes)
hash := sha256.Sum256(bytes)
return hex.EncodeToString(hash[:])
}