浏览代码

feat(second): 添加风控记录查询与商品批量下架功能

- 新增根据规则类型和业务ID查询相同类型风控记录接口
- 实现基于风控记录的商品批量下架逻辑
- 调整商品发布时用户发布限制检查顺序-修复商品记录查询条件错误问题- 在更新商品时自动设置当前用户ID- 添加商品批量下架时的操作记录与消息通知
wxd 1 月之前
父节点
当前提交
063653dca3

+ 5 - 0
alien-second/src/main/java/shop/alien/second/controller/SecondGoodsController.java

@@ -101,6 +101,11 @@ public class SecondGoodsController {
     @NoRepeatSubmit(expireTime = 5, message = "请勿重复提交更新商品请求")
     public R<Void> updateSecondGoods(@ApiParam("二手商品信息") @RequestBody SecondGoodsVo secondGoods) throws Exception {
         log.info("SecondGoodsController.updateSecondGoods?secondGoods={}", secondGoods.toString());
+        JSONObject data = JwtUtil.getCurrentUserInfo();
+        if (null != data) {
+            int userId = data.getInteger("userId");
+            secondGoods.setUserId(userId);// 设置用户ID (发布者)
+        }
         // 添加商品 0 创建 1 更新
         if (!secondGoodsService.createBasicInfo(secondGoods,1)) {
             return R.fail("修改二手商品失败");

+ 11 - 0
alien-second/src/main/java/shop/alien/second/service/RiskControlService.java

@@ -3,6 +3,8 @@ package shop.alien.second.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.second.SecondRiskControlRecord;
 
+import java.util.List;
+
 /**
  * 风控服务接口
  */
@@ -22,4 +24,13 @@ public interface RiskControlService extends IService<SecondRiskControlRecord> {
                                String ruleName,
                                String businessId,
                                String detailInfo);
+
+    /**
+     * 获取相同类型的风控数据
+     *
+     * @param ruleType   规则类型
+     * @param businessId 业务ID
+     * @return 相同类型的风控数据列表
+     */
+    List<SecondRiskControlRecord> getSameTypeRiskControlRecords(Integer ruleType, String businessId);
 }

+ 9 - 0
alien-second/src/main/java/shop/alien/second/service/SecondGoodsService.java

@@ -6,6 +6,7 @@ import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.SecondVideoTask;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.SecondGoodsRecord;
+import shop.alien.entity.second.SecondRiskControlRecord;
 import shop.alien.entity.second.vo.SecondGoodsVo;
 import shop.alien.entity.second.vo.SecondGoodsAdminQueryDTO;
 import shop.alien.entity.second.vo.SecondGoodsDetailVo;
@@ -208,4 +209,12 @@ public interface SecondGoodsService extends IService<SecondGoods> {
      * @return 处理后的商品详情信息
      */
     SecondGoodsVo dealSecondGoodsRecordInfo(Integer goodsId);
+
+    /**
+     * 批量处理商品信息(管理后台使用)( ruleType = 4 异常发布场景)
+     * @param ruleType 风险类型
+     * @param businessId 业务ID
+     * @return 是否处理成功
+     */
+    boolean batchShelveGoodsByRiskControlRecord(Integer ruleType, String businessId);
 }

+ 19 - 0
alien-second/src/main/java/shop/alien/second/service/impl/RiskControlServiceImpl.java

@@ -1,5 +1,6 @@
 package shop.alien.second.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -9,6 +10,7 @@ import shop.alien.mapper.second.SecondRiskControlRecordMapper;
 import shop.alien.second.service.RiskControlService;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * 风控服务实现类
@@ -53,4 +55,21 @@ public class RiskControlServiceImpl extends ServiceImpl<SecondRiskControlRecordM
             log.error("记录风控数据时发生异常: 用户ID={}, 规则类型={},业务id={}", userId, ruleType, businessId, e);
         }
     }
+
+    /**
+     * 获取相同类型的风控数据
+     *
+     * @param ruleType   规则类型 1:洗钱嫌疑 2:账号异常 3:交易欺诈 4:异常发布
+     * @param businessId 业务ID
+     * @return 相同类型的风控数据列表
+     */
+    @Override
+    public List<SecondRiskControlRecord> getSameTypeRiskControlRecords(Integer ruleType, String businessId) {
+        log.info("获取相同类型的风控数据: 规则类型={},业务id={}", ruleType, businessId);
+        QueryWrapper<SecondRiskControlRecord> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("rule_type", ruleType);
+        queryWrapper.eq("business_id", businessId);
+        log.info("查询条件: {}", queryWrapper.getSqlSegment());
+        return secondRiskControlRecordMapper.selectList(queryWrapper);
+    }
 }

+ 79 - 12
alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java

