feat: 新增按状态批量删除链接功能
主要修改: 1. 在LinkController中新增按状态批量删除链接的接口,允许用户根据指定状态批量删除自己创建的链接。 2. 在LinkStatusService中实现批量删除逻辑,确保用户只能删除自己的链接,并进行状态验证。 3. 更新LinkTaskMapper和对应的XML文件,增加查询和删除链接任务的相关方法。 技术细节: - 通过新增的批量删除功能,提升了用户对链接的管理能力,确保操作的安全性和有效性,同时优化了数据库操作的灵活性。
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.gameplatform.server.controller.link;
|
||||
|
||||
import com.gameplatform.server.model.dto.link.BatchDeleteByStatusRequest;
|
||||
import com.gameplatform.server.model.dto.link.BatchDeleteRequest;
|
||||
import com.gameplatform.server.model.dto.link.BatchDeleteResponse;
|
||||
import com.gameplatform.server.model.dto.link.LinkGenerateRequest;
|
||||
@@ -296,6 +297,58 @@ public Mono<Boolean> deleteLink(@PathVariable("codeNo") String codeNo, Authentic
|
||||
});
|
||||
}
|
||||
|
||||
@PostMapping("/batch-delete-by-status")
|
||||
@Operation(summary = "按状态批量删除链接", description = "根据指定的状态批量删除链接,用户只能删除自己创建的链接,支持删除的状态:NEW、USING、LOGGED_IN、COMPLETED、REFUNDED、EXPIRED")
|
||||
public Mono<BatchDeleteResponse> batchDeleteLinksByStatus(@Valid @RequestBody BatchDeleteByStatusRequest request, Authentication authentication) {
|
||||
log.info("=== 开始按状态批量删除链接 ===");
|
||||
log.info("要删除的状态列表: {}", request.getStatusList());
|
||||
log.info("是否确认删除: {}", request.getConfirmDelete());
|
||||
|
||||
if (authentication == null) {
|
||||
log.error("=== 认证失败:Authentication为空 ===");
|
||||
return Mono.error(new IllegalArgumentException("用户未认证:Authentication为空"));
|
||||
}
|
||||
|
||||
// 检查是否确认删除
|
||||
if (!Boolean.TRUE.equals(request.getConfirmDelete())) {
|
||||
log.error("=== 未确认删除操作 ===");
|
||||
return Mono.error(new IllegalArgumentException("必须确认删除操作,请设置confirmDelete为true"));
|
||||
}
|
||||
|
||||
// 获取用户ID
|
||||
Claims claims = (Claims) authentication.getDetails();
|
||||
if (claims == null) {
|
||||
log.error("=== 认证失败:Claims为空 ===");
|
||||
log.error("Authentication details: {}", authentication.getDetails());
|
||||
return Mono.error(new IllegalArgumentException("用户未认证:Claims为空"));
|
||||
}
|
||||
|
||||
Long agentId = claims.get("userId", Long.class);
|
||||
String userType = claims.get("userType", String.class);
|
||||
|
||||
log.info("用户信息: agentId={}, userType={}", agentId, userType);
|
||||
|
||||
if (agentId == null) {
|
||||
log.error("=== 无法获取用户ID ===");
|
||||
return Mono.error(new IllegalArgumentException("无法获取用户ID"));
|
||||
}
|
||||
|
||||
return linkStatusService.batchDeleteLinksByStatus(request.getStatusList(), agentId)
|
||||
.doOnSuccess(response -> {
|
||||
log.info("按状态批量删除链接完成: 总数={}, 成功={}, 失败={}, agentId={}",
|
||||
response.getTotalCount(), response.getSuccessCount(),
|
||||
response.getFailedCount(), agentId);
|
||||
if (!response.isAllSuccess()) {
|
||||
log.warn("部分链接删除失败: 失败的链接={}, 失败原因={}",
|
||||
response.getFailedCodeNos(), response.getFailedReasons());
|
||||
}
|
||||
})
|
||||
.doOnError(error -> {
|
||||
log.error("按状态批量删除链接时发生错误: agentId={}, statusList={}, error={}",
|
||||
agentId, request.getStatusList(), error.getMessage(), error);
|
||||
});
|
||||
}
|
||||
|
||||
@PostMapping("/batch-delete")
|
||||
@Operation(summary = "批量删除链接", description = "批量删除指定的链接,用户只能删除自己创建的链接,最多一次删除100个")
|
||||
public Mono<BatchDeleteResponse> batchDeleteLinks(@RequestBody BatchDeleteRequest request, Authentication authentication) {
|
||||
|
||||
@@ -95,4 +95,19 @@ public interface LinkTaskMapper extends BaseMapper<LinkTask> {
|
||||
* 根据设备ID和状态查询链接任务
|
||||
*/
|
||||
List<LinkTask> findByMachineIdAndStatus(@Param("machineId") String machineId, @Param("status") String status);
|
||||
|
||||
/**
|
||||
* 根据状态列表和代理ID查询链接任务(用于验证权限和获取要删除的链接)
|
||||
*/
|
||||
List<LinkTask> findByStatusListAndAgentId(@Param("statusList") List<String> statusList, @Param("agentId") Long agentId);
|
||||
|
||||
/**
|
||||
* 根据状态列表和代理ID统计链接任务数量
|
||||
*/
|
||||
long countByStatusListAndAgentId(@Param("statusList") List<String> statusList, @Param("agentId") Long agentId);
|
||||
|
||||
/**
|
||||
* 根据状态列表和代理ID批量删除链接任务
|
||||
*/
|
||||
int batchDeleteByStatusListAndAgentId(@Param("statusList") List<String> statusList, @Param("agentId") Long agentId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.gameplatform.server.model.dto.link;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 按狀態批量刪除鏈接請求DTO
|
||||
*
|
||||
* @author GamePlatform
|
||||
*/
|
||||
@Schema(description = "按狀態批量刪除鏈接請求")
|
||||
public class BatchDeleteByStatusRequest {
|
||||
|
||||
@NotEmpty(message = "要刪除的狀態列表不能為空")
|
||||
@Size(max = 10, message = "單次最多只能指定10個狀態")
|
||||
@Schema(description = "要刪除的鏈接狀態列表,可選值:NEW、USING、LOGGED_IN、COMPLETED、REFUNDED、EXPIRED",
|
||||
example = "[\"EXPIRED\", \"REFUNDED\"]", required = true)
|
||||
private List<String> statusList;
|
||||
|
||||
@Schema(description = "是否確認刪除,必須設置為true才能執行刪除操作", example = "true", required = true)
|
||||
private Boolean confirmDelete = false;
|
||||
|
||||
public BatchDeleteByStatusRequest() {}
|
||||
|
||||
public BatchDeleteByStatusRequest(List<String> statusList, Boolean confirmDelete) {
|
||||
this.statusList = statusList;
|
||||
this.confirmDelete = confirmDelete;
|
||||
}
|
||||
|
||||
public List<String> getStatusList() {
|
||||
return statusList;
|
||||
}
|
||||
|
||||
public void setStatusList(List<String> statusList) {
|
||||
this.statusList = statusList;
|
||||
}
|
||||
|
||||
public Boolean getConfirmDelete() {
|
||||
return confirmDelete;
|
||||
}
|
||||
|
||||
public void setConfirmDelete(Boolean confirmDelete) {
|
||||
this.confirmDelete = confirmDelete;
|
||||
}
|
||||
}
|
||||
@@ -266,6 +266,93 @@ public class LinkStatusService {
|
||||
}).subscribeOn(Schedulers.boundedElastic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 按状态批量删除链接(确保用户只能删除自己的链接)
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Mono<BatchDeleteResponse> batchDeleteLinksByStatus(List<String> statusList, Long agentId) {
|
||||
return Mono.fromCallable(() -> {
|
||||
log.info("开始按状态批量删除链接: statusList={}, agentId={}", statusList, agentId);
|
||||
|
||||
if (statusList == null || statusList.isEmpty()) {
|
||||
throw new IllegalArgumentException("要删除的状态列表不能为空");
|
||||
}
|
||||
|
||||
if (statusList.size() > 10) {
|
||||
throw new IllegalArgumentException("单次最多只能指定10个状态");
|
||||
}
|
||||
|
||||
// 验证状态值是否有效
|
||||
List<String> validStatuses = List.of("NEW", "USING", "LOGGED_IN", "COMPLETED", "REFUNDED", "EXPIRED");
|
||||
for (String status : statusList) {
|
||||
if (!validStatuses.contains(status)) {
|
||||
throw new IllegalArgumentException("无效的状态值: " + status);
|
||||
}
|
||||
}
|
||||
|
||||
// 统计要删除的链接数量
|
||||
long totalCount = linkTaskMapper.countByStatusListAndAgentId(statusList, agentId);
|
||||
log.info("用户拥有的指定状态链接数量: {}", totalCount);
|
||||
|
||||
if (totalCount == 0) {
|
||||
// 没有符合条件的链接
|
||||
BatchDeleteResponse response = new BatchDeleteResponse(0, 0, 0,
|
||||
List.of(), List.of(), List.of());
|
||||
log.info("没有找到符合条件的链接");
|
||||
return response;
|
||||
}
|
||||
|
||||
// 查询要删除的链接详情(用于记录日志)
|
||||
List<LinkTask> linksToDelete = linkTaskMapper.findByStatusListAndAgentId(statusList, agentId);
|
||||
List<String> codeNosToDelete = linksToDelete.stream()
|
||||
.map(LinkTask::getCodeNo)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("即将删除的链接: {}", codeNosToDelete);
|
||||
|
||||
// 执行批量删除
|
||||
int deleteCount = linkTaskMapper.batchDeleteByStatusListAndAgentId(statusList, agentId);
|
||||
log.info("批量删除执行结果: 预期删除数量={}, 实际删除数量={}", totalCount, deleteCount);
|
||||
|
||||
// 构建响应
|
||||
List<String> successCodeNos = new ArrayList<>();
|
||||
List<String> failedCodeNos = new ArrayList<>();
|
||||
List<String> failedReasons = new ArrayList<>();
|
||||
|
||||
if (deleteCount == totalCount) {
|
||||
// 全部删除成功
|
||||
successCodeNos.addAll(codeNosToDelete);
|
||||
} else if (deleteCount > 0) {
|
||||
// 部分删除成功(这种情况比较少见,可能是并发操作导致)
|
||||
successCodeNos.addAll(codeNosToDelete.subList(0, deleteCount));
|
||||
failedCodeNos.addAll(codeNosToDelete.subList(deleteCount, codeNosToDelete.size()));
|
||||
for (int i = deleteCount; i < codeNosToDelete.size(); i++) {
|
||||
failedReasons.add("删除操作部分失败");
|
||||
}
|
||||
} else {
|
||||
// 全部删除失败
|
||||
failedCodeNos.addAll(codeNosToDelete);
|
||||
for (int i = 0; i < codeNosToDelete.size(); i++) {
|
||||
failedReasons.add("删除操作失败");
|
||||
}
|
||||
}
|
||||
|
||||
BatchDeleteResponse response = new BatchDeleteResponse(
|
||||
successCodeNos.size(),
|
||||
failedCodeNos.size(),
|
||||
codeNosToDelete.size(),
|
||||
successCodeNos,
|
||||
failedCodeNos,
|
||||
failedReasons
|
||||
);
|
||||
|
||||
log.info("按状态批量删除完成: 总数={}, 成功={}, 失败={}",
|
||||
response.getTotalCount(), response.getSuccessCount(), response.getFailedCount());
|
||||
|
||||
return response;
|
||||
}).subscribeOn(Schedulers.boundedElastic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除链接(确保用户只能删除自己的链接)
|
||||
*/
|
||||
|
||||
@@ -218,4 +218,34 @@
|
||||
FROM link_task
|
||||
WHERE machine_id = #{machineId} AND status = #{status}
|
||||
</select>
|
||||
|
||||
<select id="findByStatusListAndAgentId" resultMap="LinkTaskMap">
|
||||
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, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
|
||||
FROM link_task
|
||||
WHERE agent_id = #{agentId}
|
||||
AND status IN
|
||||
<foreach collection="statusList" item="status" open="(" close=")" separator=",">
|
||||
#{status}
|
||||
</foreach>
|
||||
ORDER BY created_at DESC
|
||||
</select>
|
||||
|
||||
<select id="countByStatusListAndAgentId" resultType="long">
|
||||
SELECT COUNT(1)
|
||||
FROM link_task
|
||||
WHERE agent_id = #{agentId}
|
||||
AND status IN
|
||||
<foreach collection="statusList" item="status" open="(" close=")" separator=",">
|
||||
#{status}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<delete id="batchDeleteByStatusListAndAgentId">
|
||||
DELETE FROM link_task
|
||||
WHERE agent_id = #{agentId}
|
||||
AND status IN
|
||||
<foreach collection="statusList" item="status" open="(" close=")" separator=",">
|
||||
#{status}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user