diff --git a/backend/gateway/controller/activity_controller.go b/backend/gateway/controller/activity_controller.go
index 22fd5f2..16bf983 100644
--- a/backend/gateway/controller/activity_controller.go
+++ b/backend/gateway/controller/activity_controller.go
@@ -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))
diff --git a/backend/gateway/controller/asset_controller.go b/backend/gateway/controller/asset_controller.go
index ace8372..170f090 100644
--- a/backend/gateway/controller/asset_controller.go
+++ b/backend/gateway/controller/asset_controller.go
@@ -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)
}
diff --git a/backend/gateway/router/router.go b/backend/gateway/router/router.go
index 2d632e2..ba78a78 100644
--- a/backend/gateway/router/router.go
+++ b/backend/gateway/router/router.go
@@ -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) // 获取最新贡献记录
}
diff --git a/backend/pkg/proto/activity/activity.pb.go b/backend/pkg/proto/activity/activity.pb.go
index d64a75c..590c45e 100644
--- a/backend/pkg/proto/activity/activity.pb.go
+++ b/backend/pkg/proto/activity/activity.pb.go
@@ -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,
},
diff --git a/backend/pkg/proto/activity/activity.triple.go b/backend/pkg/proto/activity/activity.triple.go
index 4e6dcc4..54c4030 100644
--- a/backend/pkg/proto/activity/activity.triple.go
+++ b/backend/pkg/proto/activity/activity.triple.go
@@ -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,
diff --git a/backend/pkg/proto/asset/asset.pb.go b/backend/pkg/proto/asset/asset.pb.go
index eef9ae4..cb43c99 100644
--- a/backend/pkg/proto/asset/asset.pb.go
+++ b/backend/pkg/proto/asset/asset.pb.go
@@ -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" +
diff --git a/backend/pkg/proto/asset/asset.triple.go b/backend/pkg/proto/asset/asset.triple.go
index 249ea37..fcf6803 100644
--- a/backend/pkg/proto/asset/asset.triple.go
+++ b/backend/pkg/proto/asset/asset.triple.go
@@ -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
- },
- },
},
}
diff --git a/backend/proto/activity.proto b/backend/proto/activity.proto
index d7798a5..0a3a271 100644
--- a/backend/proto/activity.proto
+++ b/backend/proto/activity.proto
@@ -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) = {
diff --git a/backend/proto/asset.proto b/backend/proto/asset.proto
index 655213c..dac2372 100644
--- a/backend/proto/asset.proto
+++ b/backend/proto/asset.proto
@@ -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; // 下一阶梯费用
}
// ==================== 资产查询相关消息 ====================
diff --git a/backend/scripts/compile-proto.sh b/backend/scripts/compile-proto.sh
index 4797312..eb50999 100755
--- a/backend/scripts/compile-proto.sh
+++ b/backend/scripts/compile-proto.sh
@@ -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 ""
diff --git a/backend/services/activityService/provider/activity_provider.go b/backend/services/activityService/provider/activity_provider.go
index 2935ccb..f6a0f1d 100644
--- a/backend/services/activityService/provider/activity_provider.go
+++ b/backend/services/activityService/provider/activity_provider.go
@@ -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",
diff --git a/backend/services/activityService/service/activity_service.go b/backend/services/activityService/service/activity_service.go
index bd79bec..70c61fc 100644
--- a/backend/services/activityService/service/activity_service.go
+++ b/backend/services/activityService/service/activity_service.go
@@ -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",
diff --git a/backend/services/assetService/provider/asset_provider.go b/backend/services/assetService/provider/asset_provider.go
index c2d5e1b..35e623a 100644
--- a/backend/services/assetService/provider/asset_provider.go
+++ b/backend/services/assetService/provider/asset_provider.go
@@ -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
}
diff --git a/backend/services/assetService/service/mint_service.go b/backend/services/assetService/service/mint_service.go
index f2f8dac..377cc8d 100644
--- a/backend/services/assetService/service/mint_service.go
+++ b/backend/services/assetService/service/mint_service.go
@@ -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 更新铸爱次数和收益提升
diff --git a/frontend/components/ConfirmModal.vue b/frontend/components/ConfirmModal.vue
index 70c4947..1e16e5e 100644
--- a/frontend/components/ConfirmModal.vue
+++ b/frontend/components/ConfirmModal.vue
@@ -1,34 +1,43 @@
+
+
+
+
+
+
+
+
+
+ {{ currentBalance }}
+
+
+
{{ title }}
-
+
-
+
本次消耗
- {{ costCrystal }} 水晶
-
-
- 当前余额
- {{ currentBalance }} 水晶
-
-
- 铸造后余额
- {{ balanceAfter }} 水晶
+
+ {{ costCrystal }}
+ 水晶
+
铸造次数
- 第 {{ mintCount }} 次
-
-
- {{ nextTierHint }}
+
+ 第
+ {{ mintCount }}
+ 次
+
@@ -39,13 +48,17 @@
-
- {{ cancelText }}
-
{{ confirmText }}
+
+
+
+ 下一阶段消耗
+ {{ nextTierCost }}
+ 水晶
+
@@ -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() {
diff --git a/frontend/pages/ai-dazi/index.vue b/frontend/pages/ai-dazi/index.vue
index 880a218..2ba1a17 100644
--- a/frontend/pages/ai-dazi/index.vue
+++ b/frontend/pages/ai-dazi/index.vue
@@ -5,7 +5,7 @@
- ←
+ ←
@@ -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;
}
/* 浮动装饰物 */
diff --git a/frontend/pages/castlove/lenticular/lenticular-result.vue b/frontend/pages/castlove/lenticular/lenticular-result.vue
index 5f3c6fa..6411889 100644
--- a/frontend/pages/castlove/lenticular/lenticular-result.vue
+++ b/frontend/pages/castlove/lenticular/lenticular-result.vue
@@ -2,12 +2,12 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -53,46 +39,24 @@
-
-
+
+
-
+
-
+
重新生成
-
+
开始铸造
-
+
@@ -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(() => {