diff --git a/logs/server.2025-09-20.0.log.gz b/logs/server.2025-09-20.0.log.gz new file mode 100644 index 0000000..b5bd8b3 Binary files /dev/null and b/logs/server.2025-09-20.0.log.gz differ diff --git a/src/main/java/com/gameplatform/server/controller/ScriptOperationLogController.java b/src/main/java/com/gameplatform/server/controller/ScriptOperationLogController.java new file mode 100644 index 0000000..8043d3f --- /dev/null +++ b/src/main/java/com/gameplatform/server/controller/ScriptOperationLogController.java @@ -0,0 +1,72 @@ +package com.gameplatform.server.controller; + +import com.gameplatform.server.mapper.log.ScriptOperationLogMapper; +import com.gameplatform.server.model.entity.log.ScriptOperationLog; +import com.gameplatform.server.model.enums.ScriptOperationType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * 脚本操作日志查询接口 + */ +@RestController +@RequestMapping("/api/admin/script-operation-log") +@Slf4j +public class ScriptOperationLogController { + + @Autowired + private ScriptOperationLogMapper logMapper; + + /** + * 根据设备ID查询操作记录 + */ + // @GetMapping("/machine/{machineId}") + // public List getByMachineId(@PathVariable String machineId, + // @RequestParam(defaultValue = "10") Integer limit) { + // return logMapper.findByMachineId(machineId, limit); + // } + + // /** + // * 根据操作类型查询记录 + // */ + // @GetMapping("/type/{operationType}") + // public List getByOperationType(@PathVariable ScriptOperationType operationType, + // @RequestParam(defaultValue = "10") Integer limit) { + // return logMapper.findByOperationType(operationType, limit); + // } + + // /** + // * 查询失败的操作记录 + // */ + // @GetMapping("/failed") + // public List getFailedOperations(@RequestParam(defaultValue = "10") Integer limit) { + // LocalDateTime yesterday = LocalDateTime.now().minusDays(1); + // LocalDateTime now = LocalDateTime.now(); + // return logMapper.findFailedOperations(yesterday, now, limit); + // } + + // /** + // * 获取操作统计信息 + // */ + // @GetMapping("/statistics") + // public List> getStatistics(@RequestParam(defaultValue = "1") Integer days) { + // LocalDateTime startTime = LocalDateTime.now().minusDays(days); + // LocalDateTime endTime = LocalDateTime.now(); + // return logMapper.getOperationStatistics(startTime, endTime); + // } + + // /** + // * 查询最近的操作记录 + // */ + // @GetMapping("/recent") + // public List getRecentOperations(@RequestParam(defaultValue = "20") Integer limit) { + // LocalDateTime yesterday = LocalDateTime.now().minusDays(1); + // LocalDateTime now = LocalDateTime.now(); + // return logMapper.findByTimeRange(yesterday, now, limit); + // } +} diff --git a/src/main/java/com/gameplatform/server/device/DeviceStats.java b/src/main/java/com/gameplatform/server/device/DeviceStats.java index 08ef9f2..07a3c86 100644 --- a/src/main/java/com/gameplatform/server/device/DeviceStats.java +++ b/src/main/java/com/gameplatform/server/device/DeviceStats.java @@ -308,7 +308,8 @@ public class DeviceStats { int completed = 0; for (LinkTask task : loggedInTasks) { LocalDateTime loginAt = task.getLoginAt(); - boolean over3m = loginAt != null && loginAt.isBefore(now.minusMinutes(3)); + // 检查登录时间到现在是否已经超过3分钟 + boolean over3m = loginAt != null && Duration.between(loginAt, now).toMinutes() >= 3; if (!over3m) { continue; } diff --git a/src/main/java/com/gameplatform/server/mapper/log/ScriptOperationLogMapper.java b/src/main/java/com/gameplatform/server/mapper/log/ScriptOperationLogMapper.java new file mode 100644 index 0000000..6e2da40 --- /dev/null +++ b/src/main/java/com/gameplatform/server/mapper/log/ScriptOperationLogMapper.java @@ -0,0 +1,76 @@ +package com.gameplatform.server.mapper.log; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gameplatform.server.model.entity.log.ScriptOperationLog; +import com.gameplatform.server.model.enums.ScriptOperationType; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 脚本操作记录Mapper + */ +@Mapper +public interface ScriptOperationLogMapper extends BaseMapper { + + /** + * 插入操作记录 + */ + int insert(ScriptOperationLog log); + + /** + * 更新操作记录 + */ + int update(ScriptOperationLog log); + + /** + * 根据ID查询 + */ + ScriptOperationLog findById(@Param("id") Long id); + + /** + * 根据设备ID查询操作记录 + */ + List findByMachineId(@Param("machineId") String machineId, + @Param("limit") Integer limit); + + /** + * 根据操作类型查询记录 + */ + List findByOperationType(@Param("operationType") ScriptOperationType operationType, + @Param("limit") Integer limit); + + /** + * 根据时间范围查询操作记录 + */ + List findByTimeRange(@Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime, + @Param("limit") Integer limit); + + /** + * 查询某个设备特定操作类型的记录 + */ + List findByMachineIdAndOperationType(@Param("machineId") String machineId, + @Param("operationType") ScriptOperationType operationType, + @Param("limit") Integer limit); + + /** + * 查询失败的操作记录 + */ + List findFailedOperations(@Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime, + @Param("limit") Integer limit); + + /** + * 统计某个时间段内各操作类型的成功率 + */ + List> getOperationStatistics(@Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime); + + /** + * 删除指定时间之前的记录(用于数据清理) + */ + int deleteOldRecords(@Param("beforeTime") LocalDateTime beforeTime); +} diff --git a/src/main/java/com/gameplatform/server/model/entity/log/ScriptOperationLog.java b/src/main/java/com/gameplatform/server/model/entity/log/ScriptOperationLog.java new file mode 100644 index 0000000..fa10f23 --- /dev/null +++ b/src/main/java/com/gameplatform/server/model/entity/log/ScriptOperationLog.java @@ -0,0 +1,205 @@ +package com.gameplatform.server.model.entity.log; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.gameplatform.server.model.enums.ScriptOperationType; + +import java.time.LocalDateTime; + +/** + * 脚本操作记录实体 + */ +@TableName("script_operation_log") +public class ScriptOperationLog { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @TableField("operation_type") + private ScriptOperationType operationType; + + @TableField("machine_id") + private String machineId; + + @TableField("request_url") + private String requestUrl; + + @TableField("request_params") + private String requestParams; // JSON字符串 + + @TableField("response_result") + private String responseResult; + + @TableField("success") + private Boolean success; + + @TableField("error_message") + private String errorMessage; + + @TableField("duration_ms") + private Integer durationMs; + + @TableField("request_time") + private LocalDateTime requestTime; + + @TableField("response_time") + private LocalDateTime responseTime; + + @TableField("created_at") + private LocalDateTime createdAt; + + @TableField("updated_at") + private LocalDateTime updatedAt; + + // 构造函数 + public ScriptOperationLog() {} + + public ScriptOperationLog(ScriptOperationType operationType, String machineId, String requestUrl) { + this.operationType = operationType; + this.machineId = machineId; + this.requestUrl = requestUrl; + this.requestTime = LocalDateTime.now(); + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + this.success = false; // 默认失败,成功时再更新 + } + + // Getter和Setter方法 + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public ScriptOperationType getOperationType() { + return operationType; + } + + public void setOperationType(ScriptOperationType operationType) { + this.operationType = operationType; + } + + public String getMachineId() { + return machineId; + } + + public void setMachineId(String machineId) { + this.machineId = machineId; + } + + public String getRequestUrl() { + return requestUrl; + } + + public void setRequestUrl(String requestUrl) { + this.requestUrl = requestUrl; + } + + public String getRequestParams() { + return requestParams; + } + + public void setRequestParams(String requestParams) { + this.requestParams = requestParams; + } + + public String getResponseResult() { + return responseResult; + } + + public void setResponseResult(String responseResult) { + this.responseResult = responseResult; + } + + public Boolean getSuccess() { + return success; + } + + public void setSuccess(Boolean success) { + this.success = success; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public Integer getDurationMs() { + return durationMs; + } + + public void setDurationMs(Integer durationMs) { + this.durationMs = durationMs; + } + + public LocalDateTime getRequestTime() { + return requestTime; + } + + public void setRequestTime(LocalDateTime requestTime) { + this.requestTime = requestTime; + } + + public LocalDateTime getResponseTime() { + return responseTime; + } + + public void setResponseTime(LocalDateTime responseTime) { + this.responseTime = responseTime; + } + + 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; + } + + // 便捷方法:设置成功响应 + public void setSuccessResponse(String result, LocalDateTime responseTime, long durationMs) { + this.responseResult = result; + this.success = true; + this.responseTime = responseTime; + this.durationMs = (int) durationMs; + this.updatedAt = LocalDateTime.now(); + } + + // 便捷方法:设置失败响应 + public void setFailureResponse(String errorMessage, LocalDateTime responseTime, long durationMs) { + this.errorMessage = errorMessage; + this.success = false; + this.responseTime = responseTime; + this.durationMs = (int) durationMs; + this.updatedAt = LocalDateTime.now(); + } + + @Override + public String toString() { + return "ScriptOperationLog{" + + "id=" + id + + ", operationType=" + operationType + + ", machineId='" + machineId + '\'' + + ", requestUrl='" + requestUrl + '\'' + + ", success=" + success + + ", durationMs=" + durationMs + + ", requestTime=" + requestTime + + ", responseTime=" + responseTime + + '}'; + } +} diff --git a/src/main/java/com/gameplatform/server/model/enums/ScriptOperationType.java b/src/main/java/com/gameplatform/server/model/enums/ScriptOperationType.java new file mode 100644 index 0000000..60bdfef --- /dev/null +++ b/src/main/java/com/gameplatform/server/model/enums/ScriptOperationType.java @@ -0,0 +1,21 @@ +package com.gameplatform.server.model.enums; + +/** + * 脚本操作类型枚举 + */ +public enum ScriptOperationType { + SELECT_REGION("选区操作"), + REFRESH("判断刷新"), + SAVE_TOTAL_TIMES("保存总次数"), + REFUND_ORDER("退单操作"); + + private final String description; + + ScriptOperationType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/com/gameplatform/server/service/external/ScriptClient.java b/src/main/java/com/gameplatform/server/service/external/ScriptClient.java index 4924af1..21a5248 100644 --- a/src/main/java/com/gameplatform/server/service/external/ScriptClient.java +++ b/src/main/java/com/gameplatform/server/service/external/ScriptClient.java @@ -2,7 +2,9 @@ package com.gameplatform.server.service.external; import com.gameplatform.server.annotation.RepeatCall; import com.gameplatform.server.model.dto.device.DeviceStatusResponse; +import com.gameplatform.server.model.entity.log.ScriptOperationLog; import com.gameplatform.server.service.device.DeviceStatusService; +import com.gameplatform.server.service.log.ScriptOperationLogService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -27,6 +29,7 @@ public class ScriptClient { private final String appBaseUrl; private final DeviceStatusService deviceStatusService; private final ApplicationEventPublisher eventPublisher; + private final ScriptOperationLogService operationLogService; public ScriptClient( @Value("${script.base-url}") String baseUrl, @@ -35,13 +38,15 @@ public class ScriptClient { @Value("${script.read-timeout-ms:5000}") int readTimeoutMs, @Value("${app.base-url}") String appBaseUrl, DeviceStatusService deviceStatusService, - ApplicationEventPublisher eventPublisher + ApplicationEventPublisher eventPublisher, + ScriptOperationLogService operationLogService ) { this.baseUrl = baseUrl; this.apiBaseUrl = apiBaseUrl; this.appBaseUrl = appBaseUrl; this.deviceStatusService = deviceStatusService; this.eventPublisher = eventPublisher; + this.operationLogService = operationLogService; this.webClient = WebClient.builder() .baseUrl(baseUrl) .exchangeStrategies(ExchangeStrategies.builder() @@ -188,11 +193,16 @@ public class ScriptClient { log.warn("选区操作失败: 区域={} 必须是Q或V", region); return Mono.just("选区操作失败"); } + // 构建选区URL,使用设备编号作为参数名,区域作为参数值 // 示例: {apiBaseUrl}/yijianwan_netfile/saveMsg?文件名=判断系统&f1=Q String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断系统&%s=%s", deviceId, region); log.info("选区操作: 设备={}, 区域={}, url={}", deviceId, region, url); + // 创建操作日志记录 + ScriptOperationLog operationLog = operationLogService.logSelectRegion(deviceId, url, region); + long startTime = System.currentTimeMillis(); + return webClient.get() // 根据您的curl示例,这应该是GET请求 .uri(url) .accept(MediaType.TEXT_PLAIN) @@ -201,9 +211,13 @@ public class ScriptClient { .timeout(Duration.ofSeconds(10)) .doOnSuccess(result -> { log.info("选区操作成功: 设备={}, 区域={}, 结果={}", deviceId, region, result); + // 记录成功响应 + operationLogService.recordSuccess(operationLog, result, startTime); }) .doOnError(e -> { log.error("选区操作失败: 设备={}, 区域={}, 错误={}", deviceId, region, e.toString()); + // 记录失败响应 + operationLogService.recordFailure(operationLog, e.toString(), startTime); }); } @@ -216,14 +230,27 @@ public class ScriptClient { public Mono refresh(String machineId) { String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断刷新&%s=刷新", machineId); log.info("调用判断刷新接口: {}", url); + + // 创建操作日志记录 + ScriptOperationLog operationLog = operationLogService.logRefresh(machineId, url); + long startTime = System.currentTimeMillis(); + return webClient.get() .uri(url) .accept(MediaType.TEXT_PLAIN) .retrieve() .bodyToMono(String.class) .timeout(Duration.ofSeconds(10)) - .doOnSuccess(result -> log.info("判断刷新接口调用成功: result={}", result)) - .doOnError(e -> log.warn("判断刷新接口调用失败: {}", e.toString())); + .doOnSuccess(result -> { + log.info("判断刷新接口调用成功: result={}", result); + // 记录成功响应 + operationLogService.recordSuccess(operationLog, result, startTime); + }) + .doOnError(e -> { + log.warn("判断刷新接口调用失败: {}", e.toString()); + // 记录失败响应 + operationLogService.recordFailure(operationLog, e.toString(), startTime); + }); } /** @@ -346,22 +373,36 @@ public class ScriptClient { /** * 保存总次数(使用f4参数格式) + * @param machineId 设备ID * @param times 总次数 * @return 保存结果 */ @RepeatCall(times = 3, description = "保存总次数") - public Mono saveTotalTimes(String meachainId,int times) { - String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=总次数&%s=%d", meachainId,times); + public Mono saveTotalTimes(String machineId, int times) { + String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=总次数&%s=%d", machineId, times); log.info("保存刷副本的次数的url: {}", url); log.info("开始调用保存总次数接口: times={}, url={}", times, url); + + // 创建操作日志记录 + ScriptOperationLog operationLog = operationLogService.logSaveTotalTimes(machineId, url, times); + long startTime = System.currentTimeMillis(); + return webClient.get() .uri(url) .accept(MediaType.TEXT_PLAIN) .retrieve() .bodyToMono(String.class) .timeout(Duration.ofSeconds(10)) - .doOnSuccess(result -> log.info("保存总次数接口调用成功: url={}, result={}", url, result)) - .doOnError(e -> log.warn("保存总次数接口调用失败: times={}, error={}", times, e.toString())); + .doOnSuccess(result -> { + log.info("保存总次数接口调用成功: url={}, result={}", url, result); + // 记录成功响应 + operationLogService.recordSuccess(operationLog, result, startTime); + }) + .doOnError(e -> { + log.warn("保存总次数接口调用失败: times={}, error={}", times, e.toString()); + // 记录失败响应 + operationLogService.recordFailure(operationLog, e.toString(), startTime); + }); } /** @@ -403,6 +444,10 @@ public class ScriptClient { String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断退单&%s=T", machineId); log.info("调用退单接口: 设备={}, url={}", machineId, url); + // 创建操作日志记录 + ScriptOperationLog operationLog = operationLogService.logRefundOrder(machineId, url); + long startTime = System.currentTimeMillis(); + return webClient.get() .uri(url) .accept(MediaType.TEXT_PLAIN) @@ -411,9 +456,13 @@ public class ScriptClient { .timeout(Duration.ofSeconds(10)) .doOnSuccess(result -> { log.info("退单接口调用成功: 设备={}, 结果={}", machineId, result); + // 记录成功响应 + operationLogService.recordSuccess(operationLog, result, startTime); }) .doOnError(e -> { log.error("退单接口调用失败: 设备={}, 错误={}", machineId, e.toString()); + // 记录失败响应 + operationLogService.recordFailure(operationLog, e.toString(), startTime); }); } } diff --git a/src/main/java/com/gameplatform/server/service/log/ScriptOperationLogService.java b/src/main/java/com/gameplatform/server/service/log/ScriptOperationLogService.java new file mode 100644 index 0000000..7cfac9f --- /dev/null +++ b/src/main/java/com/gameplatform/server/service/log/ScriptOperationLogService.java @@ -0,0 +1,163 @@ +package com.gameplatform.server.service.log; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gameplatform.server.mapper.log.ScriptOperationLogMapper; +import com.gameplatform.server.model.entity.log.ScriptOperationLog; +import com.gameplatform.server.model.enums.ScriptOperationType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 脚本操作日志服务 + */ +@Service +@Slf4j +public class ScriptOperationLogService { + + @Autowired + private ScriptOperationLogMapper logMapper; + + @Autowired + private ObjectMapper objectMapper; + + /** + * 创建操作记录 + */ + public ScriptOperationLog createOperationLog(ScriptOperationType operationType, String machineId, String requestUrl) { + ScriptOperationLog operationLog = new ScriptOperationLog(operationType, machineId, requestUrl); + try { + logMapper.insert(operationLog); + log.debug("创建脚本操作记录: id={}, type={}, machine={}", operationLog.getId(), operationType, machineId); + return operationLog; + } catch (Exception e) { + log.error("创建脚本操作记录失败: type={}, machine={}, error={}", operationType, machineId, e.getMessage(), e); + return operationLog; // 即使保存失败也返回对象,避免影响主流程 + } + } + + /** + * 记录选区操作 + */ + public ScriptOperationLog logSelectRegion(String machineId, String requestUrl, String region) { + ScriptOperationLog log = createOperationLog(ScriptOperationType.SELECT_REGION, machineId, requestUrl); + + // 设置请求参数 + Map params = new HashMap<>(); + params.put("region", region); + setRequestParams(log, params); + + return log; + } + + /** + * 记录刷新操作 + */ + public ScriptOperationLog logRefresh(String machineId, String requestUrl) { + ScriptOperationLog log = createOperationLog(ScriptOperationType.REFRESH, machineId, requestUrl); + + // 设置请求参数 + Map params = new HashMap<>(); + params.put("action", "刷新"); + setRequestParams(log, params); + + return log; + } + + /** + * 记录保存总次数操作 + */ + public ScriptOperationLog logSaveTotalTimes(String machineId, String requestUrl, int times) { + ScriptOperationLog log = createOperationLog(ScriptOperationType.SAVE_TOTAL_TIMES, machineId, requestUrl); + + // 设置请求参数 + Map params = new HashMap<>(); + params.put("times", times); + setRequestParams(log, params); + + return log; + } + + /** + * 记录退单操作 + */ + public ScriptOperationLog logRefundOrder(String machineId, String requestUrl) { + ScriptOperationLog log = createOperationLog(ScriptOperationType.REFUND_ORDER, machineId, requestUrl); + + // 设置请求参数 + Map params = new HashMap<>(); + params.put("action", "T"); + setRequestParams(log, params); + + return log; + } + + /** + * 记录成功响应 + */ + public void recordSuccess(ScriptOperationLog operationLog, String result, long startTime) { + try { + LocalDateTime responseTime = LocalDateTime.now(); + long duration = System.currentTimeMillis() - startTime; + + operationLog.setSuccessResponse(result, responseTime, duration); + logMapper.update(operationLog); + + log.debug("记录操作成功: id={}, duration={}ms", operationLog.getId(), duration); + } catch (Exception e) { + log.error("记录操作成功失败: id={}, error={}", operationLog.getId(), e.getMessage(), e); + } + } + + /** + * 记录失败响应 + */ + public void recordFailure(ScriptOperationLog operationLog, String errorMessage, long startTime) { + try { + LocalDateTime responseTime = LocalDateTime.now(); + long duration = System.currentTimeMillis() - startTime; + + operationLog.setFailureResponse(errorMessage, responseTime, duration); + logMapper.update(operationLog); + + log.debug("记录操作失败: id={}, duration={}ms, error={}", operationLog.getId(), duration, errorMessage); + } catch (Exception e) { + log.error("记录操作失败失败: id={}, error={}", operationLog.getId(), e.getMessage(), e); + } + } + + /** + * 设置请求参数(转换为JSON字符串) + */ + private void setRequestParams(ScriptOperationLog operationLog, Map params) { + try { + String paramsJson = objectMapper.writeValueAsString(params); + operationLog.setRequestParams(paramsJson); + logMapper.update(operationLog); + } catch (JsonProcessingException e) { + log.warn("转换请求参数为JSON失败: params={}, error={}", params, e.getMessage()); + } catch (Exception e) { + log.error("设置请求参数失败: id={}, error={}", operationLog.getId(), e.getMessage(), e); + } + } + + /** + * 清理旧记录(可以通过定时任务调用) + */ + public int cleanOldRecords(int daysToKeep) { + try { + LocalDateTime cutoffTime = LocalDateTime.now().minusDays(daysToKeep); + int deletedCount = logMapper.deleteOldRecords(cutoffTime); + log.info("清理脚本操作记录: 删除{}条{}天前的记录", deletedCount, daysToKeep); + return deletedCount; + } catch (Exception e) { + log.error("清理旧记录失败: error={}", e.getMessage(), e); + return 0; + } + } +} diff --git a/src/main/java/com/gameplatform/server/task/DeviceStatusCheckTask.java b/src/main/java/com/gameplatform/server/task/DeviceStatusCheckTask.java index c5691b1..07fb092 100644 --- a/src/main/java/com/gameplatform/server/task/DeviceStatusCheckTask.java +++ b/src/main/java/com/gameplatform/server/task/DeviceStatusCheckTask.java @@ -4,6 +4,7 @@ import com.gameplatform.server.model.dto.device.DeviceStatusResponse; import com.gameplatform.server.service.device.DeviceStatusCheckService; import com.gameplatform.server.service.external.ScriptClient; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import reactor.core.Exceptions; import reactor.core.publisher.Mono; @@ -29,7 +30,7 @@ public class DeviceStatusCheckTask { /** * 每分钟检查一次空闲设备,并更新相关链接任务状态 */ -// @Scheduled(fixedRate = 60000) // 每60秒执行一次 + @Scheduled(fixedRate = 60000) // 每60秒执行一次 public void checkIdleDevicesAndUpdateTasks() { log.debug("开始定时检查空闲设备"); diff --git a/src/main/resources/db/migration/V20250920__create_script_operation_log.sql b/src/main/resources/db/migration/V20250920__create_script_operation_log.sql new file mode 100644 index 0000000..6fbb4df --- /dev/null +++ b/src/main/resources/db/migration/V20250920__create_script_operation_log.sql @@ -0,0 +1,21 @@ +-- 脚本操作记录表 +CREATE TABLE script_operation_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + operation_type VARCHAR(50) NOT NULL COMMENT '操作类型: SELECT_REGION, REFRESH, SAVE_TOTAL_TIMES, REFUND_ORDER', + machine_id VARCHAR(50) NOT NULL COMMENT '设备/机器ID', + request_url TEXT NOT NULL COMMENT '请求URL', + request_params JSON COMMENT '请求参数(JSON格式)', + response_result TEXT COMMENT '响应结果', + success BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否成功', + error_message TEXT COMMENT '错误信息', + duration_ms INT COMMENT '请求耗时(毫秒)', + request_time DATETIME NOT NULL COMMENT '请求发送时间', + response_time DATETIME COMMENT '响应接收时间', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + INDEX idx_operation_type (operation_type), + INDEX idx_machine_id (machine_id), + INDEX idx_request_time (request_time), + INDEX idx_success (success) +) COMMENT '脚本操作记录表'; diff --git a/src/main/resources/mapper/log/ScriptOperationLogMapper.xml b/src/main/resources/mapper/log/ScriptOperationLogMapper.xml new file mode 100644 index 0000000..ebfddc5 --- /dev/null +++ b/src/main/resources/mapper/log/ScriptOperationLogMapper.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + id, operation_type, machine_id, request_url, request_params, response_result, + success, error_message, duration_ms, request_time, response_time, created_at, updated_at + + + + + + + + + + + + + + + + + + INSERT INTO script_operation_log ( + operation_type, machine_id, request_url, request_params, response_result, + success, error_message, duration_ms, request_time, response_time, created_at, updated_at + ) VALUES ( + #{operationType}, #{machineId}, #{requestUrl}, #{requestParams}, #{responseResult}, + #{success}, #{errorMessage}, #{durationMs}, #{requestTime}, #{responseTime}, #{createdAt}, #{updatedAt} + ) + + + + UPDATE script_operation_log + + response_result = #{responseResult}, + success = #{success}, + error_message = #{errorMessage}, + duration_ms = #{durationMs}, + response_time = #{responseTime}, + updated_at = #{updatedAt} + + WHERE id = #{id} + + + + DELETE FROM script_operation_log + WHERE created_at < #{beforeTime} + + +