fix invite rule id precision

This commit is contained in:
hy001 2026-04-27 20:56:49 +08:00
parent b7c0225dc3
commit 362069e2d4
2 changed files with 72 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import (
"chatapp3-golang/internal/integration"
"chatapp3-golang/internal/model"
"context"
"encoding/json"
"errors"
"strings"
"testing"
@ -526,3 +527,31 @@ func TestDispatchGoldReturnsGrantError(t *testing.T) {
t.Fatalf("reward log status = %s, want %s", log.Status, rewardLogStatusFailed)
}
}
func TestInviteRuleIDJSONUsesStringForSnowflakeIDs(t *testing.T) {
const ruleID int64 = 2048743937920790530
payload, err := json.Marshal(HomeResponse{
ValidCountTasks: []TaskView{{RuleID: ruleID, RuleType: ruleTypeInviterValidCount}},
InviterBindReward: RewardView{
RuleID: ruleID,
RuleType: ruleTypeInviterBind,
},
})
if err != nil {
t.Fatalf("json.Marshal() error = %v", err)
}
raw := string(payload)
if !strings.Contains(raw, `"ruleId":"2048743937920790530"`) {
t.Fatalf("ruleId was not encoded as a string: %s", raw)
}
}
func TestTaskClaimRequestAcceptsStringRuleID(t *testing.T) {
var req TaskClaimRequest
if err := json.Unmarshal([]byte(`{"ruleId":"2048743937920790530"}`), &req); err != nil {
t.Fatalf("json.Unmarshal() error = %v", err)
}
if req.RuleID != 2048743937920790530 {
t.Fatalf("RuleID = %d, want 2048743937920790530", req.RuleID)
}
}

View File

@ -1,12 +1,17 @@
package invite
import (
"bytes"
"chatapp3-golang/internal/common"
"chatapp3-golang/internal/config"
"chatapp3-golang/internal/integration"
"chatapp3-golang/internal/model"
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
@ -43,7 +48,7 @@ var NewAppError = common.NewAppError
// RewardView 是邀请活动奖励的通用展示结构。
type RewardView struct {
RuleID int64 `json:"ruleId,omitempty"`
RuleID int64 `json:"ruleId,string,omitempty"`
RuleType string `json:"ruleType,omitempty"`
Threshold int64 `json:"threshold,omitempty"`
GoldAmount int64 `json:"goldAmount"`
@ -53,7 +58,7 @@ type RewardView struct {
// TaskView 是邀请任务进度及领取状态的展示结构。
type TaskView struct {
RuleID int64 `json:"ruleId"`
RuleID int64 `json:"ruleId,string"`
RuleType string `json:"ruleType"`
Threshold int64 `json:"threshold"`
Progress int64 `json:"progress"`
@ -171,11 +176,46 @@ type TaskClaimRequest struct {
RuleID int64 `json:"ruleId"`
}
// UnmarshalJSON 允许 H5 按字符串提交 Snowflake 规则 ID避免 JS Number 精度丢失。
func (r *TaskClaimRequest) UnmarshalJSON(data []byte) error {
var payload struct {
RuleID any `json:"ruleId"`
}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
if err := decoder.Decode(&payload); err != nil {
return err
}
ruleID, err := parseClaimRuleID(payload.RuleID)
if err != nil {
return err
}
r.RuleID = ruleID
return nil
}
func parseClaimRuleID(value any) (int64, error) {
switch typed := value.(type) {
case nil:
return 0, nil
case json.Number:
return typed.Int64()
case string:
raw := strings.TrimSpace(typed)
if raw == "" {
return 0, nil
}
return strconv.ParseInt(raw, 10, 64)
default:
return 0, fmt.Errorf("ruleId must be string or number")
}
}
// TaskClaimResponse 是任务领取结果。
type TaskClaimResponse struct {
Claimed bool `json:"claimed"`
AlreadyClaimed bool `json:"alreadyClaimed"`
RuleID int64 `json:"ruleId"`
RuleID int64 `json:"ruleId,string"`
RuleType string `json:"ruleType"`
Progress int64 `json:"progress"`
Threshold int64 `json:"threshold"`