Bläddra i källkod

Merge remote-tracking branch 'origin/master'

lyx 2 veckor sedan
förälder
incheckning
29d9b5cb6e
23 ändrade filer med 1008 tillägg och 187 borttagningar
  1. 117 0
      alien-entity/src/main/java/shop/alien/entity/second/vo/SellGoodsVo.java
  2. 10 4
      alien-entity/src/main/java/shop/alien/mapper/LifeMessageMapper.java
  3. 32 0
      alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsMapper.java
  4. 32 15
      alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java
  5. 16 12
      alien-second/src/main/java/shop/alien/second/controller/UserGoodsController.java
  6. 9 0
      alien-second/src/main/java/shop/alien/second/service/SecondGoodsService.java
  7. 11 20
      alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java
  8. 79 28
      alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java
  9. 66 22
      alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java
  10. 21 11
      alien-store/src/main/java/shop/alien/store/controller/LifeMessageController.java
  11. 9 9
      alien-store/src/main/java/shop/alien/store/controller/LifeNoticeController.java
  12. 2 2
      alien-store/src/main/java/shop/alien/store/controller/WebAuditController.java
  13. 5 1
      alien-store/src/main/java/shop/alien/store/service/LifeMessageService.java
  14. 3 1
      alien-store/src/main/java/shop/alien/store/service/LifeNoticeService.java
  15. 122 47
      alien-store/src/main/java/shop/alien/store/service/impl/LifeMessageServiceImpl.java
  16. 15 14
      alien-store/src/main/java/shop/alien/store/service/impl/LifeNoticeServiceImpl.java
  17. 5 1
      alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java
  18. 6 0
      alien-util/pom.xml
  19. 173 0
      alien-util/src/main/java/shop/alien/util/common/safe/ImageModerationUtil.java
  20. 56 0
      alien-util/src/main/java/shop/alien/util/common/safe/ImageReviewServiceEnum.java
  21. 23 0
      alien-util/src/main/java/shop/alien/util/common/safe/TextModerationResultVO.java
  22. 170 0
      alien-util/src/main/java/shop/alien/util/common/safe/TextModerationUtil.java
  23. 26 0
      alien-util/src/main/java/shop/alien/util/common/safe/TextReviewServiceEnum.java

+ 117 - 0
alien-entity/src/main/java/shop/alien/entity/second/vo/SellGoodsVo.java

@@ -0,0 +1,117 @@
+package shop.alien.entity.second.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.second.SecondGoods;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Data
+@JsonInclude
+@ApiModel(value = "二手商品发布", description = "发布")
+public class SellGoodsVo extends SecondGoods {
+
+    @ApiModelProperty(value = "保存方式 0:草稿 1:发布")
+    private Integer saveType;
+
+    @ApiModelProperty(value = "商品距离")
+    private String distance;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "用户名称")
+    private String userName;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "用户真名")
+    private String realName;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "用户电话")
+    private String userPhone;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "用户头像")
+    private String userImage;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "收藏状态 默认为 0")
+    private Integer collectStatus = 0;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "点赞状态 默认为 0")
+    private Integer likeStatus = 0;
+
+    @ApiModelProperty("一级分类名称")
+    @TableField(exist = false)
+    private String categoryOneName;
+
+    @ApiModelProperty("二级分类名称")
+    @TableField(exist = false)
+    private String categoryTwoName;
+
+    /** -------------------- 搜索入参 -------------------- */
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "当前页码")
+    private Integer pageNum = 1;
+
+    @ApiModelProperty(value = "每页数量")
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "当前经度")
+    private Double currentLatitude;
+
+    @ApiModelProperty(value = "当前纬度")
+    private Double currentLongitude;
+
+
+
+    @ApiModelProperty(value = "买家id")
+    private Integer buyerId;
+
+    @ApiModelProperty(value = "卖家id")
+    private Integer sellerId;
+
+    @ApiModelProperty(value = "交易时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date transactionTime;
+
+    @ApiModelProperty(value = "交易地点(经纬度)")
+    private String transactionLatitudeLongitude;
+
+    @ApiModelProperty(value = "交易地点(详细地址)")
+    private String transactionLocation;
+
+    @ApiModelProperty(value = "交易金额")
+    private BigDecimal transactionAmount;
+
+    @ApiModelProperty(value = "买家交易状态  1-交易成功  2-交易失败")
+    private Integer buyerTransactionStatus;
+
+    @ApiModelProperty(value = "卖家交易状态  1-交易成功  2-交易失败")
+    private Integer sellerTransactionStatus;
+
+    @ApiModelProperty(value = "交易状态  0-待交易  1-交易成功  2-交易失败  3-交易取消")
+    private Integer tradeStatus;
+
+    @ApiModelProperty(value = "买家评价")
+    private String buyerEvaluate;
+
+    @ApiModelProperty(value = "卖家评价")
+    private String sellerEvaluate;
+
+    @ApiModelProperty(value = "交易对方的用户ID")
+    private Integer otherPartyId;
+
+
+}

+ 10 - 4
alien-entity/src/main/java/shop/alien/mapper/LifeMessageMapper.java

@@ -38,13 +38,19 @@ public interface LifeMessageMapper extends BaseMapper<LifeMessage> {
             "        where delete_flag = 0 and (sender_id = #{phoneId} or receiver_id = #{phoneId}) " +
             "               and (instr(delete_phone_id, #{phoneId}) is null or instr(delete_phone_id, #{phoneId}) = 0)" +
             "    ) " +
-            "    select *, row_number() over (partition by phoneId order by created_time desc ) num " +
+            "    select *, row_number() over (partition by phoneId order by created_time desc ) num, " +
+            "           substring_index(phoneId, '_', 1) flag, substring_index(phoneId, '_', -1) phone " +
             "    from message " +
             ") " +
-            "select id, type, phoneId, content, created_time createdTime, is_read " +
-            "from message_num " +
+            "select message.id, message.type, message.phoneId, message.content, message.created_time createdTime, message.is_read, " +
+            "       if (message.flag = 'user', user.user_name, suser.name) userName, " +
+            "       if (message.flag = 'user', user.user_image, img.img_url) userImage " +
+            "from message_num message " +
+            "left join life_user user on message.flag = 'user' and message.phone = user.user_phone and user.delete_flag = 0 " +
+            "left join store_user suser on message.flag = 'store' and message.phone = suser.phone and suser.delete_flag = 0 " +
+            "left join store_img img on img.store_id = suser.store_id and img.img_type = '10' and img.delete_flag = 0 " +
             "${ew.customSqlSegment}")
-    IPage<LifeMessageVo> getLifeMessagePageByPhoneId(IPage<LifeMessageVo> iPage, @Param("phoneId") String phoneId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> dynamicsWrapper);
+    List<LifeMessageVo> getLifeMessagePageByPhoneId(@Param("phoneId") String phoneId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> dynamicsWrapper);
 
     @Update("update life_message set delete_phone_id = (if(delete_phone_id is null, #{receiverId}, concat(delete_phone_id, ',', #{receiverId}))) ,delete_flag = '1'" +
             "where (receiver_id = #{senderId} and sender_id = #{receiverId}) or (sender_id = #{senderId} and receiver_id = #{receiverId}) ")

+ 32 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsMapper.java

@@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Select;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.SecondShield;
 import shop.alien.entity.second.vo.SecondGoodsVo;
+import shop.alien.entity.second.vo.SellGoodsVo;
 import shop.alien.entity.store.StoreInfo;
 
 import java.util.List;
@@ -245,4 +246,35 @@ public interface SecondGoodsMapper extends BaseMapper<SecondGoods> {
             "on sg.category_two_id = sgc2.id "+
             "${ew.customSqlSegment}")
     IPage<SecondGoodsVo> getLikeGoodsPage(IPage<SecondGoodsVo> page,  @Param(Constants.WRAPPER) QueryWrapper<SecondGoodsVo> queryWrapper);
+
+    /**
+     * 获取用户交易中的商品列表
+     * @param page 分页参数
+     * @param queryWrapper 查询条件
+     * @return 交易中的商品列表
+     */
+    @Select("SELECT " +
+            "str.goods_id, " +
+            "    str.buyer_id, " +
+            "    str.seller_id, " +
+            "    str.transaction_time, " +
+            "    str.transaction_latitude_longitude, " +
+            "    str.transaction_location, " +
+            "    str.transaction_amount, " +
+            "    str.buyer_signin, " +
+            "    str.seller_signin, " +
+            "    str.buyer_transaction_status, " +
+            "    str.seller_transaction_status, " +
+            "    str.trade_status, " +
+            "    str.buyer_evaluate, " +
+            "    str.seller_evaluate,"+
+            "sg.*, " +
+            "    CASE " +
+            "        WHEN str.buyer_id = #{userId} THEN str.seller_id " +
+            "        ELSE str.buyer_id " +
+            "    END AS other_party_id " +
+            "FROM second_trade_record str " +
+            "LEFT JOIN second_goods sg ON str.goods_id = sg.id "+
+            "${ew.customSqlSegment}")
+    IPage<SellGoodsVo> getTransactionList(IPage<SellGoodsVo> page, @Param("userId") Integer userId, @Param(Constants.WRAPPER) QueryWrapper<SellGoodsVo> queryWrapper);
 }

