diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..07e08fc
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,100 @@
+# 游戏平台后端服务
+
+基于 Spring Boot WebFlux + MyBatis + MySQL 的游戏平台后端服务。
+
+## 🚀 快速开始
+
+### 环境要求
+- JDK 17+
+- Maven 3.6+
+- MySQL 8.0+
+
+### 启动步骤
+1. 配置数据库连接(`application.yml`)
+2. 运行 `mvn spring-boot:run`
+3. 访问 http://localhost:8080
+
+## 📚 API 文档
+
+### Swagger UI
+启动应用后,访问以下地址查看交互式 API 文档:
+- **Swagger UI**: http://localhost:8080/swagger-ui.html
+- **OpenAPI JSON**: http://localhost:8080/api-docs
+- **OpenAPI YAML**: http://localhost:8080/api-docs.yaml
+
+### 接口分组
+- **管理员账户管理**: `/api/admin/accounts` 相关接口
+- **用户账户管理**: `/api/users` 相关接口
+
+### 使用说明
+详细的使用说明请参考:[Swagger使用说明.md](docs/Swagger使用说明.md)
+
+## 🔧 主要功能
+
+### 用户管理
+- 用户账户的增删改查
+- 支持管理员和代理两种用户类型
+- 账户状态管理(启用/禁用)
+- 密码重置功能
+
+### 认证授权
+- JWT Token 认证
+- 基于角色的权限控制
+- 安全的密码加密存储
+
+## 📁 项目结构
+
+```
+src/main/java/com/gameplatform/server/
+├── config/ # 配置类
+├── controller/ # 控制器
+│ ├── admin/ # 管理员接口
+│ └── ... # 其他接口
+├── service/ # 业务逻辑
+├── mapper/ # 数据访问层
+├── model/ # 数据模型
+│ ├── dto/ # 数据传输对象
+│ └── entity/ # 实体类
+└── security/ # 安全相关
+```
+
+## 🔐 认证说明
+
+### JWT Token
+- 访问令牌有效期:30分钟
+- 刷新令牌有效期:7天
+- 支持强制登出功能
+
+### 权限控制
+- 管理员接口需要管理员权限
+- 用户接口支持公开访问(仅限AGENT类型)
+
+## 📖 文档
+
+- [API文档](docs/API文档.md) - 详细的API接口说明
+- [Swagger使用说明](docs/Swagger使用说明.md) - Swagger文档使用指南
+
+## 🛠️ 开发
+
+### 编译
+```bash
+mvn compile
+```
+
+### 测试
+```bash
+mvn test
+```
+
+### 打包
+```bash
+mvn package
+```
+
+## 📝 更新日志
+
+### v1.0.0
+- 初始版本发布
+- 基础的用户管理功能
+- JWT认证系统
+- Swagger API文档集成
diff --git a/docs/Swagger使用说明.md b/docs/Swagger使用说明.md
new file mode 100644
index 0000000..035aa0a
--- /dev/null
+++ b/docs/Swagger使用说明.md
@@ -0,0 +1,171 @@
+# Swagger API 文档使用说明
+
+## 📖 概述
+
+本项目已集成 Swagger/OpenAPI 3.0,提供交互式的 API 文档界面,方便开发者和测试人员查看和测试 API 接口。
+
+## 🚀 访问地址
+
+启动应用后,可以通过以下地址访问 Swagger 文档:
+
+- **Swagger UI 界面**: http://localhost:8080/swagger-ui.html
+- **OpenAPI JSON**: http://localhost:8080/api-docs
+- **OpenAPI YAML**: http://localhost:8080/api-docs.yaml
+
+## 📋 功能特性
+
+### 1. 交互式文档
+- 在线查看所有 API 接口
+- 直接在浏览器中测试接口
+- 支持请求参数验证
+- 实时查看响应结果
+
+### 2. 接口分组
+- **管理员账户管理**: `/api/admin/accounts` 相关接口
+- **用户账户管理**: `/api/users` 相关接口
+
+### 3. 详细文档
+- 接口描述和用途说明
+- 请求参数详细说明
+- 响应数据结构
+- 错误码说明
+
+## 🔧 配置说明
+
+### 配置文件
+```yaml
+# application.yml
+springdoc:
+ api-docs:
+ path: /api-docs
+ swagger-ui:
+ path: /swagger-ui.html
+ tags-sorter: alpha
+ operations-sorter: alpha
+ doc-expansion: none
+ disable-swagger-default-url: true
+ display-request-duration: true
+ packages-to-scan: com.gameplatform.server.controller
+```
+
+### 配置参数说明
+- `tags-sorter: alpha`: 按字母顺序排序标签
+- `operations-sorter: alpha`: 按字母顺序排序操作
+- `doc-expansion: none`: 默认折叠所有接口
+- `display-request-duration: true`: 显示请求耗时
+
+## 📝 使用示例
+
+### 1. 查看接口列表
+1. 打开 http://localhost:8080/swagger-ui.html
+2. 选择对应的接口分组(如"管理员账户管理")
+3. 展开需要查看的接口
+
+### 2. 测试接口
+1. 点击接口右侧的"Try it out"按钮
+2. 填写请求参数
+3. 点击"Execute"执行请求
+4. 查看响应结果
+
+### 3. 复制接口信息
+每个接口都提供了以下信息:
+- **cURL 命令**: 可直接复制到终端执行
+- **请求 URL**: 完整的请求地址
+- **请求头**: 包含认证信息等
+- **请求体**: JSON 格式的请求数据
+- **响应示例**: 成功和失败的响应示例
+
+## 🔐 认证说明
+
+### Bearer Token 认证
+对于需要认证的接口,在 Swagger UI 中:
+1. 点击右上角的"Authorize"按钮
+2. 在 "Value" 字段中输入 JWT Token
+3. 格式:`Bearer your-jwt-token`
+4. 点击"Authorize"确认
+
+### 获取 Token
+1. 使用登录接口获取 JWT Token
+2. 复制响应中的 `accessToken` 字段
+3. 在 Swagger UI 中配置认证
+
+## 📊 接口文档结构
+
+### 管理员账户管理接口
+```
+POST /api/admin/accounts # 创建账户
+GET /api/admin/accounts # 获取账户列表
+GET /api/admin/accounts/{id} # 获取账户详情
+PATCH /api/admin/accounts/{id} # 更新账户
+POST /api/admin/accounts/{id}/enable # 启用账户
+POST /api/admin/accounts/{id}/disable # 禁用账户
+POST /api/admin/accounts/{id}/reset-password # 重置密码
+```
+
+### 用户账户管理接口
+```
+POST /api/users # 创建用户
+GET /api/users # 获取用户列表
+GET /api/users/{id} # 获取用户详情
+PUT /api/users/{id} # 更新用户
+POST /api/users/{id}/enable # 启用用户
+POST /api/users/{id}/disable # 禁用用户
+```
+
+## 🎯 最佳实践
+
+### 1. 开发阶段
+- 使用 Swagger UI 快速测试接口
+- 验证请求参数和响应格式
+- 调试认证和权限问题
+
+### 2. 测试阶段
+- 导出 OpenAPI 规范文件
+- 使用 Postman 等工具导入接口
+- 编写自动化测试用例
+
+### 3. 文档维护
+- 及时更新接口描述
+- 添加详细的参数说明
+- 提供完整的示例数据
+
+## 🔧 自定义配置
+
+### 添加新的接口分组
+```java
+@Tag(name = "新功能模块", description = "新功能模块的接口说明")
+@RestController
+@RequestMapping("/api/new-feature")
+public class NewFeatureController {
+ // 接口实现
+}
+```
+
+### 自定义接口描述
+```java
+@Operation(summary = "接口标题", description = "详细的接口描述")
+@Parameter(description = "参数说明")
+public ResponseEntity> methodName(@RequestParam String param) {
+ // 实现逻辑
+}
+```
+
+## 📚 相关资源
+
+- [OpenAPI 3.0 规范](https://swagger.io/specification/)
+- [SpringDoc 官方文档](https://springdoc.org/)
+- [Swagger UI 配置选项](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)
+
+## 🆘 常见问题
+
+### Q: 无法访问 Swagger UI
+A: 检查应用是否正常启动,确认端口 8080 未被占用
+
+### Q: 接口显示不完整
+A: 确认控制器类在 `com.gameplatform.server.controller` 包下
+
+### Q: 认证失败
+A: 检查 JWT Token 是否有效,格式是否正确
+
+### Q: 参数验证失败
+A: 查看接口文档中的参数要求,确保数据格式正确
diff --git a/docs/game.sql b/docs/game.sql
index 44ace88..73ba2e1 100644
--- a/docs/game.sql
+++ b/docs/game.sql
@@ -11,7 +11,7 @@
Target Server Version : 80043 (8.0.43)
File Encoding : 65001
- Date: 24/08/2025 17:24:44
+ Date: 24/08/2025 19:08:50
*/
SET NAMES utf8mb4;
@@ -22,21 +22,21 @@ SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
DROP TABLE IF EXISTS `agent_points_tx`;
CREATE TABLE `agent_points_tx` (
- `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
- `account_id` bigint UNSIGNED NOT NULL,
- `type` enum('ADD','DEDUCT') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `before_points` bigint UNSIGNED NOT NULL,
- `delta_points` bigint NOT NULL,
- `after_points` bigint UNSIGNED NOT NULL,
- `reason` enum('create_links','manual','refund_no_rollback','other') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'other',
- `ref_id` bigint UNSIGNED NULL DEFAULT NULL,
- `operator_id` bigint UNSIGNED NULL DEFAULT NULL,
- `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
- PRIMARY KEY (`id`) USING BTREE,
- INDEX `idx_apx_account_time`(`account_id` ASC, `created_at` ASC) USING BTREE,
- INDEX `fk_apx_operator`(`operator_id` ASC) USING BTREE,
- CONSTRAINT `fk_apx_account` FOREIGN KEY (`account_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
- CONSTRAINT `fk_apx_operator` FOREIGN KEY (`operator_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+ `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
+ `account_id` bigint UNSIGNED NOT NULL,
+ `type` enum('ADD','DEDUCT') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `before_points` bigint UNSIGNED NOT NULL,
+ `delta_points` bigint NOT NULL,
+ `after_points` bigint UNSIGNED NOT NULL,
+ `reason` enum('create_links','manual','refund_no_rollback','other') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'other',
+ `ref_id` bigint UNSIGNED NULL DEFAULT NULL,
+ `operator_id` bigint UNSIGNED NULL DEFAULT NULL,
+ `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_apx_account_time`(`account_id` ASC, `created_at` ASC) USING BTREE,
+ INDEX `fk_apx_operator`(`operator_id` ASC) USING BTREE,
+ CONSTRAINT `fk_apx_account` FOREIGN KEY (`account_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_apx_operator` FOREIGN KEY (`operator_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
@@ -44,14 +44,14 @@ CREATE TABLE `agent_points_tx` (
-- ----------------------------
DROP TABLE IF EXISTS `announcement`;
CREATE TABLE `announcement` (
- `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
- `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `enabled` tinyint(1) NOT NULL DEFAULT 1,
- `jump_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
- `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
- PRIMARY KEY (`id`) USING BTREE
+ `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
+ `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `enabled` tinyint(1) NOT NULL DEFAULT 1,
+ `jump_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+ `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
+ PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
@@ -59,22 +59,22 @@ CREATE TABLE `announcement` (
-- ----------------------------
DROP TABLE IF EXISTS `link_batch`;
CREATE TABLE `link_batch` (
- `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
- `agent_id` bigint UNSIGNED NOT NULL,
- `quantity` int UNSIGNED NOT NULL,
- `times` int UNSIGNED NOT NULL,
- `batch_size` int UNSIGNED NOT NULL,
- `deduct_points` bigint UNSIGNED NOT NULL,
- `operator_id` bigint UNSIGNED NULL DEFAULT NULL,
- `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
- PRIMARY KEY (`id`) USING BTREE,
- INDEX `idx_lb_agent_time`(`agent_id` ASC, `created_at` ASC) USING BTREE,
- INDEX `fk_lb_operator`(`operator_id` ASC) USING BTREE,
- CONSTRAINT `fk_lb_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
- CONSTRAINT `fk_lb_operator` FOREIGN KEY (`operator_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
- CONSTRAINT `chk_lb_batch_pos` CHECK (`batch_size` > 0),
- CONSTRAINT `chk_lb_quantity_pos` CHECK (`quantity` > 0),
- CONSTRAINT `chk_lb_times_pos` CHECK (`times` > 0)
+ `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
+ `agent_id` bigint UNSIGNED NOT NULL,
+ `quantity` int UNSIGNED NOT NULL,
+ `times` int UNSIGNED NOT NULL,
+ `batch_size` int UNSIGNED NOT NULL,
+ `deduct_points` bigint UNSIGNED NOT NULL,
+ `operator_id` bigint UNSIGNED NULL DEFAULT NULL,
+ `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_lb_agent_time`(`agent_id` ASC, `created_at` ASC) USING BTREE,
+ INDEX `fk_lb_operator`(`operator_id` ASC) USING BTREE,
+ CONSTRAINT `fk_lb_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_lb_operator` FOREIGN KEY (`operator_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `chk_lb_batch_pos` CHECK (`batch_size` > 0),
+ CONSTRAINT `chk_lb_quantity_pos` CHECK (`quantity` > 0),
+ CONSTRAINT `chk_lb_times_pos` CHECK (`times` > 0)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
@@ -82,29 +82,29 @@ CREATE TABLE `link_batch` (
-- ----------------------------
DROP TABLE IF EXISTS `link_task`;
CREATE TABLE `link_task` (
- `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
- `batch_id` bigint UNSIGNED NOT NULL,
- `agent_id` bigint UNSIGNED NOT NULL,
- `code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `token_hash` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `expire_at` datetime(3) NOT NULL,
- `status` enum('NEW','USING','LOGGED_IN','REFUNDED','EXPIRED') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NEW',
- `region` enum('Q','V') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `machine_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `login_at` datetime(3) NULL DEFAULT NULL,
- `refund_at` datetime(3) NULL DEFAULT NULL,
- `revoked_at` datetime(3) NULL DEFAULT NULL,
- `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
- `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
- PRIMARY KEY (`id`) USING BTREE,
- UNIQUE INDEX `uk_code_no`(`code_no` ASC) USING BTREE,
- UNIQUE INDEX `uk_token_hash`(`token_hash` ASC) USING BTREE,
- INDEX `idx_agent_status`(`agent_id` ASC, `status` ASC) USING BTREE,
- INDEX `idx_expire_at`(`expire_at` ASC) USING BTREE,
- INDEX `idx_created_at`(`created_at` ASC) USING BTREE,
- INDEX `fk_lt_batch`(`batch_id` ASC) USING BTREE,
- CONSTRAINT `fk_lt_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
- CONSTRAINT `fk_lt_batch` FOREIGN KEY (`batch_id`) REFERENCES `link_batch` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+ `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
+ `batch_id` bigint UNSIGNED NOT NULL,
+ `agent_id` bigint UNSIGNED NOT NULL,
+ `code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `token_hash` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `expire_at` datetime(3) NOT NULL,
+ `status` enum('NEW','USING','LOGGED_IN','REFUNDED','EXPIRED') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NEW',
+ `region` enum('Q','V') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+ `machine_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+ `login_at` datetime(3) NULL DEFAULT NULL,
+ `refund_at` datetime(3) NULL DEFAULT NULL,
+ `revoked_at` datetime(3) NULL DEFAULT NULL,
+ `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `uk_code_no`(`code_no` ASC) USING BTREE,
+ UNIQUE INDEX `uk_token_hash`(`token_hash` ASC) USING BTREE,
+ INDEX `idx_agent_status`(`agent_id` ASC, `status` ASC) USING BTREE,
+ INDEX `idx_expire_at`(`expire_at` ASC) USING BTREE,
+ INDEX `idx_created_at`(`created_at` ASC) USING BTREE,
+ INDEX `fk_lt_batch`(`batch_id` ASC) USING BTREE,
+ CONSTRAINT `fk_lt_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_lt_batch` FOREIGN KEY (`batch_id`) REFERENCES `link_batch` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
@@ -112,18 +112,18 @@ CREATE TABLE `link_task` (
-- ----------------------------
DROP TABLE IF EXISTS `operation_log`;
CREATE TABLE `operation_log` (
- `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
- `actor_type` enum('admin','agent','system','user') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `actor_id` bigint UNSIGNED NULL DEFAULT NULL,
- `code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `op` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `detail` json NULL,
- `client_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
- PRIMARY KEY (`id`) USING BTREE,
- INDEX `idx_log_code_time`(`code_no` ASC, `created_at` ASC) USING BTREE,
- INDEX `idx_log_time`(`created_at` ASC) USING BTREE
+ `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
+ `actor_type` enum('admin','agent','system','user') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `actor_id` bigint UNSIGNED NULL DEFAULT NULL,
+ `code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+ `op` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `detail` json NULL,
+ `client_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+ `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
+ `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `idx_log_code_time`(`code_no` ASC, `created_at` ASC) USING BTREE,
+ INDEX `idx_log_time`(`created_at` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
@@ -131,19 +131,17 @@ CREATE TABLE `operation_log` (
-- ----------------------------
DROP TABLE IF EXISTS `user_account`;
CREATE TABLE `user_account` (
- `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
- `user_type` enum('ADMIN','AGENT') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `display_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `password_hash` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `role` enum('SUPER','ADMIN') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
- `status` enum('ENABLED','DISABLED') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'ENABLED',
- `points_balance` bigint UNSIGNED NOT NULL DEFAULT 0,
- `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
- `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
- PRIMARY KEY (`id`) USING BTREE,
- UNIQUE INDEX `username`(`username` ASC) USING BTREE,
- CONSTRAINT `chk_points_nonneg` CHECK (`points_balance` >= 0)
-) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+ `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
+ `user_type` enum('ADMIN','AGENT') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `password_hash` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `status` enum('ENABLED','DISABLED') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'ENABLED',
+ `points_balance` bigint UNSIGNED NOT NULL DEFAULT 0,
+ `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE INDEX `username`(`username` ASC) USING BTREE,
+ CONSTRAINT `chk_points_nonneg` CHECK (`points_balance` >= 0)
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
diff --git a/pom.xml b/pom.xml
index 6fb87e2..cd1de69 100644
--- a/pom.xml
+++ b/pom.xml
@@ -85,6 +85,13 @@
true
+
+
+ org.springdoc
+ springdoc-openapi-starter-webflux-ui
+ 2.3.0
+
+
org.springframework.boot
spring-boot-starter-test
diff --git a/src/main/java/com/gameplatform/server/config/SwaggerConfig.java b/src/main/java/com/gameplatform/server/config/SwaggerConfig.java
new file mode 100644
index 0000000..1bd469a
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/config/SwaggerConfig.java
@@ -0,0 +1,39 @@
+package com.gameplatform.server.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import io.swagger.v3.oas.models.servers.Server;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .info(new Info()
+ .title("游戏平台 API 文档")
+ .description("游戏平台后端服务 API 接口文档")
+ .version("1.0.0")
+ .contact(new Contact()
+ .name("游戏平台开发团队")
+ .email("dev@gameplatform.com")
+ .url("https://gameplatform.com"))
+ .license(new License()
+ .name("MIT License")
+ .url("https://opensource.org/licenses/MIT")))
+ .servers(List.of(
+ new Server()
+ .url("http://localhost:8080")
+ .description("本地开发环境"),
+ new Server()
+ .url("https://api.gameplatform.com")
+ .description("生产环境")
+ ));
+ }
+}
diff --git a/src/main/java/com/gameplatform/server/controller/UserController.java b/src/main/java/com/gameplatform/server/controller/UserController.java
index b34100f..d4f81de 100644
--- a/src/main/java/com/gameplatform/server/controller/UserController.java
+++ b/src/main/java/com/gameplatform/server/controller/UserController.java
@@ -5,6 +5,9 @@ import com.gameplatform.server.model.dto.account.AccountResponse;
import com.gameplatform.server.model.dto.account.AccountUpdateRequest;
import com.gameplatform.server.model.dto.common.PageResult;
import com.gameplatform.server.service.account.AccountService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@@ -16,6 +19,7 @@ import reactor.core.publisher.Mono;
*/
@RestController
@RequestMapping("/api/users")
+@Tag(name = "用户账户管理", description = "用户账户的增删改查操作")
public class UserController {
private final AccountService accountService;
@@ -27,7 +31,8 @@ public class UserController {
* 根据ID获取用户账户信息
*/
@GetMapping("/{id}")
- public Mono getById(@PathVariable Long id) {
+ @Operation(summary = "获取用户详情", description = "根据用户ID获取用户详细信息")
+ public Mono getById(@Parameter(description = "用户ID") @PathVariable Long id) {
return accountService.get(id);
}
@@ -35,15 +40,15 @@ public class UserController {
* 分页查询用户列表
*/
@GetMapping
+ @Operation(summary = "获取用户列表", description = "分页获取用户列表,支持按用户类型、状态、关键词筛选")
public Mono> list(
- @RequestParam(value = "userType", required = false) String userType,
- @RequestParam(value = "status", required = false) String status,
- @RequestParam(value = "role", required = false) String role,
- @RequestParam(value = "keyword", required = false) String keyword,
- @RequestParam(value = "page", defaultValue = "1") Integer page,
- @RequestParam(value = "size", defaultValue = "20") Integer size
+ @Parameter(description = "用户类型:ADMIN 或 AGENT") @RequestParam(value = "userType", required = false) String userType,
+ @Parameter(description = "账户状态:ENABLED 或 DISABLED") @RequestParam(value = "status", required = false) String status,
+ @Parameter(description = "搜索关键词") @RequestParam(value = "keyword", required = false) String keyword,
+ @Parameter(description = "页码,默认1") @RequestParam(value = "page", defaultValue = "1") Integer page,
+ @Parameter(description = "每页大小,默认20") @RequestParam(value = "size", defaultValue = "20") Integer size
) {
- return accountService.list(userType, status, role, keyword, page, size);
+ return accountService.list(userType, status, keyword, page, size);
}
/**
@@ -51,6 +56,7 @@ public class UserController {
*/
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
+ @Operation(summary = "创建用户", description = "创建新的代理用户账户")
public Mono create(@Valid @RequestBody AccountCreateRequest request) {
return accountService.create(request);
}
@@ -59,7 +65,8 @@ public class UserController {
* 更新用户账户信息
*/
@PutMapping("/{id}")
- public Mono update(@PathVariable Long id, @Valid @RequestBody AccountUpdateRequest request) {
+ @Operation(summary = "更新用户", description = "更新用户账户信息")
+ public Mono update(@Parameter(description = "用户ID") @PathVariable Long id, @Valid @RequestBody AccountUpdateRequest request) {
return accountService.update(id, request);
}
@@ -68,7 +75,8 @@ public class UserController {
*/
@PostMapping("/{id}/enable")
@ResponseStatus(HttpStatus.NO_CONTENT)
- public Mono enable(@PathVariable Long id) {
+ @Operation(summary = "启用用户", description = "启用指定用户账户")
+ public Mono enable(@Parameter(description = "用户ID") @PathVariable Long id) {
return accountService.setStatus(id, "ENABLED").then();
}
@@ -77,7 +85,8 @@ public class UserController {
*/
@PostMapping("/{id}/disable")
@ResponseStatus(HttpStatus.NO_CONTENT)
- public Mono disable(@PathVariable Long id) {
+ @Operation(summary = "禁用用户", description = "禁用指定用户账户")
+ public Mono disable(@Parameter(description = "用户ID") @PathVariable Long id) {
return accountService.setStatus(id, "DISABLED").then();
}
}
\ No newline at end of file
diff --git a/src/main/java/com/gameplatform/server/controller/admin/AccountController.java b/src/main/java/com/gameplatform/server/controller/admin/AccountController.java
index 4ebbae9..ea9bcde 100644
--- a/src/main/java/com/gameplatform/server/controller/admin/AccountController.java
+++ b/src/main/java/com/gameplatform/server/controller/admin/AccountController.java
@@ -3,6 +3,9 @@ package com.gameplatform.server.controller.admin;
import com.gameplatform.server.model.dto.account.*;
import com.gameplatform.server.model.dto.common.PageResult;
import com.gameplatform.server.service.account.AccountService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@@ -10,6 +13,7 @@ import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/admin/accounts")
+@Tag(name = "管理员账户管理", description = "管理员账户的增删改查操作")
public class AccountController {
private final AccountService accountService;
@@ -18,48 +22,54 @@ public class AccountController {
}
@GetMapping
+ @Operation(summary = "获取账户列表", description = "分页获取账户列表,支持按用户类型、状态、关键词筛选")
public Mono> list(
- @RequestParam(value = "userType", required = false) String userType,
- @RequestParam(value = "status", required = false) String status,
- @RequestParam(value = "role", required = false) String role,
- @RequestParam(value = "keyword", required = false) String keyword,
- @RequestParam(value = "page", required = false) Integer page,
- @RequestParam(value = "size", required = false) Integer size
+ @Parameter(description = "用户类型:ADMIN 或 AGENT") @RequestParam(value = "userType", required = false) String userType,
+ @Parameter(description = "账户状态:ENABLED 或 DISABLED") @RequestParam(value = "status", required = false) String status,
+ @Parameter(description = "搜索关键词") @RequestParam(value = "keyword", required = false) String keyword,
+ @Parameter(description = "页码,默认1") @RequestParam(value = "page", required = false) Integer page,
+ @Parameter(description = "每页大小,默认20,最大200") @RequestParam(value = "size", required = false) Integer size
) {
- return accountService.list(userType, status, role, keyword, page, size);
+ return accountService.list(userType, status, keyword, page, size);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
+ @Operation(summary = "创建账户", description = "创建新的管理员或代理账户")
public Mono create(@Valid @RequestBody AccountCreateRequest req) {
return accountService.create(req);
}
@GetMapping("/{id}")
- public Mono detail(@PathVariable Long id) {
+ @Operation(summary = "获取账户详情", description = "根据账户ID获取账户详细信息")
+ public Mono detail(@Parameter(description = "账户ID") @PathVariable Long id) {
return accountService.get(id);
}
@PatchMapping("/{id}")
- public Mono update(@PathVariable Long id, @Valid @RequestBody AccountUpdateRequest req) {
+ @Operation(summary = "更新账户", description = "更新账户信息")
+ public Mono update(@Parameter(description = "账户ID") @PathVariable Long id, @Valid @RequestBody AccountUpdateRequest req) {
return accountService.update(id, req);
}
@PostMapping("/{id}/enable")
@ResponseStatus(HttpStatus.NO_CONTENT)
- public Mono enable(@PathVariable Long id) {
+ @Operation(summary = "启用账户", description = "启用指定账户")
+ public Mono enable(@Parameter(description = "账户ID") @PathVariable Long id) {
return accountService.setStatus(id, "ENABLED").then();
}
@PostMapping("/{id}/disable")
@ResponseStatus(HttpStatus.NO_CONTENT)
- public Mono disable(@PathVariable Long id) {
+ @Operation(summary = "禁用账户", description = "禁用指定账户")
+ public Mono disable(@Parameter(description = "账户ID") @PathVariable Long id) {
return accountService.setStatus(id, "DISABLED").then();
}
@PostMapping("/{id}/reset-password")
@ResponseStatus(HttpStatus.NO_CONTENT)
- public Mono resetPassword(@PathVariable Long id, @Valid @RequestBody ResetPasswordRequest req) {
+ @Operation(summary = "重置密码", description = "重置指定账户的密码")
+ public Mono resetPassword(@Parameter(description = "账户ID") @PathVariable Long id, @Valid @RequestBody ResetPasswordRequest req) {
return accountService.resetPassword(id, req.getNewPassword(), Boolean.TRUE.equals(req.getForceLogout()));
}
}
diff --git a/src/main/java/com/gameplatform/server/mapper/account/UserAccountMapper.java b/src/main/java/com/gameplatform/server/mapper/account/UserAccountMapper.java
index e8a4528..ca47788 100644
--- a/src/main/java/com/gameplatform/server/mapper/account/UserAccountMapper.java
+++ b/src/main/java/com/gameplatform/server/mapper/account/UserAccountMapper.java
@@ -15,12 +15,10 @@ public interface UserAccountMapper {
long countByFilter(@Param("userType") String userType,
@Param("status") String status,
- @Param("role") String role,
@Param("keyword") String keyword);
java.util.List listByFilter(@Param("userType") String userType,
@Param("status") String status,
- @Param("role") String role,
@Param("keyword") String keyword,
@Param("size") int size,
@Param("offset") int offset);
diff --git a/src/main/java/com/gameplatform/server/mapper/admin/AnnouncementMapper.java b/src/main/java/com/gameplatform/server/mapper/admin/AnnouncementMapper.java
new file mode 100644
index 0000000..fd4d781
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/mapper/admin/AnnouncementMapper.java
@@ -0,0 +1,29 @@
+package com.gameplatform.server.mapper.admin;
+
+import com.gameplatform.server.model.entity.admin.Announcement;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface AnnouncementMapper {
+ Announcement findById(@Param("id") Long id);
+
+ int insert(Announcement announcement);
+
+ int update(Announcement announcement);
+
+ int deleteById(@Param("id") Long id);
+
+ List findAll(@Param("size") int size,
+ @Param("offset") int offset);
+
+ long countAll();
+
+ List findByEnabled(@Param("enabled") Boolean enabled,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByEnabled(@Param("enabled") Boolean enabled);
+
+ int updateEnabled(@Param("id") Long id, @Param("enabled") Boolean enabled);
+}
diff --git a/src/main/java/com/gameplatform/server/mapper/admin/OperationLogMapper.java b/src/main/java/com/gameplatform/server/mapper/admin/OperationLogMapper.java
new file mode 100644
index 0000000..bdf238d
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/mapper/admin/OperationLogMapper.java
@@ -0,0 +1,35 @@
+package com.gameplatform.server.mapper.admin;
+
+import com.gameplatform.server.model.entity.admin.OperationLog;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface OperationLogMapper {
+ OperationLog findById(@Param("id") Long id);
+
+ int insert(OperationLog operationLog);
+
+ List findByCodeNo(@Param("codeNo") String codeNo,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByCodeNo(@Param("codeNo") String codeNo);
+
+ List findByActorId(@Param("actorId") Long actorId,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByActorId(@Param("actorId") Long actorId);
+
+ List findByActorType(@Param("actorType") String actorType,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByActorType(@Param("actorType") String actorType);
+
+ List findAll(@Param("size") int size,
+ @Param("offset") int offset);
+
+ long countAll();
+}
diff --git a/src/main/java/com/gameplatform/server/mapper/agent/AgentPointsTxMapper.java b/src/main/java/com/gameplatform/server/mapper/agent/AgentPointsTxMapper.java
new file mode 100644
index 0000000..3983587
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/mapper/agent/AgentPointsTxMapper.java
@@ -0,0 +1,26 @@
+package com.gameplatform.server.mapper.agent;
+
+import com.gameplatform.server.model.entity.agent.AgentPointsTx;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface AgentPointsTxMapper {
+ AgentPointsTx findById(@Param("id") Long id);
+
+ int insert(AgentPointsTx agentPointsTx);
+
+ List findByAccountId(@Param("accountId") Long accountId,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByAccountId(@Param("accountId") Long accountId);
+
+ List findByAccountIdAndType(@Param("accountId") Long accountId,
+ @Param("type") String type,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByAccountIdAndType(@Param("accountId") Long accountId,
+ @Param("type") String type);
+}
diff --git a/src/main/java/com/gameplatform/server/mapper/agent/LinkBatchMapper.java b/src/main/java/com/gameplatform/server/mapper/agent/LinkBatchMapper.java
new file mode 100644
index 0000000..17e904e
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/mapper/agent/LinkBatchMapper.java
@@ -0,0 +1,23 @@
+package com.gameplatform.server.mapper.agent;
+
+import com.gameplatform.server.model.entity.agent.LinkBatch;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface LinkBatchMapper {
+ LinkBatch findById(@Param("id") Long id);
+
+ int insert(LinkBatch linkBatch);
+
+ List findByAgentId(@Param("agentId") Long agentId,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByAgentId(@Param("agentId") Long agentId);
+
+ List findAll(@Param("size") int size,
+ @Param("offset") int offset);
+
+ long countAll();
+}
diff --git a/src/main/java/com/gameplatform/server/mapper/agent/LinkTaskMapper.java b/src/main/java/com/gameplatform/server/mapper/agent/LinkTaskMapper.java
new file mode 100644
index 0000000..3eb9e03
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/mapper/agent/LinkTaskMapper.java
@@ -0,0 +1,50 @@
+package com.gameplatform.server.mapper.agent;
+
+import com.gameplatform.server.model.entity.agent.LinkTask;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface LinkTaskMapper {
+ LinkTask findById(@Param("id") Long id);
+
+ LinkTask findByCodeNo(@Param("codeNo") String codeNo);
+
+ LinkTask findByTokenHash(@Param("tokenHash") String tokenHash);
+
+ int insert(LinkTask linkTask);
+
+ int update(LinkTask linkTask);
+
+ int updateStatus(@Param("id") Long id, @Param("status") String status);
+
+ int updateStatusAndMachine(@Param("id") Long id,
+ @Param("status") String status,
+ @Param("region") String region,
+ @Param("machineId") String machineId,
+ @Param("loginAt") LocalDateTime loginAt);
+
+ List findByAgentId(@Param("agentId") Long agentId,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByAgentId(@Param("agentId") Long agentId);
+
+ List findByAgentIdAndStatus(@Param("agentId") Long agentId,
+ @Param("status") String status,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByAgentIdAndStatus(@Param("agentId") Long agentId,
+ @Param("status") String status);
+
+ List findByBatchId(@Param("batchId") Long batchId,
+ @Param("size") int size,
+ @Param("offset") int offset);
+
+ long countByBatchId(@Param("batchId") Long batchId);
+
+ List findExpiredTasks(@Param("expireTime") LocalDateTime expireTime,
+ @Param("size") int size);
+}
diff --git a/src/main/java/com/gameplatform/server/model/dto/account/AccountCreateRequest.java b/src/main/java/com/gameplatform/server/model/dto/account/AccountCreateRequest.java
index f889b36..5072a2c 100644
--- a/src/main/java/com/gameplatform/server/model/dto/account/AccountCreateRequest.java
+++ b/src/main/java/com/gameplatform/server/model/dto/account/AccountCreateRequest.java
@@ -1,20 +1,32 @@
package com.gameplatform.server.model.dto.account;
+import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
+@Schema(description = "账户创建请求")
public class AccountCreateRequest {
- @NotBlank
+ @Schema(description = "用户类型", example = "AGENT", allowableValues = {"ADMIN", "AGENT"})
+ @NotBlank(message = "userType 不能为空")
+ @Pattern(regexp = "^(ADMIN|AGENT)$", message = "userType 只能是 ADMIN 或 AGENT")
private String userType; // ADMIN | AGENT
- @NotBlank
- @Size(min = 3, max = 64)
+
+ @Schema(description = "用户名", example = "newuser", minLength = 3, maxLength = 64)
+ @NotBlank(message = "username 不能为空")
+ @Size(min = 3, max = 64, message = "username 长度必须在 3-64 字符之间")
+ @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "username 只能包含字母、数字、下划线")
private String username;
- private String status = "ENABLED"; // ENABLED | DISABLED
- @NotBlank
- @Size(min = 6, max = 128)
+ @Schema(description = "密码", example = "123456", minLength = 6, maxLength = 128)
+ @NotBlank(message = "password 不能为空")
+ @Size(min = 6, max = 128, message = "password 长度必须在 6-128 字符之间")
private String password;
+
+ @Schema(description = "账户状态", example = "ENABLED", allowableValues = {"ENABLED", "DISABLED"}, defaultValue = "ENABLED")
+ private String status;
+
+ @Schema(description = "积分余额", example = "1000", minimum = "0", defaultValue = "0")
@Min(0)
- private Long pointsBalance = 0L; // for AGENT
+ private Long pointsBalance; // for AGENT
public String getUserType() { return userType; }
public void setUserType(String userType) { this.userType = userType; }
diff --git a/src/main/java/com/gameplatform/server/model/dto/account/AccountResponse.java b/src/main/java/com/gameplatform/server/model/dto/account/AccountResponse.java
index 5969097..c32b879 100644
--- a/src/main/java/com/gameplatform/server/model/dto/account/AccountResponse.java
+++ b/src/main/java/com/gameplatform/server/model/dto/account/AccountResponse.java
@@ -1,15 +1,30 @@
package com.gameplatform.server.model.dto.account;
+import io.swagger.v3.oas.annotations.media.Schema;
+
import java.time.LocalDateTime;
+@Schema(description = "账户响应")
public class AccountResponse {
+ @Schema(description = "账户ID", example = "1")
private Long id;
+
+ @Schema(description = "用户类型", example = "AGENT", allowableValues = {"ADMIN", "AGENT"})
private String userType;
+
+ @Schema(description = "用户名", example = "newuser")
private String username;
+ @Schema(description = "账户状态", example = "ENABLED", allowableValues = {"ENABLED", "DISABLED"})
private String status;
+
+ @Schema(description = "积分余额", example = "1000")
private Long pointsBalance;
+
+ @Schema(description = "创建时间", example = "2025-08-24T18:30:00.000")
private LocalDateTime createdAt;
+
+ @Schema(description = "更新时间", example = "2025-08-24T18:30:00.000")
private LocalDateTime updatedAt;
public Long getId() { return id; }
diff --git a/src/main/java/com/gameplatform/server/model/dto/account/AccountUpdateRequest.java b/src/main/java/com/gameplatform/server/model/dto/account/AccountUpdateRequest.java
index f5defd6..001dbcc 100644
--- a/src/main/java/com/gameplatform/server/model/dto/account/AccountUpdateRequest.java
+++ b/src/main/java/com/gameplatform/server/model/dto/account/AccountUpdateRequest.java
@@ -1,10 +1,13 @@
package com.gameplatform.server.model.dto.account;
-import jakarta.validation.constraints.Size;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Pattern;
+@Schema(description = "账户更新请求")
public class AccountUpdateRequest {
-
- private String status; // ENABLED | DISABLED
+ @Schema(description = "账户状态", example = "ENABLED", allowableValues = {"ENABLED", "DISABLED"})
+ @Pattern(regexp = "^(ENABLED|DISABLED)$", message = "status 只能是 ENABLED 或 DISABLED")
+ private String status;
public String getStatus() { return status; }
diff --git a/src/main/java/com/gameplatform/server/model/dto/account/ResetPasswordRequest.java b/src/main/java/com/gameplatform/server/model/dto/account/ResetPasswordRequest.java
index 85854c8..c7b383a 100644
--- a/src/main/java/com/gameplatform/server/model/dto/account/ResetPasswordRequest.java
+++ b/src/main/java/com/gameplatform/server/model/dto/account/ResetPasswordRequest.java
@@ -1,12 +1,17 @@
package com.gameplatform.server.model.dto.account;
+import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
+@Schema(description = "重置密码请求")
public class ResetPasswordRequest {
- @NotBlank
- @Size(min = 6, max = 128)
+ @Schema(description = "新密码", example = "NewPassword123!", minLength = 6, maxLength = 128)
+ @NotBlank(message = "newPassword 不能为空")
+ @Size(min = 6, max = 128, message = "newPassword 长度必须在 6-128 字符之间")
private String newPassword;
+
+ @Schema(description = "是否强制登出", example = "true", defaultValue = "true")
private Boolean forceLogout = Boolean.TRUE;
public String getNewPassword() { return newPassword; }
diff --git a/src/main/java/com/gameplatform/server/model/entity/account/UserAccount.java b/src/main/java/com/gameplatform/server/model/entity/account/UserAccount.java
index 2323624..ae39486 100644
--- a/src/main/java/com/gameplatform/server/model/entity/account/UserAccount.java
+++ b/src/main/java/com/gameplatform/server/model/entity/account/UserAccount.java
@@ -6,9 +6,7 @@ public class UserAccount {
private Long id;
private String userType; // ADMIN | AGENT
private String username; // 登录名(admin/agent 共用)
-
private String passwordHash; // BCrypt 或 PLAIN:xxx(初始化用)
-
private String status; // ENABLED / DISABLED
private Long pointsBalance; // 仅 AGENT 使用
private LocalDateTime createdAt;
@@ -20,10 +18,8 @@ public class UserAccount {
public void setUserType(String userType) { this.userType = userType; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
-
public String getPasswordHash() { return passwordHash; }
public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; }
-
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public Long getPointsBalance() { return pointsBalance; }
diff --git a/src/main/java/com/gameplatform/server/model/entity/admin/Announcement.java b/src/main/java/com/gameplatform/server/model/entity/admin/Announcement.java
new file mode 100644
index 0000000..37f1b3b
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/model/entity/admin/Announcement.java
@@ -0,0 +1,34 @@
+package com.gameplatform.server.model.entity.admin;
+
+import java.time.LocalDateTime;
+
+public class Announcement {
+ private Long id;
+ private String title;
+ private String content;
+ private Boolean enabled;
+ private String jumpUrl;
+ private LocalDateTime createdAt;
+ private LocalDateTime updatedAt;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+
+ public String getContent() { return content; }
+ public void setContent(String content) { this.content = content; }
+
+ public Boolean getEnabled() { return enabled; }
+ public void setEnabled(Boolean enabled) { this.enabled = enabled; }
+
+ public String getJumpUrl() { return jumpUrl; }
+ public void setJumpUrl(String jumpUrl) { this.jumpUrl = jumpUrl; }
+
+ public LocalDateTime getCreatedAt() { return createdAt; }
+ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
+
+ public LocalDateTime getUpdatedAt() { return updatedAt; }
+ public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
+}
diff --git a/src/main/java/com/gameplatform/server/model/entity/admin/OperationLog.java b/src/main/java/com/gameplatform/server/model/entity/admin/OperationLog.java
new file mode 100644
index 0000000..3416dbf
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/model/entity/admin/OperationLog.java
@@ -0,0 +1,42 @@
+package com.gameplatform.server.model.entity.admin;
+
+import java.time.LocalDateTime;
+
+public class OperationLog {
+ private Long id;
+ private String actorType; // admin | agent | system | user
+ private Long actorId;
+ private String codeNo;
+ private String op;
+ private String detail; // JSON字符串
+ private String clientIp;
+ private String userAgent;
+ private LocalDateTime createdAt;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+
+ public String getActorType() { return actorType; }
+ public void setActorType(String actorType) { this.actorType = actorType; }
+
+ public Long getActorId() { return actorId; }
+ public void setActorId(Long actorId) { this.actorId = actorId; }
+
+ public String getCodeNo() { return codeNo; }
+ public void setCodeNo(String codeNo) { this.codeNo = codeNo; }
+
+ public String getOp() { return op; }
+ public void setOp(String op) { this.op = op; }
+
+ public String getDetail() { return detail; }
+ public void setDetail(String detail) { this.detail = detail; }
+
+ public String getClientIp() { return clientIp; }
+ public void setClientIp(String clientIp) { this.clientIp = clientIp; }
+
+ public String getUserAgent() { return userAgent; }
+ public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
+
+ public LocalDateTime getCreatedAt() { return createdAt; }
+ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
+}
diff --git a/src/main/java/com/gameplatform/server/model/entity/agent/AgentPointsTx.java b/src/main/java/com/gameplatform/server/model/entity/agent/AgentPointsTx.java
new file mode 100644
index 0000000..d59d4ce
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/model/entity/agent/AgentPointsTx.java
@@ -0,0 +1,46 @@
+package com.gameplatform.server.model.entity.agent;
+
+import java.time.LocalDateTime;
+
+public class AgentPointsTx {
+ private Long id;
+ private Long accountId;
+ private String type; // ADD | DEDUCT
+ private Long beforePoints;
+ private Long deltaPoints;
+ private Long afterPoints;
+ private String reason; // create_links | manual | refund_no_rollback | other
+ private Long refId;
+ private Long operatorId;
+ private LocalDateTime createdAt;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+
+ public Long getAccountId() { return accountId; }
+ public void setAccountId(Long accountId) { this.accountId = accountId; }
+
+ public String getType() { return type; }
+ public void setType(String type) { this.type = type; }
+
+ public Long getBeforePoints() { return beforePoints; }
+ public void setBeforePoints(Long beforePoints) { this.beforePoints = beforePoints; }
+
+ public Long getDeltaPoints() { return deltaPoints; }
+ public void setDeltaPoints(Long deltaPoints) { this.deltaPoints = deltaPoints; }
+
+ public Long getAfterPoints() { return afterPoints; }
+ public void setAfterPoints(Long afterPoints) { this.afterPoints = afterPoints; }
+
+ public String getReason() { return reason; }
+ public void setReason(String reason) { this.reason = reason; }
+
+ public Long getRefId() { return refId; }
+ public void setRefId(Long refId) { this.refId = refId; }
+
+ public Long getOperatorId() { return operatorId; }
+ public void setOperatorId(Long operatorId) { this.operatorId = operatorId; }
+
+ public LocalDateTime getCreatedAt() { return createdAt; }
+ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
+}
diff --git a/src/main/java/com/gameplatform/server/model/entity/agent/LinkBatch.java b/src/main/java/com/gameplatform/server/model/entity/agent/LinkBatch.java
new file mode 100644
index 0000000..b82848e
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/model/entity/agent/LinkBatch.java
@@ -0,0 +1,38 @@
+package com.gameplatform.server.model.entity.agent;
+
+import java.time.LocalDateTime;
+
+public class LinkBatch {
+ private Long id;
+ private Long agentId;
+ private Integer quantity;
+ private Integer times;
+ private Integer batchSize;
+ private Long deductPoints;
+ private Long operatorId;
+ private LocalDateTime createdAt;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+
+ public Long getAgentId() { return agentId; }
+ public void setAgentId(Long agentId) { this.agentId = agentId; }
+
+ public Integer getQuantity() { return quantity; }
+ public void setQuantity(Integer quantity) { this.quantity = quantity; }
+
+ public Integer getTimes() { return times; }
+ public void setTimes(Integer times) { this.times = times; }
+
+ public Integer getBatchSize() { return batchSize; }
+ public void setBatchSize(Integer batchSize) { this.batchSize = batchSize; }
+
+ public Long getDeductPoints() { return deductPoints; }
+ public void setDeductPoints(Long deductPoints) { this.deductPoints = deductPoints; }
+
+ public Long getOperatorId() { return operatorId; }
+ public void setOperatorId(Long operatorId) { this.operatorId = operatorId; }
+
+ public LocalDateTime getCreatedAt() { return createdAt; }
+ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
+}
diff --git a/src/main/java/com/gameplatform/server/model/entity/agent/LinkTask.java b/src/main/java/com/gameplatform/server/model/entity/agent/LinkTask.java
new file mode 100644
index 0000000..70663f9
--- /dev/null
+++ b/src/main/java/com/gameplatform/server/model/entity/agent/LinkTask.java
@@ -0,0 +1,62 @@
+package com.gameplatform.server.model.entity.agent;
+
+import java.time.LocalDateTime;
+
+public class LinkTask {
+ private Long id;
+ private Long batchId;
+ private Long agentId;
+ private String codeNo;
+ private String tokenHash;
+ private LocalDateTime expireAt;
+ private String status; // NEW | USING | LOGGED_IN | REFUNDED | EXPIRED
+ private String region; // Q | V
+ private String machineId;
+ private LocalDateTime loginAt;
+ private LocalDateTime refundAt;
+ private LocalDateTime revokedAt;
+ private LocalDateTime createdAt;
+ private LocalDateTime updatedAt;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+
+ public Long getBatchId() { return batchId; }
+ public void setBatchId(Long batchId) { this.batchId = batchId; }
+
+ public Long getAgentId() { return agentId; }
+ public void setAgentId(Long agentId) { this.agentId = agentId; }
+
+ public String getCodeNo() { return codeNo; }
+ public void setCodeNo(String codeNo) { this.codeNo = codeNo; }
+
+ public String getTokenHash() { return tokenHash; }
+ public void setTokenHash(String tokenHash) { this.tokenHash = tokenHash; }
+
+ public LocalDateTime getExpireAt() { return expireAt; }
+ public void setExpireAt(LocalDateTime expireAt) { this.expireAt = expireAt; }
+
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+
+ public String getRegion() { return region; }
+ public void setRegion(String region) { this.region = region; }
+
+ public String getMachineId() { return machineId; }
+ public void setMachineId(String machineId) { this.machineId = machineId; }
+
+ public LocalDateTime getLoginAt() { return loginAt; }
+ public void setLoginAt(LocalDateTime loginAt) { this.loginAt = loginAt; }
+
+ public LocalDateTime getRefundAt() { return refundAt; }
+ public void setRefundAt(LocalDateTime refundAt) { this.refundAt = refundAt; }
+
+ public LocalDateTime getRevokedAt() { return revokedAt; }
+ public void setRevokedAt(LocalDateTime revokedAt) { this.revokedAt = revokedAt; }
+
+ public LocalDateTime getCreatedAt() { return createdAt; }
+ public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
+
+ public LocalDateTime getUpdatedAt() { return updatedAt; }
+ public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
+}
diff --git a/src/main/java/com/gameplatform/server/service/UserService.java b/src/main/java/com/gameplatform/server/service/UserService.java
index 72e4177..fa0e841 100644
--- a/src/main/java/com/gameplatform/server/service/UserService.java
+++ b/src/main/java/com/gameplatform/server/service/UserService.java
@@ -46,15 +46,15 @@ public class UserService {
/**
* 分页查询用户列表
*/
- public Mono> list(String userType, String status, String role, String keyword,
+ public Mono> list(String userType, String status, String keyword,
Integer page, Integer size) {
int p = (page == null || page < 1) ? 1 : page;
int s = (size == null || size < 1 || size > 200) ? 20 : size;
int offset = (p - 1) * s;
return Mono.fromCallable(() -> {
- long total = userAccountMapper.countByFilter(userType, status, role, keyword);
- List list = userAccountMapper.listByFilter(userType, status, role, keyword, s, offset);
+ long total = userAccountMapper.countByFilter(userType, status, keyword);
+ List list = userAccountMapper.listByFilter(userType, status, keyword, s, offset);
List items = list.stream()
.map(this::toAccountResponse)
.collect(Collectors.toList());
@@ -81,8 +81,6 @@ public class UserService {
response.setId(account.getId());
response.setUserType(account.getUserType());
response.setUsername(account.getUsername());
- response.setDisplayName(account.getDisplayName());
- response.setRole(account.getRole());
response.setStatus(account.getStatus());
response.setPointsBalance(account.getPointsBalance());
response.setCreatedAt(account.getCreatedAt());
diff --git a/src/main/java/com/gameplatform/server/service/account/AccountService.java b/src/main/java/com/gameplatform/server/service/account/AccountService.java
index bd9eb7d..4d23192 100644
--- a/src/main/java/com/gameplatform/server/service/account/AccountService.java
+++ b/src/main/java/com/gameplatform/server/service/account/AccountService.java
@@ -31,8 +31,8 @@ public class AccountService {
int s = (size == null || size < 1 || size > 200) ? 20 : size;
int offset = (p - 1) * s;
return Mono.fromCallable(() -> {
- long total = mapper.countByFilter(userType, status, null, keyword);
- List list = mapper.listByFilter(userType, status, null, keyword, s, offset);
+ long total = mapper.countByFilter(userType, status, keyword);
+ List list = mapper.listByFilter(userType, status, keyword, s, offset);
List items = list.stream().map(this::toResp).collect(Collectors.toList());
return new PageResult<>(items, total, p, s);
})
diff --git a/src/main/java/com/gameplatform/server/service/auth/AuthService.java b/src/main/java/com/gameplatform/server/service/auth/AuthService.java
index 4161414..69cfe36 100644
--- a/src/main/java/com/gameplatform/server/service/auth/AuthService.java
+++ b/src/main/java/com/gameplatform/server/service/auth/AuthService.java
@@ -38,7 +38,7 @@ public class AuthService {
if (acc == null) {
log.warn("login account not found username={}", req.getUsername());
} else {
- log.debug("login account loaded id={}, status={}, role={} userType={}", acc.getId(), acc.getStatus(), acc.getRole(), acc.getUserType());
+ log.debug("login account loaded id={}, status={}, userType={}", acc.getId(), acc.getStatus(), acc.getUserType());
}
})
.flatMap(acc -> validatePasswordAndBuild(acc, req.getPassword()))
@@ -73,7 +73,7 @@ public class AuthService {
String token = jwtService.generateToken(
userType + ":" + acc.getId(),
userType, acc.getId(), acc.getUsername(),
- "admin".equals(userType) ? Map.of("role", acc.getRole()) : Map.of("displayName", acc.getDisplayName())
+ Map.of()
);
LoginResponse resp = new LoginResponse();
resp.setAccessToken(token);
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 594fce6..f46ffa2 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -40,3 +40,16 @@ security:
secret: "change-this-secret-to-a-long-random-string-please"
access-token-minutes: 30
refresh-token-days: 7
+
+# Swagger/OpenAPI 配置
+springdoc:
+ api-docs:
+ path: /api-docs
+ swagger-ui:
+ path: /swagger-ui.html
+ tags-sorter: alpha
+ operations-sorter: alpha
+ doc-expansion: none
+ disable-swagger-default-url: true
+ display-request-duration: true
+ packages-to-scan: com.gameplatform.server.controller
diff --git a/src/main/resources/mapper/account/UserAccountMapper.xml b/src/main/resources/mapper/account/UserAccountMapper.xml
index 578d906..c99ea1f 100644
--- a/src/main/resources/mapper/account/UserAccountMapper.xml
+++ b/src/main/resources/mapper/account/UserAccountMapper.xml
@@ -5,9 +5,7 @@
-
-
@@ -15,7 +13,7 @@
- INSERT INTO user_account (user_type, username, display_name, password_hash, role, status, points_balance)
- VALUES (#{userType}, #{username}, #{displayName}, #{passwordHash}, #{role}, #{status}, #{pointsBalance})
+ INSERT INTO user_account (user_type, username, password_hash, status, points_balance)
+ VALUES (#{userType}, #{username}, #{passwordHash}, #{status}, #{pointsBalance})
UPDATE user_account
- display_name = #{displayName},
- role = #{role},
status = #{status},
+ points_balance = #{pointsBalance},
WHERE id = #{id}
@@ -64,22 +61,20 @@
AND user_type = #{userType}
AND status = #{status}
- AND role = #{role}
- AND (username LIKE CONCAT('%', #{keyword}, '%') OR display_name LIKE CONCAT('%', #{keyword}, '%'))
+ AND username LIKE CONCAT('%', #{keyword}, '%')
- SELECT id, user_type, username, display_name, password_hash, role, status, points_balance, created_at, updated_at
+ SELECT id, user_type, username, password_hash, status, points_balance, created_at, updated_at
FROM user_account
AND user_type = #{userType}
AND status = #{status}
- AND role = #{role}
- AND (username LIKE CONCAT('%', #{keyword}, '%') OR display_name LIKE CONCAT('%', #{keyword}, '%'))
+ AND username LIKE CONCAT('%', #{keyword}, '%')
ORDER BY id DESC
diff --git a/target/classes/mapper/admin/AnnouncementMapper.xml b/target/classes/mapper/admin/AnnouncementMapper.xml
new file mode 100644
index 0000000..7b0060b
--- /dev/null
+++ b/target/classes/mapper/admin/AnnouncementMapper.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, title, content, enabled, jump_url, created_at, updated_at
+ FROM announcement
+ WHERE id = #{id}
+ LIMIT 1
+
+
+
+ INSERT INTO announcement (title, content, enabled, jump_url)
+ VALUES (#{title}, #{content}, #{enabled}, #{jumpUrl})
+
+
+
+ UPDATE announcement
+
+ title = #{title},
+ content = #{content},
+ enabled = #{enabled},
+ jump_url = #{jumpUrl},
+
+ WHERE id = #{id}
+
+
+
+ DELETE FROM announcement WHERE id = #{id}
+
+
+
+ SELECT id, title, content, enabled, jump_url, created_at, updated_at
+ FROM announcement
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM announcement
+
+
+
+ SELECT id, title, content, enabled, jump_url, created_at, updated_at
+ FROM announcement
+ WHERE enabled = #{enabled}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM announcement WHERE enabled = #{enabled}
+
+
+
+ UPDATE announcement SET enabled = #{enabled} WHERE id = #{id}
+
+
diff --git a/target/classes/mapper/admin/OperationLogMapper.xml b/target/classes/mapper/admin/OperationLogMapper.xml
new file mode 100644
index 0000000..4663ac7
--- /dev/null
+++ b/target/classes/mapper/admin/OperationLogMapper.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, actor_type, actor_id, code_no, op, detail, client_ip, user_agent, created_at
+ FROM operation_log
+ WHERE id = #{id}
+ LIMIT 1
+
+
+
+ INSERT INTO operation_log (actor_type, actor_id, code_no, op, detail, client_ip, user_agent)
+ VALUES (#{actorType}, #{actorId}, #{codeNo}, #{op}, #{detail}, #{clientIp}, #{userAgent})
+
+
+
+ SELECT id, actor_type, actor_id, code_no, op, detail, client_ip, user_agent, created_at
+ FROM operation_log
+ WHERE code_no = #{codeNo}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM operation_log WHERE code_no = #{codeNo}
+
+
+
+ SELECT id, actor_type, actor_id, code_no, op, detail, client_ip, user_agent, created_at
+ FROM operation_log
+ WHERE actor_id = #{actorId}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM operation_log WHERE actor_id = #{actorId}
+
+
+
+ SELECT id, actor_type, actor_id, code_no, op, detail, client_ip, user_agent, created_at
+ FROM operation_log
+ WHERE actor_type = #{actorType}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM operation_log WHERE actor_type = #{actorType}
+
+
+
+ SELECT id, actor_type, actor_id, code_no, op, detail, client_ip, user_agent, created_at
+ FROM operation_log
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM operation_log
+
+
diff --git a/target/classes/mapper/agent/AgentPointsTxMapper.xml b/target/classes/mapper/agent/AgentPointsTxMapper.xml
new file mode 100644
index 0000000..488603b
--- /dev/null
+++ b/target/classes/mapper/agent/AgentPointsTxMapper.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, account_id, type, before_points, delta_points, after_points, reason, ref_id, operator_id, created_at
+ FROM agent_points_tx
+ WHERE id = #{id}
+ LIMIT 1
+
+
+
+ INSERT INTO agent_points_tx (account_id, type, before_points, delta_points, after_points, reason, ref_id, operator_id)
+ VALUES (#{accountId}, #{type}, #{beforePoints}, #{deltaPoints}, #{afterPoints}, #{reason}, #{refId}, #{operatorId})
+
+
+
+ SELECT id, account_id, type, before_points, delta_points, after_points, reason, ref_id, operator_id, created_at
+ FROM agent_points_tx
+ WHERE account_id = #{accountId}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM agent_points_tx WHERE account_id = #{accountId}
+
+
+
+ SELECT id, account_id, type, before_points, delta_points, after_points, reason, ref_id, operator_id, created_at
+ FROM agent_points_tx
+ WHERE account_id = #{accountId} AND type = #{type}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM agent_points_tx WHERE account_id = #{accountId} AND type = #{type}
+
+
diff --git a/target/classes/mapper/agent/LinkBatchMapper.xml b/target/classes/mapper/agent/LinkBatchMapper.xml
new file mode 100644
index 0000000..21cb034
--- /dev/null
+++ b/target/classes/mapper/agent/LinkBatchMapper.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, agent_id, quantity, times, batch_size, deduct_points, operator_id, created_at
+ FROM link_batch
+ WHERE id = #{id}
+ LIMIT 1
+
+
+
+ INSERT INTO link_batch (agent_id, quantity, times, batch_size, deduct_points, operator_id)
+ VALUES (#{agentId}, #{quantity}, #{times}, #{batchSize}, #{deductPoints}, #{operatorId})
+
+
+
+ SELECT id, agent_id, quantity, times, batch_size, deduct_points, operator_id, created_at
+ FROM link_batch
+ WHERE agent_id = #{agentId}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM link_batch WHERE agent_id = #{agentId}
+
+
+
+ SELECT id, agent_id, quantity, times, batch_size, deduct_points, operator_id, created_at
+ FROM link_batch
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM link_batch
+
+
diff --git a/target/classes/mapper/agent/LinkTaskMapper.xml b/target/classes/mapper/agent/LinkTaskMapper.xml
new file mode 100644
index 0000000..a71bebe
--- /dev/null
+++ b/target/classes/mapper/agent/LinkTaskMapper.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE id = #{id}
+ LIMIT 1
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE code_no = #{codeNo}
+ LIMIT 1
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE token_hash = #{tokenHash}
+ LIMIT 1
+
+
+
+ INSERT INTO link_task (batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at)
+ VALUES (#{batchId}, #{agentId}, #{codeNo}, #{tokenHash}, #{expireAt}, #{status}, #{region}, #{machineId}, #{loginAt}, #{refundAt}, #{revokedAt})
+
+
+
+ UPDATE link_task
+
+ status = #{status},
+ region = #{region},
+ machine_id = #{machineId},
+ login_at = #{loginAt},
+ refund_at = #{refundAt},
+ revoked_at = #{revokedAt},
+
+ WHERE id = #{id}
+
+
+
+ UPDATE link_task SET status = #{status} WHERE id = #{id}
+
+
+
+ UPDATE link_task
+ SET status = #{status}, region = #{region}, machine_id = #{machineId}, login_at = #{loginAt}
+ WHERE id = #{id}
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE agent_id = #{agentId}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM link_task WHERE agent_id = #{agentId}
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE agent_id = #{agentId} AND status = #{status}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM link_task WHERE agent_id = #{agentId} AND status = #{status}
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE batch_id = #{batchId}
+ ORDER BY created_at DESC
+ LIMIT #{size} OFFSET #{offset}
+
+
+
+ SELECT COUNT(1) FROM link_task WHERE batch_id = #{batchId}
+
+
+
+ SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at
+ FROM link_task
+ WHERE expire_at <= #{expireTime} AND status IN ('NEW', 'USING')
+ ORDER BY expire_at ASC
+ LIMIT #{size}
+
+
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
index e69de29..ba69f71 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -0,0 +1,34 @@
+com\gameplatform\server\mapper\agent\LinkTaskMapper.class
+com\gameplatform\server\exception\GlobalExceptionHandler$2.class
+com\gameplatform\server\model\entity\admin\Announcement.class
+com\gameplatform\server\mapper\agent\AgentPointsTxMapper.class
+com\gameplatform\server\config\CorsConfig.class
+com\gameplatform\server\exception\GlobalExceptionHandler.class
+com\gameplatform\server\model\dto\common\PageResult.class
+com\gameplatform\server\service\UserService.class
+com\gameplatform\server\controller\auth\AuthController.class
+com\gameplatform\server\model\entity\agent\AgentPointsTx.class
+com\gameplatform\server\controller\admin\AccountController.class
+com\gameplatform\server\GamePlatformServerApplication.class
+com\gameplatform\server\model\dto\auth\LoginRequest.class
+com\gameplatform\server\model\entity\account\UserAccount.class
+com\gameplatform\server\mapper\admin\AnnouncementMapper.class
+com\gameplatform\server\model\dto\auth\LoginResponse.class
+com\gameplatform\server\model\entity\agent\LinkTask.class
+com\gameplatform\server\service\auth\AuthService.class
+com\gameplatform\server\config\SwaggerConfig.class
+com\gameplatform\server\exception\GlobalExceptionHandler$1.class
+com\gameplatform\server\mapper\account\UserAccountMapper.class
+com\gameplatform\server\mapper\agent\LinkBatchMapper.class
+com\gameplatform\server\security\JwtService.class
+com\gameplatform\server\mapper\admin\OperationLogMapper.class
+com\gameplatform\server\model\entity\agent\LinkBatch.class
+com\gameplatform\server\service\account\AccountService.class
+com\gameplatform\server\controller\UserController.class
+com\gameplatform\server\security\SecurityConfig.class
+com\gameplatform\server\model\entity\admin\OperationLog.class
+com\gameplatform\server\model\dto\account\AccountResponse.class
+com\gameplatform\server\model\dto\account\AccountCreateRequest.class
+com\gameplatform\server\model\dto\account\AccountUpdateRequest.class
+com\gameplatform\server\controller\auth\AuthController$1.class
+com\gameplatform\server\model\dto\account\ResetPasswordRequest.class
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
index 7916b02..7079876 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -1,20 +1,31 @@
-D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\GamePlatformServerApplication.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\agent\AgentPointsTxMapper.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\admin\AnnouncementMapper.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\security\SecurityConfig.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\account\ResetPasswordRequest.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\service\account\AccountService.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\service\auth\AuthService.java
-D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\account\AccountUpdateRequest.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\auth\LoginRequest.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\admin\AccountController.java
-D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\auth\LoginResponse.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\UserController.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\agent\LinkBatchMapper.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\agent\LinkTaskMapper.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\config\SwaggerConfig.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\account\AccountResponse.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\admin\OperationLog.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\service\UserService.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\auth\AuthController.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\security\JwtService.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\config\CorsConfig.java
-D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\exception\GlobalExceptionHandler.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\common\PageResult.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\GamePlatformServerApplication.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\agent\LinkTask.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\account\AccountUpdateRequest.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\admin\Announcement.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\agent\AgentPointsTx.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\auth\LoginResponse.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\admin\OperationLogMapper.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\exception\GlobalExceptionHandler.java
+D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\agent\LinkBatch.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\account\UserAccountMapper.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\account\AccountCreateRequest.java
D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\account\UserAccount.java