@@ -548,17 +548,6 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             SecondGoods goods = new SecondGoods();
             BeanUtils.copyProperties(goodsDTO, goods);
 
-            // 检查用户是否在24小时内发布商品超过阈值
-            if (!checkUserPublishLimit(goods)) {
-                log.warn("用户 {} 在24小时内发布商品次数超过限制", goodsDTO.getUserId());
-
-            }
-
-            // 检查用户是否在24小时内发布同类商品超过阈值
-            if (!checkUserPublishSameCategoryLimit(goods)) {
-                log.warn("用户 {} 在24小时内发布同类商品次数超过限制", goodsDTO.getUserId());
-            }
-
             boolean saveResult;
             if (editFlag == 1) {
                 goods.setId(goodsDTO.getId());
@@ -580,6 +569,16 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                 return false; // 如果获取不到ID,视为操作失败
             }
 
+            // 检查用户是否在24小时内发布同类商品超过阈值
+            if (!checkUserPublishSameCategoryLimit(goods)) {
+                log.warn("用户 {} 在24小时内发布同类商品次数超过限制", goodsDTO.getUserId());
+            }
+
+            // 检查用户是否在24小时内发布商品超过阈值
+            if (!checkUserPublishLimit(goods)) {
+                log.warn("用户 {} 在24小时内发布商品次数超过限制", goodsDTO.getUserId());
+
+            }
             // 保存商品图片信息
             if (!saveStoreImages(savedGoodsId, goodsDTO )) {
                 return false;
@@ -614,7 +613,7 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
         // 查询用户在24小时内发布的商品数量
         LambdaQueryWrapper<SecondGoodsRecord> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(SecondGoodsRecord::getUserId, goods.getUserId())
-                .eq(SecondGoodsRecord::getId, goods.getId())
+                .eq(SecondGoodsRecord::getGoodsId, goods.getId())
                 .ge(SecondGoodsRecord::getReleaseTime, timeWindowStart)
                 .in(SecondGoodsRecord::getGoodsStatus,
                         SecondGoodsStatusEnum.LISTED.getCode(),
@@ -1872,6 +1871,74 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
+     * 根据风控记录中的JSON数据批量下架商品
+     * @param goodsIds 商品ID集合
+     * @return 是否下架成功
+     */
+    public boolean batchShelveGoodsByIds(List<Integer> goodsIds) {
+        if (goodsIds == null || goodsIds.isEmpty()) {
+            return true;
+        }
+        
+        // 批量更新商品状态为下架状态
+        LambdaUpdateWrapper<SecondGoods> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.in(SecondGoods::getId, goodsIds)
+                .set(SecondGoods::getGoodsStatus, SecondGoodsStatusEnum.DELISTED.getCode());
+        
+        boolean updateResult = update(updateWrapper);
+        
+        if (updateResult) {
+            // 批量查询更新后的商品信息
+            Collection<SecondGoods> updatedGoodsList = listByIds(goodsIds);
+            
+            // 为每个商品记录操作历史并发送通知
+            for (SecondGoods goods : updatedGoodsList) {
+                recordGoodsOperation(goods, "风控下架");
+                sendShelveMessage(goods);
+            }
+        }
+        
+        return updateResult;
+    }
+
+    /**
+     * 根据风控记录中的JSON数据批量下架商品( ruleType = 4 异常发布场景)
+     * @param ruleType 风控规则类型
+     * @param businessId 业务ID
+     * @return 是否下架成功
+     */
+    @Override
+    public boolean batchShelveGoodsByRiskControlRecord(Integer ruleType, String businessId) {
+        try {
+            // 获取相同类型的风控数据
+            List<SecondRiskControlRecord> riskControlRecordList = riskControlService.getSameTypeRiskControlRecords(ruleType, businessId);
+            // 获取风控数据详情
+            List<String> detailInfoList = riskControlRecordList.stream()
+                    .map(SecondRiskControlRecord::getDetailInfo)
+                    .collect(Collectors.toList());
+
+            // 声明所有被风控的商品ID
+            List<Integer> goodsIdList = Lists.newArrayList();
+
+            // 循环情信息json 转换为集合
+            for (String detailInfo : detailInfoList){
+                // 解析JSON获取商品ID列表
+                List<Integer> goodsIds = JSON.parseArray(detailInfo, Integer.class);
+                goodsIdList.addAll(goodsIds);
+            }
+
+            // goodsIdList 去重
+            goodsIdList = goodsIdList.stream().distinct().collect(Collectors.toList());
+
+            // 调用批量下架方法
+            return batchShelveGoodsByIds(goodsIdList);
+        } catch (Exception e) {
+            log.error("根据风控记录批量下架商品失败,详情: {}", ruleType, e);
+            return false;
+        }
+    }
+
+    /**
      * 下架商品
      * @param secondGoods 商品信息
      * @return 是否下架成功