longz
2026-07-09 a62cffd2d300bff5885e983c4fc68d555c1e4157
微信订阅消息推送
3个文件已添加
3个文件已修改
299 ■■■■■ 已修改文件
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TOrderEvaluateController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/WxSubscribeMessageService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TOrderEvaluateServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WxSubscribeMessageServiceImpl.java 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WxSubscribeTemplate.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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;
    }
}