87 lines
2.5 KiB
Go
87 lines
2.5 KiB
Go
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 "后台调整"
|
||
}
|
||
}
|