新增待办任务通用领域服务

This commit is contained in:
jsowell
2026-07-16 16:11:38 +08:00
parent e65017ab22
commit 181d4a5b40
9 changed files with 757 additions and 4 deletions

View File

@@ -41,8 +41,8 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
| 批次 | 范围 | 优先级 | 状态 | 验收结果 | Commit |
| --- | --- | --- | --- | --- | --- |
| B01 | 任务拆分、数据表和索引 | P0 | done | SQL 结构和索引评审通过 | 本批提交 |
| B02 | 实体、命令模型、枚举、Mapper、Service | P0 | todo | - | - |
| B01 | 任务拆分、数据表和索引 | P0 | done | SQL 结构和索引评审通过 | `e65017ab2` |
| B02 | 实体、命令模型、枚举、Mapper、Service | P0 | done | 模块编译和 Mapper XML 校验通过 | 本批提交 |
| B03 | 当前用户查询、已读、完成、取消接口及测试 | P0 | todo | - | - |
| B04 | 前端 API、待办中心页面和路由跳转 | P0 | todo | - | - |
| B05 | 首页待办卡片、数量展示和轮询刷新 | P0 | todo | - | - |
@@ -72,7 +72,7 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
- 优先级P0
- 批次B02
- 状态:todo
- 状态done
- 目标新增实体、创建命令、状态常量、Mapper 和统一 `TodoTaskService`
- 验收标准:
- 创建接口校验必要字段并设置默认状态、优先级和阅读状态。
@@ -173,4 +173,6 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
每完成一个批次,在此追加:完成时间、验证命令、结果和 commit hash。
- 2026-07-16B01完成优先级拆分、任务跟踪文档和 `sys_todo_task` 建表脚本;通过 SQL 人工结构评审与 `git diff --check`commit hash 在下一批记录中回填。
- 2026-07-16B01完成优先级拆分、任务跟踪文档和 `sys_todo_task` 建表脚本;通过 SQL 人工结构评审与 `git diff --check`commit `e65017ab2`
- 2026-07-16B01 环境进展:用户已在测试数据库创建 `sys_todo_task` 表,可供后续接口联调。
- 2026-07-16B02完成领域模型、创建/查询 DTO、状态常量、Mapper 和统一 Service`mvn -pl jsowell-system -am -DskipTests compile` 与 Mapper XML 语法校验通过commit hash 在下一批记录中回填。

View File

@@ -0,0 +1,44 @@
package com.jsowell.system.constant;
/**
* 待办任务常量。
*
* @author jsowell
*/
public final class TodoTaskConstants {
private TodoTaskConstants() {
}
public static final String STATUS_PENDING = "PENDING";
public static final String STATUS_PROCESSING = "PROCESSING";
public static final String STATUS_COMPLETED = "COMPLETED";
public static final String STATUS_CANCELLED = "CANCELLED";
public static final String STATUS_EXPIRED = "EXPIRED";
public static final String STATUS_ACTIVE = "ACTIVE";
public static final String READ_UNREAD = "0";
public static final String READ_READ = "1";
public static final int PRIORITY_NORMAL = 1;
public static final int PRIORITY_IMPORTANT = 2;
public static final int PRIORITY_URGENT = 3;
public static final int DEFAULT_HOME_LIMIT = 3;
public static final int MAX_HOME_LIMIT = 10;
public static boolean isActiveStatus(String status) {
return STATUS_PENDING.equals(status) || STATUS_PROCESSING.equals(status);
}
public static boolean isTerminalStatus(String status) {
return STATUS_COMPLETED.equals(status)
|| STATUS_CANCELLED.equals(status)
|| STATUS_EXPIRED.equals(status);
}
public static boolean isSupportedStatus(String status) {
return STATUS_ACTIVE.equals(status)
|| isActiveStatus(status)
|| isTerminalStatus(status);
}
}

View File

