feat: 添加实时查询余额的接口
This commit is contained in:
parent
eaad2642a8
commit
7b8fba5701
@ -32,25 +32,43 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/topfans/backend/pkg/logger"
|
||||
pbGallery "github.com/topfans/backend/pkg/proto/gallery"
|
||||
pbUser "github.com/topfans/backend/pkg/proto/user"
|
||||
"github.com/topfans/backend/services/assetService/service"
|
||||
)
|
||||
|
||||
// AssetController 资产相关控制器
|
||||
type AssetController struct {
|
||||
assetService pbAsset.AssetService
|
||||
userService pbUser.UserSocialService
|
||||
galleryService pbGallery.GalleryService
|
||||
minimaxService service.MinimaxService
|
||||
}
|
||||
|
||||
// NewAssetController 创建资产控制器
|
||||
func NewAssetController(dubboClient *client.Client) (*AssetController, error) {
|
||||
func NewAssetController(assetClient *client.Client, userClient *client.Client, galleryClient *client.Client) (*AssetController, error) {
|
||||
// 创建 AssetService 客户端
|
||||
assetService, err := pbAsset.NewAssetService(dubboClient)
|
||||
assetService, err := pbAsset.NewAssetService(assetClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建 UserService 客户端
|
||||
userService, err := pbUser.NewUserSocialService(userClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建 GalleryService 客户端
|
||||
galleryService, err := pbGallery.NewGalleryService(galleryClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AssetController{
|
||||
assetService: assetService,
|
||||
userService: userService,
|
||||
galleryService: galleryService,
|
||||
minimaxService: service.NewMinimaxService(),
|
||||
}, nil
|
||||
}
|
||||
@ -264,11 +282,11 @@ func (ctrl *AssetController) EstimateMintCost(c *gin.Context) {
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"cost_crystal": resp.CostCrystal,
|
||||
"current_balance": resp.CurrentBalance,
|
||||
"balance_after": resp.BalanceAfter,
|
||||
"mint_count": resp.MintCount,
|
||||
"next_tier_hint": resp.NextTierHint,
|
||||
"cost_crystal": resp.CostCrystal,
|
||||
"current_balance": resp.CurrentBalance,
|
||||
"balance_after": resp.BalanceAfter,
|
||||
"mint_count": resp.MintCount,
|
||||
"next_tier_hint": resp.NextTierHint,
|
||||
}
|
||||
response.Success(c, data)
|
||||
}
|
||||
@ -1585,7 +1603,8 @@ func (ctrl *AssetController) BindAssetMaterials(c *gin.Context) {
|
||||
uid, _ := userIDVal.(int64)
|
||||
starIDVal, _ := c.Get("star_id")
|
||||
sid, _ := starIDVal.(int64)
|
||||
_ = uid; _ = sid // suppress unused
|
||||
_ = uid
|
||||
_ = sid // suppress unused
|
||||
|
||||
var req dto.BindAssetMaterialsRequestDTO
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@ -1786,3 +1805,98 @@ func (ctrl *AssetController) UnbindAssetMaterial(c *gin.Context) {
|
||||
|
||||
response.Success(c, gin.H{"message": "解绑成功"})
|
||||
}
|
||||
|
||||
// GetEarningsSummary 获取收益汇总
|
||||
// @Summary 获取收益汇总
|
||||
// @Description 获取当前用户的收益汇总(总每小时收益、总展出收益、水晶余额)
|
||||
// @Tags assets
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/v1/assets/me/earnings-summary [get]
|
||||
func (ctrl *AssetController) GetEarningsSummary(c *gin.Context) {
|
||||
userIDVal, _ := c.Get("user_id")
|
||||
starIDVal, _ := c.Get("star_id")
|
||||
|
||||
userID, ok := userIDVal.(int64)
|
||||
if !ok {
|
||||
logger.Logger.Error("GetEarningsSummary: user_id type assertion failed", zap.Any("value", userIDVal))
|
||||
response.Error(c, http.StatusInternalServerError, "用户ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
starID, ok := starIDVal.(int64)
|
||||
if !ok {
|
||||
logger.Logger.Error("GetEarningsSummary: star_id type assertion failed", zap.Any("value", starIDVal))
|
||||
response.Error(c, http.StatusInternalServerError, "明星ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
logger.Logger.Info("GetEarningsSummary: start", zap.Int64("user_id", userID), zap.Int64("star_id", starID))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{
|
||||
"user_id": strconv.FormatInt(userID, 10),
|
||||
"star_id": strconv.FormatInt(starID, 10),
|
||||
})
|
||||
|
||||
// 1. 获取我展出的作品列表
|
||||
var totalHourlyEarnings float64
|
||||
var totalExhibitionRevenue int64
|
||||
page := int32(1)
|
||||
pageSize := int32(200)
|
||||
|
||||
for {
|
||||
resp, err := ctrl.galleryService.GetMyExhibitedAssets(ctx, &pbGallery.GetMyExhibitedAssetsRequest{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Logger.Error("GetEarningsSummary: GetMyExhibitedAssets failed", zap.Error(err))
|
||||
response.Error(c, http.StatusInternalServerError, "获取展出作品列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||||
logger.Logger.Warn("GetEarningsSummary: GetMyExhibitedAssets returned non-OK", zap.Any("code", resp.Base.Code), zap.String("msg", resp.Base.Message))
|
||||
}
|
||||
|
||||
// 累加每个 item 的收益(GetMyExhibitedAssets 返回的都是展出中的作品)
|
||||
for _, item := range resp.Data.Items {
|
||||
hourlyEarnings := item.HourlyEarnings
|
||||
totalHourlyEarnings += hourlyEarnings
|
||||
totalExhibitionRevenue += item.Earnings
|
||||
}
|
||||
|
||||
// 检查是否还有更多
|
||||
if !resp.Data.HasMore {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
logger.Logger.Info("GetEarningsSummary: assets fetched", zap.Float64("total_hourly", totalHourlyEarnings), zap.Int64("total_revenue", totalExhibitionRevenue))
|
||||
|
||||
// 2. 获取水晶余额
|
||||
logger.Logger.Info("GetEarningsSummary: calling GetFanProfile", zap.Int64("user_id", userID), zap.Int64("star_id", starID))
|
||||
userResp, err := ctrl.userService.GetFanProfile(ctx, &pbUser.GetFanProfileRequest{
|
||||
UserId: userID,
|
||||
StarId: starID,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Logger.Error("GetEarningsSummary: GetFanProfile failed", zap.Error(err), zap.Int64("user_id", userID), zap.Int64("star_id", starID))
|
||||
response.Error(c, http.StatusInternalServerError, "获取用户信息失败")
|
||||
return
|
||||
}
|
||||
|
||||
logger.Logger.Info("GetEarningsSummary: success", zap.Float64("total_hourly", totalHourlyEarnings), zap.Int64("total_revenue", totalExhibitionRevenue), zap.Int64("balance", userResp.GetProfile().GetCrystalBalance()))
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"total_hourly_earnings": totalHourlyEarnings,
|
||||
"total_exhibition_revenue": totalExhibitionRevenue,
|
||||
"crystal_balance": userResp.GetProfile().GetCrystalBalance(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ func SetupRouter(userClient *client.Client, socialClient *client.Client, assetCl
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assetCtrl, err := controller.NewAssetController(assetClient)
|
||||
assetCtrl, err := controller.NewAssetController(assetClient, userClient, galleryClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -192,6 +192,7 @@ func SetupRouter(userClient *client.Client, socialClient *client.Client, assetCl
|
||||
assets.GET("/mints/:order_id", assetCtrl.GetMintOrder) // 查询铸造订单状态
|
||||
assets.DELETE("/mints/:order_id", assetCtrl.CancelMintOrder) // 取消铸造订单
|
||||
assets.POST("/mints/image/generation", assetCtrl.ImageGeneration) // 图生图
|
||||
assets.GET("/me/earnings-summary", assetCtrl.GetEarningsSummary) // 获取收益汇总
|
||||
assets.GET("/me/items", assetCtrl.GetMyAssets) // 获取我的藏品列表
|
||||
assets.GET("/:asset_id", assetCtrl.GetAsset) // 获取资产详情
|
||||
assets.GET("/:asset_id/status", assetCtrl.GetAssetStatus) // 查询上链状态
|
||||
|
||||
@ -69,12 +69,12 @@
|
||||
|
||||
<!-- 上层:文字内容 -->
|
||||
<view class="crystal-text-layer">
|
||||
<text class="balance-number">{{ crystalBalance }}</text>
|
||||
<text class="balance-number">{{ exhibitionRevenue }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 收益文字 -->
|
||||
<view class="crystal-bg-layer">
|
||||
<text class="balance-income">收益 0/H</text>
|
||||
<text class="balance-income">收益 {{ hourlyEarnings }}/时</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
@ -103,6 +103,7 @@ import DailyTasks from '@/pages/tasks/daily-tasks.vue';
|
||||
import GuideModal from '@/pages/tasks/GuideModal.vue';
|
||||
import { useBanner } from '@/pages/square/composables/useBanner.js';
|
||||
import { reportEvent } from '@/utils/task-api.js';
|
||||
import { getEarningsSummaryApi } from '@/utils/api.js';
|
||||
|
||||
// 获取星援活动数据(复用 square 的 useBanner)
|
||||
const { bannerActivities, loadBannerActivities } = useBanner();
|
||||
@ -170,10 +171,29 @@ const userAvatarUrl = computed(() => {
|
||||
return userInfo.value?.avatar_url || '';
|
||||
});
|
||||
|
||||
// 获取水晶余额
|
||||
const crystalBalance = computed(() => {
|
||||
return userInfo.value?.crystal_balance ?? 9527;
|
||||
});
|
||||
// // 获取水晶余额
|
||||
// const crystalBalance = computed(() => {
|
||||
// return userInfo.value?.crystal_balance ?? 9527;
|
||||
// });
|
||||
|
||||
// 收益相关数据
|
||||
const exhibitionRevenue = ref(0); // 当前展出收益
|
||||
const hourlyEarnings = ref(0); // 每小时收益之和
|
||||
|
||||
// 加载收益汇总
|
||||
const loadEarningsSummary = async () => {
|
||||
try {
|
||||
const response = await getEarningsSummaryApi();
|
||||
|
||||
if (response.code === 200) {
|
||||
const data = response.data;
|
||||
exhibitionRevenue.value = data.crystal_balance || 0;
|
||||
hourlyEarnings.value = data.total_hourly_earnings || 0;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取收益汇总失败:', e);
|
||||
}
|
||||
};
|
||||
|
||||
// 监听头像更新事件
|
||||
const handleAvatarUpdate = (data) => {
|
||||
@ -243,9 +263,10 @@ const starActivities = computed(() => {
|
||||
});
|
||||
|
||||
// 组件挂载时加载用户信息和星援活动数据
|
||||
onMounted(() => {
|
||||
loadUserInfo();
|
||||
loadBannerActivities();
|
||||
onMounted(async() => {
|
||||
await loadUserInfo();
|
||||
await loadBannerActivities();
|
||||
await loadEarningsSummary();
|
||||
uni.$on('avatarUpdated', handleAvatarUpdate);
|
||||
uni.$on('userInfoUpdated', handleUserInfoUpdate);
|
||||
uni.$on('balanceUpdated', handleBalanceUpdate);
|
||||
|
||||
@ -798,4 +798,12 @@ export function getMintingActivitiesApi(starId = null, page = 1, pageSize = 10)
|
||||
url: url,
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取收益汇总接口
|
||||
export function getEarningsSummaryApi() {
|
||||
return request({
|
||||
url: '/api/v1/assets/me/earnings-summary',
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user