Răsfoiți Sursa

feat:门店头图(版本:1225):商户未上传头图的场合,上传头图保存时,反应时间太慢了

panzhilin 16 ore în urmă
părinte
comite
06aa9bee6c

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

@@ -1,6 +1,5 @@
 package shop.alien.store.controller;
 
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -10,9 +9,6 @@ import shop.alien.entity.store.StoreImg;
 import shop.alien.entity.store.vo.StoreImgInfoVo;
 import shop.alien.entity.store.vo.StoreImgTypeVo;
 import shop.alien.store.service.StoreImgService;
-import shop.alien.store.service.StoreInfoService;
-import shop.alien.store.util.GroupConstant;
-import shop.alien.store.util.ai.AiImageColorExtractUtil;
 
 import java.util.List;
 
@@ -31,8 +27,6 @@ import java.util.List;
 @RequiredArgsConstructor
 public class StoreImgController {
     private final StoreImgService storeImgService;
-    private final StoreInfoService storeInfoService;
-    private final AiImageColorExtractUtil aiImageColorExtractUtil;
 
     @ApiOperation("获取图片")
     @ApiOperationSupport(order = 1)
@@ -73,117 +67,8 @@ public class StoreImgController {
     @PostMapping("/saveOrUpdateImg")
     public R<String> saveOrUpdateImg(@RequestBody StoreImgInfoVo storeImgInfoVo) {
         log.info("StoreImgController.saveOrUpdateImg?storeImgInfoVo={}", storeImgInfoVo);
-        List<StoreImg> storeImgList = storeImgInfoVo.getStoreImgList();
-        if (storeImgInfoVo.getStoreId()==null || storeImgInfoVo.getImgType()==null) {
-            return R.fail("失败");
-        }
-        
-        // 判断是否是头图(20:单图模式, 21:多图模式)
-        Integer imgType = storeImgInfoVo.getImgType();
-        boolean isHeadImage = (imgType == 20 || imgType == 21);
-        
-        // 清空storeid,imgType下图片
-        int deleteCount = storeImgService.saveOrUpdateImg(storeImgInfoVo.getStoreId(),storeImgInfoVo.getImgType());
-        log.info("StoreImgController.updateStoreImgModeInfo?deleteCount={}", deleteCount);
-        int result = storeInfoService.updateStoreImgModeInfo(storeImgInfoVo);
-        log.info("StoreImgController.updateStoreImgModeInfo?result={}", result);
-        
-        if(!CollectionUtils.isEmpty(storeImgList)){
-            // 判断是否为多图模式
-            boolean isMultiMode = imgType != null && imgType.equals(GroupConstant.IMG_TYPE_MULTI_MODE);
-            
-            // 如果是多图模式,需要找到第一张图片(imgSort最小的)
-            StoreImg firstImg = null;
-            if (isMultiMode) {
-                firstImg = storeImgList.stream()
-                        .filter(img -> img != null && img.getImgUrl() != null)
-                        .min((img1, img2) -> {
-                            Integer sort1 = img1.getImgSort() != null ? img1.getImgSort() : Integer.MAX_VALUE;
-                            Integer sort2 = img2.getImgSort() != null ? img2.getImgSort() : Integer.MAX_VALUE;
-                            return sort1.compareTo(sort2);
-                        })
-                        .orElse(null);
-            }
-            
-            // 遍历图片列表,设置图片描述,并根据条件提取颜色
-            for (StoreImg storeImg : storeImgList) {
-                if (storeImg != null && storeImg.getImgUrl() != null) {
-                    // 根据图片类型设置图片描述
-                    String imgDescription = getImgDescriptionByType(imgType);
-                    if (imgDescription != null) {
-                        storeImg.setImgDescription(imgDescription);
-                    }
-                    
-                    // 只有当 is_extract=1 时才提取颜色
-                    Integer isExtract = storeImg.getIsExtract();
-                    if (isExtract != null && isExtract == 1) {
-                        // 如果是多图模式,只对第一张图片提取颜色
-                        if (isMultiMode) {
-                            // 判断是否为第一张图片(通过比较imgSort,如果imgSort相同则认为是同一张图片)
-                            boolean isFirstImg = firstImg != null && 
-                                    firstImg.getImgSort() != null && 
-                                    storeImg.getImgSort() != null && 
-                                    firstImg.getImgSort().equals(storeImg.getImgSort());
-                            
-                            if (isFirstImg) {
-                                log.info("多图模式,检测到需要提取第一张图片颜色,imgUrl: {}, imgSort: {}, isExtract: {}", 
-                                        storeImg.getImgUrl(), storeImg.getImgSort(), isExtract);
-                                extractColorForImg(storeImg);
-                            } else {
-                                log.info("多图模式,跳过非第一张图片的颜色提取,imgUrl: {}, imgSort: {}", 
-                                        storeImg.getImgUrl(), storeImg.getImgSort());
-                                // 非第一张图片,保持 is_extract 为 1,但不提取颜色
-                            }
-                        } else {
-                            // 单图模式,正常提取颜色
-                            log.info("单图模式,检测到需要提取图片颜色,imgUrl: {}, isExtract: {}", storeImg.getImgUrl(), isExtract);
-                            extractColorForImg(storeImg);
-                        }
-                    }
-                }
-            }
-            Integer id = storeImgList.get(0).getId();
-            if (storeImgService.saveOrUpdateBatch(storeImgList)) {
-                // 如果是头图,设置审核状态为通过(1),前端已完成门头图识别
-                if (isHeadImage) {
-                    // 有头图,设置为审核通过状态(1)
-                    try {
-                        storeInfoService.updateHeadImgStatus(storeImgInfoVo.getStoreId(), 1);
-                        log.info("头图保存成功,设置审核状态为通过,storeId={}", storeImgInfoVo.getStoreId());
-                    } catch (Exception e) {
-                        log.error("更新头图审核状态失败,storeId={}, error={}", 
-                                storeImgInfoVo.getStoreId(), e.getMessage(), e);
-                    }
-                }
-                if (null != id) {
-                    return R.success("修改成功");
-                }
-                return R.success("新增成功");
-            } else {
-                // 图片保存失败,如果是头图,设置审核状态为不通过
-                if (isHeadImage) {
-                    try {
-                        storeInfoService.updateHeadImgStatus(storeImgInfoVo.getStoreId(), 2);
-                        log.info("图片保存失败,更新头图审核状态为不通过,storeId={}", storeImgInfoVo.getStoreId());
-                    } catch (Exception e) {
-                        log.error("更新头图审核状态失败,storeId={}, error={}", 
-                                storeImgInfoVo.getStoreId(), e.getMessage(), e);
-                    }
-                }
-            }
-        } else {
-            // 如果是头图且没有图片,设置审核状态为不通过
-            if (isHeadImage) {
-                try {
-                    storeInfoService.updateHeadImgStatus(storeImgInfoVo.getStoreId(), 2);
-                } catch (Exception e) {
-                    log.error("更新头图审核状态失败,storeId={}, error={}", 
-                            storeImgInfoVo.getStoreId(), e.getMessage(), e);
-                }
-            }
-            return R.success("保存成功");
-        }
-        return R.fail("失败");
+        // 调用Service层处理业务逻辑
+        return storeImgService.saveOrUpdateImgWithInfo(storeImgInfoVo);
     }
 
 
@@ -225,45 +110,4 @@ public class StoreImgController {
         return R.data(storeImgService.getByBusinessId(storeId, imgType, businessId));
     }
 
-    /**
-     * 根据图片类型获取图片描述
-     *
-     * @param imgType 图片类型
-     * @return 图片描述
-     */
-    private String getImgDescriptionByType(Integer imgType) {
-        if (imgType == null) {
-            return null;
-        }
-        switch (imgType) {
-            case 20:
-                return "头图单图模式";
-            case 21:
-                return "头图多图模式";
-            default:
-                return null;
-        }
-    }
-
-    /**
-     * 提取图片颜色
-     *
-     * @param storeImg 图片对象
-     */
-    private void extractColorForImg(StoreImg storeImg) {
-        try {
-            String colorCode = aiImageColorExtractUtil.extractCoverColor(storeImg.getImgUrl());
-            if (colorCode != null) {
-                storeImg.setColorCode(colorCode);
-                storeImg.setIsExtract(1); // 提取成功,设置为已提取
-                log.info("成功提取图片颜色码,imgUrl: {}, colorCode: {}", storeImg.getImgUrl(), colorCode);
-            } else {
-                log.warn("提取图片颜色失败,imgUrl: {}", storeImg.getImgUrl());
-                // 提取失败时,保持 is_extract 为 1(表示已尝试提取)
-            }
-        } catch (Exception e) {
-            log.error("提取图片颜色异常,imgUrl: {}", storeImg.getImgUrl(), e);
-            // 异常时,保持 is_extract 为 1(表示已尝试提取)
-        }
-    }
 }

+ 18 - 0
alien-store/src/main/java/shop/alien/store/service/StoreImgService.java

@@ -3,6 +3,7 @@ package shop.alien.store.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.StoreImg;
+import shop.alien.entity.store.vo.StoreImgInfoVo;
 import shop.alien.entity.store.vo.StoreImgTypeVo;
 
 import java.util.List;
@@ -70,4 +71,21 @@ public interface StoreImgService extends IService<StoreImg> {
      * @param imgType 图片类型, 0:其他, 1:入口图, 2:相册, 3:菜品, 4:环境, 5:价目表, 6:推荐菜, 7:菜单, 8:用户评论, 9:商家申诉, 10:商家头像, 11:店铺轮播图
      */
     int saveOrUpdateImg(Integer storeId, Integer imgType);
+
+    /**
+     * 异步提取图片颜色(不阻塞主流程)
+     *
+     * @param storeImgId 图片ID
+     * @param imgUrl 图片URL
+     */
+    void asyncExtractColorForImg(Integer storeImgId, String imgUrl);
+
+    /**
+     * 新增/修改/删除图片(包含完整的业务逻辑处理)
+     * 包括:删除旧图片、更新图片模式、设置图片描述、异步提取颜色、更新审核状态等
+     *
+     * @param storeImgInfoVo 图片信息VO
+     * @return 操作结果
+     */
+    R<String> saveOrUpdateImgWithInfo(StoreImgInfoVo storeImgInfoVo);
 }

+ 212 - 1
alien-store/src/main/java/shop/alien/store/service/impl/StoreImgServiceImpl.java

@@ -3,21 +3,27 @@ package shop.alien.store.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeClassManage;
 import shop.alien.entity.store.LifeUser;
 import shop.alien.entity.store.StoreImg;
 import shop.alien.entity.store.StoreOfficialAlbum;
+import shop.alien.entity.store.vo.StoreImgInfoVo;
 import shop.alien.entity.store.vo.StoreImgTypeVo;
 import shop.alien.mapper.LifeUserMapper;
 import shop.alien.mapper.StoreImgMapper;
 import shop.alien.mapper.StoreOfficialAlbumMapper;
 import shop.alien.store.service.StoreImgService;
+import shop.alien.store.service.StoreInfoService;
+import shop.alien.store.util.GroupConstant;
+import shop.alien.store.util.ai.AiImageColorExtractUtil;
 
 import java.util.Comparator;
 import java.util.List;
@@ -30,6 +36,7 @@ import java.util.stream.Collectors;
  * @author ssk
  * @since 2024-12-05
  */
+@Slf4j
 @Transactional
 @Service
 @RequiredArgsConstructor
@@ -38,6 +45,8 @@ public class StoreImgServiceImpl extends ServiceImpl<StoreImgMapper, StoreImg> i
     private final StoreImgMapper storeImgMapper;
     private final StoreOfficialAlbumMapper storeOfficialAlbumMapper;
     private final LifeUserMapper lifeUserMapper;
+    private final AiImageColorExtractUtil aiImageColorExtractUtil;
+    private final StoreInfoService storeInfoService;
 
     /**
      * 获取门店图片
@@ -174,4 +183,206 @@ public class StoreImgServiceImpl extends ServiceImpl<StoreImgMapper, StoreImg> i
         }
         return result;
     }
+
+    /**
+     * 异步提取图片颜色(不阻塞主流程)
+     * 该方法在后台异步执行,提取成功后更新数据库中的颜色码
+     *
+     * @param storeImgId 图片ID
+     * @param imgUrl 图片URL
+     */
+    @Override
+    @Async("taskExecutor")
+    public void asyncExtractColorForImg(Integer storeImgId, String imgUrl) {
+        try {
+            log.info("开始异步提取图片颜色,storeImgId: {}, imgUrl: {}", storeImgId, imgUrl);
+            String colorCode = aiImageColorExtractUtil.extractCoverColor(imgUrl);
+            if (colorCode != null) {
+                // 更新数据库中的颜色码
+                StoreImg updateImg = new StoreImg();
+                updateImg.setId(storeImgId);
+                updateImg.setColorCode(colorCode);
+                updateImg.setIsExtract(1); // 提取成功,设置为已提取
+                this.updateById(updateImg);
+                log.info("异步提取图片颜色成功,storeImgId: {}, colorCode: {}", storeImgId, colorCode);
+            } else {
+                log.warn("异步提取图片颜色失败,storeImgId: {}, imgUrl: {}", storeImgId, imgUrl);
+            }
+        } catch (Exception e) {
+            log.error("异步提取图片颜色异常,storeImgId: {}, imgUrl: {}", storeImgId, imgUrl, e);
+        }
+    }
+
+    /**
+     * 新增/修改/删除图片(包含完整的业务逻辑处理)
+     * 包括:删除旧图片、更新图片模式、设置图片描述、异步提取颜色、更新审核状态等
+     *
+     * @param storeImgInfoVo 图片信息VO
+     * @return 操作结果
+     */
+    @Override
+    public R<String> saveOrUpdateImgWithInfo(StoreImgInfoVo storeImgInfoVo) {
+        log.info("StoreImgServiceImpl.saveOrUpdateImgWithInfo?storeImgInfoVo={}", storeImgInfoVo);
+        List<StoreImg> storeImgList = storeImgInfoVo.getStoreImgList();
+        
+        // 参数校验
+        if (storeImgInfoVo.getStoreId() == null || storeImgInfoVo.getImgType() == null) {
+            return R.fail("失败");
+        }
+        
+        // 判断是否是头图(20:单图模式, 21:多图模式)
+        Integer imgType = storeImgInfoVo.getImgType();
+        boolean isHeadImage = (imgType == 20 || imgType == 21);
+        
+        // 清空storeId,imgType下图片
+        int deleteCount = this.saveOrUpdateImg(storeImgInfoVo.getStoreId(), storeImgInfoVo.getImgType());
+        log.info("StoreImgServiceImpl.saveOrUpdateImgWithInfo?deleteCount={}", deleteCount);
+        
+        // 更新图片模式信息
+        int result = storeInfoService.updateStoreImgModeInfo(storeImgInfoVo);
+        log.info("StoreImgServiceImpl.saveOrUpdateImgWithInfo?result={}", result);
+        
+        if (!CollectionUtils.isEmpty(storeImgList)) {
+            // 判断是否为多图模式
+            boolean isMultiMode = imgType != null && imgType.equals(GroupConstant.IMG_TYPE_MULTI_MODE);
+            
+            // 如果是多图模式,需要找到第一张图片(imgSort最小的)
+            StoreImg firstImg = null;
+            if (isMultiMode) {
+                firstImg = storeImgList.stream()
+                        .filter(img -> img != null && img.getImgUrl() != null)
+                        .min((img1, img2) -> {
+                            Integer sort1 = img1.getImgSort() != null ? img1.getImgSort() : Integer.MAX_VALUE;
+                            Integer sort2 = img2.getImgSort() != null ? img2.getImgSort() : Integer.MAX_VALUE;
+                            return sort1.compareTo(sort2);
+                        })
+                        .orElse(null);
+            }
+            
+            // 遍历图片列表,设置图片描述,标记需要异步提取颜色的图片
+            final StoreImg[] needExtractColorImgRef = {null}; // 需要提取颜色的图片(单图模式或多图模式的第一张)
+            for (StoreImg storeImg : storeImgList) {
+                if (storeImg != null && storeImg.getImgUrl() != null) {
+                    // 根据图片类型设置图片描述
+                    String imgDescription = getImgDescriptionByType(imgType);
+                    if (imgDescription != null) {
+                        storeImg.setImgDescription(imgDescription);
+                    }
+                    
+                    // 只有当 is_extract=1 时才标记需要提取颜色
+                    Integer isExtract = storeImg.getIsExtract();
+                    if (isExtract != null && isExtract == 1) {
+                        // 如果是多图模式,只对第一张图片提取颜色
+                        if (isMultiMode) {
+                            // 判断是否为第一张图片(通过比较imgSort,如果imgSort相同则认为是同一张图片)
+                            boolean isFirstImg = firstImg != null && 
+                                    firstImg.getImgSort() != null && 
+                                    storeImg.getImgSort() != null && 
+                                    firstImg.getImgSort().equals(storeImg.getImgSort());
+                            
+                            if (isFirstImg) {
+                                log.info("多图模式,标记第一张图片需要异步提取颜色,imgUrl: {}, imgSort: {}, isExtract: {}", 
+                                        storeImg.getImgUrl(), storeImg.getImgSort(), isExtract);
+                                needExtractColorImgRef[0] = storeImg;
+                            } else {
+                                log.info("多图模式,跳过非第一张图片的颜色提取,imgUrl: {}, imgSort: {}", 
+                                        storeImg.getImgUrl(), storeImg.getImgSort());
+                                // 非第一张图片,保持 is_extract 为 1,但不提取颜色
+                            }
+                        } else {
+                            // 单图模式,标记需要提取颜色
+                            log.info("单图模式,标记图片需要异步提取颜色,imgUrl: {}, isExtract: {}", storeImg.getImgUrl(), isExtract);
+                            needExtractColorImgRef[0] = storeImg;
+                        }
+                    }
+                }
+            }
+            
+            Integer id = storeImgList.get(0).getId();
+            if (this.saveOrUpdateBatch(storeImgList)) {
+                // 异步提取颜色,不阻塞主流程
+                // 保存后,MyBatis-Plus会自动填充ID,需要从保存后的列表中获取
+                StoreImg needExtractColorImg = needExtractColorImgRef[0];
+                if (needExtractColorImg != null) {
+                    // 如果是新增的图片,保存后ID会被自动填充,需要重新查找
+                    Integer storeImgId = needExtractColorImg.getId();
+                    if (storeImgId == null) {
+                        // 新增图片,保存后从列表中查找对应的图片(通过imgUrl匹配)
+                        String targetImgUrl = needExtractColorImg.getImgUrl();
+                        StoreImg savedImg = storeImgList.stream()
+                                .filter(img -> img.getImgUrl() != null && 
+                                        img.getImgUrl().equals(targetImgUrl))
+                                .findFirst()
+                                .orElse(null);
+                        if (savedImg != null) {
+                            storeImgId = savedImg.getId();
+                        }
+                    }
+                    if (storeImgId != null) {
+                        // 调用异步提取颜色方法
+                        this.asyncExtractColorForImg(storeImgId, needExtractColorImg.getImgUrl());
+                    }
+                }
+                
+                // 如果是头图,设置审核状态为通过(1),前端已完成门头图识别
+                if (isHeadImage) {
+                    // 有头图,设置为审核通过状态(1)
+                    try {
+                        storeInfoService.updateHeadImgStatus(storeImgInfoVo.getStoreId(), 1);
+                        log.info("头图保存成功,设置审核状态为通过,storeId={}", storeImgInfoVo.getStoreId());
+                    } catch (Exception e) {
+                        log.error("更新头图审核状态失败,storeId={}, error={}", 
+                                storeImgInfoVo.getStoreId(), e.getMessage(), e);
+                    }
+                }
+                if (null != id) {
+                    return R.success("修改成功");
+                }
+                return R.success("新增成功");
+            } else {
+                // 图片保存失败,如果是头图,设置审核状态为不通过
+                if (isHeadImage) {
+                    try {
+                        storeInfoService.updateHeadImgStatus(storeImgInfoVo.getStoreId(), 2);
+                        log.info("图片保存失败,更新头图审核状态为不通过,storeId={}", storeImgInfoVo.getStoreId());
+                    } catch (Exception e) {
+                        log.error("更新头图审核状态失败,storeId={}, error={}", 
+                                storeImgInfoVo.getStoreId(), e.getMessage(), e);
+                    }
+                }
+            }
+        } else {
+            // 如果是头图且没有图片,设置审核状态为不通过
+            if (isHeadImage) {
+                try {
+                    storeInfoService.updateHeadImgStatus(storeImgInfoVo.getStoreId(), 2);
+                } catch (Exception e) {
+                    log.error("更新头图审核状态失败,storeId={}, error={}", 
+                            storeImgInfoVo.getStoreId(), e.getMessage(), e);
+                }
+            }
+            return R.success("保存成功");
+        }
+        return R.fail("失败");
+    }
+
+    /**
+     * 根据图片类型获取图片描述
+     *
+     * @param imgType 图片类型
+     * @return 图片描述
+     */
+    private String getImgDescriptionByType(Integer imgType) {
+        if (imgType == null) {
+            return null;
+        }
+        switch (imgType) {
+            case 20:
+                return "头图单图模式";
+            case 21:
+                return "头图多图模式";
+            default:
+                return null;
+        }
+    }
 }