@@ -0,0 +1,47 @@
package com.jsowell.system.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.jsowell.common.core.domain.BaseEntity;
import lombok.Data;
import java.util.Date;
/**
* 用户待办任务表 sys_todo_task。
*
* @author jsowell
*/
@Data
public class SysTodoTask extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long todoId;
private String taskType;
private String title;
private String summary;
private String content;
private String businessType;
private String businessId;
private String routeName;
private String routeParams;
private Long assigneeUserId;
private String assigneeMerchantId;
private Integer priority;
private String taskStatus;
private String readStatus;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date readTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date dueTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date completedTime;
private Long completedBy;
private String cancelReason;
private String idempotentKey;
private String activeIdempotentKey;
private String delFlag;
}

View File

@@ -0,0 +1,38 @@
package com.jsowell.system.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 创建待办任务命令。
*
* @author jsowell
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TodoTaskCreateCommand implements Serializable {
private static final long serialVersionUID = 1L;
private String taskType;
private String title;
private String summary;
private String content;
private String businessType;
private String businessId;
private String routeName;
private String routeParams;
private Long assigneeUserId;
private String assigneeMerchantId;
private Integer priority;
private Date dueTime;
private String idempotentKey;
private String createBy;
private String remark;
}

View File

@@ -0,0 +1,23 @@
package com.jsowell.system.domain.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 当前用户待办查询条件。
*
* @author jsowell
*/
@Data
public class TodoTaskQuery implements Serializable {
private static final long serialVersionUID = 1L;
/** 由服务端覆盖,不信任请求参数。 */
private Long assigneeUserId;
private String taskStatus;
private String readStatus;
private String taskType;
private String keyword;
private Boolean hideCompleted;
}

View File

@@ -0,0 +1,59 @@
package com.jsowell.system.mapper;
import com.jsowell.system.domain.SysTodoTask;
import com.jsowell.system.domain.dto.TodoTaskQuery;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 待办任务数据层。
*
* @author jsowell
*/
public interface SysTodoTaskMapper {
SysTodoTask selectTodoById(@Param("todoId") Long todoId);
SysTodoTask selectTodoByIdForAssignee(@Param("todoId") Long todoId,
@Param("assigneeUserId") Long assigneeUserId);
SysTodoTask selectActiveByIdempotentKey(@Param("activeIdempotentKey") String activeIdempotentKey);
List<SysTodoTask> selectTodoList(TodoTaskQuery query);
List<SysTodoTask> selectHomeList(@Param("assigneeUserId") Long assigneeUserId,
@Param("limit") int limit);
int countActive(@Param("assigneeUserId") Long assigneeUserId);
int countUnread(@Param("assigneeUserId") Long assigneeUserId);
int insertTodoTask(SysTodoTask todoTask);
int markTodoRead(@Param("todoId") Long todoId,
@Param("assigneeUserId") Long assigneeUserId,
@Param("updateBy") String updateBy);
int markAllRead(@Param("assigneeUserId") Long assigneeUserId,
@Param("updateBy") String updateBy);
int completeTodoForAssignee(@Param("todoId") Long todoId,
@Param("assigneeUserId") Long assigneeUserId,
@Param("completedBy") Long completedBy,
@Param("updateBy") String updateBy);
int completeTodoByBusiness(@Param("businessType") String businessType,
@Param("businessId") String businessId,
@Param("assigneeUserId") Long assigneeUserId,
@Param("completedBy") Long completedBy,
@Param("updateBy") String updateBy);
int cancelTodoForAssignee(@Param("todoId") Long todoId,
@Param("assigneeUserId") Long assigneeUserId,
@Param("reason") String reason,
@Param("updateBy") String updateBy);
int cancelTodo(@Param("todoId") Long todoId,
@Param("reason") String reason,
@Param("updateBy") String updateBy);
}

View File

