package com.izouma.walkchina.service; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import com.izouma.walkchina.constant.AppConstants; import com.izouma.walkchina.constant.Strings; import com.izouma.walkchina.domain.Message; import com.izouma.walkchina.domain.TeamMember; import com.izouma.walkchina.domain.UserInfo; import com.izouma.walkchina.domain.WalkData; import com.izouma.walkchina.dto.UserDTO; import com.izouma.walkchina.exception.ServiceException; import com.izouma.walkchina.repo.*; import com.izouma.walkchina.utils.ImageUtils; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.math.BigDecimal; import java.net.URL; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; import static java.time.temporal.ChronoUnit.DAYS; @Service @Slf4j public class TeamService { @Autowired private TeamMemberRepository teamMemberRepository; @Autowired private UserInfoRepository userInfoRepository; @Autowired private MessageRepository messageRepository; @Autowired private WalkDataRepository walkDataRepository; @Autowired private FriendInfoRepository friendInfoRepository; @Autowired private CoinService coinService; @Autowired private WxMaService wxMaService; @Autowired private FormIdService formIdService; @Autowired private UserInfoService userInfoService; public void hire(Long userId, Long target) { LocalDateTime now = LocalDateTime.now(); UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在")); UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在")); TeamMember teamMember = teamMemberRepository.findCurrent(target, now.toLocalDate()); if (teamMember != null) { if (teamMember.getLeader().equals(userId)) { throw new ServiceException("Ta已经是你的队员"); } if (teamMember.getStartDate().atTime(0, 0).isAfter(now)) { throw new ServiceException(Strings.GRAB_FAIL); } teamMember.setEndDate(now.toLocalDate()); teamMember.setGrabbed(true); teamMemberRepository.save(teamMember); Message grabMsg = Message.builder() .userId(teamMember.getLeader()) .type(AppConstants.MessageType.NORMAL) .content(String.format(Strings.MSG_MEMBER_GRABBED, targetUserInfo.getNickname(), userInfo.getNickname())) .active(true) .isRead(false) .build(); messageRepository.save(grabMsg); } BigDecimal price = Optional.ofNullable(userInfo.getPrice()).orElse(AppConstants.MIN_PRICE); BigDecimal balance = Optional.ofNullable(userInfo.getCoin()).orElse(BigDecimal.ZERO); if (balance.compareTo(price) < 0) { throw new ServiceException("雇佣失败,商城币不足"); } coinService.balanceChange(userInfo, price.negate(), AppConstants.CoinRecordType.HIRE, Strings.REMARK_HIRE, null); coinService.balanceChange(targetUserInfo, price, AppConstants.CoinRecordType.BE_HIRED, Strings.REMARK_BE_HIRED, String.format(Strings.MSG_HIRED, userInfo.getNickname(), price)); TeamMember newTeamMember = TeamMember.builder() .userId(target) .leader(userId) .hireDate(now.toLocalDate()) .startDate(now.toLocalDate()) .endDate(AppConstants.FOREVER) .active(true) .build(); teamMemberRepository.save(newTeamMember); userInfoService.updateUserPrice(targetUserInfo); } public boolean canHire(Long userId, Long target) { if (userId.equals(target)) { return false; } TeamMember teamMember = teamMemberRepository.findCurrent(target, LocalDate.now()); if (teamMember != null) { return !teamMember.getLeader().equals(userId); } return true; } public List userTeam(Long userId) { List list = teamMemberRepository.findUserTeam(userId); for (UserDTO userDTO : list) { WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), LocalDate.now()); if (walkData != null) { userDTO.setTodaySteps(walkData.getSteps()); } else { userDTO.setTodaySteps(0L); userDTO.setShouldWake(true); } } return list; } public List userFriend(Long userId) { LocalDate now = LocalDate.now(); List list = friendInfoRepository.findUserFriend(userId); for (UserDTO userDTO : list) { WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), now); if (walkData != null) { userDTO.setTodaySteps(walkData.getSteps()); } else { userDTO.setTodaySteps(0L); } TeamMember teamMember = teamMemberRepository.findCurrent(userDTO.getUserId(), now); if (teamMember != null) { userDTO.setHiredBy(teamMember.getLeader()); userDTO.setHireDate(teamMember.getHireDate()); } } return list; } public UserDTO userLeader(Long userId) { UserDTO userDTO = teamMemberRepository.findLeader(userId, LocalDate.now()); if (userDTO == null) { return null; } WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), LocalDate.now()); if (walkData != null) { userDTO.setTodaySteps(walkData.getSteps()); } else { userDTO.setTodaySteps(0L); } return userDTO; } public BufferedImage recruitImg(Long userId) throws IOException, FontFormatException, WxErrorException { UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在")); Font pingFangRegular = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/static/PingFangRegular.ttf")); Font pingFangMedium = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/static/PingFangMedium.ttf")); Font robot = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/static/Roboto-Black.ttf")); BufferedImage shareImg = ImageIO.read(this.getClass().getResourceAsStream("/static/share_img.png")); Graphics2D g = shareImg.createGraphics(); g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setComposite(AlphaComposite.SrcOver); BufferedImage avatarImg = ImageUtils.makeRoundedCorner(ImageUtils .scale(ImageIO.read(new URL(userInfo.getAvatar())), 46 * 3, 46 * 3, ImageUtils.Fit.COVER), 23 * 3); g.drawImage(avatarImg, 145 * 3, 177 * 3, null); BufferedImage levelImg = ImageIO.read(this.getClass().getResourceAsStream("/static/level_" + userInfo.getLevel() + ".png")); g.drawImage(levelImg, (shareImg.getWidth() - levelImg.getWidth()) / 2, 251 * 3, null); Font nicknameFont = pingFangRegular.deriveFont(14f * 3); g.setColor(Color.BLACK); ImageUtils.drawCenteredString(g, userInfo.getNickname(), new Rectangle(0, 230 * 3, shareImg.getWidth(), 20 * 3), nicknameFont); Font walkDataFont = pingFangMedium.deriveFont(17f * 3); ImageUtils.drawCenteredString(g, DAYS.between(userInfo.getCreatedAt(), LocalDateTime.now()) + 1 + "", new Rectangle(20 * 3, 295 * 3, 295 * 3 / 2, 24 * 3), walkDataFont); ImageUtils.drawCenteredString(g, String.valueOf(userInfo.getWalkCities()), new Rectangle(295 * 3 / 2 + 20 * 3, 295 * 3, 295 * 3 / 2, 24 * 3), walkDataFont); ImageUtils.drawCenteredString(g, String.valueOf(userInfo.getTotalSteps()), new Rectangle(20 * 3, 353 * 3, 295 * 3 / 2, 24 * 3), walkDataFont); ImageUtils.drawCenteredString(g, coinService.totalAward(userId).toString(), new Rectangle(295 * 3 / 2 + 20 * 3, 353 * 3, 295 * 3 / 2, 24 * 3), walkDataFont); Font labelFont = pingFangRegular.deriveFont(12f * 3); g.setColor(new Color(128, 128, 128)); ImageUtils.drawCenteredString(g, "参赛天数", new Rectangle(20 * 3, 321 * 3, 295 * 3 / 2, 24 * 3), labelFont); ImageUtils.drawCenteredString(g, "途经城市", new Rectangle(295 * 3 / 2 + 20 * 3, 321 * 3, 295 * 3 / 2, 24 * 3), labelFont); ImageUtils.drawCenteredString(g, "总步数", new Rectangle(20 * 3, 376 * 3, 295 * 3 / 2, 24 * 3), labelFont); ImageUtils.drawCenteredString(g, "获得奖金", new Rectangle(295 * 3 / 2 + 20 * 3, 376 * 3, 295 * 3 / 2, 24 * 3), labelFont); String userNum = String.valueOf(userInfoRepository.count() + 10000); Font numberFont = robot.deriveFont(39f * 3); g.setColor(new Color(76, 128, 255)); g.setFont(numberFont); g.drawString(userNum, 20 * 3, 505 * 3); int numberWidth = g.getFontMetrics(numberFont).stringWidth(userNum); g.setFont(pingFangRegular.deriveFont(14f * 3)); g.drawString("位", 20 * 3 + numberWidth, 505 * 3); // byte[] bytes = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes("recruit", "pages/home/home?from=" + userId, 72 * 3, true, new WxMaCodeLineColor("0", "0", "0"), true); // ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); // BufferedImage codeImg = ImageIO.read(byteArrayInputStream); BufferedImage codeImg = ImageIO.read(this.getClass().getResourceAsStream("/static/wxaqrcode.jpg")); g.drawImage(ImageUtils.scale(codeImg, 72 * 3, 72 * 3, ImageUtils.Fit.COVER), 235 * 3, 425 * 3, null); return shareImg; } public void wake(Long userId, Long target) throws WxErrorException { UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在")); UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在")); String formId = formIdService.get(target); if (formId == null) { return; } List templateData = new ArrayList<>(); templateData.add(new WxMaTemplateData("keyword1", "你的好友" + userInfo.getNickname() + "邀请您继续比赛")); templateData.add(new WxMaTemplateData("keyword2", "点击进入小程序")); WxMaTemplateMessage msg = new WxMaTemplateMessage(targetUserInfo.getOpenId(), "dSqxPurf6VpMUwUD0bhF7Hwt4fA5y_Pa441MepRWScE", "/pages/home/home", formId, templateData, null); wxMaService.getMsgService().sendTemplateMsg(msg); } public void recruit(Long userId, Long target) { UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在")); UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在")); TeamMember teamMember = teamMemberRepository.findCurrent(target, LocalDate.now()); if (teamMember != null) { return; } TeamMember newTeamMember = TeamMember.builder() .userId(target) .leader(userId) .hireDate(LocalDate.now()) .startDate(LocalDate.now()) .endDate(AppConstants.FOREVER) .active(true) .build(); teamMemberRepository.save(newTeamMember); userInfoService.updateUserPrice(targetUserInfo); } }