新增admin 任务

This commit is contained in:
tianfeng 2025-11-25 11:15:24 +08:00
parent 323505ca48
commit 79ef0e68f6
19 changed files with 1129 additions and 0 deletions

View File

@ -0,0 +1,31 @@
package com.red.circle.other.adapter.app;
import com.red.circle.other.app.dto.clientobject.AdminTaskSummaryCO;
import com.red.circle.other.app.dto.cmd.AdminTaskQueryCmd;
import com.red.circle.other.app.service.AdminTaskService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 管理员任务控制器
*
* @author tf
* @date 2025-11-25
*/
@RestController
@RequestMapping("/admin/task")
@RequiredArgsConstructor
public class AdminTaskRestController {
private final AdminTaskService adminTaskService;
/**
* 查询任务进度
*/
@PostMapping("/query")
public AdminTaskSummaryCO queryTaskSummary(@Validated @RequestBody AdminTaskQueryCmd cmd) {
AdminTaskSummaryCO summary = adminTaskService.queryTaskSummary(cmd);
return summary;
}
}

View File

@ -0,0 +1,55 @@
package com.red.circle.other.app.command.admintask;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import com.red.circle.other.domain.admintask.AdminTaskStatus;
import com.red.circle.other.domain.admintask.AdminTaskType;
import com.red.circle.other.domain.gateway.AdminTaskGateway;
import com.red.circle.other.app.dto.cmd.AdminTaskInitCmd;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* 管理员任务初始化执行器
*
* @author tf
* @date 2025-11-25
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class AdminTaskInitCmdExe {
private final AdminTaskGateway adminTaskGateway;
public void execute(AdminTaskInitCmd cmd) {
// 检查是否已初始化
boolean exists = adminTaskGateway.existsByUserIdAndCycle(cmd.getUserId(), cmd.getCycleStartDate());
if (exists) {
throw new RuntimeException("该周期任务已初始化");
}
// 批量创建5个任务记录
List<AdminTaskRecord> tasks = new ArrayList<>();
for (AdminTaskType taskType : AdminTaskType.values()) {
AdminTaskRecord record = new AdminTaskRecord();
record.setUserId(cmd.getUserId());
record.setUserRole("ADMIN");
record.setCycleStartDate(cmd.getCycleStartDate());
record.setCycleEndDate(cmd.getCycleEndDate());
record.setTaskType(taskType.getCode());
record.setTargetCount(taskType.getDefaultTarget());
record.setCompletedCount(0);
record.setStatus(AdminTaskStatus.IN_PROGRESS.getCode());
record.setCreateTime(LocalDateTime.now());
record.setUpdateTime(LocalDateTime.now());
tasks.add(record);
}
adminTaskGateway.batchInsert(tasks);
}
}

View File

