|
|
@@ -2,11 +2,16 @@ package com.etotem.cfc.service;
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.etotem.cfc.common.Result;
|
|
|
+import com.etotem.cfc.dto.CreateProductOrderDTO;
|
|
|
import com.etotem.cfc.dto.CreateTaskDTO;
|
|
|
+import com.etotem.cfc.dto.ProductOrderDTO;
|
|
|
import com.etotem.cfc.dto.TaskReviewDTO;
|
|
|
import com.etotem.cfc.entity.*;
|
|
|
import com.etotem.cfc.mapper.*;
|
|
|
import com.etotem.cfc.service.api.TaskServiceInterface;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
import javax.annotation.Resource;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
@@ -58,6 +63,15 @@ public class TaskService implements TaskServiceInterface {
|
|
|
@Resource
|
|
|
private GrowthTaskService growthTaskService;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private CartService cartService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ProductOrderService productOrderService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ConsigneeMapper consigneeMapper;
|
|
|
+
|
|
|
private static final int EARLY_BONUS = 1; // 提前完成奖励
|
|
|
private static final int PENALTY_MAX_DAILY = 5; // 每日最多扣分
|
|
|
private static final int LATE_GRACE_MINUTES = 10; // 10分钟内不算迟到
|
|
|
@@ -459,6 +473,13 @@ public List<Task> getTodayTasks(Long memberId, String dimensionCode) {
|
|
|
exec.setCreatedAt(now);
|
|
|
taskExecutionMapper.insert(exec);
|
|
|
|
|
|
+ // TASK-SYS-248: 购物任务联动——cart/order 动作自动加购/下单
|
|
|
+ try {
|
|
|
+ handleShoppingAction(task, memberId, exec, now);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("购物任务联动失败(不影响任务开始): taskId={}, error={}", taskId, e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
result.put("executionId", exec.getId());
|
|
|
result.put("taskId", taskId);
|
|
|
@@ -1249,4 +1270,120 @@ return 0; // 达到每日扣分上限
|
|
|
if (commDelta != 0) score.setCommunicationScore(score.getCommunicationScore().add(java.math.BigDecimal.valueOf(commDelta)));
|
|
|
familyRelationshipScoreMapper.updateById(score);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * TASK-SYS-248: 购物任务联动(cart/order 动作的自动加购/下单)
|
|
|
+ * 在任务开始(startTask)时被调用,将 actionConfig 解析后驱动 CartService / ProductOrderService
|
|
|
+ * actionConfig JSON 格式示例:
|
|
|
+ * cart: {"productId": 123, "quantity": 1, "skuId": 456}
|
|
|
+ * order: {"productId": 123, "quantity": 1, "skuId": 456, "consigneeId": 789, "deliveryMethod": 1}
|
|
|
+ */
|
|
|
+ private void handleShoppingAction(Task task, Long memberId, TaskExecution exec, Date now) {
|
|
|
+ String actionType = task.getActionType();
|
|
|
+ if (actionType == null || actionType.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!"cart".equals(actionType) && !"order".equals(actionType)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject config = parseActionConfig(task.getActionConfig());
|
|
|
+ Long productId = config != null ? config.getLong("productId") : null;
|
|
|
+ Integer quantity = config != null && config.getInteger("quantity") != null ? config.getInteger("quantity") : 1;
|
|
|
+ Long skuId = config != null ? config.getLong("skuId") : null;
|
|
|
+
|
|
|
+ if (productId == null) {
|
|
|
+ log.warn("购物任务缺少 productId: taskId={}", task.getId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从 member 获取 userId
|
|
|
+ FamilyMember member = familyMemberMapper.selectById(memberId);
|
|
|
+ Long userId = member != null ? member.getUserId() : null;
|
|
|
+ if (userId == null) {
|
|
|
+ log.warn("购物任务无法找到 userId: memberId={}", memberId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject extra = new JSONObject();
|
|
|
+ extra.put("actionType", actionType);
|
|
|
+ extra.put("productId", productId);
|
|
|
+ extra.put("quantity", quantity);
|
|
|
+ if (skuId != null) {
|
|
|
+ extra.put("skuId", skuId);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 加购(cart 和 order 都需要)
|
|
|
+ cartService.addToCart(userId, productId, quantity, skuId);
|
|
|
+ extra.put("cartAdded", true);
|
|
|
+
|
|
|
+ if ("order".equals(actionType)) {
|
|
|
+ // 创建 pending 订单
|
|
|
+ Long consigneeId = config != null ? config.getLong("consigneeId") : null;
|
|
|
+ Integer deliveryMethod = config != null ? config.getInteger("deliveryMethod") : null;
|
|
|
+ // 未指定收货地址时取用户默认地址
|
|
|
+ if (consigneeId == null) {
|
|
|
+ try {
|
|
|
+ Consignee defaultConsignee = consigneeMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<Consignee>()
|
|
|
+ .eq(Consignee::getUserId, userId)
|
|
|
+ .eq(Consignee::getIsDefault, 1)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (defaultConsignee != null) {
|
|
|
+ consigneeId = defaultConsignee.getId();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("查询默认收货地址失败: userId={}", userId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CreateProductOrderDTO orderDto = new CreateProductOrderDTO();
|
|
|
+ orderDto.setProductId(productId);
|
|
|
+ orderDto.setQuantity(quantity);
|
|
|
+ orderDto.setPaymentMethod("wechat");
|
|
|
+ if (deliveryMethod != null) {
|
|
|
+ orderDto.setDeliveryMethod(deliveryMethod);
|
|
|
+ }
|
|
|
+ if (consigneeId != null) {
|
|
|
+ orderDto.setConsigneeId(consigneeId);
|
|
|
+ }
|
|
|
+ Result<ProductOrderDTO> orderResult = productOrderService.create(orderDto, userId);
|
|
|
+ if (orderResult.getCode() == 200 && orderResult.getData() != null) {
|
|
|
+ extra.put("orderId", orderResult.getData().getId());
|
|
|
+ extra.put("orderNo", orderResult.getData().getOrderNo());
|
|
|
+ exec.setExtra(JSON.toJSONString(extra));
|
|
|
+ taskExecutionMapper.updateById(exec);
|
|
|
+ log.info("购物任务下单成功: taskId={}, orderNo={}", task.getId(), orderResult.getData().getOrderNo());
|
|
|
+ } else {
|
|
|
+ // 下单失败(通常因缺地址/库存),保留加购状态
|
|
|
+ extra.put("orderFailed", true);
|
|
|
+ extra.put("orderError", orderResult.getMessage());
|
|
|
+ exec.setExtra(JSON.toJSONString(extra));
|
|
|
+ taskExecutionMapper.updateById(exec);
|
|
|
+ log.warn("购物任务下单失败: taskId={}, reason={}", task.getId(), orderResult.getMessage());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 纯加购
|
|
|
+ exec.setExtra(JSON.toJSONString(extra));
|
|
|
+ taskExecutionMapper.updateById(exec);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("购物任务联动失败: taskId={}, error={}", task.getId(), e.getMessage(), e);
|
|
|
+ extra.put("error", e.getMessage());
|
|
|
+ exec.setExtra(JSON.toJSONString(extra));
|
|
|
+ taskExecutionMapper.updateById(exec);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private com.alibaba.fastjson.JSONObject parseActionConfig(String json) {
|
|
|
+ if (json == null || json.trim().isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return JSON.parseObject(json);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("解析 actionConfig 失败: {}", json);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|