package com.ruoyi.account.task; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.account.api.model.TAppUser; import com.ruoyi.account.api.model.TAppUserSiteFavorite; import com.ruoyi.account.service.TAppUserService; import com.ruoyi.account.service.TAppUserSiteFavoriteService; import com.ruoyi.account.wx.model.WeixinProperties; import com.ruoyi.account.wx.tools.WxAppletTools; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.vo.FavoriteSitePriceVO; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.HttpUtils; import com.ruoyi.common.redis.service.RedisService; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @Slf4j @Component public class FavoritePriceDropTask { private static final String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="; @Resource private TAppUserSiteFavoriteService favoriteService; @Resource private TAppUserService appUserService; @Resource private SiteClient siteClient; @Resource private RestTemplate wxRestTemplate; @Resource private WeixinProperties wxConfig; @Resource private RedisService redisService; @Resource private RedissonClient redissonClient; @Value("${wx.applet.price-drop-template-id:7nCycRUZxQ2jxAb2UaYazjp2sPZy3qYyeLqVytyhHhY}") private String templateId; @Value("${wx.applet.price-drop-page:pagesMine/favoriteSite/favoriteSite}") private String page; // 降价推送已改为计费策略审批通过时触发(TAccountingStrategyController.authPass → TAppUserSiteFavoriteClient),此轮询任务暂停(如需回退恢复 @Scheduled 即可) // @Scheduled(fixedDelay = 30 * 60 * 1000L, initialDelay = 2 * 60 * 1000L) public void notifyPriceDrop() { if (!StringUtils.hasText(templateId)) { return; } RLock lock = redissonClient.getLock("FAVORITE_SITE_PRICE_DROP_TASK"); boolean locked = false; try { locked = lock.tryLock(0, 10, TimeUnit.MINUTES); if (!locked) { return; } List favorites = favoriteService.lambdaQuery() .eq(TAppUserSiteFavorite::getNotifyEnabled, true) .list(); if (favorites.isEmpty()) { return; } List siteIds = favorites.stream().map(TAppUserSiteFavorite::getSiteId) .filter(Objects::nonNull).distinct().collect(Collectors.toList()); R> response = siteClient.getFavoriteSitePrices(siteIds); List prices = response == null || response.getData() == null ? Collections.emptyList() : response.getData(); Map priceMap = prices.stream() .collect(Collectors.toMap(FavoriteSitePriceVO::getSiteId, Function.identity(), (a, b) -> a)); for (TAppUserSiteFavorite favorite : favorites) { FavoriteSitePriceVO price = priceMap.get(favorite.getSiteId()); if (price == null || price.getCurrentPrice() == null || favorite.getFavoritePrice() == null || price.getCurrentPrice().compareTo(favorite.getFavoritePrice()) >= 0) { continue; } TAppUser user = appUserService.getById(favorite.getAppUserId()); if (user == null || !StringUtils.hasText(user.getWxOpenid())) { log.info("收藏站点降价提醒未发送,用户openid为空,userId={}, siteId={}", favorite.getAppUserId(), favorite.getSiteId()); continue; } if (sendSubscribeMessage(user.getWxOpenid(), favorite, price)) { favorite.setNotifyEnabled(false); favorite.setLastNotifiedPrice(price.getCurrentPrice()); favoriteService.updateById(favorite); log.info("收藏站点降价提醒发送成功,userId={}, siteId={}, currentPrice={}", favorite.getAppUserId(), favorite.getSiteId(), price.getCurrentPrice()); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { log.error("收藏站点降价提醒任务执行失败", e); } finally { if (locked && lock.isHeldByCurrentThread()) { lock.unlock(); } } } private boolean sendSubscribeMessage(String openId, TAppUserSiteFavorite favorite, FavoriteSitePriceVO price) { JSONObject body = new JSONObject(); body.put("touser", openId); body.put("template_id", templateId); body.put("page", page + "?siteId=" + favorite.getSiteId()); JSONObject data = new JSONObject(); data.put("thing1", value(limit(price.getSiteName(), 20))); data.put("amount4", value(formatAmount(price.getCurrentPrice()))); body.put("data", data); String accessToken = new WxAppletTools(wxRestTemplate, wxConfig, redisService).getAccessToken(""); String result = HttpUtils.post(SEND_URL + accessToken, body.toJSONString()); JSONObject response = JSON.parseObject(result); boolean success = response != null && response.getIntValue("errcode") == 0; if (!success) { log.warn("发送收藏站点降价提醒失败,userId={}, siteId={}, response={}", favorite.getAppUserId(), favorite.getSiteId(), result); } return success; } private JSONObject value(String value) { JSONObject item = new JSONObject(); item.put("value", value); return item; } private String formatAmount(BigDecimal amount) { return amount.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "元"; } private String limit(String value, int length) { if (!StringUtils.hasText(value) || value.length() <= length) { return value; } return value.substring(0, length); } }