+ 32 - 15
alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java

@@ -10,6 +10,8 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.second.SecondTradeRecord;
 import shop.alien.second.service.SecondTradeRecordService;
 
+import java.util.List;
+
 /**
  * <p>
  * 二手交易记录表 前端控制器
@@ -31,27 +33,42 @@ public class SecondTradeRecordController {
 
     @ApiOperation("获取交易信息")
     @ApiOperationSupport(order = 1)
-    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键id", dataType = "Integer", paramType = "query", required = true)})
+    @ApiImplicitParams({@ApiImplicitParam(name = "sideId", value = "对方的id", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/getTradeRecord")
-    public R<SecondTradeRecord> getTradeRecord(@Param("id") Long id) {
-        log.error("SecondTradeRecordController.getTradeRecord?id={}", id);
-        return R.data(secondTradeRecordService.getTradeRecord(id));
+    public R<List<SecondTradeRecord>> getTradeRecord(@RequestParam int sideId) {
+        log.info("SecondTradeRecordController.getTradeRecord?sideId={}", sideId);
+        return R.data(secondTradeRecordService.getTradeRecord(sideId));
     }
 
-    @ApiOperation("保存或更新交易记录")
+    @ApiOperation("创建交易")
     @ApiOperationSupport(order = 2)
-    @PostMapping("/saveOrUpdate")
-    public R<Boolean> saveOrUpdate(@RequestBody SecondTradeRecord entity) {
-        log.error("SecondTradeRecordController.getTradeRecord?entity={}", entity.toString());
-        return R.data(secondTradeRecordService.saveOrUpdate(entity));
+    @PostMapping("/createTrade")
+    public R<Boolean> createTrade(@RequestBody SecondTradeRecord entity) {
+        log.info("SecondTradeRecordController.createTrade?entity={}", entity.toString());
+        if (secondTradeRecordService.createTrade(entity)) return R.success("创建成功");
+        return R.fail("创建失败");
     }
 
-    @ApiOperation("删除交易信息")
+    @ApiOperation("交易签到")
     @ApiOperationSupport(order = 3)
-    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键id", dataType = "Integer", paramType = "query", required = true)})
-    @DeleteMapping("/deleteTradeRecord")
-    public R<Boolean> deleteTradeRecord(@Param("id") Long id) {
-        log.error("SecondTradeRecordController.deleteTradeRecord?id={}", id);
-        return R.data(secondTradeRecordService.removeById(id));
+    @ApiImplicitParams({@ApiImplicitParam(name = "tradeId", value = "交易id", dataType = "Integer", paramType = "query", required = true)})
+    @GetMapping("/tradeSignin")
+    public R<Boolean> tradeSignin(@RequestParam int tradeId) {
+        log.info("SecondTradeRecordController.tradeSignin?tradeId={}", tradeId);
+        if (secondTradeRecordService.tradeSignin(tradeId)) return R.success("签到成功");
+        return R.fail("签到失败");
+    }
+
+    @ApiOperation("交易确认")
+    @ApiOperationSupport(order = 4)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "tradeId", value = "交易id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "type", value = "0-失败  1-成功", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "evaluate", value = "评价", dataType = "String", paramType = "query")})
+    @GetMapping("/tradeConfirm")
+    public R<Boolean> tradeConfirm(@RequestParam int tradeId, @RequestParam int type, @RequestParam String evaluate) {
+        log.info("SecondTradeRecordController.tradeConfirm?tradeId={}, type={}, evaluate={}", tradeId, type, evaluate);
+        if (secondTradeRecordService.tradeConfirm(tradeId, type, evaluate)) return R.success("交易确认成功");
+        return R.fail("交易确认失败");
     }
 }

+ 16 - 12
alien-second/src/main/java/shop/alien/second/controller/UserGoodsController.java

@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.vo.SecondGoodsVo;
+import shop.alien.entity.second.vo.SellGoodsVo;
 import shop.alien.second.service.SecondGoodsService;
 import shop.alien.util.common.JwtUtil;
 
@@ -200,23 +201,26 @@ public class UserGoodsController {
         return result;
     }
 
-
     /**
-     * 我的 - 交易列表
-     * 我卖出的商品列表-分页
+     * 我的- 交易列表
      */