@ -0,0 +1,87 @@
package com.red.circle.other.app.command.admintask;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import com.red.circle.other.domain.admintask.AdminTaskType;
import com.red.circle.other.domain.gateway.AdminTaskGateway;
import com.red.circle.other.app.dto.cmd.AdminTaskProgressUpdateCmd;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
/**
* 管理员任务进度更新执行器
*
* @author tf
* @date 2025-11-25
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class AdminTaskProgressUpdateCmdExe {
private final AdminTaskGateway adminTaskGateway;
private static final int HOURS_PER_WORKING_DAY = 2;
public AdminTaskRecord execute(AdminTaskProgressUpdateCmd cmd) {
LocalDate cycleStartDate = cmd.getCycleStartDate() != null ? cmd.getCycleStartDate() : getCurrentCycleStartDate();
// 校验任务类型
AdminTaskType taskType = AdminTaskType.fromCode(cmd.getTaskType());
if (taskType == null) {
throw new RuntimeException("无效的任务类型: " + cmd.getTaskType());
}
// 增量更新任务进度
AdminTaskRecord updatedRecord = adminTaskGateway.incrementCompletedCount(
cmd.getUserId(),
cmd.getTaskType(),
cycleStartDate,
cmd.getIncrementValue()
);
if (updatedRecord == null) {
throw new RuntimeException("任务记录不存在");
}
// 检查是否达到目标更新状态
if (updatedRecord.reachedTarget() && !updatedRecord.isCompleted()) {
adminTaskGateway.markAsCompleted(cmd.getUserId(), cmd.getTaskType(), cycleStartDate);
updatedRecord.setStatus("COMPLETED");
}
// 特殊处理麦克风使用时长影响工作天数
if (AdminTaskType.MIC_USAGE.getCode().equals(cmd.getTaskType())) {
int workingDays = updatedRecord.getCompletedCount() / HOURS_PER_WORKING_DAY;
AdminTaskRecord workingDaysRecord = adminTaskGateway.updateCompletedCountAbsolute(
cmd.getUserId(),
AdminTaskType.WORKING_DAYS.getCode(),
cycleStartDate,
workingDays
);
// 检查工作天数是否达到目标
if (workingDaysRecord != null && workingDaysRecord.reachedTarget() && !workingDaysRecord.isCompleted()) {
adminTaskGateway.markAsCompleted(cmd.getUserId(), AdminTaskType.WORKING_DAYS.getCode(), cycleStartDate);
}
}
return updatedRecord;
}
/**
* 获取当前周期开始日期
*/
private LocalDate getCurrentCycleStartDate() {
LocalDate now = LocalDate.now();
int dayOfMonth = now.getDayOfMonth();
if (dayOfMonth <= 15) {
return LocalDate.of(now.getYear(), now.getMonth(), 1);
} else {
return LocalDate.of(now.getYear(), now.getMonth(), 16);
}
}
}

View File

@ -0,0 +1,42 @@
package com.red.circle.other.app.command.admintask;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import com.red.circle.other.domain.gateway.AdminTaskGateway;
import com.red.circle.other.app.dto.cmd.AdminTaskQueryCmd;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.util.List;
/**
* 管理员任务查询执行器
*
* @author tf
* @date 2025-11-25
*/
@Component
@RequiredArgsConstructor
public class AdminTaskQueryCmdExe {
private final AdminTaskGateway adminTaskGateway;
public List<AdminTaskRecord> execute(AdminTaskQueryCmd cmd) {
LocalDate cycleStartDate = cmd.getCycleStartDate() != null ? cmd.getCycleStartDate() : getCurrentCycleStartDate();
return adminTaskGateway.findByUserIdAndCycle(cmd.getUserId(), cycleStartDate);
}
/**
* 获取当前周期开始日期
*/
private LocalDate getCurrentCycleStartDate() {
LocalDate now = LocalDate.now();
int dayOfMonth = now.getDayOfMonth();
if (dayOfMonth <= 15) {
return LocalDate.of(now.getYear(), now.getMonth(), 1);
} else {
return LocalDate.of(now.getYear(), now.getMonth(), 16);
}
}
}

View File

@ -0,0 +1,45 @@
package com.red.circle.other.app.convertor;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import com.red.circle.other.domain.admintask.AdminTaskStatus;
import com.red.circle.other.domain.admintask.AdminTaskType;
import com.red.circle.other.app.dto.clientobject.AdminTaskRecordCO;
import org.springframework.stereotype.Component;
/**
* 管理员任务转换器
*
* @author tf
* @date 2025-11-25
*/
@Component
public class AdminTaskConvertor {
public AdminTaskRecordCO toRecordCO(AdminTaskRecord record) {
if (record == null) {
return null;
}
AdminTaskRecordCO co = new AdminTaskRecordCO();
co.setTaskType(record.getTaskType());
co.setTargetCount(record.getTargetCount());
co.setCompletedCount(record.getCompletedCount());
co.setStatus(record.getStatus());
co.setCompletionRate(record.getCompletionRate());
// 设置任务名称和单位
AdminTaskType taskType = AdminTaskType.fromCode(record.getTaskType());
if (taskType != null) {
co.setTaskName(taskType.getName());
co.setUnit(taskType.getUnit());
}
// 设置状态名称
AdminTaskStatus status = AdminTaskStatus.fromCode(record.getStatus());
if (status != null) {
co.setStatusName(status.getName());
}
return co;
}
}

