ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TOrderEvaluateController.java
@@ -2,6 +2,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.PageInfo; import com.ruoyi.common.log.annotation.Log; @@ -10,6 +12,7 @@ import com.ruoyi.common.security.annotation.Logical; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TOrderEvaluate; import com.ruoyi.order.api.model.TOrderEvaluateTag; import com.ruoyi.order.api.query.TOrderEvaluateQuery; @@ -18,16 +21,21 @@ import com.ruoyi.order.dto.GetOrderEvaluatePageList; import com.ruoyi.order.dto.GetOrderEvaluatePageListDTO; import com.ruoyi.order.dto.OrderEvaluateVo; import com.ruoyi.order.service.TChargingOrderService; import com.ruoyi.order.service.TOrderEvaluateService; import com.ruoyi.order.service.TOrderEvaluateTagService; import com.ruoyi.order.service.WxSubscribeMessageService; import com.ruoyi.order.vo.ReplyEvaluationVO; import com.ruoyi.other.api.vo.TEvaluationTagVO; import io.swagger.annotations.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; /** @@ -43,6 +51,8 @@ @RequestMapping("/t-order-evaluate") public class TOrderEvaluateController { private static final Logger log = LoggerFactory.getLogger(TOrderEvaluateController.class); @Autowired private TOrderEvaluateService orderEvaluateService; @@ -51,6 +61,15 @@ @Resource private TokenService tokenService; @Resource private TChargingOrderService chargingOrderService; @Resource private SiteClient siteClient; @Resource private WxSubscribeMessageService wxSubscribeMessageService; @@ -109,8 +128,26 @@ orderEvaluate.setEvaluationResponse(reply); orderEvaluate.setResponseTime(LocalDateTime.now()); orderEvaluateService.updateById(orderEvaluate); sendEvaluationReplyMessage(orderEvaluate); return AjaxResult.success(); } private void sendEvaluationReplyMessage(TOrderEvaluate orderEvaluate) { try { if (orderEvaluate == null || !Integer.valueOf(1).equals(orderEvaluate.getOrderType())) { return; } TChargingOrder order = chargingOrderService.getById(orderEvaluate.getOrderId()); Site site = null; if (order != null && order.getSiteId() != null) { List<Site> sites = siteClient.getSiteByIds(Collections.singletonList(order.getSiteId())).getData(); site = sites == null || sites.isEmpty() ? null : sites.get(0); } wxSubscribeMessageService.sendEvaluationReply(orderEvaluate, order, site); } catch (Exception e) { log.warn("评价回复订阅消息发送异常,evaluateId={}", orderEvaluate == null ? null : orderEvaluate.getId(), e); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/WxSubscribeMessageService.java
New file @@ -0,0 +1,19 @@ package com.ruoyi.order.service; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TOrderEvaluate; import java.math.BigDecimal; public interface WxSubscribeMessageService { void sendChargeStart(TChargingOrder order, Site site, TChargingGun chargingGun); void sendChargeEnd(TChargingOrder order, Site site, TChargingGun chargingGun); void sendEvaluationReply(TOrderEvaluate orderEvaluate, TChargingOrder order, Site site); void sendPriceDrop(Long appUserId, Site site, BigDecimal price); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -169,6 +169,8 @@ @Resource private SendMessageClient sendMessageClient; @Resource private WxSubscribeMessageService wxSubscribeMessageService; @Resource private TOrderEvaluateService orderEvaluateService; @@ -1256,6 +1258,7 @@ //推送状态给三方平台 tcecClient.pushChargingGunStatus(chargingGun.getFullNumber(), 4); } wxSubscribeMessageService.sendChargeStart(order, site, chargingGun); } redisService.setCacheObject("AQJC_" + order.getChargingGunId(), preChargeCheck1, 24L, TimeUnit.HOURS); @@ -3481,6 +3484,7 @@ if (2 == chargingOrder.getOrderSource() && 1 == site.getIsOpenSynchronization()) { tcecClient.pushChargingGunStatus(chargingGun.getFullNumber(), 2); } wxSubscribeMessageService.sendChargeEnd(chargingOrder, site, chargingGun); //添加积分 if (1 == chargingOrder.getOrderSource()) { ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TOrderEvaluateServiceImpl.java
@@ -36,6 +36,7 @@ import com.ruoyi.order.service.TChargingOrderService; import com.ruoyi.order.service.TEvaluationAutoReplyService; import com.ruoyi.order.service.TOrderEvaluateService; import com.ruoyi.order.service.WxSubscribeMessageService; import com.ruoyi.other.api.domain.TEvaluationTag; import com.ruoyi.other.api.domain.TIntegralRule; import com.ruoyi.other.api.domain.TVip; @@ -45,6 +46,8 @@ import com.ruoyi.system.api.feignClient.SysUserClient; import com.ruoyi.system.api.feignClient.SysUserRoleClient; import com.ruoyi.system.api.model.SysUserRoleVo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -65,6 +68,8 @@ */ @Service public class TOrderEvaluateServiceImpl extends ServiceImpl<TOrderEvaluateMapper, TOrderEvaluate> implements TOrderEvaluateService { private static final Logger log = LoggerFactory.getLogger(TOrderEvaluateServiceImpl.class); @Resource private TEvaluationTagClient evaluationTagClient; @@ -112,6 +117,9 @@ @Resource private TEvaluationAutoReplyService evaluationAutoReplyService; @Resource private WxSubscribeMessageService wxSubscribeMessageService; @@ -409,6 +417,24 @@ orderEvaluate.setEvaluationResponse(rule.getReplyContent()); orderEvaluate.setResponseTime(LocalDateTime.now()); this.updateById(orderEvaluate); sendAutoEvaluationReplyMessage(orderEvaluate); } private void sendAutoEvaluationReplyMessage(TOrderEvaluate orderEvaluate) { try { if (orderEvaluate == null || !Integer.valueOf(1).equals(orderEvaluate.getOrderType())) { return; } TChargingOrder order = chargingOrderService.getById(orderEvaluate.getOrderId()); Site site = null; if (order != null && order.getSiteId() != null) { List<Site> sites = siteClient.getSiteByIds(Collections.singletonList(order.getSiteId())).getData(); site = sites == null || sites.isEmpty() ? null : sites.get(0); } wxSubscribeMessageService.sendEvaluationReply(orderEvaluate, order, site); } catch (Exception e) { log.warn("评价自动回复订阅消息发送异常,evaluateId={}", orderEvaluate == null ? null : orderEvaluate.getId(), e); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WxSubscribeMessageServiceImpl.java
New file @@ -0,0 +1,188 @@ package com.ruoyi.order.service.impl; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.account.api.feignClient.AppUserClient; import com.ruoyi.account.api.model.TAppUser; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.common.core.domain.R; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TOrderEvaluate; import com.ruoyi.order.service.WxSubscribeMessageService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.LinkedHashMap; import java.util.Map; @Service public class WxSubscribeMessageServiceImpl implements WxSubscribeMessageService { private static final Logger log = LoggerFactory.getLogger(WxSubscribeMessageServiceImpl.class); private static final String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={accessToken}"; @Resource private AppUserClient appUserClient; @Resource private RestTemplate restTemplate; @Override public void sendChargeStart(TChargingOrder order, Site site, TChargingGun chargingGun) { if (order == null) { return; } Map<String, String> data = new LinkedHashMap<>(); data.put("thing16", limit(siteName(site), 20)); data.put("thing17", limit(gunCode(chargingGun), 20)); data.put("amount10", amount(order.getRechargeAmount())); data.put("thing21", limit(defaultText(order.getPlateNum(), "未填写"), 20)); send(WxSubscribeTemplate.CHARGE_START, order.getAppUserId(), page(WxSubscribeTemplate.CHARGE_START, order), data); } @Override public void sendChargeEnd(TChargingOrder order, Site site, TChargingGun chargingGun) { if (order == null) { return; } Map<String, String> data = new LinkedHashMap<>(); data.put("thing6", limit(siteName(site), 20)); data.put("character_string15", limit(gunCode(chargingGun), 32)); data.put("amount33", amount(order.getPaymentAmount() == null ? order.getOrderAmount() : order.getPaymentAmount())); data.put("amount18", amount(order.getRefundAmount())); data.put("thing3", limit(endReason(order.getEndMode()), 20)); send(WxSubscribeTemplate.CHARGE_END, order.getAppUserId(), page(WxSubscribeTemplate.CHARGE_END, order), data); } @Override public void sendEvaluationReply(TOrderEvaluate orderEvaluate, TChargingOrder order, Site site) { if (orderEvaluate == null) { return; } Map<String, String> data = new LinkedHashMap<>(); data.put("thing1", limit(siteName(site), 20)); data.put("thing3", limit(defaultText(orderEvaluate.getEvaluationResponse(), "平台已回复您的评价"), 20)); send(WxSubscribeTemplate.SERVICE_EVALUATION, orderEvaluate.getAppUserId(), WxSubscribeTemplate.SERVICE_EVALUATION.getDefaultPage(), data); } @Override public void sendPriceDrop(Long appUserId, Site site, BigDecimal price) { Map<String, String> data = new LinkedHashMap<>(); data.put("thing1", limit(siteName(site), 20)); data.put("amount4", amount(price)); send(WxSubscribeTemplate.PRICE_DROP, appUserId, priceDropPage(site), data); } private void send(WxSubscribeTemplate template, Long appUserId, String page, Map<String, String> data) { try { if (appUserId == null) { return; } R<TAppUser> userResult = appUserClient.getUserById(appUserId); TAppUser appUser = userResult == null ? null : userResult.getData(); if (appUser == null || !StringUtils.hasText(appUser.getWxOpenid())) { log.info("微信订阅消息未发送,用户openid为空,template={}, appUserId={}", template.name(), appUserId); return; } R<String> tokenResult = appUserClient.getWXToken(); String accessToken = tokenResult == null ? null : tokenResult.getData(); if (!StringUtils.hasText(accessToken)) { log.warn("微信订阅消息未发送,access_token为空,template={}, appUserId={}", template.name(), appUserId); return; } JSONObject payload = buildPayload(appUser.getWxOpenid(), template, page, data); JSONObject response = restTemplate.postForObject(SEND_URL, payload, JSONObject.class, accessToken); if (response != null && response.getIntValue("errcode") != 0) { log.warn("微信订阅消息发送失败,template={}, appUserId={}, response={}", template.name(), appUserId, response); } } catch (Exception e) { log.warn("微信订阅消息发送异常,template={}, appUserId={}", template.name(), appUserId, e); } } static JSONObject buildPayload(String openid, WxSubscribeTemplate template, String page, Map<String, String> data) { JSONObject payload = new JSONObject(); payload.put("touser", openid); payload.put("template_id", template.getTemplateId()); if (StringUtils.hasText(page)) { payload.put("page", page); } JSONObject dataJson = new JSONObject(); for (Map.Entry<String, String> entry : data.entrySet()) { JSONObject value = new JSONObject(); value.put("value", entry.getValue()); dataJson.put(entry.getKey(), value); } payload.put("data", dataJson); return payload; } private static String page(WxSubscribeTemplate template, TChargingOrder order) { if (order == null || order.getChargingGunId() == null) { return template.getDefaultPage(); } return template.getDefaultPage() + "?gunId=" + order.getChargingGunId(); } private static String priceDropPage(Site site) { if (site == null || site.getId() == null) { return WxSubscribeTemplate.PRICE_DROP.getDefaultPage(); } return WxSubscribeTemplate.PRICE_DROP.getDefaultPage() + "?id=" + site.getId(); } private static String siteName(Site site) { return site == null ? "充电站" : defaultText(site.getName(), "充电站"); } private static String gunCode(TChargingGun chargingGun) { if (chargingGun == null) { return "充电桩"; } if (StringUtils.hasText(chargingGun.getFullNumber())) { return chargingGun.getFullNumber(); } if (StringUtils.hasText(chargingGun.getCode())) { return chargingGun.getCode(); } return defaultText(chargingGun.getName(), "充电桩"); } private static String amount(BigDecimal value) { return (value == null ? BigDecimal.ZERO : value).setScale(2, RoundingMode.HALF_UP).toPlainString() + "元"; } private static String endReason(Integer endMode) { if (endMode == null) { return "充电结束"; } switch (endMode) { case 0: return "异常终止"; case 1: return "主动终止"; case 2: return "满电终止"; case 3: return "费用不足终止"; default: return "充电结束"; } } private static String defaultText(String value, String defaultValue) { return StringUtils.hasText(value) ? value : defaultValue; } private static String limit(String value, int maxLength) { if (value == null || value.length() <= maxLength) { return value; } return value.substring(0, maxLength); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WxSubscribeTemplate.java
New file @@ -0,0 +1,25 @@ package com.ruoyi.order.service.impl; public enum WxSubscribeTemplate { SERVICE_EVALUATION("LwdykWyQ2P74AR0qk-pLZR6f0oFn0TC03H1eh6Mg2tY", "pagesMine/evaluateRecord/evaluateRecord"), PRICE_DROP("7nCycRUZxQ2jxAb2UaYazjp2sPZy3qYyeLqVytyhHhY", "pagesHome/pileDetail/index"), CHARGE_END("aetqMnzytun-66wQ40bT-7r97hMKu9pgcnvMkRyx5yA", "pagesMap/startCharge/chargeEnd"), CHARGE_START("Zz42EOeBt_hlCt50T7bRzlLtpGrZvt1idULi7m9PW_8", "pagesMap/startCharge/startCharge"); private final String templateId; private final String defaultPage; WxSubscribeTemplate(String templateId, String defaultPage) { this.templateId = templateId; this.defaultPage = defaultPage; } public String getTemplateId() { return templateId; } public String getDefaultPage() { return defaultPage; } }