PointActivityServiceImpl.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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.core.conditions.query.LambdaQueryWrapper;
  8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  9. import com.ylx.common.exception.base.BaseException;
  10. import com.ylx.common.utils.DateUtils;
  11. import com.ylx.point.domain.PointActivity;
  12. import com.ylx.point.domain.PointActivityTask;
  13. import com.ylx.point.domain.PointSignReward;
  14. import com.ylx.point.domain.PointSignTask;
  15. import com.ylx.point.domain.dto.*;
  16. import com.ylx.point.domain.vo.*;
  17. import com.ylx.point.enums.PointActivityExpirePolicyEnum;
  18. import com.ylx.point.enums.PointActivityStatusEnum;
  19. import com.ylx.point.enums.PointActivityTypeEnum;
  20. import com.ylx.point.mapper.PointActivityMapper;
  21. import com.ylx.point.service.*;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.stereotype.Service;
  24. import org.springframework.transaction.annotation.Transactional;
  25. import java.time.DateTimeException;
  26. import java.time.LocalDateTime;
  27. import java.time.ZoneId;
  28. import java.util.ArrayList;
  29. import java.util.Date;
  30. import java.util.List;
  31. import java.util.stream.Collectors;
  32. /**
  33. * 积分活动主Service业务层处理
  34. *
  35. * @author wzj
  36. * @date 2026-03-25
  37. */
  38. @Service
  39. public class PointActivityServiceImpl extends ServiceImpl<PointActivityMapper, PointActivity> implements IPointActivityService {
  40. @Autowired
  41. private PointActivityMapper pointActivityMapper;
  42. @Autowired
  43. private IPointActivityTaskService pointActivityTaskService;
  44. @Autowired
  45. private IPointSignTaskService pointSignTaskService;
  46. @Autowired
  47. private IPointSignRewardService pointSignRewardService;
  48. @Autowired
  49. private IPointUserActivityTaskCompletionService pointUserActivityTaskCompletionService;
  50. @Override
  51. public List<PointActivityPageVo> list(PointActivityPageDTO dto) {
  52. return pointActivityMapper.list(dto);
  53. }
  54. @Override
  55. public PointActivityDetailsVo<?> getDetailsInfo(Long id) {
  56. PointActivity pointActivity = this.pointActivityMapper.selectPointActivityById(id);
  57. if (ObjectUtil.isNull(pointActivity)) {
  58. throw new BaseException("参数有误,活动不存在");
  59. }
  60. Integer activityType = pointActivity.getActivityType();
  61. if (PointActivityTypeEnum.SIGN_TASK.getCode().equals(activityType)) {
  62. PointSignTaskVo vo = this.pointSignTaskService.selectPointSignTaskByActivityId(pointActivity.getId());
  63. BeanUtil.copyProperties(pointActivity, vo);
  64. return PointActivityDetailsVo.of(activityType, vo);
  65. } else {
  66. PointActivityTaskVo vo = new PointActivityTaskVo();
  67. BeanUtil.copyProperties(pointActivity, vo);
  68. List<PointActivityTaskDTO> activityTaskList = this.pointActivityTaskService.selectPointActivityTaskByActivityId(pointActivity.getId());
  69. vo.setActivityTaskList(activityTaskList);
  70. return PointActivityDetailsVo.of(activityType, vo);
  71. }
  72. }
  73. @Override
  74. @Transactional(rollbackFor = Exception.class)
  75. public void add(PointActivityDTO dto) {
  76. // 校验参数
  77. validateActivityDTO(dto);
  78. // 保存活动信息
  79. PointActivity entity = createActivityEntity(dto);
  80. saveActivity(entity);
  81. // 保存活动详情信息
  82. saveActivityDetails(dto, entity.getId());
  83. }
  84. @Override
  85. @Transactional(rollbackFor = Exception.class)
  86. public void edit(PointActivityDTO dto) {
  87. // 校验参数
  88. Long id = dto.getId();
  89. if (ObjectUtil.isNull(id)) {
  90. throw new BaseException("活动主键id不能为空");
  91. }
  92. // 根据id获取活动详情
  93. PointActivity entity = this.pointActivityMapper.selectPointActivityById(id);
  94. if (ObjectUtil.isNull(entity)) {
  95. throw new BaseException("参数有误,活动不存在");
  96. }
  97. // 校验活动状态
  98. if (PointActivityStatusEnum.IN_PROGRESS.getCode().equals(entity.getStatus())) {
  99. throw new BaseException("活动进行中,不可编辑");
  100. }
  101. // 更新活动信息
  102. BeanUtil.copyProperties(dto, entity);
  103. updateActivity(entity);
  104. // 更新活动详情信息
  105. updateActivityDetails(dto, id);
  106. }
  107. @Override
  108. public PointActivityStatVo getStatInfo(Long id) {
  109. // 根据id获取活动详情
  110. PointActivity entity = this.pointActivityMapper.selectPointActivityById(id);
  111. if (ObjectUtil.isNull(entity)) {
  112. throw new BaseException("参数有误,活动不存在");
  113. }
  114. PointActivityStatVo vo = new PointActivityStatVo();
  115. BeanUtil.copyProperties(entity, vo);
  116. // 数据总览
  117. PointActivityOverviewVO dataOverview = this.pointUserActivityTaskCompletionService.getPointActivityOverviewByActivityId(id);
  118. vo.setDataOverview(dataOverview);
  119. // 数据详情
  120. List<PointActivityTaskDetailVO> taskDetailList = pointActivityMapper.getTaskDetailListById(id);
  121. vo.setTaskDetailList(taskDetailList);
  122. return vo;
  123. }
  124. @Override
  125. @Transactional(rollbackFor = Exception.class)
  126. public void editValidity(PointActivityValidityDTO dto) {
  127. // 根据dto中activityType获取全部的活动list
  128. LambdaQueryWrapper<PointActivity> queryWrapper = new LambdaQueryWrapper<>();
  129. queryWrapper.eq(PointActivity::getActivityType, dto.getActivityType());
  130. PointActivity pointActivity = new PointActivity();
  131. pointActivity.setActivityType(dto.getActivityType());
  132. List<PointActivity> activityList = pointActivityMapper.selectPointActivityList(pointActivity);
  133. if (CollectionUtil.isEmpty(activityList)) {
  134. throw new BaseException("该类型的活动不存在,设置失败");
  135. }
  136. // 判断活动list中只要有活动的状态为"进行中",修改就失败
  137. boolean hasOngoingActivity = activityList.stream()
  138. .anyMatch(activity -> PointActivityStatusEnum.IN_PROGRESS.getCode().equals(activity.getStatus()));
  139. if (hasOngoingActivity) {
  140. throw new BaseException("存在进行中的活动,无法修改有效期");
  141. }
  142. // 批量更新活动的有效期策略
  143. batchUpdateExpirePolicy(activityList, dto);
  144. }
  145. private void validateActivityDTO(PointActivityDTO dto) {
  146. if (ObjectUtil.isNull(dto)) {
  147. throw new BaseException("活动信息不能为空");
  148. }
  149. PointActivityDTO.ActivityTimeConfig timeConfig = dto.getTimeConfig();
  150. if (ObjectUtil.isNull(timeConfig) || (StrUtil.equals(timeConfig.getIsPermanent(), "1") &&
  151. (ObjectUtil.isNull(timeConfig.getStartTime()) || ObjectUtil.isNull(timeConfig.getEndTime())))) {
  152. throw new BaseException("活动时间配置不能为空");
  153. }
  154. }
  155. private PointActivity createActivityEntity(PointActivityDTO dto) {
  156. // 创建基础实体
  157. PointActivity entity = new PointActivity();
  158. BeanUtil.copyProperties(dto, entity);
  159. // 处理时间配置
  160. PointActivityDTO.ActivityTimeConfig timeConfig = dto.getTimeConfig();
  161. entity.setStartTime(DateUtil.beginOfDay(timeConfig.getStartTime()));
  162. entity.setEndTime(processEndTime(timeConfig.getEndTime()));
  163. entity.setIsPermanent(timeConfig.getIsPermanent());
  164. // 处理状态
  165. if (PointActivityStatusEnum.PUBLISHED.getCode().equals(dto.getStatus())) {
  166. entity.setStatus(determineActivityStatus(
  167. entity.getStartTime(),
  168. entity.getEndTime(),
  169. timeConfig.getIsPermanent()
  170. ));
  171. }
  172. return entity;
  173. }
  174. private void saveActivity(PointActivity entity) {
  175. int affectedRows = pointActivityMapper.insertPointActivity(entity);
  176. if (affectedRows <= 0) {
  177. throw new BaseException("保存积分活动失败");
  178. }
  179. }
  180. private void updateActivity(PointActivity entity) {
  181. int affectedRows = pointActivityMapper.updatePointActivity(entity);
  182. if (affectedRows <= 0) {
  183. throw new BaseException("更新积分活动失败");
  184. }
  185. }
  186. private void saveActivityDetails(PointActivityDTO dto, Long activityId) {
  187. if (PointActivityTypeEnum.SIGN_TASK.getCode().equals(dto.getActivityType())) {
  188. saveSignTaskDetails(dto, activityId);
  189. } else {
  190. saveActivityTaskDetails(dto, activityId);
  191. }
  192. }
  193. private void updateActivityDetails(PointActivityDTO dto, Long activityId) {
  194. if (PointActivityTypeEnum.SIGN_TASK.getCode().equals(dto.getActivityType())) {
  195. updateSignTaskDetails(dto, activityId);
  196. } else {
  197. updateActivityTaskDetails(dto, activityId);
  198. }
  199. }
  200. private void saveSignTaskDetails(PointActivityDTO dto, Long activityId) {
  201. PointSignTaskDTO signTaskDTO = dto.getSignTaskDTO();
  202. if (ObjectUtil.isNull(signTaskDTO)) {
  203. throw new BaseException("签到任务配置不能为空");
  204. }
  205. PointSignTask pointSignTask = new PointSignTask();
  206. pointSignTask.setActivityId(activityId);
  207. pointSignTask.setBasePoints(signTaskDTO.getBasePoints());
  208. pointSignTask.setBreakRule(signTaskDTO.getBreakRule());
  209. pointSignTask.setCreateTime(new Date());
  210. pointSignTask.setUpdateTime(pointSignTask.getCreateTime());
  211. pointSignTask.setIsDeleted(0);
  212. int affectedRows = pointSignTaskService.insertPointSignTask(pointSignTask);
  213. if (affectedRows <= 0) {
  214. throw new BaseException("保存积分签到任务规则失败");
  215. }
  216. saveSignRewards(signTaskDTO.getSignRewardList(), pointSignTask.getId());
  217. }
  218. private void saveSignRewards(List<PointSignRewardDTO> rewardList, Long taskId) {
  219. if (CollectionUtil.isEmpty(rewardList)) {
  220. return;
  221. }
  222. List<PointSignReward> rewards = rewardList.stream()
  223. .map(dto -> {
  224. PointSignReward reward = new PointSignReward();
  225. reward.setRewardPoints(dto.getRewardPoints());
  226. reward.setContinueDays(dto.getContinueDays());
  227. reward.setCreateTime(new Date());
  228. reward.setUpdateTime(reward.getCreateTime());
  229. reward.setIsDeleted(0);
  230. reward.setSignTaskId(taskId);
  231. return reward;
  232. })
  233. .collect(Collectors.toList());
  234. pointSignRewardService.batchInsertPointSignReward(rewards);
  235. }
  236. private void saveActivityTaskDetails(PointActivityDTO dto, Long activityId) {
  237. List<PointActivityTaskDTO> tasks = dto.getTasks();
  238. if (CollectionUtil.isEmpty(tasks)) {
  239. return;
  240. }
  241. List<PointActivityTask> activityTasks = tasks.stream()
  242. .map(task -> {
  243. PointActivityTask activityTask = new PointActivityTask();
  244. BeanUtil.copyProperties(task, activityTask);
  245. activityTask.setActivityId(activityId);
  246. activityTask.setIsDeleted(0);
  247. activityTask.setCreateTime(new Date());
  248. activityTask.setUpdateTime(activityTask.getCreateTime());
  249. return activityTask;
  250. })
  251. .collect(Collectors.toList());
  252. pointActivityTaskService.batchInsertPointActivityTask(activityTasks);
  253. }
  254. /**
  255. * 处理结束时间,设置为当天的23:59:59
  256. */
  257. private Date processEndTime(Date endTime) {
  258. if (endTime == null) {
  259. return null;
  260. }
  261. try {
  262. LocalDateTime localDateTime = LocalDateTime.ofInstant(
  263. endTime.toInstant(),
  264. ZoneId.systemDefault()
  265. );
  266. LocalDateTime endOfDay = localDateTime.with(
  267. java.time.LocalTime.of(23, 59, 59));
  268. return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
  269. } catch (DateTimeException e) {
  270. throw new IllegalArgumentException("Invalid end time", e);
  271. }
  272. }
  273. /**
  274. * 确定活动状态
  275. */
  276. private Integer determineActivityStatus(Date startTime, Date endTime, String isPermanent) {
  277. if (StrUtil.equals(isPermanent, "1")) {
  278. return PointActivityStatusEnum.IN_PROGRESS.getCode();
  279. }
  280. Date now = DateUtils.getNowDate();
  281. if (startTime.after(now)) {
  282. return PointActivityStatusEnum.NOT_START.getCode();
  283. } else if (endTime != null && endTime.before(now)) {
  284. return PointActivityStatusEnum.FINISHED.getCode();
  285. } else {
  286. return PointActivityStatusEnum.IN_PROGRESS.getCode();
  287. }
  288. }
  289. /**
  290. * 更新签到任务详情
  291. */
  292. private void updateSignTaskDetails(PointActivityDTO dto, Long activityId) {
  293. PointSignTaskDTO signTaskDTO = dto.getSignTaskDTO();
  294. if (ObjectUtil.isNull(signTaskDTO)) {
  295. throw new BaseException("签到任务配置不能为空");
  296. }
  297. // 获取现有的签到任务
  298. PointSignTaskVo existingTask = pointSignTaskService.selectPointSignTaskByActivityId(activityId);
  299. // 更新签到任务基本信息
  300. PointSignTask pointSignTask = new PointSignTask();
  301. pointSignTask.setId(existingTask.getSignTaskId());
  302. pointSignTask.setBasePoints(signTaskDTO.getBasePoints());
  303. pointSignTask.setBreakRule(signTaskDTO.getBreakRule());
  304. // 更新签到任务
  305. int affectedRows = pointSignTaskService.updatePointSignTask(pointSignTask);
  306. if (affectedRows <= 0) {
  307. throw new BaseException("更新积分签到任务规则失败");
  308. }
  309. // 更新签到奖励配置
  310. updateSignRewards(signTaskDTO.getSignRewardList(), pointSignTask.getId());
  311. }
  312. /**
  313. * 更新签到奖励配置
  314. */
  315. private void updateSignRewards(List<PointSignRewardDTO> rewardList, Long taskId) {
  316. // 先删除原有的奖励配置
  317. PointSignReward query = new PointSignReward();
  318. query.setSignTaskId(taskId);
  319. List<PointSignReward> existingRewards = pointSignRewardService.selectPointSignRewardList(query);
  320. if (CollectionUtil.isNotEmpty(existingRewards)) {
  321. String[] ids = existingRewards.stream()
  322. .map(reward -> String.valueOf(reward.getId()))
  323. .toArray(String[]::new);
  324. pointSignRewardService.deletePointSignRewardByIds(ids);
  325. }
  326. // 重新插入新的奖励配置
  327. if (CollectionUtil.isEmpty(rewardList)) {
  328. return;
  329. }
  330. List<PointSignReward> rewards = rewardList.stream()
  331. .map(dto -> {
  332. PointSignReward reward = new PointSignReward();
  333. reward.setRewardPoints(dto.getRewardPoints());
  334. reward.setContinueDays(dto.getContinueDays());
  335. reward.setCreateTime(new Date());
  336. reward.setUpdateTime(reward.getCreateTime());
  337. reward.setIsDeleted(0);
  338. reward.setSignTaskId(taskId);
  339. return reward;
  340. })
  341. .collect(Collectors.toList());
  342. pointSignRewardService.batchInsertPointSignReward(rewards);
  343. }
  344. /**
  345. * 更新活动任务详情
  346. */
  347. private void updateActivityTaskDetails(PointActivityDTO dto, Long activityId) {
  348. // 先删除原有的活动任务
  349. pointActivityTaskService.deletePointActivityTaskByActivityId(activityId);
  350. // 重新插入新的活动任务
  351. List<PointActivityTaskDTO> tasks = dto.getTasks();
  352. if (CollectionUtil.isEmpty(tasks)) {
  353. return;
  354. }
  355. List<PointActivityTask> activityTasks = tasks.stream()
  356. .map(task -> {
  357. PointActivityTask activityTask = new PointActivityTask();
  358. BeanUtil.copyProperties(task, activityTask);
  359. activityTask.setActivityId(activityId);
  360. activityTask.setIsDeleted(0);
  361. activityTask.setCreateTime(new Date());
  362. activityTask.setUpdateTime(activityTask.getCreateTime());
  363. return activityTask;
  364. })
  365. .collect(Collectors.toList());
  366. pointActivityTaskService.batchInsertPointActivityTask(activityTasks);
  367. }
  368. private void batchUpdateExpirePolicy(List<PointActivity> activityList, PointActivityValidityDTO dto) {
  369. Integer expirePolicy = dto.getExpirePolicy();
  370. // 使用Stream处理活动列表
  371. List<PointActivity> updateList = activityList.stream()
  372. .peek(activity -> {
  373. activity.setExpirePolicy(expirePolicy);
  374. // 根据策略设置不同的过期时间字段
  375. if (PointActivityExpirePolicyEnum.TRANSACTION_EXPIRE.getCode().equals(expirePolicy)) {
  376. activity.setExpireDays(dto.getExpireDays());
  377. activity.setExpireYear(null);
  378. } else if (PointActivityExpirePolicyEnum.YEARLY_EXPIRE.getCode().equals(expirePolicy)) {
  379. activity.setExpireYear(dto.getExpireYear());
  380. activity.setExpireDays(null);
  381. } else {
  382. activity.setExpireDays(null);
  383. activity.setExpireYear(null);
  384. }
  385. })
  386. .collect(Collectors.toList());
  387. // 批量更新数据库
  388. if (CollectionUtil.isNotEmpty(updateList)) {
  389. super.updateBatchById(updateList);
  390. }
  391. }
  392. }