新增系统配置表及默认配置,更新链接生成请求DTO以支持链接数量参数,重构链接生成服务逻辑,添加链接状态查询和有效性检查接口,优化日志记录。

This commit is contained in:
zyh
2025-08-26 10:33:26 +08:00
parent 7317866f98
commit 599ec0a36b
73 changed files with 1829 additions and 50 deletions

View File

@@ -0,0 +1,101 @@
package com.gameplatform.server.service.admin;
import com.gameplatform.server.mapper.admin.SystemConfigMapper;
import com.gameplatform.server.model.entity.admin.SystemConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class SystemConfigService {
@Autowired
private SystemConfigMapper systemConfigMapper;
public SystemConfig getConfigByKey(String configKey) {
return systemConfigMapper.findByKey(configKey);
}
public String getConfigValue(String configKey, String defaultValue) {
SystemConfig config = systemConfigMapper.findByKey(configKey);
return config != null ? config.getConfigValue() : defaultValue;
}
public Integer getConfigValueAsInt(String configKey, Integer defaultValue) {
String value = getConfigValue(configKey, null);
if (value == null) return defaultValue;
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
public Boolean getConfigValueAsBoolean(String configKey, Boolean defaultValue) {
String value = getConfigValue(configKey, null);
if (value == null) return defaultValue;
return Boolean.parseBoolean(value);
}
public List<SystemConfig> getAllConfigs(int size, int offset) {
return systemConfigMapper.findAll(size, offset);
}
public long getConfigCount() {
return systemConfigMapper.countAll();
}
public List<SystemConfig> getConfigsByType(String configType) {
return systemConfigMapper.findByType(configType);
}
public boolean createConfig(SystemConfig systemConfig) {
return systemConfigMapper.insert(systemConfig) > 0;
}
public boolean updateConfig(SystemConfig systemConfig) {
return systemConfigMapper.update(systemConfig) > 0;
}
public boolean deleteConfig(Long id) {
return systemConfigMapper.deleteById(id) > 0;
}
public boolean deleteConfigByKey(String configKey) {
return systemConfigMapper.deleteByKey(configKey) > 0;
}
// 获取链接相关的默认配置
public Integer getDefaultQuantity() {
return getConfigValueAsInt("link.default_quantity", 50);
}
public Integer getRefreshInterval() {
return getConfigValueAsInt("link.refresh_interval", 300);
}
public Integer getQrExpireTime() {
return getConfigValueAsInt("link.qr_expire_time", 600);
}
public Integer getMaxTimesPerBatch() {
return getConfigValueAsInt("link.max_times_per_batch", 100);
}
public Integer getMinQuantity() {
return getConfigValueAsInt("link.min_quantity", 10);
}
public Integer getMaxQuantity() {
return getConfigValueAsInt("link.max_quantity", 1000);
}
public String getScriptServerUrl() {
return getConfigValue("script.server_url", "http://36.138.184.60:12345");
}
public String getQrPathTemplate() {
return getConfigValue("script.qr_path_template", "/{machineId}/二维码.png");
}
}

View File

@@ -11,7 +11,8 @@ import com.gameplatform.server.model.entity.agent.LinkTask;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import com.gameplatform.server.service.admin.SystemConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;
@@ -30,31 +31,31 @@ public class LinkGenerationService {
private final LinkBatchMapper linkBatchMapper;
private final LinkTaskMapper linkTaskMapper;
private final AgentPointsTxMapper agentPointsTxMapper;
private final int expireHours;
private final SystemConfigService systemConfigService;
public LinkGenerationService(UserAccountMapper userAccountMapper,
LinkBatchMapper linkBatchMapper,
LinkTaskMapper linkTaskMapper,
AgentPointsTxMapper agentPointsTxMapper,
@Value("${link.expire-hours:2}") int expireHours) {
SystemConfigService systemConfigService) {
this.userAccountMapper = userAccountMapper;
this.linkBatchMapper = linkBatchMapper;
this.linkTaskMapper = linkTaskMapper;
this.agentPointsTxMapper = agentPointsTxMapper;
this.expireHours = expireHours;
this.systemConfigService = systemConfigService;
}
@Transactional
public Mono<GenerateResult> generateLinks(Long operatorId, String operatorType,
int times, int perTimeQuantity) {
return Mono.fromCallable(() -> doGenerate(operatorId, operatorType, times, perTimeQuantity))
int times, int linkCount) {
return Mono.fromCallable(() -> doGenerate(operatorId, operatorType, times, linkCount))
.subscribeOn(Schedulers.boundedElastic());
}
private GenerateResult doGenerate(Long operatorId, String operatorType,
int times, int perTimeQuantity) {
if (times <= 0 || perTimeQuantity <= 0) {
throw new IllegalArgumentException("times 与 perTimeQuantity 必须为正整数");
int times, int linkCount) {
if (times <= 0 || linkCount <= 0) {
throw new IllegalArgumentException("times 与 linkCount 必须为正整数");
}
// 获取操作者账户信息
@@ -68,11 +69,16 @@ public class LinkGenerationService {
throw new IllegalArgumentException("非法操作者类型");
}
// 从配置表获取每次副本的奖励点数
int perTimeQuantity = systemConfigService.getDefaultQuantity();
long needPoints = (long) times * (long) perTimeQuantity;
int expireHours = systemConfigService.getConfigValueAsInt("link.expire-hours", 2);
if (log.isDebugEnabled()) {
log.debug("generateLinks operatorId={} operatorType={} times={} perTimeQuantity={} needPoints={} expireHours={}",
operatorId, operatorType, times, perTimeQuantity, needPoints, expireHours);
log.debug("generateLinks operatorId={} operatorType={} times={} linkCount={} perTimeQuantity={} needPoints={} expireHours={}",
operatorId, operatorType, times, linkCount, perTimeQuantity, needPoints, expireHours);
}
if (!isAdminOperator) {
// 代理商自操作,需扣点判断
long balance = operator.getPointsBalance() == null ? 0L : operator.getPointsBalance();
@@ -83,16 +89,14 @@ public class LinkGenerationService {
LinkBatch batch = new LinkBatch();
batch.setAgentId(operator.getId());
batch.setQuantity(times);
batch.setTimes(times);
batch.setBatchSize(perTimeQuantity);
batch.setDeductPoints(needPoints);
batch.setQuantity(perTimeQuantity); // 每次副本的奖励点数
batch.setTimes(times); // 打副本的次数
batch.setOperatorId(operatorId);
linkBatchMapper.insert(batch);
LocalDateTime expireAt = LocalDateTime.now().plusHours(expireHours);
List<LinkTask> tasks = new ArrayList<>();
for (int i = 0; i < times; i++) {
for (int i = 0; i < linkCount; i++) { // 生成linkCount个链接
LinkTask t = new LinkTask();
t.setBatchId(batch.getId());
t.setAgentId(operator.getId());

View File

@@ -0,0 +1,125 @@
package com.gameplatform.server.service.link;
import com.gameplatform.server.mapper.agent.LinkBatchMapper;
import com.gameplatform.server.mapper.agent.LinkTaskMapper;
import com.gameplatform.server.model.dto.link.LinkStatusResponse;
import com.gameplatform.server.model.entity.agent.LinkBatch;
import com.gameplatform.server.model.entity.agent.LinkTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
@Service
public class LinkStatusService {
private static final Logger log = LoggerFactory.getLogger(LinkStatusService.class);
private final LinkTaskMapper linkTaskMapper;
private final LinkBatchMapper linkBatchMapper;
// 状态描述映射
private static final Map<String, String> STATUS_DESC_MAP = new HashMap<>();
static {
STATUS_DESC_MAP.put("NEW", "新建");
STATUS_DESC_MAP.put("USING", "使用中");
STATUS_DESC_MAP.put("LOGGED_IN", "已登录");
STATUS_DESC_MAP.put("REFUNDED", "已退款");
STATUS_DESC_MAP.put("EXPIRED", "已过期");
}
public LinkStatusService(LinkTaskMapper linkTaskMapper, LinkBatchMapper linkBatchMapper) {
this.linkTaskMapper = linkTaskMapper;
this.linkBatchMapper = linkBatchMapper;
}
/**
* 根据链接编号获取链接状态
*/
public Mono<LinkStatusResponse> getLinkStatus(String codeNo) {
return Mono.fromCallable(() -> doGetLinkStatus(codeNo))
.subscribeOn(Schedulers.boundedElastic());
}
private LinkStatusResponse doGetLinkStatus(String codeNo) {
if (codeNo == null || codeNo.trim().isEmpty()) {
throw new IllegalArgumentException("链接编号不能为空");
}
log.debug("查询链接状态: codeNo={}", codeNo);
// 查询链接任务
LinkTask linkTask = linkTaskMapper.findByCodeNo(codeNo);
if (linkTask == null) {
throw new IllegalArgumentException("链接不存在: " + codeNo);
}
// 查询批次信息
LinkBatch linkBatch = linkBatchMapper.findById(linkTask.getBatchId());
if (linkBatch == null) {
throw new IllegalStateException("批次信息不存在: batchId=" + linkTask.getBatchId());
}
// 构建响应对象
LinkStatusResponse response = new LinkStatusResponse();
response.setCodeNo(linkTask.getCodeNo());
response.setBatchId(linkTask.getBatchId());
response.setStatus(linkTask.getStatus());
response.setStatusDesc(STATUS_DESC_MAP.getOrDefault(linkTask.getStatus(), "未知状态"));
response.setExpireAt(linkTask.getExpireAt());
response.setQuantity(linkBatch.getQuantity());
response.setTimes(linkBatch.getTimes());
response.setTotalPoints(linkBatch.getQuantity() * linkBatch.getTimes());
response.setRegion(linkTask.getRegion());
response.setMachineId(linkTask.getMachineId());
response.setLoginAt(linkTask.getLoginAt());
response.setCreatedAt(linkTask.getCreatedAt());
response.setUpdatedAt(linkTask.getUpdatedAt());
// 计算过期状态和剩余时间
LocalDateTime now = LocalDateTime.now();
boolean isExpired = now.isAfter(linkTask.getExpireAt());
response.setIsExpired(isExpired);
if (!isExpired) {
long remainingSeconds = ChronoUnit.SECONDS.between(now, linkTask.getExpireAt());
response.setRemainingSeconds(remainingSeconds);
} else {
response.setRemainingSeconds(0L);
}
log.debug("链接状态查询完成: codeNo={}, status={}, isExpired={}, remainingSeconds={}",
codeNo, linkTask.getStatus(), isExpired, response.getRemainingSeconds());
return response;
}
/**
* 检查链接是否存在
*/
public Mono<Boolean> isLinkExists(String codeNo) {
return Mono.fromCallable(() -> {
if (codeNo == null || codeNo.trim().isEmpty()) {
return false;
}
LinkTask linkTask = linkTaskMapper.findByCodeNo(codeNo);
return linkTask != null;
}).subscribeOn(Schedulers.boundedElastic());
}
/**
* 检查链接是否有效(未过期且状态正常)
*/
public Mono<Boolean> isLinkValid(String codeNo) {
return getLinkStatus(codeNo)
.map(response -> !response.getIsExpired() &&
("NEW".equals(response.getStatus()) || "USING".equals(response.getStatus())))
.onErrorReturn(false);
}
}