Files
mce/internal/service/energy_admin.go

87 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"fmt"
"metazone.cc/mce/internal/common"
"metazone.cc/mce/internal/model"
)
// AdminAdjust 后台调整用户域能
// mode: "admin_transfer"(受公户余额约束)| "system_operation"(不受约束,不碰公户)
func (s *EnergyService) AdminAdjust(operatorUID uint, userIDs []uint, amount int, description string, mode string) error {
if mode == "" {
mode = model.FundTypeAdminTransfer
}
return s.repo.Transaction(func(txRepo EnergyStore, txFundRepo FundStore) error {
// admin_transfer公户出账需检查余额行锁防 TOCTOU 竞态)
isAdminTransfer := mode == model.FundTypeAdminTransfer
if isAdminTransfer && amount > 0 && txFundRepo != nil {
totalCost := amount * len(userIDs)
balance, err := txFundRepo.LockAndGetBalance()
if err != nil {
return fmt.Errorf("查询公户余额失败: %w", err)
}
if balance < totalCost {
return common.ErrInsufficientFund
}
}
for _, uid := range userIDs {
if err := txRepo.AddEnergy(uid, amount); err != nil {
return fmt.Errorf("调整用户 %d 域能失败: %w", uid, err)
}
opUID := operatorUID
energyLog := &model.EnergyLog{
UserID: uid,
Amount: amount,
Type: model.EnergyTypeAdminAdjust,
Description: description,
OperatorUID: &opUID,
}
if err := txRepo.CreateEnergyLog(energyLog); err != nil {
return fmt.Errorf("创建调整流水失败: %w", err)
}
}
// admin_transfer公户扣款 + 公户流水system_operation 不碰公户)
if isAdminTransfer && txFundRepo != nil {
totalCost := amount * len(userIDs)
if err := txFundRepo.IncrBalance(-totalCost); err != nil {
return fmt.Errorf("公户余额调整失败: %w", err)
}
totalDisplay := float64(totalCost) / 10
fundLog := &model.FundLog{
Amount: -totalCost,
Type: mode,
OperatorUID: &operatorUID,
Description: fmt.Sprintf("%s调整 %d 名用户域能 %.1f,说明:%s", getFundModeName(mode), len(userIDs), totalDisplay, description),
}
if len(userIDs) > 0 {
fundLog.RelatedType = "user"
fundLog.RelatedID = userIDs[0]
}
if err := txFundRepo.CreateLog(fundLog); err != nil {
return fmt.Errorf("创建公户流水失败: %w", err)
}
}
return nil
})
}
// getFundModeName 返回操作模式中文名
func getFundModeName(mode string) string {
switch mode {
case model.FundTypeAdminTransfer:
return "管理转出"
case model.FundTypeSystemOperation:
return "系统操作"
default:
return "后台调整"
}
}