Explorar o código

Merge remote-tracking branch 'origin/sit' into uat-20260202

dujian hai 15 horas
pai
achega
029c2ed3f8

+ 6 - 3
alien-dining/src/main/java/shop/alien/dining/strategy/payment/impl/WeChatPartnerPaymentMininProgramStrategyImpl.java

@@ -195,7 +195,8 @@ public class WeChatPartnerPaymentMininProgramStrategyImpl implements PaymentStra
         }
         String subMchid = resolveSubMchidFromStore(storeId);
         if (subMchid == null) {
-            return R.fail("请维护门店特约商户号 store_info.wechat_sub_mchid");
+            log.error("请维护门店特约商户号 store_info.wechat_sub_mchid" + storeId);
+            return R.fail("该商家未绑定收款账号,无法付款");
         }
 
         PartnerJsapiPrepayRequest request = new PartnerJsapiPrepayRequest();
@@ -467,7 +468,8 @@ public class WeChatPartnerPaymentMininProgramStrategyImpl implements PaymentStra
         }
         String subMchid = resolveSubMchidFromStore(storeId);
         if (subMchid == null) {
-            return R.fail("请维护门店特约商户号 store_info.wechat_sub_mchid");
+            log.error("请维护门店特约商户号 store_info.wechat_sub_mchid" + storeId);
+            return R.fail("该商家未绑定收款账号,无法付款");
         }
         try {
             DirectAPIv3QueryResponse response = partnerSearchOrderRun(transactionId, subMchid);
@@ -570,7 +572,8 @@ public class WeChatPartnerPaymentMininProgramStrategyImpl implements PaymentStra
         }
         String subMchid = resolveSubMchidFromStore(storeId);
         if (subMchid == null) {
-            return R.fail("请维护门店特约商户号 store_info.wechat_sub_mchid");
+            log.error("请维护门店特约商户号 store_info.wechat_sub_mchid" + storeId);
+            return R.fail("该商家未绑定收款账号,无法付款");
         }
         QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
         request.setOutRefundNo(outRefundNo);

+ 8 - 4
alien-store/src/main/java/shop/alien/store/controller/OperationalActivityController.java