View File

@ -0,0 +1,77 @@
package com.red.circle.other.app.service;
import com.red.circle.other.app.command.admintask.AdminTaskInitCmdExe;
import com.red.circle.other.app.command.admintask.AdminTaskProgressUpdateCmdExe;
import com.red.circle.other.app.command.admintask.AdminTaskQueryCmdExe;
import com.red.circle.other.app.convertor.AdminTaskConvertor;
import com.red.circle.other.app.dto.clientobject.AdminTaskRecordCO;
import com.red.circle.other.app.dto.clientobject.AdminTaskSummaryCO;
import com.red.circle.other.app.dto.cmd.AdminTaskInitCmd;
import com.red.circle.other.app.dto.cmd.AdminTaskProgressUpdateCmd;
import com.red.circle.other.app.dto.cmd.AdminTaskQueryCmd;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
/**
* 管理员任务服务实现
*
* @author tf
* @date 2025-11-25
*/
@Service
@RequiredArgsConstructor
public class AdminTaskServiceImpl implements AdminTaskService {
private final AdminTaskInitCmdExe adminTaskInitCmdExe;
private final AdminTaskProgressUpdateCmdExe adminTaskProgressUpdateCmdExe;
private final AdminTaskQueryCmdExe adminTaskQueryCmdExe;
private final AdminTaskConvertor adminTaskConvertor;
@Override
@Transactional(rollbackFor = Exception.class)
public void initTasks(AdminTaskInitCmd cmd) {
adminTaskInitCmdExe.execute(cmd);
}
@Override
@Transactional(rollbackFor = Exception.class)
public AdminTaskRecordCO updateTaskProgress(AdminTaskProgressUpdateCmd cmd) {
AdminTaskRecord record = adminTaskProgressUpdateCmdExe.execute(cmd);
return adminTaskConvertor.toRecordCO(record);
}
@Override
public AdminTaskSummaryCO queryTaskSummary(AdminTaskQueryCmd cmd) {
List<AdminTaskRecord> records = adminTaskQueryCmdExe.execute(cmd);
// 转换为 CO
List<AdminTaskRecordCO> taskCOList = records.stream()
.map(adminTaskConvertor::toRecordCO)
.collect(Collectors.toList());
// 统计已完成任务数
long completedCount = records.stream()
.filter(AdminTaskRecord::isCompleted)
.count();
// 构建汇总对象
AdminTaskSummaryCO summary = new AdminTaskSummaryCO();
summary.setUserId(cmd.getUserId());
summary.setCompletedTaskCount((int) completedCount);
summary.setTotalTaskCount(records.size());
summary.setTasks(taskCOList);
// 设置周期信息
if (!records.isEmpty()) {
summary.setCycleStartDate(records.get(0).getCycleStartDate());
summary.setCycleEndDate(records.get(0).getCycleEndDate());
}
return summary;
}
}

View File

@ -0,0 +1,53 @@
package com.red.circle.other.app.dto.clientobject;
import lombok.Data;
/**
* 管理员任务记录客户端对象
*
* @author tf
* @date 2025-11-25
*/
@Data
public class AdminTaskRecordCO {
/**
* 任务类型编码
*/
private String taskType;
/**
* 任务名称
*/
private String taskName;
/**
* 目标数量
*/
private Integer targetCount;
/**
* 已完成数量
*/
private Integer completedCount;
/**
* 单位
*/
private String unit;
/**
* 任务状态
*/
private String status;
/**
* 任务状态名称
*/
private String statusName;
/**
* 完成率百分比
*/
private Double completionRate;
}

View File

@ -0,0 +1,46 @@
package com.red.circle.other.app.dto.clientobject;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
/**
* 管理员任务汇总客户端对象
*
* @author tf
* @date 2025-11-25
*/
@Data
public class AdminTaskSummaryCO {
/**
* 用户 ID
*/
private Long userId;
/**
* 周期开始日期
*/
private LocalDate cycleStartDate;
/**
* 周期结束日期
*/
private LocalDate cycleEndDate;
/**
* 已完成任务数
*/
private Integer completedTaskCount;
/**
* 总任务数
*/
private Integer totalTaskCount;
/**
* 任务列表
*/
private List<AdminTaskRecordCO> tasks;
}

