|
@@ -0,0 +1,669 @@
|
|
|
|
|
+package com.haha.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
+import com.haha.common.enums.ActivityStatusEnum;
|
|
|
|
|
+import com.haha.common.enums.ActivityTypeEnum;
|
|
|
|
|
+import com.haha.common.exception.BusinessException;
|
|
|
|
|
+import com.haha.entity.InviteActivity;
|
|
|
|
|
+import com.haha.entity.InviteRecord;
|
|
|
|
|
+import com.haha.entity.MarketingActivity;
|
|
|
|
|
+import com.haha.entity.dto.ActivityCreateDTO;
|
|
|
|
|
+import com.haha.entity.dto.ActivityQueryDTO;
|
|
|
|
|
+import com.haha.entity.dto.ActivityUpdateDTO;
|
|
|
|
|
+import com.haha.entity.dto.InviteActivityCreateDTO;
|
|
|
|
|
+import com.haha.entity.dto.InviteActivityUpdateDTO;
|
|
|
|
|
+import com.haha.entity.dto.InviteRecordQueryDTO;
|
|
|
|
|
+import com.haha.entity.dto.UnifiedActivityCreateDTO;
|
|
|
|
|
+import com.haha.entity.dto.UnifiedActivityQueryDTO;
|
|
|
|
|
+import com.haha.entity.dto.UnifiedActivityUpdateDTO;
|
|
|
|
|
+import com.haha.entity.vo.UnifiedActivityVO;
|
|
|
|
|
+import com.haha.service.CouponTemplateService;
|
|
|
|
|
+import com.haha.service.InviteActivityService;
|
|
|
|
|
+import com.haha.service.MarketingActivityService;
|
|
|
|
|
+import com.haha.service.UnifiedActivityService;
|
|
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 统一活动服务实现类
|
|
|
|
|
+ * 作为前端和后端之间的中间层,根据 activityType 分发请求到对应的 Service
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>核心设计:
|
|
|
|
|
+ * <ul>
|
|
|
|
|
+ * <li><b>类型分发</b>:使用 if-else 根据 type 字段路由请求(type=4 -> 邀请服务,其他 -> 营销服务)</li>
|
|
|
|
|
+ * <li><b>DTO 转换</b>:将统一 DTO 转换为各服务所需的特定 DTO 格式</li>
|
|
|
|
|
+ * <li><b>VO 统一</b>:将不同实体的数据转换为统一的 VO 格式返回</li>
|
|
|
|
|
+ * <li><b>日志记录</b>:完整的操作日志便于问题排查和审计</li>
|
|
|
|
|
+ * <li><b>异常处理</b>:对不支持的类型抛出明确的业务异常</li>
|
|
|
|
|
+ * </ul>
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class UnifiedActivityServiceImpl implements UnifiedActivityService {
|
|
|
|
|
+
|
|
|
|
|
+ private final MarketingActivityService marketingActivityService;
|
|
|
|
|
+ private final InviteActivityService inviteActivityService;
|
|
|
|
|
+ private final CouponTemplateService couponTemplateService;
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 统一 CRUD 操作 ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Long create(UnifiedActivityCreateDTO dto) {
|
|
|
|
|
+ log.info("[统一活动] 创建活动 - type: {}, name: {}", dto.getActivityType(), dto.getActivityName());
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 从安全上下文获取当前用户信息(需要集成 Spring Security 或自定义上下文)
|
|
|
|
|
+ Long creatorId = 1L; // 默认值,实际应从 SecurityContext 获取
|
|
|
|
|
+ String creatorName = "系统管理员"; // 默认值,实际应从 SecurityContext 获取
|
|
|
|
|
+
|
|
|
|
|
+ if (dto.getActivityType() == 4) {
|
|
|
|
|
+ log.info("[统一活动] 路由到邀请活动服务");
|
|
|
|
|
+ InviteActivityCreateDTO inviteDTO = convertToInviteCreateDTO(dto);
|
|
|
|
|
+ InviteActivity activity = inviteActivityService.create(inviteDTO, creatorId, creatorName);
|
|
|
|
|
+
|
|
|
|
|
+ // 【Task 8】创建活动成功后,关联优惠券模板的 activityId
|
|
|
|
|
+ associateCouponTemplatesWithActivity(activity.getId(),
|
|
|
|
|
+ dto.getInviterCouponTemplateId(), dto.getInviteeCouponTemplateId());
|
|
|
|
|
+
|
|
|
|
|
+ return activity.getId();
|
|
|
|
|
+ } else if (dto.getActivityType() >= 1 && dto.getActivityType() <= 3) {
|
|
|
|
|
+ log.info("[统一活动] 路由到营销活动服务");
|
|
|
|
|
+ ActivityCreateDTO marketingDTO = convertToMarketingCreateDTO(dto);
|
|
|
|
|
+ MarketingActivity activity = marketingActivityService.create(marketingDTO, creatorId, creatorName);
|
|
|
|
|
+ return activity.getId();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + dto.getActivityType());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void update(UnifiedActivityUpdateDTO dto) {
|
|
|
|
|
+ log.info("[统一活动] 更新活动 - id: {}, type: {}", dto.getId(), getActivityTypeFromUpdateDTO(dto));
|
|
|
|
|
+
|
|
|
|
|
+ Integer type = getActivityTypeFromUpdateDTO(dto);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == 4) {
|
|
|
|
|
+ log.info("[统一活动] 路由到邀请活动服务进行更新");
|
|
|
|
|
+
|
|
|
|
|
+ // 【Task 8】更新前获取旧的优惠券模板ID,用于后续清理旧关联
|
|
|
|
|
+ Long oldInviterCouponId = null;
|
|
|
|
|
+ Long oldInviteeCouponId = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ InviteActivity existingActivity = inviteActivityService.getDetail(dto.getId());
|
|
|
|
|
+ if (existingActivity != null) {
|
|
|
|
|
+ oldInviterCouponId = existingActivity.getCouponTemplateId();
|
|
|
|
|
+ oldInviteeCouponId = existingActivity.getInviteeCouponTemplateId();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("[统一活动] 获取原活动信息失败,跳过旧关联清理: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ InviteActivityUpdateDTO inviteDTO = convertToInviteUpdateDTO(dto);
|
|
|
|
|
+ inviteActivityService.update(inviteDTO);
|
|
|
|
|
+
|
|
|
|
|
+ // 【Task 8】更新后同步优惠券模板的 activityId 关联
|
|
|
|
|
+ syncCouponTemplateAssociation(dto.getId(),
|
|
|
|
|
+ oldInviterCouponId, oldInviteeCouponId,
|
|
|
|
|
+ dto.getInviterCouponTemplateId(), dto.getInviteeCouponTemplateId());
|
|
|
|
|
+ } else if (type >= 1 && type <= 3) {
|
|
|
|
|
+ log.info("[统一活动] 路由到营销活动服务进行更新");
|
|
|
|
|
+ ActivityUpdateDTO marketingDTO = convertToMarketingUpdateDTO(dto);
|
|
|
|
|
+ marketingActivityService.update(marketingDTO);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public IPage<UnifiedActivityVO> getPage(UnifiedActivityQueryDTO queryDTO) {
|
|
|
|
|
+ log.info("[统一活动] 分页查询 - type: {}, page: {}, size: {}",
|
|
|
|
|
+ queryDTO.getActivityType(), queryDTO.getPage(), queryDTO.getPageSize());
|
|
|
|
|
+
|
|
|
|
|
+ if (queryDTO.getActivityType() != null && queryDTO.getActivityType() == 4) {
|
|
|
|
|
+ // 仅查询邀请活动,并转换为统一 VO 格式
|
|
|
|
|
+ log.info("[统一活动] 查询邀请活动列表");
|
|
|
|
|
+ InviteRecordQueryDTO inviteQuery = convertToInviteQuery(queryDTO);
|
|
|
|
|
+ IPage<InviteActivity> page = inviteActivityService.getPage(inviteQuery);
|
|
|
|
|
+ return convertInvitePageToUnified(page);
|
|
|
|
|
+ } else if (queryDTO.getActivityType() == null ||
|
|
|
|
|
+ (queryDTO.getActivityType() >= 1 && queryDTO.getActivityType() <= 3)) {
|
|
|
|
|
+ // 查询营销活动 (type 1-3 或全部)
|
|
|
|
|
+ log.info("[统一活动] 查询营销活动列表");
|
|
|
|
|
+ ActivityQueryDTO marketingQuery = convertToMarketingQuery(queryDTO);
|
|
|
|
|
+ IPage<MarketingActivity> page = marketingActivityService.getPage(marketingQuery);
|
|
|
|
|
+ return convertMarketingPageToUnified(page);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + queryDTO.getActivityType());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public UnifiedActivityVO getDetail(Long id, Integer type) {
|
|
|
|
|
+ log.info("[统一活动] 查询详情 - id: {}, type: {}", id, type);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == 4) {
|
|
|
|
|
+ log.info("[统一活动] 从邀请活动服务获取详情");
|
|
|
|
|
+ InviteActivity activity = inviteActivityService.getDetail(id);
|
|
|
|
|
+ return convertInviteToUnifiedVO(activity);
|
|
|
|
|
+ } else if (type >= 1 && type <= 3) {
|
|
|
|
|
+ log.info("[统一活动] 从营销活动服务获取详情");
|
|
|
|
|
+ MarketingActivity activity = marketingActivityService.getDetail(id);
|
|
|
|
|
+ return convertMarketingToUnifiedVO(activity);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 统一状态管理 ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void publish(Long id, Integer type) {
|
|
|
|
|
+ log.info("[统一活动] 发布活动 - id: {}, type: {}", id, type);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == 4) {
|
|
|
|
|
+ boolean result = inviteActivityService.publish(id);
|
|
|
|
|
+ logPublishResult(id, type, result);
|
|
|
|
|
+ } else if (type >= 1 && type <= 3) {
|
|
|
|
|
+ boolean result = marketingActivityService.publish(id);
|
|
|
|
|
+ logPublishResult(id, type, result);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void pause(Long id, Integer type) {
|
|
|
|
|
+ log.info("[统一活动] 暂停活动 - id: {}, type: {}", id, type);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == 4) {
|
|
|
|
|
+ boolean result = inviteActivityService.pause(id);
|
|
|
|
|
+ logOperationResult("暂停", id, type, result);
|
|
|
|
|
+ } else if (type >= 1 && type <= 3) {
|
|
|
|
|
+ boolean result = marketingActivityService.pause(id);
|
|
|
|
|
+ logOperationResult("暂停", id, type, result);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void resume(Long id, Integer type) {
|
|
|
|
|
+ log.info("[统一活动] 恢复活动 - id: {}, type: {}", id, type);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == 4) {
|
|
|
|
|
+ boolean result = inviteActivityService.resume(id);
|
|
|
|
|
+ logOperationResult("恢复", id, type, result);
|
|
|
|
|
+ } else if (type >= 1 && type <= 3) {
|
|
|
|
|
+ boolean result = marketingActivityService.resume(id);
|
|
|
|
|
+ logOperationResult("恢复", id, type, result);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 删除操作 ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void delete(Long id, Integer type) {
|
|
|
|
|
+ log.info("[统一活动] 删除活动 - id: {}, type: {}", id, type);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == 4) {
|
|
|
|
|
+ // 【Task 8】删除前清理关联的优惠券模板 activityId
|
|
|
|
|
+ try {
|
|
|
|
|
+ InviteActivity existingActivity = inviteActivityService.getDetail(id);
|
|
|
|
|
+ if (existingActivity != null) {
|
|
|
|
|
+ disassociateCouponTemplatesFromActivity(
|
|
|
|
|
+ existingActivity.getCouponTemplateId(),
|
|
|
|
|
+ existingActivity.getInviteeCouponTemplateId());
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("[统一活动] 清理优惠券关联失败(不影响删除操作): {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ boolean result = inviteActivityService.deleteActivity(id);
|
|
|
|
|
+ logOperationResult("删除", id, type, result);
|
|
|
|
|
+ } else if (type >= 1 && type <= 3) {
|
|
|
|
|
+ boolean result = marketingActivityService.deleteActivity(id);
|
|
|
|
|
+ logOperationResult("删除", id, type, result);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new BusinessException(400, "不支持的活动类型: " + type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 邀请活动特有方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public IPage<InviteRecord> getInviteRecords(Long activityId, InviteRecordQueryDTO queryDTO) {
|
|
|
|
|
+ log.info("[统一活动] 查询邀请记录 - activityId: {}", activityId);
|
|
|
|
|
+ queryDTO.setActivityId(activityId);
|
|
|
|
|
+ return inviteActivityService.getInviteRecords(queryDTO);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Map<String, Object> getInviteStatistics(Long activityId) {
|
|
|
|
|
+ log.info("[统一活动] 查询邀请统计 - activityId: {}", activityId);
|
|
|
|
|
+ return inviteActivityService.getActivityStatistics(activityId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== DTO 转换方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将 UnifiedActivityCreateDTO 转换为 InviteActivityCreateDTO
|
|
|
|
|
+ * 提取邀请活动特有的字段
|
|
|
|
|
+ */
|
|
|
|
|
+ private InviteActivityCreateDTO convertToInviteCreateDTO(UnifiedActivityCreateDTO dto) {
|
|
|
|
|
+ InviteActivityCreateDTO inviteDTO = new InviteActivityCreateDTO();
|
|
|
|
|
+ inviteDTO.setActivityName(dto.getActivityName());
|
|
|
|
|
+ inviteDTO.setActivityDesc(dto.getActivityDesc());
|
|
|
|
|
+ inviteDTO.setStartTime(dto.getStartTime());
|
|
|
|
|
+ inviteDTO.setEndTime(dto.getEndTime());
|
|
|
|
|
+ inviteDTO.setApplyScope(dto.getApplyScope());
|
|
|
|
|
+ inviteDTO.setProductScope(dto.getProductScope());
|
|
|
|
|
+
|
|
|
|
|
+ // 邀请特有字段
|
|
|
|
|
+ inviteDTO.setInviterCouponTemplateId(dto.getInviterCouponTemplateId());
|
|
|
|
|
+ inviteDTO.setInviteeCouponTemplateId(dto.getInviteeCouponTemplateId());
|
|
|
|
|
+ inviteDTO.setDailyLimit(dto.getDailyLimit());
|
|
|
|
|
+ inviteDTO.setTotalLimit(dto.getTotalLimit());
|
|
|
|
|
+ inviteDTO.setRequireFirstOrder(dto.getRequireFirstOrder());
|
|
|
|
|
+ inviteDTO.setMinOrderAmount(dto.getMinOrderAmount());
|
|
|
|
|
+ inviteDTO.setInviteCodePrefix(dto.getInviteCodePrefix());
|
|
|
|
|
+
|
|
|
|
|
+ // 关联ID列表
|
|
|
|
|
+ inviteDTO.setShopIds(dto.getShopIds());
|
|
|
|
|
+ inviteDTO.setProductIds(dto.getProductIds());
|
|
|
|
|
+
|
|
|
|
|
+ return inviteDTO;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将 UnifiedActivityCreateDTO 转换为 ActivityCreateDTO(营销活动)
|
|
|
|
|
+ * 提取营销活动特有的字段
|
|
|
|
|
+ */
|
|
|
|
|
+ private ActivityCreateDTO convertToMarketingCreateDTO(UnifiedActivityCreateDTO dto) {
|
|
|
|
|
+ ActivityCreateDTO marketingDTO = new ActivityCreateDTO();
|
|
|
|
|
+ marketingDTO.setActivityName(dto.getActivityName());
|
|
|
|
|
+ marketingDTO.setActivityType(dto.getActivityType());
|
|
|
|
|
+ marketingDTO.setActivityDesc(dto.getActivityDesc());
|
|
|
|
|
+ marketingDTO.setStartTime(dto.getStartTime());
|
|
|
|
|
+ marketingDTO.setEndTime(dto.getEndTime());
|
|
|
|
|
+ marketingDTO.setApplyScope(dto.getApplyScope());
|
|
|
|
|
+ marketingDTO.setDeviceScope(dto.getDeviceScope());
|
|
|
|
|
+ marketingDTO.setProductScope(dto.getProductScope());
|
|
|
|
|
+ marketingDTO.setTotalBudget(dto.getTotalBudget());
|
|
|
|
|
+
|
|
|
|
|
+ // 优惠字段 (type 1-3)
|
|
|
|
|
+ marketingDTO.setDiscountValue(dto.getDiscountValue());
|
|
|
|
|
+ marketingDTO.setMinAmount(dto.getMinAmount());
|
|
|
|
|
+ marketingDTO.setMaxDiscount(dto.getMaxDiscount());
|
|
|
|
|
+
|
|
|
|
|
+ // 关联ID列表
|
|
|
|
|
+ marketingDTO.setShopIds(dto.getShopIds());
|
|
|
|
|
+ marketingDTO.setDeviceIds(dto.getDeviceIds());
|
|
|
|
|
+ marketingDTO.setProductIds(dto.getProductIds());
|
|
|
|
|
+
|
|
|
|
|
+ return marketingDTO;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将 UnifiedActivityUpdateDTO 转换为 InviteActivityUpdateDTO
|
|
|
|
|
+ */
|
|
|
|
|
+ private InviteActivityUpdateDTO convertToInviteUpdateDTO(UnifiedActivityUpdateDTO dto) {
|
|
|
|
|
+ InviteActivityUpdateDTO inviteDTO = new InviteActivityUpdateDTO();
|
|
|
|
|
+ inviteDTO.setId(dto.getId());
|
|
|
|
|
+ inviteDTO.setActivityName(dto.getActivityName());
|
|
|
|
|
+ inviteDTO.setActivityDesc(dto.getActivityDesc());
|
|
|
|
|
+ inviteDTO.setStartTime(dto.getStartTime());
|
|
|
|
|
+ inviteDTO.setEndTime(dto.getEndTime());
|
|
|
|
|
+ inviteDTO.setApplyScope(dto.getApplyScope());
|
|
|
|
|
+ inviteDTO.setProductScope(dto.getProductScope());
|
|
|
|
|
+
|
|
|
|
|
+ // 邀请特有字段
|
|
|
|
|
+ inviteDTO.setInviterCouponTemplateId(dto.getInviterCouponTemplateId());
|
|
|
|
|
+ inviteDTO.setInviteeCouponTemplateId(dto.getInviteeCouponTemplateId());
|
|
|
|
|
+ inviteDTO.setDailyLimit(dto.getDailyLimit());
|
|
|
|
|
+ inviteDTO.setTotalLimit(dto.getTotalLimit());
|
|
|
|
|
+ inviteDTO.setRequireFirstOrder(dto.getRequireFirstOrder());
|
|
|
|
|
+ inviteDTO.setMinOrderAmount(dto.getMinOrderAmount());
|
|
|
|
|
+ inviteDTO.setInviteCodePrefix(dto.getInviteCodePrefix());
|
|
|
|
|
+
|
|
|
|
|
+ // 关联ID列表
|
|
|
|
|
+ inviteDTO.setShopIds(dto.getShopIds());
|
|
|
|
|
+ inviteDTO.setProductIds(dto.getProductIds());
|
|
|
|
|
+
|
|
|
|
|
+ return inviteDTO;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将 UnifiedActivityUpdateDTO 转换为 ActivityUpdateDTO(营销活动)
|
|
|
|
|
+ */
|
|
|
|
|
+ private ActivityUpdateDTO convertToMarketingUpdateDTO(UnifiedActivityUpdateDTO dto) {
|
|
|
|
|
+ ActivityUpdateDTO marketingDTO = new ActivityUpdateDTO();
|
|
|
|
|
+ marketingDTO.setId(dto.getId());
|
|
|
|
|
+ marketingDTO.setActivityName(dto.getActivityName());
|
|
|
|
|
+ marketingDTO.setActivityDesc(dto.getActivityDesc());
|
|
|
|
|
+ marketingDTO.setStartTime(dto.getStartTime());
|
|
|
|
|
+ marketingDTO.setEndTime(dto.getEndTime());
|
|
|
|
|
+ marketingDTO.setApplyScope(dto.getApplyScope());
|
|
|
|
|
+ marketingDTO.setDeviceScope(dto.getDeviceScope());
|
|
|
|
|
+ marketingDTO.setProductScope(dto.getProductScope());
|
|
|
|
|
+ marketingDTO.setTotalBudget(dto.getTotalBudget());
|
|
|
|
|
+
|
|
|
|
|
+ // 优惠字段 (type 1-3)
|
|
|
|
|
+ marketingDTO.setDiscountValue(dto.getDiscountValue());
|
|
|
|
|
+ marketingDTO.setMinAmount(dto.getMinAmount());
|
|
|
|
|
+ marketingDTO.setMaxDiscount(dto.getMaxDiscount());
|
|
|
|
|
+
|
|
|
|
|
+ // 关联ID列表
|
|
|
|
|
+ marketingDTO.setShopIds(dto.getShopIds());
|
|
|
|
|
+ marketingDTO.setDeviceIds(dto.getDeviceIds());
|
|
|
|
|
+ marketingDTO.setProductIds(dto.getProductIds());
|
|
|
|
|
+
|
|
|
|
|
+ return marketingDTO;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将 UnifiedActivityQueryDTO 转换为 InviteRecordQueryDTO(邀请活动查询)
|
|
|
|
|
+ */
|
|
|
|
|
+ private InviteRecordQueryDTO convertToInviteQuery(UnifiedActivityQueryDTO queryDTO) {
|
|
|
|
|
+ InviteRecordQueryDTO inviteQuery = new InviteRecordQueryDTO();
|
|
|
|
|
+ inviteQuery.setPage(queryDTO.getPage());
|
|
|
|
|
+ inviteQuery.setPageSize(queryDTO.getPageSize());
|
|
|
|
|
+ inviteQuery.setActivityName(queryDTO.getActivityName());
|
|
|
|
|
+ inviteQuery.setStatus(queryDTO.getStatus());
|
|
|
|
|
+ inviteQuery.setStartDate(queryDTO.getStartTimeBegin());
|
|
|
|
|
+ inviteQuery.setEndDate(queryDTO.getEndTimeEnd());
|
|
|
|
|
+
|
|
|
|
|
+ return inviteQuery;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将 UnifiedActivityQueryDTO 转换为 ActivityQueryDTO(营销活动查询)
|
|
|
|
|
+ */
|
|
|
|
|
+ private ActivityQueryDTO convertToMarketingQuery(UnifiedActivityQueryDTO queryDTO) {
|
|
|
|
|
+ ActivityQueryDTO marketingQuery = new ActivityQueryDTO();
|
|
|
|
|
+ marketingQuery.setPage(queryDTO.getPage());
|
|
|
|
|
+ marketingQuery.setPageSize(queryDTO.getPageSize());
|
|
|
|
|
+ marketingQuery.setActivityName(queryDTO.getActivityName());
|
|
|
|
|
+ marketingQuery.setActivityType(queryDTO.getActivityType());
|
|
|
|
|
+ marketingQuery.setStatus(queryDTO.getStatus());
|
|
|
|
|
+ marketingQuery.setCreatorId(queryDTO.getCreatorId());
|
|
|
|
|
+ marketingQuery.setStartTimeBegin(queryDTO.getStartTimeBegin());
|
|
|
|
|
+ marketingQuery.setStartTimeEnd(queryDTO.getStartTimeEnd());
|
|
|
|
|
+
|
|
|
|
|
+ return marketingQuery;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== VO 转换方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将营销活动分页结果转换为统一 VO 分页结果
|
|
|
|
|
+ */
|
|
|
|
|
+ private IPage<UnifiedActivityVO> convertMarketingPageToUnified(IPage<MarketingActivity> page) {
|
|
|
|
|
+ Page<UnifiedActivityVO> unifiedPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
|
|
|
|
+ List<UnifiedActivityVO> records = page.getRecords().stream()
|
|
|
|
|
+ .map(this::convertMarketingToUnifiedVO)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ unifiedPage.setRecords(records);
|
|
|
|
|
+ return unifiedPage;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将邀请活动分页结果转换为统一 VO 分页结果
|
|
|
|
|
+ */
|
|
|
|
|
+ private IPage<UnifiedActivityVO> convertInvitePageToUnified(IPage<InviteActivity> page) {
|
|
|
|
|
+ Page<UnifiedActivityVO> unifiedPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
|
|
|
|
+ List<UnifiedActivityVO> records = page.getRecords().stream()
|
|
|
|
|
+ .map(this::convertInviteToUnifiedVO)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ unifiedPage.setRecords(records);
|
|
|
|
|
+ return unifiedPage;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将单个营销活动实体转换为统一 VO
|
|
|
|
|
+ */
|
|
|
|
|
+ private UnifiedActivityVO convertMarketingToUnifiedVO(MarketingActivity activity) {
|
|
|
|
|
+ return UnifiedActivityVO.builder()
|
|
|
|
|
+ .id(activity.getId())
|
|
|
|
|
+ .activityName(activity.getActivityName())
|
|
|
|
|
+ .activityType(activity.getActivityType())
|
|
|
|
|
+ .activityTypeName(ActivityTypeEnum.getLabelByCode(activity.getActivityType()).getLabel())
|
|
|
|
|
+ .activityDesc(activity.getActivityDesc())
|
|
|
|
|
+ .startTime(activity.getStartTime())
|
|
|
|
|
+ .endTime(activity.getEndTime())
|
|
|
|
|
+ .status(activity.getStatus())
|
|
|
|
|
+ .statusName(ActivityStatusEnum.getLabelByCode(activity.getStatus()).getLabel())
|
|
|
|
|
+
|
|
|
|
|
+ // 营销活动特有字段
|
|
|
|
|
+ .discountValue(activity.getDiscountValue())
|
|
|
|
|
+ .minAmount(activity.getMinAmount())
|
|
|
|
|
+ .maxDiscount(activity.getMaxDiscount())
|
|
|
|
|
+ .totalBudget(activity.getTotalBudget())
|
|
|
|
|
+ .usedBudget(activity.getUsedBudget())
|
|
|
|
|
+
|
|
|
|
|
+ // 统计信息
|
|
|
|
|
+ .createTime(activity.getCreateTime())
|
|
|
|
|
+ .creatorName(activity.getCreatorName())
|
|
|
|
|
+ .applyScope(activity.getApplyScope())
|
|
|
|
|
+
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将单个邀请活动实体转换为统一 VO
|
|
|
|
|
+ */
|
|
|
|
|
+ private UnifiedActivityVO convertInviteToUnifiedVO(InviteActivity activity) {
|
|
|
|
|
+ return UnifiedActivityVO.builder()
|
|
|
|
|
+ .id(activity.getId())
|
|
|
|
|
+ .activityName(activity.getActivityName())
|
|
|
|
|
+ .activityType(4) // 邀请活动固定为 type 4
|
|
|
|
|
+ .activityTypeName(ActivityTypeEnum.INVITE_REWARD.getLabel())
|
|
|
|
|
+ .activityDesc(activity.getActivityDesc())
|
|
|
|
|
+ .startTime(activity.getStartTime())
|
|
|
|
|
+ .endTime(activity.getEndTime())
|
|
|
|
|
+ .status(activity.getStatus())
|
|
|
|
|
+ .statusName(ActivityStatusEnum.getLabelByCode(activity.getStatus()).getLabel())
|
|
|
|
|
+
|
|
|
|
|
+ // 邀请活动特有字段
|
|
|
|
|
+ .inviterCouponTemplateId(activity.getCouponTemplateId())
|
|
|
|
|
+ .inviteeCouponTemplateId(activity.getInviteeCouponTemplateId())
|
|
|
|
|
+ .dailyLimit(activity.getDailyLimit())
|
|
|
|
|
+ .totalLimit(activity.getTotalLimit())
|
|
|
|
|
+ .requireFirstOrder(activity.getRequireFirstOrder())
|
|
|
|
|
+ .minOrderAmount(activity.getMinOrderAmount())
|
|
|
|
|
+ .totalInviteCount(activity.getTotalInviteCount())
|
|
|
|
|
+ .validInviteCount(activity.getValidInviteCount())
|
|
|
|
|
+ .rewardCount(activity.getRewardCount())
|
|
|
|
|
+
|
|
|
|
|
+ // 统计信息
|
|
|
|
|
+ .createTime(activity.getCreateTime())
|
|
|
|
|
+ .creatorName(activity.getCreatorName())
|
|
|
|
|
+ .applyScope(activity.getApplyScope())
|
|
|
|
|
+
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 辅助方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从 UpdateDTO 中推断活动类型
|
|
|
|
|
+ * 由于 UpdateDTO 不包含 type 字段,需要先查询原活动获取类型
|
|
|
|
|
+ * 实现策略:先尝试从邀请活动表查询,再尝试从营销活动表查询
|
|
|
|
|
+ */
|
|
|
|
|
+ private Integer getActivityTypeFromUpdateDTO(UnifiedActivityUpdateDTO dto) {
|
|
|
|
|
+ Long id = dto.getId();
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 先尝试从邀请活动表查询(type=4)
|
|
|
|
|
+ try {
|
|
|
|
|
+ InviteActivity inviteActivity = inviteActivityService.getById(id);
|
|
|
|
|
+ if (inviteActivity != null && inviteActivity.getDeleted() != null && inviteActivity.getDeleted() == 0) {
|
|
|
|
|
+ log.info("[统一活动] 从邀请活动表查到活动类型: id={}, type=4", id);
|
|
|
|
|
+ return 4;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.debug("[统一活动] 邀请活动表未找到该记录: id={}", id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 再尝试从营销活动表查询(type=1,2,3)
|
|
|
|
|
+ try {
|
|
|
|
|
+ MarketingActivity marketingActivity = marketingActivityService.getById(id);
|
|
|
|
|
+ if (marketingActivity != null) {
|
|
|
|
|
+ log.info("[统一活动] 从营销活动表查到活动类型: id={}, type={}", id, marketingActivity.getActivityType());
|
|
|
|
|
+ return marketingActivity.getActivityType();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.debug("[统一活动] 营销活动表未找到该记录: id={}", id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ throw new BusinessException(404, "活动不存在或已被删除,id: " + id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 记录发布操作结果日志
|
|
|
|
|
+ */
|
|
|
|
|
+ private void logPublishResult(Long id, Integer type, boolean success) {
|
|
|
|
|
+ if (success) {
|
|
|
|
|
+ log.info("[统一活动] 发布成功 - id: {}, type: {}", id, type);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.warn("[统一活动] 发布失败 - id: {}, type: {}", id, type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 记录通用操作结果日志
|
|
|
|
|
+ */
|
|
|
|
|
+ private void logOperationResult(String operation, Long id, Integer type, boolean success) {
|
|
|
|
|
+ if (success) {
|
|
|
|
|
+ log.info("[统一活动] {}成功 - id: {}, type: {}", operation, id, type);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.warn("[统一活动] {}失败 - id: {}, type: {}", operation, id, type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 优惠券-活动关联方法 (Task 8) ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建活动后,将优惠券模板与活动关联
|
|
|
|
|
+ * 更新 CouponTemplate 的 activityId 字段指向当前活动
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param activityId 活动ID
|
|
|
|
|
+ * @param inviterCouponTemplateId 邀请人优惠券模板ID(可为null)
|
|
|
|
|
+ * @param inviteeCouponTemplateId 被邀请人优惠券模板ID(可为null)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void associateCouponTemplatesWithActivity(Long activityId,
|
|
|
|
|
+ Long inviterCouponTemplateId,
|
|
|
|
|
+ Long inviteeCouponTemplateId) {
|
|
|
|
|
+ if (inviterCouponTemplateId != null) {
|
|
|
|
|
+ updateCouponTemplateActivityId(inviterCouponTemplateId, activityId, "邀请人");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (inviteeCouponTemplateId != null) {
|
|
|
|
|
+ updateCouponTemplateActivityId(inviteeCouponTemplateId, activityId, "被邀请人");
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("[统一活动] 优惠券模板关联完成 - activityId={}, inviter={}, invitee={}",
|
|
|
|
|
+ activityId, inviterCouponTemplateId, inviteeCouponTemplateId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 更新活动时同步优惠券模板关联
|
|
|
|
|
+ * 处理逻辑:
|
|
|
|
|
+ * 1. 如果旧模板ID与新不同,清除旧的 activityId
|
|
|
|
|
+ * 2. 如果新模板ID不为空且与旧的不同,设置新的 activityId
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param activityId 活动ID
|
|
|
|
|
+ * @param oldInviterId 旧的邀请人优惠券模板ID
|
|
|
|
|
+ * @param oldInviteeId 旧的被邀请人优惠券模板ID
|
|
|
|
|
+ * @param newInviterId 新的邀请人优惠券模板ID
|
|
|
|
|
+ * @param newInviteeId 新的被邀请人优惠券模板ID
|
|
|
|
|
+ */
|
|
|
|
|
+ private void syncCouponTemplateAssociation(Long activityId,
|
|
|
|
|
+ Long oldInviterId, Long oldInviteeId,
|
|
|
|
|
+ Long newInviterId, Long newInviteeId) {
|
|
|
|
|
+ // 同步邀请人优惠券模板
|
|
|
|
|
+ if (oldInviterId != null && !oldInviterId.equals(newInviterId)) {
|
|
|
|
|
+ clearCouponTemplateActivityId(oldInviterId); // 清除旧关联
|
|
|
|
|
+ }
|
|
|
|
|
+ if (newInviterId != null && !newInviterId.equals(oldInviterId)) {
|
|
|
|
|
+ updateCouponTemplateActivityId(newInviterId, activityId, "邀请人"); // 建立新关联
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 同步被邀请人优惠券模板
|
|
|
|
|
+ if (oldInviteeId != null && !oldInviteeId.equals(newInviteeId)) {
|
|
|
|
|
+ clearCouponTemplateActivityId(oldInviteeId); // 清除旧关联
|
|
|
|
|
+ }
|
|
|
|
|
+ if (newInviteeId != null && !newInviteeId.equals(oldInviteeId)) {
|
|
|
|
|
+ updateCouponTemplateActivityId(newInviteeId, activityId, "被邀请人"); // 建立新关联
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("[统一活动] 优惠券模板关联同步完成 - activityId={}, 旧:[{},{}] -> 新:[{},{}]",
|
|
|
|
|
+ activityId, oldInviterId, oldInviteeId, newInviterId, newInviteeId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 删除活动时,解除优惠券模板的活动关联
|
|
|
|
|
+ * 将相关 CouponTemplate 的 activityId 设为 null
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param inviterCouponTemplateId 邀请人优惠券模板ID
|
|
|
|
|
+ * @param inviteeCouponTemplateId 被邀请人优惠券模板ID
|
|
|
|
|
+ */
|
|
|
|
|
+ private void disassociateCouponTemplatesFromActivity(Long inviterCouponTemplateId,
|
|
|
|
|
+ Long inviteeCouponTemplateId) {
|
|
|
|
|
+ if (inviterCouponTemplateId != null) {
|
|
|
|
|
+ clearCouponTemplateActivityId(inviterCouponTemplateId);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (inviteeCouponTemplateId != null) {
|
|
|
|
|
+ clearCouponTemplateActivityId(inviteeCouponTemplateId);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("[统一活动] 已解除优惠券模板关联 - inviter={}, invitee={}",
|
|
|
|
|
+ inviterCouponTemplateId, inviteeCouponTemplateId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 更新单个优惠券模板的 activityId
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param templateId 优惠券模板ID
|
|
|
|
|
+ * @param activityId 要关联的活动ID
|
|
|
|
|
+ * @param role 角色(用于日志:邀请人/被邀请人)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void updateCouponTemplateActivityId(Long templateId, Long activityId, String role) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ com.haha.entity.CouponTemplate template = couponTemplateService.getById(templateId);
|
|
|
|
|
+ if (template != null) {
|
|
|
|
|
+ template.setActivityId(activityId);
|
|
|
|
|
+ couponTemplateService.updateById(template);
|
|
|
|
|
+ log.info("[统一活动] 已更新{}优惠券模板关联 - templateId={}, activityId={}",
|
|
|
|
|
+ role, templateId, activityId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.warn("[统一活动] {}优惠券模板不存在,跳过关联 - templateId={}", role, templateId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("[统一活动] 更新{}优惠券模板关联失败 - templateId={}, error={}",
|
|
|
|
|
+ role, templateId, e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 清除单个优惠券模板的 activityId(设为 null)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param templateId 优惠券模板ID
|
|
|
|
|
+ */
|
|
|
|
|
+ private void clearCouponTemplateActivityId(Long templateId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ com.haha.entity.CouponTemplate template = couponTemplateService.getById(templateId);
|
|
|
|
|
+ if (template != null) {
|
|
|
|
|
+ template.setActivityId(null);
|
|
|
|
|
+ couponTemplateService.updateById(template);
|
|
|
|
|
+ log.info("[统一活动] 已清除优惠券模板关联 - templateId={}", templateId);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("[统一活动] 清除优惠券模板关联失败 - templateId={}, error={}",
|
|
|
|
|
+ templateId, e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|