puzhibing
2026-09-09 4a5e1477afc559cf870b34e4693f41d85e9580d1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.ruoyi.account.service.impl;
 
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.model.TAppUser;
import com.ruoyi.account.api.model.TAppUserSiteFavorite;
import com.ruoyi.account.api.vo.SitePriceDropNotifyVO;
import com.ruoyi.account.mapper.TAppUserSiteFavoriteMapper;
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.common.core.utils.HttpUtils;
import com.ruoyi.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
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.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
 
@Slf4j
@Service
public class TAppUserSiteFavoriteServiceImpl
        extends ServiceImpl<TAppUserSiteFavoriteMapper, TAppUserSiteFavorite>
        implements TAppUserSiteFavoriteService {
 
    private static final String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
 
    @Resource
    private TAppUserService appUserService;
    @Resource
    private RestTemplate wxRestTemplate;
    @Resource
    private WeixinProperties wxConfig;
    @Resource
    private RedisService redisService;
 
    @Value("${wx.applet.price-drop-template-id:7nCycRUZxQ2jxAb2UaYazjp2sPZy3qYyeLqVytyhHhY}")
    private String templateId;
 
    @Value("${wx.applet.price-drop-page:pagesMine/favoriteSite/favoriteSite}")
    private String page;
 
    @Override
    public void saveOrRestore(Long appUserId, Integer siteId, BigDecimal favoritePrice, Boolean notifyEnabled) {
        baseMapper.upsert(appUserId, siteId, favoritePrice, Boolean.TRUE.equals(notifyEnabled));
    }
 
    @Override
    public void notifyPriceDrop(List<SitePriceDropNotifyVO> drops) {
        if (drops == null || drops.isEmpty() || !StringUtils.hasText(templateId)) {
            return;
        }
        List<Integer> siteIds = drops.stream().map(SitePriceDropNotifyVO::getSiteId)
                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (siteIds.isEmpty()) {
            return;
        }
        Map<Integer, SitePriceDropNotifyVO> priceMap = drops.stream()
                .collect(Collectors.toMap(SitePriceDropNotifyVO::getSiteId, Function.identity(), (a, b) -> a));
        List<TAppUserSiteFavorite> favorites = lambdaQuery()
                .eq(TAppUserSiteFavorite::getNotifyEnabled, true)
                .in(TAppUserSiteFavorite::getSiteId, siteIds)
                .list();
        for (TAppUserSiteFavorite favorite : favorites) {
            SitePriceDropNotifyVO drop = priceMap.get(favorite.getSiteId());
            if (drop == null || drop.getPrice() == null) {
                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, drop)) {
                favorite.setNotifyEnabled(false);
                favorite.setLastNotifiedPrice(drop.getPrice());
                updateById(favorite);
                log.info("收藏站点降价提醒发送成功,userId={}, siteId={}, price={}",
                        favorite.getAppUserId(), favorite.getSiteId(), drop.getPrice());
            }
        }
    }
 
    private boolean sendSubscribeMessage(String openId, TAppUserSiteFavorite favorite, SitePriceDropNotifyVO drop) {
        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(drop.getSiteName(), 20)));
        data.put("amount4", value(formatAmount(drop.getPrice())));
        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);
    }
}