|
@@ -10,12 +10,10 @@ import com.fs.his.constant.IntegralTaskConstants;
|
|
|
import com.fs.his.domain.FsUser;
|
|
import com.fs.his.domain.FsUser;
|
|
|
import com.fs.his.domain.FsUserIntegralBatch;
|
|
import com.fs.his.domain.FsUserIntegralBatch;
|
|
|
import com.fs.his.domain.FsUserIntegralLogs;
|
|
import com.fs.his.domain.FsUserIntegralLogs;
|
|
|
-import com.fs.his.domain.FsUserNewTask;
|
|
|
|
|
import com.fs.his.enums.FsUserIntegralLogTypeEnum;
|
|
import com.fs.his.enums.FsUserIntegralLogTypeEnum;
|
|
|
import com.fs.his.mapper.FsUserIntegralBatchMapper;
|
|
import com.fs.his.mapper.FsUserIntegralBatchMapper;
|
|
|
import com.fs.his.mapper.FsUserIntegralLogsMapper;
|
|
import com.fs.his.mapper.FsUserIntegralLogsMapper;
|
|
|
import com.fs.his.mapper.FsUserMapper;
|
|
import com.fs.his.mapper.FsUserMapper;
|
|
|
-import com.fs.his.mapper.FsUserNewTaskMapper;
|
|
|
|
|
import com.fs.his.param.FsUserAddIntegralTemplateParam;
|
|
import com.fs.his.param.FsUserAddIntegralTemplateParam;
|
|
|
import com.fs.his.param.IntegralBrowseCompleteParam;
|
|
import com.fs.his.param.IntegralBrowseCompleteParam;
|
|
|
import com.fs.his.param.IntegralBrowseStartParam;
|
|
import com.fs.his.param.IntegralBrowseStartParam;
|
|
@@ -31,6 +29,7 @@ import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+import org.springframework.transaction.support.TransactionTemplate;
|
|
|
|
|
|
|
|
import java.time.Instant;
|
|
import java.time.Instant;
|
|
|
import java.time.LocalDate;
|
|
import java.time.LocalDate;
|
|
@@ -50,8 +49,6 @@ public class IntegralTaskServiceImpl implements IIntegralTaskService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private FsUserIntegralLogsMapper fsUserIntegralLogsMapper;
|
|
private FsUserIntegralLogsMapper fsUserIntegralLogsMapper;
|
|
|
@Autowired
|
|
@Autowired
|
|
|
- private FsUserNewTaskMapper fsUserNewTaskMapper;
|
|
|
|
|
- @Autowired
|
|
|
|
|
private IFsUserIntegralLogsService userIntegralLogsService;
|
|
private IFsUserIntegralLogsService userIntegralLogsService;
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private IFsUserSignService userSignService;
|
|
private IFsUserSignService userSignService;
|
|
@@ -59,6 +56,8 @@ public class IntegralTaskServiceImpl implements IIntegralTaskService {
|
|
|
private RedisCache redisCache;
|
|
private RedisCache redisCache;
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private FsUserIntegralBatchMapper fsUserIntegralBatchMapper;
|
|
private FsUserIntegralBatchMapper fsUserIntegralBatchMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private TransactionTemplate transactionTemplate;
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public R getTaskCenter(Long userId, String platform) {
|
|
public R getTaskCenter(Long userId, String platform) {
|
|
@@ -177,15 +176,15 @@ public class IntegralTaskServiceImpl implements IIntegralTaskService {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
@Transactional
|
|
@Transactional
|
|
|
- public void tryGrantCourseCommentIntegral(Long userId, Long videoId, Long commentId) {
|
|
|
|
|
|
|
+ public int tryGrantCourseCommentIntegral(Long userId, Long videoId, Long commentId) {
|
|
|
if (userId == null || videoId == null) {
|
|
if (userId == null || videoId == null) {
|
|
|
- return;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
List<FsUserIntegralLogs> exists = fsUserIntegralLogsMapper.selectFsUserIntegralLogsByUserIdAndLogType(
|
|
List<FsUserIntegralLogs> exists = fsUserIntegralLogsMapper.selectFsUserIntegralLogsByUserIdAndLogType(
|
|
|
userId, FsUserIntegralLogTypeEnum.TYPE_33.getValue(), null);
|
|
userId, FsUserIntegralLogTypeEnum.TYPE_33.getValue(), null);
|
|
|
for (FsUserIntegralLogs item : exists) {
|
|
for (FsUserIntegralLogs item : exists) {
|
|
|
if (videoId.toString().equals(item.getBusinessId())) {
|
|
if (videoId.toString().equals(item.getBusinessId())) {
|
|
|
- return;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
FsUserAddIntegralTemplateParam param = new FsUserAddIntegralTemplateParam();
|
|
FsUserAddIntegralTemplateParam param = new FsUserAddIntegralTemplateParam();
|
|
@@ -194,42 +193,77 @@ public class IntegralTaskServiceImpl implements IIntegralTaskService {
|
|
|
param.setBusinessId(videoId.toString());
|
|
param.setBusinessId(videoId.toString());
|
|
|
param.setRemark(commentId != null ? commentId.toString() : null);
|
|
param.setRemark(commentId != null ? commentId.toString() : null);
|
|
|
userIntegralLogsService.addIntegralTemplate(param);
|
|
userIntegralLogsService.addIntegralTemplate(param);
|
|
|
|
|
+ return 1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- @Transactional
|
|
|
|
|
public void processExpiredIntegralBatches() {
|
|
public void processExpiredIntegralBatches() {
|
|
|
- List<FsUserIntegralBatch> batches = fsUserIntegralBatchMapper.selectExpiredBatches(new Date(), 500);
|
|
|
|
|
- for (FsUserIntegralBatch batch : batches) {
|
|
|
|
|
- if (batch.getRemain() == null || batch.getRemain() <= 0) {
|
|
|
|
|
- continue;
|
|
|
|
|
|
|
+ IntegralConfig config = IntegralConfigHelper.load(configService);
|
|
|
|
|
+ int expireDays = config.getIntegralExpireDays();
|
|
|
|
|
+ Date launchDate = DateUtils.parseDate(config.getIntegralExpireLaunchDate());
|
|
|
|
|
+ if (launchDate == null) {
|
|
|
|
|
+ launchDate = DateUtils.parseDate("2026-07-10");
|
|
|
|
|
+ }
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ int batchSize = 500;
|
|
|
|
|
+ int totalExpired = 0;
|
|
|
|
|
+ while (true) {
|
|
|
|
|
+ List<FsUserIntegralBatch> batches = fsUserIntegralBatchMapper.selectExpiredBatches(
|
|
|
|
|
+ now, launchDate, expireDays, batchSize);
|
|
|
|
|
+ if (batches == null || batches.isEmpty()) {
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- FsUser user = fsUserMapper.selectFsUserByUserId(batch.getUserId());
|
|
|
|
|
- if (user == null) {
|
|
|
|
|
- continue;
|
|
|
|
|
|
|
+ for (FsUserIntegralBatch batch : batches) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ transactionTemplate.execute(status -> {
|
|
|
|
|
+ expireIntegralBatch(batch);
|
|
|
|
|
+ return null;
|
|
|
|
|
+ });
|
|
|
|
|
+ totalExpired++;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("积分批次过期处理失败,batchId={},userId={}", batch.getBatchId(), batch.getUserId(), e);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- long deduct = batch.getRemain();
|
|
|
|
|
- long newBalance = Math.max(0, user.getIntegral() - deduct);
|
|
|
|
|
- FsUser userMap = new FsUser();
|
|
|
|
|
- userMap.setUserId(batch.getUserId());
|
|
|
|
|
- userMap.setIntegral(newBalance);
|
|
|
|
|
- fsUserMapper.updateFsUser(userMap);
|
|
|
|
|
-
|
|
|
|
|
- fsUserIntegralBatchMapper.updateRemain(batch.getBatchId(), 0L);
|
|
|
|
|
-
|
|
|
|
|
- FsUserIntegralLogs logs = new FsUserIntegralLogs();
|
|
|
|
|
- logs.setIntegral(-deduct);
|
|
|
|
|
- logs.setUserId(batch.getUserId());
|
|
|
|
|
- logs.setBalance(newBalance);
|
|
|
|
|
- logs.setLogType(FsUserIntegralLogTypeEnum.TYPE_7.getValue());
|
|
|
|
|
- logs.setBusinessId(batch.getBatchId().toString());
|
|
|
|
|
- logs.setCreateTime(new Date());
|
|
|
|
|
- logs.setRemark("积分过期失效");
|
|
|
|
|
- fsUserIntegralLogsMapper.insertFsUserIntegralLogs(logs);
|
|
|
|
|
|
|
+ if (batches.size() < batchSize) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (totalExpired > 0) {
|
|
|
|
|
+ log.info("积分过期处理完成,共失效 {} 笔批次,规则:{} 之后获得且超过 {} 天",
|
|
|
|
|
+ totalExpired, config.getIntegralExpireLaunchDate(), expireDays);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void expireIntegralBatch(FsUserIntegralBatch batch) {
|
|
|
|
|
+ if (batch.getRemain() == null || batch.getRemain() <= 0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ FsUser user = fsUserMapper.selectFsUserByUserId(batch.getUserId());
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ long deduct = batch.getRemain();
|
|
|
|
|
+ long newBalance = Math.max(0, user.getIntegral() - deduct);
|
|
|
|
|
+ FsUser userMap = new FsUser();
|
|
|
|
|
+ userMap.setUserId(batch.getUserId());
|
|
|
|
|
+ userMap.setIntegral(newBalance);
|
|
|
|
|
+ fsUserMapper.updateFsUser(userMap);
|
|
|
|
|
+
|
|
|
|
|
+ fsUserIntegralBatchMapper.updateRemain(batch.getBatchId(), 0L);
|
|
|
|
|
+
|
|
|
|
|
+ FsUserIntegralLogs logs = new FsUserIntegralLogs();
|
|
|
|
|
+ logs.setIntegral(-deduct);
|
|
|
|
|
+ logs.setUserId(batch.getUserId());
|
|
|
|
|
+ logs.setBalance(newBalance);
|
|
|
|
|
+ logs.setLogType(FsUserIntegralLogTypeEnum.TYPE_7.getValue());
|
|
|
|
|
+ logs.setBusinessId(batch.getBatchId().toString());
|
|
|
|
|
+ logs.setCreateTime(new Date());
|
|
|
|
|
+ logs.setRemark("积分过期失效");
|
|
|
|
|
+ fsUserIntegralLogsMapper.insertFsUserIntegralLogs(logs);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
|
|
+ @Transactional
|
|
|
public void markSignPopupShown(Long userId) {
|
|
public void markSignPopupShown(Long userId) {
|
|
|
String popupKey = IntegralTaskConstants.REDIS_SIGN_POPUP_PREFIX + userId + ":" + LocalDate.now();
|
|
String popupKey = IntegralTaskConstants.REDIS_SIGN_POPUP_PREFIX + userId + ":" + LocalDate.now();
|
|
|
redisCache.setCacheObject(popupKey, "1", 1, TimeUnit.DAYS);
|
|
redisCache.setCacheObject(popupKey, "1", 1, TimeUnit.DAYS);
|
|
@@ -313,21 +347,57 @@ public class IntegralTaskServiceImpl implements IIntegralTaskService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void hideCompletedNewbieTasks(List<Map<String, Object>> tasks, Long userId) {
|
|
private void hideCompletedNewbieTasks(List<Map<String, Object>> tasks, Long userId) {
|
|
|
- FsUserNewTask newTask = fsUserNewTaskMapper.selectFsUserNewTaskByUserId(userId);
|
|
|
|
|
- if (newTask == null || newTask.getCreateTime() == null) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- long hours = ChronoUnit.HOURS.between(newTask.getCreateTime().toInstant(), Instant.now());
|
|
|
|
|
- if (hours < 24) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Instant now = Instant.now();
|
|
|
for (Map<String, Object> task : tasks) {
|
|
for (Map<String, Object> task : tasks) {
|
|
|
- if (Integer.valueOf(2).equals(task.get("status"))) {
|
|
|
|
|
|
|
+ if (!Integer.valueOf(2).equals(task.get("status"))) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Integer logType = resolveNewbieLogType(task.get("code"));
|
|
|
|
|
+ if (logType == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Date completedAt = getTaskCompletedTime(userId, logType);
|
|
|
|
|
+ if (completedAt == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ task.put("completedAt", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, completedAt));
|
|
|
|
|
+ long hours = ChronoUnit.HOURS.between(completedAt.toInstant(), now);
|
|
|
|
|
+ if (hours >= IntegralTaskConstants.NEWBIE_COMPLETED_HIDE_HOURS) {
|
|
|
task.put("hidden", true);
|
|
task.put("hidden", true);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private Integer resolveNewbieLogType(Object code) {
|
|
|
|
|
+ if (code == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ switch (code.toString()) {
|
|
|
|
|
+ case IntegralTaskConstants.TASK_REGISTER:
|
|
|
|
|
+ return FsUserIntegralLogTypeEnum.TYPE_20.getValue();
|
|
|
|
|
+ case IntegralTaskConstants.TASK_DOWNLOAD_APP:
|
|
|
|
|
+ return FsUserIntegralLogTypeEnum.TYPE_28.getValue();
|
|
|
|
|
+ case IntegralTaskConstants.TASK_FIRST_PURCHASE:
|
|
|
|
|
+ return FsUserIntegralLogTypeEnum.TYPE_32.getValue();
|
|
|
|
|
+ case IntegralTaskConstants.TASK_INVITED:
|
|
|
|
|
+ return FsUserIntegralLogTypeEnum.TYPE_19.getValue();
|
|
|
|
|
+ default:
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Date getTaskCompletedTime(Long userId, int logType) {
|
|
|
|
|
+ List<FsUserIntegralLogs> logs = fsUserIntegralLogsMapper.selectFsUserIntegralLogsByUserIdAndLogType(userId, logType, null);
|
|
|
|
|
+ if (logs == null || logs.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ return logs.stream()
|
|
|
|
|
+ .map(FsUserIntegralLogs::getCreateTime)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .min(Date::compareTo)
|
|
|
|
|
+ .orElse(null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private boolean hasLogType(Long userId, int logType) {
|
|
private boolean hasLogType(Long userId, int logType) {
|
|
|
List<FsUserIntegralLogs> logs = fsUserIntegralLogsMapper.selectFsUserIntegralLogsByUserIdAndLogType(userId, logType, null);
|
|
List<FsUserIntegralLogs> logs = fsUserIntegralLogsMapper.selectFsUserIntegralLogsByUserIdAndLogType(userId, logType, null);
|
|
|
return logs != null && !logs.isEmpty();
|
|
return logs != null && !logs.isEmpty();
|