TeamService.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package com.izouma.walkchina.service;
  2. import cn.binarywang.wx.miniapp.api.WxMaService;
  3. import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
  4. import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
  5. import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
  6. import com.izouma.walkchina.constant.AppConstants;
  7. import com.izouma.walkchina.constant.Strings;
  8. import com.izouma.walkchina.domain.*;
  9. import com.izouma.walkchina.dto.UserDTO;
  10. import com.izouma.walkchina.exception.ServiceException;
  11. import com.izouma.walkchina.repo.*;
  12. import com.izouma.walkchina.utils.ImageUtils;
  13. import lombok.extern.slf4j.Slf4j;
  14. import me.chanjar.weixin.common.error.WxErrorException;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.data.domain.Example;
  17. import org.springframework.scheduling.annotation.Async;
  18. import org.springframework.stereotype.Service;
  19. import javax.imageio.ImageIO;
  20. import java.awt.*;
  21. import java.awt.image.BufferedImage;
  22. import java.io.ByteArrayInputStream;
  23. import java.io.IOException;
  24. import java.math.BigDecimal;
  25. import java.net.URL;
  26. import java.time.LocalDate;
  27. import java.time.LocalDateTime;
  28. import java.util.ArrayList;
  29. import java.util.List;
  30. import java.util.Optional;
  31. import static java.time.temporal.ChronoUnit.DAYS;
  32. @Service
  33. @Slf4j
  34. public class TeamService {
  35. @Autowired
  36. private TeamMemberRepository teamMemberRepository;
  37. @Autowired
  38. private UserInfoRepository userInfoRepository;
  39. @Autowired
  40. private MessageRepository messageRepository;
  41. @Autowired
  42. private WalkDataRepository walkDataRepository;
  43. @Autowired
  44. private FriendInfoService friendInfoService;
  45. @Autowired
  46. private CoinService coinService;
  47. @Autowired
  48. private WxMaService wxMaService;
  49. @Autowired
  50. private FormIdService formIdService;
  51. @Autowired
  52. private UserInfoService userInfoService;
  53. @Autowired
  54. private RewardRecordRepository rewardRecordRepository;
  55. @Autowired
  56. private MessageService messageService;
  57. @Autowired
  58. private JourneyService journeyService;
  59. public void hire(Long userId, Long target) {
  60. friendInfoService.becomeFriend(userId, target);
  61. LocalDateTime now = LocalDateTime.now();
  62. UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在"));
  63. UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在"));
  64. TeamMember teamMember = teamMemberRepository.findCurrent(target, now.toLocalDate());
  65. if (teamMember != null) {
  66. if (teamMember.getLeader().equals(userId)) {
  67. throw new ServiceException("Ta已经是你的队员");
  68. }
  69. if (teamMember.getStartDate().atTime(0, 0).isAfter(now)) {
  70. throw new ServiceException(Strings.GRAB_FAIL);
  71. }
  72. teamMember.setEndDate(now.toLocalDate());
  73. teamMember.setGrabbed(true);
  74. teamMemberRepository.save(teamMember);
  75. Message grabMsg = Message.builder()
  76. .userId(teamMember.getLeader())
  77. .type(AppConstants.MessageType.NORMAL)
  78. .content(String.format(Strings.MSG_MEMBER_GRABBED, targetUserInfo.getNickname(), userInfo.getNickname()))
  79. .active(true)
  80. .isRead(false)
  81. .build();
  82. messageRepository.save(grabMsg);
  83. }
  84. BigDecimal price = Optional.ofNullable(targetUserInfo.getPrice()).orElse(AppConstants.MIN_PRICE);
  85. BigDecimal balance = Optional.ofNullable(userInfo.getCoin()).orElse(BigDecimal.ZERO);
  86. if (balance.compareTo(price) < 0) {
  87. throw new ServiceException("雇佣失败,商城币不足");
  88. }
  89. coinService.balanceChange(userInfo, price.negate(), AppConstants.CoinRecordType.HIRE, Strings.REMARK_HIRE, null);
  90. coinService.balanceChange(targetUserInfo, price, AppConstants.CoinRecordType.BE_HIRED, Strings.REMARK_BE_HIRED, null);
  91. TeamMember newTeamMember = TeamMember.builder()
  92. .userId(target)
  93. .leader(userId)
  94. .hireDate(now.toLocalDate())
  95. .startDate(now.toLocalDate())
  96. .endDate(AppConstants.FOREVER)
  97. .active(true)
  98. .build();
  99. teamMemberRepository.save(newTeamMember);
  100. userInfoService.updateUserPrice(targetUserInfo);
  101. messageRepository.save(Message.builder()
  102. .userId(target)
  103. .content(String.format(Strings.MSG_HIRED, userInfo.getNickname(), targetUserInfo.getPrice()))
  104. .type(AppConstants.MessageType.NORMAL)
  105. .build());
  106. Message grabMsg = Message.builder()
  107. .userId(userId)
  108. .type(AppConstants.MessageType.NORMAL)
  109. .content(String.format(Strings.MSG_HIRE, price, targetUserInfo.getNickname()))
  110. .active(true)
  111. .isRead(false)
  112. .build();
  113. messageRepository.save(grabMsg);
  114. WalkData walkData = walkDataRepository.findByUserIdAndDate(target, LocalDate.now());
  115. if (walkData != null) {
  116. messageService.sendStepContributeMsg(targetUserInfo, Math.toIntExact(walkData.getSteps()));
  117. }
  118. }
  119. public boolean canHire(Long userId, Long target) {
  120. if (userId.equals(target)) {
  121. return false;
  122. }
  123. TeamMember teamMember = teamMemberRepository.findCurrent(target, LocalDate.now());
  124. if (teamMember != null) {
  125. return !teamMember.getLeader().equals(userId);
  126. }
  127. return true;
  128. }
  129. public List<UserDTO> userTeam(Long userId, boolean queryReward) {
  130. List<UserDTO> list = teamMemberRepository.findUserTeam(userId);
  131. for (UserDTO userDTO : list) {
  132. WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), LocalDate.now());
  133. if (walkData != null) {
  134. userDTO.setTodaySteps(walkData.getSteps());
  135. } else {
  136. userDTO.setTodaySteps(0L);
  137. userDTO.setShouldWake(true);
  138. }
  139. if (queryReward) {
  140. LocalDate now = LocalDate.now();
  141. RewardRecord rewardRecord = new RewardRecord();
  142. rewardRecord.setUserId(userId);
  143. rewardRecord.setTargetUserId(userDTO.getUserId());
  144. rewardRecord.setDate(now);
  145. userDTO.setCanReward(rewardRecordRepository.findAll(Example.of(rewardRecord)).size() == 0);
  146. }
  147. }
  148. return list;
  149. }
  150. public List<UserDTO> userFriend(Long userId) {
  151. LocalDate now = LocalDate.now();
  152. List<UserDTO> list = friendInfoService.findUserFriend(userId);
  153. for (UserDTO userDTO : list) {
  154. WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), now);
  155. if (walkData != null) {
  156. userDTO.setTodaySteps(walkData.getSteps());
  157. } else {
  158. userDTO.setTodaySteps(0L);
  159. }
  160. TeamMember teamMember = teamMemberRepository.findCurrent(userDTO.getUserId(), now);
  161. if (teamMember != null) {
  162. userDTO.setHiredBy(teamMember.getLeader());
  163. userDTO.setHireDate(teamMember.getHireDate());
  164. }
  165. }
  166. return list;
  167. }
  168. public UserDTO userLeader(Long userId) {
  169. UserDTO userDTO = teamMemberRepository.findLeader(userId, LocalDate.now()).stream().findFirst().orElse(null);
  170. if (userDTO == null) {
  171. return null;
  172. }
  173. WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), LocalDate.now());
  174. if (walkData != null) {
  175. userDTO.setTodaySteps(walkData.getSteps());
  176. } else {
  177. userDTO.setTodaySteps(0L);
  178. }
  179. return userDTO;
  180. }
  181. public BufferedImage recruitImg(Long userId) throws IOException, FontFormatException, WxErrorException {
  182. UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在"));
  183. Font pingFangRegular = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/static/PingFangRegular.ttf"));
  184. Font pingFangMedium = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/static/PingFangMedium.ttf"));
  185. Font robot = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/static/Roboto-Black.ttf"));
  186. BufferedImage shareImg = ImageIO.read(this.getClass().getResourceAsStream("/static/share_img.png"));
  187. Graphics2D g = shareImg.createGraphics();
  188. g.setComposite(AlphaComposite.Src);
  189. g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  190. g.setComposite(AlphaComposite.SrcOver);
  191. BufferedImage avatarImg = ImageUtils.makeRoundedCorner(ImageUtils
  192. .scale(ImageIO.read(new URL(userInfo.getAvatar())),
  193. 46 * 3, 46 * 3,
  194. ImageUtils.Fit.COVER), 23 * 3);
  195. g.drawImage(avatarImg, 145 * 3, 177 * 3, null);
  196. BufferedImage levelImg = ImageIO.read(this.getClass().getResourceAsStream("/static/level_" + userInfo.getLevel() + ".png"));
  197. g.drawImage(levelImg, (shareImg.getWidth() - levelImg.getWidth()) / 2, 251 * 3, null);
  198. Font nicknameFont = pingFangRegular.deriveFont(14f * 3);
  199. g.setColor(Color.BLACK);
  200. ImageUtils.drawCenteredString(g, userInfo.getNickname(), new Rectangle(0, 230 * 3, shareImg.getWidth(), 20 * 3), nicknameFont);
  201. Font walkDataFont = pingFangMedium.deriveFont(17f * 3);
  202. ImageUtils.drawCenteredString(g, DAYS.between(userInfo.getCreatedAt().toLocalDate(), LocalDate.now()) + 1 + "", new Rectangle(20 * 3, 295 * 3, 295 * 3 / 2, 24 * 3), walkDataFont);
  203. ImageUtils.drawCenteredString(g, String.valueOf(userInfo.getWalkCities()), new Rectangle(295 * 3 / 2 + 20 * 3, 295 * 3, 295 * 3 / 2, 24 * 3), walkDataFont);
  204. ImageUtils.drawCenteredString(g, String.valueOf(userInfo.getTotalSteps()), new Rectangle(20 * 3, 353 * 3, 295 * 3 / 2, 24 * 3), walkDataFont);
  205. ImageUtils.drawCenteredString(g, coinService.totalAward(userId).toString(), new Rectangle(295 * 3 / 2 + 20 * 3, 353 * 3, 295 * 3 / 2, 24 * 3), walkDataFont);
  206. Font labelFont = pingFangRegular.deriveFont(12f * 3);
  207. g.setColor(new Color(128, 128, 128));
  208. ImageUtils.drawCenteredString(g, "参赛天数", new Rectangle(20 * 3, 321 * 3, 295 * 3 / 2, 24 * 3), labelFont);
  209. ImageUtils.drawCenteredString(g, "途经城市", new Rectangle(295 * 3 / 2 + 20 * 3, 321 * 3, 295 * 3 / 2, 24 * 3), labelFont);
  210. ImageUtils.drawCenteredString(g, "总步数", new Rectangle(20 * 3, 376 * 3, 295 * 3 / 2, 24 * 3), labelFont);
  211. ImageUtils.drawCenteredString(g, "获得奖金", new Rectangle(295 * 3 / 2 + 20 * 3, 376 * 3, 295 * 3 / 2, 24 * 3), labelFont);
  212. String userNum = String.valueOf(userInfoRepository.count() + 100365);
  213. Font numberFont = robot.deriveFont(39f * 3);
  214. g.setColor(new Color(76, 128, 255));
  215. g.setFont(numberFont);
  216. g.drawString(userNum, 20 * 3, 505 * 3);
  217. int numberWidth = g.getFontMetrics(numberFont).stringWidth(userNum);
  218. g.setFont(pingFangRegular.deriveFont(14f * 3));
  219. g.drawString("位", 20 * 3 + numberWidth, 505 * 3);
  220. byte[] bytes = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes("recruit#" + userId, "pages/home/home", 430, false, new WxMaCodeLineColor("0", "0", "0"), false);
  221. ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
  222. BufferedImage codeImg = ImageIO.read(byteArrayInputStream);
  223. // BufferedImage codeImg = ImageIO.read(this.getClass().getResourceAsStream("/static/wxaqrcode.jpg"));
  224. g.setComposite(AlphaComposite.Src);
  225. g.drawImage(codeImg, 235 * 3, 425 * 3, 72 * 3, 72 * 3, null);
  226. // g.drawImage(ImageUtils.scale(codeImg, 72 * 3, 72 * 3, ImageUtils.Fit.COVER), 235 * 3, 425 * 3, null);
  227. return shareImg;
  228. }
  229. public void wake(Long userId, Long target) throws WxErrorException {
  230. UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在"));
  231. UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在"));
  232. String formId = formIdService.get(target);
  233. if (formId == null) {
  234. return;
  235. }
  236. List<WxMaTemplateData> templateData = new ArrayList<>();
  237. templateData.add(new WxMaTemplateData("keyword1", "你的好友" + userInfo.getNickname() + "邀请您继续比赛"));
  238. templateData.add(new WxMaTemplateData("keyword2", "点击进入小程序"));
  239. WxMaTemplateMessage msg = new WxMaTemplateMessage(targetUserInfo.getOpenId(), "dSqxPurf6VpMUwUD0bhF7Hwt4fA5y_Pa441MepRWScE",
  240. "/pages/home/home", formId, templateData, null);
  241. wxMaService.getMsgService().sendTemplateMsg(msg);
  242. }
  243. public void recruit(Long userId, Long target) {
  244. UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在"));
  245. UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在"));
  246. TeamMember teamMember = teamMemberRepository.findCurrent(target, LocalDate.now());
  247. if (teamMember != null) {
  248. return;
  249. }
  250. TeamMember newTeamMember = TeamMember.builder()
  251. .userId(target)
  252. .leader(userId)
  253. .hireDate(LocalDate.now())
  254. .startDate(LocalDate.now())
  255. .endDate(AppConstants.FOREVER)
  256. .active(true)
  257. .build();
  258. teamMemberRepository.save(newTeamMember);
  259. userInfoService.updateUserPrice(targetUserInfo);
  260. messageRepository.save(Message.builder()
  261. .userId(userId)
  262. .content(String.format(Strings.MSG_RECRUIT, targetUserInfo.getNickname()))
  263. .type(AppConstants.MessageType.NORMAL)
  264. .active(true)
  265. .isRead(false)
  266. .build());
  267. }
  268. @Async
  269. public void updateLeaderJourney(Long userId) {
  270. List<UserDTO> leaders = teamMemberRepository.findLeader(userId, LocalDate.now());
  271. for (UserDTO userDTO : leaders) {
  272. journeyService.updateUserJourney(userDTO.getUserId());
  273. }
  274. }
  275. }