RiceService.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. package com.izouma.nineth.service;
  2. import com.alipay.mychain.sdk.vm.abi.datatype.Int;
  3. import com.izouma.nineth.domain.Rice;
  4. import com.izouma.nineth.domain.RiceOperationRecord;
  5. import com.izouma.nineth.domain.RiceUserWaterDropRecord;
  6. import com.izouma.nineth.domain.User;
  7. import com.izouma.nineth.dto.PageQuery;
  8. import com.izouma.nineth.dto.R;
  9. import com.izouma.nineth.dto.RiceDTO;
  10. import com.izouma.nineth.enums.RiceOperationType;
  11. import com.izouma.nineth.exception.BusinessException;
  12. import com.izouma.nineth.repo.RiceOperationRecordRepo;
  13. import com.izouma.nineth.repo.RiceRepo;
  14. import com.izouma.nineth.repo.RiceUserWaterDropRecordRepo;
  15. import com.izouma.nineth.repo.UserRepo;
  16. import com.izouma.nineth.utils.JpaUtils;
  17. import com.izouma.nineth.utils.SecurityUtils;
  18. import lombok.AllArgsConstructor;
  19. import org.apache.commons.lang.StringUtils;
  20. import org.apache.commons.lang.time.DateUtils;
  21. import org.springframework.beans.BeanUtils;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.data.domain.Page;
  24. import org.springframework.stereotype.Service;
  25. import org.springframework.transaction.annotation.Transactional;
  26. import org.springframework.web.bind.annotation.PostMapping;
  27. import org.springframework.web.bind.annotation.RequestParam;
  28. import javax.json.Json;
  29. import javax.json.JsonArray;
  30. import javax.json.JsonObject;
  31. import javax.json.JsonReader;
  32. import java.io.StringReader;
  33. import java.time.LocalDateTime;
  34. import java.util.*;
  35. @Service
  36. @AllArgsConstructor
  37. public class RiceService {
  38. private static final int MAX_NICKNAME_LENGTH = 6;
  39. private static final String UPDATE_SUCCESS_MSG = "修改成功";
  40. private RiceRepo riceRepo;
  41. private RiceUserWaterDropRecordRepo riceUserWaterDropRecordRepo;
  42. private RiceOperationRecordRepo riceOperationRecordRepo;
  43. private UserRepo userRepo;
  44. private SysConfigService sysConfigService;
  45. public Page<Rice> all(PageQuery pageQuery) {
  46. return riceRepo.findAll(JpaUtils.toSpecification(pageQuery, Rice.class), JpaUtils.toPageRequest(pageQuery));
  47. }
  48. //点击水稻游戏,进行初始化
  49. public Rice getCurrentRiceUser(User authenticatedUser) throws BusinessException {
  50. Long id = authenticatedUser.getId();
  51. Optional<User> byId = userRepo.findByIdAndDelFalse(id);
  52. String nickname = null;
  53. String avatar = null;
  54. if (byId.isPresent()) {
  55. User user = byId.get();
  56. nickname = user.getNickname();
  57. avatar = user.getAvatar();
  58. } else {
  59. throw new BusinessException("用户不存在");
  60. }
  61. Optional<Rice> byUserId = riceRepo.findByUserId(id);
  62. if (byUserId.isPresent()) {
  63. Rice rice = byUserId.get();
  64. return rice;
  65. } else {
  66. Rice rice = new Rice();
  67. rice.setUserId(id);
  68. rice.setAvatar(avatar);
  69. rice.setNickname(nickname);
  70. rice.setLevel(0L);
  71. rice.setWaterDropCount(0L);
  72. rice.setSignCount(0L);
  73. rice.setSelfScore(0L);
  74. rice.setSelfActivityScore(0L);
  75. rice.setEmpiricalValue(0L);
  76. riceRepo.save(rice);
  77. return rice;
  78. }
  79. }
  80. //修改昵称
  81. public R updateNickName(Long userId, String nickname) {
  82. String trimmedNickname = StringUtils.trim(nickname);
  83. if (trimmedNickname.length() > MAX_NICKNAME_LENGTH) {
  84. return R.error("昵称不能超过" + MAX_NICKNAME_LENGTH + "个字符");
  85. }
  86. riceRepo.updateNickName(userId, trimmedNickname);
  87. return R.success(UPDATE_SUCCESS_MSG);
  88. }
  89. /**
  90. * 获取当前等级
  91. *
  92. * @param empiricalValue
  93. * @return
  94. */
  95. public Map<String, Object> getCurrentLevel(Long empiricalValue) {
  96. String jsonString = sysConfigService.getString("rice_level");
  97. User authenticatedUser = SecurityUtils.getAuthenticatedUser();
  98. Long authId = authenticatedUser.getId();
  99. Optional<Rice> byUserId = riceRepo.findByUserId(authId);
  100. if (byUserId.isPresent()) {
  101. Rice rice = byUserId.get();
  102. empiricalValue = rice.getEmpiricalValue();
  103. JsonReader jsonReader = Json.createReader(new StringReader(jsonString));
  104. JsonArray jsonArray = jsonReader.readArray();
  105. Long currentLevel = null;
  106. Long currentStart = null;
  107. Long nextStart = null;
  108. for (int i = 0; i < jsonArray.size(); i++) {
  109. JsonObject jsonObject = jsonArray.getJsonObject(i);
  110. Long start = Long.valueOf(jsonObject.getInt("start"));
  111. if (empiricalValue >= start && empiricalValue < (i<jsonArray.size()-1?Long.valueOf(jsonArray.getJsonObject(i+1).getInt("start")):Long.MAX_VALUE)) {
  112. String currentLevelStr = jsonObject.getString("name").replace("Lv", "");
  113. currentLevel = Long.parseLong(currentLevelStr);
  114. currentStart = Long.valueOf(jsonObject.getInt("start"));
  115. if (i < jsonArray.size() - 1) {
  116. JsonObject nextObject = jsonArray.getJsonObject(i + 1);
  117. nextStart = nextObject.getJsonNumber("start").longValue();
  118. }
  119. break;
  120. }
  121. }
  122. if (currentLevel != null && currentStart != null) {
  123. Map<String, Object> result = new HashMap<>();
  124. result.put("currentLevel", currentLevel);
  125. double levelUpPercentage;
  126. if (nextStart != null) {
  127. levelUpPercentage = (double)(empiricalValue - currentStart) / (nextStart - currentStart);
  128. } else {
  129. levelUpPercentage = 1.0;
  130. }
  131. result.put("levelUpPercentage", levelUpPercentage);
  132. return result;
  133. } else {
  134. throw new BusinessException("没有配置对应的等级对应经验值");
  135. }
  136. } else {
  137. throw new BusinessException("用户不存在");
  138. }
  139. }
  140. /**
  141. * 任务初始化.显示各个任务能否点击
  142. *
  143. * @return R<?>
  144. */
  145. public R<?> taskInitialization() {
  146. User authenticatedUser = SecurityUtils.getAuthenticatedUser();
  147. Long authId = authenticatedUser.getId();
  148. Optional<Rice> byUserId = riceRepo.findByUserId(authId);
  149. if (byUserId.isPresent()) {
  150. Rice rice = byUserId.get();
  151. Long lastSignInTime = rice.getLastSignInTime();
  152. Long currentTime = System.currentTimeMillis();
  153. // 判断上次签到时间是否为空,如果为空,则默认为从未签到过
  154. if (lastSignInTime == null) {
  155. return R.success("未签到").add("isSignedIn", false).add("exchangeCount", rice.getExchangeCount() == null ? 0 : rice.getExchangeCount()).add("waterDropCount", rice.getWaterDropCount());
  156. }
  157. // 判断今天是否已经签到过
  158. if (DateUtils.isSameDay(new Date(lastSignInTime), new Date(currentTime))) {
  159. return R.success("已签到").add("isSignedIn", true).add("exchangeCount", rice.getExchangeCount() == null ? 0 : rice.getExchangeCount()).add("waterDropCount", rice.getWaterDropCount());
  160. } else {
  161. return R.success("未签到").add("isSignedIn", false).add("exchangeCount", rice.getExchangeCount() == null ? 0 : rice.getExchangeCount()).add("waterDropCount", rice.getWaterDropCount());
  162. }
  163. }
  164. return R.error("查询失败");
  165. }
  166. /**
  167. * 获取当前用户积分
  168. */
  169. public R<String> getCurrentScore() {
  170. User authenticatedUser = SecurityUtils.getAuthenticatedUser();
  171. Long authId = authenticatedUser.getId();
  172. Optional<Rice> byUserId = riceRepo.findByUserId(authId);
  173. if (byUserId.isPresent()) {
  174. Rice rice = byUserId.get();
  175. Long selfScore = rice.getSelfScore();
  176. return R.success("获取到当前用户积分").add("selfScore", selfScore);
  177. }
  178. return R.error("获取失败");
  179. }
  180. //在RiceService中添加一个方法用于更新所有用户的排名。
  181. public void updateScoreRank() {
  182. List<Rice> allRices = riceRepo.findAll();
  183. allRices.sort(Comparator.comparing(Rice::getSelfScore).reversed());
  184. for (int i = 0; i < allRices.size(); i++) {
  185. Rice rice = allRices.get(i);
  186. // rice.setScoreRank(i + 1);
  187. riceRepo.save(rice);
  188. }
  189. }
  190. public List<RiceDTO> getTop100(Long userId) {
  191. List<Rice> top100Rices = riceRepo.findTop100OrderByEmpiricalValueDesc();
  192. List<RiceDTO> result = new ArrayList<>();
  193. // 计算自己的排名
  194. int selfRank = 0;
  195. for (int i = 0; i < top100Rices.size(); i++) {
  196. if (top100Rices.get(i).getId().equals(userId)) {
  197. selfRank = i + 1;
  198. break;
  199. }
  200. }
  201. for (int i = 0; i < top100Rices.size(); i++) {
  202. Rice rice = top100Rices.get(i);
  203. RiceDTO riceDTO = new RiceDTO();
  204. BeanUtils.copyProperties(rice, riceDTO);
  205. riceDTO.setScoreRank(i + 1);
  206. // 判断是否上榜
  207. if (i < 100) {
  208. riceDTO.setOnTop100(true);
  209. } else {
  210. riceDTO.setOnTop100(false);
  211. }
  212. // 如果是自己,则设置自己的头像、昵称、等级和离上榜还差多少名
  213. if (rice.getId().equals(userId)) {
  214. riceDTO.setAvatar(rice.getAvatar());
  215. riceDTO.setNickname(rice.getNickname());
  216. riceDTO.setLevel(rice.getLevel());
  217. if (i < 100) {
  218. riceDTO.setRankGap(0);
  219. } else {
  220. riceDTO.setRankGap(i + 1 - 100);
  221. }
  222. }
  223. result.add(riceDTO);
  224. }
  225. return result;
  226. }
  227. //计算自己排名
  228. public R<RiceDTO> getRiceUserRank(Long userId) {
  229. Optional<Rice> rice1 = riceRepo.findByUserId(userId);
  230. if (!rice1.isPresent()) {
  231. return R.error("用户不存在");
  232. }
  233. List<Rice> top100Rices = riceRepo.findByOrderBySelfScoreDesc();
  234. List<RiceDTO> result = new ArrayList<>();
  235. RiceDTO dto = new RiceDTO();
  236. // 计算自己的排名
  237. int selfRank = 0;
  238. for (int i = 0; i < top100Rices.size(); i++) {
  239. if (top100Rices.get(i).getUserId().equals(userId)) {
  240. selfRank = i + 1;
  241. break;
  242. }
  243. }
  244. for (int i = 0; i < top100Rices.size(); i++) {
  245. Rice rice = top100Rices.get(i);
  246. RiceDTO riceDTO = new RiceDTO();
  247. BeanUtils.copyProperties(rice, riceDTO);
  248. riceDTO.setScoreRank(i + 1);
  249. // 判断是否上榜
  250. if (i < 100) {
  251. riceDTO.setOnTop100(true);
  252. } else {
  253. riceDTO.setOnTop100(false);
  254. }
  255. // 如果是自己,则设置自己的头像、昵称、等级和离上榜还差多少名
  256. if (rice.getUserId().equals(userId)) {
  257. riceDTO.setAvatar(rice.getAvatar());
  258. riceDTO.setNickname(rice.getNickname());
  259. riceDTO.setLevel(rice.getLevel());
  260. if (i < 100) {
  261. riceDTO.setRankGap(0);
  262. } else {
  263. riceDTO.setRankGap(i + 1 - 100);
  264. }
  265. BeanUtils.copyProperties(riceDTO, dto);
  266. }
  267. }
  268. if (dto == null) {
  269. return R.error("用户不存在");
  270. }
  271. return R.success(dto);
  272. }
  273. //浇水
  274. public R<? extends Object> watering() {
  275. // 获取当前用户 ID,
  276. User authenticatedUser = SecurityUtils.getAuthenticatedUser();
  277. Long authId = authenticatedUser.getId();
  278. Optional<Rice> byUserId = riceRepo.findByUserId(authId);
  279. if (byUserId.isPresent()) {
  280. Rice rice = byUserId.get();
  281. Long waterDropCount = rice.getWaterDropCount();
  282. Long beforeWaterDropCount = rice.getWaterDropCount();
  283. Long beforeEmpiricalValue = rice.getEmpiricalValue();
  284. // 如果水滴次数为 0,返回不能浇水的提示
  285. if (waterDropCount == 0) {
  286. return R.error("水滴次数已用完,无法浇水").add("can", false);
  287. }
  288. // 浇水成功,更新水滴次数,经验值加2
  289. rice.setWaterDropCount(waterDropCount - 1);
  290. rice.setEmpiricalValue(rice.getEmpiricalValue()+2);
  291. riceRepo.save(rice);
  292. createRiceOperationRecord(authId, RiceOperationType.WATER_DROP, 1L,beforeWaterDropCount , rice.getWaterDropCount());
  293. createRiceOperationRecord(authId, RiceOperationType.EMPIRICAL_VALUE, 2L,beforeEmpiricalValue , rice.getEmpiricalValue());
  294. // Save watering record
  295. RiceUserWaterDropRecord record = new RiceUserWaterDropRecord();
  296. record.setUserId(authId);
  297. record.setWateringTime(LocalDateTime.now());
  298. riceUserWaterDropRecordRepo.save(record);
  299. return R.success("浇水成功").add("can", true).add("time", waterDropCount - 1);
  300. }
  301. return R.error("浇水失败").add("can", false);
  302. }
  303. //根据用户ID和今日时间获取今日浇水次数的方法
  304. public Long getTodayWateringCount(Long userId) {
  305. List<RiceUserWaterDropRecord> records = riceUserWaterDropRecordRepo.findByUserId(userId);
  306. Long count = records.stream()
  307. .filter(RiceUserWaterDropRecord::isToday)
  308. .count();
  309. return count;
  310. }
  311. /**
  312. * 每浇水一次可获得2经验值,升级所需经验值为下一等级所配置的经验值标准。按照以下方式来计算用户升级所需水滴数
  313. * @param rice
  314. * @return
  315. */
  316. public Long getWaterDropNeededForLevelUp(Rice rice) {
  317. Long currentEmpiricalValue = rice.getEmpiricalValue();
  318. String jsonString = sysConfigService.getString("rice_level");
  319. JsonReader jsonReader = Json.createReader(new StringReader(jsonString));
  320. JsonArray jsonArray = jsonReader.readArray();
  321. for (int i = 0; i < jsonArray.size(); i++) {
  322. JsonObject jsonObject = jsonArray.getJsonObject(i);
  323. Long start = Long.valueOf(jsonObject.getInt("start"));
  324. Long nextStart = 0L;
  325. if (i + 1 < jsonArray.size()) {
  326. JsonObject nextJsonObject = jsonArray.getJsonObject(i + 1);
  327. nextStart = Long.valueOf(nextJsonObject.getInt("start"));
  328. }
  329. if (currentEmpiricalValue >= start && currentEmpiricalValue < nextStart) {
  330. Long levelUpEmpiricalValue = nextStart - currentEmpiricalValue;
  331. Long waterDropNeededForLevelUp = levelUpEmpiricalValue / 2;
  332. return waterDropNeededForLevelUp;
  333. }
  334. }
  335. throw new BusinessException("没有配置对应的等级对应经验值");
  336. }
  337. //签到
  338. public R<?> signIn(Long userId) {
  339. Optional<Rice> byUserId = riceRepo.findByUserId(userId);
  340. if (byUserId.isPresent()) {
  341. Rice rice = byUserId.get();
  342. Long lastSignInTime = rice.getLastSignInTime();
  343. Long currentTime = System.currentTimeMillis();
  344. Long beforeWaterDropCount = rice.getWaterDropCount();
  345. Long beforeEmpiricalValue = rice.getEmpiricalValue();
  346. // 判断上次签到时间是否为空,如果为空,则默认为从未签到过
  347. if (lastSignInTime == null) {
  348. rice.setWaterDropCount(rice.getWaterDropCount() + 1);
  349. rice.setSignCount(rice.getSignCount() + 1);
  350. rice.setLastSignInTime(currentTime);
  351. riceRepo.save(rice);
  352. createRiceOperationRecord(userId,RiceOperationType.WATER_DROP, (long) 1,beforeWaterDropCount,rice.getWaterDropCount());
  353. return R.success("签到成功").add("can",true).add("waterDropCount",rice.getWaterDropCount());
  354. }
  355. // 判断今天是否已经签到过
  356. if (DateUtils.isSameDay(new Date(lastSignInTime), new Date(currentTime))) {
  357. return R.error("今天已经签到过了").add("can",false);
  358. }
  359. // 签到成功,水滴数加1,签到次数加1,更新签到时间
  360. rice.setWaterDropCount(rice.getWaterDropCount() + 1);
  361. rice.setSignCount(rice.getSignCount() + 1);
  362. rice.setLastSignInTime(currentTime);
  363. riceRepo.save(rice);
  364. createRiceOperationRecord(userId,RiceOperationType.WATER_DROP, (long) 1,beforeWaterDropCount,rice.getWaterDropCount());
  365. return R.success("签到成功").add("can",true).add("waterDropCount",rice.getWaterDropCount());
  366. }
  367. return R.error("签到失败").add("can",false);
  368. }
  369. @Transactional
  370. public R<?> exchangeScoreForWaterDrop(User authenticatedUser) {
  371. Long authId = authenticatedUser.getId();
  372. Optional<Rice> byUserId = riceRepo.findByUserId(authId);
  373. if (byUserId.isPresent()) {
  374. Rice rice = byUserId.get();
  375. Long selfScore = rice.getSelfScore();
  376. Long beforeSelfScore = rice.getSelfScore();
  377. Integer waterDropCount = Math.toIntExact(rice.getWaterDropCount());
  378. Long beforeWaterDropCount = rice.getWaterDropCount();
  379. // 每次兑换需要消耗的积分和最大兑换次数
  380. int exchangeScore = 2;
  381. int maxExchangeCount = 10;
  382. // 计算当前可兑换的次数和消耗的积分
  383. if(rice.getExchangeCount()==null){
  384. rice.setExchangeCount(0);
  385. }
  386. int exchangeCount = Math.min((int) (selfScore / exchangeScore), maxExchangeCount-rice.getExchangeCount());
  387. int totalScore = exchangeCount * exchangeScore;
  388. if (exchangeCount > 0) {
  389. rice.setSelfScore(selfScore - totalScore);
  390. rice.setWaterDropCount((long) (waterDropCount + exchangeCount));
  391. riceRepo.save(rice);
  392. createRiceOperationRecord(authId,RiceOperationType.WATER_DROP, (long) exchangeCount,beforeWaterDropCount,rice.getWaterDropCount());
  393. return R.success("兑换成功").add("exchangeCount", exchangeCount).add("waterDropCount", rice.getWaterDropCount());
  394. } else if(exchangeCount==0){
  395. return R.error("今天已经兑换满10滴水滴了");
  396. }
  397. else {
  398. return R.error("兑换失败,当前积分不足").add("exchangeCount", 0).add("waterDropCount", rice.getWaterDropCount());
  399. }
  400. }
  401. return R.error("兑换失败,用户不存在");
  402. }
  403. private void createRiceOperationRecord(Long userId, RiceOperationType type, Long amount, Long beforeAmount, Long afterAmount) {
  404. RiceOperationRecord record = new RiceOperationRecord();
  405. record.setUserId(userId);
  406. record.setType(type);
  407. record.setAmount(amount);
  408. record.setBeforeAmount(beforeAmount);
  409. record.setAfterAmount(afterAmount);
  410. riceOperationRecordRepo.save(record);
  411. }
  412. //活动积分兑换水滴,无上限.
  413. public R<?> exchangeActivityScoreForWaterDrop(User authenticatedUser) {
  414. // 检查用户活动积分是否足够
  415. Optional<Rice> optionalRice = riceRepo.findById(authenticatedUser.getId());
  416. if (!optionalRice.isPresent()) {
  417. return R.error("未找到用户信息");
  418. }
  419. Rice rice = optionalRice.get();
  420. Long currentActivityPoints = rice.getSelfActivityScore();
  421. Long beforeWaterDropCount = rice.getWaterDropCount();
  422. // 计算兑换的水滴数量
  423. Long exchangedWaterDropCount = (long) Math.floor(currentActivityPoints / 2.0);
  424. if (exchangedWaterDropCount <= 0) {
  425. return R.error("活动积分不足以兑换水滴").add("times",exchangedWaterDropCount);
  426. }
  427. // 更新用户活动积分和水滴数
  428. rice.setSelfActivityScore(currentActivityPoints - (Long) exchangedWaterDropCount*2);
  429. rice.setWaterDropCount(rice.getWaterDropCount() + exchangedWaterDropCount);
  430. riceRepo.save(rice);
  431. // 记录水滴操作记录
  432. createRiceOperationRecord(authenticatedUser.getId(), RiceOperationType.WATER_DROP, exchangedWaterDropCount, beforeWaterDropCount, rice.getWaterDropCount());
  433. createRiceOperationRecord(authenticatedUser.getId(), RiceOperationType.SELF_ACTIVITY_SCORE, (Long) exchangedWaterDropCount*2, currentActivityPoints, rice.getSelfActivityScore());
  434. return R.success("兑换成功").add("times", exchangedWaterDropCount);
  435. }
  436. }