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 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 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 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 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 data) { try { if (appUserId == null) { return; } R 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 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 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 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); } }