-    @GetMapping("/getSellGoodsPage")
-    @ApiOperation("根据商品状态获取商品列表 - 0:草稿(我的草稿列表) 1:审核中 2:审核失败 3:已上架 4:已下架 5:已售出(我卖出的商品列表) -分页")
-    public R<IPage<SecondGoodsVo>> getSellGoodsPage(
-            @ApiParam("分页参数") @RequestBody SecondGoodsVo secondGoodsVo) {
-        log.info("SecondGoodsController.getSellGoodsPage?secondGoodsVo={}", secondGoodsVo.toString());
-        R<IPage<SecondGoodsVo>> result = new R<>();
-        IPage<SecondGoodsVo> page = new Page<>(secondGoodsVo.getPageNum(), secondGoodsVo.getPageSize());
+    @GetMapping("/getTransactionList")
+    @ApiOperation("我的- 交易列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "pageNum", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "pageSize", value = "分页条数", dataType = "Integer", paramType = "query", required = true)})
+    public R<IPage<SellGoodsVo>> getTransactionList(
+            @RequestParam(defaultValue = "1") Integer pageNum,
+            @RequestParam(defaultValue = "10") Integer pageSize) {
+        log.info("SecondGoodsController.getTransactionList?page={},size={},", pageNum,pageSize);
+        IPage<SellGoodsVo> page = new Page<>(pageNum, pageSize);
+        R<IPage<SellGoodsVo>> result = new R<>();
         JSONObject data = JwtUtil.getCurrentUserInfo();
         if (null != data) {
-            int userId = data.getInteger("userId");
-            result = R.data(secondGoodsService.getSellGoodsPage(page,secondGoodsVo,userId));
+            Integer userId = data.getInteger("userId");
+            result = R.data(secondGoodsService.getTransactionList(page,userId));
         }
         return result;
     }
+
 }

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

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.vo.SecondGoodsVo;
+import shop.alien.entity.second.vo.SellGoodsVo;
 
 import java.util.List;
 
@@ -135,4 +136,12 @@ public interface SecondGoodsService extends IService<SecondGoods> {
      * @return 分页后的商品点赞商品列表
      */
     IPage<SecondGoodsVo> getLikeGoodsPage(IPage<SecondGoodsVo> page, int userId, String phone);
+
+    /**
+     * 获取商品交易列表(分页)
+     * @param page 搜索条件
+     * @param userId 用户ID
+     * @return 分页后的商品交易列表
+     */
+    IPage<SellGoodsVo> getTransactionList(IPage<SellGoodsVo> page, Integer userId);
 }

+ 11 - 20
alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java

@@ -2,8 +2,11 @@ package shop.alien.second.service;
 
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import io.swagger.models.auth.In;
 import shop.alien.entity.second.SecondTradeRecord;
 
+import java.util.List;
+
 /**
  * <p>
  * 二手交易记录表 服务类
@@ -13,24 +16,12 @@ import shop.alien.entity.second.SecondTradeRecord;
  * @since 2025-07-07
  */
 public interface SecondTradeRecordService extends IService<SecondTradeRecord> {
-    /**
-     * 根据ID获取交易记录
-     * @param id 交易记录ID
-     * @return 交易记录对象
-     */
-    SecondTradeRecord getTradeRecord(Long id);
-
-    /**
-     * 保存或更新交易记录
-     * @param entity 交易记录对象
-     * @return 操作结果
-     */
-    boolean saveOrUpdate(SecondTradeRecord entity);
-
-    /**
-     * 根据ID删除交易记录
-     * @param id 交易记录ID
-     * @return 删除结果
-     */
-    boolean removeById(Long id);
+    List<SecondTradeRecord> getTradeRecord(int sideId);
+
+    boolean createTrade(SecondTradeRecord entity);
+
+    boolean tradeSignin(int tradeId);
+
+    boolean tradeConfirm(int tradeId, int type, String evaluate);
+
 }

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

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.apache.ibatis.annotations.Param;
@@ -12,6 +13,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.vo.SecondGoodsVo;
+import shop.alien.entity.second.vo.SellGoodsVo;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.LifeUserVo;
 import shop.alien.mapper.*;
@@ -360,7 +362,7 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             // 批量设置商品图片信息
 //            batchSetGoodsImages(searchGoodsList);
             // 批量设置用户信息
-            batchSetUserInfo(searchGoodsList);
+            batchSetSearchUserInfo(searchGoodsList);
             // 批量设置收藏状态
             batchSetCollectStatus(searchGoodsList,secondGoodsVo.getUserPhone(), userId);
             // 批量设置点赞状态
@@ -573,6 +575,27 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
+     * 获取交易列表
+     * @param page 分页参数
+     * @param userId 用户ID
+     * @return IPage<SecondGoodsVo> 交易列表
+     */
+    @Override
+    public IPage<SellGoodsVo> getTransactionList(IPage<SellGoodsVo> page, Integer userId) {
+        IPage<SellGoodsVo> result = new Page<>();
+        QueryWrapper<SellGoodsVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("sg.delete_flag", 0)
+                .eq("str.delete_flag", 0)
+                .and(wrapper -> wrapper.eq("str.buyer_id", userId)
+                        .or()
+                        .eq("str.seller_id", userId));
+        result = secondGoodsMapper.getTransactionList(page, userId, queryWrapper);
+        // 批量设置用户信息
+        batchSetSellUserInfo(result);
+        return result;
+    }
+
+    /**
      * 查询搜索结果
      * @param page 分页参数
      * @param secondGoodsVo 查询参数
@@ -628,40 +651,35 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
-     * 批量设置用户信息
+     * 批量设置用户信息(用于SecondGoodsVo列表)
      * @param searchGoodsList 搜索结果
      */
-    private void batchSetUserInfo(IPage<SecondGoodsVo> searchGoodsList) {
-        // 批量获取用户信息(头像,用户姓名,用户id)
-        if (CollectionUtil.isNotEmpty(searchGoodsList.getRecords())) {
-            List<Integer> userIds = searchGoodsList.getRecords().stream()
-                    .map(SecondGoodsVo::getUserId)
-                    .collect(Collectors.toList());
-                    // 批量获取用户信息
-                    QueryWrapper<LifeUserVo> queryWrapper = new QueryWrapper<>();
-                    queryWrapper.in("id", userIds); // 使用字符串 "user_id" 直接指定数据库列名
-                    queryWrapper.in("delete_flag", 0);
-                    List<LifeUserVo> userInfoList = lifeUserMapper.getUserByIds(queryWrapper);
-                    // 根据用户id进行分组 返回map
-                    Map<Integer, LifeUserVo> userInfoMap = userInfoList.stream()
-                            .collect(Collectors.toMap(LifeUserVo::getId, lifeUserVo -> lifeUserVo));
-                    // 获取用户信息
-                    for (SecondGoodsVo goods : searchGoodsList.getRecords()) {
-                        LifeUserVo userInfo = userInfoMap.get(goods.getUserId());
-                        if (userInfo != null){
-                            // 用户名称
+    private void batchSetSearchUserInfo(IPage<SecondGoodsVo> searchGoodsList) {
+        batchSetUserInfo(searchGoodsList, 
+                        SecondGoodsVo::getUserId,
+                        (goods, userInfo) -> {
+                            goods.setUserName(userInfo.getUserName());
+                            goods.setRealName(userInfo.getRealName());
+                            goods.setUserImage(userInfo.getUserImage());
+                            goods.setUserId(userInfo.getId());
+                            goods.setUserPhone("user_"+userInfo.getUserPhone());
+                        });
+    }
+    
+    /**
+     * 批量设置用户信息(用于SellGoodsVo列表)
+     * @param sellGoodsList 搜索结果
+     */
+    private void batchSetSellUserInfo(IPage<SellGoodsVo> sellGoodsList) {
+        batchSetUserInfo(sellGoodsList, 
+                        SellGoodsVo::getUserId,
+                        (goods, userInfo) -> {
                             goods.setUserName(userInfo.getUserName());
-                            // 用户真实姓名
                             goods.setRealName(userInfo.getRealName());
-                            // 用户头像
                             goods.setUserImage(userInfo.getUserImage());
-                            // 用户id
                             goods.setUserId(userInfo.getId());
-                            // 用户手机号
                             goods.setUserPhone(userInfo.getUserPhone());
-                        }
-                    }
-        }
+                        });
     }
 
     /**
@@ -696,4 +714,37 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                     }
         }
     }
+
+
+    /**
+     * 批量设置用户信息
+     * @param <T> 任意商品VO类型
+     * @param goodsList 商品列表
+     * @param userIdMapper 从商品VO获取用户ID的函数
+     * @param userSetter 从用户信息设置到商品VO的函数
+     */
+    private <T> void batchSetUserInfo(IPage<T> goodsList,
+                                      java.util.function.Function<T, Integer> userIdMapper,
+                                      java.util.function.BiConsumer<T, LifeUserVo> userSetter) {
+        if (CollectionUtil.isNotEmpty(goodsList.getRecords())) {
+            List<Integer> userIds = goodsList.getRecords().stream()
+                    .map(userIdMapper)
+                    .collect(Collectors.toList());
+
+            QueryWrapper<LifeUserVo> queryWrapper = new QueryWrapper<>();
+            queryWrapper.in("id", userIds)
+                    .eq("delete_flag", 0);
+
+            List<LifeUserVo> userInfoList = lifeUserMapper.getUserByIds(queryWrapper);
+            Map<Integer, LifeUserVo> userInfoMap = userInfoList.stream()
+                    .collect(Collectors.toMap(LifeUserVo::getId, lifeUserVo -> lifeUserVo));
+
+            for (T goods : goodsList.getRecords()) {
+                LifeUserVo userInfo = userInfoMap.get(userIdMapper.apply(goods));
+                if (userInfo != null && userSetter != null) {
+                    userSetter.accept(goods, userInfo);
+                }
+            }
+        }
+    }
 }

+ 66 - 22
alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.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,10 @@ import shop.alien.entity.second.SecondTradeRecord;
 import shop.alien.mapper.second.SecondGoodsMapper;
 import shop.alien.mapper.second.SecondTradeRecordMapper;
 import shop.alien.second.service.SecondTradeRecordService;
+import shop.alien.util.common.JwtUtil;
+
+import java.util.List;
+import java.util.Objects;
 
 /**
  * <p>
@@ -27,42 +32,81 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
     private final SecondGoodsMapper secondGoodsMapper;
 
     @Override
-    public SecondTradeRecord getTradeRecord(Long id) {
-        return super.getById(id);
+    public List<SecondTradeRecord> getTradeRecord(int sideId) {
+        try {
+            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
+            QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
+            wrapper.apply("(buyer_id = '" + sideId + "' and seller_id = '" + userId + "') || (buyer_id = '" + userId + "' and seller_id = '" + sideId + "')");
+            wrapper.orderByDesc("created_time");
+            return secondTradeRecordMapper.selectList(wrapper);
+        } catch (Exception e) {
+            log.error("SecondTradeRecordServiceImpl.getTradeRecord===", e.fillInStackTrace());
+            return null;
+        }
     }
 
     /**
-     * 保存或更新交易记录
+     * 创建交易
      * @param entity 交易记录对象
      * @return 操作结果
      */
     @Override
-    public boolean saveOrUpdate(SecondTradeRecord entity) {
+    public boolean createTrade(SecondTradeRecord entity) {
         try {
-            if (null == entity.getId()) {
-                super.saveOrUpdate(entity);
-                SecondGoods goods = new SecondGoods();
-                goods.setId(entity.getGoodsId());
-                goods.setTradeId(entity.getId());
-                secondGoodsMapper.updateById(goods);
-            } else {
-                super.saveOrUpdate(entity);
-            }
+            secondTradeRecordMapper.insert(entity);
+            SecondGoods goods = new SecondGoods();
+            goods.setId(entity.getGoodsId());
+            goods.setTradeId(entity.getId());
+            secondGoodsMapper.updateById(goods);
             return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.saveOrUpdate?error={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.createTrade===", e.fillInStackTrace());
         }
-
         return false;
     }
 
-    /**
-     * 根据ID删除交易记录
-     * @param id 交易记录ID
-     * @return 删除结果
-     */
     @Override
-    public boolean removeById(Long id) {
-        return super.removeById(id);
+    public boolean tradeSignin(int tradeId) {
+        try {
+            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
+            SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
+            SecondTradeRecord record = new SecondTradeRecord();
+            record.setId(tradeId);
+            if (userId == tradeRecord.getBuyerId()) {
+                record.setBuyerSignin(1);
+            } else if (userId == tradeRecord.getSellerId()) {
+                record.setSellerSignin(1);
+            } else {
+                return false;
+            }
+            secondTradeRecordMapper.updateById(record);
+        } catch (Exception e) {
+            log.error("SecondTradeRecordServiceImpl.tradeSignin===", e.fillInStackTrace());
+        }
+        return true;
+    }
+
+    @Override
+    public boolean tradeConfirm(int tradeId, int type, String evaluate) {
+        try {
+            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
+            SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
+            SecondTradeRecord record = new SecondTradeRecord();
+            record.setId(tradeId);
+            if (userId == tradeRecord.getBuyerId()) {
+                record.setBuyerTransactionStatus(type);
+                record.setBuyerEvaluate(evaluate);
+            } else if (userId == tradeRecord.getSellerId()) {
+                record.setSellerTransactionStatus(type);
+                record.setSellerEvaluate(evaluate);
+                record.setTradeStatus(type);
+            } else {
+                return false;
+            }
+            secondTradeRecordMapper.updateById(record);
+        } catch (Exception e) {
+            log.error("SecondTradeRecordServiceImpl.tradeConfirm===", e.fillInStackTrace());
+        }
+        return true;
     }
 }

+ 21 - 11
alien-store/src/main/java/shop/alien/store/controller/LifeMessageController.java

@@ -34,18 +34,28 @@ public class LifeMessageController {
     @ApiOperation("消息列表")
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
-            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "friendType", value = "好友类型 1-好友 2-好友以外", dataType = "Integer", paramType = "query")})
+            @ApiImplicitParam(name = "friendType", value = "聊天类型 1-聊过 2-未聊过", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "search", value = "搜索字段", dataType = "Integer", paramType = "query")})
     @GetMapping("/getMessageList")
