This repository has been archived on 2026-06-21. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MetaLab/internal/service/energy_energize.go
Victor_Jay ff9886f08b refactor: 文件行数超标拆解(Service + Controller 9/16 完成)
- Service 层:energy_service → energize/operations/admin/query 四文件
- Service 层:post_service → helpers/audit + 核心 CRUD 保留
- Service 层:favorite_service → items + 核心文件夹操作保留
- Service 层:auth_service → password + 核心注册/登录保留
- Service 层:notification_service → notify + 核心列表/已读保留
- Service 层:audit_service → review + 核心列表/详情保留
- Controller 层:studio_controller → page/write/api/post_api/action 五文件
- Controller 层:post_controller → page/api/upload 三文件
- Controller 层:comment_controller → list/write/action/upload 四文件
- 清理未使用导入(notification_service.go 移除 fmt)
2026-06-02 15:45:54 +08:00

191 lines
5.4 KiB
Go
Raw 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"
"time"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
"gorm.io/gorm"
)
// Energize 赋能文章
// 返回:获得的经验值、错误
func (s *EnergyService) Energize(energizerID uint, postID uint, amount int) (int, error) {
// 验证赋能量
if amount != EnergyEnergize1 && amount != EnergyEnergize2 {
return 0, common.ErrInvalidEnergyAmount
}
var expGained int
var needExpUpdate bool
var expToday time.Time
var expTotal int
err := s.db.Transaction(func(tx *gorm.DB) error {
txRepo := s.repo.WithTx(tx)
var txFundRepo FundStore
if s.fundRepo != nil {
txFundRepo = s.fundRepo.WithTx(tx)
}
// 1. 检查帖子存在,获取作者
post, err := txRepo.FindPostByID(postID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return common.ErrPostNotFound
}
return fmt.Errorf("查询帖子失败: %w", err)
}
// 2. 不能给自己赋能
if post.UserID == energizerID {
return common.ErrCannotEnergizeSelf
}
// 3. 检查赋能者域能余额owner 跳过)
energizer, err := txRepo.FindUserByID(energizerID)
if err != nil {
return fmt.Errorf("查询用户失败: %w", err)
}
if energizer.Role != model.RoleOwner && energizer.Energy < amount {
return common.ErrInsufficientEnergy
}
// 4. 检查单用户单文章赋能总量 ≤ MaxEnergizePerPost
total, err := txRepo.SumUserPostEnergy(energizerID, postID)
if err != nil {
return fmt.Errorf("查询赋能记录失败: %w", err)
}
if total+amount > MaxEnergizePerPost {
return common.ErrEnergizeLimitReached
}
// 5. 扣赋能者域能
if err := txRepo.AddEnergy(energizerID, -amount); err != nil {
return fmt.Errorf("扣减域能失败: %w", err)
}
// 6. 增加被赋能者(文章作者)域能(赋能量的十分之一)
receivedAmount := amount / 10 // 1 域能→0.12 域能→0.2
if err := txRepo.AddEnergy(post.UserID, receivedAmount); err != nil {
return fmt.Errorf("增加被赋能者域能失败: %w", err)
}
// 7. 更新 Post.total_energy_received
if err := txRepo.IncrPostEnergy(postID, amount); err != nil {
return fmt.Errorf("更新文章赋能计数失败: %w", err)
}
// 8. 插入赋能记录
eLog := &model.PostEnergizeLog{
UserID: energizerID,
PostID: postID,
Amount: amount,
}
if err := txRepo.CreateEnergizeLog(eLog); err != nil {
return fmt.Errorf("创建赋能记录失败: %w", err)
}
// 9. 写入域能流水 ×2
amountDisplay := float64(amount) / 10
receivedDisplay := float64(receivedAmount) / 10
energizerLog := &model.EnergyLog{
UserID: energizerID,
Amount: -amount,
Type: model.EnergyTypeEnergize,
RelatedType: "post",
RelatedID: postID,
Description: fmt.Sprintf("给文章 %d 赋能 %.1f 域能", postID, amountDisplay),
}
if err := txRepo.CreateEnergyLog(energizerLog); err != nil {
return fmt.Errorf("创建赋能者流水失败: %w", err)
}
energizedLog := &model.EnergyLog{
UserID: post.UserID,
Amount: receivedAmount,
Type: model.EnergyTypeEnergized,
RelatedType: "post",
RelatedID: postID,
Description: fmt.Sprintf("文章 %d 被赋能 +%.1f 域能", postID, receivedDisplay),
}
if err := txRepo.CreateEnergyLog(energizedLog); err != nil {
return fmt.Errorf("创建被赋能者流水失败: %w", err)
}
// 10. 赋能税收入公户(差价 = amount - receivedAmount
if txFundRepo != nil {
tax := amount - receivedAmount
if tax > 0 {
if err := txFundRepo.IncrBalance(tax); err != nil {
return fmt.Errorf("公户入账失败: %w", err)
}
taxDisplay := float64(tax) / 10
fundLog := &model.FundLog{
Amount: tax,
Type: model.FundTypeEnergizeTax,
RelatedType: "post",
RelatedID: postID,
Description: fmt.Sprintf("赋能文章 #%d 税收 %.1f 域能,赋能者 uid=%d", postID, taxDisplay, energizerID),
}
if err := txFundRepo.CreateLog(fundLog); err != nil {
return fmt.Errorf("创建公户流水失败: %w", err)
}
}
}
// 11. 计算经验值(溢出截断)—— 在事务内读取以保证一致性
loc, _ := time.LoadLocation("Asia/Shanghai")
now := time.Now().In(loc)
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
summary, err := txRepo.GetDailyEnergizeExp(energizerID, today)
currentDaily := 0
if err == nil && summary != nil {
currentDaily = summary.ExpEarned
}
expGain := amount // 1域能(DB10) → 10经验, 2域能(DB20) → 20经验
expRoom := DailyEnergizeExpCap - currentDaily
if expRoom < 0 {
expRoom = 0
}
if expGain > expRoom {
expGain = expRoom
}
expGained = expGain
if expGain > 0 {
needExpUpdate = true
expToday = today
expTotal = currentDaily + expGain
}
return nil
})
if err != nil {
return 0, err
}
// 12. 事务提交后,在事务外增加经验 + 更新每日汇总
if needExpUpdate {
if s.expSvc != nil {
if _, _, err := s.expSvc.AddExp(energizerID, expGained); err != nil {
return expGained, fmt.Errorf("赋能成功,但增加经验失败: %w", err)
}
}
newSummary := &model.DailyExpSummary{
UserID: energizerID,
Date: expToday,
ExpEarned: expTotal,
}
if err := s.repo.UpsertDailyExp(newSummary); err != nil {
return expGained, fmt.Errorf("赋能成功,但更新经验汇总失败: %w", err)
}
}
return expGained, nil
}