fix: 修复LinkTaskMapper中target_score列不存在的SQL错误

- 移除LinkTaskMapper.xml中所有对不存在的target_score列的引用
- 修复因SQL查询不存在列导致的BadSqlGrammarException
- 添加TargetScoreResponse DTO用于目标点数响应
- 更新LinkController添加获取目标点数接口
- 优化UserLinkStatusResponse添加machineId字段
- 更新数据库schema文档

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zyh
2025-08-29 19:26:11 +08:00
parent 058970b95c
commit e7d36d5723
13 changed files with 344 additions and 278 deletions

View File

@@ -1,29 +0,0 @@
-- 数据库迁移脚本添加完成时点数字段和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

@@ -1,20 +0,0 @@
-- 数据库迁移脚本:添加 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

@@ -1,20 +0,0 @@
-- 数据库迁移脚本为link_task表添加完成图片字段
-- 执行时间2025-08-27
-- 说明添加completion_images字段用于存储任务完成时的4张图片URLJSON格式
-- 为link_task表添加完成图片字段
ALTER TABLE `link_task`
ADD COLUMN `completion_images` TEXT NULL DEFAULT NULL COMMENT '完成图片JSON存储4张图片URL' AFTER `completed_points`;
-- 验证表结构变更
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'link_task'
AND COLUMN_NAME = 'completion_images'
ORDER BY ORDINAL_POSITION;
-- 验证现有数据
SELECT COUNT(*) as total_tasks,
COUNT(completion_images) as tasks_with_images
FROM `link_task`;

View File

@@ -1,26 +0,0 @@
-- =====================================================
-- 添加设备空闲状态检测系统配置项
-- 创建日期: 2024-01-15
-- 描述: 添加可配置的设备空闲状态字符串,用于检测设备是否空闲
-- =====================================================
-- 插入设备空闲状态配置项
INSERT INTO `system_config` (`config_key`, `config_value`, `config_type`, `description`, `is_system`, `created_at`, `updated_at`)
VALUES
(
'device.idle_status',
'空闲',
'STRING',
'设备空闲状态的字符串标识,用于判断设备是否处于空闲状态',
1,
CURRENT_TIMESTAMP(3),
CURRENT_TIMESTAMP(3)
)
ON DUPLICATE KEY UPDATE
`config_value` = VALUES(`config_value`),
`description` = VALUES(`description`),
`is_system` = VALUES(`is_system`),
`updated_at` = CURRENT_TIMESTAMP(3);
-- 验证插入结果
SELECT * FROM `system_config` WHERE `config_key` = 'device.idle_status';

View File

@@ -1,34 +0,0 @@
-- 数据库迁移脚本为link_task表添加首次选区时间字段
-- 执行时间2025-01-XX
-- 说明:记录链接首次选区的准确时间,便于跟踪和分析
-- 为link_task表添加首次选区时间字段
ALTER TABLE `link_task`
ADD COLUMN `first_region_select_at` datetime(3) NULL DEFAULT NULL COMMENT '首次选区时间' AFTER `qr_expire_at`;
-- 添加索引以优化查询性能
ALTER TABLE `link_task`
ADD INDEX `idx_first_region_select` (`first_region_select_at` ASC);
-- 为现有USING状态的记录回填首次选区时间使用qr_created_at作为首次选区时间
UPDATE `link_task`
SET `first_region_select_at` = `qr_created_at`
WHERE `status` = 'USING'
AND `qr_created_at` IS NOT NULL
AND `first_region_select_at` IS NULL;
-- 验证表结构变更
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'link_task'
AND COLUMN_NAME = 'first_region_select_at'
ORDER BY ORDINAL_POSITION;
-- 验证数据回填结果
SELECT
COUNT(*) as total_using_links,
COUNT(first_region_select_at) as links_with_first_select_time,
COUNT(qr_created_at) as links_with_qr_time
FROM `link_task`
WHERE `status` = 'USING';

View File