View File

@ -0,0 +1,37 @@
package com.red.circle.other.app.dto.cmd;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
/**
* 管理员任务初始化命令
*
* @author tf
* @date 2025-11-25
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class AdminTaskInitCmd extends AppExtCommand {
/**
* 用户 ID
*/
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* 周期开始日期
*/
@NotNull(message = "周期开始日期不能为空")
private LocalDate cycleStartDate;
/**
* 周期结束日期
*/
@NotNull(message = "周期结束日期不能为空")
private LocalDate cycleEndDate;
}

View File

@ -0,0 +1,43 @@
package com.red.circle.other.app.dto.cmd;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
/**
* 管理员任务进度更新命令
*
* @author tf
* @date 2025-11-25
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class AdminTaskProgressUpdateCmd extends AppExtCommand {
/**
* 用户 ID
*/
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* 任务类型
*/
@NotBlank(message = "任务类型不能为空")
private String taskType;
/**
* 增量值
*/
@NotNull(message = "增量值不能为空")
private Integer incrementValue;
/**
* 周期开始日期可选默认当前周期
*/
private LocalDate cycleStartDate;
}

View File

@ -0,0 +1,27 @@
package com.red.circle.other.app.dto.cmd;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDate;
/**
* 管理员任务查询命令
*
* @author tf
* @date 2025-11-25
*/
@Data
public class AdminTaskQueryCmd {
/**
* 用户 ID
*/
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* 周期开始日期可选默认当前周期
*/
private LocalDate cycleStartDate;
}

View File

@ -0,0 +1,31 @@
package com.red.circle.other.app.service;
import com.red.circle.other.app.dto.clientobject.AdminTaskRecordCO;
import com.red.circle.other.app.dto.clientobject.AdminTaskSummaryCO;
import com.red.circle.other.app.dto.cmd.AdminTaskInitCmd;
import com.red.circle.other.app.dto.cmd.AdminTaskProgressUpdateCmd;
import com.red.circle.other.app.dto.cmd.AdminTaskQueryCmd;
/**
* 管理员任务服务接口
*
* @author tf
* @date 2025-11-25
*/
public interface AdminTaskService {
/**
* 初始化任务批量创建5个任务
*/
void initTasks(AdminTaskInitCmd cmd);
/**
* 更新任务进度
*/
AdminTaskRecordCO updateTaskProgress(AdminTaskProgressUpdateCmd cmd);
/**
* 查询任务汇总
*/
AdminTaskSummaryCO queryTaskSummary(AdminTaskQueryCmd cmd);
}

View File

@ -0,0 +1,103 @@
package com.red.circle.other.domain.admintask;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 管理员任务记录领域对象
*
* @author tf
* @date 2025-11-25
*/
@Data
public class AdminTaskRecord {
/**
* 主键 ID
*/
private Long id;
/**
* 用户 ID
*/
private Long userId;
/**
* 用户角色
*/
private String userRole;
/**
* 任务周期开始日期
*/
private LocalDate cycleStartDate;
/**
* 任务周期结束日期
*/
private LocalDate cycleEndDate;
/**
* 任务类型
*/
private String taskType;
/**
* 目标数量
*/
private Integer targetCount;
/**
* 已完成数量
*/
private Integer completedCount;
/**
* 任务状态
*/
private String status;
/**
* 完成时间
*/
private LocalDateTime completedAt;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 判断任务是否完成
*/
public boolean isCompleted() {
return AdminTaskStatus.COMPLETED.getCode().equals(status);
}
/**
* 判断任务是否已达到目标
*/
public boolean reachedTarget() {
return completedCount != null && targetCount != null && completedCount >= targetCount;
}
/**
* 计算完成率
*/
public double getCompletionRate() {
if (targetCount == null || targetCount == 0) {
return 0.0;
}
if (completedCount == null) {
return 0.0;
}
return Math.min(100.0, (completedCount * 100.0) / targetCount);
}
}

