Merge remote-tracking branch 'origin/master'

This commit is contained in:
张松 2025-03-17 13:54:56 +08:00
commit 329687d5df
16 changed files with 408 additions and 15 deletions

View File

@ -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<Void> 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();
}
/**
* 店铺推送状态获取
*/

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -70,4 +70,10 @@ public interface ConsStockFlowService extends IService<ConsStockFlow> {
* @return 分页数据
*/
Page<ConsStockFlowDTO> findConsStockFlowPage(ConsStockFlowParam param);
/**
* 保存库存变动记录
* @param entity 库存变动记录实体
*/
void saveFlow(ConsStockFlow entity);
}

View File

@ -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<ProductStockFlow> {
void saveFlow(ProductStockFlow entity);
}

View File

@ -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);
}

View File

@ -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<ShopMsgStateMapper, Sho
private AliOssUtil aliOssUtil;
@Resource
private ShopPushOpenIdMapper shopPushOpenIdMapper;
@Value("${spring.profiles.active}")
private String active;
@Override
@ -98,7 +101,7 @@ public class ShopMsgStateServiceImpl extends ServiceImpl<ShopMsgStateMapper, Sho
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
org.springframework.core.io.Resource resource = resourceLoader.getResource("classpath:/static/logo.jpg");
InputStream inputStream = resource.getInputStream();
String url = StrUtil.format("https://invoice.sxczgkj.cn/index/wechat/weuserk?shopId={}", shopId);
String url = StrUtil.format("https://invoice.sxczgkj.cn/index/wechat/weuserk?source=ysk&active={}&shopId={}", active, shopId);
QrCodeUtil.generate(url, new QrConfig(500, 500).
setImg(ImageIO.read(inputStream)).setErrorCorrection(ErrorCorrectionLevel.H).setRatio(4), "png", outputStream);

View File

@ -3,6 +3,9 @@ package com.czg.service.product.mapper;
import com.czg.product.entity.ConsInfo;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 耗材信息
@ -12,5 +15,5 @@ import org.apache.ibatis.annotations.Mapper;
*/
@Mapper
public interface ConsInfoMapper extends BaseMapper<ConsInfo> {
List<String> findOpenIdList(@Param("shopId") Long shopId, @Param("type") String type);
}

View File

@ -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<ConsStockFlowMapper, ConsStockFlow> 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<ConsStockFlowMapper, C
}
entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice()));
entity.setRemark(param.getRemark());
super.save(entity);
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
}
@ -199,7 +205,7 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice()));
entity.setImgUrls(JSON.toJSONString(param.getImgUrls()));
super.save(entity);
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
}
@ -222,4 +228,27 @@ public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, C
return pageAs(PageUtil.buildPage(), queryWrapper, ConsStockFlowDTO.class);
}
@Override
public void saveFlow(ConsStockFlow entity) {
super.save(entity);
Long shopId = entity.getShopId();
BigDecimal afterNumber = entity.getAfterNumber();
ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId());
String shopName = StpKit.USER.getShopName();
BigDecimal conWarning = consInfo.getConWarning();
// 库存小于警告值发送消息提醒
if (NumberUtil.isLess(afterNumber, conWarning)) {
List<String> 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);
});
});
}
}
}

View File

@ -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<ProdGroupMapper, ProdGroup> 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<ProdGroupMapper, ProdGroup
.eq(ProdGroup::getId, id)
.eq(ProdGroup::getShopId, shopId)
.update();
ProdGroup prodGroup = mapper.selectOneById(id);
sensitiveOperationService.send("关闭分组:" + prodGroup.getName());
}
@Override
@ -162,6 +165,8 @@ public class ProdGroupServiceImpl extends ServiceImpl<ProdGroupMapper, ProdGroup
.eq(ProdGroup::getId, id)
.eq(ProdGroup::getShopId, shopId)
.update();
ProdGroup prodGroup = mapper.selectOneById(id);
sensitiveOperationService.send("开启分组:" + prodGroup.getName());
}
}

View File

@ -17,7 +17,10 @@ import com.czg.product.dto.ProductDTO;
import com.czg.product.entity.*;
import com.czg.product.enums.*;
import com.czg.product.param.*;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.service.ProductService;
import com.czg.product.service.ProductStockFlowService;
import com.czg.product.service.SensitiveOperationService;
import com.czg.product.vo.ProductStatisticsVo;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.*;
@ -59,6 +62,9 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> 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<ProductMapper, Product> 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<ProductMapper, Product> impl
return;
}
flow.setAfterNumber(NumberUtil.toBigDecimal(entity.getStockNumber()));
productStockFlowMapper.insert(flow);
productStockFlowService.saveFlow(flow);
}
@Override
@ -331,6 +337,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> 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<ProductMapper, Product> 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<ProductMapper, Product> 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<ProductMapper, Product> 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<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByProdId(param.getProductId());
if (CollUtil.isEmpty(consList)) {
@ -465,6 +480,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> 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())

View File

@ -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<ProductStockFlowMapper, ProductStockFlow> 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<String> 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);
});
});
}
}
}

View File

@ -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<String> openIdList = consInfoMapper.findOpenIdList(shopId, "ope");
if (CollUtil.isEmpty(openIdList)) {
return;
}
ThreadUtil.execAsync(() -> {
wxAccountUtil.sendOperationMsg(openIdList, userName, operationDesc);
});
}
}

View File

@ -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<String, String> 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<String, Object> 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<String> openIdList, String userName, String operationDesc) {
openIdList.forEach(openId -> {
Map<String, Object> data = new HashMap<String, Object>() {{
put("thing19", new HashMap<String, Object>() {{
put("value", userName);
}});
put("thing8", new HashMap<String, Object>() {{
put("value", operationDesc);
}});
put("time21", new HashMap<String, Object>() {{
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<String, Object> data = new HashMap<String, Object>() {{
put("thing22", new HashMap<String, Object>() {{
put("value", shopName);
}});
put("thing4", new HashMap<String, Object>() {{
put("value", productName);
}});
put("number5", new HashMap<String, Object>() {{
put("value", stockNumStr);
}});
}};
log.info("开始发送库存预警消息, 接收用户openId: {}, 消息数据: {}", openId, data);
try {
sendTemplateMsg(warnMsgTmpId, openId, data);
} catch (Exception e) {
log.error("发送失败, openId:{}, msg: {}", openId, e.getMessage());
}
}
}

View File

@ -3,4 +3,12 @@
<mapper namespace="com.czg.service.product.mapper.ConsInfoMapper">
<select id="findOpenIdList" resultType="java.lang.String">
select
open_id
from tb_shop_push_open_id
where shop_id = #{shopId}
and status = 1
and type_info like concat('%', #{type}, '%')
</select>
</mapper>