RiceService.java 17 KB

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