-    public R<IPage<LifeMessageVo>> getMessageList(@RequestParam String receiverId, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, int friendType) {
-        log.info("LifeMessageController.getMessageList?receiverId={}, page={}, size={}, friendType={}", receiverId, page, size, friendType);
-        return R.data(lifeMessageService.getMessageList(receiverId, page, size, friendType));
+    public R<List<LifeMessageVo>> getMessageList(@RequestParam String receiverId,
+                                                  @RequestParam int friendType,
+                                                  @RequestParam String search) {
+        log.info("LifeMessageController.getMessageList?receiverId={}, friendType={}, search={}", receiverId, friendType, search);
+        return R.data(lifeMessageService.getMessageList(receiverId, friendType, search));
+    }
+
+    @ApiOperation("未聊过的消息数据")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
+    @GetMapping("/getStrangerMessageNum")
+    public R<LifeMessageVo> getStrangerMessageNum(@RequestParam String receiverId) {
+        log.info("LifeMessageController.getStrangerMessageNum?receiverId={}", receiverId);
+        return R.data(lifeMessageService.getStrangerMessageNum(receiverId));
     }
 
     @ApiOperation("未关注人的消息数据")
-    @ApiOperationSupport(order = 1)
+    @ApiOperationSupport(order = 3)
     @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
     @GetMapping("/getNoFriendMessage")
     public R<LifeMessageVo> getNoFriendMessage(@RequestParam String receiverId) {
@@ -54,7 +64,7 @@ public class LifeMessageController {
     }
 
     @ApiOperation("消息详情")
-    @ApiOperationSupport(order = 2)
+    @ApiOperationSupport(order = 4)
     @ApiImplicitParams({@ApiImplicitParam(name = "当前登录人", value = "receiverId", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/getMessageListByReceiverId")
     public R<List<LifeMessageVo>> getMessageListByReceiverId(@RequestParam String receiverId, @RequestParam String senderId) {
@@ -63,7 +73,7 @@ public class LifeMessageController {
     }
 
     @ApiOperation("消息已读")
-    @ApiOperationSupport(order = 3)
+    @ApiOperationSupport(order = 5)
     @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/read")
     public R<Boolean> read(@RequestParam String receiverId, @RequestParam String senderId) {
@@ -73,7 +83,7 @@ public class LifeMessageController {
     }
 
     @ApiOperation("未读消息数量")
-    @ApiOperationSupport(order = 4)
+    @ApiOperationSupport(order = 6)
     @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
     @GetMapping("/noReadCount")
     public R<Integer> noReadCount(@RequestParam String receiverId) {
@@ -82,7 +92,7 @@ public class LifeMessageController {
     }
 
     @ApiOperation("删除消息")
-    @ApiOperationSupport(order = 5)
+    @ApiOperationSupport(order = 7)
     @ApiImplicitParams({@ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
     @GetMapping("/deleteMessageByPhoneId")
     public R<Integer> deleteMessageByPhoneId(@RequestParam String senderId, @RequestParam String receiverId) {

+ 9 - 9
alien-store/src/main/java/shop/alien/store/controller/LifeNoticeController.java

@@ -12,6 +12,8 @@ import shop.alien.entity.store.vo.LifeNoticeVo;
 import shop.alien.mapper.LifeNoticeMapper;
 import shop.alien.store.service.LifeNoticeService;
 
+import java.util.List;
+
 @Api(tags = {"一期-公告"})
 @Slf4j
 @RestController
@@ -27,15 +29,13 @@ public class LifeNoticeController {
     @GetMapping("/getNoticeByPhoneId")
     @ApiOperation("通知列表")
     @ApiOperationSupport(order = 1)
-    @ApiImplicitParams({@ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
-            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = true),
-            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
-    public R<IPage<LifeNoticeVo>> getNoticeByPhoneId(@RequestParam String receiverId,
-                                                     @RequestParam(defaultValue = "0") int noticeType,
-                                                     @RequestParam(defaultValue = "1") int page,
-                                                     @RequestParam(defaultValue = "10") int size) {
-        log.info("LifeNoticeController.getNoticeByPhoneId?receiverId={},page={},size={}, noticeType={}", receiverId, page, size, noticeType);
-        return R.data(lifeNoticeService.getNoticeList(receiverId, noticeType, page, size));
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "noticeType", value = "0-系统通知和订单提醒之外的类型 1-系统通知 2-订单提醒", dataType = "Integer", paramType = "query")})
+    public R<List<LifeNoticeVo>> getNoticeByPhoneId(@RequestParam String receiverId,
+                                                    @RequestParam(defaultValue = "0") int noticeType) {
+        log.info("LifeNoticeController.getNoticeByPhoneId?receiverId={}, noticeType={}", receiverId, noticeType);
+        return R.data(lifeNoticeService.getNoticeList(receiverId, noticeType));
     }
 
     @GetMapping("/getSystemAndOrderNoticeSum")

+ 2 - 2
alien-store/src/main/java/shop/alien/store/controller/WebAuditController.java

@@ -54,8 +54,8 @@ public class WebAuditController {
 
     @ApiOperation("平台处理审核退款等埋点")
     @PostMapping("/platformAuditRefundTrack")
-    public Integer platformAuditRefundTrack(@RequestBody WebAudit webAudit) {
-        return webAuditService.platformAuditRefundTrack(webAudit);
+    public R platformAuditRefundTrack(@RequestBody WebAudit webAudit) {
+        return webAuditService.platformAuditRefundTrack(webAudit) > 0 ? R.success("成功") : R.fail("失败");
     }
 
 }

+ 5 - 1
alien-store/src/main/java/shop/alien/store/service/LifeMessageService.java

@@ -9,7 +9,9 @@ import java.util.List;
 
 public interface LifeMessageService extends IService<LifeMessage> {
 
-    IPage<LifeMessageVo> getMessageList(String receiverId, int page, int size, int friendType);
+    List<LifeMessageVo> getMessageList(String receiverId, int friendType, String search);
+
+    LifeMessageVo getStrangerMessageNum(String receiverId);
 
     LifeMessageVo getNoFriendMessageNum(String receiverId);
 
@@ -20,4 +22,6 @@ public interface LifeMessageService extends IService<LifeMessage> {
     int noReadCount(String receiverId);
 
     int deleteMessageByPhoneId(String senderId, String receiverId);
+
+    boolean notDisturb(String receiverId, int disturbId, int type);
 }

+ 3 - 1
alien-store/src/main/java/shop/alien/store/service/LifeNoticeService.java

@@ -6,9 +6,11 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.store.LifeNotice;
 import shop.alien.entity.store.vo.LifeNoticeVo;
 
+import java.util.List;
+
 public interface LifeNoticeService extends IService<LifeNotice> {
 
-    IPage<LifeNoticeVo> getNoticeList(String receiverId, int noticeType, int page, int size);
+    List<LifeNoticeVo> getNoticeList(String receiverId, int noticeType);
 
     JSONObject getSystemAndOrderNoticeSum(String receiverId);
 

+ 122 - 47
alien-store/src/main/java/shop/alien/store/service/impl/LifeMessageServiceImpl.java

@@ -6,9 +6,11 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.pagehelper.util.StringUtil;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.LifeFansVo;
 import shop.alien.entity.store.vo.LifeMessageVo;
@@ -17,9 +19,11 @@ import shop.alien.mapper.LifeMessageMapper;
 import shop.alien.mapper.LifeUserMapper;
 import shop.alien.store.service.LifeMessageService;
 import shop.alien.store.service.LifeUserService;
+import shop.alien.util.common.JwtUtil;
 
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 @Service
@@ -37,43 +41,77 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
 
 
     @Override
-    public IPage<LifeMessageVo> getMessageList(String receiverId, int page, int size, int friendType) {
+    public List<LifeMessageVo> getMessageList(String receiverId, int friendType, String search) {
         // 查询所有好友
+//        QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
+//        wrapper.groupBy("foll.phoneId");
+
+//        if ("user".equals(receiverId.split("_")[0])) {
+//            String myselfUserPhone = receiverId.split("_")[1];
+//            blockerType = "2";
+//            LifeUser myLifeUser = lifeUserService.getUserByPhone(myselfUserPhone);
+//            blockerId = String.valueOf(myLifeUser.getId());
+//        } else {
+//            String myselfStorePhone = receiverId.split("_")[1];
+//            blockerType = "1";
+//            StoreUser myStoreUser = storeUserService.getUserByPhone(myselfStorePhone);
+//            blockerId = String.valueOf(myStoreUser.getId());
+//        }
+
+//        List<LifeFansVo> lifeFansList = lifeFansMapper.getMutualAttention(new Page<>(1, Integer.MAX_VALUE), receiverId, blockerType, blockerId, wrapper).getRecords();
+//        List<String> friendsIds = lifeFansList.stream().map(LifeFansVo::getPhoneId).filter(item -> !item.equals(receiverId)).collect(Collectors.toList());
+//        String friendsIdsStr = "'" + String.join("','", friendsIds) + "'";
+
+//        wrapper = new QueryWrapper<>();
+//        wrapper.eq("num", 1);
+//        if (1 == friendType) {
+//            // 当前用户的所有好友消息
+//            wrapper.apply("(sender_id in (" + friendsIdsStr + ") or receiver_id in (" + friendsIdsStr + "))");
+//        } else {
+//            // 当前用户的所有未关注人消息
+//            wrapper.apply("(sender_id not in (" + friendsIdsStr + ") and receiver_id not in (" + friendsIdsStr + "))");
+//        }
+
+        String blockerType = "user".equals(Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getString("userType")) ? "2" : "1";
+        String blockerId = JwtUtil.getCurrentUserInfo().getString("userId");
         QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
-        wrapper.groupBy("foll.phoneId");
-        String blockerType = "";
-        String blockerId = "";
-        if ("user".equals(receiverId.split("_")[0])) {
-            String myselfUserPhone = receiverId.split("_")[1];
-            blockerType = "2";
-            LifeUser myLifeUser = lifeUserService.getUserByPhone(myselfUserPhone);
-            blockerId = String.valueOf(myLifeUser.getId());
-        } else {
-            String myselfStorePhone = receiverId.split("_")[1];
-            blockerType = "1";
-            StoreUser myStoreUser = storeUserService.getUserByPhone(myselfStorePhone);
-            blockerId = String.valueOf(myStoreUser.getId());
+        wrapper.eq("message.num", 1);
+        // 过滤拉黑
+        wrapper.apply("(user.id not in ( " +
+                            "     select blocked_id from life_blacklist " +
+                            "     where blocker_type = '" + blockerType + "' and blocker_id = '" + blockerId + "' and blocked_type = '2' and delete_flag = 0 " +
+                            ") or user.id is null)");
+        wrapper.apply("(suser.id not in ( " +
+                            "     select blocked_id from life_blacklist " +
+                            "     where blocker_type = '" + blockerType + "' and blocker_id = '" + blockerId + "' and blocked_type = '1' and delete_flag = 0 " +
+                            ") or suser.id is null)");
+
+        // 通过搜索查询的情况下  不区分是否聊过  搜索所有消息
+        if (0 == friendType && StringUtil.isNotEmpty(search)) {
+            wrapper.apply("(user.user_name like '%" + search + "%' or suser.name like '%" + search + "%')");
+        // 聊过
+        } else if (1 == friendType) {
+            wrapper.apply("message.phoneId in ( " +
+                    "    select receiver_id " +
+                    "    from life_message " +
+                    "    where sender_id = '" + receiverId + "'" +
+                    "    group by receiver_id " +
+                    ")");
+        // 没聊过
+        } else if (2 == friendType) {
+            wrapper.apply("message.phoneId not in ( " +
+                    "    select receiver_id " +
+                    "    from life_message " +
+                    "    where sender_id = '" + receiverId + "'" +
+                    "    group by receiver_id " +
+                    ")");
         }
-
-        List<LifeFansVo> lifeFansList = lifeFansMapper.getMutualAttention(new Page<>(1, Integer.MAX_VALUE), receiverId, blockerType, blockerId, wrapper).getRecords();
-        List<String> friendsIds = lifeFansList.stream().map(LifeFansVo::getPhoneId).filter(item -> !item.equals(receiverId)).collect(Collectors.toList());
-        String friendsIdsStr = "'" + String.join("','", friendsIds) + "'";
-
-        wrapper = new QueryWrapper<>();
-        wrapper.eq("num", 1);
-        if (1 == friendType) {
-            // 当前用户的所有好友消息
-            wrapper.apply("(sender_id in (" + friendsIdsStr + ") or receiver_id in (" + friendsIdsStr + "))");
-        } else {
-            // 当前用户的所有未关注人消息
-            wrapper.apply("(sender_id not in (" + friendsIdsStr + ") and receiver_id not in (" + friendsIdsStr + "))");
-        }
-        wrapper.orderByDesc("created_time");
-        IPage<LifeMessageVo> ipage = new Page<>(page, size);
-        IPage<LifeMessageVo> lifeMessagePageList = messageMapper.getLifeMessagePageByPhoneId(ipage, receiverId, wrapper);
-        if (!CollectionUtils.isEmpty(lifeMessagePageList.getRecords())) {
+        wrapper.orderByDesc("message.created_time");
+//        IPage<LifeMessageVo> ipage = new Page<>(page, size);
+        List<LifeMessageVo> lifeMessagePageList = messageMapper.getLifeMessagePageByPhoneId(receiverId, wrapper);
+        if (!CollectionUtils.isEmpty(lifeMessagePageList)) {
             // 取出所有发送消息的用户
-            List<String> phoneIdList = lifeMessagePageList.getRecords().stream().map(LifeMessageVo::getPhoneId).filter(item -> item.contains("_")).collect(Collectors.toList());
+//            List<String> phoneIdList = lifeMessagePageList.stream().map(LifeMessageVo::getPhoneId).filter(item -> item.contains("_")).collect(Collectors.toList());
 
             // 当前用户的所有关注
             LambdaQueryWrapper<LifeFans> followWrapper = new LambdaQueryWrapper<>();
@@ -97,18 +135,18 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
             messageWrapper.eq(LifeMessage::getDeleteFlag, 0);
             List<LifeMessage> noReadList = messageMapper.selectList(messageWrapper);
 
-            // 根据手机号查询发送人信息
-            List<String> storePhoneList = phoneIdList.stream().filter(item -> "store".equals(item.split("_")[0])).map(item -> item.split("_")[1]).collect(Collectors.toList());
-            List<String> userPhoneList = phoneIdList.stream().filter(item -> "user".equals(item.split("_")[0])).map(item -> item.split("_")[1]).collect(Collectors.toList());
-            String storePhones = "'" + String.join("','", storePhoneList) + "'";
-            String userPhones = "'" + String.join("','", userPhoneList) + "'";
-            List<LifeMessageVo> userList = messageMapper.getLifeUserAndStoreUserByPhone(storePhones, userPhones);
+//            // 根据手机号查询发送人信息
+//            List<String> storePhoneList = phoneIdList.stream().filter(item -> "store".equals(item.split("_")[0])).map(item -> item.split("_")[1]).collect(Collectors.toList());
+//            List<String> userPhoneList = phoneIdList.stream().filter(item -> "user".equals(item.split("_")[0])).map(item -> item.split("_")[1]).collect(Collectors.toList());
+//            String storePhones = "'" + String.join("','", storePhoneList) + "'";
+//            String userPhones = "'" + String.join("','", userPhoneList) + "'";
+//            List<LifeMessageVo> userList = messageMapper.getLifeUserAndStoreUserByPhone(storePhones, userPhones);
 
-            for (LifeMessageVo messageVo : lifeMessagePageList.getRecords()) {
-                // 发送人信息
-                LifeMessageVo user = userList.stream().filter(item -> item.getPhoneId().equals(messageVo.getPhoneId())).findFirst().orElse(null);
-                messageVo.setUserName(null == user ? "" : user.getUserName());
-                messageVo.setUserImage(null == user ? "" : user.getUserImage());
+            for (LifeMessageVo messageVo : lifeMessagePageList) {
+//                // 发送人信息
+//                LifeMessageVo user = userList.stream().filter(item -> item.getPhoneId().equals(messageVo.getPhoneId())).findFirst().orElse(null);
+//                messageVo.setUserName(null == user ? "" : user.getUserName());
+//                messageVo.setUserImage(null == user ? "" : user.getUserImage());
 
                 // 未读消息数量
                 messageVo.setNotReadCount(noReadList.stream().filter(item -> item.getSenderId().equals(messageVo.getPhoneId())).count());
@@ -137,11 +175,43 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
             }
         }
 
-
         return lifeMessagePageList;
     }
 
     @Override
+    public LifeMessageVo getStrangerMessageNum(String receiverId) {
+        String blockerType = "user".equals(Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getString("userType")) ? "2" : "1";
+        String blockerId = JwtUtil.getCurrentUserInfo().getString("userId");
+        QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
+        // 过滤拉黑
+        wrapper.apply("(user.id not in ( " +
+                "     select blocked_id from life_blacklist " +
+                "     where blocker_type = '" + blockerType + "' and blocker_id = '" + blockerId + "' and blocked_type = '2' and delete_flag = 0 " +
+                ") or user.id is null)");
+        wrapper.apply("(suser.id not in ( " +
+                "     select blocked_id from life_blacklist " +
+                "     where blocker_type = '" + blockerType + "' and blocker_id = '" + blockerId + "' and blocked_type = '1' and delete_flag = 0 " +
+                ") or suser.id is null)");
+        // 没聊过
+        wrapper.apply("message.phoneId not in ( " +
+                "    select receiver_id " +
+                "    from life_message " +
+                "    where sender_id = '" + receiverId + "'" +
+                "    group by receiver_id " +
+                ")");
+        wrapper.orderByDesc("message.created_time");
+//        IPage<LifeMessageVo> ipage = new Page<>(1, Integer.MAX_VALUE);
+        List<LifeMessageVo> lifeMessagePageList = messageMapper.getLifeMessagePageByPhoneId(receiverId, wrapper);
+        LifeMessageVo vo = new LifeMessageVo();
+        if (!CollectionUtils.isEmpty(lifeMessagePageList)) {
+            vo.setUserName(lifeMessagePageList.get(0).getUserName());
+            vo.setNotReadCount(lifeMessagePageList.stream().filter(item -> 0 == item.getIsRead()).count());
+        }
+
+        return vo;
+    }
+
+    @Override
     public LifeMessageVo getNoFriendMessageNum(String receiverId) {
         // 查询所有好友
         QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
@@ -169,8 +239,8 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
         wrapper.eq("num", 1);
         wrapper.apply("(sender_id not in (" + friendsIdsStr + ") and receiver_id not in (" + friendsIdsStr + "))");
         wrapper.orderByDesc("created_time");
-        IPage<LifeMessageVo> ipage = new Page<>(1, Integer.MAX_VALUE);
-        List<LifeMessageVo> lifeMessageVoList = messageMapper.getLifeMessagePageByPhoneId(ipage, receiverId, wrapper).getRecords();
+//        IPage<LifeMessageVo> ipage = new Page<>(1, Integer.MAX_VALUE);
+        List<LifeMessageVo> lifeMessageVoList = messageMapper.getLifeMessagePageByPhoneId(receiverId, wrapper);
 
         LifeMessageVo messageVo = lifeMessageVoList.stream().max(Comparator.comparing(LifeMessageVo::getCreatedTime)).orElse(null);
         if (messageVo != null) {
@@ -276,4 +346,9 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
     public int deleteMessageByPhoneId(String senderId, String receiverId) {
         return messageMapper.deleteMessageByPhoneId(senderId, receiverId);
     }
+
+    @Override
+    public boolean notDisturb(String receiverId, int disturbId, int type) {
+        return false;
+    }
 }

+ 15 - 14
alien-store/src/main/java/shop/alien/store/service/impl/LifeNoticeServiceImpl.java

@@ -1,5 +1,6 @@
 package shop.alien.store.service.impl;
 
+import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -30,17 +31,17 @@ public class LifeNoticeServiceImpl extends ServiceImpl<LifeNoticeMapper, LifeNot
     private final LifeMessageMapper lifeMessageMapper;
 
     @Override
-    public IPage<LifeNoticeVo> getNoticeList(String receiverId, int noticeType, int page, int size) {
-        IPage<LifeNotice> ipage = new Page<>(page, size);
+    public List<LifeNoticeVo> getNoticeList(String receiverId, int noticeType) {
+//        IPage<LifeNotice> ipage = new Page<>(page, size);
         LambdaQueryWrapper<LifeNotice> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(LifeNotice::getReceiverId, receiverId);
         queryWrapper.eq(LifeNotice::getNoticeType, noticeType);
         queryWrapper.eq(LifeNotice::getDeleteFlag, 0);
-        IPage<LifeNotice> lifeNoticeList = lifeNoticeMapper.selectPage(ipage, queryWrapper);
+        List<LifeNotice> lifeNoticeList = lifeNoticeMapper.selectList(queryWrapper);
 
         List<String> senderIdList = new ArrayList<>();
-        if (lifeNoticeList != null && lifeNoticeList.getRecords() != null) {
-            senderIdList = lifeNoticeList.getRecords().stream()
+        if (CollectionUtil.isNotEmpty(lifeNoticeList)) {
+            senderIdList = lifeNoticeList.stream()
                     .map(LifeNotice::getSenderId)
                     .filter(item -> item != null && !"system".equals(item) && item.contains("_"))
                     .map(item -> item.split("_")[1])
@@ -52,8 +53,8 @@ public class LifeNoticeServiceImpl extends ServiceImpl<LifeNoticeMapper, LifeNot
         List<LifeMessageVo> userList = lifeMessageMapper.getLifeUserAndStoreUserByPhone(senderIds, "''");
 
         List<LifeNoticeVo> noticeVoList = new ArrayList<>();
-        if (lifeNoticeList != null && lifeNoticeList.getRecords() != null) {
-            lifeNoticeList.getRecords().forEach(item -> {
+        if (CollectionUtil.isNotEmpty(lifeNoticeList)) {
+            lifeNoticeList.forEach(item -> {
                 LifeNoticeVo noticeVo = new LifeNoticeVo();
                 BeanUtils.copyProperties(item, noticeVo);
                 LifeMessageVo userinfo = userList.stream().filter(user -> user.getPhoneId().equals(item.getSenderId())).findFirst().orElse(null);
@@ -65,14 +66,14 @@ public class LifeNoticeServiceImpl extends ServiceImpl<LifeNoticeMapper, LifeNot
             });
         }
 
-        IPage<LifeNoticeVo> result = new Page<>();
-        result.setRecords(noticeVoList);
-        result.setCurrent(lifeNoticeList.getCurrent());
-        result.setSize(lifeNoticeList.getSize());
-        result.setTotal(lifeNoticeList.getTotal());
-        result.setPages(lifeNoticeList.getPages());
+//        IPage<LifeNoticeVo> result = new Page<>();
+//        result.setRecords(noticeVoList);
+//        result.setCurrent(lifeNoticeList.getCurrent());
+//        result.setSize(lifeNoticeList.getSize());
+//        result.setTotal(lifeNoticeList.getTotal());
+//        result.setPages(lifeNoticeList.getPages());
 
-        return result;
+        return noticeVoList;
     }
 
     @Override

+ 5 - 1
alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java

@@ -421,7 +421,11 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
                 StringBuilder imgId = new StringBuilder();
                 for (int i = 0; i < fileNameSet.size(); i++) {
                     MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
-                    if (null != multipartFile) {
+                   //b
+                    System.out.println(multipartFile.getSize());
+                    //kb
+                    System.out.println(multipartFile.getSize() / 1024);
+                    if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
                         byte[] fileByte;
                         try {
                             fileByte = multipartFile.getBytes();

+ 6 - 0
alien-util/pom.xml

@@ -123,6 +123,12 @@
             <artifactId>easyexcel</artifactId>
             <version>1.1.2-beta5</version>
         </dependency>
+        <!--    阿里安全图片/文本检测    -->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>green20220302</artifactId>
+            <version>2.20.0</version>
+        </dependency>
 
         <!--openoffice-->
         <dependency>

+ 173 - 0
alien-util/src/main/java/shop/alien/util/common/safe/ImageModerationUtil.java

@@ -0,0 +1,173 @@
+package shop.alien.util.common.safe;
+import com.alibaba.fastjson.JSON;
+import com.aliyun.green20220302.Client;
+import com.aliyun.green20220302.models.ImageBatchModerationResponse;
+import com.aliyun.green20220302.models.ImageModerationRequest;
+import com.aliyun.green20220302.models.ImageModerationResponse;
+import com.aliyun.green20220302.models.ImageBatchModerationRequest;
+import com.aliyun.green20220302.models.ImageBatchModerationResponse;
+import com.aliyun.green20220302.models.ImageBatchModerationResponseBody;
+import com.aliyun.green20220302.models.ImageModerationResponseBody;
+import com.aliyun.green20220302.models.ImageModerationResponseBody.ImageModerationResponseBodyData;
+import com.aliyun.green20220302.models.ImageModerationResponseBody.ImageModerationResponseBodyDataResult;
+import com.aliyun.teaopenapi.models.Config;
+import com.aliyun.teautil.models.RuntimeOptions;
+import jdk.nashorn.internal.runtime.logging.Logger;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+@Logger
+public class ImageModerationUtil {
+
+    @Value("${ali.yundun.accessKeyID}")
+    private String accessKeyId;
+
+    @Value("${ali.yundun.secret}")
+    private String accessKeySecret;
+
+    @Value("${ali.yundun.imgEndpoint}")
+    private String ImgEndpoint;
+
+    /**
+     * 创建请求客户端
+     * @return  Client
+     * @throws Exception 创建客户端异常
+     */
+    public Client createClient() throws Exception {
+        Config config = new Config();
+        config.setAccessKeyId(accessKeyId);
+        config.setAccessKeySecret(accessKeySecret);
+        // 设置http代理。
+        //config.setHttpProxy("http://10.10.xx.xx:xxxx");
+        // 设置https代理。
+        //config.setHttpsProxy("https://10.10.xx.xx:xxxx");
+        // 接入区域和地址请根据实际情况修改
+        // 接入地址列表:https://help.aliyun.com/document_detail/467828.html?#section-uib-qkw-0c8
+        config.setEndpoint(ImgEndpoint);
+        return new Client(config);
+    }
+
+    /**
+     * 提供给service调用的方法
+     *
+     * @param imageUrl 图片地址
+     * @param serviceEnum Service类型
+     * @return 检测结果
+     * @throws Exception 检测异常
+     */
+    public ImageModerationResponse invokeFunction(String imageUrl,String serviceEnum) throws Exception {
+        //注意,此处实例化的client请尽可能重复使用,避免重复建立连接,提升检测性能。
+        Client client = createClient();
+
+        // 创建RuntimeObject实例并设置运行参数
+        RuntimeOptions runtime = new RuntimeOptions();
+
+        // 检测参数构造。
+        Map<String, String> serviceParameters = new HashMap<>();
+        //公网可访问的URL。
+        serviceParameters.put("imageUrl", imageUrl);
+        //待检测数据唯一标识
+        serviceParameters.put("dataId", UUID.randomUUID().toString());
+
+        ImageModerationRequest request = new ImageModerationRequest();
+        // 图片检测service:内容安全控制台图片增强版规则配置的serviceCode,示例:baselineCheck
+        // 支持service请参考:https://help.aliyun.com/document_detail/467826.html?0#p-23b-o19-gff
+        request.setService(serviceEnum);
+        request.setServiceParameters(JSON.toJSONString(serviceParameters));
+
+        ImageModerationResponse response = null;
+        try {
+            response = client.imageModerationWithOptions(request, runtime);
+        } catch (Exception e) {
+            throw new Exception("调用服务失败" + e.getMessage());
+        }
+        return response;
+    }
+
+    /**
+     * 批量图片检测
+     *
+     * @param imageUrl 图片地址
+     * @param serviceEnum Service类型 服务名逗号拼接
+     * @return 检测结果
+     * @throws Exception 检测异常
+     */
+    public ImageBatchModerationResponse invokeBeachFunction(String imageUrl,String serviceEnum) throws Exception {
+        Client client = createClient();
+        RuntimeOptions runtime = new RuntimeOptions();
+        Map<String, String> serviceParameters = new HashMap<>();
+        serviceParameters.put("imageUrl", imageUrl);
+        serviceParameters.put("dataId", UUID.randomUUID().toString());
+        ImageBatchModerationRequest imageBatchModerationRequest = new ImageBatchModerationRequest();
+        imageBatchModerationRequest.setService(serviceEnum);
+        imageBatchModerationRequest.setServiceParameters(JSON.toJSONString(serviceParameters));
+        ImageBatchModerationResponse response = null;
+        try {
+            response = client.imageBatchModerationWithOptions(imageBatchModerationRequest, runtime);
+        } catch (Exception e) {
+            throw new Exception("调用服务失败" + e.getMessage());
+        }
+        return response;
+    }
+    /**
+     * 发布商品场景检测
+     * 顺序调用内容治理检测、AIGC图片风险检测、图片万物识别
+     *
+     * @param imageUrl 图片地址
+     * @return 检测结果
+     * @throws Exception 检测异常
+     */
+    public ImageBatchModerationResponse productPublishCheck(String imageUrl) throws Exception {
+
+        // 批量服务key
+        String serviceEnum = ImageReviewServiceEnum.TONALITY_IMPROVE.getService() + "," + ImageReviewServiceEnum.AIGC_CHECK.getService() + "," + ImageReviewServiceEnum.GENERAL_RECOGNITION.getService();
+
+        // 批量图片检测
+        ImageBatchModerationResponse response = invokeBeachFunction(imageUrl,serviceEnum);
+        if (response != null) {
+            if (response.getStatusCode() == 200) {
+                ImageBatchModerationResponseBody body = response.getBody();
+                System.out.println("requestId=" + body.getRequestId());
+                System.out.println("code=" + body.getCode());
+                System.out.println("msg=" + body.getMsg());
+                if (body.getCode() == 200) {
+                    ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyData data = body.getData();
+                    System.out.println("dataId=" + data.getDataId());
+                    List<ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResult> results = data.getResult();
+                    for (ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResult result : results) {
+                        System.out.println("label=" + result.getLabel());
+                        System.out.println("confidence=" + result.getConfidence());
+                    }
+                } else {
+                    System.out.println("image moderation not success. code:" + body.getCode());
+                }
+            } else {
+                System.out.println("response not success. status:" + response.getStatusCode());
+            }
+        }
+        return response;
+    }
+
+    /**
+     * 聊一聊场景检测
+     * 顺序调用图片万物识别、内容治理检测
+     *
+     * @param imageUrl 图片地址
+     * @return 检测结果
+     * @throws Exception 检测异常
+     */
+    public ImageBatchModerationResponse chatCheck(String imageUrl) throws Exception {
+        // 批量服务key
+        String serviceEnum = ImageReviewServiceEnum.GENERAL_RECOGNITION.getService() + "," + ImageReviewServiceEnum.TONALITY_IMPROVE.getService();
+
+        // 批量图片检测
+        ImageBatchModerationResponse response = invokeBeachFunction(imageUrl,serviceEnum);
+
+        return response;
+    }
+}

+ 56 - 0
alien-util/src/main/java/shop/alien/util/common/safe/ImageReviewServiceEnum.java

@@ -0,0 +1,56 @@
+package shop.alien.util.common.safe;
+
+/**
+ * 图片审核服务枚举
+ */
+public enum ImageReviewServiceEnum {
+
+    BASELINE_CHECK("baselineCheck", "通用基线检测", "检测图片中是否存在色情、涉政、暴恐、违禁等红线类的违规内容。", "通用场景"),
+    BASELINE_CHECK_PRO("baselineCheck_pro", "通用基线检测_专业版", "在通用基线检测的基础上支持更细粒度的标签返回。", "通用场景"),
+    TONALITY_IMPROVE("tonalityImprove", "内容治理检测", "检测图片中是否存在广告引流、不良引导、辱骂等影响平台秩序、内容调性或影响用户体验的内容。", "通用场景"),
+    PROFILE_PHOTO_CHECK("profilePhotoCheck", "头像图片检测", "检测头像中是否存在违规、不宜传播或者影响平台秩序的内容。建议对头像场景的图片均进行该项检测。", "业务场景"),
+    POST_IMAGE_CHECK("postImageCheck", "帖子评论图片检测", "检测帖子中图片或者评论中图片是否存在违规、不宜传播或者影响平台秩序的内容。建议对贴图评论场景的图片均进行该项检测。", "业务场景"),
+    AIGC_CHECK("aigcCheck", "AIGC图片风险检测", "针对AIGC场景,检测AIGC生成的图片是否存在违规或者不宜传播的内容。建议AIGC生成的图片都进行该项检测。", "AIGC场景"),
+    AIGC_DETECTOR("aigcDetector", "AIGC图片生成判定", "针对各种场景,判断图片是否由AIGC生成。建议需要对图片的来源进行标识时使用。", "AIGC场景"),
+    AIGC_DETECTOR_PRO("aigcDetector_pro", "AIGC图片生成判定_专业版", "在判断图片是否由AIGC生成的基础上,增加判断图片是否疑似合成,是否有PS痕迹的检测能力。", "AIGC场景"),
+    AIGC_VIOLATION_DETECTION("aigcViolationDetection", "AIGC图片侵权检测", "针对AIGC场景,检测AIGC生成的图片是否存在侵权风险。建议AIGC生成的用于素材、宣传类的图片都进行该项检测。", "AIGC场景"),
+    ADVERTISING_CHECK("advertisingCheck", "营销素材检测", "针对有推广含义的图片(包括商品图、详情介绍页、投放营销的素材等)进行专门优化,检测是否有违反广告法以及其他违规或不宜传播的内容。", "业务场景"),
+    LIVE_STREAM_CHECK("liveStreamCheck", "视频\\直播截图检测", "检测视频/直播画面是否存在违规或不宜传播的内容。建议对涉及开放公网访问的视频/直播画面均可截图进行该项检测。", "业务场景"),
+    POST_IMAGE_CHECK_BY_VL("postImageCheckByVL", "大小模型融合图片审核服务", "综合应用图片审核大模型和专家模型能力,能够全方位识别图片中的色情、性感、涉政、暴恐、违禁、宗教、引流广告、不良等违规内容。", "通用场景"),
+    BASELINE_CHECK_BY_VL("baselineCheckByVL", "通用图片审核大模型服务", "基于图片审核场景定制训练的审核大模型,能够识别图片中的涉黄、涉政、暴恐、违禁、不良、辱骂、广告等风险。支持返回大模型的原始结果。", "通用场景"),
+    OSS_BASELINE_CHECK("oss_baselineCheck", "OSS基线检测(OSS普惠版专用)", "适用于OSS检测图片中是否存在违规或不宜传播的内容,包含对黑产类图片识别能力。", "通用场景"),
+    BAILIAN_QUERY_IMAGE_CHECK("bailianQueryImageCheck", "百炼输入图片检测", "百炼图片输入场景专用,检测图片中是否存在色情、性感、涉政、暴恐、违禁、宗教、广告引流、特殊标识、行为、特定物体、不良等违规内容。", "百炼场景"),
+    BAILIAN_RESPONSE_IMAGE_CHECK("bailianResponseImageCheck", "百炼生成图片检测", "百炼图片输出场景专用,检测图片中是否存在色情、性感、涉政、暴恐、违禁、宗教、广告引流、特殊标识、行为、特定物体、不良等违规内容。", "百炼场景"),
+    GENERAL_RECOGNITION("generalRecognition", "图片万物识别", "基于大模型能力,能识别图片中的多种元素并返回元素标签和置信度。", "特殊场景"),
+    IMG_QUERY_SECURITY_CHECK("img_query_security_check", "cts.pictureReviews.ruleConfig.service.img_query_security_check", "cts.pictureReviews.ruleConfig.service.description.img_query_security_check", "--"),
+    IMG_RESPONSE_SECURITY_CHECK("img_response_security_check", "cts.pictureReviews.ruleConfig.service.img_response_security_check", "cts.pictureReviews.ruleConfig.service.description.img_response_security_check", "--"),
+    RISK_DETECTION("riskDetection", "恶意图片检测", "检测图片中隐藏的视频、播放器等风险内容。建议在存储图片和CDN流量发现异常,疑似被黑产攻击时调用。", "特殊场景");
+
+    private final String service;
+    private final String serviceName;
+    private final String serviceDescription;
+    private final String serviceScene;
+
+    ImageReviewServiceEnum(String service, String serviceName, String serviceDescription, String serviceScene) {
+        this.service = service;
+        this.serviceName = serviceName;
+        this.serviceDescription = serviceDescription;
+        this.serviceScene = serviceScene;
+    }
+
+    public String getService() {
+        return service;
+    }
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public String getServiceDescription() {
+        return serviceDescription;
+    }
+
+    public String getServiceScene() {
+        return serviceScene;
+    }
+}

+ 23 - 0
alien-util/src/main/java/shop/alien/util/common/safe/TextModerationResultVO.java

@@ -0,0 +1,23 @@
+package shop.alien.util.common.safe;
+
+import lombok.Data;
+
+/**
+ * 文本审核结果返回值对象
+ */
+@Data
+public class TextModerationResultVO {
+    private Integer code;
+    private String message;
+    
+    // 以下字段对应原始data对象中的属性
+    private String labels; // 标签
+    private String reason; // 原因(JSON字符串)
+
+    // 扁平化的风险信息字段
+    private String riskLevel; // 风险等级
+    private String riskTips; // 细分标签
+    private String riskWords; // 命中风险内容
+    private String customizedWords; // 命中用户词
+    private String customizedLibs; // 命中用户词库名
+}

+ 170 - 0
alien-util/src/main/java/shop/alien/util/common/safe/TextModerationUtil.java

@@ -0,0 +1,170 @@
+package shop.alien.util.common.safe;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.green20220302.Client;
+import com.aliyun.green20220302.models.ImageModerationResponse;
+import com.aliyun.green20220302.models.TextModerationPlusRequest;
+import com.aliyun.green20220302.models.TextModerationPlusResponse;
+import com.aliyun.green20220302.models.TextModerationPlusResponseBody;
+import com.aliyun.teaopenapi.models.Config;
+import org.springframework.beans.factory.annotation.Value;
+
+public class TextModerationUtil {
+
+
+    @Value("${ali.yundun.accessKeyID}")
+    private String accessKeyId;
+
+    @Value("${ali.yundun.secret}")
+    private String accessKeySecret;
+
+    @Value("${ali.yundun.textEndpoint}")
+    private String textEndpoint;
+
+    @Value("${ali.yundun.regionId}")
+    private String regionId;
+
+    /**
+     * 创建请求客户端
+     * @return  Client
+     * @throws Exception 创建客户端异常
+     */
+    public Client createClient() throws Exception {
+        Config config = new Config();
+        config.setAccessKeyId(accessKeyId);
+        config.setAccessKeySecret(accessKeySecret);
+        //接入区域和地址请根据实际情况修改
+        config.setRegionId(regionId);
+        config.setEndpoint(textEndpoint);
+        //读取时超时时间,单位毫秒(ms)。
+        config.setReadTimeout(6000);
+        //连接时超时时间,单位毫秒(ms)。
+        config.setConnectTimeout(3000);
+        //设置http代理。
+        //config.setHttpProxy("http://xx.xx.xx.xx:xxxx");
+        //设置https代理。
+        //config.setHttpsProxy("https://xx.xx.xx.xx:xxxx");
+        return new Client(config);
+    }
+
+    /**
+     * 根据业务类型执行文本审核
+     * @param text 待审核文本
+     * @param services 文本审核服务枚举
+     * @return 审核结果VO
+     * @throws Exception 调用服务异常
+     */
+    public TextModerationResultVO invokeFunction(String text, ImageReviewServiceEnum... services) throws Exception {
+        if (services == null || services.length == 0) {
+            throw new IllegalArgumentException("至少需要一个审核服务");
+        }
+
+        Client client = createClient();
+        
+        TextModerationResultVO resultVO = new TextModerationResultVO();
+        
+        // 存储风险等级和原因的字符串
+        StringBuilder riskTipsBuilder = new StringBuilder();
+        StringBuilder riskWordsBuilder = new StringBuilder();
+        StringBuilder customizedWordsBuilder = new StringBuilder();
+        StringBuilder customizedLibsBuilder = new StringBuilder();
+        String highestRiskLevel = "low"; // 默认最低风险等级
+        
+        try {
+            for (ImageReviewServiceEnum service : services) {
+                TextModerationPlusRequest textModerationPlusRequest = new TextModerationPlusRequest();
+                textModerationPlusRequest.setService(service.getService());
+                
+                // 构建服务参数
+                textModerationPlusRequest.setServiceParameters(buildServiceParameters(text));
+                
+                TextModerationPlusResponse response = client.textModerationPlus(textModerationPlusRequest);
+                if (response.getStatusCode() == 200) {
+                    TextModerationPlusResponseBody result = response.getBody();
+                    
+                    if (200 == result.getCode()) {
+                        // 解析审核结果
+                        TextModerationPlusResponseBody.TextModerationPlusResponseBodyData data = result.getData();
+
+                        // 解析审核结果
+                        JSONObject dataJson = JSON.parseObject(JSON.toJSONString(result.getData()));
+                        String labels = dataJson.getString("labels");
+                        String reason = dataJson.getString("reason");
+
+                        // 解析风险等级和详细信息
+                        JSONObject reasonJson = JSON.parseObject(reason);
+                        String riskLevel = reasonJson.getString("riskLevel");
+                        String riskTip = reasonJson.getString("riskTips");
+                        String riskWord = reasonJson.getString("riskWords");
+                        String customizedWord = reasonJson.getString("customizedWords");
+                        String customizedLib = reasonJson.getString("customizedLibs");
+                        
+                        // 如果存在风险信息,则添加到构建器中
+                        if (riskTip != null && !riskTip.isEmpty()) {
+                            if (riskTipsBuilder.length() > 0) {
+                                riskTipsBuilder.append(", ");
+                            }
+                            riskTipsBuilder.append(riskTip);
+                        }
+                        
+                        if (riskWord != null && !riskWord.isEmpty()) {
+                            if (riskWordsBuilder.length() > 0) {
+                                riskWordsBuilder.append(", ");
+                            }
+                            riskWordsBuilder.append(riskWord);
+                        }
+                        
+                        if (customizedWord != null && !customizedWord.isEmpty()) {
+                            if (customizedWordsBuilder.length() > 0) {
+                                customizedWordsBuilder.append(", ");
+                            }
+                            customizedWordsBuilder.append(customizedWord);
+                        }
+                        
+                        if (customizedLib != null && !customizedLib.isEmpty()) {
+                            if (customizedLibsBuilder.length() > 0) {
+                                customizedLibsBuilder.append(", ");
+                            }
+                            customizedLibsBuilder.append(customizedLib);
+                        }
+                        
+                        // 判断风险等级优先级
+                        if (riskLevel != null) {
+                            if (riskLevel.equals("high") && !highestRiskLevel.equals("high")) {
+                                highestRiskLevel = "high";
+                            } else if (riskLevel.equals("medium") && highestRiskLevel.equals("low")) {
+                                highestRiskLevel = "medium";
+                            }
+                        }
+                        
+                        // 设置基础信息
+                        resultVO.setLabels(labels);
+                    }
+                }
+            }
+            
+            // 设置结果VO
+            resultVO.setCode(200);
+            resultVO.setMessage("OK");
+            resultVO.setRiskLevel(highestRiskLevel);
+            resultVO.setRiskTips(riskTipsBuilder.toString());
+            resultVO.setRiskWords(riskWordsBuilder.toString());
+            resultVO.setCustomizedWords(customizedWordsBuilder.toString());
+            resultVO.setCustomizedLibs(customizedLibsBuilder.toString());
+            
+        } catch (Exception e) {
+            resultVO.setCode(500);
+            resultVO.setMessage("调用服务失败: " + e.getMessage());
+        }
+        
+        return resultVO;
+    }
+
+
+    private String buildServiceParameters(String text) {
+        // 创建服务参数JSON
+        JSONObject serviceParameters = new JSONObject();
+        serviceParameters.put("content", text);
+        return serviceParameters.toJSONString();
+    }
+}

+ 26 - 0
alien-util/src/main/java/shop/alien/util/common/safe/TextReviewServiceEnum.java

@@ -0,0 +1,26 @@
+package shop.alien.util.common.safe;
+
+import jdk.nashorn.internal.runtime.logging.Logger;
+import lombok.Getter;
+
+/**
+ * @author Alien
+ * @date 2021/09/05
+ */
+@Getter
+@Logger
+public enum TextReviewServiceEnum {
+    SPAM("spam"),
+    AD("ad"),
+    POLITICS("politics"),
+    ABUSE("abuse"),
+    VIOLENCE("violence"),
+    PORNOGRAPHY("pornography");
+
+    private final String service;
+
+    TextReviewServiceEnum(String service) {
+        this.service = service;
+    }
+
+}