feat: 添加实时查询余额的接口
This commit is contained in:
parent
eaad2642a8
commit
7b8fba5701
@ -32,25 +32,43 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/topfans/backend/pkg/logger"
|
"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"
|
"github.com/topfans/backend/services/assetService/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AssetController 资产相关控制器
|
// AssetController 资产相关控制器
|
||||||
type AssetController struct {
|
type AssetController struct {
|
||||||
assetService pbAsset.AssetService
|
assetService pbAsset.AssetService
|
||||||
|
userService pbUser.UserSocialService
|
||||||
|
galleryService pbGallery.GalleryService
|
||||||
minimaxService service.MinimaxService
|
minimaxService service.MinimaxService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAssetController 创建资产控制器
|
// NewAssetController 创建资产控制器
|
||||||
func NewAssetController(dubboClient *client.Client) (*AssetController, error) {
|
func NewAssetController(assetClient *client.Client, userClient *client.Client, galleryClient *client.Client) (*AssetController, error) {
|
||||||
// 创建 AssetService 客户端
|
// 创建 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &AssetController{
|
return &AssetController{
|
||||||
assetService: assetService,
|
assetService: assetService,
|
||||||
|
userService: userService,
|
||||||
|
galleryService: galleryService,
|
||||||
minimaxService: service.NewMinimaxService(),
|
minimaxService: service.NewMinimaxService(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -264,11 +282,11 @@ func (ctrl *AssetController) EstimateMintCost(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"cost_crystal": resp.CostCrystal,
|
"cost_crystal": resp.CostCrystal,
|
||||||
"current_balance": resp.CurrentBalance,
|
"current_balance": resp.CurrentBalance,
|
||||||
"balance_after": resp.BalanceAfter,
|
"balance_after": resp.BalanceAfter,
|
||||||
"mint_count": resp.MintCount,
|
"mint_count": resp.MintCount,
|
||||||
"next_tier_hint": resp.NextTierHint,
|
"next_tier_hint": resp.NextTierHint,
|
||||||
}
|
}
|
||||||
response.Success(c, data)
|
response.Success(c, data)
|
||||||
}
|
}
|
||||||
@ -1585,7 +1603,8 @@ func (ctrl *AssetController) BindAssetMaterials(c *gin.Context) {
|
|||||||
uid, _ := userIDVal.(int64)
|
uid, _ := userIDVal.(int64)
|
||||||
starIDVal, _ := c.Get("star_id")
|
starIDVal, _ := c.Get("star_id")
|
||||||
sid, _ := starIDVal.(int64)
|
sid, _ := starIDVal.(int64)
|
||||||
_ = uid; _ = sid // suppress unused
|
_ = uid
|
||||||
|
_ = sid // suppress unused
|
||||||
|
|
||||||
var req dto.BindAssetMaterialsRequestDTO
|
var req dto.BindAssetMaterialsRequestDTO
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@ -1786,3 +1805,98 @@ func (ctrl *AssetController) UnbindAssetMaterial(c *gin.Context) {
|
|||||||
|
|
||||||
response.Success(c, gin.H{"message": "解绑成功"})
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
assetCtrl, err := controller.NewAssetController(assetClient)
|
assetCtrl, err := controller.NewAssetController(assetClient, userClient, galleryClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -192,6 +192,7 @@ func SetupRouter(userClient *client.Client, socialClient *client.Client, assetCl
|
|||||||
assets.GET("/mints/:order_id", assetCtrl.GetMintOrder) // 查询铸造订单状态
|
assets.GET("/mints/:order_id", assetCtrl.GetMintOrder) // 查询铸造订单状态
|
||||||
assets.DELETE("/mints/:order_id", assetCtrl.CancelMintOrder) // 取消铸造订单
|
assets.DELETE("/mints/:order_id", assetCtrl.CancelMintOrder) // 取消铸造订单
|
||||||
assets.POST("/mints/image/generation", assetCtrl.ImageGeneration) // 图生图
|
assets.POST("/mints/image/generation", assetCtrl.ImageGeneration) // 图生图
|
||||||
|
assets.GET("/me/earnings-summary", assetCtrl.GetEarningsSummary) // 获取收益汇总
|
||||||
assets.GET("/me/items", assetCtrl.GetMyAssets) // 获取我的藏品列表
|
assets.GET("/me/items", assetCtrl.GetMyAssets) // 获取我的藏品列表
|
||||||
assets.GET("/:asset_id", assetCtrl.GetAsset) // 获取资产详情
|
assets.GET("/:asset_id", assetCtrl.GetAsset) // 获取资产详情
|
||||||
assets.GET("/:asset_id/status", assetCtrl.GetAssetStatus) // 查询上链状态
|
assets.GET("/:asset_id/status", assetCtrl.GetAssetStatus) // 查询上链状态
|
||||||
|
|||||||
@ -69,12 +69,12 @@
|
|||||||
|
|
||||||
<!-- 上层:文字内容 -->
|
<!-- 上层:文字内容 -->
|
||||||
<view class="crystal-text-layer">
|
<view class="crystal-text-layer">
|
||||||
<text class="balance-number">{{ crystalBalance }}</text>
|
<text class="balance-number">{{ exhibitionRevenue }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 收益文字 -->
|
<!-- 收益文字 -->
|
||||||
<view class="crystal-bg-layer">
|
<view class="crystal-bg-layer">
|
||||||
<text class="balance-income">收益 0/H</text>
|
<text class="balance-income">收益 {{ hourlyEarnings }}/时</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
@ -103,6 +103,7 @@ import DailyTasks from '@/pages/tasks/daily-tasks.vue';
|
|||||||
import GuideModal from '@/pages/tasks/GuideModal.vue';
|
import GuideModal from '@/pages/tasks/GuideModal.vue';
|
||||||
import { useBanner } from '@/pages/square/composables/useBanner.js';
|
import { useBanner } from '@/pages/square/composables/useBanner.js';
|
||||||
import { reportEvent } from '@/utils/task-api.js';
|
import { reportEvent } from '@/utils/task-api.js';
|
||||||
|
import { getEarningsSummaryApi } from '@/utils/api.js';
|
||||||
|
|
||||||
// 获取星援活动数据(复用 square 的 useBanner)
|
// 获取星援活动数据(复用 square 的 useBanner)
|
||||||
const { bannerActivities, loadBannerActivities } = useBanner();
|
const { bannerActivities, loadBannerActivities } = useBanner();
|
||||||
@ -170,10 +171,29 @@ const userAvatarUrl = computed(() => {
|
|||||||
return userInfo.value?.avatar_url || '';
|
return userInfo.value?.avatar_url || '';
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取水晶余额
|
// // 获取水晶余额
|
||||||
const crystalBalance = computed(() => {
|
// const crystalBalance = computed(() => {
|
||||||
return userInfo.value?.crystal_balance ?? 9527;
|
// 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) => {
|
const handleAvatarUpdate = (data) => {
|
||||||
@ -243,9 +263,10 @@ const starActivities = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 组件挂载时加载用户信息和星援活动数据
|
// 组件挂载时加载用户信息和星援活动数据
|
||||||
onMounted(() => {
|
onMounted(async() => {
|
||||||
loadUserInfo();
|
await loadUserInfo();
|
||||||
loadBannerActivities();
|
await loadBannerActivities();
|
||||||
|
await loadEarningsSummary();
|
||||||
uni.$on('avatarUpdated', handleAvatarUpdate);
|
uni.$on('avatarUpdated', handleAvatarUpdate);
|
||||||
uni.$on('userInfoUpdated', handleUserInfoUpdate);
|
uni.$on('userInfoUpdated', handleUserInfoUpdate);
|
||||||
uni.$on('balanceUpdated', handleBalanceUpdate);
|
uni.$on('balanceUpdated', handleBalanceUpdate);
|
||||||
|
|||||||
@ -798,4 +798,12 @@ export function getMintingActivitiesApi(starId = null, page = 1, pageSize = 10)
|
|||||||
url: url,
|
url: url,
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取收益汇总接口
|
||||||
|
export function getEarningsSummaryApi() {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/assets/me/earnings-summary',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user