feat: 更新数据库结构和链接任务逻辑

主要修改:
1. 更新`game.sql`文件,添加`system_config`表并调整多个表的`ENGINE`和`AUTO_INCREMENT`设置。
2. 在`LinkTask`实体中新增`completedPoints`字段,更新状态字段以包含`COMPLETED`状态。
3. 在`LinkTaskMapper`中新增根据设备ID和状态查询链接任务的方法。
4. 在`LinkStatusService`中更新状态描述映射,增加对`COMPLETED`状态的处理。
5. 在`DeviceStatusService`和`ScriptClient`中新增解析设备状态的方法,支持检查设备是否完成游戏。

技术细节:
- 通过数据库结构的更新,增强了系统的配置管理和链接任务的状态处理能力。
- 新增的功能支持更灵活的设备状态监控和任务管理。
This commit is contained in:
zyh
2025-08-27 16:00:43 +08:00
parent bb4136b4ab
commit c6e8953960
16 changed files with 620 additions and 55 deletions

View File

@@ -0,0 +1,29 @@
-- 数据库迁移脚本添加完成时点数字段和COMPLETED状态
-- 执行时间2025-08-27
-- 1. 添加 completed_points 字段
ALTER TABLE `link_task`
ADD COLUMN `completed_points` int UNSIGNED NULL DEFAULT NULL COMMENT '完成时的点数'
AFTER `first_region_select_at`;
-- 2. 修改 status 枚举,添加 COMPLETED 状态
ALTER TABLE `link_task`
MODIFY COLUMN `status` enum('NEW','USING','LOGGED_IN','COMPLETED','REFUNDED','EXPIRED')
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NEW';
-- 3. 验证修改结果
SELECT
COLUMN_NAME,
DATA_TYPE,
COLUMN_TYPE,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'link_task'
AND COLUMN_NAME IN ('status', 'completed_points')
ORDER BY ORDINAL_POSITION;
-- 4. 检查表结构
SHOW CREATE TABLE `link_task`;

View File

@@ -0,0 +1,20 @@
-- 数据库迁移脚本:添加 COMPLETED 状态到 link_task 表
-- 执行时间:请在维护窗口期间执行
-- 影响:修改 link_task 表的 status 字段枚举值
-- 修改 link_task 表的 status 字段,添加 'COMPLETED' 状态
-- 'COMPLETED' 状态表示用户正常完成了游戏任务
ALTER TABLE `link_task`
MODIFY COLUMN `status` enum('NEW','USING','LOGGED_IN','COMPLETED','REFUNDED','EXPIRED')
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NEW'
COMMENT '任务状态: NEW=新建, USING=使用中, LOGGED_IN=已登录, COMPLETED=正常完成, REFUNDED=已退款, EXPIRED=已过期';
-- 验证修改结果
-- 查看表结构确认枚举值已更新
DESCRIBE `link_task`;
-- 查看当前各状态的统计
SELECT status, COUNT(*) as count
FROM `link_task`
GROUP BY status
ORDER BY status;

View File