@@ -1,33 +0,0 @@
-- 数据库迁移脚本为link_task表添加用户端需要的字段
-- 执行时间2025-01-XX
-- 说明:为支持用户端链接状态查询功能添加字段
-- 为link_task表添加新字段
ALTER TABLE `link_task`
ADD COLUMN `need_refresh` tinyint(1) NULL DEFAULT 0 COMMENT '是否需要刷新0否1是' AFTER `updated_at`,
ADD COLUMN `refresh_time` datetime(3) NULL DEFAULT NULL COMMENT '刷新时间' AFTER `need_refresh`,
ADD COLUMN `qr_created_at` datetime(3) NULL DEFAULT NULL COMMENT '二维码创建时间' AFTER `refresh_time`,
ADD COLUMN `qr_expire_at` datetime(3) NULL DEFAULT NULL COMMENT '二维码过期时间' AFTER `qr_created_at`;
-- 添加索引以优化查询性能
ALTER TABLE `link_task`
ADD INDEX `idx_need_refresh` (`need_refresh` ASC),
ADD INDEX `idx_qr_expire` (`qr_expire_at` ASC);
-- 更新系统配置,添加用户端相关配置
INSERT INTO `system_config` (`config_key`, `config_value`, `config_type`, `description`, `is_system`) VALUES
('user.qr_expire_seconds', '60', 'INTEGER', '用户端二维码有效期(秒)', 1),
('user.refresh_wait_seconds', '10', 'INTEGER', '用户端刷新等待时间(秒)', 1),
('user.link_expire_hours', '24', 'INTEGER', '用户端链接有效期(小时)', 1),
('user.assets_base_url', 'http://36.138.184.60:12345', 'STRING', '用户端静态资源基础URL', 1)
ON DUPLICATE KEY UPDATE
`config_value` = VALUES(`config_value`),
`updated_at` = CURRENT_TIMESTAMP(3);
-- 验证表结构变更
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'link_task'
AND COLUMN_NAME IN ('need_refresh', 'refresh_time', 'qr_created_at', 'qr_expire_at')
ORDER BY ORDINAL_POSITION;

View File