@@ -0,0 +1,39 @@
package com.jsowell.system.service;
import com.jsowell.system.domain.SysTodoTask;
import com.jsowell.system.domain.dto.TodoTaskCreateCommand;
import com.jsowell.system.domain.dto.TodoTaskQuery;
import java.util.List;
/**
* 统一待办任务服务。
*
* @author jsowell
*/
public interface TodoTaskService {
SysTodoTask createTask(TodoTaskCreateCommand command);
SysTodoTask getForAssignee(Long todoId, Long assigneeUserId);
List<SysTodoTask> listForAssignee(TodoTaskQuery query, Long assigneeUserId);
List<SysTodoTask> homeList(Long assigneeUserId, Integer limit);
int countActive(Long assigneeUserId);
int countUnread(Long assigneeUserId);
boolean markRead(Long todoId, Long assigneeUserId, String operatorName);
int markAllRead(Long assigneeUserId, String operatorName);
boolean complete(Long todoId, Long assigneeUserId, String operatorName);
int completeByBusiness(String businessType, String businessId, Long assigneeUserId,
Long operatorId, String operatorName);
boolean cancelForAssignee(Long todoId, Long assigneeUserId, String operatorName, String reason);
boolean cancel(Long todoId, Long operatorId, String operatorName, String reason);
}

View File

