diff --git a/cash-api/account-server/src/main/java/com/czg/controller/admin/ShopMsgPushController.java b/cash-api/account-server/src/main/java/com/czg/controller/admin/ShopMsgPushController.java index 873e34d3..6a4afdb0 100644 --- a/cash-api/account-server/src/main/java/com/czg/controller/admin/ShopMsgPushController.java +++ b/cash-api/account-server/src/main/java/com/czg/controller/admin/ShopMsgPushController.java @@ -1,5 +1,6 @@ package com.czg.controller.admin; +import com.czg.account.dto.WxMsgSubDTO; import com.czg.account.dto.msg.ShopMsgEditDTO; import com.czg.account.dto.msg.ShopPushOpenIdEditDTO; import com.czg.account.entity.ShopPushOpenId; @@ -14,6 +15,7 @@ import com.czg.validator.group.DefaultGroup; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -22,6 +24,7 @@ import org.springframework.web.bind.annotation.*; * * @author Administrator */ +@Slf4j @RestController @RequestMapping("/admin/shopMsgPush") public class ShopMsgPushController { @@ -30,6 +33,32 @@ public class ShopMsgPushController { @Resource private ShopPushOpenIdService shopPushOpenIdService; + + /** + * 店铺推送状态获取 + */ + @PostMapping("/subscribe") + public CzgResult subscribe(@RequestBody WxMsgSubDTO wxMsgSubDTO) { + log.info("接收到订阅消息接口调用,携带数据: {}", wxMsgSubDTO); + if (wxMsgSubDTO.getOpenId() == null || wxMsgSubDTO.getShopId() == null) { + return CzgResult.failure("shopId或openId缺失"); + } + ShopPushOpenId entity = shopPushOpenIdService.getOne(QueryWrapper.create().eq(ShopPushOpenId::getOpenId, wxMsgSubDTO.getOpenId()).eq(ShopPushOpenId::getShopId, wxMsgSubDTO.getShopId())); + if (entity == null) { + entity = new ShopPushOpenId(); + } + entity.setShopId(wxMsgSubDTO.getShopId()); + entity.setOpenId(wxMsgSubDTO.getOpenId()); + entity.setNickname(wxMsgSubDTO.getNickname()); + entity.setAvatar(wxMsgSubDTO.getAvatar()); + if (entity.getId() == null) { + shopPushOpenIdService.save(entity); + } else { + shopPushOpenIdService.updateById(entity); + } + return CzgResult.success(); + } + /** * 店铺推送状态获取 */ diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/HandoverRecordDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/HandoverRecordDTO.java index 29c6b2f6..0c08a6fc 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/HandoverRecordDTO.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/HandoverRecordDTO.java @@ -1,8 +1,5 @@ package com.czg.account.dto; -import cn.hutool.core.convert.Convert; -import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.annotation.JSONField; import com.czg.account.vo.HandoverCategoryListVo; import com.czg.account.vo.HandoverProductListVo; diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/WxMsgSubDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/WxMsgSubDTO.java new file mode 100644 index 00000000..0e4529e8 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/WxMsgSubDTO.java @@ -0,0 +1,23 @@ +package com.czg.account.dto; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 微信订阅消息 + * + * @author Tankaikai tankaikai@aliyun.com + * @since 1.0 2025-02-27 + */ +@Data +public class WxMsgSubDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + private Long shopId; + private String openId; + private String nickname; + private String avatar; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopPushOpenId.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopPushOpenId.java index 46df7a85..8968dead 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopPushOpenId.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopPushOpenId.java @@ -7,6 +7,7 @@ import com.mybatisflex.annotation.Table; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; + import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; @@ -29,7 +30,7 @@ public class ShopPushOpenId implements Serializable { @Id(keyType = KeyType.Auto) private Integer id; - private Integer shopId; + private Long shopId; /** * 微信openid diff --git a/cash-common/cash-common-service/src/main/java/com/czg/product/service/ConsStockFlowService.java b/cash-common/cash-common-service/src/main/java/com/czg/product/service/ConsStockFlowService.java index 97725fb1..dcbc6101 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/product/service/ConsStockFlowService.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/product/service/ConsStockFlowService.java @@ -70,4 +70,10 @@ public interface ConsStockFlowService extends IService { * @return 分页数据 */ Page findConsStockFlowPage(ConsStockFlowParam param); + + /** + * 保存库存变动记录 + * @param entity 库存变动记录实体 + */ + void saveFlow(ConsStockFlow entity); } \ No newline at end of file diff --git a/cash-common/cash-common-service/src/main/java/com/czg/product/service/ProductStockFlowService.java b/cash-common/cash-common-service/src/main/java/com/czg/product/service/ProductStockFlowService.java new file mode 100644 index 00000000..46c6b77d --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/product/service/ProductStockFlowService.java @@ -0,0 +1,16 @@ +package com.czg.product.service; + +import com.czg.product.entity.ProductStockFlow; +import com.mybatisflex.core.service.IService; + +/** + * + + * 商品库存流水服务类 + * + * @author tankaikai + * @since 2025-03-14 15:44 + */ +public interface ProductStockFlowService extends IService { + + void saveFlow(ProductStockFlow entity); +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/product/service/SensitiveOperationService.java b/cash-common/cash-common-service/src/main/java/com/czg/product/service/SensitiveOperationService.java new file mode 100644 index 00000000..352bac4a --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/product/service/SensitiveOperationService.java @@ -0,0 +1,13 @@ +package com.czg.product.service; + +/** + * 敏感操作Service + * + * @author Tankaikai tankaikai@aliyun.com + * @since 1.0 2025-02-16 + */ +public interface SensitiveOperationService { + + void send(String operationDesc); + +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopMsgStateServiceImpl.java b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopMsgStateServiceImpl.java index 183a83fb..feff55f9 100644 --- a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopMsgStateServiceImpl.java +++ b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopMsgStateServiceImpl.java @@ -18,6 +18,7 @@ import com.czg.service.account.util.AliOssUtil; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.mybatisflex.spring.service.impl.ServiceImpl; import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; @@ -50,6 +51,8 @@ public class ShopMsgStateServiceImpl extends ServiceImpl { - + List findOpenIdList(@Param("shopId") Long shopId, @Param("type") String type); } \ No newline at end of file diff --git a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java index f8a1676f..0eb6bcf1 100644 --- a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java +++ b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java @@ -2,6 +2,8 @@ package com.czg.service.product.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; @@ -21,10 +23,12 @@ import com.czg.product.vo.ConsCheckStockRecordVo; import com.czg.sa.StpKit; import com.czg.service.product.mapper.ConsInfoMapper; import com.czg.service.product.mapper.ConsStockFlowMapper; +import com.czg.service.product.util.WxAccountUtil; import com.czg.utils.PageUtil; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.spring.service.impl.ServiceImpl; +import jakarta.annotation.Resource; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -44,6 +48,8 @@ import java.util.List; public class ConsStockFlowServiceImpl extends ServiceImpl implements ConsStockFlowService { private final ConsInfoMapper consInfoMapper; + @Resource + private WxAccountUtil wxAccountUtil; private QueryWrapper buildQueryWrapper(ConsStockFlowDTO param) { QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper(); @@ -155,7 +161,7 @@ public class ConsStockFlowServiceImpl extends ServiceImpl openIdList = consInfoMapper.findOpenIdList(shopId, "con"); + if (CollUtil.isEmpty(openIdList)) { + return; + } + String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning); + ThreadUtil.execAsync(() -> { + openIdList.parallelStream().forEach(openId -> { + wxAccountUtil.sendStockMsg(shopName, conName, afterNumber, openId); + }); + }); + } + } + } \ No newline at end of file diff --git a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProdGroupServiceImpl.java b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProdGroupServiceImpl.java index 9add1dfd..862e2335 100644 --- a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProdGroupServiceImpl.java +++ b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProdGroupServiceImpl.java @@ -13,6 +13,7 @@ import com.czg.product.entity.ProdGroup; import com.czg.product.entity.ProdGroupRelation; import com.czg.product.entity.Product; import com.czg.product.service.ProdGroupService; +import com.czg.product.service.SensitiveOperationService; import com.czg.sa.StpKit; import com.czg.service.product.mapper.ProdGroupMapper; import com.czg.service.product.mapper.ProdGroupRelationMapper; @@ -41,8 +42,8 @@ import java.util.List; public class ProdGroupServiceImpl extends ServiceImpl implements ProdGroupService { private final ProdGroupRelationMapper prodGroupRelationMapper; - private final ProductMapper productMapper; + private final SensitiveOperationService sensitiveOperationService; private QueryWrapper buildQueryWrapper(ProdGroupDTO param) { QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper(); @@ -152,6 +153,8 @@ public class ProdGroupServiceImpl extends ServiceImpl impl private final ConsInfoMapper consInfoMapper; private final ConsStockFlowMapper consStockFlowMapper; private final ProductStockFlowMapper productStockFlowMapper; + private final ProductStockFlowService productStockFlowService; + private final ConsStockFlowService consStockFlowService; + private final SensitiveOperationService sensitiveOperationService; private QueryWrapper buildQueryWrapper(ProductDTO param) { QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper(); @@ -222,7 +228,7 @@ public class ProductServiceImpl extends ServiceImpl impl flow.setAfterNumber(NumberUtil.toBigDecimal(entity.getStockNumber())); flow.setInOutType(InOutTypeEnum.IN.value()); flow.setInOutItem(InOutItemEnum.WIN_IN.value()); - productStockFlowMapper.insert(flow); + productStockFlowService.saveFlow(flow); } @Override @@ -310,7 +316,7 @@ public class ProductServiceImpl extends ServiceImpl impl return; } flow.setAfterNumber(NumberUtil.toBigDecimal(entity.getStockNumber())); - productStockFlowMapper.insert(flow); + productStockFlowService.saveFlow(flow); } @Override @@ -331,6 +337,12 @@ public class ProductServiceImpl extends ServiceImpl impl String type = param.getType(); Long id = param.getId(); Integer isSale = param.getIsSale(); + String sensitiveOperation = ""; + if (isSale == 1) { + sensitiveOperation = "上架"; + } else { + sensitiveOperation = "下架"; + } if (ProductIsSaleTypeEnum.SKU.value().equals(type)) { ProdSku prodSku = prodSkuMapper.selectOneById(id); if (prodSku == null) { @@ -346,6 +358,9 @@ public class ProductServiceImpl extends ServiceImpl impl .eq(Product::getShopId, shopId) .update(); } + Long productId = prodSku.getProductId(); + Product product = mapper.selectOneById(productId); + sensitiveOperation = sensitiveOperation + "商品:" + product.getName() + " 规格:" + prodSku.getSpecInfo(); } else if (ProductIsSaleTypeEnum.PRODUCT.value().equals(type)) { UpdateChain.of(Product.class) .set(Product::getIsSale, isSale) @@ -357,10 +372,10 @@ public class ProductServiceImpl extends ServiceImpl impl .eq(ProdSku::getProductId, id) .eq(ProdSku::getShopId, shopId) .update(); + Product product = mapper.selectOneById(id); + sensitiveOperation = sensitiveOperation + "商品:" + product.getName(); } - - prodSkuMapper.selectOneById(id); - + sensitiveOperationService.send(sensitiveOperation); } @Override @@ -438,7 +453,7 @@ public class ProductServiceImpl extends ServiceImpl impl flow.setInOutType(InOutTypeEnum.OUT.value()); flow.setInOutItem(InOutItemEnum.DAMAGE_OUT.value()); flow.setImgUrls(JSON.toJSONString(param.getImgUrls())); - productStockFlowMapper.insert(flow); + productStockFlowService.saveFlow(flow); // 如果绑定了耗材,则同步更新耗材库存 List consList = prodConsRelationMapper.selectListByProdId(param.getProductId()); if (CollUtil.isEmpty(consList)) { @@ -465,6 +480,7 @@ public class ProductServiceImpl extends ServiceImpl impl entity.setImgUrls(JSON.toJSONString(param.getImgUrls())); entity.setRemark("【商品报损,自动报损相关耗材】" + StrUtil.nullToDefault(param.getRemark(), "")); consStockFlowMapper.insert(entity); + consStockFlowService.saveFlow(entity); consInfo.setStockNumber(entity.getAfterNumber()); UpdateChain.of(ConsInfo.class) .set(ConsInfo::getStockNumber, consInfo.getStockNumber()) diff --git a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProductStockFlowServiceImpl.java b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProductStockFlowServiceImpl.java new file mode 100644 index 00000000..3a3f0597 --- /dev/null +++ b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ProductStockFlowServiceImpl.java @@ -0,0 +1,61 @@ +package com.czg.service.product.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import com.czg.product.entity.Product; +import com.czg.product.entity.ProductStockFlow; +import com.czg.product.service.ProductStockFlowService; +import com.czg.sa.StpKit; +import com.czg.service.product.mapper.ConsInfoMapper; +import com.czg.service.product.mapper.ProductMapper; +import com.czg.service.product.mapper.ProductStockFlowMapper; +import com.czg.service.product.util.WxAccountUtil; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 商品库存流水服务实现类 + * + * @author tankaikai + * @since 2025-03-14 15:45 + */ +@Service +public class ProductStockFlowServiceImpl extends ServiceImpl implements ProductStockFlowService { + + @Resource + private ProductMapper productMapper; + @Resource + private ConsInfoMapper consInfoMapper; + @Resource + private WxAccountUtil wxAccountUtil; + + @Override + public void saveFlow(ProductStockFlow entity) { + mapper.insert(entity); + Long shopId = entity.getShopId(); + BigDecimal afterNumber = entity.getAfterNumber(); + Product product = productMapper.selectOneById(entity.getProductId()); + String shopName = StpKit.USER.getShopName(); + BigDecimal warnLine = Convert.toBigDecimal(product.getWarnLine()); + // 库存小于警告值,发送消息提醒 + if (NumberUtil.isLess(afterNumber, warnLine)) { + List openIdList = consInfoMapper.findOpenIdList(shopId, "pro"); + if (CollUtil.isEmpty(openIdList)) { + return; + } + String conName = StrUtil.format("{}数量<预警值{}", product.getName(), warnLine); + ThreadUtil.execAsync(() -> { + openIdList.parallelStream().forEach(openId -> { + wxAccountUtil.sendStockMsg(shopName, conName, afterNumber, openId); + }); + }); + } + } +} diff --git a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/SensitiveOperationServiceImpl.java b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/SensitiveOperationServiceImpl.java new file mode 100644 index 00000000..1303e527 --- /dev/null +++ b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/SensitiveOperationServiceImpl.java @@ -0,0 +1,40 @@ +package com.czg.service.product.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.thread.ThreadUtil; +import com.czg.product.service.SensitiveOperationService; +import com.czg.sa.StpKit; +import com.czg.service.product.mapper.ConsInfoMapper; +import com.czg.service.product.util.WxAccountUtil; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 敏感操作ServiceImpl + * + * @author tankaikai + * @since 2025-03-17 11:47 + */ +@Service +public class SensitiveOperationServiceImpl implements SensitiveOperationService { + + @Resource + private ConsInfoMapper consInfoMapper; + @Resource + private WxAccountUtil wxAccountUtil; + + @Override + public void send(String operationDesc) { + Long shopId = StpKit.USER.getShopId(0L); + String userName = StpKit.USER.getAccount(); + List openIdList = consInfoMapper.findOpenIdList(shopId, "ope"); + if (CollUtil.isEmpty(openIdList)) { + return; + } + ThreadUtil.execAsync(() -> { + wxAccountUtil.sendOperationMsg(openIdList, userName, operationDesc); + }); + } +} diff --git a/cash-service/product-service/src/main/java/com/czg/service/product/util/WxAccountUtil.java b/cash-service/product-service/src/main/java/com/czg/service/product/util/WxAccountUtil.java new file mode 100644 index 00000000..6fbc65e5 --- /dev/null +++ b/cash-service/product-service/src/main/java/com/czg/service/product/util/WxAccountUtil.java @@ -0,0 +1,143 @@ +package com.czg.service.product.util; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.czg.service.RedisService; +import jakarta.annotation.Resource; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 微信公众号消息推送 + * + * @author tankaikai + * @since 2025-03-14 14:56 + */ +@Data +@Slf4j +@Component +public class WxAccountUtil { + + @Value("${wx.ysk.appId}") + private String appId = "wx212769170d2c6b2a"; + @Value("${wx.ysk.secrete}") + private String secrete = "8492a7e8d55bbb1b57f5c8276ea1add0"; + @Value("${wx.ysk.operationMsgTmpId}") + private String operationMsgTmpId; + @Value("${wx.ysk.warnMsgTmpId}") + private String warnMsgTmpId; + + @Resource + @Lazy + private RedisService redisService; + + static LinkedHashMap linkedHashMap = new LinkedHashMap<>(); + + static { + linkedHashMap.put("40001", "获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口"); + linkedHashMap.put("40003", "不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID"); + linkedHashMap.put("40014", "不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口"); + linkedHashMap.put("40037", "不合法的 template_id"); + linkedHashMap.put("43101", "用户未订阅消息"); + linkedHashMap.put("43107", "订阅消息能力封禁"); + linkedHashMap.put("43108", "并发下发消息给同一个粉丝"); + linkedHashMap.put("45168", "命中敏感词"); + linkedHashMap.put("47003", "参数错误"); + } + + public String getAccessToken() { + String accessToken = Convert.toStr(redisService.get("accessToken")); + accessToken = "90_OzMitqhQZ1EPbaqFqGiaCeIhCWCPerSs43dTSNVdriltnbu6F-13Yao0ByELKKP50LtyFo2Kw9xnjivQhNagYqQoJy_vsqP7Nk5l0gfBfOBZDqrlKSFyKKiiIVoBPScAJASGJ"; + if (StrUtil.isNotEmpty(accessToken)) { + return accessToken; + } + String resp = HttpUtil.get(StrUtil.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", appId, secrete)); + JSONObject respInfo = JSONObject.parseObject(resp); + if (!respInfo.containsKey("access_token")) { + log.warn("公众号获取token失败, 响应内容: {}", resp); + throw new RuntimeException(resp); + } + accessToken = respInfo.getString("access_token"); + int expiresIn = respInfo.getInteger("expires_in"); + redisService.set("accessToken", accessToken, expiresIn - 10); + return accessToken; + } + + public JSONObject sendTemplateMsg(String templateId, String toUserOpenId, Map data) { + log.info("开始发送微信模板消息, 接收用户openId: {}, 消息数据: {}", toUserOpenId, data); + String accessToken = getAccessToken(); + + JSONObject object1 = new JSONObject(); + + object1.put("template_id", templateId); + object1.put("touser", toUserOpenId); + object1.put("data", data); + + String response = HttpRequest.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=".concat(accessToken)).body(object1.toString()).execute().body(); + log.info("微信模板消息发送成功,响应内容:{}", response); + JSONObject resObj = JSONObject.parseObject(response); + if (ObjectUtil.isNotEmpty(resObj) && ObjectUtil.isNotNull(resObj) && "0".equals(resObj.get("errcode") + "")) { + return resObj; + } + + throw new RuntimeException(linkedHashMap.getOrDefault(resObj.get("errcode") + "", "未知错误")); + } + + public void sendOperationMsg(List openIdList, String userName, String operationDesc) { + openIdList.forEach(openId -> { + Map data = new HashMap() {{ + put("thing19", new HashMap() {{ + put("value", userName); + }}); + put("thing8", new HashMap() {{ + put("value", operationDesc); + }}); + put("time21", new HashMap() {{ + put("value", DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")); + }}); + }}; + log.info("开始发送敏感操作消息, 接收用户openId: {}, 操作用户: {}, 操作描述: {}", openId, userName, operationDesc); + try { + sendTemplateMsg(operationMsgTmpId, openId, data); + } catch (Exception e) { + log.error("发送失败, openId: {}, 响应: {}", openId, e.getMessage()); + } + }); + } + + public void sendStockMsg(String shopName, String productName, BigDecimal stockNum, String openId) { + String stockNumStr = stockNum.toPlainString(); + Map data = new HashMap() {{ + put("thing22", new HashMap() {{ + put("value", shopName); + }}); + put("thing4", new HashMap() {{ + put("value", productName); + }}); + put("number5", new HashMap() {{ + put("value", stockNumStr); + }}); + }}; + log.info("开始发送库存预警消息, 接收用户openId: {}, 消息数据: {}", openId, data); + try { + sendTemplateMsg(warnMsgTmpId, openId, data); + } catch (Exception e) { + log.error("发送失败, openId:{}, msg: {}", openId, e.getMessage()); + } + } + +} diff --git a/cash-service/product-service/src/main/resources/mapper/ConsInfoMapper.xml b/cash-service/product-service/src/main/resources/mapper/ConsInfoMapper.xml index 1d0445bc..e9e0ad2e 100644 --- a/cash-service/product-service/src/main/resources/mapper/ConsInfoMapper.xml +++ b/cash-service/product-service/src/main/resources/mapper/ConsInfoMapper.xml @@ -3,4 +3,12 @@ + \ No newline at end of file