@@ -1,17 +1,17 @@
/* /*
Navicat Premium Dump SQL Navicat Premium Dump SQL
Source Server : localhost Source Server : 192.140.164.137_3306
Source Server Type : MySQL Source Server Type : MySQL
Source Server Version : 80043 (8.0.43) Source Server Version : 50744 (5.7.44-log)
Source Host : localhost:3306 Source Host : 192.140.164.137:3306
Source Schema : login_task_db Source Schema : login_task_db
Target Server Type : MySQL Target Server Type : MySQL
Target Server Version : 80043 (8.0.43) Target Server Version : 50744 (5.7.44-log)
File Encoding : 65001 File Encoding : 65001
Date: 27/08/2025 15:45:17 Date: 29/08/2025 19:16:57
*/ */
SET NAMES utf8mb4; SET NAMES utf8mb4;
@@ -22,150 +22,148 @@ SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `agent_points_tx`; DROP TABLE IF EXISTS `agent_points_tx`;
CREATE TABLE `agent_points_tx` ( CREATE TABLE `agent_points_tx` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`account_id` bigint UNSIGNED NOT NULL, `account_id` bigint(20) UNSIGNED NOT NULL,
`type` enum('ADD','DEDUCT') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `type` enum('ADD','DEDUCT') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`before_points` bigint UNSIGNED NOT NULL, `before_points` bigint(20) UNSIGNED NOT NULL,
`delta_points` bigint NOT NULL, `delta_points` bigint(20) NOT NULL,
`after_points` bigint UNSIGNED NOT NULL, `after_points` bigint(20) UNSIGNED NOT NULL,
`reason` enum('create_links','manual','refund_no_rollback','other') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'other', `reason` enum('create_links','manual','refund_no_rollback','other') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'other',
`ref_id` bigint UNSIGNED NULL DEFAULT NULL, `ref_id` bigint(20) UNSIGNED NULL DEFAULT NULL,
`operator_id` bigint UNSIGNED NULL DEFAULT NULL, `operator_id` bigint(20) UNSIGNED NULL DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_apx_account_time`(`account_id` ASC, `created_at` ASC) USING BTREE, INDEX `idx_apx_account_time`(`account_id`, `created_at`) USING BTREE,
INDEX `fk_apx_operator`(`operator_id` ASC) USING BTREE, INDEX `fk_apx_operator`(`operator_id`) USING BTREE,
CONSTRAINT `fk_apx_account` FOREIGN KEY (`account_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 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 CONSTRAINT `fk_apx_operator` FOREIGN KEY (`operator_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------
-- Table structure for announcement -- Table structure for announcement
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `announcement`; DROP TABLE IF EXISTS `announcement`;
CREATE TABLE `announcement` ( CREATE TABLE `announcement` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`enabled` tinyint(1) NOT NULL DEFAULT 1, `enabled` tinyint(1) NOT NULL DEFAULT 1,
`jump_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `jump_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `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), `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------
-- Table structure for link_batch -- Table structure for link_batch
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `link_batch`; DROP TABLE IF EXISTS `link_batch`;
CREATE TABLE `link_batch` ( CREATE TABLE `link_batch` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`agent_id` bigint UNSIGNED NOT NULL, `agent_id` bigint(20) UNSIGNED NOT NULL,
`quantity` int UNSIGNED NOT NULL, `quantity` int(10) UNSIGNED NOT NULL,
`times` int UNSIGNED NOT NULL, `times` int(10) UNSIGNED NOT NULL,
`operator_id` bigint UNSIGNED NULL DEFAULT NULL, `operator_id` bigint(20) UNSIGNED NULL DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_lb_agent_time`(`agent_id` ASC, `created_at` ASC) USING BTREE, INDEX `idx_lb_agent_time`(`agent_id`, `created_at`) USING BTREE,
INDEX `fk_lb_operator`(`operator_id` ASC) USING BTREE, INDEX `fk_lb_operator`(`operator_id`) USING BTREE,
CONSTRAINT `fk_lb_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 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 `fk_lb_operator` FOREIGN KEY (`operator_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
CONSTRAINT `chk_lb_quantity_pos` CHECK (`quantity` > 0), ) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
CONSTRAINT `chk_lb_times_pos` CHECK (`times` > 0)
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ---------------------------- -- ----------------------------
-- Table structure for link_task -- Table structure for link_task
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `link_task`; DROP TABLE IF EXISTS `link_task`;
CREATE TABLE `link_task` ( CREATE TABLE `link_task` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`batch_id` bigint UNSIGNED NOT NULL, `batch_id` bigint(20) UNSIGNED NOT NULL,
`agent_id` bigint UNSIGNED NOT NULL, `agent_id` bigint(20) UNSIGNED NOT NULL,
`code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`token_hash` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `token_hash` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`expire_at` datetime(3) NOT NULL, `expire_at` datetime(3) NOT NULL,
`status` enum('NEW','USING','LOGGED_IN','COMPLETED','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_unicode_ci NOT NULL DEFAULT 'NEW',
`region` enum('Q','V') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `region` enum('Q','V') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`machine_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `machine_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`login_at` datetime(3) NULL DEFAULT NULL, `login_at` datetime(3) NULL DEFAULT NULL,
`refund_at` datetime(3) NULL DEFAULT NULL, `refund_at` datetime(3) NULL DEFAULT NULL,
`revoked_at` datetime(3) NULL DEFAULT NULL, `revoked_at` datetime(3) NULL DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `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), `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是', `need_refresh` tinyint(1) NULL DEFAULT 0 COMMENT '是否需要刷新0否1是',
`refresh_time` datetime(3) NULL DEFAULT NULL COMMENT '刷新时间', `refresh_time` datetime(3) NULL DEFAULT NULL COMMENT '刷新时间',
`qr_created_at` datetime(3) NULL DEFAULT NULL COMMENT '二维码创建时间', `qr_created_at` datetime(3) NULL DEFAULT NULL COMMENT '二维码创建时间',
`qr_expire_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 '首次选区时间', `first_region_select_at` datetime(3) NULL DEFAULT NULL COMMENT '首次选区时间',
`completed_points` int UNSIGNED NULL DEFAULT NULL COMMENT '完成时的点数', `completed_points` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '完成时的点数',
PRIMARY KEY (`id`) USING BTREE, `completion_images` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '完成图片JSON存储4张图片URL',
UNIQUE INDEX `uk_code_no`(`code_no` ASC) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_token_hash`(`token_hash` ASC) USING BTREE, UNIQUE INDEX `uk_code_no`(`code_no`) USING BTREE,
INDEX `idx_agent_status`(`agent_id` ASC, `status` ASC) USING BTREE, UNIQUE INDEX `uk_token_hash`(`token_hash`) USING BTREE,
INDEX `idx_expire_at`(`expire_at` ASC) USING BTREE, INDEX `idx_agent_status`(`agent_id`, `status`) USING BTREE,
INDEX `idx_created_at`(`created_at` ASC) USING BTREE, INDEX `idx_expire_at`(`expire_at`) USING BTREE,
INDEX `fk_lt_batch`(`batch_id` ASC) USING BTREE, INDEX `idx_created_at`(`created_at`) USING BTREE,
INDEX `idx_need_refresh`(`need_refresh` ASC) USING BTREE, INDEX `fk_lt_batch`(`batch_id`) USING BTREE,
INDEX `idx_qr_expire`(`qr_expire_at` ASC) USING BTREE, INDEX `idx_need_refresh`(`need_refresh`) USING BTREE,
INDEX `idx_first_region_select`(`first_region_select_at` ASC) USING BTREE, INDEX `idx_qr_expire`(`qr_expire_at`) USING BTREE,
CONSTRAINT `fk_lt_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, INDEX `idx_first_region_select`(`first_region_select_at`) USING BTREE,
CONSTRAINT `fk_lt_batch` FOREIGN KEY (`batch_id`) REFERENCES `link_batch` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT CONSTRAINT `fk_lt_agent` FOREIGN KEY (`agent_id`) REFERENCES `user_account` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; CONSTRAINT `fk_lt_batch` FOREIGN KEY (`batch_id`) REFERENCES `link_batch` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 78 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------
-- Table structure for operation_log -- Table structure for operation_log
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `operation_log`; DROP TABLE IF EXISTS `operation_log`;
CREATE TABLE `operation_log` ( CREATE TABLE `operation_log` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`actor_type` enum('admin','agent','system','user') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `actor_type` enum('admin','agent','system','user') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`actor_id` bigint UNSIGNED NULL DEFAULT NULL, `actor_id` bigint(20) UNSIGNED NULL DEFAULT NULL,
`code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `code_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`op` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `op` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`detail` json NULL, `detail` json NULL,
`client_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `client_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_log_code_time`(`code_no` ASC, `created_at` ASC) USING BTREE, INDEX `idx_log_code_time`(`code_no`, `created_at`) USING BTREE,
INDEX `idx_log_time`(`created_at` ASC) USING BTREE INDEX `idx_log_time`(`created_at`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------
-- Table structure for system_config -- Table structure for system_config
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `system_config`; DROP TABLE IF EXISTS `system_config`;
CREATE TABLE `system_config` ( CREATE TABLE `system_config` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置键', `config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键',
`config_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置值', `config_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_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', `config_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_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 '配置描述', `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '配置描述',
`is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否系统配置1是0否', `is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否系统配置1是0否',
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `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), `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_config_key`(`config_key` ASC) USING BTREE, UNIQUE INDEX `uk_config_key`(`config_key`) USING BTREE,
INDEX `idx_config_type`(`config_type` ASC) USING BTREE INDEX `idx_config_type`(`config_type`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; ) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------
-- Table structure for user_account -- Table structure for user_account
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `user_account`; DROP TABLE IF EXISTS `user_account`;
CREATE TABLE `user_account` ( CREATE TABLE `user_account` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_type` enum('ADMIN','AGENT') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `user_type` enum('ADMIN','AGENT') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`password_hash` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `password_hash` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`status` enum('ENABLED','DISABLED') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'ENABLED', `status` enum('ENABLED','DISABLED') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'ENABLED',
`points_balance` bigint UNSIGNED NOT NULL DEFAULT 0, `points_balance` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `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), `updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `username`(`username` ASC) USING BTREE, UNIQUE INDEX `username`(`username`) USING BTREE
CONSTRAINT `chk_points_nonneg` CHECK (`points_balance` >= 0) ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -12,6 +12,7 @@ import com.gameplatform.server.model.dto.link.PollLoginResponse;
import com.gameplatform.server.model.dto.link.SelectRegionRequest; import com.gameplatform.server.model.dto.link.SelectRegionRequest;
import com.gameplatform.server.model.dto.link.SelectRegionResponse; import com.gameplatform.server.model.dto.link.SelectRegionResponse;
import com.gameplatform.server.model.dto.link.UserLinkStatusResponse; import com.gameplatform.server.model.dto.link.UserLinkStatusResponse;
import com.gameplatform.server.model.dto.link.TargetScoreResponse;
import com.gameplatform.server.service.link.LinkGenerationService; import com.gameplatform.server.service.link.LinkGenerationService;
import com.gameplatform.server.service.link.LinkListService; import com.gameplatform.server.service.link.LinkListService;
import com.gameplatform.server.service.link.LinkStatusService; import com.gameplatform.server.service.link.LinkStatusService;
@@ -484,6 +485,31 @@ public Mono<Boolean> deleteLink(@PathVariable("codeNo") String codeNo, Authentic
} }
}); });
} }
/**
* 获取目标点数接口
*/
@GetMapping("/target-score")
@Operation(summary = "获取目标点数", description = "根据链接编号获取目标点数,如果返回的是数字则保存到数据库,否则提示网络繁忙")
public Mono<TargetScoreResponse> getTargetScore(@RequestParam("codeNo") String codeNo) {
log.info("=== 开始获取目标点数 ===");
log.info("请求参数: codeNo={}", codeNo);
return linkStatusService.getTargetScore(codeNo)
.doOnSuccess(response -> {
if (response.isSuccess()) {
log.info("目标点数获取成功: codeNo={}, machineId={}, targetScore={}",
response.getCodeNo(), response.getMachineId(), response.getCompletedPoints());
} else {
log.warn("目标点数获取失败: codeNo={}, machineId={}, error={}",
response.getCodeNo(), response.getMachineId(), response.getErrorMessage());
}
})
.doOnError(error -> {
log.error("获取目标点数时发生异常: codeNo={}, error={}",
codeNo, error.getMessage(), error);
});
}
} }