@@ -11,7 +11,7 @@
Target Server Version : 80043 (8.0.43)
File Encoding : 65001
Date: 24/08/2025 19:08:50
Date: 27/08/2025 15:45:17
*/
SET NAMES utf8mb4;
@@ -37,7 +37,7 @@ CREATE TABLE `agent_points_tx` (
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;
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for announcement
@@ -52,7 +52,7 @@ CREATE TABLE `announcement` (
`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;
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for link_batch
@@ -63,8 +63,6 @@ CREATE TABLE `link_batch` (
`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,
@@ -72,10 +70,9 @@ CREATE TABLE `link_batch` (
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;
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for link_task
@@ -88,7 +85,7 @@ CREATE TABLE `link_task` (
`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',
`status` enum('NEW','USING','LOGGED_IN','COMPLETED','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,
@@ -96,6 +93,12 @@ CREATE TABLE `link_task` (
`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),
`need_refresh` tinyint(1) NULL DEFAULT 0 COMMENT '是否需要刷新0否1是',
`refresh_time` datetime(3) NULL DEFAULT NULL COMMENT '刷新时间',
`qr_created_at` datetime(3) NULL DEFAULT NULL COMMENT '二维码创建时间',
`qr_expire_at` datetime(3) NULL DEFAULT NULL COMMENT '二维码过期时间',
`first_region_select_at` datetime(3) NULL DEFAULT NULL COMMENT '首次选区时间',
`completed_points` int UNSIGNED NULL DEFAULT NULL COMMENT '完成时的点数',
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,
@@ -103,9 +106,12 @@ CREATE TABLE `link_task` (
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,
INDEX `idx_need_refresh`(`need_refresh` ASC) USING BTREE,
INDEX `idx_qr_expire`(`qr_expire_at` ASC) USING BTREE,
INDEX `idx_first_region_select`(`first_region_select_at` 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;
) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for operation_log
@@ -124,7 +130,25 @@ CREATE TABLE `operation_log` (
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;
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for system_config
-- ----------------------------
DROP TABLE IF EXISTS `system_config`;
CREATE TABLE `system_config` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置键',
`config_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置值',
`config_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'STRING' COMMENT '配置类型STRING, INTEGER, BOOLEAN, JSON',
`description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '配置描述',
`is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否系统配置1是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 `uk_config_key`(`config_key` ASC) USING BTREE,
INDEX `idx_config_type`(`config_type` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Table structure for user_account
@@ -144,33 +168,4 @@ CREATE TABLE `user_account` (
CONSTRAINT `chk_points_nonneg` CHECK (`points_balance` >= 0)
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for system_config
-- ----------------------------
DROP TABLE IF EXISTS `system_config`;
CREATE TABLE `system_config` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`config_key` varchar(100) NOT NULL COMMENT '配置键',
`config_value` text NOT NULL COMMENT '配置值',
`config_type` varchar(50) NOT NULL DEFAULT 'STRING' COMMENT '配置类型STRING, INTEGER, BOOLEAN, JSON',
`description` varchar(500) NULL DEFAULT NULL COMMENT '配置描述',
`is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否系统配置1是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 `uk_config_key`(`config_key` ASC) USING BTREE,
INDEX `idx_config_type`(`config_type` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- 插入默认配置
INSERT INTO `system_config` (`config_key`, `config_value`, `config_type`, `description`, `is_system`) VALUES
('link.default_quantity', '50', 'INTEGER', '链接生成默认奖励点数', 1),
('link.refresh_interval', '300', 'INTEGER', '链接刷新间隔(秒)', 1),
('link.qr_expire_time', '600', 'INTEGER', '二维码过期时间(秒)', 1),
('link.max_times_per_batch', '100', 'INTEGER', '每批次最大刷奖励次数', 1),
('link.min_quantity', '10', 'INTEGER', '最小奖励点数', 1),
('link.max_quantity', '1000', 'INTEGER', '最大奖励点数', 1),
('script.server_url', 'http://36.138.184.60:12345', 'STRING', '脚本服务器地址', 1),
('script.qr_path_template', '/{machineId}/二维码.png', 'STRING', '二维码图片路径模板', 1);
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,176 @@
# 游戏完成检测实现文档
## 📋 功能概述
实现了两种方式来自动检测游戏是否完成,并在检测到完成时自动更新链接状态为 `COMPLETED`,同时记录完成时的点数。
## 🔧 实现方案
### **方案1: 定时检查空闲设备**
- **触发方式**: 每1分钟自动执行
- **检查逻辑**:
1. 获取所有空闲设备列表
2. 对每个空闲设备,查找是否有 `LOGGED_IN` 状态的链接任务使用该设备
3. 如果找到,则将该链接任务标记为 `COMPLETED`,并记录当前点数
### **方案2: 选区请求时检查**
- **触发方式**: 用户发起选区请求时
- **检查逻辑**:
1. 在分配新设备给用户前,先检查该设备是否空闲
2. 如果设备空闲且有之前的 `LOGGED_IN` 状态链接任务,则标记为完成
3. 然后继续正常的选区流程
## 🗄️ 数据库变更
### **1. link_task 表结构更新**
```sql
-- 添加完成时点数字段
ALTER TABLE `link_task`
ADD COLUMN `completed_points` int UNSIGNED NULL DEFAULT NULL COMMENT '完成时的点数'
AFTER `first_region_select_at`;
-- 更新状态枚举,添加 COMPLETED 状态
ALTER TABLE `link_task`
MODIFY COLUMN `status` enum('NEW','USING','LOGGED_IN','COMPLETED','REFUNDED','EXPIRED')
CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NEW';
```
### **2. 状态流转图**
```
NEW (新建)
USING (使用中)
LOGGED_IN (已登录)
COMPLETED (正常完成) ← 新增状态
```
**终态状态**: `COMPLETED`, `REFUNDED`, `EXPIRED`
## 💻 代码实现
### **1. 核心服务类**
#### **DeviceStatusCheckService**
- 负责设备状态检查和链接任务更新逻辑
- 解析设备状态响应数据 (f0: 点数, f1: 状态)
- 更新相关链接任务为完成状态
#### **DeviceStatusCheckTask**
- 定时任务类,每分钟执行一次
- 获取空闲设备列表并逐个检查
### **2. API 接口更新**
#### **ScriptClient**
```java
// 新增方法:获取特定设备状态
public Mono<Map<String, Object>> getDeviceStatus(String machineId)
```
#### **DeviceStatusService**
```java
// 新增方法:解析特定设备状态
public Map<String, Object> parseDeviceStatusForMachine(String jsonResponse, String machineId)
```
#### **LinkTaskMapper**
```java
// 新增方法根据设备ID和状态查询链接任务
List<LinkTask> findByMachineIdAndStatus(String machineId, String status);
```
### **3. 实体类更新**
#### **LinkTask**
```java
@TableField("completed_points")
private Integer completedPoints; // 完成时的点数
```
## 📊 数据处理流程
### **设备状态数据格式**
```json
{
"f0": {
"val": "900", // 当前点数
"time": "2025-08-27 15:49:04"
},
"f1": {
"val": "空闲", // 设备状态
"time": "2025-08-27 15:49:01"
}
}
```
### **完成检测逻辑**
1. **获取设备状态**: 调用 `readAllMsg?文件名=判断分数` 接口
2. **解析状态**: 提取 f0(点数) 和 f1(状态) 信息
3. **判断空闲**: 检查 f1.val 是否为 "空闲"
4. **查找任务**: 根据 machine_id 和 status='LOGGED_IN' 查询链接任务
5. **更新状态**: 设置 status='COMPLETED', completed_points=f0.val
## 🔧 配置说明
### **定时任务配置**
- **执行频率**: 每60秒 (`@Scheduled(fixedRate = 60000)`)
- **启用方式**: 主应用类添加 `@EnableScheduling` 注解
### **日志记录**
- **定时检查**: `DEBUG` 级别,避免日志过多
- **状态更新**: `INFO` 级别,记录重要操作
- **异常处理**: `WARN/ERROR` 级别,不影响主流程
## 🚀 部署说明
### **1. 数据库迁移**
```bash
# 执行迁移脚本
mysql -u username -p database_name < docs/database_migration_add_completed_points.sql
```
### **2. 应用重启**
- 新增的定时任务会在应用启动后自动运行
- 选区请求的检查逻辑会立即生效
### **3. 验证方法**
1. **查看日志**: 观察定时任务执行日志
2. **数据库检查**: 验证 `completed_points` 字段是否正确填充
3. **API 测试**: 测试选区请求是否正常工作
## 📈 监控指标
### **关键日志**
- `=== 开始定时检查空闲设备 ===`
- `发现 X 个空闲设备: [设备列表]`
- `链接任务 X (代码: X) 已标记为完成,完成点数: X`
### **异常监控**
- 设备状态获取失败
- JSON 解析异常
- 数据库更新失败
## 🔄 扩展性
### **支持更多设备状态**
- 可扩展 DeviceStatusInfo 类添加更多状态字段
- 支持不同的完成判断条件
### **自定义检查频率**
- 通过配置文件调整定时任务执行频率
- 支持不同环境使用不同配置
### **完成通知**
- 可扩展添加完成通知功能 (邮件、短信、webhook等)
- 支持完成统计和报表功能
## ⚠️ 注意事项
1. **性能考虑**: 定时任务频率不宜过高,避免对系统造成压力
2. **异常处理**: 单个设备检查失败不应影响其他设备的检查
3. **数据一致性**: 使用事务确保状态更新的原子性
4. **日志管理**: 合理设置日志级别,避免日志过多影响性能