2026-05-14 00:25:02 +08:00

189 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package activityapi
import (
"hyapp/services/gateway-service/internal/transport/http/httpkit"
"net/http"
"strings"
activityv1 "hyapp.local/api/proto/activity/v1"
"hyapp/services/gateway-service/internal/auth"
)
type taskSectionData struct {
Section string `json:"section"`
Items []taskItemData `json:"items"`
ServerTimeMS int64 `json:"server_time_ms"`
NextRefreshAtMS int64 `json:"next_refresh_at_ms"`
}
type taskItemData struct {
TaskID string `json:"task_id"`
TaskType string `json:"task_type"`
Category string `json:"category"`
MetricType string `json:"metric_type"`
Title string `json:"title"`
Description string `json:"description"`
TargetValue int64 `json:"target_value"`
TargetUnit string `json:"target_unit"`
ProgressValue int64 `json:"progress_value"`
RewardCoinAmount int64 `json:"reward_coin_amount"`
Status string `json:"status"`
Claimable bool `json:"claimable"`
TaskDay string `json:"task_day"`
ServerTimeMS int64 `json:"server_time_ms"`
NextRefreshAtMS int64 `json:"next_refresh_at_ms"`
SortOrder int32 `json:"sort_order"`
Version int64 `json:"version"`
}
type taskClaimData struct {
ClaimID string `json:"claim_id"`
TaskID string `json:"task_id"`
TaskType string `json:"task_type"`
TaskDay string `json:"task_day"`
RewardCoinAmount int64 `json:"reward_coin_amount"`
Status string `json:"status"`
WalletTransactionID string `json:"wallet_transaction_id"`
GrantedAtMS int64 `json:"granted_at_ms"`
Claimed bool `json:"claimed"`
}
type taskClaimRequestBody struct {
TaskID string `json:"task_id"`
TaskIDCamel string `json:"taskId"`
TaskType string `json:"task_type"`
TaskTypeCamel string `json:"taskType"`
TaskDay string `json:"task_day"`
TaskDayCamel string `json:"taskDay"`
CommandID string `json:"command_id"`
CommandIDCamel string `json:"commandId"`
}
func (b taskClaimRequestBody) normalizedTaskID() string {
if value := strings.TrimSpace(b.TaskID); value != "" {
return value
}
return strings.TrimSpace(b.TaskIDCamel)
}
func (b taskClaimRequestBody) normalizedTaskType() string {
if value := strings.TrimSpace(b.TaskType); value != "" {
return value
}
return strings.TrimSpace(b.TaskTypeCamel)
}
func (b taskClaimRequestBody) normalizedTaskDay() string {
if value := strings.TrimSpace(b.TaskDay); value != "" {
return value
}
return strings.TrimSpace(b.TaskDayCamel)
}
func (b taskClaimRequestBody) normalizedCommandID() string {
if value := strings.TrimSpace(b.CommandID); value != "" {
return value
}
return strings.TrimSpace(b.CommandIDCamel)
}
// listTaskTabs 返回当前用户任务页;进度由 activity-service 事实表决定。
func (h *Handler) listTaskTabs(writer http.ResponseWriter, request *http.Request) {
if h.taskClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
resp, err := h.taskClient.ListUserTasks(request.Context(), &activityv1.ListUserTasksRequest{
Meta: httpkit.ActivityMeta(request),
UserId: auth.UserIDFromContext(request.Context()),
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
sections := make([]taskSectionData, 0, len(resp.GetSections()))
for _, section := range resp.GetSections() {
items := make([]taskItemData, 0, len(section.GetItems()))
for _, item := range section.GetItems() {
items = append(items, taskItemFromProto(item))
}
sections = append(sections, taskSectionData{
Section: section.GetSection(),
Items: items,
ServerTimeMS: section.GetServerTimeMs(),
NextRefreshAtMS: section.GetNextRefreshAtMs(),
})
}
httpkit.WriteOK(writer, request, map[string]any{
"sections": sections,
"server_time_ms": resp.GetServerTimeMs(),
"next_refresh_at_ms": resp.GetNextRefreshAtMs(),
})
}
// claimTaskReward 只透传当前用户身份和幂等命令,完成校验及发奖在 activity-service 内完成。
func (h *Handler) claimTaskReward(writer http.ResponseWriter, request *http.Request) {
if h.taskClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
var body taskClaimRequestBody
if !httpkit.Decode(writer, request, &body) {
return
}
taskID := body.normalizedTaskID()
taskType := body.normalizedTaskType()
taskDay := body.normalizedTaskDay()
// command_id 是客户端动作的幂等锚点gateway 只裁剪空白,不替客户端补值。
commandID := strings.TrimSpace(body.normalizedCommandID())
if commandID == "" || taskID == "" || taskType == "" || taskDay == "" {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
resp, err := h.taskClient.ClaimTaskReward(request.Context(), &activityv1.ClaimTaskRewardRequest{
Meta: httpkit.ActivityMeta(request),
UserId: auth.UserIDFromContext(request.Context()),
TaskId: taskID,
TaskType: taskType,
TaskDay: taskDay,
CommandId: commandID,
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
httpkit.WriteOK(writer, request, taskClaimData{
ClaimID: resp.GetClaimId(),
TaskID: resp.GetTaskId(),
TaskType: resp.GetTaskType(),
TaskDay: resp.GetTaskDay(),
RewardCoinAmount: resp.GetRewardCoinAmount(),
Status: resp.GetStatus(),
WalletTransactionID: resp.GetWalletTransactionId(),
GrantedAtMS: resp.GetGrantedAtMs(),
Claimed: resp.GetClaimed(),
})
}
func taskItemFromProto(item *activityv1.TaskItem) taskItemData {
return taskItemData{
TaskID: item.GetTaskId(),
TaskType: item.GetTaskType(),
Category: item.GetCategory(),
MetricType: item.GetMetricType(),
Title: item.GetTitle(),
Description: item.GetDescription(),
TargetValue: item.GetTargetValue(),
TargetUnit: item.GetTargetUnit(),
ProgressValue: item.GetProgressValue(),
RewardCoinAmount: item.GetRewardCoinAmount(),
Status: item.GetStatus(),
Claimable: item.GetClaimable(),
TaskDay: item.GetTaskDay(),
ServerTimeMS: item.GetServerTimeMs(),
NextRefreshAtMS: item.GetNextRefreshAtMs(),
SortOrder: item.GetSortOrder(),
Version: item.GetVersion(),
}
}