View File

@ -0,0 +1,55 @@
package com.red.circle.other.domain.admintask;
import lombok.Getter;
/**
* 管理员任务状态枚举
*
* @author tf
* @date 2025-11-25
*/
@Getter
public enum AdminTaskStatus {
/**
* 进行中
*/
IN_PROGRESS("IN_PROGRESS", "进行中"),
/**
* 已完成
*/
COMPLETED("COMPLETED", "已完成"),
/**
* 已过期
*/
EXPIRED("EXPIRED", "已过期");
/**
* 状态编码
*/
private final String code;
/**
* 状态名称
*/
private final String name;
AdminTaskStatus(String code, String name) {
this.code = code;
this.name = name;
}
/**
* 根据 code 获取枚举
*/
public static AdminTaskStatus fromCode(String code) {
for (AdminTaskStatus status : values()) {
if (status.code.equals(code)) {
return status;
}
}
return null;
}
}

View File

@ -0,0 +1,77 @@
package com.red.circle.other.domain.admintask;
import lombok.Getter;
/**
* 管理员任务类型枚举
*
* @author tf
* @date 2025-11-25
*/
@Getter
public enum AdminTaskType {
/**
* 麦克风使用时长
*/
MIC_USAGE("MIC_USAGE", "麦克风使用时长", 20, "小时"),
/**
* 工作天数2小时算1天
*/
WORKING_DAYS("WORKING_DAYS", "工作天数", 10, ""),
/**
* 新绑定 BD Leader
*/
NEW_BD_LEADERS("NEW_BD_LEADERS", "新绑定 BD Leader", 1, ""),
/**
* 新绑定 BD
*/
NEW_BDS("NEW_BDS", "新绑定 BD", 3, ""),
/**
* 新绑定代理
*/
NEW_AGENCIES("NEW_AGENCIES", "新绑定代理", 5, "");
/**
* 任务类型编码
*/
private final String code;
/**
* 任务名称
*/
private final String name;
/**
* 默认目标值
*/
private final int defaultTarget;
/**
* 单位
*/
private final String unit;
AdminTaskType(String code, String name, int defaultTarget, String unit) {
this.code = code;
this.name = name;
this.defaultTarget = defaultTarget;
this.unit = unit;
}
/**
* 根据 code 获取枚举
*/
public static AdminTaskType fromCode(String code) {
for (AdminTaskType type : values()) {
if (type.code.equals(code)) {
return type;
}
}
return null;
}
}

View File

@ -0,0 +1,81 @@
package com.red.circle.other.domain.gateway;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import java.time.LocalDate;
import java.util.List;
/**
* 管理员任务网关接口
*
* @author tf
* @date 2025-11-25
*/
public interface AdminTaskGateway {
/**
* 批量创建任务记录
*
* @param records 任务记录列表
*/
void batchInsert(List<AdminTaskRecord> records);
/**
* 查询用户指定周期的所有任务
*
* @param userId 用户 ID
* @param cycleStartDate 周期开始日期
* @return 任务记录列表
*/
List<AdminTaskRecord> findByUserIdAndCycle(Long userId, LocalDate cycleStartDate);
/**
* 查询用户指定周期的特定任务类型
*
* @param userId 用户 ID
* @param taskType 任务类型
* @param cycleStartDate 周期开始日期
* @return 任务记录
*/
AdminTaskRecord findByUserIdAndTaskTypeAndCycle(Long userId, String taskType, LocalDate cycleStartDate);
/**
* 增量更新任务完成数量原子操作
*
* @param userId 用户 ID
* @param taskType 任务类型
* @param cycleStartDate 周期开始日期
* @param incrementValue 增量值
* @return 更新后的记录
*/
AdminTaskRecord incrementCompletedCount(Long userId, String taskType, LocalDate cycleStartDate, int incrementValue);
/**
* 绝对值更新任务完成数量用于工作天数计算
*
* @param userId 用户 ID
* @param taskType 任务类型
* @param cycleStartDate 周期开始日期
* @param absoluteValue 绝对值
* @return 更新后的记录
*/
AdminTaskRecord updateCompletedCountAbsolute(Long userId, String taskType, LocalDate cycleStartDate, int absoluteValue);
/**
* 更新任务状态为已完成
*
* @param userId 用户 ID
* @param taskType 任务类型
* @param cycleStartDate 周期开始日期
*/
void markAsCompleted(Long userId, String taskType, LocalDate cycleStartDate);
/**
* 检查用户指定周期是否已初始化任务
*
* @param userId 用户 ID
* @param cycleStartDate 周期开始日期
* @return 是否存在
*/
boolean existsByUserIdAndCycle(Long userId, LocalDate cycleStartDate);
}