View File

@@ -352,7 +352,6 @@ public class QrProxyController {
response.setTimes(linkBatch.getTimes()); response.setTimes(linkBatch.getTimes());
response.setTotalPoints(linkBatch.getQuantity() * linkBatch.getTimes()); response.setTotalPoints(linkBatch.getQuantity() * linkBatch.getTimes());
response.setCompletedPoints(linkTask.getCompletedPoints()); response.setCompletedPoints(linkTask.getCompletedPoints());
// 设置游戏区域信息 // 设置游戏区域信息
response.setRegion(linkTask.getRegion()); response.setRegion(linkTask.getRegion());
response.setRegionDesc(getRegionDescription(linkTask.getRegion())); response.setRegionDesc(getRegionDescription(linkTask.getRegion()));

View File

@@ -0,0 +1,105 @@
package com.gameplatform.server.model.dto.link;
/**
* 目标点数响应DTO
*/
public class TargetScoreResponse {
/**
* 是否成功获取目标点数
*/
private boolean success;
/**
* 完成点数值当success为true时有效
*/
private Integer completedPoints;
/**
* 错误消息当success为false时
*/
private String errorMessage;
/**
* 设备ID
*/
private String machineId;
/**
* 链接编号
*/
private String codeNo;
public TargetScoreResponse() {
}
public TargetScoreResponse(boolean success, Integer completedPoints, String errorMessage) {
this.success = success;
this.completedPoints = completedPoints;
this.errorMessage = errorMessage;
}
/**
* 成功响应
*/
public static TargetScoreResponse success(String codeNo, String machineId, Integer completedPoints) {
TargetScoreResponse response = new TargetScoreResponse();
response.setSuccess(true);
response.setCodeNo(codeNo);
response.setMachineId(machineId);
response.setCompletedPoints(completedPoints);
return response;
}
/**
* 失败响应
*/
public static TargetScoreResponse error(String codeNo, String machineId, String errorMessage) {
TargetScoreResponse response = new TargetScoreResponse();
response.setSuccess(false);
response.setCodeNo(codeNo);
response.setMachineId(machineId);
response.setErrorMessage(errorMessage);
return response;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public Integer getCompletedPoints() {
return completedPoints;
}
public void setCompletedPoints(Integer completedPoints) {
this.completedPoints = completedPoints;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getMachineId() {
return machineId;
}
public void setMachineId(String machineId) {
this.machineId = machineId;
}
public String getCodeNo() {
return codeNo;
}
public void setCodeNo(String codeNo) {
this.codeNo = codeNo;
}
}

View File

@@ -8,7 +8,13 @@ public class UserLinkStatusResponse {
@Schema(description = "链接状态", example = "NEW", allowableValues = {"NEW", "USING", "LOGGED_IN", "COMPLETED", "REFUNDED", "EXPIRED"}) @Schema(description = "链接状态", example = "NEW", allowableValues = {"NEW", "USING", "LOGGED_IN", "COMPLETED", "REFUNDED", "EXPIRED"})
private String status; private String status;
@Schema(description = "机器ID")
private String machineId;
// Getter and Setter // Getter and Setter
public String getStatus() { return status; } public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; } public void setStatus(String status) { this.status = status; }
public String getMachineId() { return machineId; }
public void setMachineId(String machineId) { this.machineId = machineId; }
} }

View File

@@ -68,6 +68,8 @@ public class LinkTask {
@TableField("completion_images") @TableField("completion_images")
private String completionImages; // JSON格式存储4张图片URL private String completionImages; // JSON格式存储4张图片URL
public Long getId() { return id; } public Long getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(Long id) { this.id = id; }
@@ -130,4 +132,6 @@ public class LinkTask {
public String getCompletionImages() { return completionImages; } public String getCompletionImages() { return completionImages; }
public void setCompletionImages(String completionImages) { this.completionImages = completionImages; } public void setCompletionImages(String completionImages) { this.completionImages = completionImages; }
} }

View File

@@ -8,6 +8,7 @@ import com.gameplatform.server.model.dto.link.LinkStatusResponse;
import com.gameplatform.server.model.dto.link.PollLoginResponse; import com.gameplatform.server.model.dto.link.PollLoginResponse;
import com.gameplatform.server.model.dto.link.SelectRegionResponse; import com.gameplatform.server.model.dto.link.SelectRegionResponse;
import com.gameplatform.server.model.dto.link.UserLinkStatusResponse; import com.gameplatform.server.model.dto.link.UserLinkStatusResponse;
import com.gameplatform.server.model.dto.link.TargetScoreResponse;
import com.gameplatform.server.model.entity.agent.LinkBatch; import com.gameplatform.server.model.entity.agent.LinkBatch;
import com.gameplatform.server.model.entity.agent.LinkTask; import com.gameplatform.server.model.entity.agent.LinkTask;
@@ -521,7 +522,7 @@ public class LinkStatusService {
// 如果状态是USING返回NEW给用户端 // 如果状态是USING返回NEW给用户端
String statusToReturn = "USING".equals(linkTask.getStatus()) ? "NEW" : linkTask.getStatus(); String statusToReturn = "USING".equals(linkTask.getStatus()) ? "NEW" : linkTask.getStatus();
response.setStatus(statusToReturn); response.setStatus(statusToReturn);
response.setMachineId(linkTask.getMachineId());
return response; return response;
} }
@@ -900,4 +901,93 @@ public class LinkStatusService {
return null; return null;
} }
} }
/**
* 获取目标点数
* @param codeNo 链接编号
* @return 目标点数响应
*/
public Mono<TargetScoreResponse> getTargetScore(String codeNo) {
return Mono.fromCallable(() -> doGetTargetScore(codeNo))
.subscribeOn(Schedulers.boundedElastic());
}
private TargetScoreResponse doGetTargetScore(String codeNo) {
log.info("=== 开始获取目标点数 ===");
log.info("链接编号: {}", codeNo);
try {
// 1. 验证参数
if (codeNo == null || codeNo.trim().isEmpty()) {
log.error("参数验证失败: codeNo不能为空");
return TargetScoreResponse.error(codeNo, null, "链接编号不能为空");
}
// 2. 查询链接任务获取machineId
LinkTask linkTask = linkTaskMapper.findByCodeNo(codeNo.trim());
if (linkTask == null) {
log.error("链接任务不存在: codeNo={}", codeNo);
return TargetScoreResponse.error(codeNo, null, "链接不存在");
}
String machineId = linkTask.getMachineId();
if (machineId == null || machineId.trim().isEmpty()) {
log.error("链接未关联设备: codeNo={}", codeNo);
return TargetScoreResponse.error(codeNo, null, "链接未关联设备");
}
log.info("查询到设备ID: codeNo={}, machineId={}", codeNo, machineId);
// 3. 调用脚本端获取目标分数
log.info("调用脚本端获取目标分数: machineId={}", machineId);
String targetScoreStr = scriptClient.getTargetScore(machineId).block();
log.info("脚本端返回结果: machineId={}, result={}", machineId, targetScoreStr);
// 4. 解析返回结果
if (targetScoreStr == null || targetScoreStr.trim().isEmpty()) {
log.warn("脚本端返回空结果: machineId={}", machineId);
return TargetScoreResponse.error(codeNo, machineId, "网络繁忙,稍后再试");
}
String trimmedResult = targetScoreStr.trim();
// 检查是否为数字
try {
Integer targetScore = Integer.parseInt(trimmedResult);
log.info("解析到数字目标分数: {}", targetScore);
// 5. 保存到数据库
linkTask.setCompletedPoints(targetScore);
linkTask.setUpdatedAt(LocalDateTime.now());
int updateResult = linkTaskMapper.update(linkTask);
if (updateResult > 0) {
log.info("目标分数保存成功: codeNo={}, machineId={}, targetScore={}",
codeNo, machineId, targetScore);
return TargetScoreResponse.success(codeNo, machineId, targetScore);
} else {
log.error("目标分数保存失败: codeNo={}, machineId={}, targetScore={}",
codeNo, machineId, targetScore);
return TargetScoreResponse.error(codeNo, machineId, "保存目标分数失败");
}
} catch (NumberFormatException e) {
// 不是数字,检查特殊状态
log.info("脚本端返回非数字结果: {}", trimmedResult);
if ("空的".equals(trimmedResult) || "空闲".equals(trimmedResult) || "已运行".equals(trimmedResult)) {
log.info("设备状态为: {}", trimmedResult);
return TargetScoreResponse.error(codeNo, machineId, "网络繁忙,稍后再试");
} else {
log.warn("未知的返回结果: {}", trimmedResult);
return TargetScoreResponse.error(codeNo, machineId, "网络繁忙,稍后再试");
}
}
} catch (Exception e) {
log.error("=== 获取目标点数失败 ===");
log.error("错误详情: codeNo={}, error={}", codeNo, e.getMessage(), e);
return TargetScoreResponse.error(codeNo, null, "系统异常,请稍后再试");
}
}
} }