@@ -51,7 +51,9 @@ public class OperationalActivityController {
             @ApiImplicitParam(name = "pageNum", value = "当前页", dataTypeClass = Integer.class, paramType = "query"),
             @ApiImplicitParam(name = "pageSize", value = "每页数量", dataTypeClass = Integer.class, paramType = "query"),
             @ApiImplicitParam(name = "activityStatus", value = "活动状态", dataTypeClass = Integer.class, paramType = "query"),
-            @ApiImplicitParam(name = "activityName", value = "活动名称(模糊)", dataTypeClass = String.class, paramType = "query")
+            @ApiImplicitParam(name = "activityName", value = "活动名称(模糊)", dataTypeClass = String.class, paramType = "query"),
+            @ApiImplicitParam(name = "startTime", value = "提交开始时间", dataTypeClass = String.class, paramType = "query"),
+            @ApiImplicitParam(name = "endTime", value = "提交结束时间", dataTypeClass = String.class, paramType = "query")
     })
     @GetMapping("/detail")
     public R<IPage<StoreOperationalActivityVO>> pageActivityDetail(
@@ -61,10 +63,12 @@ public class OperationalActivityController {
             @RequestParam(value = "pageSize", required = false) Integer pageSize,
             @RequestParam(value = "status", required = false) Integer status,
             @RequestParam(value = "activityType", required = false) String activityType,
-            @RequestParam(value = "activityName", required = false) String activityName) {
-        log.info("OperationalActivityController.pageActivityDetail storeId={}, storeName={}, pageNum={}, pageSize={}, status={}, activityName={}", storeId, storeName, pageNum, pageSize, status, activityName);
+            @RequestParam(value = "activityName", required = false) String activityName,
+            @RequestParam(value = "startTime", required = false) String startTime,
+            @RequestParam(value = "endTime", required = false) String endTime) {
+        log.info("OperationalActivityController.pageActivityDetail storeId={}, storeName={}, pageNum={}, pageSize={}, status={}, activityName={}, startTime={}, endTime={}", storeId, storeName, pageNum, pageSize, status, activityName, startTime, endTime);
         try {
-            IPage<StoreOperationalActivityVO> result = activityService.pageActivityDetail(storeId, storeName, pageNum, pageSize, status, activityName, activityType);
+            IPage<StoreOperationalActivityVO> result = activityService.pageActivityDetail(storeId, storeName, pageNum, pageSize, status, activityName, activityType, startTime, endTime);
             return R.data(result);
         } catch (IllegalArgumentException e) {
             return R.fail(e.getMessage());

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

@@ -31,9 +31,11 @@ public interface OperationalActivityService {
      * @param activityStatus 活动状态
      * @param activityName 活动名称(模糊)
      * @param activityType 活动类型(COMMENT-评论有礼, MARKETING-营销活动)
+     * @param startTime 提交开始时间
+     * @param endTime 提交结束时间
      * @return 活动分页结果
      */
-    IPage<StoreOperationalActivityVO> pageActivityDetail(Integer storeId, String storeName, Integer pageNum, Integer pageSize, Integer activityStatus, String activityName, String activityType);
+    IPage<StoreOperationalActivityVO> pageActivityDetail(Integer storeId, String storeName, Integer pageNum, Integer pageSize, Integer activityStatus, String activityName, String activityType, String startTime, String endTime);
 
     /**
      * 根据活动ID获取活动详情

+ 30 - 2
alien-store/src/main/java/shop/alien/store/service/impl/OperationalActivityServiceImpl.java

@@ -112,8 +112,8 @@ public class OperationalActivityServiceImpl implements OperationalActivityServic
     }
 
     @Override
-    public IPage<StoreOperationalActivityVO> pageActivityDetail(Integer storeId, String storeName, Integer pageNum, Integer pageSize, Integer activityStatus, String activityName, String activityType) {
-        log.info("OperationalActivityServiceImpl.pageActivityDetail: storeId={}, storeName={}, pageNum={}, pageSize={}, activityStatus={}, activityName={}, activityType={}", storeId, storeName, pageNum, pageSize, activityStatus, activityName, activityType);
+    public IPage<StoreOperationalActivityVO> pageActivityDetail(Integer storeId, String storeName, Integer pageNum, Integer pageSize, Integer activityStatus, String activityName, String activityType, String startTime, String endTime) {
+        log.info("OperationalActivityServiceImpl.pageActivityDetail: storeId={}, storeName={}, pageNum={}, pageSize={}, activityStatus={}, activityName={}, activityType={}, startTime={}, endTime={}", storeId, storeName, pageNum, pageSize, activityStatus, activityName, activityType, startTime, endTime);
 
 //        if (storeId == null && StringUtils.isBlank(storeName)) {
 //            throw new IllegalArgumentException("请至少提供商户ID或商户名称");
@@ -154,6 +154,12 @@ public class OperationalActivityServiceImpl implements OperationalActivityServic
         if (StringUtils.isNotBlank(activityType)) {
             wrapper.eq(StoreOperationalActivity::getActivityType, activityType);
         }
+        if (StringUtils.isNotBlank(startTime)) {
+            wrapper.ge(StoreOperationalActivity::getCreatedTime, normalizeStartTime(startTime));
+        }
+        if (StringUtils.isNotBlank(endTime)) {
+            wrapper.le(StoreOperationalActivity::getCreatedTime, normalizeEndTime(endTime));
+        }
 
         if (!storeIds.isEmpty()) {
             wrapper.in(StoreOperationalActivity::getStoreId, storeIds);
@@ -348,6 +354,28 @@ public class OperationalActivityServiceImpl implements OperationalActivityServic
         }
     }
 
+    private String normalizeStartTime(String timeText) {
+        if (StringUtils.isBlank(timeText)) {
+            return timeText;
+        }
+        String value = timeText.trim();
+        if (value.length() == 10) {
+            return value + " 00:00:00";
+        }
+        return value;
+    }
+
+    private String normalizeEndTime(String timeText) {
+        if (StringUtils.isBlank(timeText)) {
+            return timeText;
+        }
+        String value = timeText.trim();
+        if (value.length() == 10) {
+            return value + " 23:59:59";
+        }
+        return value;
+    }
+
     /**
      * 发送活动审核通知给商户
      *

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

@@ -6085,7 +6085,7 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         // 该用户的打卡记录(仅审核通过 check_flag=2)
         LambdaQueryWrapper<StoreClockIn> clockInWrapper = new LambdaQueryWrapper<>();
         clockInWrapper.eq(StoreClockIn::getUserId, userId);
-        clockInWrapper.eq(StoreClockIn::getCheckFlag, 2);
+//        clockInWrapper.eq(StoreClockIn::getCheckFlag, 2);
         List<StoreClockIn> clockInList = storeClockInMapper.selectList(clockInWrapper);
 
         List<StoreClockIn> clockStoreList = clockInList.stream().filter(item -> item.getStoreId() == Integer.parseInt(storeId)).collect(Collectors.toList());

+ 22 - 162
alien-store/src/main/java/shop/alien/store/service/impl/StoreRenovationRequirementServiceImpl.java

@@ -19,14 +19,10 @@ import shop.alien.mapper.*;
 import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.service.StoreRenovationRequirementService;
 import shop.alien.store.util.ai.AiContentModerationUtil;
-import shop.alien.store.util.ai.AiVideoModerationUtil;
 import shop.alien.util.common.JwtUtil;
 
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
 import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.concurrent.*;
 import java.util.stream.Collectors;
 
 /**
@@ -41,9 +37,6 @@ import java.util.stream.Collectors;
 @Transactional(rollbackFor = Exception.class)
 public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreRenovationRequirementMapper, StoreRenovationRequirement> implements StoreRenovationRequirementService {
 
-    // 1. 自定义视频审核线程池(全局复用,避免频繁创建线程)
-    private ExecutorService videoAuditExecutor;
-
     private final StoreInfoMapper storeInfoMapper;
 
     private final LifeMessageMapper lifeMessageMapper;
@@ -55,7 +48,7 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
     private final StoreUserMapper storeUserMapper;
 
     private final AiContentModerationUtil aiContentModerationUtil;
-    private final AiVideoModerationUtil aiVideoModerationUtil;
+    // 供 CommonRatingServiceImpl 等复用的 URL 分类;本服务保存需求时不再对图/视频做审核
     // 定义图片后缀常量(不可修改,保证线程安全)
     private static final Set<String> IMAGE_SUFFIXES = Collections.unmodifiableSet(
             new HashSet<>(Arrays.asList(".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"))
@@ -66,55 +59,6 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
             new HashSet<>(Arrays.asList(".mp4", ".avi", ".mov", ".flv", ".mkv", ".wmv", ".mpeg"))
     );
 
-    // 初始化线程池
-    @PostConstruct
-    public void initExecutor() {
-        // 核心参数根据业务调整,IO密集型任务线程数可设为CPU核心数*2~4
-        int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
-        int maxPoolSize = Runtime.getRuntime().availableProcessors() * 4;
-        videoAuditExecutor = new ThreadPoolExecutor(
-                corePoolSize,
-                maxPoolSize,
-                60L,
-                TimeUnit.SECONDS,
-                new LinkedBlockingQueue<>(500), // 任务队列,避免无界队列溢出
-                new ThreadFactory() {
-                    private int count = 0;
-                    @Override
-                    public Thread newThread(Runnable r) {
-                        Thread t = new Thread(r);
-                        t.setName("video-audit-" + count++); // 自定义线程名,便于排查
-                        return t;
-                    }
-                },
-                // 任务拒绝策略:记录日志+调用者线程兜底(避免任务丢失)
-                new ThreadPoolExecutor.CallerRunsPolicy() {
-                    @Override
-                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
-                        log.error("视频审核任务被拒绝,队列已满!当前队列大小:{},活跃线程数:{}",
-                                e.getQueue().size(), e.getActiveCount());
-                        super.rejectedExecution(r, e);
-                    }
-                }
-        );
-    }
-
-    // 优雅关闭线程池
-    @PreDestroy
-    public void destroyExecutor() {
-        if (Objects.nonNull(videoAuditExecutor)) {
-            videoAuditExecutor.shutdown();
-            try {
-                if (!videoAuditExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
-                    videoAuditExecutor.shutdownNow();
-                }
-            } catch (InterruptedException e) {
-                videoAuditExecutor.shutdownNow();
-                Thread.currentThread().interrupt();
-            }
-        }
-    }
-
     @Override
     public boolean saveOrUpdateRequirement(StoreRenovationRequirementDto dto) {
         log.info("StoreRenovationRequirementServiceImpl.saveOrUpdateRequirement?dto={}", dto);
@@ -183,89 +127,27 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
             websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
             webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());
 
-
-            // 附件图/视频由前端直连 AI;服务端仅审 detailedRequirement 文本(图片 URL 在 util 内不传 moderate)
-            Map<String, List<String>> urlCategoryMap = classifyUrls(dto.getAttachmentUrls());
-            List<String> videoUrls = urlCategoryMap.get("video");
-            AiContentModerationUtil.AuditResult auditResult = aiContentModerationUtil.auditContent(requirement.getDetailedRequirement(), null);
-            if (!auditResult.isPassed()) {
-                requirement.setAuditStatus(2);
-                requirement.setAuditReason(auditResult.getFailureReason());
-                // 发送审核失败通知(文本图片)
+            // 仅审核 detailedRequirement 文本;无文字则整体直接审核通过;附件原样存 attachment_urls
+            if (!StringUtils.hasText(requirement.getDetailedRequirement())) {
+                requirement.setAuditStatus(1);
+                requirement.setAuditReason(null);
                 if (storeUser != null && storeUser.getPhone() != null) {
-                    sendAuditNotification(storeUser.getPhone(), 2, auditResult.getFailureReason(), "text_image");
+                    sendAuditNotification(storeUser.getPhone(), 1, null);
                 }
-
             } else {
-                // 如果文本/图片审核通过,且没有视频需要审核,直接设置为审核通过
-                if (videoUrls == null || videoUrls.isEmpty()) {
-                    requirement.setAuditStatus(1);
-                    requirement.setAuditReason(null);
-                    // 发送审核通过通知(文本图片,无视频)
+                AiContentModerationUtil.AuditResult auditResult = aiContentModerationUtil.auditContent(requirement.getDetailedRequirement(), null);
+                if (!auditResult.isPassed()) {
+                    requirement.setAuditStatus(2);
+                    requirement.setAuditReason(auditResult.getFailureReason());
                     if (storeUser != null && storeUser.getPhone() != null) {
-                        sendAuditNotification(storeUser.getPhone(), 1, null, "text_image");
+                        sendAuditNotification(storeUser.getPhone(), 2, auditResult.getFailureReason());
                     }
                 } else {
-                    // 有视频时走异步分支;视频不在服务端审(前端已审),auditVideos 恒通过
-                    // 保存storeUser信息供异步任务使用
-                    final StoreUser finalStoreUser = storeUser;
-                    CompletableFuture.runAsync(() -> {
-                    AiVideoModerationUtil.VideoAuditResult videoAuditResult = null;
-                    try {
-                        // 调用审核接口,增加超时控制(避免接口挂死)
-                        videoAuditResult = CompletableFuture.supplyAsync(
-                                () -> aiVideoModerationUtil.auditVideos(urlCategoryMap.get("video")),
-                                videoAuditExecutor
-                        ).get();
-
-                        // 审核不通过则更新状态和原因
-                        if (Objects.nonNull(videoAuditResult) && !videoAuditResult.isPassed()) {
-                            // 重新查询最新的requirement,避免并发覆盖
-                            StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
-                            if (Objects.isNull(latestRequirement)) {
-                                log.error("视频审核后更新失败,requirement不存在,ID:{}", requirement.getId());
-                                return;
-                            }
-                            latestRequirement.setAuditStatus(2);
-                            latestRequirement.setAuditReason(videoAuditResult.getFailureReason());
-                            this.saveOrUpdate(latestRequirement);
-                            log.info("视频审核不通过,已更新状态,requirementID:{},原因:{}",
-                                    requirement.getId(), videoAuditResult.getFailureReason());
-                            // 发送审核不通过通知(视频)
-                            if (finalStoreUser != null && finalStoreUser.getPhone() != null) {
-                                sendAuditNotification(finalStoreUser.getPhone(), 2, videoAuditResult.getFailureReason(), "video");
-                            }
-
-                        } else if (Objects.nonNull(videoAuditResult) && videoAuditResult.isPassed()) {
-                            // 审核通过也更新状态(可选,根据业务需求)
-                            StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
-                            if (Objects.nonNull(latestRequirement)) {
-                                latestRequirement.setAuditStatus(1);
-                                latestRequirement.setAuditReason(null);
-                                this.saveOrUpdate(latestRequirement);
-                                // 发送审核通过通知(视频)
-                                if (finalStoreUser != null && finalStoreUser.getPhone() != null) {
-                                    sendAuditNotification(finalStoreUser.getPhone(), 1, null, "video");
-                                }
-
-                                log.info("视频审核通过,已更新状态,requirementID:{}", requirement.getId());
-                            }
-                        }
-                    } catch (Exception e) {
-                        log.error("视频审核接口调用异常,requirementID:{}", requirement.getId(), e);
-                        StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
-                        if (Objects.nonNull(latestRequirement)) {
-                            String exceptionMessage = "视频审核接口调用异常:" + e.getMessage();
-                            latestRequirement.setAuditStatus(2);
-                            latestRequirement.setAuditReason(exceptionMessage);
-                            this.saveOrUpdate(latestRequirement);
-                            // 发送审核异常通知(视频)
-                            if (finalStoreUser != null && finalStoreUser.getPhone() != null) {
-                                sendAuditNotification(finalStoreUser.getPhone(), 2, exceptionMessage, "video");
-                            }
-                        }
+                    requirement.setAuditStatus(1);
+                    requirement.setAuditReason(null);
+                    if (storeUser != null && storeUser.getPhone() != null) {
+                        sendAuditNotification(storeUser.getPhone(), 1, null);
                     }
-                    }, videoAuditExecutor);
                 }
             }
             requirement.setAuditTime(new Date());
@@ -332,43 +214,21 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
     }
 
     /**
-     * 发送审核结果通知
-     * @param storePhone 商铺电话
-     * @param auditStatus 审核状态:1-通过,2-不通过
-     * @param auditReason 审核原因(不通过时提供)
-     * @param auditType 审核类型:text_image-文本图片审核,video-视频审核
+     * 发送文本审核结果通知(图/视频不参与审核,仅与需求一并保存)
      */
-    private void sendAuditNotification(String storePhone, Integer auditStatus, String auditReason, String auditType) {
+    private void sendAuditNotification(String storePhone, Integer auditStatus, String auditReason) {
         try {
             if (storePhone == null || storePhone.trim().isEmpty()) {
                 log.warn("发送审核通知失败,商铺电话为空");
                 return;
             }
 
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
-            String commonDate = sdf.format(new Date());
-
-            String title;
+            String title = "审核通知";
             String message;
             if (auditStatus == 1) {
-                // 审核通过
-                title = "审核通知";
-                if ("video".equals(auditType)) {
-                    message = "在" + commonDate + ",您发布的装修动态视频审核已通过。";
-                } else {
-                    message = "您发布的装修需求已通过审核,平台已将此需求发布,有意向的装修公司会与您联系";
-                }
+                message = "您发布的装修需求已通过审核,平台已将此需求发布,有意向的装修公司会与您联系";
             } else {
-                // 审核不通过
-                title = "审核通知";
-//                String reasonText = auditReason != null && !auditReason.trim().isEmpty()
-//                    ? ",原因:" + auditReason
-//                    : "";
-                if ("video".equals(auditType)) {
-                    message = "在" + commonDate + ",您发布的装修动态视频审核未通过" + auditReason + ",请修改后重新提交。";
-                } else {
-                    message = "您发布的装修需求未通过审核.驳回原因:"+auditReason+"请您重新发布.";
-                }
+                message = "您发布的装修需求未通过审核.驳回原因:" + (auditReason != null ? auditReason : "") + "请您重新发布.";
             }
 
             LifeNotice lifeNotice = new LifeNotice();
@@ -391,9 +251,9 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
             websocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
             webSocketProcess.sendMessage("store_" + storePhone, JSONObject.from(websocketVo).toJSONString());
 
-            log.info("审核通知发送成功,商铺电话:{},审核状态:{},审核类型:{}", storePhone, auditStatus, auditType);
+            log.info("审核通知发送成功,商铺电话:{},审核状态:{}", storePhone, auditStatus);
         } catch (Exception e) {
-            log.error("发送审核通知异常,商铺电话:{},审核状态:{},审核类型:{}", storePhone, auditStatus, auditType, e);
+            log.error("发送审核通知异常,商铺电话:{},审核状态:{}", storePhone, auditStatus, e);
         }
     }