View File

@ -0,0 +1,66 @@
package com.red.circle.other.infra.database.mongo.document;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.CompoundIndexes;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 管理员任务记录 MongoDB 文档
*
* @author tf
* @date 2025-11-25
*/
@Data
@Document(collection = "admin_task_record")
@CompoundIndexes({
@CompoundIndex(name = "uk_user_cycle_type", def = "{'user_id': 1, 'cycle_start_date': 1, 'task_type': 1}", unique = true),
@CompoundIndex(name = "idx_user_role", def = "{'user_id': 1, 'user_role': 1}"),
@CompoundIndex(name = "idx_cycle", def = "{'cycle_start_date': 1, 'cycle_end_date': 1}")
})
public class AdminTaskRecordDO {
@Id
private String id;
@Field("user_id")
private Long userId;
@Field("user_role")
private String userRole;
@Field("cycle_start_date")
private LocalDate cycleStartDate;
@Field("cycle_end_date")
private LocalDate cycleEndDate;
@Field("task_type")
@Indexed
private String taskType;
@Field("target_count")
private Integer targetCount;
@Field("completed_count")
private Integer completedCount;
@Field("status")
@Indexed
private String status;
@Field("completed_at")
private LocalDateTime completedAt;
@Field("create_time")
private LocalDateTime createTime;
@Field("update_time")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,34 @@
package com.red.circle.other.infra.database.mongo.repository;
import com.red.circle.other.infra.database.mongo.document.AdminTaskRecordDO;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
/**
* 管理员任务记录 Repository
*
* @author tf
* @date 2025-11-25
*/
@Repository
public interface AdminTaskRecordRepository extends MongoRepository<AdminTaskRecordDO, String> {
/**
* 查询用户指定周期的所有任务
*/
List<AdminTaskRecordDO> findByUserIdAndCycleStartDate(Long userId, LocalDate cycleStartDate);
/**
* 查询用户指定周期的特定任务类型
*/
Optional<AdminTaskRecordDO> findByUserIdAndTaskTypeAndCycleStartDate(Long userId, String taskType, LocalDate cycleStartDate);
/**
* 检查是否存在
*/
boolean existsByUserIdAndCycleStartDate(Long userId, LocalDate cycleStartDate);
}

View File

@ -0,0 +1,139 @@
package com.red.circle.other.infra.gateway;
import com.red.circle.other.domain.admintask.AdminTaskRecord;
import com.red.circle.other.domain.admintask.AdminTaskStatus;
import com.red.circle.other.domain.gateway.AdminTaskGateway;
import com.red.circle.other.infra.database.mongo.document.AdminTaskRecordDO;
import com.red.circle.other.infra.database.mongo.repository.AdminTaskRecordRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
* 管理员任务网关实现
*
* @author tf
* @date 2025-11-25
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class AdminTaskGatewayImpl implements AdminTaskGateway {
private final AdminTaskRecordRepository adminTaskRecordRepository;
private final MongoTemplate mongoTemplate;
@Override
public void batchInsert(List<AdminTaskRecord> records) {
List<AdminTaskRecordDO> doList = records.stream()
.map(this::toDO)
.collect(Collectors.toList());
adminTaskRecordRepository.saveAll(doList);
}
@Override
public List<AdminTaskRecord> findByUserIdAndCycle(Long userId, LocalDate cycleStartDate) {
List<AdminTaskRecordDO> doList = adminTaskRecordRepository.findByUserIdAndCycleStartDate(userId, cycleStartDate);
return doList.stream()
.map(this::toDomain)
.collect(Collectors.toList());
}
@Override
public AdminTaskRecord findByUserIdAndTaskTypeAndCycle(Long userId, String taskType, LocalDate cycleStartDate) {
return adminTaskRecordRepository.findByUserIdAndTaskTypeAndCycleStartDate(userId, taskType, cycleStartDate)
.map(this::toDomain)
.orElse(null);
}
@Override
public AdminTaskRecord incrementCompletedCount(Long userId, String taskType, LocalDate cycleStartDate, int incrementValue) {
Query query = Query.query(Criteria.where("user_id").is(userId)
.and("task_type").is(taskType)
.and("cycle_start_date").is(cycleStartDate));
Update update = new Update()
.inc("completed_count", incrementValue)
.set("update_time", LocalDateTime.now());
mongoTemplate.updateFirst(query, update, AdminTaskRecordDO.class);
return findByUserIdAndTaskTypeAndCycle(userId, taskType, cycleStartDate);
}
@Override
public AdminTaskRecord updateCompletedCountAbsolute(Long userId, String taskType, LocalDate cycleStartDate, int absoluteValue) {
Query query = Query.query(Criteria.where("user_id").is(userId)
.and("task_type").is(taskType)
.and("cycle_start_date").is(cycleStartDate));
Update update = new Update()
.set("completed_count", absoluteValue)
.set("update_time", LocalDateTime.now());
mongoTemplate.updateFirst(query, update, AdminTaskRecordDO.class);
return findByUserIdAndTaskTypeAndCycle(userId, taskType, cycleStartDate);
}
@Override
public void markAsCompleted(Long userId, String taskType, LocalDate cycleStartDate) {
Query query = Query.query(Criteria.where("user_id").is(userId)
.and("task_type").is(taskType)
.and("cycle_start_date").is(cycleStartDate));
Update update = new Update()
.set("status", AdminTaskStatus.COMPLETED.getCode())
.set("completed_at", LocalDateTime.now())
.set("update_time", LocalDateTime.now());
mongoTemplate.updateFirst(query, update, AdminTaskRecordDO.class);
}
@Override
public boolean existsByUserIdAndCycle(Long userId, LocalDate cycleStartDate) {
return adminTaskRecordRepository.existsByUserIdAndCycleStartDate(userId, cycleStartDate);
}
private AdminTaskRecordDO toDO(AdminTaskRecord record) {
AdminTaskRecordDO dobj = new AdminTaskRecordDO();
dobj.setUserId(record.getUserId());
dobj.setUserRole(record.getUserRole());
dobj.setCycleStartDate(record.getCycleStartDate());
dobj.setCycleEndDate(record.getCycleEndDate());
dobj.setTaskType(record.getTaskType());
dobj.setTargetCount(record.getTargetCount());
dobj.setCompletedCount(record.getCompletedCount());
dobj.setStatus(record.getStatus());
dobj.setCompletedAt(record.getCompletedAt());
dobj.setCreateTime(record.getCreateTime() != null ? record.getCreateTime() : LocalDateTime.now());
dobj.setUpdateTime(record.getUpdateTime() != null ? record.getUpdateTime() : LocalDateTime.now());
return dobj;
}
private AdminTaskRecord toDomain(AdminTaskRecordDO dobj) {
AdminTaskRecord record = new AdminTaskRecord();
record.setId(dobj.getId() != null ? Long.parseLong(dobj.getId()) : null);
record.setUserId(dobj.getUserId());
record.setUserRole(dobj.getUserRole());
record.setCycleStartDate(dobj.getCycleStartDate());
record.setCycleEndDate(dobj.getCycleEndDate());
record.setTaskType(dobj.getTaskType());
record.setTargetCount(dobj.getTargetCount());
record.setCompletedCount(dobj.getCompletedCount());
record.setStatus(dobj.getStatus());
record.setCompletedAt(dobj.getCompletedAt());
record.setCreateTime(dobj.getCreateTime());
record.setUpdateTime(dobj.getUpdateTime());
return record;
}
}