TeamService.java 12 KB

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