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.apache.commons.lang3.time.DateUtils; import org.joda.time.Days; import org.joda.time.LocalDate; 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.File; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Optional; @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; public void hire(Long userId, Long target) { Date now = new Date(); UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在")); UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在")); TeamMember teamMember = teamMemberRepository.findCurrent(target, now); if (teamMember != null) { if (teamMember.getLeader().equals(userId)) { throw new ServiceException("Ta已经是你的队员"); } if (teamMember.getStartDate().after(now)) { throw new ServiceException(Strings.GRAB_FAIL); } teamMember.setEndDate(now); 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 = BigDecimal.valueOf(Optional.ofNullable(targetUserInfo.getTotalSteps()).orElse(0L)) .multiply(BigDecimal.valueOf(AppConstants.HIRE_PRICE_RATE)) .setScale(1, RoundingMode.FLOOR); 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) .startDate(DateUtils.addDays(now, 1)) .endDate(AppConstants.FOREVER) .active(true) .build(); teamMemberRepository.save(newTeamMember); } public boolean canHire(Long userId, Long target) { if (userId.equals(target)) { return false; } Date now = new Date(); TeamMember teamMember = teamMemberRepository.findCurrent(target, now); if (teamMember != null) { return !teamMember.getLeader().equals(userId); } return true; } public List userTeam(Long userId) { List list = teamMemberRepository.findUserTeam(userId); Date now = new Date(); for (UserDTO userDTO : list) { WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), now); if (walkData != null) { userDTO.setTodaySteps(walkData.getSteps()); } else { userDTO.setTodaySteps(0L); userDTO.setShouldWake(true); } } return list; } public List userFriend(Long userId) { Date now = new Date(); List list = friendInfoRepository.findUserFriend(userId, now); 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.findByLeaderAndUserId(userId, userDTO.getUserId(), now); userDTO.setHired(teamMember != null); } return list; } public UserDTO userLeader(Long userId) { UserDTO userDTO = teamMemberRepository.findLeader(userId, new Date()); if (userDTO == null) { return null; } WalkData walkData = walkDataRepository.findByUserIdAndDate(userDTO.getUserId(), new Date()); 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, new File(ClassLoader.getSystemResource("static/PingFangRegular.ttf").getFile())); Font pingFangMedium = Font.createFont(Font.TRUETYPE_FONT, new File(ClassLoader.getSystemResource("static/PingFangMedium.ttf").getFile())); Font robot = Font.createFont(Font.TRUETYPE_FONT, new File(ClassLoader.getSystemResource("static/Roboto-Black.ttf").getFile())); BufferedImage shareImg = ImageIO.read(ClassLoader.getSystemResource("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(ClassLoader.getSystemResource("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.daysBetween(LocalDate.fromDateFields(userInfo.getCreatedAt()), LocalDate.fromDateFields(new Date())).getDays() + "", 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()); 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(ClassLoader.getSystemResource("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("keyword1", "点击进入小程序")); WxMaTemplateMessage msg = new WxMaTemplateMessage(targetUserInfo.getOpenId(), "dSqxPurf6VpMUwUD0bhF7Hwt4fA5y_Pa441MepRWScE", null, formId, templateData, null); wxMaService.getMsgService().sendTemplateMsg(msg); } public void recruit(Long userId, Long target) { Date now = new Date(); UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在")); UserInfo targetUserInfo = userInfoRepository.findById(target).orElseThrow(new ServiceException("用户不存在")); TeamMember teamMember = teamMemberRepository.findCurrent(target, now); if (teamMember != null) { return; } BigDecimal price = BigDecimal.valueOf(Optional.ofNullable(targetUserInfo.getTotalSteps()).orElse(0L)) .multiply(BigDecimal.valueOf(AppConstants.HIRE_PRICE_RATE)) .setScale(1, RoundingMode.FLOOR); if (price.compareTo(BigDecimal.ZERO) > 0) { return; } TeamMember newTeamMember = TeamMember.builder() .userId(target) .leader(userId) .hireDate(now) .startDate(DateUtils.addDays(now, 1)) .endDate(AppConstants.FOREVER) .active(true) .build(); teamMemberRepository.save(newTeamMember); } }