feat: 修改铸造消耗确认框和新增批量购买道具的功能,修改回退按钮的颜色
This commit is contained in:
parent
569321bb41
commit
ee0433464f
@ -343,6 +343,131 @@ func (ctrl *ActivityController) PurchaseItem(c *gin.Context) {
|
||||
response.Success(c, data)
|
||||
}
|
||||
|
||||
// BatchPurchaseItem 批量购买道具
|
||||
// @Summary 批量购买道具
|
||||
// @Description 批量购买活动道具
|
||||
// @Tags activities
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param activity_id path int64 true "活动ID"
|
||||
// @Param request body pbActivity.BatchPurchaseItemRequest true "批量购买请求"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /api/v1/activities/{activity_id}/batch-purchase [post]
|
||||
func (ctrl *ActivityController) BatchPurchaseItem(c *gin.Context) {
|
||||
// 从上下文获取用户信息
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
response.Error(c, http.StatusUnauthorized, "未授权")
|
||||
return
|
||||
}
|
||||
starID, exists := c.Get("star_id")
|
||||
if !exists {
|
||||
response.Error(c, http.StatusUnauthorized, "未授权")
|
||||
return
|
||||
}
|
||||
|
||||
// 解析路径参数
|
||||
activityIDStr := c.Param("id")
|
||||
activityID, err := strconv.ParseInt(activityIDStr, 10, 64)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "活动ID参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 解析请求体
|
||||
var req struct {
|
||||
Items []struct {
|
||||
ItemType string `json:"item_type"`
|
||||
Quantity int `json:"quantity"`
|
||||
} `json:"items"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Items) == 0 {
|
||||
response.Error(c, http.StatusBadRequest, "items 是必填参数")
|
||||
return
|
||||
}
|
||||
|
||||
logger.Logger.Info("BatchPurchaseItem request",
|
||||
zap.Int64("user_id", userID.(int64)),
|
||||
zap.Int64("star_id", starID.(int64)),
|
||||
zap.Int64("activity_id", activityID),
|
||||
zap.Int("items_count", len(req.Items)),
|
||||
)
|
||||
|
||||
// 设置上下文
|
||||
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.(int64), 10),
|
||||
"star_id": strconv.FormatInt(starID.(int64), 10),
|
||||
})
|
||||
|
||||
// 转换请求
|
||||
pbItems := make([]*pbActivity.PurchaseItem, len(req.Items))
|
||||
for i, item := range req.Items {
|
||||
quantity := int32(item.Quantity)
|
||||
if quantity <= 0 {
|
||||
quantity = 1
|
||||
}
|
||||
pbItems[i] = &pbActivity.PurchaseItem{
|
||||
ItemType: item.ItemType,
|
||||
Quantity: quantity,
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 RPC
|
||||
resp, err := ctrl.activityService.BatchPurchaseItem(ctx, &pbActivity.BatchPurchaseItemRequest{
|
||||
ActivityId: activityID,
|
||||
Items: pbItems,
|
||||
StarId: starID.(int64),
|
||||
UserId: userID.(int64),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Logger.Error("BatchPurchaseItem RPC failed", zap.Error(err))
|
||||
response.Error(c, http.StatusInternalServerError, "批量购买道具失败")
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||||
response.ErrorWithCode(c, int(resp.Base.Code), resp.Base.Message)
|
||||
return
|
||||
}
|
||||
|
||||
// 非 active 阶段:通过 message 信号返回 200 + activity_status
|
||||
activityStatusMap := map[string]string{
|
||||
"activity:expired": "expired",
|
||||
"activity:pending": "pending",
|
||||
"activity:completed": "completed",
|
||||
"activity:incomplete": "incomplete",
|
||||
"activity:active": "active",
|
||||
}
|
||||
activityMessageMap := map[string]string{
|
||||
"expired": "活动已结束",
|
||||
"pending": "活动未开始",
|
||||
"completed": "活动已完成",
|
||||
"incomplete": "活动未完成",
|
||||
"active": "活动进行中",
|
||||
}
|
||||
if status, ok := activityStatusMap[resp.Base.Message]; ok {
|
||||
response.Success(c, map[string]interface{}{
|
||||
"activity_status": status,
|
||||
"message": activityMessageMap[status],
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 正常购买成功
|
||||
data := convertBatchPurchaseResponse(resp)
|
||||
response.Success(c, data)
|
||||
}
|
||||
|
||||
// GetContributionRanking 获取贡献点排名
|
||||
// @Summary 获取贡献点排名
|
||||
// @Description 获取活动贡献点排名
|
||||
@ -742,6 +867,26 @@ func convertPurchaseResponse(resp *pbActivity.PurchaseItemResponse) map[string]i
|
||||
}
|
||||
}
|
||||
|
||||
// convertBatchPurchaseResponse 转换批量购买响应
|
||||
func convertBatchPurchaseResponse(resp *pbActivity.BatchPurchaseItemResponse) map[string]interface{} {
|
||||
fails := make([]map[string]interface{}, 0, len(resp.Fails))
|
||||
for _, fail := range resp.Fails {
|
||||
fails = append(fails, map[string]interface{}{
|
||||
"item_type": fail.ItemType,
|
||||
"reason": fail.Reason,
|
||||
})
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"total_crystal_spent": resp.TotalCrystalSpent,
|
||||
"total_contribution": resp.TotalContribution,
|
||||
"current_progress": resp.CurrentProgress,
|
||||
"remaining_balance": resp.RemainingBalance,
|
||||
"success_count": resp.SuccessCount,
|
||||
"fail_count": resp.FailCount,
|
||||
"fails": fails,
|
||||
}
|
||||
}
|
||||
|
||||
// convertContributionRankingResponse 转换排名响应
|
||||
func convertContributionRankingResponse(resp *pbActivity.ContributionRankingResponse) map[string]interface{} {
|
||||
items := make([]map[string]interface{}, 0, len(resp.Items))
|
||||
|
||||
@ -286,7 +286,7 @@ func (ctrl *AssetController) EstimateMintCost(c *gin.Context) {
|
||||
"current_balance": resp.CurrentBalance,
|
||||
"balance_after": resp.BalanceAfter,
|
||||
"mint_count": resp.MintCount,
|
||||
"next_tier_hint": resp.NextTierHint,
|
||||
"next_tier_cost": resp.NextTierCost,
|
||||
}
|
||||
response.Success(c, data)
|
||||
}
|
||||
|
||||
@ -248,7 +248,8 @@ func SetupRouter(userClient *client.Client, socialClient *client.Client, assetCl
|
||||
activities.GET("/:id", activityCtrl.GetActivity) // 获取活动详情
|
||||
activities.GET("/:id/items", activityCtrl.GetActivityItems) // 获取活动道具列表
|
||||
activities.GET("/:id/progress", activityCtrl.GetProgress) // 获取活动进度
|
||||
activities.POST("/:id/purchase", activityCtrl.PurchaseItem) // 购买道具
|
||||
activities.POST("/:id/purchase", activityCtrl.PurchaseItem) // 购买道具
|
||||
activities.POST("/:id/batch-purchase", activityCtrl.BatchPurchaseItem) // 批量购买道具
|
||||
activities.GET("/:id/ranking", activityCtrl.GetContributionRanking) // 获取贡献点排名
|
||||
activities.GET("/:id/contributions/latest", activityCtrl.GetLatestContributions) // 获取最新贡献记录
|
||||
}
|
||||
|
||||
@ -496,6 +496,282 @@ func (x *PurchaseItemResponse) GetRemainingBalance() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 单个购买项(用于批量购买)
|
||||
type PurchaseItem struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ItemType string `protobuf:"bytes,1,opt,name=item_type,json=itemType,proto3" json:"item_type,omitempty"`
|
||||
Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PurchaseItem) Reset() {
|
||||
*x = PurchaseItem{}
|
||||
mi := &file_activity_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PurchaseItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PurchaseItem) ProtoMessage() {}
|
||||
|
||||
func (x *PurchaseItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PurchaseItem.ProtoReflect.Descriptor instead.
|
||||
func (*PurchaseItem) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *PurchaseItem) GetItemType() string {
|
||||
if x != nil {
|
||||
return x.ItemType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PurchaseItem) GetQuantity() int32 {
|
||||
if x != nil {
|
||||
return x.Quantity
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 批量购买道具请求
|
||||
type BatchPurchaseItemRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ActivityId int64 `protobuf:"varint,1,opt,name=activity_id,json=activityId,proto3" json:"activity_id,omitempty"`
|
||||
Items []*PurchaseItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` // 购买项列表
|
||||
StarId int64 `protobuf:"varint,3,opt,name=star_id,json=starId,proto3" json:"star_id,omitempty"`
|
||||
UserId int64 `protobuf:"varint,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // 当前用户ID
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) Reset() {
|
||||
*x = BatchPurchaseItemRequest{}
|
||||
mi := &file_activity_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BatchPurchaseItemRequest) ProtoMessage() {}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BatchPurchaseItemRequest.ProtoReflect.Descriptor instead.
|
||||
func (*BatchPurchaseItemRequest) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) GetActivityId() int64 {
|
||||
if x != nil {
|
||||
return x.ActivityId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) GetItems() []*PurchaseItem {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) GetStarId() int64 {
|
||||
if x != nil {
|
||||
return x.StarId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemRequest) GetUserId() int64 {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 批量购买道具响应
|
||||
type BatchPurchaseItemResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
||||
TotalCrystalSpent int64 `protobuf:"varint,2,opt,name=total_crystal_spent,json=totalCrystalSpent,proto3" json:"total_crystal_spent,omitempty"` // 本次消费水晶
|
||||
TotalContribution int64 `protobuf:"varint,3,opt,name=total_contribution,json=totalContribution,proto3" json:"total_contribution,omitempty"` // 本次获得贡献点
|
||||
CurrentProgress int64 `protobuf:"varint,4,opt,name=current_progress,json=currentProgress,proto3" json:"current_progress,omitempty"` // 当前活动进度
|
||||
RemainingBalance int64 `protobuf:"varint,5,opt,name=remaining_balance,json=remainingBalance,proto3" json:"remaining_balance,omitempty"` // 剩余水晶余额
|
||||
SuccessCount int32 `protobuf:"varint,6,opt,name=success_count,json=successCount,proto3" json:"success_count,omitempty"` // 成功购买数量
|
||||
FailCount int32 `protobuf:"varint,7,opt,name=fail_count,json=failCount,proto3" json:"fail_count,omitempty"` // 失败购买数量
|
||||
Fails []*PurchaseFailItem `protobuf:"bytes,8,rep,name=fails,proto3" json:"fails,omitempty"` // 失败的项
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) Reset() {
|
||||
*x = BatchPurchaseItemResponse{}
|
||||
mi := &file_activity_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BatchPurchaseItemResponse) ProtoMessage() {}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BatchPurchaseItemResponse.ProtoReflect.Descriptor instead.
|
||||
func (*BatchPurchaseItemResponse) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetBase() *common.BaseResponse {
|
||||
if x != nil {
|
||||
return x.Base
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetTotalCrystalSpent() int64 {
|
||||
if x != nil {
|
||||
return x.TotalCrystalSpent
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetTotalContribution() int64 {
|
||||
if x != nil {
|
||||
return x.TotalContribution
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetCurrentProgress() int64 {
|
||||
if x != nil {
|
||||
return x.CurrentProgress
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetRemainingBalance() int64 {
|
||||
if x != nil {
|
||||
return x.RemainingBalance
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetSuccessCount() int32 {
|
||||
if x != nil {
|
||||
return x.SuccessCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetFailCount() int32 {
|
||||
if x != nil {
|
||||
return x.FailCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BatchPurchaseItemResponse) GetFails() []*PurchaseFailItem {
|
||||
if x != nil {
|
||||
return x.Fails
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 购买失败的项
|
||||
type PurchaseFailItem struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ItemType string `protobuf:"bytes,1,opt,name=item_type,json=itemType,proto3" json:"item_type,omitempty"`
|
||||
Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PurchaseFailItem) Reset() {
|
||||
*x = PurchaseFailItem{}
|
||||
mi := &file_activity_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PurchaseFailItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PurchaseFailItem) ProtoMessage() {}
|
||||
|
||||
func (x *PurchaseFailItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PurchaseFailItem.ProtoReflect.Descriptor instead.
|
||||
func (*PurchaseFailItem) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *PurchaseFailItem) GetItemType() string {
|
||||
if x != nil {
|
||||
return x.ItemType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PurchaseFailItem) GetReason() string {
|
||||
if x != nil {
|
||||
return x.Reason
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 贡献点排名请求
|
||||
type ContributionRankingRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@ -510,7 +786,7 @@ type ContributionRankingRequest struct {
|
||||
|
||||
func (x *ContributionRankingRequest) Reset() {
|
||||
*x = ContributionRankingRequest{}
|
||||
mi := &file_activity_proto_msgTypes[5]
|
||||
mi := &file_activity_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -522,7 +798,7 @@ func (x *ContributionRankingRequest) String() string {
|
||||
func (*ContributionRankingRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ContributionRankingRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[5]
|
||||
mi := &file_activity_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -535,7 +811,7 @@ func (x *ContributionRankingRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ContributionRankingRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ContributionRankingRequest) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{5}
|
||||
return file_activity_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *ContributionRankingRequest) GetActivityId() int64 {
|
||||
@ -588,7 +864,7 @@ type ContributionRankingItem struct {
|
||||
|
||||
func (x *ContributionRankingItem) Reset() {
|
||||
*x = ContributionRankingItem{}
|
||||
mi := &file_activity_proto_msgTypes[6]
|
||||
mi := &file_activity_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -600,7 +876,7 @@ func (x *ContributionRankingItem) String() string {
|
||||
func (*ContributionRankingItem) ProtoMessage() {}
|
||||
|
||||
func (x *ContributionRankingItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[6]
|
||||
mi := &file_activity_proto_msgTypes[10]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -613,7 +889,7 @@ func (x *ContributionRankingItem) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ContributionRankingItem.ProtoReflect.Descriptor instead.
|
||||
func (*ContributionRankingItem) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{6}
|
||||
return file_activity_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *ContributionRankingItem) GetRank() int32 {
|
||||
@ -673,7 +949,7 @@ type ContributionRankingResponse struct {
|
||||
|
||||
func (x *ContributionRankingResponse) Reset() {
|
||||
*x = ContributionRankingResponse{}
|
||||
mi := &file_activity_proto_msgTypes[7]
|
||||
mi := &file_activity_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -685,7 +961,7 @@ func (x *ContributionRankingResponse) String() string {
|
||||
func (*ContributionRankingResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ContributionRankingResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[7]
|
||||
mi := &file_activity_proto_msgTypes[11]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -698,7 +974,7 @@ func (x *ContributionRankingResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ContributionRankingResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ContributionRankingResponse) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{7}
|
||||
return file_activity_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *ContributionRankingResponse) GetBase() *common.BaseResponse {
|
||||
@ -758,7 +1034,7 @@ type MyContribution struct {
|
||||
|
||||
func (x *MyContribution) Reset() {
|
||||
*x = MyContribution{}
|
||||
mi := &file_activity_proto_msgTypes[8]
|
||||
mi := &file_activity_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -770,7 +1046,7 @@ func (x *MyContribution) String() string {
|
||||
func (*MyContribution) ProtoMessage() {}
|
||||
|
||||
func (x *MyContribution) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[8]
|
||||
mi := &file_activity_proto_msgTypes[12]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -783,7 +1059,7 @@ func (x *MyContribution) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use MyContribution.ProtoReflect.Descriptor instead.
|
||||
func (*MyContribution) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{8}
|
||||
return file_activity_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
func (x *MyContribution) GetRank() int32 {
|
||||
@ -841,7 +1117,7 @@ type GetActivityListRequest struct {
|
||||
|
||||
func (x *GetActivityListRequest) Reset() {
|
||||
*x = GetActivityListRequest{}
|
||||
mi := &file_activity_proto_msgTypes[9]
|
||||
mi := &file_activity_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -853,7 +1129,7 @@ func (x *GetActivityListRequest) String() string {
|
||||
func (*GetActivityListRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetActivityListRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[9]
|
||||
mi := &file_activity_proto_msgTypes[13]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -866,7 +1142,7 @@ func (x *GetActivityListRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetActivityListRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetActivityListRequest) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{9}
|
||||
return file_activity_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *GetActivityListRequest) GetStarId() int64 {
|
||||
@ -911,7 +1187,7 @@ type GetActivityListResponse struct {
|
||||
|
||||
func (x *GetActivityListResponse) Reset() {
|
||||
*x = GetActivityListResponse{}
|
||||
mi := &file_activity_proto_msgTypes[10]
|
||||
mi := &file_activity_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -923,7 +1199,7 @@ func (x *GetActivityListResponse) String() string {
|
||||
func (*GetActivityListResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetActivityListResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[10]
|
||||
mi := &file_activity_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -936,7 +1212,7 @@ func (x *GetActivityListResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetActivityListResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetActivityListResponse) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{10}
|
||||
return file_activity_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *GetActivityListResponse) GetBase() *common.BaseResponse {
|
||||
@ -984,7 +1260,7 @@ type GetProgressRequest struct {
|
||||
|
||||
func (x *GetProgressRequest) Reset() {
|
||||
*x = GetProgressRequest{}
|
||||
mi := &file_activity_proto_msgTypes[11]
|
||||
mi := &file_activity_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -996,7 +1272,7 @@ func (x *GetProgressRequest) String() string {
|
||||
func (*GetProgressRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetProgressRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[11]
|
||||
mi := &file_activity_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1009,7 +1285,7 @@ func (x *GetProgressRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetProgressRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetProgressRequest) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{11}
|
||||
return file_activity_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *GetProgressRequest) GetActivityId() int64 {
|
||||
@ -1035,7 +1311,7 @@ type GetProgressResponse struct {
|
||||
|
||||
func (x *GetProgressResponse) Reset() {
|
||||
*x = GetProgressResponse{}
|
||||
mi := &file_activity_proto_msgTypes[12]
|
||||
mi := &file_activity_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1047,7 +1323,7 @@ func (x *GetProgressResponse) String() string {
|
||||
func (*GetProgressResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetProgressResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[12]
|
||||
mi := &file_activity_proto_msgTypes[16]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1060,7 +1336,7 @@ func (x *GetProgressResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetProgressResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetProgressResponse) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{12}
|
||||
return file_activity_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *GetProgressResponse) GetBase() *common.BaseResponse {
|
||||
@ -1130,7 +1406,7 @@ type MintingActivity struct {
|
||||
|
||||
func (x *MintingActivity) Reset() {
|
||||
*x = MintingActivity{}
|
||||
mi := &file_activity_proto_msgTypes[13]
|
||||
mi := &file_activity_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1142,7 +1418,7 @@ func (x *MintingActivity) String() string {
|
||||
func (*MintingActivity) ProtoMessage() {}
|
||||
|
||||
func (x *MintingActivity) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[13]
|
||||
mi := &file_activity_proto_msgTypes[17]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1155,7 +1431,7 @@ func (x *MintingActivity) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use MintingActivity.ProtoReflect.Descriptor instead.
|
||||
func (*MintingActivity) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{13}
|
||||
return file_activity_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
func (x *MintingActivity) GetId() int64 {
|
||||
@ -1233,7 +1509,7 @@ type GetMintingActivitiesRequest struct {
|
||||
|
||||
func (x *GetMintingActivitiesRequest) Reset() {
|
||||
*x = GetMintingActivitiesRequest{}
|
||||
mi := &file_activity_proto_msgTypes[14]
|
||||
mi := &file_activity_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1245,7 +1521,7 @@ func (x *GetMintingActivitiesRequest) String() string {
|
||||
func (*GetMintingActivitiesRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetMintingActivitiesRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[14]
|
||||
mi := &file_activity_proto_msgTypes[18]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1258,7 +1534,7 @@ func (x *GetMintingActivitiesRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetMintingActivitiesRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetMintingActivitiesRequest) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{14}
|
||||
return file_activity_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
func (x *GetMintingActivitiesRequest) GetStarId() int64 {
|
||||
@ -1296,7 +1572,7 @@ type GetMintingActivitiesResponse struct {
|
||||
|
||||
func (x *GetMintingActivitiesResponse) Reset() {
|
||||
*x = GetMintingActivitiesResponse{}
|
||||
mi := &file_activity_proto_msgTypes[15]
|
||||
mi := &file_activity_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1308,7 +1584,7 @@ func (x *GetMintingActivitiesResponse) String() string {
|
||||
func (*GetMintingActivitiesResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetMintingActivitiesResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[15]
|
||||
mi := &file_activity_proto_msgTypes[19]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1321,7 +1597,7 @@ func (x *GetMintingActivitiesResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetMintingActivitiesResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetMintingActivitiesResponse) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{15}
|
||||
return file_activity_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
func (x *GetMintingActivitiesResponse) GetBase() *common.BaseResponse {
|
||||
@ -1372,7 +1648,7 @@ type GetLatestContributionsRequest struct {
|
||||
|
||||
func (x *GetLatestContributionsRequest) Reset() {
|
||||
*x = GetLatestContributionsRequest{}
|
||||
mi := &file_activity_proto_msgTypes[16]
|
||||
mi := &file_activity_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1384,7 +1660,7 @@ func (x *GetLatestContributionsRequest) String() string {
|
||||
func (*GetLatestContributionsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetLatestContributionsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[16]
|
||||
mi := &file_activity_proto_msgTypes[20]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1397,7 +1673,7 @@ func (x *GetLatestContributionsRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetLatestContributionsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetLatestContributionsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{16}
|
||||
return file_activity_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *GetLatestContributionsRequest) GetActivityId() int64 {
|
||||
@ -1449,7 +1725,7 @@ type ContributionRecord struct {
|
||||
|
||||
func (x *ContributionRecord) Reset() {
|
||||
*x = ContributionRecord{}
|
||||
mi := &file_activity_proto_msgTypes[17]
|
||||
mi := &file_activity_proto_msgTypes[21]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1461,7 +1737,7 @@ func (x *ContributionRecord) String() string {
|
||||
func (*ContributionRecord) ProtoMessage() {}
|
||||
|
||||
func (x *ContributionRecord) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[17]
|
||||
mi := &file_activity_proto_msgTypes[21]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1474,7 +1750,7 @@ func (x *ContributionRecord) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ContributionRecord.ProtoReflect.Descriptor instead.
|
||||
func (*ContributionRecord) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{17}
|
||||
return file_activity_proto_rawDescGZIP(), []int{21}
|
||||
}
|
||||
|
||||
func (x *ContributionRecord) GetId() int64 {
|
||||
@ -1572,7 +1848,7 @@ type GetLatestContributionsResponse struct {
|
||||
|
||||
func (x *GetLatestContributionsResponse) Reset() {
|
||||
*x = GetLatestContributionsResponse{}
|
||||
mi := &file_activity_proto_msgTypes[18]
|
||||
mi := &file_activity_proto_msgTypes[22]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1584,7 +1860,7 @@ func (x *GetLatestContributionsResponse) String() string {
|
||||
func (*GetLatestContributionsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetLatestContributionsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_activity_proto_msgTypes[18]
|
||||
mi := &file_activity_proto_msgTypes[22]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1597,7 +1873,7 @@ func (x *GetLatestContributionsResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetLatestContributionsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetLatestContributionsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_activity_proto_rawDescGZIP(), []int{18}
|
||||
return file_activity_proto_rawDescGZIP(), []int{22}
|
||||
}
|
||||
|
||||
func (x *GetLatestContributionsResponse) GetBase() *common.BaseResponse {
|
||||
@ -1663,7 +1939,29 @@ const file_activity_proto_rawDesc = "" +
|
||||
"\x13total_crystal_spent\x18\x02 \x01(\x03R\x11totalCrystalSpent\x12-\n" +
|
||||
"\x12total_contribution\x18\x03 \x01(\x03R\x11totalContribution\x12)\n" +
|
||||
"\x10current_progress\x18\x04 \x01(\x03R\x0fcurrentProgress\x12+\n" +
|
||||
"\x11remaining_balance\x18\x05 \x01(\x03R\x10remainingBalance\"\xa0\x01\n" +
|
||||
"\x11remaining_balance\x18\x05 \x01(\x03R\x10remainingBalance\"G\n" +
|
||||
"\fPurchaseItem\x12\x1b\n" +
|
||||
"\titem_type\x18\x01 \x01(\tR\bitemType\x12\x1a\n" +
|
||||
"\bquantity\x18\x02 \x01(\x05R\bquantity\"\xa3\x01\n" +
|
||||
"\x18BatchPurchaseItemRequest\x12\x1f\n" +
|
||||
"\vactivity_id\x18\x01 \x01(\x03R\n" +
|
||||
"activityId\x124\n" +
|
||||
"\x05items\x18\x02 \x03(\v2\x1e.topfans.activity.PurchaseItemR\x05items\x12\x17\n" +
|
||||
"\astar_id\x18\x03 \x01(\x03R\x06starId\x12\x17\n" +
|
||||
"\auser_id\x18\x04 \x01(\x03R\x06userId\"\x82\x03\n" +
|
||||
"\x19BatchPurchaseItemResponse\x120\n" +
|
||||
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12.\n" +
|
||||
"\x13total_crystal_spent\x18\x02 \x01(\x03R\x11totalCrystalSpent\x12-\n" +
|
||||
"\x12total_contribution\x18\x03 \x01(\x03R\x11totalContribution\x12)\n" +
|
||||
"\x10current_progress\x18\x04 \x01(\x03R\x0fcurrentProgress\x12+\n" +
|
||||
"\x11remaining_balance\x18\x05 \x01(\x03R\x10remainingBalance\x12#\n" +
|
||||
"\rsuccess_count\x18\x06 \x01(\x05R\fsuccessCount\x12\x1d\n" +
|
||||
"\n" +
|
||||
"fail_count\x18\a \x01(\x05R\tfailCount\x128\n" +
|
||||
"\x05fails\x18\b \x03(\v2\".topfans.activity.PurchaseFailItemR\x05fails\"G\n" +
|
||||
"\x10PurchaseFailItem\x12\x1b\n" +
|
||||
"\titem_type\x18\x01 \x01(\tR\bitemType\x12\x16\n" +
|
||||
"\x06reason\x18\x02 \x01(\tR\x06reason\"\xa0\x01\n" +
|
||||
"\x1aContributionRankingRequest\x12\x1f\n" +
|
||||
"\vactivity_id\x18\x01 \x01(\x03R\n" +
|
||||
"activityId\x12\x17\n" +
|
||||
@ -1769,13 +2067,15 @@ const file_activity_proto_rawDesc = "" +
|
||||
"created_at\x18\f \x01(\x03R\tcreatedAt\"\x92\x01\n" +
|
||||
"\x1eGetLatestContributionsResponse\x120\n" +
|
||||
"\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12>\n" +
|
||||
"\arecords\x18\x02 \x03(\v2$.topfans.activity.ContributionRecordR\arecords2\xce\t\n" +
|
||||
"\arecords\x18\x02 \x03(\v2$.topfans.activity.ContributionRecordR\arecords2\xf9\n" +
|
||||
"\n" +
|
||||
"\x0fActivityService\x12\x82\x01\n" +
|
||||
"\x0fGetActivityList\x12(.topfans.activity.GetActivityListRequest\x1a).topfans.activity.GetActivityListResponse\"\x1a\x82\xd3\xe4\x93\x02\x14\x12\x12/api/v1/activities\x12y\n" +
|
||||
"\vGetActivity\x12$.topfans.activity.GetProgressRequest\x1a\x1a.topfans.activity.Activity\"(\x82\xd3\xe4\x93\x02\"\x12 /api/v1/activities/{activity_id}\x12\x91\x01\n" +
|
||||
"\x10GetActivityItems\x12$.topfans.activity.GetProgressRequest\x1a'.topfans.activity.ActivityItemsResponse\".\x82\xd3\xe4\x93\x02(\x12&/api/v1/activities/{activity_id}/items\x12\x8d\x01\n" +
|
||||
"\vGetProgress\x12$.topfans.activity.GetProgressRequest\x1a%.topfans.activity.GetProgressResponse\"1\x82\xd3\xe4\x93\x02+\x12)/api/v1/activities/{activity_id}/progress\x12\x93\x01\n" +
|
||||
"\fPurchaseItem\x12%.topfans.activity.PurchaseItemRequest\x1a&.topfans.activity.PurchaseItemResponse\"4\x82\xd3\xe4\x93\x02.:\x01*\")/api/v1/activities/{activity_id}/purchase\x12\xa7\x01\n" +
|
||||
"\fPurchaseItem\x12%.topfans.activity.PurchaseItemRequest\x1a&.topfans.activity.PurchaseItemResponse\"4\x82\xd3\xe4\x93\x02.:\x01*\")/api/v1/activities/{activity_id}/purchase\x12\xa8\x01\n" +
|
||||
"\x11BatchPurchaseItem\x12*.topfans.activity.BatchPurchaseItemRequest\x1a+.topfans.activity.BatchPurchaseItemResponse\":\x82\xd3\xe4\x93\x024:\x01*\"//api/v1/activities/{activity_id}/batch-purchase\x12\xa7\x01\n" +
|
||||
"\x16GetContributionRanking\x12,.topfans.activity.ContributionRankingRequest\x1a-.topfans.activity.ContributionRankingResponse\"0\x82\xd3\xe4\x93\x02*\x12(/api/v1/activities/{activity_id}/ranking\x12\x99\x01\n" +
|
||||
"\x14GetMintingActivities\x12-.topfans.activity.GetMintingActivitiesRequest\x1a..topfans.activity.GetMintingActivitiesResponse\"\"\x82\xd3\xe4\x93\x02\x1c\x12\x1a/api/v1/minting-activities\x12\xba\x01\n" +
|
||||
"\x16GetLatestContributions\x12/.topfans.activity.GetLatestContributionsRequest\x1a0.topfans.activity.GetLatestContributionsResponse\"=\x82\xd3\xe4\x93\x027\x125/api/v1/activities/{activity_id}/contributions/latestB8Z6github.com/topfans/backend/pkg/proto/activity;activityb\x06proto3"
|
||||
@ -1792,64 +2092,73 @@ func file_activity_proto_rawDescGZIP() []byte {
|
||||
return file_activity_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
||||
var file_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
|
||||
var file_activity_proto_goTypes = []any{
|
||||
(*Activity)(nil), // 0: topfans.activity.Activity
|
||||
(*ActivityItem)(nil), // 1: topfans.activity.ActivityItem
|
||||
(*ActivityItemsResponse)(nil), // 2: topfans.activity.ActivityItemsResponse
|
||||
(*PurchaseItemRequest)(nil), // 3: topfans.activity.PurchaseItemRequest
|
||||
(*PurchaseItemResponse)(nil), // 4: topfans.activity.PurchaseItemResponse
|
||||
(*ContributionRankingRequest)(nil), // 5: topfans.activity.ContributionRankingRequest
|
||||
(*ContributionRankingItem)(nil), // 6: topfans.activity.ContributionRankingItem
|
||||
(*ContributionRankingResponse)(nil), // 7: topfans.activity.ContributionRankingResponse
|
||||
(*MyContribution)(nil), // 8: topfans.activity.MyContribution
|
||||
(*GetActivityListRequest)(nil), // 9: topfans.activity.GetActivityListRequest
|
||||
(*GetActivityListResponse)(nil), // 10: topfans.activity.GetActivityListResponse
|
||||
(*GetProgressRequest)(nil), // 11: topfans.activity.GetProgressRequest
|
||||
(*GetProgressResponse)(nil), // 12: topfans.activity.GetProgressResponse
|
||||
(*MintingActivity)(nil), // 13: topfans.activity.MintingActivity
|
||||
(*GetMintingActivitiesRequest)(nil), // 14: topfans.activity.GetMintingActivitiesRequest
|
||||
(*GetMintingActivitiesResponse)(nil), // 15: topfans.activity.GetMintingActivitiesResponse
|
||||
(*GetLatestContributionsRequest)(nil), // 16: topfans.activity.GetLatestContributionsRequest
|
||||
(*ContributionRecord)(nil), // 17: topfans.activity.ContributionRecord
|
||||
(*GetLatestContributionsResponse)(nil), // 18: topfans.activity.GetLatestContributionsResponse
|
||||
(*common.BaseResponse)(nil), // 19: topfans.common.BaseResponse
|
||||
(*PurchaseItem)(nil), // 5: topfans.activity.PurchaseItem
|
||||
(*BatchPurchaseItemRequest)(nil), // 6: topfans.activity.BatchPurchaseItemRequest
|
||||
(*BatchPurchaseItemResponse)(nil), // 7: topfans.activity.BatchPurchaseItemResponse
|
||||
(*PurchaseFailItem)(nil), // 8: topfans.activity.PurchaseFailItem
|
||||
(*ContributionRankingRequest)(nil), // 9: topfans.activity.ContributionRankingRequest
|
||||
(*ContributionRankingItem)(nil), // 10: topfans.activity.ContributionRankingItem
|
||||
(*ContributionRankingResponse)(nil), // 11: topfans.activity.ContributionRankingResponse
|
||||
(*MyContribution)(nil), // 12: topfans.activity.MyContribution
|
||||
(*GetActivityListRequest)(nil), // 13: topfans.activity.GetActivityListRequest
|
||||
(*GetActivityListResponse)(nil), // 14: topfans.activity.GetActivityListResponse
|
||||
(*GetProgressRequest)(nil), // 15: topfans.activity.GetProgressRequest
|
||||
(*GetProgressResponse)(nil), // 16: topfans.activity.GetProgressResponse
|
||||
(*MintingActivity)(nil), // 17: topfans.activity.MintingActivity
|
||||
(*GetMintingActivitiesRequest)(nil), // 18: topfans.activity.GetMintingActivitiesRequest
|
||||
(*GetMintingActivitiesResponse)(nil), // 19: topfans.activity.GetMintingActivitiesResponse
|
||||
(*GetLatestContributionsRequest)(nil), // 20: topfans.activity.GetLatestContributionsRequest
|
||||
(*ContributionRecord)(nil), // 21: topfans.activity.ContributionRecord
|
||||
(*GetLatestContributionsResponse)(nil), // 22: topfans.activity.GetLatestContributionsResponse
|
||||
(*common.BaseResponse)(nil), // 23: topfans.common.BaseResponse
|
||||
}
|
||||
var file_activity_proto_depIdxs = []int32{
|
||||
1, // 0: topfans.activity.Activity.items:type_name -> topfans.activity.ActivityItem
|
||||
1, // 1: topfans.activity.ActivityItemsResponse.items:type_name -> topfans.activity.ActivityItem
|
||||
19, // 2: topfans.activity.PurchaseItemResponse.base:type_name -> topfans.common.BaseResponse
|
||||
19, // 3: topfans.activity.ContributionRankingResponse.base:type_name -> topfans.common.BaseResponse
|
||||
6, // 4: topfans.activity.ContributionRankingResponse.items:type_name -> topfans.activity.ContributionRankingItem
|
||||
8, // 5: topfans.activity.ContributionRankingResponse.my_contribution:type_name -> topfans.activity.MyContribution
|
||||
19, // 6: topfans.activity.GetActivityListResponse.base:type_name -> topfans.common.BaseResponse
|
||||
0, // 7: topfans.activity.GetActivityListResponse.activities:type_name -> topfans.activity.Activity
|
||||
19, // 8: topfans.activity.GetProgressResponse.base:type_name -> topfans.common.BaseResponse
|
||||
19, // 9: topfans.activity.GetMintingActivitiesResponse.base:type_name -> topfans.common.BaseResponse
|
||||
13, // 10: topfans.activity.GetMintingActivitiesResponse.activities:type_name -> topfans.activity.MintingActivity
|
||||
19, // 11: topfans.activity.GetLatestContributionsResponse.base:type_name -> topfans.common.BaseResponse
|
||||
17, // 12: topfans.activity.GetLatestContributionsResponse.records:type_name -> topfans.activity.ContributionRecord
|
||||
9, // 13: topfans.activity.ActivityService.GetActivityList:input_type -> topfans.activity.GetActivityListRequest
|
||||
11, // 14: topfans.activity.ActivityService.GetActivity:input_type -> topfans.activity.GetProgressRequest
|
||||
11, // 15: topfans.activity.ActivityService.GetActivityItems:input_type -> topfans.activity.GetProgressRequest
|
||||
11, // 16: topfans.activity.ActivityService.GetProgress:input_type -> topfans.activity.GetProgressRequest
|
||||
3, // 17: topfans.activity.ActivityService.PurchaseItem:input_type -> topfans.activity.PurchaseItemRequest
|
||||
5, // 18: topfans.activity.ActivityService.GetContributionRanking:input_type -> topfans.activity.ContributionRankingRequest
|
||||
14, // 19: topfans.activity.ActivityService.GetMintingActivities:input_type -> topfans.activity.GetMintingActivitiesRequest
|
||||
16, // 20: topfans.activity.ActivityService.GetLatestContributions:input_type -> topfans.activity.GetLatestContributionsRequest
|
||||
10, // 21: topfans.activity.ActivityService.GetActivityList:output_type -> topfans.activity.GetActivityListResponse
|
||||
0, // 22: topfans.activity.ActivityService.GetActivity:output_type -> topfans.activity.Activity
|
||||
2, // 23: topfans.activity.ActivityService.GetActivityItems:output_type -> topfans.activity.ActivityItemsResponse
|
||||
12, // 24: topfans.activity.ActivityService.GetProgress:output_type -> topfans.activity.GetProgressResponse
|
||||
4, // 25: topfans.activity.ActivityService.PurchaseItem:output_type -> topfans.activity.PurchaseItemResponse
|
||||
7, // 26: topfans.activity.ActivityService.GetContributionRanking:output_type -> topfans.activity.ContributionRankingResponse
|
||||
15, // 27: topfans.activity.ActivityService.GetMintingActivities:output_type -> topfans.activity.GetMintingActivitiesResponse
|
||||
18, // 28: topfans.activity.ActivityService.GetLatestContributions:output_type -> topfans.activity.GetLatestContributionsResponse
|
||||
21, // [21:29] is the sub-list for method output_type
|
||||
13, // [13:21] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
23, // 2: topfans.activity.PurchaseItemResponse.base:type_name -> topfans.common.BaseResponse
|
||||
5, // 3: topfans.activity.BatchPurchaseItemRequest.items:type_name -> topfans.activity.PurchaseItem
|
||||
23, // 4: topfans.activity.BatchPurchaseItemResponse.base:type_name -> topfans.common.BaseResponse
|
||||
8, // 5: topfans.activity.BatchPurchaseItemResponse.fails:type_name -> topfans.activity.PurchaseFailItem
|
||||
23, // 6: topfans.activity.ContributionRankingResponse.base:type_name -> topfans.common.BaseResponse
|
||||
10, // 7: topfans.activity.ContributionRankingResponse.items:type_name -> topfans.activity.ContributionRankingItem
|
||||
12, // 8: topfans.activity.ContributionRankingResponse.my_contribution:type_name -> topfans.activity.MyContribution
|
||||
23, // 9: topfans.activity.GetActivityListResponse.base:type_name -> topfans.common.BaseResponse
|
||||
0, // 10: topfans.activity.GetActivityListResponse.activities:type_name -> topfans.activity.Activity
|
||||
23, // 11: topfans.activity.GetProgressResponse.base:type_name -> topfans.common.BaseResponse
|
||||
23, // 12: topfans.activity.GetMintingActivitiesResponse.base:type_name -> topfans.common.BaseResponse
|
||||
17, // 13: topfans.activity.GetMintingActivitiesResponse.activities:type_name -> topfans.activity.MintingActivity
|
||||
23, // 14: topfans.activity.GetLatestContributionsResponse.base:type_name -> topfans.common.BaseResponse
|
||||
21, // 15: topfans.activity.GetLatestContributionsResponse.records:type_name -> topfans.activity.ContributionRecord
|
||||
13, // 16: topfans.activity.ActivityService.GetActivityList:input_type -> topfans.activity.GetActivityListRequest
|
||||
15, // 17: topfans.activity.ActivityService.GetActivity:input_type -> topfans.activity.GetProgressRequest
|
||||
15, // 18: topfans.activity.ActivityService.GetActivityItems:input_type -> topfans.activity.GetProgressRequest
|
||||
15, // 19: topfans.activity.ActivityService.GetProgress:input_type -> topfans.activity.GetProgressRequest
|
||||
3, // 20: topfans.activity.ActivityService.PurchaseItem:input_type -> topfans.activity.PurchaseItemRequest
|
||||
6, // 21: topfans.activity.ActivityService.BatchPurchaseItem:input_type -> topfans.activity.BatchPurchaseItemRequest
|
||||
9, // 22: topfans.activity.ActivityService.GetContributionRanking:input_type -> topfans.activity.ContributionRankingRequest
|
||||
18, // 23: topfans.activity.ActivityService.GetMintingActivities:input_type -> topfans.activity.GetMintingActivitiesRequest
|
||||
20, // 24: topfans.activity.ActivityService.GetLatestContributions:input_type -> topfans.activity.GetLatestContributionsRequest
|
||||
14, // 25: topfans.activity.ActivityService.GetActivityList:output_type -> topfans.activity.GetActivityListResponse
|
||||
0, // 26: topfans.activity.ActivityService.GetActivity:output_type -> topfans.activity.Activity
|
||||
2, // 27: topfans.activity.ActivityService.GetActivityItems:output_type -> topfans.activity.ActivityItemsResponse
|
||||
16, // 28: topfans.activity.ActivityService.GetProgress:output_type -> topfans.activity.GetProgressResponse
|
||||
4, // 29: topfans.activity.ActivityService.PurchaseItem:output_type -> topfans.activity.PurchaseItemResponse
|
||||
7, // 30: topfans.activity.ActivityService.BatchPurchaseItem:output_type -> topfans.activity.BatchPurchaseItemResponse
|
||||
11, // 31: topfans.activity.ActivityService.GetContributionRanking:output_type -> topfans.activity.ContributionRankingResponse
|
||||
19, // 32: topfans.activity.ActivityService.GetMintingActivities:output_type -> topfans.activity.GetMintingActivitiesResponse
|
||||
22, // 33: topfans.activity.ActivityService.GetLatestContributions:output_type -> topfans.activity.GetLatestContributionsResponse
|
||||
25, // [25:34] is the sub-list for method output_type
|
||||
16, // [16:25] is the sub-list for method input_type
|
||||
16, // [16:16] is the sub-list for extension type_name
|
||||
16, // [16:16] is the sub-list for extension extendee
|
||||
0, // [0:16] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_activity_proto_init() }
|
||||
@ -1863,7 +2172,7 @@ func file_activity_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_activity_proto_rawDesc), len(file_activity_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 19,
|
||||
NumMessages: 23,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@ -46,6 +46,8 @@ const (
|
||||
ActivityServiceGetProgressProcedure = "/topfans.activity.ActivityService/GetProgress"
|
||||
// ActivityServicePurchaseItemProcedure is the fully-qualified name of the ActivityService's PurchaseItem RPC.
|
||||
ActivityServicePurchaseItemProcedure = "/topfans.activity.ActivityService/PurchaseItem"
|
||||
// ActivityServiceBatchPurchaseItemProcedure is the fully-qualified name of the ActivityService's BatchPurchaseItem RPC.
|
||||
ActivityServiceBatchPurchaseItemProcedure = "/topfans.activity.ActivityService/BatchPurchaseItem"
|
||||
// ActivityServiceGetContributionRankingProcedure is the fully-qualified name of the ActivityService's GetContributionRanking RPC.
|
||||
ActivityServiceGetContributionRankingProcedure = "/topfans.activity.ActivityService/GetContributionRanking"
|
||||
// ActivityServiceGetMintingActivitiesProcedure is the fully-qualified name of the ActivityService's GetMintingActivities RPC.
|
||||
@ -65,6 +67,7 @@ type ActivityService interface {
|
||||
GetActivityItems(ctx context.Context, req *GetProgressRequest, opts ...client.CallOption) (*ActivityItemsResponse, error)
|
||||
GetProgress(ctx context.Context, req *GetProgressRequest, opts ...client.CallOption) (*GetProgressResponse, error)
|
||||
PurchaseItem(ctx context.Context, req *PurchaseItemRequest, opts ...client.CallOption) (*PurchaseItemResponse, error)
|
||||
BatchPurchaseItem(ctx context.Context, req *BatchPurchaseItemRequest, opts ...client.CallOption) (*BatchPurchaseItemResponse, error)
|
||||
GetContributionRanking(ctx context.Context, req *ContributionRankingRequest, opts ...client.CallOption) (*ContributionRankingResponse, error)
|
||||
GetMintingActivities(ctx context.Context, req *GetMintingActivitiesRequest, opts ...client.CallOption) (*GetMintingActivitiesResponse, error)
|
||||
GetLatestContributions(ctx context.Context, req *GetLatestContributionsRequest, opts ...client.CallOption) (*GetLatestContributionsResponse, error)
|
||||
@ -130,6 +133,14 @@ func (c *ActivityServiceImpl) PurchaseItem(ctx context.Context, req *PurchaseIte
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *ActivityServiceImpl) BatchPurchaseItem(ctx context.Context, req *BatchPurchaseItemRequest, opts ...client.CallOption) (*BatchPurchaseItemResponse, error) {
|
||||
resp := new(BatchPurchaseItemResponse)
|
||||
if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "BatchPurchaseItem", opts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *ActivityServiceImpl) GetContributionRanking(ctx context.Context, req *ContributionRankingRequest, opts ...client.CallOption) (*ContributionRankingResponse, error) {
|
||||
resp := new(ContributionRankingResponse)
|
||||
if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetContributionRanking", opts...); err != nil {
|
||||
@ -156,7 +167,7 @@ func (c *ActivityServiceImpl) GetLatestContributions(ctx context.Context, req *G
|
||||
|
||||
var ActivityService_ClientInfo = client.ClientInfo{
|
||||
InterfaceName: "topfans.activity.ActivityService",
|
||||
MethodNames: []string{"GetActivityList", "GetActivity", "GetActivityItems", "GetProgress", "PurchaseItem", "GetContributionRanking", "GetMintingActivities", "GetLatestContributions"},
|
||||
MethodNames: []string{"GetActivityList", "GetActivity", "GetActivityItems", "GetProgress", "PurchaseItem", "BatchPurchaseItem", "GetContributionRanking", "GetMintingActivities", "GetLatestContributions"},
|
||||
ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) {
|
||||
dubboCli := dubboCliRaw.(*ActivityServiceImpl)
|
||||
dubboCli.conn = conn
|
||||
@ -170,6 +181,7 @@ type ActivityServiceHandler interface {
|
||||
GetActivityItems(context.Context, *GetProgressRequest) (*ActivityItemsResponse, error)
|
||||
GetProgress(context.Context, *GetProgressRequest) (*GetProgressResponse, error)
|
||||
PurchaseItem(context.Context, *PurchaseItemRequest) (*PurchaseItemResponse, error)
|
||||
BatchPurchaseItem(context.Context, *BatchPurchaseItemRequest) (*BatchPurchaseItemResponse, error)
|
||||
GetContributionRanking(context.Context, *ContributionRankingRequest) (*ContributionRankingResponse, error)
|
||||
GetMintingActivities(context.Context, *GetMintingActivitiesRequest) (*GetMintingActivitiesResponse, error)
|
||||
GetLatestContributions(context.Context, *GetLatestContributionsRequest) (*GetLatestContributionsResponse, error)
|
||||
@ -262,6 +274,21 @@ var ActivityService_ServiceInfo = server.ServiceInfo{
|
||||
return triple_protocol.NewResponse(res), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "BatchPurchaseItem",
|
||||
Type: constant.CallUnary,
|
||||
ReqInitFunc: func() interface{} {
|
||||
return new(BatchPurchaseItemRequest)
|
||||
},
|
||||
MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
|
||||
req := args[0].(*BatchPurchaseItemRequest)
|
||||
res, err := handler.(ActivityServiceHandler).BatchPurchaseItem(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return triple_protocol.NewResponse(res), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GetContributionRanking",
|
||||
Type: constant.CallUnary,
|
||||
|
||||
@ -951,7 +951,7 @@ type EstimateMintCostResponse struct {
|
||||
CurrentBalance int64 `protobuf:"varint,3,opt,name=current_balance,json=currentBalance,proto3" json:"current_balance,omitempty"` // 当前余额(铸造前)
|
||||
BalanceAfter int64 `protobuf:"varint,4,opt,name=balance_after,json=balanceAfter,proto3" json:"balance_after,omitempty"` // 铸造后余额
|
||||
MintCount int32 `protobuf:"varint,5,opt,name=mint_count,json=mintCount,proto3" json:"mint_count,omitempty"` // 本次是第几次铸造
|
||||
NextTierHint string `protobuf:"bytes,6,opt,name=next_tier_hint,json=nextTierHint,proto3" json:"next_tier_hint,omitempty"` // 下一阶梯提示
|
||||
NextTierCost int64 `protobuf:"varint,6,opt,name=next_tier_cost,json=nextTierCost,proto3" json:"next_tier_cost,omitempty"` // 下一阶梯费用
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -1021,11 +1021,11 @@ func (x *EstimateMintCostResponse) GetMintCount() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *EstimateMintCostResponse) GetNextTierHint() string {
|
||||
func (x *EstimateMintCostResponse) GetNextTierCost() int64 {
|
||||
if x != nil {
|
||||
return x.NextTierHint
|
||||
return x.NextTierCost
|
||||
}
|
||||
return ""
|
||||
return 0
|
||||
}
|
||||
|
||||
// 获取我的藏品列表请求
|
||||
@ -3736,7 +3736,7 @@ const file_asset_proto_rawDesc = "" +
|
||||
"\rbalance_after\x18\x04 \x01(\x03R\fbalanceAfter\x12\x1d\n" +
|
||||
"\n" +
|
||||
"mint_count\x18\x05 \x01(\x05R\tmintCount\x12$\n" +
|
||||
"\x0enext_tier_hint\x18\x06 \x01(\tR\fnextTierHint\"\x8b\x01\n" +
|
||||
"\x0enext_tier_cost\x18\x06 \x01(\x03R\fnextTierCost\"\x8b\x01\n" +
|
||||
"\x12GetMyAssetsRequest\x12\x12\n" +
|
||||
"\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" +
|
||||
"\tpage_size\x18\x02 \x01(\x05R\bpageSize\x12\x16\n" +
|
||||
|
||||
@ -42,6 +42,8 @@ const (
|
||||
AssetServicePreCreateMintOrderProcedure = "/topfans.asset.AssetService/PreCreateMintOrder"
|
||||
// AssetServiceCreateMintOrderProcedure is the fully-qualified name of the AssetService's CreateMintOrder RPC.
|
||||
AssetServiceCreateMintOrderProcedure = "/topfans.asset.AssetService/CreateMintOrder"
|
||||
// AssetServiceEstimateMintCostProcedure is the fully-qualified name of the AssetService's EstimateMintCost RPC.
|
||||
AssetServiceEstimateMintCostProcedure = "/topfans.asset.AssetService/EstimateMintCost"
|
||||
// AssetServiceGetMyAssetsProcedure is the fully-qualified name of the AssetService's GetMyAssets RPC.
|
||||
AssetServiceGetMyAssetsProcedure = "/topfans.asset.AssetService/GetMyAssets"
|
||||
// AssetServiceGetAssetProcedure is the fully-qualified name of the AssetService's GetAsset RPC.
|
||||
@ -64,6 +66,16 @@ const (
|
||||
AssetServiceGetAssetLikesProcedure = "/topfans.asset.AssetService/GetAssetLikes"
|
||||
// AssetServiceClearAssetLikeRecordsProcedure is the fully-qualified name of the AssetService's ClearAssetLikeRecords RPC.
|
||||
AssetServiceClearAssetLikeRecordsProcedure = "/topfans.asset.AssetService/ClearAssetLikeRecords"
|
||||
// AssetServiceUploadMaterialProcedure is the fully-qualified name of the AssetService's UploadMaterial RPC.
|
||||
AssetServiceUploadMaterialProcedure = "/topfans.asset.AssetService/UploadMaterial"
|
||||
// AssetServiceBindAssetMaterialsProcedure is the fully-qualified name of the AssetService's BindAssetMaterials RPC.
|
||||
AssetServiceBindAssetMaterialsProcedure = "/topfans.asset.AssetService/BindAssetMaterials"
|
||||
// AssetServiceGetAssetMaterialsProcedure is the fully-qualified name of the AssetService's GetAssetMaterials RPC.
|
||||
AssetServiceGetAssetMaterialsProcedure = "/topfans.asset.AssetService/GetAssetMaterials"
|
||||
// AssetServiceUpdateMaterialLayerOrderProcedure is the fully-qualified name of the AssetService's UpdateMaterialLayerOrder RPC.
|
||||
AssetServiceUpdateMaterialLayerOrderProcedure = "/topfans.asset.AssetService/UpdateMaterialLayerOrder"
|
||||
// AssetServiceUnbindAssetMaterialProcedure is the fully-qualified name of the AssetService's UnbindAssetMaterial RPC.
|
||||
AssetServiceUnbindAssetMaterialProcedure = "/topfans.asset.AssetService/UnbindAssetMaterial"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -75,6 +87,7 @@ type AssetService interface {
|
||||
InitMintOrder(ctx context.Context, req *InitMintOrderRequest, opts ...client.CallOption) (*InitMintOrderResponse, error)
|
||||
PreCreateMintOrder(ctx context.Context, req *PreCreateMintOrderRequest, opts ...client.CallOption) (*PreCreateMintOrderResponse, error)
|
||||
CreateMintOrder(ctx context.Context, req *CreateMintOrderRequest, opts ...client.CallOption) (*CreateMintOrderResponse, error)
|
||||
EstimateMintCost(ctx context.Context, req *EstimateMintCostRequest, opts ...client.CallOption) (*EstimateMintCostResponse, error)
|
||||
GetMyAssets(ctx context.Context, req *GetMyAssetsRequest, opts ...client.CallOption) (*GetMyAssetsResponse, error)
|
||||
GetAsset(ctx context.Context, req *GetAssetRequest, opts ...client.CallOption) (*GetAssetResponse, error)
|
||||
GetAssetStatus(ctx context.Context, req *GetAssetStatusRequest, opts ...client.CallOption) (*GetAssetStatusResponse, error)
|
||||
@ -91,7 +104,6 @@ type AssetService interface {
|
||||
GetAssetMaterials(ctx context.Context, req *GetAssetMaterialsRequest, opts ...client.CallOption) (*GetAssetMaterialsResponse, error)
|
||||
UpdateMaterialLayerOrder(ctx context.Context, req *UpdateMaterialLayerOrderRequest, opts ...client.CallOption) (*UpdateMaterialLayerOrderResponse, error)
|
||||
UnbindAssetMaterial(ctx context.Context, req *UnbindAssetMaterialRequest, opts ...client.CallOption) (*UnbindAssetMaterialResponse, error)
|
||||
EstimateMintCost(ctx context.Context, req *EstimateMintCostRequest, opts ...client.CallOption) (*EstimateMintCostResponse, error)
|
||||
}
|
||||
|
||||
// NewAssetService constructs a client for the asset.AssetService service.
|
||||
@ -138,6 +150,14 @@ func (c *AssetServiceImpl) CreateMintOrder(ctx context.Context, req *CreateMintO
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *AssetServiceImpl) EstimateMintCost(ctx context.Context, req *EstimateMintCostRequest, opts ...client.CallOption) (*EstimateMintCostResponse, error) {
|
||||
resp := new(EstimateMintCostResponse)
|
||||
if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "EstimateMintCost", opts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *AssetServiceImpl) GetMyAssets(ctx context.Context, req *GetMyAssetsRequest, opts ...client.CallOption) (*GetMyAssetsResponse, error) {
|
||||
resp := new(GetMyAssetsResponse)
|
||||
if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetMyAssets", opts...); err != nil {
|
||||
@ -266,17 +286,9 @@ func (c *AssetServiceImpl) UnbindAssetMaterial(ctx context.Context, req *UnbindA
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *AssetServiceImpl) EstimateMintCost(ctx context.Context, req *EstimateMintCostRequest, opts ...client.CallOption) (*EstimateMintCostResponse, error) {
|
||||
resp := new(EstimateMintCostResponse)
|
||||
if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "EstimateMintCost", opts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
var AssetService_ClientInfo = client.ClientInfo{
|
||||
InterfaceName: "topfans.asset.AssetService",
|
||||
MethodNames: []string{"InitMintOrder", "PreCreateMintOrder", "CreateMintOrder", "GetMyAssets", "GetAsset", "GetAssetStatus", "GetMintOrder", "CancelMintOrder", "GetAssetForRPC", "LikeAsset", "UnlikeAsset", "CheckAssetLike", "GetAssetLikes", "ClearAssetLikeRecords", "UploadMaterial", "BindAssetMaterials", "GetAssetMaterials", "UpdateMaterialLayerOrder", "UnbindAssetMaterial", "EstimateMintCost"},
|
||||
MethodNames: []string{"InitMintOrder", "PreCreateMintOrder", "CreateMintOrder", "EstimateMintCost", "GetMyAssets", "GetAsset", "GetAssetStatus", "GetMintOrder", "CancelMintOrder", "GetAssetForRPC", "LikeAsset", "UnlikeAsset", "CheckAssetLike", "GetAssetLikes", "ClearAssetLikeRecords", "UploadMaterial", "BindAssetMaterials", "GetAssetMaterials", "UpdateMaterialLayerOrder", "UnbindAssetMaterial"},
|
||||
ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) {
|
||||
dubboCli := dubboCliRaw.(*AssetServiceImpl)
|
||||
dubboCli.conn = conn
|
||||
@ -288,6 +300,7 @@ type AssetServiceHandler interface {
|
||||
InitMintOrder(context.Context, *InitMintOrderRequest) (*InitMintOrderResponse, error)
|
||||
PreCreateMintOrder(context.Context, *PreCreateMintOrderRequest) (*PreCreateMintOrderResponse, error)
|
||||
CreateMintOrder(context.Context, *CreateMintOrderRequest) (*CreateMintOrderResponse, error)
|
||||
EstimateMintCost(context.Context, *EstimateMintCostRequest) (*EstimateMintCostResponse, error)
|
||||
GetMyAssets(context.Context, *GetMyAssetsRequest) (*GetMyAssetsResponse, error)
|
||||
GetAsset(context.Context, *GetAssetRequest) (*GetAssetResponse, error)
|
||||
GetAssetStatus(context.Context, *GetAssetStatusRequest) (*GetAssetStatusResponse, error)
|
||||
@ -304,7 +317,6 @@ type AssetServiceHandler interface {
|
||||
GetAssetMaterials(context.Context, *GetAssetMaterialsRequest) (*GetAssetMaterialsResponse, error)
|
||||
UpdateMaterialLayerOrder(context.Context, *UpdateMaterialLayerOrderRequest) (*UpdateMaterialLayerOrderResponse, error)
|
||||
UnbindAssetMaterial(context.Context, *UnbindAssetMaterialRequest) (*UnbindAssetMaterialResponse, error)
|
||||
EstimateMintCost(context.Context, *EstimateMintCostRequest) (*EstimateMintCostResponse, error)
|
||||
}
|
||||
|
||||
func RegisterAssetServiceHandler(srv *server.Server, hdlr AssetServiceHandler, opts ...server.ServiceOption) error {
|
||||
@ -364,6 +376,21 @@ var AssetService_ServiceInfo = server.ServiceInfo{
|
||||
return triple_protocol.NewResponse(res), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "EstimateMintCost",
|
||||
Type: constant.CallUnary,
|
||||
ReqInitFunc: func() interface{} {
|
||||
return new(EstimateMintCostRequest)
|
||||
},
|
||||
MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
|
||||
req := args[0].(*EstimateMintCostRequest)
|
||||
res, err := handler.(AssetServiceHandler).EstimateMintCost(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return triple_protocol.NewResponse(res), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GetMyAssets",
|
||||
Type: constant.CallUnary,
|
||||
@ -604,20 +631,5 @@ var AssetService_ServiceInfo = server.ServiceInfo{
|
||||
return triple_protocol.NewResponse(res), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "EstimateMintCost",
|
||||
Type: constant.CallUnary,
|
||||
ReqInitFunc: func() interface{} {
|
||||
return new(EstimateMintCostRequest)
|
||||
},
|
||||
MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
|
||||
req := args[0].(*EstimateMintCostRequest)
|
||||
res, err := handler.(AssetServiceHandler).EstimateMintCost(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return triple_protocol.NewResponse(res), nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -65,6 +65,38 @@ message PurchaseItemResponse {
|
||||
int64 remaining_balance = 5; // 剩余水晶余额
|
||||
}
|
||||
|
||||
// 单个购买项(用于批量购买)
|
||||
message PurchaseItem {
|
||||
string item_type = 1;
|
||||
int32 quantity = 2;
|
||||
}
|
||||
|
||||
// 批量购买道具请求
|
||||
message BatchPurchaseItemRequest {
|
||||
int64 activity_id = 1;
|
||||
repeated PurchaseItem items = 2; // 购买项列表
|
||||
int64 star_id = 3;
|
||||
int64 user_id = 4; // 当前用户ID
|
||||
}
|
||||
|
||||
// 批量购买道具响应
|
||||
message BatchPurchaseItemResponse {
|
||||
topfans.common.BaseResponse base = 1;
|
||||
int64 total_crystal_spent = 2; // 本次消费水晶
|
||||
int64 total_contribution = 3; // 本次获得贡献点
|
||||
int64 current_progress = 4; // 当前活动进度
|
||||
int64 remaining_balance = 5; // 剩余水晶余额
|
||||
int32 success_count = 6; // 成功购买数量
|
||||
int32 fail_count = 7; // 失败购买数量
|
||||
repeated PurchaseFailItem fails = 8; // 失败的项
|
||||
}
|
||||
|
||||
// 购买失败的项
|
||||
message PurchaseFailItem {
|
||||
string item_type = 1;
|
||||
string reason = 2;
|
||||
}
|
||||
|
||||
// 贡献点排名请求
|
||||
message ContributionRankingRequest {
|
||||
int64 activity_id = 1;
|
||||
@ -237,6 +269,14 @@ service ActivityService {
|
||||
};
|
||||
}
|
||||
|
||||
// 批量购买道具
|
||||
rpc BatchPurchaseItem(BatchPurchaseItemRequest) returns (BatchPurchaseItemResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/activities/{activity_id}/batch-purchase"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// 获取贡献点排名
|
||||
rpc GetContributionRanking(ContributionRankingRequest) returns (ContributionRankingResponse) {
|
||||
option (google.api.http) = {
|
||||
|
||||
@ -129,7 +129,7 @@ message EstimateMintCostResponse {
|
||||
int64 current_balance = 3; // 当前余额(铸造前)
|
||||
int64 balance_after = 4; // 铸造后余额
|
||||
int32 mint_count = 5; // 本次是第几次铸造
|
||||
string next_tier_hint = 6; // 下一阶梯提示
|
||||
int64 next_tier_cost = 6; // 下一阶梯费用
|
||||
}
|
||||
|
||||
// ==================== 资产查询相关消息 ====================
|
||||
|
||||
@ -51,6 +51,20 @@ fi
|
||||
echo "✅ 所有必需插件已安装"
|
||||
echo ""
|
||||
|
||||
# 辅助函数:移动 protoc-gen-go-triple v3 生成的文件到正确位置
|
||||
# v3 插件根据 go_package 路径生成文件到 github.com/ 目录,需要手动移动
|
||||
move_triple_files() {
|
||||
local module_path="$1"
|
||||
local target_dir="$2"
|
||||
local triple_file=$(basename "$module_path").triple.go
|
||||
local src_file="github.com/$module_path/$triple_file"
|
||||
if [ -f "$src_file" ]; then
|
||||
mv "$src_file" "$target_dir/"
|
||||
rm -rf "github.com/$module_path"
|
||||
echo " ✅ $triple_file 已移动到正确位置"
|
||||
fi
|
||||
}
|
||||
|
||||
# 预先创建目标目录
|
||||
echo "📁 创建目标目录..."
|
||||
for name in common user social asset gallery ranking activity task starbook; do
|
||||
@ -77,6 +91,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/user \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
user.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/user" "pkg/proto/user"
|
||||
|
||||
echo "✅ user.proto 编译完成"
|
||||
echo ""
|
||||
@ -90,6 +105,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/social \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
social.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/social" "pkg/proto/social"
|
||||
|
||||
echo "✅ social.proto 编译完成"
|
||||
echo ""
|
||||
@ -103,6 +119,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/asset \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
asset.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/asset" "pkg/proto/asset"
|
||||
|
||||
echo "✅ asset.proto 编译完成"
|
||||
echo ""
|
||||
@ -116,6 +133,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/gallery \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
gallery.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/gallery" "pkg/proto/gallery"
|
||||
|
||||
echo "✅ gallery.proto 编译完成"
|
||||
echo ""
|
||||
@ -129,6 +147,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/ranking \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
ranking.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/ranking" "pkg/proto/ranking"
|
||||
|
||||
echo "✅ ranking.proto 编译完成"
|
||||
echo ""
|
||||
@ -142,6 +161,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/activity \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
activity.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/activity" "pkg/proto/activity"
|
||||
|
||||
echo "✅ activity.proto 编译完成"
|
||||
echo ""
|
||||
@ -155,6 +175,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/task \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
task.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/task" "pkg/proto/task"
|
||||
|
||||
echo "✅ task.proto 编译完成"
|
||||
echo ""
|
||||
@ -168,6 +189,7 @@ protoc --proto_path=proto \
|
||||
--go-triple_out=pkg/proto/starbook \
|
||||
--go-triple_opt=paths=source_relative \
|
||||
starbook.proto
|
||||
move_triple_files "topfans/backend/pkg/proto/starbook" "pkg/proto/starbook"
|
||||
|
||||
echo "✅ starbook.proto 编译完成"
|
||||
echo ""
|
||||
|
||||
@ -162,6 +162,38 @@ func (p *ActivityProvider) PurchaseItem(ctx context.Context, req *pb.PurchaseIte
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// BatchPurchaseItem 批量购买道具
|
||||
func (p *ActivityProvider) BatchPurchaseItem(ctx context.Context, req *pb.BatchPurchaseItemRequest) (*pb.BatchPurchaseItemResponse, error) {
|
||||
logger.Logger.Info("Received BatchPurchaseItem request",
|
||||
zap.Int64("activity_id", req.ActivityId),
|
||||
zap.Int("items_count", len(req.Items)),
|
||||
zap.Int64("star_id", req.StarId),
|
||||
)
|
||||
|
||||
// 调用Service层
|
||||
resp, err := p.activityService.BatchPurchaseItem(ctx, req)
|
||||
if err != nil {
|
||||
logger.Logger.Error("BatchPurchaseItem failed", zap.Error(err))
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: appErrors.ToStatusCode(err),
|
||||
Message: err.Error(),
|
||||
Timestamp: time.Now().UnixMilli(),
|
||||
},
|
||||
}, err
|
||||
}
|
||||
|
||||
logger.Logger.Info("BatchPurchaseItem successful",
|
||||
zap.Int64("total_crystal_spent", resp.TotalCrystalSpent),
|
||||
zap.Int64("total_contribution", resp.TotalContribution),
|
||||
zap.Int64("remaining_balance", resp.RemainingBalance),
|
||||
zap.Int32("success_count", resp.SuccessCount),
|
||||
zap.Int32("fail_count", resp.FailCount),
|
||||
)
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetContributionRanking 获取贡献点排名
|
||||
func (p *ActivityProvider) GetContributionRanking(ctx context.Context, req *pb.ContributionRankingRequest) (*pb.ContributionRankingResponse, error) {
|
||||
logger.Logger.Info("Received GetContributionRanking request",
|
||||
|
||||
@ -32,6 +32,9 @@ type ActivityService interface {
|
||||
// PurchaseItem 购买道具
|
||||
PurchaseItem(ctx context.Context, req *pb.PurchaseItemRequest) (*pb.PurchaseItemResponse, error)
|
||||
|
||||
// BatchPurchaseItem 批量购买道具
|
||||
BatchPurchaseItem(ctx context.Context, req *pb.BatchPurchaseItemRequest) (*pb.BatchPurchaseItemResponse, error)
|
||||
|
||||
// GetContributionRanking 获取贡献点排名
|
||||
GetContributionRanking(ctx context.Context, req *pb.ContributionRankingRequest) (*pb.ContributionRankingResponse, error)
|
||||
|
||||
@ -411,6 +414,222 @@ func (s *activityService) PurchaseItem(ctx context.Context, req *pb.PurchaseItem
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BatchPurchaseItem 批量购买道具
|
||||
func (s *activityService) BatchPurchaseItem(ctx context.Context, req *pb.BatchPurchaseItemRequest) (*pb.BatchPurchaseItemResponse, error) {
|
||||
logger.Logger.Info("BatchPurchaseItem request",
|
||||
zap.Int64("activity_id", req.ActivityId),
|
||||
zap.Int("items_count", len(req.Items)),
|
||||
zap.Int64("star_id", req.StarId),
|
||||
)
|
||||
|
||||
// 参数校验
|
||||
if req.ActivityId <= 0 {
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 400,
|
||||
Message: "activity_id is required",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(req.Items) == 0 {
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 400,
|
||||
Message: "items 是必填参数",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
userID := req.UserId
|
||||
|
||||
// 获取活动
|
||||
activity, err := s.activityRepo.GetActivityByID(req.ActivityId)
|
||||
if err != nil {
|
||||
logger.Logger.Error("GetActivity failed", zap.Error(err))
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 500,
|
||||
Message: "获取活动失败: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if activity == nil {
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 404,
|
||||
Message: "活动不存在",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 检查活动状态
|
||||
currentStatus := activity.GetCurrentStatus()
|
||||
if currentStatus != "active" {
|
||||
var message string
|
||||
switch currentStatus {
|
||||
case "expired":
|
||||
message = "activity:expired"
|
||||
case "pending":
|
||||
message = "activity:pending"
|
||||
case "completed":
|
||||
message = "activity:completed"
|
||||
default:
|
||||
message = "activity:expired"
|
||||
}
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: pbCommon.StatusCode_STATUS_OK,
|
||||
Message: message,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 通过RPC获取用户当前水晶余额(只调用一次)
|
||||
profile, err := s.userRPCClient.GetFanProfile(userID, req.StarId)
|
||||
if err != nil {
|
||||
logger.Logger.Error("GetFanProfile failed", zap.Error(err))
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 500,
|
||||
Message: "获取粉丝档案失败: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if profile == nil {
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 404,
|
||||
Message: "粉丝档案不存在",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 计算总消费水晶和贡献点(先计算,用于校验余额)
|
||||
var totalCost int64
|
||||
var totalContribution int64
|
||||
itemInfoMap := make(map[string]*models.ActivityItem)
|
||||
|
||||
for _, item := range req.Items {
|
||||
if item.Quantity <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
activityItem, err := s.activityRepo.GetActivityItemByType(req.ActivityId, item.ItemType)
|
||||
if err != nil || activityItem == nil {
|
||||
logger.Logger.Warn("GetActivityItemByType failed or item not found",
|
||||
zap.String("item_type", item.ItemType),
|
||||
zap.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
itemInfoMap[item.ItemType] = activityItem
|
||||
totalCost += int64(activityItem.CrystalCost) * int64(item.Quantity)
|
||||
totalContribution += int64(activityItem.ContributionPoints) * int64(item.Quantity)
|
||||
}
|
||||
|
||||
// 检查水晶余额是否足够
|
||||
if profile.CrystalBalance < totalCost {
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 400,
|
||||
Message: "水晶余额不足",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 通过RPC扣减水晶
|
||||
newBalance, err := s.userRPCClient.UpdateCrystalBalance(userID, req.StarId, -totalCost)
|
||||
if err != nil {
|
||||
logger.Logger.Error("UpdateCrystalBalance failed", zap.Error(err))
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 500,
|
||||
Message: "扣减水晶失败: " + err.Error(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 更新活动进度
|
||||
newProgress := activity.CurrentProgress + totalContribution
|
||||
if newProgress > activity.TargetProgress {
|
||||
newProgress = activity.TargetProgress
|
||||
}
|
||||
|
||||
err = s.activityRepo.UpdateActivityProgress(req.ActivityId, newProgress)
|
||||
if err != nil {
|
||||
logger.Logger.Error("UpdateActivityProgress failed", zap.Error(err))
|
||||
}
|
||||
|
||||
// 创建贡献记录(合并为一个记录)
|
||||
now := time.Now().UnixMilli()
|
||||
contribution := &models.ActivityContribution{
|
||||
ActivityID: req.ActivityId,
|
||||
UserID: userID,
|
||||
StarID: req.StarId,
|
||||
Quantity: 0, // 批量购买不记录单数量
|
||||
CrystalSpent: totalCost,
|
||||
ContributionPoints: totalContribution,
|
||||
CreatedAt: now,
|
||||
}
|
||||
|
||||
err = s.activityRepo.CreateContribution(contribution)
|
||||
if err != nil {
|
||||
logger.Logger.Error("CreateContribution failed", zap.Error(err))
|
||||
}
|
||||
|
||||
// 更新用户统计
|
||||
stats, _ := s.activityRepo.GetUserStats(req.ActivityId, userID, req.StarId)
|
||||
if stats == nil {
|
||||
stats = &models.ActivityUserStats{
|
||||
ActivityID: req.ActivityId,
|
||||
UserID: userID,
|
||||
StarID: req.StarId,
|
||||
TotalContribution: 0,
|
||||
TotalCrystalSpent: 0,
|
||||
TotalItems: 0,
|
||||
LastContributeAt: now,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
}
|
||||
|
||||
stats.TotalContribution += totalContribution
|
||||
stats.TotalCrystalSpent += totalCost
|
||||
stats.TotalItems += len(req.Items)
|
||||
stats.LastContributeAt = now
|
||||
stats.UpdatedAt = now
|
||||
|
||||
err = s.activityRepo.UpdateUserStats(stats)
|
||||
if err != nil {
|
||||
logger.Logger.Error("UpdateUserStats failed", zap.Error(err))
|
||||
}
|
||||
|
||||
logger.Logger.Info("BatchPurchaseItem success",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.Int64("total_cost", totalCost),
|
||||
zap.Int64("total_contribution", totalContribution),
|
||||
zap.Int64("new_progress", newProgress),
|
||||
)
|
||||
|
||||
return &pb.BatchPurchaseItemResponse{
|
||||
Base: &pbCommon.BaseResponse{
|
||||
Code: 200,
|
||||
Message: "ok",
|
||||
},
|
||||
TotalCrystalSpent: totalCost,
|
||||
TotalContribution: totalContribution,
|
||||
CurrentProgress: newProgress,
|
||||
RemainingBalance: newBalance,
|
||||
SuccessCount: int32(len(req.Items)),
|
||||
FailCount: 0,
|
||||
Fails: []*pb.PurchaseFailItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetContributionRanking 获取贡献点排名
|
||||
func (s *activityService) GetContributionRanking(ctx context.Context, req *pb.ContributionRankingRequest) (*pb.ContributionRankingResponse, error) {
|
||||
logger.Logger.Info("GetContributionRanking request",
|
||||
|
||||
@ -853,6 +853,6 @@ func (p *AssetProvider) EstimateMintCost(ctx context.Context, req *pb.EstimateMi
|
||||
CurrentBalance: estimate.CurrentBalance,
|
||||
BalanceAfter: estimate.AfterBalance,
|
||||
MintCount: estimate.MintCount,
|
||||
NextTierHint: estimate.NextTierHint,
|
||||
NextTierCost: estimate.NextTierCost,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -59,14 +59,14 @@ type MintService interface {
|
||||
|
||||
// mintService 铸造服务实现
|
||||
type mintService struct {
|
||||
assetRepo repository.AssetRepository
|
||||
mintOrderRepo repository.MintOrderRepository
|
||||
userClient client.UserServiceClient
|
||||
db *gorm.DB
|
||||
config *config.AssetConfig
|
||||
registryRepo starbookRepo.AssetRegistryRepository // 资产索引仓库(用于星册体系)
|
||||
localMintCostRepo repository.MintCostRepository // 铸造消耗配置仓库
|
||||
userMintCountRepo repository.UserMintCountRepository // 用户铸爱累计仓库
|
||||
assetRepo repository.AssetRepository
|
||||
mintOrderRepo repository.MintOrderRepository
|
||||
userClient client.UserServiceClient
|
||||
db *gorm.DB
|
||||
config *config.AssetConfig
|
||||
registryRepo starbookRepo.AssetRegistryRepository // 资产索引仓库(用于星册体系)
|
||||
localMintCostRepo repository.MintCostRepository // 铸造消耗配置仓库
|
||||
userMintCountRepo repository.UserMintCountRepository // 用户铸爱累计仓库
|
||||
}
|
||||
|
||||
// NewMintService 创建铸造服务实例
|
||||
@ -81,13 +81,13 @@ func NewMintService(
|
||||
userMintCountRepo repository.UserMintCountRepository,
|
||||
) MintService {
|
||||
return &mintService{
|
||||
assetRepo: assetRepo,
|
||||
mintOrderRepo: mintOrderRepo,
|
||||
userClient: userClient,
|
||||
db: db,
|
||||
config: cfg,
|
||||
registryRepo: registryRepo,
|
||||
localMintCostRepo: localMintCostRepo,
|
||||
assetRepo: assetRepo,
|
||||
mintOrderRepo: mintOrderRepo,
|
||||
userClient: userClient,
|
||||
db: db,
|
||||
config: cfg,
|
||||
registryRepo: registryRepo,
|
||||
localMintCostRepo: localMintCostRepo,
|
||||
userMintCountRepo: userMintCountRepo,
|
||||
}
|
||||
}
|
||||
@ -346,11 +346,11 @@ func (s *mintService) CreateMintOrder(req *pb.CreateMintOrderRequest, userID, st
|
||||
OwnerUID: userID,
|
||||
StarID: starID,
|
||||
Name: getStringValue(mintOrder.Name),
|
||||
CoverURL: materialURLValue, // 直接使用素材图作为封面
|
||||
MaterialURL: &materialURLValue, // 使用指针
|
||||
CoverURL: materialURLValue, // 直接使用素材图作为封面
|
||||
MaterialURL: &materialURLValue, // 使用指针
|
||||
Description: mintOrder.Description,
|
||||
Visibility: models.AssetVisibilityPrivate,
|
||||
Status: models.AssetStatusActive, // 直接设为 Active
|
||||
Status: models.AssetStatusActive, // 直接设为 Active
|
||||
LikeCount: 0,
|
||||
Info: getStringValue(mintOrder.Info),
|
||||
TxHash: &mockTxHash,
|
||||
@ -856,32 +856,32 @@ func (s *mintService) EstimateMintCost(userID, starID int64) (*MintCostEstimate,
|
||||
afterBalance = 0
|
||||
}
|
||||
|
||||
// 下一阶梯费用提示
|
||||
var nextTierHint string
|
||||
// 下一阶梯费用
|
||||
var nextTierCost int64
|
||||
nextMintCount := currentMintCount + 2 // 下一次铸造的次数
|
||||
if nextMintCount <= 10 {
|
||||
nextCost, err := s.GetMintCost(nextMintCount)
|
||||
if err == nil {
|
||||
nextTierHint = fmt.Sprintf("下一阶梯 %d 水晶", nextCost.CostCrystal)
|
||||
nextTierCost = nextCost.CostCrystal
|
||||
}
|
||||
}
|
||||
|
||||
return &MintCostEstimate{
|
||||
CostCrystal: localMintCost.CostCrystal,
|
||||
CostCrystal: localMintCost.CostCrystal,
|
||||
CurrentBalance: currentBalance,
|
||||
AfterBalance: afterBalance,
|
||||
MintCount: currentMintCount + 1, // 本次将是第几次铸造
|
||||
NextTierHint: nextTierHint,
|
||||
NextTierCost: nextTierCost,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MintCostEstimate 铸造费用估算结果
|
||||
type MintCostEstimate struct {
|
||||
CostCrystal int64 // 本次铸造消耗水晶
|
||||
CurrentBalance int64 // 当前余额(铸造前)
|
||||
AfterBalance int64 // 铸造后余额
|
||||
MintCount int32 // 本次铸造是第几次
|
||||
NextTierHint string // 下一阶梯提示
|
||||
CostCrystal int64 // 本次铸造消耗水晶
|
||||
CurrentBalance int64 // 当前余额(铸造前)
|
||||
AfterBalance int64 // 铸造后余额
|
||||
MintCount int32 // 本次铸造是第几次
|
||||
NextTierCost int64 // 下一阶梯费用
|
||||
}
|
||||
|
||||
// UpdateMintCountAndBoost 更新铸爱次数和收益提升
|
||||
|
||||
@ -1,34 +1,43 @@
|
||||
<template>
|
||||
<view v-show="visible" class="modal-overlay" :class="{ 'modal-visible': visible }" @tap="handleCancel">
|
||||
<view class="modal-box" @tap.stop>
|
||||
<!-- 左上角关闭按钮 -->
|
||||
<view class="close-btn" @tap="handleCancel">
|
||||
<image class="close-icon" src="/static/starbookcontent/tuichu.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<!-- 右上角水晶数量 -->
|
||||
<view class="crystal-badge" v-if="currentBalance">
|
||||
<image class="topfans-icon" src="/static/icon/crystal.png" mode="aspectFit"></image>
|
||||
<view class="card-income-text-wrap">
|
||||
<text class="card-income-text">{{ currentBalance }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<view v-if="title" class="modal-title">
|
||||
<text>{{ title }}</text>
|
||||
</view>
|
||||
<view v-else class="modal-title">
|
||||
<!-- <view v-else class="modal-title">
|
||||
<text class="modal-title-text">铸造确认</text>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 铸造费用信息 -->
|
||||
<view v-if="costCrystal > 0 || currentBalance > 0" class="cost-info">
|
||||
<view v-if="costCrystal > 0" class="cost-info">
|
||||
<view class="cost-row">
|
||||
<text class="cost-label">本次消耗</text>
|
||||
<text class="cost-value cost-crystal">{{ costCrystal }} 水晶</text>
|
||||
</view>
|
||||
<view class="cost-row">
|
||||
<text class="cost-label">当前余额</text>
|
||||
<text class="cost-value">{{ currentBalance }} 水晶</text>
|
||||
</view>
|
||||
<view class="cost-row">
|
||||
<text class="cost-label">铸造后余额</text>
|
||||
<text class="cost-value balance-after">{{ balanceAfter }} 水晶</text>
|
||||
<view class="cost-num-wrap">
|
||||
<text class="cost-num">{{ costCrystal }}</text>
|
||||
<text class="cost-unit"> 水晶</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="mintCount > 0" class="cost-row">
|
||||
<text class="cost-label">铸造次数</text>
|
||||
<text class="cost-value">第 {{ mintCount }} 次</text>
|
||||
</view>
|
||||
<view v-if="nextTierHint" class="next-tier-hint">
|
||||
<text>{{ nextTierHint }}</text>
|
||||
<view class="cost-num-wrap">
|
||||
<text class="cost-unit">第 </text>
|
||||
<text class="cost-num">{{ mintCount }}</text>
|
||||
<text class="cost-unit"> 次</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -39,13 +48,17 @@
|
||||
|
||||
<!-- 按钮区 -->
|
||||
<view class="modal-actions">
|
||||
<view v-if="showCancel" class="btn btn-cancel" @tap="handleCancel">
|
||||
<text>{{ cancelText }}</text>
|
||||
</view>
|
||||
<view class="btn btn-confirm" @tap="handleConfirm">
|
||||
<text>{{ confirmText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 下一阶段消耗提示 -->
|
||||
<view v-if="nextTierCost > 0" class="next-tier-cost">
|
||||
<text class="cost-text">下一阶段消耗 </text>
|
||||
<text class="cost-num">{{ nextTierCost }}</text>
|
||||
<text class="cost-text"> 水晶</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@ -74,14 +87,6 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '确认'
|
||||
},
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: '取消'
|
||||
},
|
||||
showCancel: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 铸造费用信息
|
||||
costCrystal: {
|
||||
type: Number,
|
||||
@ -91,17 +96,13 @@ const props = defineProps({
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
balanceAfter: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
mintCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
nextTierHint: {
|
||||
type: String,
|
||||
default: ''
|
||||
nextTierCost: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
@ -119,7 +120,10 @@ function handleCancel() {
|
||||
<style scoped>
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
@ -138,7 +142,7 @@ function handleCancel() {
|
||||
.modal-box {
|
||||
width: 560rpx;
|
||||
/* background: #fff; */
|
||||
background-image: url('/static/starbookcontent/beijing.png');
|
||||
background-image: url('/static/icon/confirmbj.png');
|
||||
background-size: cover;
|
||||
background-position: center bottom;
|
||||
border-radius: 24rpx;
|
||||
@ -147,6 +151,63 @@ function handleCancel() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
left: 8rpx;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
z-index: 10;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
|
||||
.crystal-badge {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
/* background: rgba(0, 0, 0, 0.5); */
|
||||
/* border-radius: 20rpx; */
|
||||
/* padding: 8rpx 16rpx; */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.topfans-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin-right: -16rpx;
|
||||
left: 20rpx;
|
||||
/* top: 8rpx */
|
||||
transform: rotate(-15deg);
|
||||
}
|
||||
|
||||
.card-income-text-wrap {
|
||||
width: 64rpx;
|
||||
height: 32rpx;
|
||||
background-image: url('@/static/square/shuijingzhanshikuang.png');
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 16rpx 0 32rpx;
|
||||
}
|
||||
|
||||
.card-income-text {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
@ -157,8 +218,9 @@ function handleCancel() {
|
||||
}
|
||||
|
||||
.cost-info {
|
||||
width: 100%;
|
||||
margin-bottom: 32rpx;
|
||||
width: 480rpx;
|
||||
/* margin-bottom: 32rpx; */
|
||||
padding: 80rpx 0 32rpx;
|
||||
}
|
||||
|
||||
.cost-row {
|
||||
@ -166,50 +228,55 @@ function handleCancel() {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12rpx 0;
|
||||
/* border-bottom: 1rpx solid rgba(0, 0, 0, 0.05); */
|
||||
}
|
||||
|
||||
.cost-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.cost-label {
|
||||
background-image: url('@/static/rank/activity-support-icon/beijingkuang.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
padding: 16rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.cost-value {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.cost-crystal {
|
||||
color: #fff;
|
||||
.cost-num {
|
||||
font-size: 28rpx;
|
||||
color: #ff9500;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
|
||||
}
|
||||
|
||||
.balance-after {
|
||||
.cost-num-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
}
|
||||
|
||||
.cost-unit {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.next-tier-hint {
|
||||
.next-tier-cost {
|
||||
margin-top: 16rpx;
|
||||
padding: 12rpx 16rpx;
|
||||
background: rgba(255, 107, 157, 0.1);
|
||||
border-radius: 12rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.next-tier-hint text {
|
||||
.next-tier-cost .cost-text {
|
||||
font-size: 24rpx;
|
||||
color: #FF6B9D;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
@ -228,7 +295,7 @@ function handleCancel() {
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
width: 100%;
|
||||
width: 224rpx;
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
}
|
||||
@ -249,7 +316,13 @@ function handleCancel() {
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
background: linear-gradient(to right, #F08399, #B94E73);
|
||||
background: linear-gradient(to bottom right,
|
||||
#F0E4B1 0%,
|
||||
#F08399 50%,
|
||||
#B94E73 100%);
|
||||
box-shadow:
|
||||
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
||||
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
<!-- 左上角关闭按钮 -->
|
||||
<view class="close-btn" @click="handleClose">
|
||||
<text class="back-icon" :style="{ color: backIconColor }">←</text>
|
||||
<text class="nav-back" :style="{ color: backIconColor }">←</text>
|
||||
</view>
|
||||
|
||||
<!-- 功能按钮区域 -->
|
||||
@ -144,13 +144,18 @@ const handleAdd = () => {
|
||||
|
||||
/* 关闭按钮 */
|
||||
.close-btn {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-back-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.nav-back {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 浮动装饰物 */
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
<view class="generation-result">
|
||||
<!-- 背景图 -->
|
||||
<image class="background-image" src="/static/background/exhibitionSuccess.png" mode="aspectFill" />
|
||||
|
||||
|
||||
<!-- 星星装饰 -->
|
||||
<view class="stars-container">
|
||||
<view v-for="i in 20" :key="i" class="star" :style="getStarStyle(i)"></view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 顶部奖励提示 -->
|
||||
<!-- <view class="reward-tips">
|
||||
<view class="reward-item">
|
||||
@ -21,31 +21,17 @@
|
||||
<text class="reward-text">X 2</text>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
|
||||
<!-- 光栅卡:单张工作台预览(陀螺仪) -->
|
||||
<view
|
||||
class="lenticular-result-wrap"
|
||||
:class="{ 'cards-visible': isGiftOpened }"
|
||||
>
|
||||
<view class="lenticular-result-wrap" :class="{ 'cards-visible': isGiftOpened }">
|
||||
<view class="lenticular-result-card">
|
||||
<view class="card-wrapper craft-card-wrapper">
|
||||
<image
|
||||
class="card-frame"
|
||||
src="/static/square/gerenzhongxincangpinkuang.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<image class="card-frame" src="/static/square/gerenzhongxincangpinkuang.png" mode="aspectFit" />
|
||||
<view class="craft-lenticular-slot">
|
||||
<LenticularCard
|
||||
v-if="lenticularLayers.length > 0"
|
||||
class="craft-lenticular-card"
|
||||
:layers="lenticularLayers"
|
||||
:transforms="layerTransforms"
|
||||
:gyro-source="gyroSourceLabel"
|
||||
:skip-built-in-touch="true"
|
||||
tilt-hint-text="晃动查看"
|
||||
:shimmer-mid-opacity="0.16"
|
||||
@simulate="simulate"
|
||||
/>
|
||||
<LenticularCard v-if="lenticularLayers.length > 0" class="craft-lenticular-card"
|
||||
:layers="lenticularLayers" :transforms="layerTransforms" :gyro-source="gyroSourceLabel"
|
||||
:skip-built-in-touch="true" tilt-hint-text="晃动查看" :shimmer-mid-opacity="0.16"
|
||||
@simulate="simulate" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -53,46 +39,24 @@
|
||||
|
||||
<!-- 礼盒 -->
|
||||
<view class="gift-box" :class="{ 'gift-opened': isGiftOpened }">
|
||||
<image
|
||||
v-if="!isGiftOpened"
|
||||
class="gift-image"
|
||||
src="/static/nft/lihe.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<image
|
||||
v-else
|
||||
class="gift-image gift-image-opened"
|
||||
src="/static/nft/lihe_kaiqi.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<image v-if="!isGiftOpened" class="gift-image" src="/static/nft/lihe.png" mode="aspectFit" />
|
||||
<image v-else class="gift-image gift-image-opened" src="/static/nft/lihe_kaiqi.png" mode="aspectFit" />
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<view class="bottom-action" :class="{ 'bottom-action--row': isCraftDetailFlow }">
|
||||
<view
|
||||
v-if="isCraftDetailFlow"
|
||||
class="action-button action-button--secondary"
|
||||
@tap="handleRegenerate"
|
||||
>
|
||||
<view v-if="isCraftDetailFlow" class="action-button action-button--secondary" @tap="handleRegenerate">
|
||||
<text class="button-text">重新生成</text>
|
||||
</view>
|
||||
<view class="action-button" @tap="selectAsset">
|
||||
<view class="action-button" @tap="selectAsset">
|
||||
<text class="button-text">开始铸造</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 铸造确认弹窗 -->
|
||||
<ConfirmModal
|
||||
v-if="showConfirmModal"
|
||||
:visible="showConfirmModal"
|
||||
:cost-crystal="confirmCostInfo.costCrystal"
|
||||
:current-balance="confirmCostInfo.currentBalance"
|
||||
:balance-after="confirmCostInfo.balanceAfter"
|
||||
:mint-count="confirmCostInfo.mintCount"
|
||||
:next-tier-hint="confirmCostInfo.nextTierHint"
|
||||
@confirm="handleConfirmMint"
|
||||
@cancel="handleCancelMint"
|
||||
/>
|
||||
<ConfirmModal v-if="showConfirmModal" :visible="showConfirmModal" :cost-crystal="confirmCostInfo.costCrystal"
|
||||
:current-balance="confirmCostInfo.currentBalance" :mint-count="confirmCostInfo.mintCount"
|
||||
:next-tier-cost="confirmCostInfo.nextTierCost" @confirm="handleConfirmMint" @cancel="handleCancelMint" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -129,11 +93,10 @@ const resultMeta = ref('lenticular');
|
||||
// 确认铸造弹窗
|
||||
const showConfirmModal = ref(false);
|
||||
const confirmCostInfo = ref({
|
||||
costCrystal: 0,
|
||||
currentBalance: 0,
|
||||
balanceAfter: 0,
|
||||
mintCount: 0,
|
||||
nextTierHint: '',
|
||||
costCrystal: 0,
|
||||
currentBalance: 0,
|
||||
mintCount: 0,
|
||||
nextTierCost: 0,
|
||||
});
|
||||
|
||||
const lenticularLayers = ref([]);
|
||||
@ -181,7 +144,7 @@ const getStarStyle = (index) => {
|
||||
const top = Math.random() * 100;
|
||||
const size = Math.random() * 3 + 1;
|
||||
const delay = Math.random() * 3;
|
||||
|
||||
|
||||
return {
|
||||
left: `${left}%`,
|
||||
top: `${top}%`,
|
||||
@ -199,11 +162,11 @@ const base64ToBlob = (base64Data) => {
|
||||
const raw = atob(parts[1]);
|
||||
const rawLength = raw.length;
|
||||
const uInt8Array = new Uint8Array(rawLength);
|
||||
|
||||
|
||||
for (let i = 0; i < rawLength; i++) {
|
||||
uInt8Array[i] = raw.charCodeAt(i);
|
||||
}
|
||||
|
||||
|
||||
return new Blob([uInt8Array], { type: contentType });
|
||||
};
|
||||
|
||||
@ -211,35 +174,35 @@ const base64ToBlob = (base64Data) => {
|
||||
const uploadImageToOss = async (base64Image) => {
|
||||
console.log('[GenerationResult] uploadImageToOss 开始');
|
||||
isUploading.value = true;
|
||||
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '上传中...', mask: true });
|
||||
|
||||
|
||||
// 1. 获取OSS签名
|
||||
const signRes = await getOssSignatureApi('asset');
|
||||
console.log('[GenerationResult] 获取签名结果:', signRes);
|
||||
|
||||
|
||||
if (signRes.code !== 200) {
|
||||
throw new Error(signRes.message || '获取签名失败');
|
||||
}
|
||||
|
||||
|
||||
// 保存order_id
|
||||
currentOrderId.value = signRes.data.order_id || '';
|
||||
console.log('[GenerationResult] order_id:', currentOrderId.value);
|
||||
|
||||
|
||||
// 2. 生成文件名
|
||||
const timestamp = Date.now();
|
||||
const randomStr = Math.random().toString(36).substring(2, 8);
|
||||
const fileName = `ai_generated_${timestamp}_${randomStr}.png`;
|
||||
|
||||
|
||||
let imageUrl;
|
||||
|
||||
|
||||
// #ifdef H5
|
||||
// H5环境:使用FormData + Blob
|
||||
console.log('[GenerationResult] H5环境,使用Blob上传');
|
||||
const blob = base64ToBlob(base64Image);
|
||||
console.log('[GenerationResult] Blob创建成功,大小:', blob.size);
|
||||
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('key', signRes.data.dir + fileName);
|
||||
formData.append('policy', signRes.data.policy);
|
||||
@ -250,34 +213,34 @@ const uploadImageToOss = async (base64Image) => {
|
||||
formData.append('x-oss-signature', signRes.data.signature);
|
||||
formData.append('x-oss-signature-version', signRes.data.x_oss_signature_version);
|
||||
formData.append('file', blob, fileName);
|
||||
|
||||
|
||||
const response = await fetch(signRes.data.host, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
|
||||
console.log('[GenerationResult] OSS响应状态:', response.status);
|
||||
|
||||
|
||||
if (response.ok || response.status === 204) {
|
||||
imageUrl = `${signRes.data.host}/${signRes.data.dir}${fileName}`;
|
||||
} else {
|
||||
throw new Error(`上传失败,状态码: ${response.status}`);
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef H5
|
||||
// App/小程序环境:使用uni.uploadFile
|
||||
console.log('[GenerationResult] 非H5环境,使用uni.uploadFile');
|
||||
|
||||
|
||||
let tempFilePath; // 声明临时文件路径变量
|
||||
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
// App环境:直接使用base64上传(通过临时文件)
|
||||
console.log('[GenerationResult] App环境,使用base64临时文件');
|
||||
|
||||
|
||||
// 使用uni.saveFile保存base64为临时文件
|
||||
const base64Data = base64Image.replace(/^data:image\/\w+;base64,/, '');
|
||||
|
||||
|
||||
// 先转换为临时文件路径
|
||||
tempFilePath = await new Promise((resolve, reject) => {
|
||||
// 使用uni的base64ToTempFilePath(如果可用)
|
||||
@ -316,21 +279,21 @@ const uploadImageToOss = async (base64Image) => {
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||
// 小程序环境:使用FileSystemManager
|
||||
console.log('[GenerationResult] 小程序环境');
|
||||
const base64Data = base64Image.replace(/^data:image\/\w+;base64,/, '');
|
||||
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
tempFilePath = `${wx.env.USER_DATA_PATH}/${fileName}`;
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||
tempFilePath = `${uni.env.USER_DATA_PATH}/${fileName}`;
|
||||
// #endif
|
||||
|
||||
|
||||
console.log('[GenerationResult] 临时文件路径:', tempFilePath);
|
||||
|
||||
|
||||
const fs = uni.getFileSystemManager();
|
||||
await new Promise((resolve, reject) => {
|
||||
fs.writeFile({
|
||||
@ -348,9 +311,9 @@ const uploadImageToOss = async (base64Image) => {
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
|
||||
|
||||
console.log('[GenerationResult] 开始上传到OSS,文件路径:', tempFilePath);
|
||||
|
||||
|
||||
// 上传到OSS
|
||||
imageUrl = await new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
@ -370,7 +333,7 @@ const uploadImageToOss = async (base64Image) => {
|
||||
success: (uploadRes) => {
|
||||
console.log('[GenerationResult] OSS上传响应:', uploadRes.statusCode);
|
||||
console.log('[GenerationResult] OSS上传完整响应:', uploadRes);
|
||||
|
||||
|
||||
if (uploadRes.statusCode === 200 || uploadRes.statusCode === 204) {
|
||||
const url = `${signRes.data.host}/${signRes.data.dir}${fileName}`;
|
||||
console.log('[GenerationResult] 上传成功,URL:', url);
|
||||
@ -386,7 +349,7 @@ const uploadImageToOss = async (base64Image) => {
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
|
||||
|
||||
console.log('[GenerationResult] 上传成功,URL:', imageUrl);
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
@ -396,7 +359,7 @@ const uploadImageToOss = async (base64Image) => {
|
||||
});
|
||||
isUploading.value = false;
|
||||
return imageUrl;
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('[GenerationResult] 上传失败:', error);
|
||||
uni.hideLoading();
|
||||
@ -416,7 +379,7 @@ const uploadToOssH5 = async (base64Image, fileName, ossData) => {
|
||||
try {
|
||||
// 将base64转换为Blob
|
||||
const blob = base64ToBlob(base64Image);
|
||||
|
||||
|
||||
// 构建FormData
|
||||
const formData = new FormData();
|
||||
formData.append('key', ossData.dir + fileName);
|
||||
@ -428,32 +391,32 @@ const uploadToOssH5 = async (base64Image, fileName, ossData) => {
|
||||
formData.append('x-oss-signature', ossData.signature);
|
||||
formData.append('x-oss-signature-version', ossData.x_oss_signature_version);
|
||||
formData.append('file', blob, fileName);
|
||||
|
||||
|
||||
// 使用fetch上传
|
||||
fetch(resolveH5OssPostUrl(ossData.host), {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
const imageUrl = `${ossData.host}/${ossData.dir}${fileName}`;
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
const imageUrl = `${ossData.host}/${ossData.dir}${fileName}`;
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '上传成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
isUploading.value = false;
|
||||
resolve(imageUrl); // 只返回URL
|
||||
} else {
|
||||
throw new Error(`上传失败,状态码: ${response.status}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '上传成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
isUploading.value = false;
|
||||
resolve(imageUrl); // 只返回URL
|
||||
} else {
|
||||
throw new Error(`上传失败,状态码: ${response.status}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
uni.hideLoading();
|
||||
isUploading.value = false;
|
||||
reject(error);
|
||||
});
|
||||
reject(error);
|
||||
});
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
isUploading.value = false;
|
||||
@ -466,20 +429,20 @@ const uploadToOssH5 = async (base64Image, fileName, ossData) => {
|
||||
const uploadToOssNative = async (base64Image, fileName, ossData) => {
|
||||
console.log('[GenerationResult] uploadToOssNative 开始');
|
||||
console.log('[GenerationResult] fileName:', fileName);
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// 去掉base64前缀
|
||||
const base64Data = base64Image.replace(/^data:image\/\w+;base64,/, '');
|
||||
console.log('[GenerationResult] base64数据长度:', base64Data.length);
|
||||
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序环境
|
||||
console.log('[GenerationResult] 使用微信小程序环境');
|
||||
const fs = uni.getFileSystemManager();
|
||||
const tempFilePath = `${wx.env.USER_DATA_PATH}/${fileName}`;
|
||||
console.log('[GenerationResult] 临时文件路径:', tempFilePath);
|
||||
|
||||
|
||||
fs.writeFile({
|
||||
filePath: tempFilePath,
|
||||
data: base64Data,
|
||||
@ -496,19 +459,19 @@ const uploadToOssNative = async (base64Image, fileName, ossData) => {
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
// App环境
|
||||
console.log('[GenerationResult] 使用App环境');
|
||||
const fs = plus.io.getFileSystemManager ? uni.getFileSystemManager() : null;
|
||||
console.log('[GenerationResult] FileSystemManager:', fs ? '可用' : '不可用');
|
||||
|
||||
|
||||
if (!fs) {
|
||||
// 使用plus.io API
|
||||
console.log('[GenerationResult] 使用plus.io API');
|
||||
const tempFilePath = `_doc/${fileName}`;
|
||||
console.log('[GenerationResult] 临时文件路径:', tempFilePath);
|
||||
|
||||
|
||||
plus.io.resolveLocalFileSystemURL('_doc', (entry) => {
|
||||
console.log('[GenerationResult] 获取文件系统成功');
|
||||
entry.getFile(fileName, { create: true }, (fileEntry) => {
|
||||
@ -554,7 +517,7 @@ const uploadToOssNative = async (base64Image, fileName, ossData) => {
|
||||
console.log('[GenerationResult] 使用FileSystemManager API');
|
||||
const tempFilePath = `${plus.io.getStorageRootPath()}${fileName}`;
|
||||
console.log('[GenerationResult] 临时文件路径:', tempFilePath);
|
||||
|
||||
|
||||
fs.writeFile({
|
||||
filePath: tempFilePath,
|
||||
data: base64Data,
|
||||
@ -572,7 +535,7 @@ const uploadToOssNative = async (base64Image, fileName, ossData) => {
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('[GenerationResult] uploadToOssNative异常:', error);
|
||||
uni.hideLoading();
|
||||
@ -587,7 +550,7 @@ const uploadFileToOss = (tempFilePath, fileName, ossData, resolve, reject, fs) =
|
||||
console.log('[GenerationResult] uploadFileToOss 开始');
|
||||
console.log('[GenerationResult] tempFilePath:', tempFilePath);
|
||||
console.log('[GenerationResult] OSS host:', ossData.host);
|
||||
|
||||
|
||||
uni.uploadFile({
|
||||
url: ossData.host,
|
||||
filePath: tempFilePath,
|
||||
@ -605,11 +568,11 @@ const uploadFileToOss = (tempFilePath, fileName, ossData, resolve, reject, fs) =
|
||||
success: (uploadRes) => {
|
||||
console.log('[GenerationResult] OSS上传响应:', uploadRes);
|
||||
console.log('[GenerationResult] 状态码:', uploadRes.statusCode);
|
||||
|
||||
|
||||
if (uploadRes.statusCode === 200 || uploadRes.statusCode === 204) {
|
||||
const imageUrl = `${ossData.host}/${ossData.dir}${fileName}`;
|
||||
console.log('[GenerationResult] 上传成功,图片URL:', imageUrl);
|
||||
|
||||
|
||||
// 删除临时文件
|
||||
if (fs) {
|
||||
fs.unlink({
|
||||
@ -618,7 +581,7 @@ const uploadFileToOss = (tempFilePath, fileName, ossData, resolve, reject, fs) =
|
||||
fail: (err) => console.error('[GenerationResult] 删除临时文件失败:', err)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
resolve(imageUrl);
|
||||
} else {
|
||||
console.error('[GenerationResult] 上传失败,状态码:', uploadRes.statusCode);
|
||||
@ -673,18 +636,16 @@ const selectAsset = async () => {
|
||||
confirmCostInfo.value = {
|
||||
costCrystal: costRes.data.cost_crystal || 0,
|
||||
currentBalance: costRes.data.current_balance || 0,
|
||||
balanceAfter: costRes.data.balance_after || 0,
|
||||
mintCount: costRes.data.mint_count || 0,
|
||||
nextTierHint: costRes.data.next_tier_hint || '',
|
||||
nextTierCost: costRes.data.next_tier_cost || '',
|
||||
};
|
||||
|
||||
|
||||
} else {
|
||||
confirmCostInfo.value = {
|
||||
costCrystal: 100,
|
||||
currentBalance: 0,
|
||||
balanceAfter: 0,
|
||||
mintCount: 0,
|
||||
nextTierHint: '',
|
||||
nextTierCost: 0,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
@ -693,9 +654,8 @@ const selectAsset = async () => {
|
||||
confirmCostInfo.value = {
|
||||
costCrystal: 100,
|
||||
currentBalance: 0,
|
||||
balanceAfter: 0,
|
||||
mintCount: 0,
|
||||
nextTierHint: '',
|
||||
nextTierCost: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@ -775,7 +735,9 @@ onMounted(() => {
|
||||
const imagesData = uni.getStorageSync(GENERATED_IMAGES_KEY);
|
||||
if (!imagesData) {
|
||||
uni.showToast({ title: '未找到生成的图片', icon: 'none' });
|
||||
setTimeout(() => uni.navigateBack(), 1500);
|
||||
setTimeout(() => uni.navigateTo({
|
||||
url: '/pages/castlove/lenticular/lenticular-create'
|
||||
}), 1500);
|
||||
return;
|
||||
}
|
||||
const parsed = JSON.parse(imagesData);
|
||||
@ -796,7 +758,9 @@ onMounted(() => {
|
||||
} catch (e) {
|
||||
console.error('[GenerationResult] 读取图片数据失败:', e);
|
||||
uni.showToast({ title: '数据错误', icon: 'none' });
|
||||
setTimeout(() => uni.navigateBack(), 1500);
|
||||
setTimeout(() => uni.navigateTo({
|
||||
url: '/pages/castlove/lenticular/lenticular-create'
|
||||
}), 1500);
|
||||
}
|
||||
});
|
||||
|
||||
@ -817,7 +781,7 @@ onUnmounted(() => {
|
||||
|
||||
<style scoped>
|
||||
.generation-result {
|
||||
position: relative ;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
@ -852,10 +816,13 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
@keyframes starTwinkle {
|
||||
0%, 100% {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.3;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1.2);
|
||||
@ -893,7 +860,7 @@ onUnmounted(() => {
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
font-weight: 600;
|
||||
text-shadow:
|
||||
text-shadow:
|
||||
0 2rpx 8rpx rgba(0, 0, 0, 0.6),
|
||||
0 0 20rpx rgba(255, 107, 157, 0.5);
|
||||
white-space: nowrap;
|
||||
@ -937,6 +904,7 @@ onUnmounted(() => {
|
||||
transform: scale(0) translateY(100rpx);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
@ -968,9 +936,12 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
@keyframes cardFloat {
|
||||
0%, 100% {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0) rotate(var(--rotate, 0deg));
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(-20rpx) rotate(var(--rotate, 0deg));
|
||||
}
|
||||
@ -1018,10 +989,10 @@ onUnmounted(() => {
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.5) 50%,
|
||||
transparent 100%);
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.5) 50%,
|
||||
transparent 100%);
|
||||
animation: shine 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@ -1029,7 +1000,9 @@ onUnmounted(() => {
|
||||
0% {
|
||||
left: -100%;
|
||||
}
|
||||
50%, 100% {
|
||||
|
||||
50%,
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
@ -1097,7 +1070,7 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow:
|
||||
box-shadow:
|
||||
0 0 30rpx rgba(0, 212, 255, 0.8),
|
||||
0 8rpx 30rpx rgba(0, 0, 0, 0.4);
|
||||
animation: checkPop 0.3s ease-out;
|
||||
@ -1109,9 +1082,11 @@ onUnmounted(() => {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.2);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
@ -1147,9 +1122,12 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
@keyframes giftFloat {
|
||||
0%, 100% {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(-50%) translateY(-20rpx);
|
||||
}
|
||||
@ -1171,9 +1149,11 @@ onUnmounted(() => {
|
||||
transform: scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
|
||||
@ -20,11 +20,8 @@
|
||||
</view>
|
||||
|
||||
<!-- 镭射批量导出(离屏) -->
|
||||
<canvas
|
||||
canvas-id="laserBatchCanvas"
|
||||
class="laser-batch-canvas"
|
||||
:style="{ width: laserCanvasW + 'px', height: laserCanvasH + 'px' }"
|
||||
/>
|
||||
<canvas canvas-id="laserBatchCanvas" class="laser-batch-canvas"
|
||||
:style="{ width: laserCanvasW + 'px', height: laserCanvasH + 'px' }" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -99,7 +96,9 @@ const revertProgress = () => {
|
||||
clearInterval(revertInterval);
|
||||
// 回退完成后返回上一页
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
uni.navigateTo({
|
||||
url: '/pages/castlove/lenticular/lenticular-create'
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
}, 100);
|
||||
@ -206,7 +205,9 @@ onMounted(() => {
|
||||
const requestDataStr = uni.getStorageSync(GENERATION_REQUEST_KEY);
|
||||
if (!requestDataStr) {
|
||||
uni.showToast({ title: '数据错误', icon: 'none' });
|
||||
setTimeout(() => uni.navigateBack(), 1500);
|
||||
setTimeout(() => uni.navigateTo({
|
||||
url: '/pages/castlove/lenticular/lenticular-create'
|
||||
}), 1500);
|
||||
return;
|
||||
}
|
||||
generationData = JSON.parse(requestDataStr);
|
||||
@ -225,7 +226,9 @@ onMounted(() => {
|
||||
} catch (e) {
|
||||
console.error('[GenerationLoading] mount', e);
|
||||
uni.showToast({ title: '数据错误', icon: 'none' });
|
||||
setTimeout(() => uni.navigateBack(), 1500);
|
||||
setTimeout(() => uni.navigateTo({
|
||||
url: '/pages/castlove/lenticular/lenticular-create'
|
||||
}), 1500);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@ -268,10 +271,12 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(-50%) translateY(0) rotate(0deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(-50%) translateY(-20rpx) rotate(2deg);
|
||||
}
|
||||
@ -336,10 +341,12 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
@ -445,6 +445,7 @@ const handleBack = () => {
|
||||
.back-icon {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
|
||||
@ -214,6 +214,7 @@ const handleUserInfoUpdate = () => {
|
||||
const handleBalanceUpdate = (data) => {
|
||||
if (userInfo.value) {
|
||||
userInfo.value = { ...userInfo.value, crystal_balance: data.crystal_balance };
|
||||
exhibitionRevenue.value = data.crystal_balance || 0;
|
||||
} else {
|
||||
loadUserInfo();
|
||||
}
|
||||
|
||||
@ -326,6 +326,7 @@ onUnmounted(() => {
|
||||
.back-icon {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
|
||||
@ -361,6 +361,7 @@ onUnmounted(() => {
|
||||
.nav-back-icon {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
|
||||
@ -1019,6 +1019,7 @@ onShow(() => {
|
||||
.nav-back-icon {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
|
||||
@ -55,16 +55,9 @@
|
||||
</view>
|
||||
|
||||
<!-- 通用确认弹窗 -->
|
||||
<ConfirmModal
|
||||
:visible="confirmModal.visible"
|
||||
:title="confirmModal.title"
|
||||
:content="confirmModal.content"
|
||||
:confirmText="confirmModal.confirmText"
|
||||
:cancelText="confirmModal.cancelText"
|
||||
:showCancel="confirmModal.showCancel"
|
||||
@confirm="onConfirmModal"
|
||||
@cancel="onCancelModal"
|
||||
/>
|
||||
<ConfirmModal :visible="confirmModal.visible" :title="confirmModal.title" :content="confirmModal.content"
|
||||
:confirmText="confirmModal.confirmText" :cancelText="confirmModal.cancelText"
|
||||
:showCancel="confirmModal.showCancel" @confirm="onConfirmModal" @cancel="onCancelModal" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -406,8 +399,8 @@ const handleNext = async () => {
|
||||
|
||||
.back-icon {
|
||||
font-size: 48rpx;
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
|
||||
@ -271,8 +271,8 @@ const handleNext = async () => {
|
||||
|
||||
.back-icon {
|
||||
font-size: 48rpx;
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<image :src="userInfo?.avatar_url || '/static/icon/avatar-default.png'" class="user-avatar" mode="aspectFill" />
|
||||
<view class="user-balance">
|
||||
<image src="/static/icon/crystal.png" class="balance-icon" mode="aspectFit" />
|
||||
<text class="balance-text">{{ userInfo?.crystal_balance || 0 }}</text>
|
||||
<text class="balance-text">{{ crystalBalance || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -77,6 +77,7 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { purchaseItem } from '@/utils/activity-config'
|
||||
import { getEarningsSummaryApi } from '@/utils/api'
|
||||
import DiamondConfirmModal from './DiamondConfirmModal.vue'
|
||||
|
||||
const props = defineProps({
|
||||
@ -147,15 +148,31 @@ function handleModalCancel() {
|
||||
}
|
||||
|
||||
const userInfo = ref(null);
|
||||
const crystalBalance = ref(0)
|
||||
|
||||
function loadUserInfo() {
|
||||
async function loadUserInfo() {
|
||||
try {
|
||||
const userStr = uni.getStorageSync('user')
|
||||
if (userStr) {
|
||||
userInfo.value = typeof userStr === 'string' ? JSON.parse(userStr) : userStr
|
||||
}
|
||||
|
||||
// 从API获取真实余额
|
||||
const res = await getEarningsSummaryApi()
|
||||
if (res.code === 200 && res.data) {
|
||||
crystalBalance.value = res.data.crystal_balance || 0
|
||||
if (userInfo.value) {
|
||||
userInfo.value.crystal_balance = crystalBalance.value
|
||||
uni.setStorageSync('user', JSON.stringify(userInfo.value))
|
||||
}
|
||||
// 通知其他组件(如 Header)余额已更新
|
||||
uni.$emit('balanceUpdated', { crystal_balance: crystalBalance.value })
|
||||
} else {
|
||||
crystalBalance.value = userInfo.value?.crystal_balance || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户信息失败:', error)
|
||||
crystalBalance.value = userInfo.value?.crystal_balance || 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,6 +200,11 @@ onMounted(() => {
|
||||
// 恢复离线队列
|
||||
loadPendingActions()
|
||||
|
||||
// 默认选中第一个道具
|
||||
if (items.value && items.value.length > 0) {
|
||||
selectedItem.value = items.value[0].type
|
||||
}
|
||||
|
||||
// 监听网络状态
|
||||
networkListener = uni.onNetworkStatusChange((res) => {
|
||||
const wasOffline = !isOnline.value
|
||||
@ -333,33 +355,22 @@ async function handleConfirmContribute() {
|
||||
return
|
||||
}
|
||||
|
||||
// 调用贡献API多次
|
||||
let successCount = 0
|
||||
let lastRemainingBalance = null
|
||||
let lastErrorMessage = ''
|
||||
for (let i = 0; i < quantity.value; i++) {
|
||||
const res = await contributeItem(item, true, true)
|
||||
console.log(`第${i+1}次调用返回值:`, res)
|
||||
if (res && res.success !== false) {
|
||||
successCount++
|
||||
lastRemainingBalance = res.remainingBalance
|
||||
} else {
|
||||
lastErrorMessage = res?.message || '活动不在进行中,无法购买'
|
||||
}
|
||||
}
|
||||
// 调用贡献API一次,传入总数量
|
||||
const res = await contributeItem(item, true, true, quantity.value)
|
||||
console.log(`批量购买返回值:`, res)
|
||||
|
||||
// 更新本地余额(使用最后一次成功的余额)
|
||||
if (lastRemainingBalance !== null) {
|
||||
await updateLocalBalanceFromResult(lastRemainingBalance)
|
||||
// 更新本地余额
|
||||
if (res && res.remainingBalance !== null) {
|
||||
await updateLocalBalanceFromResult(res.remainingBalance)
|
||||
}
|
||||
|
||||
// 显示自定义结果提示
|
||||
if (successCount === quantity.value) {
|
||||
showResultToast('✅', `贡献成功\n+${item.cost * successCount} 贡献值已到账`)
|
||||
} else if (successCount > 0) {
|
||||
showResultToast('⚠️', `部分成功 ${successCount}/${quantity.value}`)
|
||||
if (res && res.success) {
|
||||
showResultToast('✅', `贡献成功\n+${item.cost * quantity.value} 贡献值已到账`)
|
||||
// 通知父组件更新进度
|
||||
emit('contribute', item.type, res.remainingBalance)
|
||||
} else {
|
||||
showResultToast('❌', lastErrorMessage || '贡献失败')
|
||||
showResultToast('❌', res?.message || '贡献失败')
|
||||
}
|
||||
} finally {
|
||||
processingItems.delete(item.type)
|
||||
@ -370,14 +381,11 @@ async function handleConfirmContribute() {
|
||||
// 验证用户余额(优先用缓存,避免重复读取存储)
|
||||
async function validateBalance(cost) {
|
||||
try {
|
||||
if (!userInfo.value) {
|
||||
const userStr = uni.getStorageSync('user')
|
||||
if (userStr) {
|
||||
userInfo.value = typeof userStr === 'string' ? JSON.parse(userStr) : { ...userStr }
|
||||
}
|
||||
// 确保余额已加载
|
||||
if (crystalBalance.value === 0 && userInfo.value?.crystal_balance) {
|
||||
crystalBalance.value = userInfo.value.crystal_balance
|
||||
}
|
||||
const balance = Number(userInfo.value?.crystal_balance) || 0
|
||||
return balance >= cost
|
||||
return crystalBalance.value >= cost
|
||||
} catch (error) {
|
||||
console.error('验证余额失败:', error)
|
||||
return false
|
||||
@ -385,11 +393,11 @@ async function validateBalance(cost) {
|
||||
}
|
||||
|
||||
// 贡献道具
|
||||
async function contributeItem(item, isRetry = false, silent = false) {
|
||||
async function contributeItem(item, isRetry = false, silent = false, qty = 1) {
|
||||
try {
|
||||
// 使用 activity-config.js 中的 purchaseItem 函数
|
||||
const result = await purchaseItem(props.activityId, item.type, 1)
|
||||
console.log(`[contributeItem] result:`, result, 'isRetry:', isRetry, 'silent:', silent)
|
||||
const result = await purchaseItem(props.activityId, item.type, qty)
|
||||
console.log(`[contributeItem] result:`, result, 'isRetry:', isRetry, 'silent:', silent, 'qty:', qty)
|
||||
|
||||
// 检查购买结果
|
||||
if (!result.success) {
|
||||
@ -478,6 +486,7 @@ function deductLocalBalance(cost) {
|
||||
// 保存回存储
|
||||
uni.setStorageSync('user', JSON.stringify(user))
|
||||
userInfo.value = user
|
||||
crystalBalance.value = user.crystal_balance
|
||||
uni.$emit('balanceUpdated', { crystal_balance: user.crystal_balance })
|
||||
}
|
||||
} catch (error) {
|
||||
@ -504,6 +513,7 @@ function refundLocalBalance(cost) {
|
||||
// 保存回存储
|
||||
uni.setStorageSync('user', JSON.stringify(user))
|
||||
userInfo.value = user
|
||||
crystalBalance.value = user.crystal_balance
|
||||
uni.$emit('balanceUpdated', { crystal_balance: user.crystal_balance })
|
||||
}
|
||||
} catch (error) {
|
||||
@ -529,6 +539,7 @@ async function updateLocalBalanceFromResult(newBalance) {
|
||||
// 保存回存储,确保是字符串格式
|
||||
uni.setStorageSync('user', JSON.stringify(user))
|
||||
userInfo.value = user
|
||||
crystalBalance.value = user.crystal_balance
|
||||
uni.$emit('balanceUpdated', { crystal_balance: user.crystal_balance })
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@ -574,6 +574,7 @@ const handleCloseClick = (e) => {
|
||||
.back-icon {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Tab 样式 */
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 2.3 MiB |
@ -681,6 +681,17 @@ export function purchaseActivityItemApi(activityId, itemType, quantity = 1) {
|
||||
})
|
||||
}
|
||||
|
||||
// 批量购买活动道具
|
||||
export function batchPurchaseActivityItemsApi(activityId, items) {
|
||||
return request({
|
||||
url: `/api/v1/activities/${activityId}/batch-purchase`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
items: items
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取活动最新贡献记录(实时轮询用)
|
||||
export function getActivityContributionsLatestApi(activityId, sinceTimestamp = 0, sinceId = 0, limit = 5) {
|
||||
return request({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user