PointActivityServiceImpl.java 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. package com.ylx.point.service.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.collection.CollectionUtil;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.util.ObjectUtil;
  6. import cn.hutool.core.util.StrUtil;
  7. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  8. import com.ylx.common.core.domain.model.WxLoginUser;
  9. import com.ylx.common.exception.base.BaseException;
  10. import com.ylx.common.utils.DateUtils;
  11. import com.ylx.common.utils.SecurityUtils;
  12. import com.ylx.massage.domain.TWxUser;
  13. import com.ylx.massage.service.TWxUserService;
  14. import com.ylx.point.domain.*;
  15. import com.ylx.point.domain.dto.*;
  16. import com.ylx.point.domain.vo.*;
  17. import com.ylx.point.enums.PointActivityStatusEnum;
  18. import com.ylx.point.enums.PointActivityTypeEnum;
  19. import com.ylx.point.mapper.PointActivityMapper;
  20. import com.ylx.point.service.*;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.stereotype.Service;
  24. import org.springframework.transaction.annotation.Transactional;
  25. import javax.annotation.Resource;
  26. import java.time.DateTimeException;
  27. import java.time.LocalDate;
  28. import java.time.LocalDateTime;
  29. import java.time.ZoneId;
  30. import java.util.*;
  31. import java.util.stream.Collectors;
  32. /**
  33. * 积分活动主Service业务层处理
  34. *
  35. * @author wzj
  36. * @date 2026-03-25
  37. */
  38. @Slf4j
  39. @Service
  40. public class PointActivityServiceImpl extends ServiceImpl<PointActivityMapper, PointActivity> implements IPointActivityService {
  41. @Resource
  42. private PointActivityMapper pointActivityMapper;
  43. @Autowired
  44. private IPointActivityTaskService pointActivityTaskService;
  45. @Autowired
  46. private IPointSignTaskService pointSignTaskService;
  47. @Autowired
  48. private IPointSignRewardService pointSignRewardService;
  49. @Autowired
  50. private IPointUserActivityTaskCompletionService pointUserActivityTaskCompletionService;
  51. @Autowired
  52. private IPointActivityExpirePolicyService pointActivityExpirePolicyService;
  53. @Resource
  54. private TWxUserService wxUserService;
  55. private static final int BATCH_SIZE = 1000;
  56. private static final int TARGET_COUNT = 2;
  57. private static final String INVALID_EXPIRE_POLICY_TYPE_MESSAGE = "无效的过期策略类型";
  58. private static final String EXPIRE_DAYS_REQUIRED_MESSAGE = "过期天数不能为空";
  59. private static final String EXPIRE_YEAR_REQUIRED_MESSAGE = "过期年数不能为空";
  60. private static final String UPDATE_FAILED_MESSAGE = "更新积分活动过期策略失败";
  61. // 优先级顺序
  62. private static final List<Integer> PRIORITY_TYPES = Arrays.asList(
  63. PointActivityTypeEnum.NEW_USER_ACTIVITY.getCode(),
  64. PointActivityTypeEnum.DAILY_ACTIVITY.getCode(),
  65. PointActivityTypeEnum.MONTHLY_ACTIVITY.getCode()); // 新手, 每日, 每月
  66. @Override
  67. public List<PointActivityPageVo> list(PointActivityPageDTO dto) {
  68. return pointActivityMapper.list(dto);
  69. }
  70. @Override
  71. public PointActivityDetailsVo<?> getDetailsInfo(Long id) {
  72. PointActivity pointActivity = this.pointActivityMapper.selectPointActivityById(id);
  73. if (ObjectUtil.isNull(pointActivity)) {
  74. throw new BaseException("参数有误,活动不存在");
  75. }
  76. Integer activityType = pointActivity.getActivityType();
  77. if (PointActivityTypeEnum.SIGN_TASK.getCode().equals(activityType)) {
  78. PointSignTaskVo vo = this.pointSignTaskService.selectPointSignTaskByActivityId(pointActivity.getId());
  79. BeanUtil.copyProperties(pointActivity, vo);
  80. return PointActivityDetailsVo.of(activityType, vo);
  81. } else {
  82. PointActivityTaskVo vo = new PointActivityTaskVo();
  83. BeanUtil.copyProperties(pointActivity, vo);
  84. List<PointActivityTaskDTO> activityTaskList = this.pointActivityTaskService.selectPointActivityTaskByActivityId(pointActivity.getId());
  85. vo.setActivityTaskList(activityTaskList);
  86. return PointActivityDetailsVo.of(activityType, vo);
  87. }
  88. }
  89. @Override
  90. @Transactional(rollbackFor = Exception.class)
  91. public void add(PointActivityDTO dto) {
  92. // 校验参数
  93. validateActivityDTO(dto);
  94. // 保存活动信息
  95. PointActivity entity = createActivityEntity(dto);
  96. saveActivity(entity);
  97. // 保存活动详情信息
  98. saveActivityDetails(dto, entity.getId());
  99. }
  100. @Override
  101. @Transactional(rollbackFor = Exception.class)
  102. public void edit(PointActivityDTO dto) {
  103. // 校验参数
  104. Long id = dto.getId();
  105. if (ObjectUtil.isNull(id)) {
  106. throw new BaseException("活动主键id不能为空");
  107. }
  108. // 根据id获取活动详情
  109. PointActivity entity = this.pointActivityMapper.selectPointActivityById(id);
  110. if (ObjectUtil.isNull(entity)) {
  111. throw new BaseException("参数有误,活动不存在");
  112. }
  113. // 校验活动状态
  114. if (PointActivityStatusEnum.IN_PROGRESS.getCode().equals(entity.getStatus())) {
  115. throw new BaseException("活动进行中,不可编辑");
  116. }
  117. updateActivity(entity, dto);
  118. // 更新活动详情信息
  119. updateActivityDetails(dto, id);
  120. }
  121. @Override
  122. public PointActivityStatVo getStatInfo(Long id) {
  123. // 根据id获取活动详情
  124. PointActivity entity = this.pointActivityMapper.selectPointActivityById(id);
  125. if (ObjectUtil.isNull(entity)) {
  126. throw new BaseException("参数有误,活动不存在");
  127. }
  128. PointActivityStatVo vo = new PointActivityStatVo();
  129. BeanUtil.copyProperties(entity, vo);
  130. // 数据总览
  131. PointActivityOverviewVO dataOverview = this.pointUserActivityTaskCompletionService.getPointActivityOverviewByActivityId(id);
  132. vo.setDataOverview(dataOverview);
  133. // 数据详情
  134. List<PointActivityTaskDetailVO> taskDetailList = pointActivityMapper.getTaskDetailListById(id);
  135. vo.setTaskDetailList(taskDetailList);
  136. return vo;
  137. }
  138. @Override
  139. @Transactional(rollbackFor = Exception.class)
  140. public void editValidity(PointActivityValidityDTO dto) {
  141. // 根据dto中activityType获取全部的活动list
  142. PointActivity pointActivity = new PointActivity();
  143. pointActivity.setActivityType(dto.getActivityType());
  144. List<PointActivity> activityList = pointActivityMapper.selectPointActivityList(pointActivity);
  145. // 根据类型获取积分活动过期策略表数据
  146. PointActivityExpirePolicy expirePolicy = pointActivityExpirePolicyService.selectPointActivityExpirePolicyByActivityType(dto.getActivityType());
  147. if (CollectionUtil.isEmpty(activityList)) {
  148. // 更新积分活动过期策略表
  149. this.saveOrUpdatePointActivityExpirePolicy(expirePolicy, dto);
  150. } else {
  151. // 判断活动list中只要有活动的状态为"进行中",修改就失败
  152. boolean hasOngoingActivity = activityList.stream()
  153. .anyMatch(activity -> PointActivityStatusEnum.IN_PROGRESS.getCode().equals(activity.getStatus()));
  154. if (hasOngoingActivity) {
  155. throw new BaseException("存在进行中的活动,无法修改有效期");
  156. }
  157. // 更新积分活动过期策略表
  158. this.saveOrUpdatePointActivityExpirePolicy(expirePolicy, dto);
  159. // 批量更新活动的有效期策略
  160. batchUpdateExpirePolicy(activityList, expirePolicy.getId());
  161. }
  162. }
  163. @Override
  164. public List<PointActivityValidityVo> validityDetails() {
  165. try {
  166. // 查询所有过期策略
  167. List<PointActivityExpirePolicy> expirePolicies = this.pointActivityExpirePolicyService.list();
  168. // 如果没有数据,返回空列表
  169. if (CollectionUtil.isEmpty(expirePolicies)) {
  170. log.debug("没有查询到积分活动过期策略数据");
  171. return Collections.emptyList();
  172. }
  173. // 转换为VO对象
  174. List<PointActivityValidityVo> result = expirePolicies.stream()
  175. .map(this::convertToVo)
  176. .collect(Collectors.toList());
  177. log.info("成功查询到 {} 条积分活动有效期详情", result.size());
  178. return result;
  179. } catch (Exception e) {
  180. log.error("查询积分活动有效期详情失败", e);
  181. throw new BaseException("查询积分活动有效期详情失败");
  182. }
  183. }
  184. @Override
  185. public Integer selectTotalActiveTasks(String cityCode) {
  186. return pointActivityMapper.selectTotalActiveTasks(cityCode);
  187. }
  188. @Override
  189. public List<UserPointActivityVo> getUserPointActivityList(UserPointActivityPageDTO dto) {
  190. // 当前登录用户信息
  191. WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
  192. TWxUser user = wxUserService.getByOpenId(wxLoginUser.getCOpenid());
  193. if (user == null) {
  194. throw new RuntimeException("用户不存在");
  195. }
  196. String userId = user.getId();
  197. dto.setUserId(userId);
  198. return pointActivityMapper.selectTaskWithProgress(dto);
  199. }
  200. @Override
  201. public List<UserPointActivityVo> activityList() {
  202. // 当前登录用户信息
  203. WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
  204. TWxUser user = wxUserService.getByOpenId(wxLoginUser.getCOpenid());
  205. if (user == null) {
  206. throw new RuntimeException("用户不存在");
  207. }
  208. String userId = user.getId();
  209. List<UserPointActivityVo> resultList = new ArrayList<>();
  210. // 2. 按优先级遍历活动类型
  211. for (Integer activityType : PRIORITY_TYPES) {
  212. if (resultList.size() >= TARGET_COUNT) {
  213. break;
  214. }
  215. // 3. 查询该类型下 进行中 的任务
  216. List<PointActivityTask> taskList = pointActivityTaskService.selectTasksByActivityType(activityType);
  217. if (CollectionUtil.isEmpty(taskList)) {
  218. continue;
  219. }
  220. // 4. 批量查询用户完成记录
  221. List<Long> taskIds = taskList.stream().map(PointActivityTask::getId).collect(Collectors.toList());
  222. List<PointUserActivityTaskCompletion> completionList =
  223. pointUserActivityTaskCompletionService.selectCompletionsByUserAndTaskIds(userId, taskIds);
  224. Map<Long, PointUserActivityTaskCompletion> completionMap = completionList.stream()
  225. .collect(Collectors.toMap(PointUserActivityTaskCompletion::getTaskId, c -> c));
  226. // 5. 筛选【未完成】的任务
  227. for (PointActivityTask task : taskList) {
  228. if (resultList.size() >= TARGET_COUNT) break;
  229. PointUserActivityTaskCompletion completion = completionMap.get(task.getId());
  230. if (isTaskIncomplete(task, completion)) {
  231. resultList.add(convertToVo(task, completion));
  232. }
  233. }
  234. }
  235. return resultList.stream().limit(2).collect(Collectors.toList());
  236. }
  237. /**
  238. * 判断任务是否未完成
  239. */
  240. private boolean isTaskIncomplete(PointActivityTask task, PointUserActivityTaskCompletion completion) {
  241. // 1. 获取规则要求的次数
  242. int requiredCount = 0;
  243. try {
  244. requiredCount = Integer.parseInt(task.getTriggerValue());
  245. } catch (NumberFormatException e) {
  246. // 如果配置错误,为了安全起见,默认视为未完成(或根据业务抛出异常)
  247. return true;
  248. }
  249. // 2. 获取用户实际完成的次数
  250. int actualCount = 0;
  251. if (ObjectUtil.isNotNull(completion) && ObjectUtil.isNotNull(completion.getCompletedCount())) {
  252. actualCount = completion.getCompletedCount();
  253. }
  254. // 3. 核心判断逻辑
  255. // 如果 实际次数 < 要求次数,则任务“未完成” (返回 true)
  256. return actualCount < requiredCount;
  257. }
  258. /**
  259. * 组装 VO 对象
  260. */
  261. private UserPointActivityVo convertToVo(PointActivityTask task, PointUserActivityTaskCompletion completion) {
  262. UserPointActivityVo vo = new UserPointActivityVo();
  263. vo.setActivityId(task.getActivityId());
  264. vo.setTaskName(task.getTaskName()); // 或者是从字典表查出的中文名称
  265. vo.setRewardPoints(task.getRewardPoints());
  266. // 完成次数:如果没有记录则为 "0"
  267. vo.setCompletedCount(completion != null ? String.valueOf(completion.getCompletedCount()) : "0");
  268. // 触发条件:直接从任务配置中获取,或者根据 taskCode 查字典
  269. vo.setTriggerValue(task.getTriggerValue());
  270. return vo;
  271. }
  272. private PointActivityValidityVo convertToVo(PointActivityExpirePolicy policy) {
  273. PointActivityValidityVo vo = new PointActivityValidityVo();
  274. BeanUtil.copyProperties(policy, vo);
  275. // 可以在这里添加额外的转换逻辑
  276. return vo;
  277. }
  278. private void validateActivityDTO(PointActivityDTO dto) {
  279. if (ObjectUtil.isNull(dto)) {
  280. throw new BaseException("活动信息不能为空");
  281. }
  282. PointActivityDTO.ActivityTimeConfig timeConfig = dto.getTimeConfig();
  283. if (ObjectUtil.isNull(timeConfig) || (!timeConfig.getIsPermanent() &&
  284. (ObjectUtil.isNull(timeConfig.getStartTime()) || ObjectUtil.isNull(timeConfig.getEndTime())))) {
  285. throw new BaseException("活动时间配置不能为空");
  286. }
  287. }
  288. private PointActivity createActivityEntity(PointActivityDTO dto) {
  289. // 创建基础实体
  290. PointActivity entity = new PointActivity();
  291. BeanUtil.copyProperties(dto, entity);
  292. // 处理时间配置
  293. PointActivityDTO.ActivityTimeConfig timeConfig = dto.getTimeConfig();
  294. entity.setStartTime(DateUtil.beginOfDay(timeConfig.getStartTime()));
  295. entity.setEndTime(processEndTime(timeConfig.getEndTime()));
  296. entity.setIsPermanent(timeConfig.getIsPermanent()? 1 : 0);
  297. // 处理状态
  298. if (PointActivityStatusEnum.PUBLISHED.getCode().equals(dto.getStatus())) {
  299. entity.setStatus(determineActivityStatus(
  300. entity.getStartTime(),
  301. entity.getEndTime(),
  302. timeConfig.getIsPermanent()
  303. ));
  304. }
  305. return entity;
  306. }
  307. private void saveActivity(PointActivity entity) {
  308. entity.setCreateBy(SecurityUtils.getUsername());
  309. entity.setCreateTime(new Date());
  310. int affectedRows = pointActivityMapper.insertPointActivity(entity);
  311. if (affectedRows <= 0) {
  312. throw new BaseException("保存积分活动失败");
  313. }
  314. }
  315. private void saveOrUpdatePointActivityExpirePolicy(PointActivityExpirePolicy expirePolicy, PointActivityValidityDTO dto) {
  316. // 参数校验
  317. if (ObjectUtil.isNull(dto)) {
  318. throw new IllegalArgumentException("参数不能为空");
  319. }
  320. // 根据expirePolicy类型设置对应的过期时间
  321. Integer expirePolicyCode = dto.getExpirePolicy();
  322. if (ObjectUtil.isNull(expirePolicyCode)) {
  323. throw new IllegalArgumentException("过期策略类型不能为空");
  324. }
  325. // 准备要保存或更新的实体
  326. PointActivityExpirePolicy entity = expirePolicy != null ? expirePolicy : new PointActivityExpirePolicy();
  327. // 设置基本信息
  328. entity.setActivityType(dto.getActivityType());
  329. entity.setExpirePolicy(dto.getExpirePolicy());
  330. // 根据过期策略类型设置对应的过期时间
  331. setExpireTimeByPolicyType(entity, dto, expirePolicyCode);
  332. // 保存或更新
  333. saveOrUpdateExpirePolicy(entity, dto.getActivityType());
  334. }
  335. private void setExpireTimeByPolicyType(PointActivityExpirePolicy entity, PointActivityValidityDTO dto, Integer expirePolicyCode) {
  336. // 先清空所有过期时间字段
  337. entity.setExpireDays(null);
  338. entity.setExpireYear(null);
  339. // 根据策略类型设置对应的过期时间
  340. switch (expirePolicyCode) {
  341. case 1: // PERMANENT_VALID - 永久有效
  342. // 已经清空了过期天数和年数,无需额外操作
  343. break;
  344. case 2: // TRANSACTION_EXPIRE - 按交易过期
  345. if (dto.getExpireDays() == null) {
  346. throw new IllegalArgumentException(EXPIRE_DAYS_REQUIRED_MESSAGE);
  347. }
  348. entity.setExpireDays(dto.getExpireDays());
  349. break;
  350. case 3: // YEARLY_EXPIRE - 按年过期
  351. if (dto.getExpireYear() == null) {
  352. throw new IllegalArgumentException(EXPIRE_YEAR_REQUIRED_MESSAGE);
  353. }
  354. entity.setExpireYear(dto.getExpireYear());
  355. break;
  356. default:
  357. throw new IllegalArgumentException(INVALID_EXPIRE_POLICY_TYPE_MESSAGE);
  358. }
  359. }
  360. private void saveOrUpdateExpirePolicy(PointActivityExpirePolicy entity, Integer activityType) {
  361. try {
  362. entity.setUpdateBy(SecurityUtils.getUsername());
  363. entity.setUpdateTime(DateUtils.getNowDate());
  364. boolean isSuccess = pointActivityExpirePolicyService.updateById(entity);
  365. if (!isSuccess) {
  366. log.error("保存或更新积分活动过期策略失败, activityType: {}", activityType);
  367. throw new BaseException(UPDATE_FAILED_MESSAGE);
  368. }
  369. } catch (Exception e) {
  370. log.error("保存或更新积分活动过期策略时发生异常, activityType: {}", activityType, e);
  371. throw new BaseException(UPDATE_FAILED_MESSAGE);
  372. }
  373. }
  374. private void saveActivityDetails(PointActivityDTO dto, Long activityId) {
  375. if (PointActivityTypeEnum.SIGN_TASK.getCode().equals(dto.getActivityType())) {
  376. saveSignTaskDetails(dto, activityId);
  377. } else {
  378. saveActivityTaskDetails(dto, activityId);
  379. }
  380. }
  381. private void updateActivityDetails(PointActivityDTO dto, Long activityId) {
  382. if (PointActivityTypeEnum.SIGN_TASK.getCode().equals(dto.getActivityType())) {
  383. updateSignTaskDetails(dto, activityId);
  384. } else {
  385. updateActivityTaskDetails(dto, activityId);
  386. }
  387. }
  388. private void updateActivity(PointActivity entity, PointActivityDTO dto) {
  389. // 更新活动信息
  390. BeanUtil.copyProperties(dto, entity);
  391. // 处理时间配置
  392. PointActivityDTO.ActivityTimeConfig timeConfig = dto.getTimeConfig();
  393. if (timeConfig != null) {
  394. entity.setStartTime(DateUtil.beginOfDay(timeConfig.getStartTime()));
  395. entity.setEndTime(processEndTime(timeConfig.getEndTime()));
  396. entity.setIsPermanent(timeConfig.getIsPermanent()? 1 : 0);
  397. }
  398. // 处理状态
  399. if (PointActivityStatusEnum.PUBLISHED.getCode().equals(dto.getStatus())) {
  400. entity.setStatus(determineActivityStatus(
  401. entity.getStartTime(),
  402. entity.getEndTime(),
  403. timeConfig.getIsPermanent()
  404. ));
  405. }
  406. entity.setUpdateBy(SecurityUtils.getUsername());
  407. entity.setUpdateTime(DateUtils.getNowDate());
  408. int affectedRows = pointActivityMapper.updatePointActivity(entity);
  409. if (affectedRows <= 0) {
  410. throw new BaseException("更新积分活动失败");
  411. }
  412. }
  413. private void saveSignTaskDetails(PointActivityDTO dto, Long activityId) {
  414. PointSignTaskDTO signTaskDTO = dto.getSignTaskDTO();
  415. if (ObjectUtil.isNull(signTaskDTO)) {
  416. throw new BaseException("签到任务配置不能为空");
  417. }
  418. PointSignTask pointSignTask = new PointSignTask();
  419. pointSignTask.setActivityId(activityId);
  420. pointSignTask.setBasePoints(signTaskDTO.getBasePoints());
  421. pointSignTask.setBreakRule(signTaskDTO.getBreakRule());
  422. int affectedRows = pointSignTaskService.insertPointSignTask(pointSignTask);
  423. if (affectedRows <= 0) {
  424. throw new BaseException("保存积分签到任务规则失败");
  425. }
  426. saveSignRewards(signTaskDTO.getSignRewardList(), pointSignTask.getId());
  427. }
  428. private void saveSignRewards(List<PointSignRewardDTO> rewardList, Long taskId) {
  429. if (CollectionUtil.isEmpty(rewardList)) {
  430. return;
  431. }
  432. List<PointSignReward> rewards = rewardList.stream()
  433. .map(dto -> {
  434. PointSignReward reward = new PointSignReward();
  435. reward.setRewardPoints(dto.getRewardPoints());
  436. reward.setContinueDays(dto.getContinueDays());
  437. reward.setCreateBy(SecurityUtils.getUsername());
  438. reward.setCreateTime(DateUtils.getNowDate());
  439. reward.setUpdateTime(reward.getCreateTime());
  440. reward.setIsDeleted(0);
  441. reward.setSignTaskId(taskId);
  442. return reward;
  443. })
  444. .collect(Collectors.toList());
  445. pointSignRewardService.batchInsertPointSignReward(rewards);
  446. }
  447. private void saveActivityTaskDetails(PointActivityDTO dto, Long activityId) {
  448. List<PointActivityTaskDTO> tasks = dto.getTasks();
  449. if (CollectionUtil.isEmpty(tasks)) {
  450. return;
  451. }
  452. List<PointActivityTask> activityTasks = tasks.stream()
  453. .map(task -> {
  454. PointActivityTask activityTask = new PointActivityTask();
  455. BeanUtil.copyProperties(task, activityTask);
  456. activityTask.setActivityId(activityId);
  457. activityTask.setIsDeleted(0);
  458. activityTask.setCreateBy(SecurityUtils.getUsername());
  459. activityTask.setCreateTime(DateUtils.getNowDate());
  460. activityTask.setUpdateTime(activityTask.getCreateTime());
  461. return activityTask;
  462. })
  463. .collect(Collectors.toList());
  464. pointActivityTaskService.batchInsertPointActivityTask(activityTasks);
  465. }
  466. /**
  467. * 处理结束时间,设置为当天的23:59:59
  468. */
  469. private Date processEndTime(Date endTime) {
  470. if (endTime == null) {
  471. return null;
  472. }
  473. try {
  474. LocalDateTime localDateTime = LocalDateTime.ofInstant(
  475. endTime.toInstant(),
  476. ZoneId.systemDefault()
  477. );
  478. LocalDateTime endOfDay = localDateTime.with(
  479. java.time.LocalTime.of(23, 59, 59));
  480. return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
  481. } catch (DateTimeException e) {
  482. throw new IllegalArgumentException("Invalid end time", e);
  483. }
  484. }
  485. /**
  486. * 确定活动状态
  487. */
  488. private Integer determineActivityStatus(Date startTime, Date endTime, Boolean isPermanent) {
  489. if (isPermanent) {
  490. return PointActivityStatusEnum.IN_PROGRESS.getCode();
  491. }
  492. Date now = DateUtils.getNowDate();
  493. if (startTime.after(now)) {
  494. return PointActivityStatusEnum.NOT_START.getCode();
  495. } else if (endTime != null && endTime.before(now)) {
  496. return PointActivityStatusEnum.FINISHED.getCode();
  497. } else {
  498. return PointActivityStatusEnum.IN_PROGRESS.getCode();
  499. }
  500. }
  501. /**
  502. * 更新签到任务详情
  503. */
  504. private void updateSignTaskDetails(PointActivityDTO dto, Long activityId) {
  505. PointSignTaskDTO signTaskDTO = dto.getSignTaskDTO();
  506. if (ObjectUtil.isNull(signTaskDTO)) {
  507. throw new BaseException("签到任务配置不能为空");
  508. }
  509. // 获取现有的签到任务
  510. PointSignTaskVo existingTask = pointSignTaskService.selectPointSignTaskByActivityId(activityId);
  511. // 更新签到任务基本信息
  512. PointSignTask pointSignTask = new PointSignTask();
  513. pointSignTask.setId(existingTask.getSignTaskId());
  514. pointSignTask.setBasePoints(signTaskDTO.getBasePoints());
  515. pointSignTask.setBreakRule(signTaskDTO.getBreakRule());
  516. // 更新签到任务
  517. int affectedRows = pointSignTaskService.updatePointSignTask(pointSignTask);
  518. if (affectedRows <= 0) {
  519. throw new BaseException("更新积分签到任务规则失败");
  520. }
  521. // 更新签到奖励配置
  522. updateSignRewards(signTaskDTO.getSignRewardList(), pointSignTask.getId());
  523. }
  524. /**
  525. * 更新签到奖励配置
  526. */
  527. private void updateSignRewards(List<PointSignRewardDTO> rewardList, Long taskId) {
  528. // 先删除原有的奖励配置
  529. PointSignReward query = new PointSignReward();
  530. query.setSignTaskId(taskId);
  531. List<PointSignReward> existingRewards = pointSignRewardService.selectPointSignRewardList(query);
  532. if (CollectionUtil.isNotEmpty(existingRewards)) {
  533. String[] ids = existingRewards.stream()
  534. .map(reward -> String.valueOf(reward.getId()))
  535. .toArray(String[]::new);
  536. pointSignRewardService.deletePointSignRewardByIds(ids);
  537. }
  538. // 重新插入新的奖励配置
  539. if (CollectionUtil.isEmpty(rewardList)) {
  540. return;
  541. }
  542. List<PointSignReward> rewards = rewardList.stream()
  543. .map(dto -> {
  544. PointSignReward reward = new PointSignReward();
  545. reward.setRewardPoints(dto.getRewardPoints());
  546. reward.setContinueDays(dto.getContinueDays());
  547. reward.setCreateTime(DateUtils.getNowDate());
  548. reward.setUpdateTime(reward.getCreateTime());
  549. reward.setIsDeleted(0);
  550. reward.setSignTaskId(taskId);
  551. return reward;
  552. })
  553. .collect(Collectors.toList());
  554. pointSignRewardService.batchInsertPointSignReward(rewards);
  555. }
  556. /**
  557. * 更新活动任务详情
  558. */
  559. private void updateActivityTaskDetails(PointActivityDTO dto, Long activityId) {
  560. // 先删除原有的活动任务
  561. pointActivityTaskService.deletePointActivityTaskByActivityId(activityId);
  562. // 重新插入新的活动任务
  563. List<PointActivityTaskDTO> tasks = dto.getTasks();
  564. if (CollectionUtil.isEmpty(tasks)) {
  565. return;
  566. }
  567. List<PointActivityTask> activityTasks = tasks.stream()
  568. .map(task -> {
  569. PointActivityTask activityTask = new PointActivityTask();
  570. BeanUtil.copyProperties(task, activityTask);
  571. activityTask.setActivityId(activityId);
  572. activityTask.setIsDeleted(0);
  573. activityTask.setUpdateBy(SecurityUtils.getUsername());
  574. activityTask.setUpdateTime(DateUtils.getNowDate());
  575. return activityTask;
  576. })
  577. .collect(Collectors.toList());
  578. pointActivityTaskService.batchInsertPointActivityTask(activityTasks);
  579. }
  580. private void batchUpdateExpirePolicy(List<PointActivity> activityList, Long expirePolicyId) {
  581. // 参数校验
  582. if (CollectionUtil.isEmpty(activityList)) {
  583. log.debug("活动列表为空,无需更新过期策略");
  584. return;
  585. }
  586. if (expirePolicyId == null) {
  587. throw new IllegalArgumentException("过期策略ID不能为空");
  588. }
  589. try {
  590. // 使用Stream处理活动列表,设置过期策略ID
  591. List<PointActivity> activitiesToUpdate = activityList.stream()
  592. .map(activity -> {
  593. activity.setExpirePolicyId(expirePolicyId);
  594. activity.setUpdateTime(DateUtils.getNowDate());
  595. activity.setUpdateBy(SecurityUtils.getUsername());
  596. return activity;
  597. })
  598. .collect(Collectors.toList());
  599. // 批量更新数据库
  600. super.updateBatchById(activitiesToUpdate, BATCH_SIZE);
  601. log.info("成功更新 {} 个活动的过期策略为 {}", activitiesToUpdate.size(), expirePolicyId);
  602. } catch (Exception e) {
  603. log.error("批量更新活动过期策略失败, expirePolicyId: {}", expirePolicyId, e);
  604. throw new BaseException("批量更新活动过期策略失败");
  605. }
  606. }
  607. }