@@ -0,0 +1,286 @@
package com.jsowell.system.service.impl;
import com.jsowell.common.exception.ServiceException;
import com.jsowell.common.util.StringUtils;
import com.jsowell.system.constant.TodoTaskConstants;
import com.jsowell.system.domain.SysTodoTask;
import com.jsowell.system.domain.dto.TodoTaskCreateCommand;
import com.jsowell.system.domain.dto.TodoTaskQuery;
import com.jsowell.system.mapper.SysTodoTaskMapper;
import com.jsowell.system.service.TodoTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 统一待办任务服务实现。
*
* @author jsowell
*/
@Service
public class TodoTaskServiceImpl implements TodoTaskService {
private static final String SYSTEM_OPERATOR = "system";
@Autowired
private SysTodoTaskMapper todoTaskMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public SysTodoTask createTask(TodoTaskCreateCommand command) {
if (command == null) {
throw new ServiceException("待办创建参数不能为空");
}
SysTodoTask todoTask = buildTask(command);
SysTodoTask existingTask = todoTaskMapper.selectActiveByIdempotentKey(todoTask.getActiveIdempotentKey());
if (existingTask != null) {
return existingTask;
}
try {
todoTaskMapper.insertTodoTask(todoTask);
return todoTask;
} catch (DuplicateKeyException exception) {
existingTask = todoTaskMapper.selectActiveByIdempotentKey(todoTask.getActiveIdempotentKey());
if (existingTask != null) {
return existingTask;
}
throw exception;
}
}
@Override
public SysTodoTask getForAssignee(Long todoId, Long assigneeUserId) {
validateIdentity(todoId, assigneeUserId);
SysTodoTask todoTask = todoTaskMapper.selectTodoByIdForAssignee(todoId, assigneeUserId);
if (todoTask == null) {
throw new ServiceException("待办任务不存在或无权访问");
}
return todoTask;
}
@Override
public List<SysTodoTask> listForAssignee(TodoTaskQuery query, Long assigneeUserId) {
validateUserId(assigneeUserId);
TodoTaskQuery safeQuery = query == null ? new TodoTaskQuery() : query;
validateQuery(safeQuery);
safeQuery.setAssigneeUserId(assigneeUserId);
return todoTaskMapper.selectTodoList(safeQuery);
}
@Override
public List<SysTodoTask> homeList(Long assigneeUserId, Integer limit) {
validateUserId(assigneeUserId);
int safeLimit = limit == null ? TodoTaskConstants.DEFAULT_HOME_LIMIT : limit;
if (safeLimit < 1) {
safeLimit = TodoTaskConstants.DEFAULT_HOME_LIMIT;
}
if (safeLimit > TodoTaskConstants.MAX_HOME_LIMIT) {
safeLimit = TodoTaskConstants.MAX_HOME_LIMIT;
}
return todoTaskMapper.selectHomeList(assigneeUserId, safeLimit);
}
@Override
public int countActive(Long assigneeUserId) {
validateUserId(assigneeUserId);
return todoTaskMapper.countActive(assigneeUserId);
}
@Override
public int countUnread(Long assigneeUserId) {
validateUserId(assigneeUserId);
return todoTaskMapper.countUnread(assigneeUserId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean markRead(Long todoId, Long assigneeUserId, String operatorName) {
validateIdentity(todoId, assigneeUserId);
int rows = todoTaskMapper.markTodoRead(todoId, assigneeUserId, normalizeOperator(operatorName, assigneeUserId));
if (rows > 0) {
return true;
}
SysTodoTask todoTask = getForAssignee(todoId, assigneeUserId);
return TodoTaskConstants.READ_READ.equals(todoTask.getReadStatus());
}
@Override
@Transactional(rollbackFor = Exception.class)
public int markAllRead(Long assigneeUserId, String operatorName) {
validateUserId(assigneeUserId);
return todoTaskMapper.markAllRead(assigneeUserId, normalizeOperator(operatorName, assigneeUserId));
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean complete(Long todoId, Long assigneeUserId, String operatorName) {
validateIdentity(todoId, assigneeUserId);
int rows = todoTaskMapper.completeTodoForAssignee(todoId, assigneeUserId, assigneeUserId,
normalizeOperator(operatorName, assigneeUserId));
if (rows > 0) {
return true;
}
SysTodoTask todoTask = getForAssignee(todoId, assigneeUserId);
if (TodoTaskConstants.STATUS_COMPLETED.equals(todoTask.getTaskStatus())) {
return true;
}
throw new ServiceException("当前待办状态不允许完成");
}
@Override
@Transactional(rollbackFor = Exception.class)
public int completeByBusiness(String businessType, String businessId, Long assigneeUserId,
Long operatorId, String operatorName) {
String safeBusinessType = normalizeRequired(businessType, "业务类型", 64);
String safeBusinessId = normalizeRequired(businessId, "业务主键", 64);
if (assigneeUserId != null) {
validateUserId(assigneeUserId);
}
if (operatorId == null || operatorId <= 0) {
throw new ServiceException("待办完成人不能为空");
}
return todoTaskMapper.completeTodoByBusiness(safeBusinessType, safeBusinessId, assigneeUserId,
operatorId, normalizeOperator(operatorName, operatorId));
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean cancelForAssignee(Long todoId, Long assigneeUserId, String operatorName, String reason) {
validateIdentity(todoId, assigneeUserId);
String safeReason = normalizeRequired(reason, "取消原因", 500);
int rows = todoTaskMapper.cancelTodoForAssignee(todoId, assigneeUserId, safeReason,
normalizeOperator(operatorName, assigneeUserId));
if (rows > 0) {
return true;
}
SysTodoTask todoTask = getForAssignee(todoId, assigneeUserId);
if (TodoTaskConstants.STATUS_CANCELLED.equals(todoTask.getTaskStatus())) {
return true;
}
throw new ServiceException("当前待办状态不允许取消");
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean cancel(Long todoId, Long operatorId, String operatorName, String reason) {
if (todoId == null || todoId <= 0) {
throw new ServiceException("待办任务 ID 不能为空");
}
if (operatorId == null || operatorId <= 0) {
throw new ServiceException("取消操作人不能为空");
}
String safeReason = normalizeRequired(reason, "取消原因", 500);
int rows = todoTaskMapper.cancelTodo(todoId, safeReason, normalizeOperator(operatorName, operatorId));
if (rows > 0) {
return true;
}
SysTodoTask todoTask = todoTaskMapper.selectTodoById(todoId);
if (todoTask == null) {
throw new ServiceException("待办任务不存在");
}
if (TodoTaskConstants.STATUS_CANCELLED.equals(todoTask.getTaskStatus())) {
return true;
}
throw new ServiceException("当前待办状态不允许取消");
}
private SysTodoTask buildTask(TodoTaskCreateCommand command) {
if (command.getAssigneeUserId() == null || command.getAssigneeUserId() <= 0) {
throw new ServiceException("待办接收用户不能为空");
}
Integer priority = command.getPriority() == null
? TodoTaskConstants.PRIORITY_NORMAL : command.getPriority();
if (priority < TodoTaskConstants.PRIORITY_NORMAL || priority > TodoTaskConstants.PRIORITY_URGENT) {
throw new ServiceException("待办优先级只能为 1、2 或 3");
}
SysTodoTask todoTask = new SysTodoTask();
todoTask.setTaskType(normalizeRequired(command.getTaskType(), "待办类型", 64));
todoTask.setTitle(normalizeRequired(command.getTitle(), "待办标题", 200));
todoTask.setSummary(normalizeOptional(command.getSummary(), "待办摘要", 500));
todoTask.setContent(normalizeOptional(command.getContent(), "待办内容", 20000));
todoTask.setBusinessType(normalizeRequired(command.getBusinessType(), "业务类型", 64));
todoTask.setBusinessId(normalizeRequired(command.getBusinessId(), "业务主键", 64));
todoTask.setRouteName(normalizeRequired(command.getRouteName(), "业务路由", 100));
todoTask.setRouteParams(normalizeOptional(command.getRouteParams(), "路由参数", 1000));
todoTask.setAssigneeUserId(command.getAssigneeUserId());
todoTask.setAssigneeMerchantId(normalizeOptional(command.getAssigneeMerchantId(), "运营商 ID", 64));
todoTask.setPriority(priority);
todoTask.setTaskStatus(TodoTaskConstants.STATUS_PENDING);
todoTask.setReadStatus(TodoTaskConstants.READ_UNREAD);
todoTask.setDueTime(command.getDueTime());
todoTask.setIdempotentKey(normalizeRequired(command.getIdempotentKey(), "幂等键", 200));
todoTask.setActiveIdempotentKey(todoTask.getIdempotentKey());
todoTask.setCreateBy(normalizeOperator(command.getCreateBy(), null));
todoTask.setRemark(normalizeOptional(command.getRemark(), "备注", 500));
todoTask.setDelFlag("0");
return todoTask;
}
private void validateQuery(TodoTaskQuery query) {
if (StringUtils.isNotEmpty(query.getTaskStatus())
&& !TodoTaskConstants.isSupportedStatus(query.getTaskStatus())) {
throw new ServiceException("不支持的待办状态筛选条件");
}
if (StringUtils.isNotEmpty(query.getReadStatus())
&& !TodoTaskConstants.READ_UNREAD.equals(query.getReadStatus())
&& !TodoTaskConstants.READ_READ.equals(query.getReadStatus())) {
throw new ServiceException("不支持的阅读状态筛选条件");
}
query.setTaskType(normalizeOptional(query.getTaskType(), "待办类型", 64));
query.setKeyword(normalizeOptional(query.getKeyword(), "关键字", 100));
}
private void validateIdentity(Long todoId, Long assigneeUserId) {
if (todoId == null || todoId <= 0) {
throw new ServiceException("待办任务 ID 不能为空");
}
validateUserId(assigneeUserId);
}
private void validateUserId(Long userId) {
if (userId == null || userId <= 0) {
throw new ServiceException("待办接收用户不能为空");
}
}
private String normalizeRequired(String value, String fieldName, int maxLength) {
String safeValue = StringUtils.trim(value);
if (StringUtils.isEmpty(safeValue)) {
throw new ServiceException(fieldName + "不能为空");
}
if (safeValue.length() > maxLength) {
throw new ServiceException(fieldName + "不能超过" + maxLength + "个字符");
}
return safeValue;
}
private String normalizeOptional(String value, String fieldName, int maxLength) {
if (StringUtils.isEmpty(value)) {
return null;
}
String safeValue = value.trim();
if (safeValue.length() > maxLength) {
throw new ServiceException(fieldName + "不能超过" + maxLength + "个字符");
}
return safeValue;
}
private String normalizeOperator(String operatorName, Long operatorId) {
String safeOperator = StringUtils.isNotEmpty(operatorName)
? operatorName.trim()
: (operatorId == null ? SYSTEM_OPERATOR : String.valueOf(operatorId));
if (safeOperator.length() > 64) {
throw new ServiceException("操作人名称不能超过64个字符");
}
return safeOperator;
}
}

View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jsowell.system.mapper.SysTodoTaskMapper">
<resultMap type="SysTodoTask" id="SysTodoTaskResult">
<id property="todoId" column="todo_id" />
<result property="taskType" column="task_type" />
<result property="title" column="title" />
<result property="summary" column="summary" />
<result property="content" column="content" />
<result property="businessType" column="business_type" />
<result property="businessId" column="business_id" />
<result property="routeName" column="route_name" />
<result property="routeParams" column="route_params" />
<result property="assigneeUserId" column="assignee_user_id" />
<result property="assigneeMerchantId" column="assignee_merchant_id" />
<result property="priority" column="priority" />
<result property="taskStatus" column="task_status" />
<result property="readStatus" column="read_status" />
<result property="readTime" column="read_time" />
<result property="dueTime" column="due_time" />
<result property="completedTime" column="completed_time" />
<result property="completedBy" column="completed_by" />
<result property="cancelReason" column="cancel_reason" />
<result property="idempotentKey" column="idempotent_key" />
<result property="activeIdempotentKey" column="active_idempotent_key" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<result property="delFlag" column="del_flag" />
</resultMap>
<sql id="selectTodoVo">
select todo_id, task_type, title, summary, cast(content as char) as content,
business_type, business_id, route_name, route_params,
assignee_user_id, assignee_merchant_id, priority, task_status,
read_status, read_time, due_time, completed_time, completed_by,
cancel_reason, idempotent_key, active_idempotent_key,
create_by, create_time, update_by, update_time, remark, del_flag
from sys_todo_task
</sql>
<select id="selectTodoById" parameterType="Long" resultMap="SysTodoTaskResult">
<include refid="selectTodoVo" />
where todo_id = #{todoId}
and del_flag = '0'
</select>
<select id="selectTodoByIdForAssignee" resultMap="SysTodoTaskResult">
<include refid="selectTodoVo" />
where todo_id = #{todoId}
and assignee_user_id = #{assigneeUserId}
and del_flag = '0'
</select>
<select id="selectActiveByIdempotentKey" parameterType="String" resultMap="SysTodoTaskResult">
<include refid="selectTodoVo" />
where active_idempotent_key = #{activeIdempotentKey}
and del_flag = '0'
limit 1
</select>
<select id="selectTodoList" parameterType="com.jsowell.system.domain.dto.TodoTaskQuery"
resultMap="SysTodoTaskResult">
<include refid="selectTodoVo" />
<where>
del_flag = '0'
and assignee_user_id = #{assigneeUserId}
<if test="taskStatus != null and taskStatus == 'ACTIVE'">
and task_status in ('PENDING', 'PROCESSING')
</if>
<if test="taskStatus != null and taskStatus != '' and taskStatus != 'ACTIVE'">
and task_status = #{taskStatus}
</if>
<if test="readStatus != null and readStatus != ''">
and read_status = #{readStatus}
</if>
<if test="taskType != null and taskType != ''">
and task_type = #{taskType}
</if>
<if test="keyword != null and keyword != ''">
and (title like concat('%', #{keyword}, '%')
or business_id like concat('%', #{keyword}, '%'))
</if>
<if test="hideCompleted != null and hideCompleted">
and task_status != 'COMPLETED'
</if>
</where>
order by priority desc, create_time desc, todo_id desc
</select>
<select id="selectHomeList" resultMap="SysTodoTaskResult">
<include refid="selectTodoVo" />
where assignee_user_id = #{assigneeUserId}
and task_status in ('PENDING', 'PROCESSING')
and del_flag = '0'
order by priority desc, create_time desc, todo_id desc
limit #{limit}
</select>
<select id="countActive" parameterType="Long" resultType="int">
select count(1)
from sys_todo_task
where assignee_user_id = #{assigneeUserId}
and task_status in ('PENDING', 'PROCESSING')
and del_flag = '0'
</select>
<select id="countUnread" parameterType="Long" resultType="int">
select count(1)
from sys_todo_task
where assignee_user_id = #{assigneeUserId}
and task_status in ('PENDING', 'PROCESSING')
and read_status = '0'
and del_flag = '0'
</select>
<insert id="insertTodoTask" parameterType="SysTodoTask" useGeneratedKeys="true" keyProperty="todoId">
insert into sys_todo_task (
task_type, title, summary, content, business_type, business_id,
route_name, route_params, assignee_user_id, assignee_merchant_id,
priority, task_status, read_status, due_time, idempotent_key,
active_idempotent_key, create_by, create_time, remark, del_flag
) values (
#{taskType}, #{title}, #{summary}, #{content}, #{businessType}, #{businessId},
#{routeName}, #{routeParams}, #{assigneeUserId}, #{assigneeMerchantId},
#{priority}, #{taskStatus}, #{readStatus}, #{dueTime}, #{idempotentKey},
#{activeIdempotentKey}, #{createBy}, sysdate(), #{remark}, #{delFlag}
)
</insert>
<update id="markTodoRead">
update sys_todo_task
set read_status = '1',
read_time = sysdate(),
update_by = #{updateBy},
update_time = sysdate()
where todo_id = #{todoId}
and assignee_user_id = #{assigneeUserId}
and read_status = '0'
and del_flag = '0'
</update>
<update id="markAllRead">
update sys_todo_task
set read_status = '1',
read_time = sysdate(),
update_by = #{updateBy},
update_time = sysdate()
where assignee_user_id = #{assigneeUserId}
and read_status = '0'
and del_flag = '0'
</update>
<update id="completeTodoForAssignee">
update sys_todo_task
set task_status = 'COMPLETED',
completed_time = sysdate(),
completed_by = #{completedBy},
active_idempotent_key = null,
update_by = #{updateBy},
update_time = sysdate()
where todo_id = #{todoId}
and assignee_user_id = #{assigneeUserId}
and task_status in ('PENDING', 'PROCESSING')
and del_flag = '0'
</update>
<update id="completeTodoByBusiness">
update sys_todo_task
set task_status = 'COMPLETED',
completed_time = sysdate(),
completed_by = #{completedBy},
active_idempotent_key = null,
update_by = #{updateBy},
update_time = sysdate()
where business_type = #{businessType}
and business_id = #{businessId}
<if test="assigneeUserId != null">
and assignee_user_id = #{assigneeUserId}
</if>
and task_status in ('PENDING', 'PROCESSING')
and del_flag = '0'
</update>
<update id="cancelTodoForAssignee">
update sys_todo_task
set task_status = 'CANCELLED',
cancel_reason = #{reason},
active_idempotent_key = null,
update_by = #{updateBy},
update_time = sysdate()
where todo_id = #{todoId}
and assignee_user_id = #{assigneeUserId}
and task_status in ('PENDING', 'PROCESSING')
and del_flag = '0'
</update>
<update id="cancelTodo">
update sys_todo_task
set task_status = 'CANCELLED',
cancel_reason = #{reason},
active_idempotent_key = null,
update_by = #{updateBy},
update_time = sysdate()
where todo_id = #{todoId}
and task_status in ('PENDING', 'PROCESSING')
and del_flag = '0'
</update>
</mapper>