# 注册奖励 Flutter 对接

## 边界

注册奖励由服务端在三方注册成功后自动发放。Flutter 端不需要、也不能主动发放奖励，只需要在登录态下查询当前用户是否仍满足领取条件，用于展示入口、提示或埋点。

服务端判断条件：

- 用户没有成功领取过注册奖励。
- 注册奖励配置已开启且奖励配置有效。
- UTC 当天每日限制份数未用完；`daily_limit=0` 表示不限量。

## 查询接口

`GET /api/v1/activities/registration-reward/eligibility`

请求头：

```http
Authorization: Bearer <access_token>
X-App-Code: lalu
```

响应仍使用 gateway 统一 envelope：

```json
{
  "code": 0,
  "message": "ok",
  "request_id": "req_xxx",
  "data": {
    "can_receive": false,
    "reason": "already_claimed",
    "enabled": true,
    "reward_type": "coin",
    "coin_amount": 100,
    "resource_group_id": 0,
    "daily_limit": 1000,
    "daily_used": 328,
    "daily_remaining": 672,
    "reward_day": "2026-05-12",
    "server_time_ms": 1778563200000
  }
}
```

`reason` 取值：

- `eligible`: 当前用户符合条件。
- `already_claimed`: 用户已经领取或正在发放中。
- `daily_limit_reached`: UTC 当天份数已用完。
- `disabled`: 后台关闭注册奖励。
- `not_configured`: 后台还没有配置注册奖励。
- `invalid_config`: 后台配置不完整，例如金币数量为 0 或资源组为空。

## Dart DTO

```dart
class RegistrationRewardEligibility {
  const RegistrationRewardEligibility({
    required this.canReceive,
    required this.reason,
    required this.enabled,
    required this.rewardType,
    required this.coinAmount,
    required this.resourceGroupId,
    required this.dailyLimit,
    required this.dailyUsed,
    required this.dailyRemaining,
    required this.rewardDay,
    required this.serverTimeMs,
  });

  final bool canReceive;
  final String reason;
  final bool enabled;
  final String rewardType;
  final int coinAmount;
  final int resourceGroupId;
  final int dailyLimit;
  final int dailyUsed;
  final int dailyRemaining;
  final String rewardDay;
  final int serverTimeMs;

  factory RegistrationRewardEligibility.fromJson(Map<String, dynamic> json) {
    return RegistrationRewardEligibility(
      canReceive: json['can_receive'] == true,
      reason: json['reason'] as String? ?? '',
      enabled: json['enabled'] == true,
      rewardType: json['reward_type'] as String? ?? '',
      coinAmount: (json['coin_amount'] as num? ?? 0).toInt(),
      resourceGroupId: (json['resource_group_id'] as num? ?? 0).toInt(),
      dailyLimit: (json['daily_limit'] as num? ?? 0).toInt(),
      dailyUsed: (json['daily_used'] as num? ?? 0).toInt(),
      dailyRemaining: (json['daily_remaining'] as num? ?? 0).toInt(),
      rewardDay: json['reward_day'] as String? ?? '',
      serverTimeMs: (json['server_time_ms'] as num? ?? 0).toInt(),
    );
  }
}
```

## 调用示例

```dart
Future<RegistrationRewardEligibility> fetchRegistrationRewardEligibility(
  ApiClient api,
) async {
  final envelope = await api.get('/api/v1/activities/registration-reward/eligibility');
  if (envelope.code != 0) {
    throw ApiException(envelope.code, envelope.message);
  }
  return RegistrationRewardEligibility.fromJson(
    envelope.data as Map<String, dynamic>,
  );
}
```

## 客户端使用建议

新用户登录成功后可以调用一次该接口刷新展示状态；如果 `can_receive=false` 且 `reason=already_claimed`，说明服务端已经成功发放或发放中，不要重复提示用户手动领取。

`reward_day` 按 UTC 日期返回，不使用设备时区；客户端只做展示，不要用本地日期自行判断每日份数。
