zoujiajian 1 жил өмнө
parent
commit
981c2691e3

+ 831 - 0
API_Documentation_v2.md

@@ -0,0 +1,831 @@
+# Claude Relay Service API 完整文档 (v2.0)
+
+## 概述
+Claude Relay Service 是一个高性能的 Claude API 转发服务,提供用户管理、API Key 管理、积分系统等功能。采用统一的AdminController架构,提供完整的管理功能。
+
+## 架构特点
+- **统一管理控制器**: 所有管理API现在使用统一的 `AdminController` 实例
+- **模块化设计**: 按功能分组的清晰架构(用户套餐、API Key、缓存、系统管理)
+- **响应格式优化**: 统一的成功/错误响应格式
+- **高性能转发**: 三级缓存机制,支持流式和非流式请求
+
+## 认证方式
+- **Claude API Routes**: 使用 FastAPIKeyAuth 中间件进行 API Key 认证
+  - Header: `Authorization: Bearer {api_key}`
+- **Management API Routes**: 使用 AdminAPIAuth 中间件进行管理员 API Key 认证
+  - Header: `Authorization: Bearer {admin_api_key}`
+- **Health Routes**: 无需认证
+
+## 通用响应格式
+所有管理API接口遵循统一的响应格式:
+
+**成功响应**:
+```json
+{
+  "success": true,
+  "data": {}
+}
+```
+
+**分页响应**:
+```json
+{
+  "success": true,
+  "data": [],
+  "pagination": {
+    "page": 1,
+    "limit": 20,
+    "total": 100
+  }
+}
+```
+
+**错误响应**:
+```json
+{
+  "success": false,
+  "message": "错误信息"
+}
+```
+
+---
+
+## 1. Claude API 标准路由组 `/v1`
+
+### 1.1 发送消息
+- **路径**: `POST /v1/messages`
+- **描述**: Claude API 核心转发接口,与官方 API 完全兼容
+- **认证**: 需要 API Key
+- **控制器**: `controller.RelayMessages`
+
+**请求参数**:
+```json
+{
+  "model": "claude-3-sonnet-20240229",
+  "max_tokens": 1024,
+  "messages": [
+    {
+      "role": "user",
+      "content": "Hello, Claude!"
+    }
+  ],
+  "stream": false,
+  "temperature": 0.7
+}
+```
+
+**响应格式** (非流式):
+```json
+{
+  "id": "msg_01234567890abcdef",
+  "type": "message",
+  "role": "assistant",
+  "content": [
+    {
+      "type": "text",
+      "text": "Hello! How can I help you today?"
+    }
+  ],
+  "model": "claude-3-sonnet-20240229",
+  "stop_reason": "end_turn",
+  "stop_sequence": null,
+  "usage": {
+    "input_tokens": 12,
+    "output_tokens": 25
+  }
+}
+```
+
+**错误响应**:
+```json
+{
+  "error": {
+    "type": "authentication_error|invalid_request_error|api_error",
+    "message": "错误描述信息"
+  }
+}
+```
+
+### 1.2 获取模型列表
+- **路径**: `GET /v1/models`
+- **描述**: 获取可用的 Claude 模型列表
+- **认证**: 需要 API Key
+- **控制器**: `controller.GetModels`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "object": "list",
+    "data": [
+      {
+        "id": "claude-3-sonnet-20240229",
+        "object": "model",
+        "created": 1677610602,
+        "owned_by": "anthropic"
+      },
+      {
+        "id": "claude-3-opus-20240229",
+        "object": "model",
+        "created": 1677610602,
+        "owned_by": "anthropic"
+      },
+      {
+        "id": "claude-3-haiku-20240307",
+        "object": "model",
+        "created": 1677610602,
+        "owned_by": "anthropic"
+      }
+    ]
+  }
+}
+```
+
+---
+
+## 2. 管理API路由组 `/api` (AdminController)
+
+所有管理API现在使用统一的AdminController,提供更好的代码组织和维护性。
+
+### 2.1 🔑 用户套餐管理
+
+#### 2.1.1 创建或更新用户套餐
+- **路径**: `PUT /api/users/{userId}/plan`
+- **描述**: 为指定用户创建或更新套餐信息
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.CreateOrUpdateUserPlan`
+
+**请求参数**:
+```json
+{
+  "plan_name": "高级套餐",
+  "credit_limit": 100000,
+  "credit_recovery": 1000,
+  "duration_days": 30
+}
+```
+
+**字段说明**:
+- `plan_name` (string, required): 套餐名称,1-100字符
+- `credit_limit` (int64, required): 积分上限,不能为负
+- `credit_recovery` (int64, optional): 每日积分恢复数量,不能为负
+- `duration_days` (int, required): 有效期天数,1-3650天
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "user_id": 123,
+    "plan_name": "高级套餐",
+    "credit_limit": 100000,
+    "used_credits": 0,
+    "available_credits": 100000,
+    "credit_recovery": 1000,
+    "start_date": "2024-01-01T00:00:00Z",
+    "end_date": "2024-01-31T00:00:00Z",
+    "status": "active",
+    "operation": "created"
+  }
+}
+```
+
+#### 2.1.2 查询用户套餐信息
+- **路径**: `GET /api/users/{userId}/plan`
+- **描述**: 获取指定用户的套餐详细信息
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetUserPlan`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "user_id": 123,
+    "plan_name": "高级套餐",
+    "credit_limit": 100000,
+    "used_credits": 15000,
+    "available_credits": 85000,
+    "credit_recovery": 1000,
+    "last_recharge_at": "2025-08-07T09:00:01Z",
+    "status": "active",
+    "start_date": "2024-01-01T00:00:00Z",
+    "end_date": "2024-01-31T00:00:00Z",
+    "recovery_enabled": true
+  }
+}
+```
+
+#### 2.1.3 调整用户积分
+- **路径**: `POST /api/users/{userId}/credits/adjust`
+- **描述**: 调整指定用户的积分余额
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.AdjustUserCredits`
+
+**请求参数**:
+```json
+{
+  "amount": 5000,
+  "description": "充值",
+  "type": "refund"
+}
+```
+
+**字段说明**:
+- `amount` (int64, required): 调整金额,正数为充值,负数为扣减
+- `description` (string, required): 调整描述,1-500字符
+- `type` (string, required): 调整类型,可选值:consume(消费), refund(退款), adjustment(调整)
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "user_id": 123,
+    "adjustment_amount": 5000,
+    "new_balance": 90000,
+    "type": "refund",
+    "description": "充值"
+  }
+}
+```
+
+### 2.2 🔐 API Key 管理
+
+#### 2.2.1 为用户创建 API Key
+- **路径**: `POST /api/users/{userId}/keys`
+- **描述**: 为指定用户生成新的 API Key
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.CreateAPIKey`
+
+**请求参数**:
+```json
+{
+  "name": "My API Key",
+  "expires_days": 30
+}
+```
+
+**字段说明**:
+- `name` (string, required): API Key名称,1-100字符
+- `expires_days` (int, optional): 过期天数,1-3650天,不提供则永不过期
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "id": 456,
+    "user_id": 123,
+    "name": "My API Key",
+    "key_value": "sk-ant-sid01-abc123...",
+    "prefix": "sk-ant-sid01",
+    "status": "active",
+    "expires_at": "2024-01-31T00:00:00Z",
+    "created_at": "2024-01-01T00:00:00Z"
+  }
+}
+```
+
+**重要**: `key_value` 字段只在创建时返回一次,请妥善保存
+
+#### 2.2.2 查询用户 API Keys
+- **路径**: `GET /api/users/{userId}/keys`
+- **描述**: 获取指定用户的所有 API Key 列表
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetUserAPIKeys`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": [
+    {
+      "id": 456,
+      "name": "My API Key",
+      "prefix": "sk-ant-sid01",
+      "status": "active",
+      "last_used_at": "2024-01-15T10:30:00Z",
+      "last_used_ip": "192.168.1.100",
+      "expires_at": "2024-01-31T00:00:00Z",
+      "created_at": "2024-01-01T00:00:00Z"
+    }
+  ]
+}
+```
+
+**注意**: 出于安全考虑,不返回完整的 `key_value`
+
+#### 2.2.3 更新 API Key 状态
+- **路径**: `PUT /api/keys/{keyId}/status`
+- **描述**: 更新指定 API Key 的状态(启用/禁用)
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.UpdateAPIKeyStatus`
+
+**请求参数**:
+```json
+{
+  "status": "active"
+}
+```
+
+**字段说明**:
+- `status` (string, required): 状态,可选值:active(活跃), inactive(禁用), revoked(已撤销)
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "key_id": 456,
+    "new_status": "active",
+    "updated_at": "2024-01-15T10:30:00Z"
+  }
+}
+```
+
+#### 2.2.4 删除 API Key
+- **路径**: `DELETE /api/keys/{keyId}`
+- **描述**: 删除指定的 API Key
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.DeleteAPIKey`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "key_id": 456,
+    "deleted": true,
+    "deleted_at": "2024-01-15T10:30:00Z"
+  }
+}
+```
+
+### 2.3 📊 积分历史和统计
+
+#### 2.3.1 用户积分明细
+- **路径**: `GET /api/users/{userId}/credits/history`
+- **描述**: 获取指定用户的积分使用历史记录
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetCreditsHistory`
+
+**查询参数**:
+- `page` (int, optional): 页码,默认1
+- `limit` (int, optional): 每页数量,默认20,最大100
+- `type` (string, optional): 积分类型过滤
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": [
+    {
+      "id": 789,
+      "type": "consume",
+      "amount": -150,
+      "balance_after": 84850,
+      "description": "API调用 - claude-3-sonnet-20240229",
+      "reference_type": "api_usage",
+      "reference_id": "101",
+      "created_at": "2024-01-15T10:30:00Z"
+    }
+  ],
+  "pagination": {
+    "page": 1,
+    "limit": 20,
+    "total": 50
+  }
+}
+```
+
+#### 2.3.2 用户使用统计
+- **路径**: `GET /api/users/{userId}/usage/stats`
+- **描述**: 获取指定用户的API使用统计信息
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetUsageStats`
+
+**查询参数**:
+- `days` (int, optional): 统计天数,默认30,最大365
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "total_requests": 150,
+    "total_tokens": 75000,
+    "total_credits_cost": 15000,
+    "average_request_time": 850,
+    "model_usage": {
+      "claude-3-sonnet-20240229": 100,
+      "claude-3-haiku-20240307": 50
+    },
+    "daily_stats": [
+      {
+        "date": "2024-01-15",
+        "requests": 25,
+        "tokens": 12500,
+        "credits_cost": 2500
+      }
+    ]
+  }
+}
+```
+
+### 2.4 📈 新增:仪表盘/余额/图表联动接口
+
+#### 2.4.1 仪表盘聚合
+- **路径**: `GET /api/users/{userId}/dashboard`
+- **描述**: 返回“当前订阅/余额卡片 + 今日汇总 + 今日请求列表”
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetUserDashboard`
+
+**响应示例**:
+```json
+{
+  "success": true,
+  "data": {
+    "subscription": {
+      "user_id": 123,
+      "plan_name": "基础月付",
+      "credit_limit": 5400,
+      "used_credits": 2160,
+      "available_credits": 3240,
+      "credit_recovery_per_hour": 100,
+      "status": "active",
+      "start_date": "2025-08-01T00:00:00Z",
+      "end_date": "2025-09-10T00:00:00Z",
+      "recovery_enabled": true,
+      "last_recharge_at": "2025-08-07T09:00:01Z"
+    },
+    "today_summary": {
+      "requests": 300,
+      "credits_consumed": 4040,
+      "credits_recharged": 800,
+      "since": "2025-08-07T00:00:00+08:00",
+      "until": "2025-08-07T16:30:00+08:00"
+    },
+    "today_requests": [
+      {
+        "id": 10001,
+        "time": "2025-08-07T16:00:00+08:00",
+        "model": "claude-sonnet-4-20250514",
+        "credits_cost": 10,
+        "status": "success",
+        "api_key_id": 555
+      }
+    ]
+  }
+}
+```
+
+**说明**:
+- 今日按自然日统计(`created_at >= CURDATE()`)
+- `last_recharge_at` 来自 `user_credits` 最近 `amount>0` 记录
+
+#### 2.4.2 余额卡片
+- **路径**: `GET /api/users/{userId}/balance`
+- **描述**: 单独返回余额卡片数据
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetUserBalance`
+
+**响应示例**:
+```json
+{
+  "success": true,
+  "data": {
+    "user_id": 123,
+    "plan_name": "基础月付",
+    "credit_limit": 5400,
+    "used_credits": 2160,
+    "available_credits": 3240,
+    "credit_recovery_per_hour": 100,
+    "status": "active",
+    "start_date": "2025-08-01T00:00:00Z",
+    "end_date": "2025-09-10T00:00:00Z",
+    "last_recharge_at": "2025-08-07T09:00:01Z"
+  }
+}
+```
+
+#### 2.4.3 图表 + 明细联动(每小时聚合)
+- **路径**: `GET /api/users/{userId}/credits/analytics`
+- **描述**: 在时间区间内返回每小时的“使用/补充/净变化”以及同一区间的积分明细(分页)
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetCreditsAnalytics`
+
+**查询参数**:
+- `start` (string, required): `YYYY-MM-DD HH:MM:SS`,例如 `2025-08-08 12:00:00`
+- `end` (string, required): `YYYY-MM-DD HH:MM:SS`,需大于 `start`
+- `tz` (string, optional): 时区,默认 `Asia/Shanghai`
+- `page` (int, optional): 明细页码,默认 1
+- `limit` (int, optional): 明细每页数量,默认 20,最大 100
+- `order` (string, optional): `asc|desc`,默认 `desc`
+- `type` (string, optional): 明细类型过滤,`consume|purchase|recovery|refund|reward|adjustment|all`,默认 `all`
+
+**成功返回**:
+```json
+{
+  "success": true,
+  "data": {
+    "meta": {
+      "start": "2025-08-08T12:00:00+08:00",
+      "end": "2025-08-09T11:00:00+08:00",
+      "interval": "hour",
+      "timezone": "Asia/Shanghai",
+      "bucket_count": 23
+    },
+    "summary": {
+      "consumed": 1720,
+      "recharged": 1820,
+      "net_change": 100
+    },
+    "series": [
+      {
+        "ts": "2025-08-08T12:00:00+08:00",
+        "consumed": 12,
+        "recharged": 0,
+        "net_change": -12
+      }
+    ],
+    "history": {
+      "page": 1,
+      "limit": 20,
+      "total": 73,
+      "records": [
+        {
+          "id": 98765,
+          "time": "2025-08-08T13:12:39+08:00",
+          "type": "consume",
+          "amount": -2,
+          "balance_after": 5398,
+          "description": "使用了2积分 - Model: claude-sonnet-4-20250514 ...",
+          "reference_type": "api_usage",
+          "reference_id": 555
+        }
+      ]
+    }
+  }
+}
+```
+
+**图表口径**:
+- 区间 `[start, end)`,按 `tz` 对齐到整点;每小时一个桶,空桶补 0
+- `consumed = SUM(-amount WHERE amount < 0)`
+- `recharged = SUM(amount WHERE amount > 0)`
+- `net_change = recharged - consumed`
+
+**明细口径**:
+- 过滤:`user_id = ? AND created_at >= start AND created_at < end`
+- `type != all` 时,对明细增加 `WHERE type = ?`(不影响图表)
+- 排序/分页:`order` + `page/limit`
+
+**错误码与边界**:
+- 400:缺少 `start/end`、时间格式错误、`end <= start`、跨度超过 90 天
+- 200 且 `series` 全 0:区间内无记录
+- 200 且 `history.total = 0`:区间无明细
+
+**性能与缓存**:
+- 图表聚合启用 Redis 缓存:`analytics:{userId}:{start_unix}:{end_unix}:{tz}`,TTL 60s
+- 明细不缓存(受分页与类型影响),依赖索引 `(user_id, created_at)`
+
+---
+
+### 2.4 🔄 批量查询接口
+
+#### 2.4.1 批量查询用户状态
+- **路径**: `POST /api/users/batch-status`
+- **描述**: 批量查询多个用户的状态信息,专为Java系统优化
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.BatchUserStatus`
+
+**请求参数**:
+```json
+{
+  "user_ids": [123, 456, 789]
+}
+```
+
+**字段说明**:
+- `user_ids` (array[int64], required): 用户ID列表,最多100个
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": [
+    {
+      "user_id": 123,
+      "plan_status": "active",
+      "credit_limit": 100000,
+      "used_credits": 15000,
+      "available_credits": 85000,
+      "api_keys_count": 2,
+      "last_activity": "2024-01-15T10:30:00Z"
+    }
+  ]
+}
+```
+
+### 2.5 🔥 缓存管理接口
+
+#### 2.5.1 用户缓存失效
+- **路径**: `POST /api/cache/invalidate/user/{userId}`
+- **描述**: 使指定用户的缓存失效,Java系统调用
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.InvalidateUserCache`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "user_id": 123,
+    "cleared": ["auth_cache", "credit_cache"],
+    "message": "用户缓存清理成功"
+  }
+}
+```
+
+#### 2.5.2 API Key缓存失效
+- **路径**: `POST /api/cache/invalidate/apikey`
+- **描述**: 使API Key相关缓存失效
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.InvalidateAPIKeyCache`
+
+**请求参数**:
+```json
+{
+  "api_key": "sk-ant-sid01-abc123..."
+}
+```
+
+**字段说明**:
+- `api_key` (string, required): 需要清理缓存的API Key,32-128字符
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "api_key_prefix": "sk-ant-sid01-abc1...",
+    "message": "API Key缓存清理成功"
+  }
+}
+```
+
+#### 2.5.3 缓存统计信息
+- **路径**: `GET /api/cache/stats`
+- **描述**: 获取系统缓存的统计信息
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetCacheStats`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "cache_type": "multi_level",
+    "l1_cache": "memory_auth_cache",
+    "l2_cache": "redis_credit_cache",
+    "features": [
+      "redis_pubsub_invalidation",
+      "auto_expiration",
+      "cache_penetration_protection"
+    ]
+  }
+}
+```
+
+### 2.6 🖥️ 系统管理接口
+
+#### 2.6.1 积分恢复状态
+- **路径**: `GET /api/system/recovery/status`
+- **描述**: 查询系统积分恢复的状态信息(内部调用)
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.GetSystemRecoveryStatus`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "pending_recovery_users": 10,
+    "last_recovery_at": "2024-01-15T00:00:00Z",
+    "next_recovery_at": "2024-01-16T00:00:00Z",
+    "system_status": "healthy"
+  }
+}
+```
+
+#### 2.6.2 手动触发积分恢复 🆕
+- **路径**: `POST /api/system/recovery/trigger`
+- **描述**: 手动触发积分恢复任务(管理员接口)
+- **认证**: 需要管理员 API Key
+- **控制器**: `AdminController.TriggerCreditRecovery`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "data": {
+    "message": "积分恢复执行成功",
+    "recovered_users": 5,
+    "trigger_by": "admin"
+  }
+}
+```
+
+**功能说明**:
+- 立即执行积分恢复任务,无需等待定时任务
+- 返回实际恢复的用户数量
+- 适用于紧急情况或测试场景
+
+---
+
+## 3. 健康检查路由
+
+### 3.1 健康检查
+- **路径**: `GET /health`
+- **描述**: 系统健康检查端点,用于监控服务状态
+- **认证**: 无需认证
+- **控制器**: `controller.Health`
+
+**响应格式**:
+```json
+{
+  "success": true,
+  "message": "服务正常运行",
+  "data": {
+    "status": "healthy",
+    "timestamp": "2024-01-15 10:30:00"
+  }
+}
+```
+
+---
+
+## 错误码说明
+
+### HTTP状态码
+- `200` - 请求成功
+- `400` - 请求参数错误
+- `401` - 认证失败
+- `403` - 权限不足
+- `404` - 资源不存在
+- `500` - 服务器内部错误
+
+### 业务错误类型
+- `authentication_error` - 认证错误
+- `invalid_request_error` - 请求参数错误
+- `api_error` - API调用错误
+- `insufficient_credits` - 积分不足
+
+---
+
+## 中间件说明
+
+1. **PanicRecover**: Panic恢复中间件,确保服务稳定性
+2. **CORS**: 跨域资源共享中间件
+3. **RequestLogger**: 请求日志记录中间件
+4. **ErrorHandler**: 统一错误处理中间件
+5. **FastAPIKeyAuth**: 高性能API Key认证(用于Claude API路由)
+6. **AdminAPIAuth**: 管理员API Key认证(用于管理API路由)
+
+---
+
+## 技术栈与特性
+
+### 核心技术
+- **框架**: GoFrame (gf/v2)
+- **路由**: ghttp.Server
+- **架构**: 分层架构(Controller-Service-DAO)
+- **缓存**: Redis + 内存双级缓存
+- **数据库**: MySQL/PostgreSQL
+
+### 主要特性
+- **高性能转发**: 三级缓存机制,毫秒级响应
+- **积分管理系统**: 自动积分恢复,精确计费
+- **统一管理架构**: AdminController统一管理所有管理功能
+- **安全认证**: 双重API Key认证机制
+- **实时监控**: 完整的使用统计和健康检查
+- **批量操作**: 优化的批量查询接口
+
+### 性能优化
+- **缓存策略**: 多级缓存避免数据库压力
+- **异步处理**: 计费和统计异步处理
+- **连接池**: 数据库连接池优化
+- **流式支持**: 支持Claude API流式响应
+
+---
+
+## 更新日志
+
+### v2.0 主要更新
+1. **统一控制器架构**: 采用AdminController统一管理所有管理API
+2. **新增接口**: 手动触发积分恢复功能 (`POST /api/system/recovery/trigger`)
+3. **响应格式优化**: 统一的分页和错误响应格式
+4. **代码结构重构**: 更清晰的模块化设计和注释
+5. **功能增强**: 积分恢复系统初始化优化

+ 1 - 0
netflix-dao/src/main/java/com/cyksj/model/request/ClaudeCodeApiKeysStatusReq.java

@@ -29,6 +29,7 @@ public class ClaudeCodeApiKeysStatusReq {
 
 	/**
 	 * api key状态
+	 * active(活跃), inactive(禁用), revoked(已撤销)
 	 */
 	@NotNull
 	private Boolean status;

+ 63 - 0
netflix-dao/src/main/java/com/cyksj/model/response/ClaudeCodePointsHistoryResp.java

@@ -0,0 +1,63 @@
+package com.cyksj.model.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.OffsetDateTime;
+import java.util.List;
+
+@Getter
+@Setter
+public class ClaudeCodePointsHistoryResp {
+	/**
+	 * 每页数量
+	 */
+	private Long limit;
+	/**
+	 * 当前页
+	 */
+	private Long page;
+
+	private List<Record> records;
+	/**
+	 * 总记录数
+	 */
+	private Long total;
+
+	@Getter
+	@Setter
+	public static class Record {
+		/**
+		 * 变动金额
+		 */
+		private Long amount;
+		/**
+		 * 变动后余额
+		 */
+		private Long balanceAfter;
+		/**
+		 * 创建时间
+		 */
+		private OffsetDateTime createdAt;
+		/**
+		 * 描述
+		 */
+		private String description;
+		/**
+		 * 记录ID
+		 */
+		private Long id;
+		/**
+		 * 关联ID
+		 */
+		private String referenceId;
+		/**
+		 * 关联类型
+		 */
+		private String referenceType;
+		/**
+		 * 类型
+		 */
+		private String type;
+	}
+}

+ 1 - 0
netflix-dao/src/main/java/com/cyksj/model/views/ClaudeCodeUserApiKeysView.java

@@ -52,6 +52,7 @@ public class ClaudeCodeUserApiKeysView {
 
 	/**
 	 * 状态
+	 * active(活跃), inactive(禁用), revoked(已撤销)
 	 */
 	private Boolean status;
 

+ 3 - 0
netflix-service/src/main/java/com/cyksj/service/claude/ClaudeCodeService.java

@@ -3,6 +3,7 @@ package com.cyksj.service.claude;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.request.ClaudeCodeApiKeysReq;
 import com.cyksj.model.request.ClaudeCodeApiKeysStatusReq;
+import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
 import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
 import com.cyksj.model.views.ClaudeCodeUserPackageView;
 
@@ -45,4 +46,6 @@ public interface ClaudeCodeService {
 	 * 用户套餐信息
 	 */
 	ClaudeCodeUserPackageView getUserPackage(long userId) throws Exception;
+
+	ClaudeCodePointsHistoryResp getUserPointsDetail(Long userId, String type, Integer page, Integer limit) throws Exception;
 }

+ 13 - 1
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -11,6 +11,7 @@ import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.request.ClaudeCodeApiKeysReq;
 import com.cyksj.model.request.ClaudeCodeApiKeysStatusReq;
+import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
 import com.cyksj.model.response.claudecode.ClaudeCodeResp;
 import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
 import com.cyksj.model.views.ClaudeCodeUserPackageView;
@@ -39,7 +40,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 
 	private final GroupsRelationMapper relationMapper;
 
-	private final static String CLAUDE_CODE_API_PREFIX = "http://104.238.220.246:18080/";
+	private final static String CLAUDE_CODE_API_PREFIX = "https://relay01.yhlxj.com/";
 
 	public static final String CLAUDE_CODE_API_ADMIN_KEY = "claudecodeyhlxjclaude";
 
@@ -105,6 +106,17 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		return null;
 	}
 
+	@Override
+	public ClaudeCodePointsHistoryResp getUserPointsDetail(Long userId, String type, Integer page, Integer limit) throws Exception {
+		String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/{userId}/credits/history?page=%s&limit=%s&type=%s", userId, page, limit, type);
+		String responseBody = executeClaudeCodeGetApi(url);
+		ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
+		if (claudeCodeResp.getSuccess()) {
+			return Jsons.parseObject(responseBody, ClaudeCodePointsHistoryResp.class);
+		}
+		return null;
+	}
+
 	public void createOrUpdateClaudeCodeUserPackage(Long userId, String planName, Integer codePoints, Integer codeCreditRecovery, Date expiryTime) throws Exception {
 		Map<String, Object> parmas = new HashMap<>();
 		parmas.put("plan_name", planName.replaceAll(";", ""));

+ 10 - 8
netflix-web/src/main/java/com/cyksj/web/controller/claude/ClaudeCodeController.java

@@ -4,6 +4,8 @@ import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.model.request.ClaudeCodeApiKeysReq;
 import com.cyksj.model.request.ClaudeCodeApiKeysStatusReq;
+import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
+import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
 import com.cyksj.model.views.ClaudeCodeUserPackageView;
 import com.cyksj.service.claude.ClaudeCodeService;
 import com.cyksj.web.util.StpUserUtil;
@@ -51,10 +53,10 @@ public class ClaudeCodeController {
 	 * 用户api keys列表
 	 */
 	@GetMapping("/get/apiKeys")
-	public Result<List<Object>> getUserApiKeys() {
+	public Result<List<ClaudeCodeUserApiKeysView>> getUserApiKeys() throws Exception {
 		long userId = StpUserUtil.getLoginIdAsLong();
-		claudeCodeService.getUserApiKeys(userId);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
+		List<ClaudeCodeUserApiKeysView> userApiKeys = claudeCodeService.getUserApiKeys(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userApiKeys);
 	}
 
 	/**
@@ -74,20 +76,20 @@ public class ClaudeCodeController {
 	 * 查询用户套餐信息
 	 */
 	@GetMapping("/get/user/package")
-	public Result<String> getUserPackage() {
+	public Result<ClaudeCodeUserPackageView> getUserPackage() throws Exception {
 		long userId = StpUserUtil.getLoginIdAsLong();
 		ClaudeCodeUserPackageView claudeCodeUserPackageView = claudeCodeService.getUserPackage(userId);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
+		return GatewayResponse.SUCCESS.newBuilder().toResult(claudeCodeUserPackageView);
 	}
 
 	/**
 	 * 用户积分明细
 	 */
 	@GetMapping("/get/user/points/detail")
-	public Result<String> getUserPointsDetail(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer limit, String type) {
+	public Result<ClaudeCodePointsHistoryResp> getUserPointsDetail(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer limit, String type) throws Exception {
 		long userId = StpUserUtil.getLoginIdAsLong();
-		claudeCodeService.getUserPointsDetail(userId, page, limit);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
+		ClaudeCodePointsHistoryResp resp = claudeCodeService.getUserPointsDetail(userId, type, page, limit);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(resp);
 	}
 
 	/**