优化订单任务列表排序并补充上线文档
This commit is contained in:
@@ -38,6 +38,8 @@ public class ReservationOrderEntity {
|
||||
private Long sourceMessageId;
|
||||
/** 首次创建该订单的任务 ID,CP1-3 允许为空。 */
|
||||
private Long createdFromTaskId;
|
||||
/** 订单最近业务活动 UTC 时间,用于订单列表按最新活动排序。 */
|
||||
private LocalDateTime latestActivityAt;
|
||||
/** 订单进入 ENDED 状态的 UTC 时间。 */
|
||||
private LocalDateTime endedAt;
|
||||
/** 逻辑删除 UTC 时间。 */
|
||||
@@ -77,6 +79,8 @@ public class ReservationOrderEntity {
|
||||
public void setSourceMessageId(Long sourceMessageId) { this.sourceMessageId = sourceMessageId; }
|
||||
public Long getCreatedFromTaskId() { return createdFromTaskId; }
|
||||
public void setCreatedFromTaskId(Long createdFromTaskId) { this.createdFromTaskId = createdFromTaskId; }
|
||||
public LocalDateTime getLatestActivityAt() { return latestActivityAt; }
|
||||
public void setLatestActivityAt(LocalDateTime latestActivityAt) { this.latestActivityAt = latestActivityAt; }
|
||||
public LocalDateTime getEndedAt() { return endedAt; }
|
||||
public void setEndedAt(LocalDateTime endedAt) { this.endedAt = endedAt; }
|
||||
public LocalDateTime getLogicDeletedAt() { return logicDeletedAt; }
|
||||
|
||||
@@ -2,11 +2,72 @@ package cn.nianxx.thhotel.workflows.reservation.mapper;
|
||||
|
||||
import cn.nianxx.thhotel.workflows.reservation.domain.ReservationOrderEntity;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* Reservation 订单 Mapper,只负责本表持久化访问。
|
||||
*/
|
||||
@Mapper
|
||||
public interface ReservationOrderMapper extends BaseMapper<ReservationOrderEntity> {
|
||||
|
||||
/**
|
||||
* 分页查询前端订单列表。排序按订单维护的最新业务活动时间倒序,避免每次列表查询聚合全量任务。
|
||||
*/
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT o.*
|
||||
FROM workflow_reservation_order o
|
||||
WHERE o.hotel_id = #{hotelId}
|
||||
AND o.order_visibility != #{hiddenSystemVisibility}
|
||||
<if test="orderStatus != null and orderStatus != ''">
|
||||
AND o.order_status = #{orderStatus}
|
||||
</if>
|
||||
<if test="groupCode != null and groupCode != ''">
|
||||
AND (
|
||||
o.order_business_key LIKE CONCAT('%', #{groupCode}, '%')
|
||||
OR o.active_business_key LIKE CONCAT('%', #{groupCode}, '%')
|
||||
OR o.display_name LIKE CONCAT('%', #{groupCode}, '%')
|
||||
)
|
||||
</if>
|
||||
<if test="confirmationNumber != null and confirmationNumber != ''">
|
||||
AND (
|
||||
o.order_business_key LIKE CONCAT('%', #{confirmationNumber}, '%')
|
||||
OR o.active_business_key LIKE CONCAT('%', #{confirmationNumber}, '%')
|
||||
OR o.display_name LIKE CONCAT('%', #{confirmationNumber}, '%')
|
||||
)
|
||||
</if>
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND (
|
||||
o.order_business_key LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR o.active_business_key LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR o.temporary_order_code LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR o.order_status LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR o.display_name LIKE CONCAT('%', #{keyword}, '%')
|
||||
<if test="sourceMessageIds != null and sourceMessageIds.size() > 0">
|
||||
OR o.source_message_id IN
|
||||
<foreach collection="sourceMessageIds" item="sourceMessageIdItem" open="(" separator="," close=")">
|
||||
#{sourceMessageIdItem}
|
||||
</foreach>
|
||||
</if>
|
||||
)
|
||||
</if>
|
||||
ORDER BY
|
||||
COALESCE(o.latest_activity_at, o.updated_at) DESC,
|
||||
o.updated_at DESC,
|
||||
o.id DESC
|
||||
</script>
|
||||
""")
|
||||
Page<ReservationOrderEntity> selectFrontendOrderPage(
|
||||
Page<ReservationOrderEntity> page,
|
||||
@Param("hotelId") String hotelId,
|
||||
@Param("orderStatus") String orderStatus,
|
||||
@Param("groupCode") String groupCode,
|
||||
@Param("confirmationNumber") String confirmationNumber,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("hiddenSystemVisibility") String hiddenSystemVisibility,
|
||||
@Param("sourceMessageIds") List<Long> sourceMessageIds);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ public interface ReservationTaskMapper extends BaseMapper<ReservationTaskEntity>
|
||||
LEFT JOIN workflow_reservation_order o
|
||||
ON o.hotel_id = t.hotel_id
|
||||
AND o.id = t.order_id
|
||||
LEFT JOIN platform_source_message_inbox sm
|
||||
ON sm.hotel_id = t.hotel_id
|
||||
AND sm.id = t.source_message_id
|
||||
WHERE t.hotel_id = #{hotelId}
|
||||
<if test="orderId != null">
|
||||
AND t.order_id = #{orderId}
|
||||
@@ -61,7 +64,14 @@ public interface ReservationTaskMapper extends BaseMapper<ReservationTaskEntity>
|
||||
</if>
|
||||
)
|
||||
</if>
|
||||
ORDER BY t.order_id ASC, t.execution_order ASC
|
||||
<choose>
|
||||
<when test="orderId != null">
|
||||
ORDER BY t.execution_order ASC, t.id ASC
|
||||
</when>
|
||||
<otherwise>
|
||||
ORDER BY COALESCE(sm.received_at, t.created_at) DESC, t.created_at DESC, t.id DESC
|
||||
</otherwise>
|
||||
</choose>
|
||||
</script>
|
||||
""")
|
||||
Page<ReservationTaskEntity> selectFrontendTaskPage(
|
||||
|
||||
@@ -204,6 +204,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
entity.setDisplayName(draft.displayName());
|
||||
entity.setSourceMessageId(draft.sourceMessageId());
|
||||
entity.setVersion(0L);
|
||||
entity.setLatestActivityAt(draft.now());
|
||||
entity.setCreatedAt(draft.now());
|
||||
entity.setUpdatedAt(draft.now());
|
||||
orderMapper.insert(entity);
|
||||
@@ -249,6 +250,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
entity.setCreatedAt(draft.now());
|
||||
entity.setUpdatedAt(draft.now());
|
||||
taskMapper.insert(entity);
|
||||
touchOrderLatestActivity(draft.hotelId(), draft.orderId(), draft.now());
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@@ -444,41 +446,15 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
int pageNum,
|
||||
int pageSize) {
|
||||
List<Long> sourceMessageIds = keywordSourceMessageIds == null ? List.of() : keywordSourceMessageIds;
|
||||
Page<ReservationOrderEntity> page = orderMapper.selectPage(Page.of(pageNum, pageSize),
|
||||
Wrappers.<ReservationOrderEntity>lambdaQuery()
|
||||
.eq(ReservationOrderEntity::getHotelId, request.hotelId())
|
||||
.ne(ReservationOrderEntity::getOrderVisibility, ReservationOrderVisibility.HIDDEN_SYSTEM.name())
|
||||
.eq(hasText(request.orderStatus()),
|
||||
ReservationOrderEntity::getOrderStatus,
|
||||
trim(request.orderStatus()))
|
||||
.and(hasText(request.groupCode()), wrapper -> wrapper
|
||||
.like(ReservationOrderEntity::getOrderBusinessKey, trim(request.groupCode()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getActiveBusinessKey, trim(request.groupCode()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getDisplayName, trim(request.groupCode())))
|
||||
.and(hasText(request.confirmationNumber()), wrapper -> wrapper
|
||||
.like(ReservationOrderEntity::getOrderBusinessKey, trim(request.confirmationNumber()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getActiveBusinessKey, trim(request.confirmationNumber()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getDisplayName, trim(request.confirmationNumber())))
|
||||
.and(hasText(request.keyword()), wrapper -> wrapper
|
||||
.like(ReservationOrderEntity::getOrderBusinessKey, trim(request.keyword()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getActiveBusinessKey, trim(request.keyword()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getTemporaryOrderCode, trim(request.keyword()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getOrderStatus, trim(request.keyword()))
|
||||
.or()
|
||||
.like(ReservationOrderEntity::getDisplayName, trim(request.keyword()))
|
||||
.or(!sourceMessageIds.isEmpty())
|
||||
.in(!sourceMessageIds.isEmpty(),
|
||||
ReservationOrderEntity::getSourceMessageId,
|
||||
sourceMessageIds))
|
||||
.orderByDesc(ReservationOrderEntity::getUpdatedAt)
|
||||
.orderByDesc(ReservationOrderEntity::getId));
|
||||
Page<ReservationOrderEntity> page = orderMapper.selectFrontendOrderPage(
|
||||
Page.of(pageNum, pageSize),
|
||||
request.hotelId(),
|
||||
trim(request.orderStatus()),
|
||||
trim(request.groupCode()),
|
||||
trim(request.confirmationNumber()),
|
||||
trim(request.keyword()),
|
||||
ReservationOrderVisibility.HIDDEN_SYSTEM.name(),
|
||||
sourceMessageIds);
|
||||
return new ReservationPageSnapshot<>(
|
||||
page.getRecords().stream().map(this::toAiQueryOrderSnapshot).toList(),
|
||||
page.getTotal(),
|
||||
@@ -592,6 +568,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
.set(ReservationOrderEntity::getOrderStatus, ReservationOrderStatus.ACTIVE.name())
|
||||
.set(ReservationOrderEntity::getBusinessKeySource, businessKeySource)
|
||||
.set(ReservationOrderEntity::getDisplayName, orderBusinessKey)
|
||||
.set(ReservationOrderEntity::getLatestActivityAt, now)
|
||||
.set(ReservationOrderEntity::getUpdatedAt, now)
|
||||
.eq(ReservationOrderEntity::getHotelId, hotelId)
|
||||
.eq(ReservationOrderEntity::getId, orderId)
|
||||
@@ -618,7 +595,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
entity.setTaskCardType(taskCardType);
|
||||
entity.setExecutionOrder(executionOrder);
|
||||
entity.setUpdatedAt(now);
|
||||
taskMapper.update(entity, Wrappers.<ReservationTaskEntity>lambdaUpdate()
|
||||
int updatedTaskCount = taskMapper.update(entity, Wrappers.<ReservationTaskEntity>lambdaUpdate()
|
||||
.eq(ReservationTaskEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskEntity::getId, taskId));
|
||||
ReservationTaskCardEntity cardEntity = new ReservationTaskCardEntity();
|
||||
@@ -627,6 +604,9 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
taskCardMapper.update(cardEntity, Wrappers.<ReservationTaskCardEntity>lambdaUpdate()
|
||||
.eq(ReservationTaskCardEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskCardEntity::getTaskId, taskId));
|
||||
if (updatedTaskCount > 0) {
|
||||
touchOrderLatestActivity(hotelId, orderId, now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -634,11 +614,15 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
*/
|
||||
@Override
|
||||
public boolean updateTaskDraftPayload(String hotelId, Long taskId, String draftPayloadJson, LocalDateTime now) {
|
||||
return taskCardMapper.update(null, Wrappers.<ReservationTaskCardEntity>lambdaUpdate()
|
||||
boolean updated = taskCardMapper.update(null, Wrappers.<ReservationTaskCardEntity>lambdaUpdate()
|
||||
.set(ReservationTaskCardEntity::getDraftPayloadJson, draftPayloadJson)
|
||||
.set(ReservationTaskCardEntity::getUpdatedAt, now)
|
||||
.eq(ReservationTaskCardEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskCardEntity::getTaskId, taskId)) > 0;
|
||||
if (updated) {
|
||||
touchOrderLatestActivityByTaskId(hotelId, taskId, now);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,6 +653,9 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
.set(ReservationTaskCardEntity::getUpdatedAt, confirmedAt)
|
||||
.eq(ReservationTaskCardEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskCardEntity::getTaskId, taskId));
|
||||
if (updatedCardCount > 0) {
|
||||
touchOrderLatestActivityByTaskId(hotelId, taskId, confirmedAt);
|
||||
}
|
||||
return updatedCardCount > 0;
|
||||
}
|
||||
|
||||
@@ -704,6 +691,9 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
.set(ReservationTaskCardEntity::getUpdatedAt, confirmedAt)
|
||||
.eq(ReservationTaskCardEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskCardEntity::getTaskId, taskId));
|
||||
if (updatedCardCount > 0) {
|
||||
touchOrderLatestActivityByTaskId(hotelId, taskId, confirmedAt);
|
||||
}
|
||||
return updatedCardCount > 0;
|
||||
}
|
||||
|
||||
@@ -817,7 +807,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
*/
|
||||
@Override
|
||||
public boolean updateTaskStatus(String hotelId, Long taskId, String taskStatus, LocalDateTime now) {
|
||||
return taskMapper.update(null, Wrappers.<ReservationTaskEntity>lambdaUpdate()
|
||||
boolean updated = taskMapper.update(null, Wrappers.<ReservationTaskEntity>lambdaUpdate()
|
||||
.set(ReservationTaskEntity::getTaskStatus, taskStatus)
|
||||
.set(ReservationTaskEntity::getCompletedAt,
|
||||
ReservationTaskStatus.COMPLETED.name().equals(taskStatus) ? now : null)
|
||||
@@ -825,6 +815,10 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
.setSql("version = version + 1")
|
||||
.eq(ReservationTaskEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskEntity::getId, taskId)) > 0;
|
||||
if (updated) {
|
||||
touchOrderLatestActivityByTaskId(hotelId, taskId, now);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -847,6 +841,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
.set(ReservationOrderEntity::getActiveBusinessKey, null)
|
||||
.set(ReservationOrderEntity::getLogicDeletedAt, now)
|
||||
.set(ReservationOrderEntity::getLogicDeletedReason, reason)
|
||||
.set(ReservationOrderEntity::getLatestActivityAt, now)
|
||||
.set(ReservationOrderEntity::getUpdatedAt, now)
|
||||
.eq(ReservationOrderEntity::getHotelId, hotelId)
|
||||
.eq(ReservationOrderEntity::getId, orderId)
|
||||
@@ -916,6 +911,40 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按任务定位订单并刷新订单最近业务活动时间,用于任务状态、确认和草稿等写操作。
|
||||
*/
|
||||
private void touchOrderLatestActivityByTaskId(String hotelId, Long taskId, LocalDateTime activityAt) {
|
||||
if (taskId == null) {
|
||||
return;
|
||||
}
|
||||
ReservationTaskEntity task = taskMapper.selectOne(Wrappers.<ReservationTaskEntity>lambdaQuery()
|
||||
.eq(ReservationTaskEntity::getHotelId, hotelId)
|
||||
.eq(ReservationTaskEntity::getId, taskId)
|
||||
.last("LIMIT 1"));
|
||||
if (task == null) {
|
||||
return;
|
||||
}
|
||||
touchOrderLatestActivity(hotelId, task.getOrderId(), activityAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新订单最近业务活动时间。只前进不回退,避免旧事件覆盖更新的用户操作。
|
||||
*/
|
||||
private void touchOrderLatestActivity(String hotelId, Long orderId, LocalDateTime activityAt) {
|
||||
if (!hasText(hotelId) || orderId == null || activityAt == null) {
|
||||
return;
|
||||
}
|
||||
orderMapper.update(null, Wrappers.<ReservationOrderEntity>lambdaUpdate()
|
||||
.set(ReservationOrderEntity::getLatestActivityAt, activityAt)
|
||||
.eq(ReservationOrderEntity::getHotelId, hotelId)
|
||||
.eq(ReservationOrderEntity::getId, orderId)
|
||||
.and(wrapper -> wrapper
|
||||
.isNull(ReservationOrderEntity::getLatestActivityAt)
|
||||
.or()
|
||||
.lt(ReservationOrderEntity::getLatestActivityAt, activityAt)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将任务实体批量转换为 AI 查询任务快照,补充 transition 中的 Skill 元数据。
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user