Forráskód Böngészése

Merge remote-tracking branch 'origin/master' into matser

吴树波 6 napja
szülő
commit
7c96353c22
44 módosított fájl, 613 hozzáadás és 143 törlés
  1. 42 24
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
  2. 8 2
      fs-ai-call-task/src/main/java/com/fs/app/service/CallTaskService.java
  3. 1 0
      fs-ai-call-task/src/main/resources/application.yml
  4. 6 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticController.java
  5. 3 0
      fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerController.java
  6. 276 2
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
  7. 2 0
      fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallees.java
  8. 1 1
      fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCalleesMapper.java
  9. 1 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyWxClientMapper.java
  10. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyWxClientService.java
  11. 14 2
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java
  12. 3 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java
  13. 10 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyWxClientServiceImpl.java
  14. 12 7
      fs-service/src/main/java/com/fs/company/service/impl/CompanyWxServiceImpl.java
  15. 15 15
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AiAddWxTaskNode.java
  16. 5 5
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AiCallTaskNode.java
  17. 46 40
      fs-service/src/main/java/com/fs/company/service/impl/call/node/AiQwAddWxTaskNode.java
  18. 1 1
      fs-service/src/main/java/com/fs/company/service/impl/call/node/WorkflowNodeFactory.java
  19. 3 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  20. 5 0
      fs-service/src/main/java/com/fs/his/domain/FsPackage.java
  21. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  22. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageVO.java
  23. 12 4
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  24. 1 1
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  25. 9 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java
  26. 3 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderParam.java
  27. 4 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderExportVO.java
  28. 2 2
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportZMVO.java
  29. 7 0
      fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java
  30. 5 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java
  31. 3 3
      fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java
  32. 1 1
      fs-service/src/main/java/com/fs/wxcid/service/ICidIpadServerService.java
  33. 2 2
      fs-service/src/main/java/com/fs/wxcid/service/impl/CidIpadServerServiceImpl.java
  34. 1 0
      fs-service/src/main/resources/application-dev.yml
  35. 1 1
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogAddwxMapper.xml
  36. 4 1
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCalleesMapper.xml
  37. 2 0
      fs-service/src/main/resources/mapper/company/CompanyWxAccountMapper.xml
  38. 14 1
      fs-service/src/main/resources/mapper/company/CompanyWxClientMapper.xml
  39. 5 1
      fs-service/src/main/resources/mapper/his/FsPackageMapper.xml
  40. 8 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  41. 8 0
      fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml
  42. 45 13
      fs-wx-task/src/main/java/com/fs/app/service/WxTaskService.java
  43. 16 10
      fs-wx-task/src/main/java/com/fs/app/task/WxTask.java
  44. 1 0
      fs-wx-task/src/main/resources/application.yml

+ 42 - 24
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -277,16 +277,10 @@ public class FsStoreHealthOrderScrmController extends BaseController {
     @Log(title = "商城订单明细导出", businessType = BusinessType.EXPORT)
     @GetMapping("/healthExportItems")
     public AjaxResult exportItems1(FsStoreOrderParam param) {
-        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
-            param.setBeginTime(null);
-            param.setEndTime(null);
-        }
+        normalizeExportParam(param);
         if (fsStoreOrderService.isEntityNull(param)){
             return AjaxResult.error("请筛选数据导出");
         }
-        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
-            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
-        }
         if(!StringUtils.isEmpty(param.getPayTimeRange())){
             param.setPayTimeList(param.getPayTimeRange().split("--"));
         }
@@ -390,16 +384,10 @@ public class FsStoreHealthOrderScrmController extends BaseController {
     @Log(title = "商城订单明细导出", businessType = BusinessType.EXPORT)
     @GetMapping("/healthExportItemsDetails")
     public AjaxResult healthExportItemsDetails(FsStoreOrderParam param) {
-        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
-            param.setBeginTime(null);
-            param.setEndTime(null);
-        }
+        normalizeExportParam(param);
         if (fsStoreOrderService.isEntityNull(param)){
             return AjaxResult.error("请筛选数据导出");
         }
-        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
-            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
-        }
         if(!StringUtils.isEmpty(param.getPayTimeRange())){
             param.setPayTimeList(param.getPayTimeRange().split("--"));
         }
@@ -428,6 +416,11 @@ public class FsStoreHealthOrderScrmController extends BaseController {
             if (zmvoList != null) {
                     LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
                     for (FsStoreOrderItemExportZMVO vo : zmvoList) {
+                        if ("2".equals(vo.getOrderType())) {
+                            vo.setOrderTypeStr("直播订单");
+                        }else {
+                            vo.setOrderTypeStr("商城订单");
+                        }
                         if (!StringUtils.isEmpty(vo.getJsonInfo())) {
                             try {
                                 StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
@@ -516,6 +509,23 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         return util.importTemplateExcel("订单发货导入模板");
     }
 
+    /** 统一处理导出接口的 GET 参数,与 healthList 的 POST 参数逻辑一致 */
+    private void normalizeExportParam(FsStoreOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (StringUtils.isNotEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        // GET 请求时 orderCodes 可能无法正确绑定,用 orderCodeList(逗号分隔)转 orderCodes
+        if ((param.getOrderCodes() == null || param.getOrderCodes().isEmpty())
+                && StringUtils.isNotBlank(param.getOrderCodeList())) {
+            String[] arr = param.getOrderCodeList().split("[,,\\s]+");
+            param.setOrderCodes(new ArrayList<>(Arrays.asList(arr)));
+        }
+    }
+
     // 检查文件是否为有效的Excel文件
     private boolean isValidExcelFile(String fileName) {
         for (String ext : ALLOWED_EXCEL_EXTENSIONS) {
@@ -588,15 +598,23 @@ public class FsStoreHealthOrderScrmController extends BaseController {
             param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
         }
         param.setIsHealth("1");
-        List<FsStoreOrderDeliveryNoteExportVO> storeOrderDeliveryNoteExportVOList=fsStoreOrderService.getDeliveryNote(param);
-        ExcelUtil<FsStoreOrderDeliveryNoteExportVO> util = new ExcelUtil<>(FsStoreOrderDeliveryNoteExportVO.class);
-        //通过商品ID获取关键字
-        String firstKeyword = storeOrderDeliveryNoteExportVOList.stream()
-                .map(FsStoreOrderDeliveryNoteExportVO::getKeyword)
-                .filter(StringUtils::isNotEmpty)
-                .findFirst()
-                .orElse("无订单");
-        String fileName="077AC"+firstKeyword+new SimpleDateFormat("yyyyMMdd").format(new Date());
-        return util.exportExcel(storeOrderDeliveryNoteExportVOList, fileName);
+        try {
+            List<FsStoreOrderDeliveryNoteExportVO> storeOrderDeliveryNoteExportVOList=fsStoreOrderService.getDeliveryNote(param);
+            if(storeOrderDeliveryNoteExportVOList == null || storeOrderDeliveryNoteExportVOList.isEmpty()){
+                return AjaxResult.error("没有可导出的发货单数据");
+            }
+            ExcelUtil<FsStoreOrderDeliveryNoteExportVO> util = new ExcelUtil<>(FsStoreOrderDeliveryNoteExportVO.class);
+            //通过商品ID获取关键字
+            String firstKeyword = storeOrderDeliveryNoteExportVOList.stream()
+                    .map(FsStoreOrderDeliveryNoteExportVO::getKeyword)
+                    .filter(StringUtils::isNotEmpty)
+                    .findFirst()
+                    .orElse("无订单");
+            String fileName="077AC"+firstKeyword+new SimpleDateFormat("yyyyMMdd").format(new Date());
+            return util.exportExcel(storeOrderDeliveryNoteExportVOList, fileName);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxResult.error("导出发货单失败:" + e.getMessage());
+        }
     }
 }

+ 8 - 2
fs-ai-call-task/src/main/java/com/fs/app/service/CallTaskService.java

@@ -8,8 +8,10 @@ import com.fs.company.service.*;
 import com.fs.company.service.impl.call.node.AiCallTaskNode;
 import com.fs.course.config.RedisKeyScanner;
 import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
@@ -17,9 +19,13 @@ import java.util.concurrent.*;
 
 @Slf4j
 @Service
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class CallTaskService {
 
+
+    @Value("${cid-group-no}")
+    private Integer cidGroupNo;
+
     private final RedisCacheT<String> redisCache;
 
     private final RedisCache redisCache2;
@@ -40,7 +46,7 @@ public class CallTaskService {
      */
     public void cidWorkflowCallRun() {
         log.info("===========工作流延时任务开始扫描===========");
-        String delayCallKeyPrefix = AiCallTaskNode.getDelayCallKeyPrefix(null) + "*";
+        String delayCallKeyPrefix = AiCallTaskNode.getDelayCallKeyPrefix(cidGroupNo,null) + "*";
         Set<String> keys = redisKeyScanner.scanMatchKey(delayCallKeyPrefix);
         log.info("共扫描到 {} 个待处理键", keys.size());
         keys.parallelStream().forEach(key -> {

+ 1 - 0
fs-ai-call-task/src/main/resources/application.yml

@@ -14,3 +14,4 @@ spring:
 #    active: druid-sxjz
 #    active: druid-hdt
 #    active: druid-myhk-test
+cid-group-no: 1

+ 6 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticController.java

@@ -267,4 +267,10 @@ public class CompanyVoiceRoboticController extends BaseController
         List<WorkflowExecRecordVo> records = companyVoiceRoboticService.getExecRecords(roboticId);
         return R.ok().put("data", records);
     }
+
+    @GetMapping("/getCurrentCompanyId")
+    public R getCurrentCompanyId(){
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        return R.ok().put("companyId", loginUser.getCompany().getCompanyId());
+    }
 }

+ 3 - 0
fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerController.java

@@ -98,6 +98,9 @@ public class CrmCustomerController extends BaseController
     @PreAuthorize("@ss.hasPermi('crm:customer:list')")
     @GetMapping("/listAll")
     public R listAll(CrmCustomerListQueryParam crmCustomer){
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        crmCustomer.setCompanyId(loginUser.getCompany().getCompanyId());
         PageHelper.startPage(1, 1000);
         if(!StringUtils.isEmpty(crmCustomer.getReceiveTimeRange())){
             crmCustomer.setReceiveTimeList(crmCustomer.getReceiveTimeRange().split("--"));

+ 276 - 2
fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.store;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
 import com.fs.common.annotation.DataScope;
 import com.fs.common.annotation.Log;
@@ -9,6 +10,7 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.crm.service.ICrmCustomerService;
@@ -31,8 +33,14 @@ import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsStoreOrderListVO;
+import com.fs.his.vo.FsStoreOrderListAndStatisticsVo;
 import com.fs.his.vo.FsStoreOrderVO;
 import com.fs.his.vo.FsStoreProductDeliverExcelVO;
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
+import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
+import com.fs.hisStore.vo.FsStoreOrderErpExportVO;
+import com.fs.hisStore.vo.FsStoreOrderItemExportVO;
+import com.fs.hisStore.dto.StoreOrderProductDTO;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -40,8 +48,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.util.Date;
-import java.util.List;
+import com.github.pagehelper.PageHelper;
+
+import java.util.*;
 
 import static com.fs.his.utils.PhoneUtil.decryptPhone;
 import static com.fs.his.utils.PhoneUtil.encryptPhone;
@@ -67,6 +76,271 @@ public class FsStoreOrderController extends BaseController
     @Autowired
     @Qualifier("erpOrderServiceImpl")
     IErpOrderService erpOrderService;
+
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderScrmService;
+    @Autowired
+    private IFsStoreOrderItemScrmService orderItemScrmService;
+
+    /**
+     * 查询直播订单列表(仅 fs_store_order_scrm 中 order_type=2)
+     * 分公司负责人(userType=00)可查公司下所有直播订单,否则仅能查自己的直播订单
+     */
+    @PostMapping("/healthLiveList")
+    public FsStoreOrderListAndStatisticsVo healthLiveList(@RequestBody com.fs.hisStore.param.FsStoreOrderParam param) {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+        param.setOrderType(2);
+        if (!"00".equals(loginUser.getUser().getUserType())) {
+            param.setCompanyUserId(loginUser.getUser().getUserId());
+        } else {
+            param.setCompanyUserId(null);
+        }
+        if (StringUtils.isNotEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (StringUtils.isNotEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (StringUtils.isNotEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if (StringUtils.isNotEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        Map<String, java.math.BigDecimal> statistics = fsStoreOrderScrmService.selectFsStoreOrderStatistics(param);
+        String productInfoStr = fsStoreOrderScrmService.selectFsStoreOrderProductStatistics(param);
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<com.fs.hisStore.vo.FsStoreOrderVO> list = fsStoreOrderScrmService.selectFsStoreOrderListVO(param);
+        if (list != null) {
+            for (com.fs.hisStore.vo.FsStoreOrderVO vo : list) {
+                if (StringUtils.isNotEmpty(vo.getPhone())) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (StringUtils.isNotEmpty(vo.getUserPhone())) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+            }
+        }
+        FsStoreOrderListAndStatisticsVo vo = new FsStoreOrderListAndStatisticsVo();
+        vo.setRows(list);
+        vo.setTotal(new com.github.pagehelper.PageInfo<>(list).getTotal());
+        vo.setCode(200);
+        vo.setMsg("查询成功");
+        if (list != null && !list.isEmpty()) {
+            if (statistics != null && statistics.size() >= 3) {
+                vo.setPayPriceTotal(statistics.get("pay_price") != null ? statistics.get("pay_price").toString() : "0");
+                vo.setPayMoneyTotal(statistics.get("pay_money") != null ? statistics.get("pay_money").toString() : "0");
+                vo.setPayRemainTotal(statistics.get("pay_remain") != null ? statistics.get("pay_remain").toString() : "0");
+            } else {
+                vo.setPayPriceTotal("0");
+                vo.setPayMoneyTotal("0");
+                vo.setPayRemainTotal("0");
+            }
+            vo.setProductInfo(StringUtils.isNotBlank(productInfoStr) ? productInfoStr : "");
+        } else {
+            vo.setPayPriceTotal("0");
+            vo.setPayMoneyTotal("0");
+            vo.setPayRemainTotal("0");
+            vo.setProductInfo("");
+        }
+        return vo;
+    }
+
+    /** 直播订单导出:筛选条件与 healthLiveList 一致(orderType=2 + 公司/负责人权限) */
+    private void applyHealthLiveFilter(com.fs.hisStore.param.FsStoreOrderParam param) {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+        param.setOrderType(2);
+        if (!"00".equals(loginUser.getUser().getUserType())) {
+            param.setCompanyUserId(loginUser.getUser().getUserId());
+        } else {
+            param.setCompanyUserId(null);
+        }
+        if (StringUtils.isNotEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (StringUtils.isNotEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (StringUtils.isNotEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if (StringUtils.isNotEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+    }
+
+    private void normalizeExportParam(com.fs.hisStore.param.FsStoreOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (StringUtils.isNotEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if ((param.getOrderCodes() == null || param.getOrderCodes().isEmpty())
+                && StringUtils.isNotBlank(param.getOrderCodeList())) {
+            String[] arr = param.getOrderCodeList().split("[,,\\s]+");
+            param.setOrderCodes(new ArrayList<>(Arrays.asList(arr)));
+        }
+    }
+
+    /**
+     * 导出直播订单列表(脱敏)
+     */
+    @Log(title = "直播订单导出", businessType = BusinessType.EXPORT)
+    @PostMapping("/healthExport")
+    public AjaxResult healthExport(@RequestBody com.fs.hisStore.param.FsStoreOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        applyHealthLiveFilter(param);
+        if (fsStoreOrderScrmService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        List<FsStoreOrderErpExportVO> list = fsStoreOrderScrmService.selectFsStoreOrderListVOByExport(param);
+        if (list != null) {
+            for (FsStoreOrderErpExportVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserPhone() != null) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserAddress() != null) {
+                    vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+                }
+            }
+        }
+        String filter = param.getFilter();
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+        ExcelUtil<FsStoreOrderErpExportVO> util = new ExcelUtil<>(FsStoreOrderErpExportVO.class);
+        if (filter != null && !filter.isEmpty()) {
+            return util.exportExcelSelectedColumns(list, "订单数据", filterList);
+        } else {
+            return util.exportExcel(list, "订单数据");
+        }
+    }
+
+    /**
+     * 导出直播订单列表(明文)
+     */
+    @Log(title = "直播订单导出(明文)", businessType = BusinessType.EXPORT)
+    @PostMapping("/healthExportDetails")
+    public AjaxResult healthExportDetails(@RequestBody com.fs.hisStore.param.FsStoreOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        applyHealthLiveFilter(param);
+        if (fsStoreOrderScrmService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        List<FsStoreOrderErpExportVO> list = fsStoreOrderScrmService.selectFsStoreOrderListVOByExport(param);
+        String filter = param.getFilter();
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+        ExcelUtil<FsStoreOrderErpExportVO> util = new ExcelUtil<>(FsStoreOrderErpExportVO.class);
+        if (filter != null && !filter.isEmpty()) {
+            return util.exportExcelSelectedColumns(list, "订单数据", filterList);
+        } else {
+            return util.exportExcel(list, "订单数据");
+        }
+    }
+
+    /**
+     * 导出直播订单明细(脱敏)
+     */
+    @Log(title = "直播订单明细导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/healthExportItems")
+    public AjaxResult healthExportItems(com.fs.hisStore.param.FsStoreOrderParam param) {
+        normalizeExportParam(param);
+        applyHealthLiveFilter(param);
+        if (fsStoreOrderScrmService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        List<FsStoreOrderItemExportVO> list = orderItemScrmService.selectFsStoreOrderItemListExportVO(param);
+        if (list != null) {
+            LoginUser loginUser = SecurityUtils.getLoginUser();
+            for (FsStoreOrderItemExportVO vo : list) {
+                if (vo.getUserPhone() != null) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2"));
+                }
+                if (StringUtils.isNotEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO dto = com.alibaba.fastjson.JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(dto, vo);
+                    } catch (Exception e) {
+                        // ignore
+                    }
+                }
+                if (vo.getUserAddress() != null) {
+                    vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+                }
+                if ((loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) && vo.getCost() != null) {
+                    vo.setFPrice(vo.getCost().multiply(java.math.BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(java.math.BigDecimal.ZERO);
+                    vo.setCost(java.math.BigDecimal.ZERO);
+                    vo.setFPrice(java.math.BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
+            }
+        }
+        ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<>(FsStoreOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+
+    /**
+     * 导出直播订单明细(明文)
+     */
+    @Log(title = "直播订单明细导出(明文)", businessType = BusinessType.EXPORT)
+    @GetMapping("/healthExportItemsDetails")
+    public AjaxResult healthExportItemsDetails(com.fs.hisStore.param.FsStoreOrderParam param) {
+        normalizeExportParam(param);
+        applyHealthLiveFilter(param);
+        if (fsStoreOrderScrmService.isEntityNull(param)) {
+            return AjaxResult.error("请筛选数据导出");
+        }
+        List<FsStoreOrderItemExportVO> list = orderItemScrmService.selectFsStoreOrderItemListExportVO(param);
+        if (list != null) {
+            LoginUser loginUser = SecurityUtils.getLoginUser();
+            for (FsStoreOrderItemExportVO vo : list) {
+                if (StringUtils.isNotEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO dto = com.alibaba.fastjson.JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(dto, vo);
+                    } catch (Exception e) {
+                        // ignore
+                    }
+                }
+                if ((loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) && vo.getCost() != null) {
+                    vo.setFPrice(vo.getCost().multiply(java.math.BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(java.math.BigDecimal.ZERO);
+                    vo.setCost(java.math.BigDecimal.ZERO);
+                    vo.setFPrice(java.math.BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                    vo.setBankTransactionId("");
+                }
+            }
+        }
+        ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<>(FsStoreOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+
     /**
      * 查询订单列表
      */

+ 2 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallees.java

@@ -62,4 +62,6 @@ public class CompanyVoiceRoboticCallees{
 
     @TableField(exist = false)
     private String idToString;
+
+    private Integer isWeCom;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCalleesMapper.java

@@ -84,6 +84,6 @@ public interface CompanyVoiceRoboticCalleesMapper extends BaseMapper<CompanyVoic
 
     List<SendMsgByTaskVO> getSendMsgTaskListByRoboticId(@Param("roboticId") Long roboticId);
 
-    List<CompanyVoiceRoboticCallees> selectExcludeList(@Param("list")List<CompanyWxClient> list);
+    List<CompanyVoiceRoboticCallees> selectExcludeList(@Param("list")List<CompanyWxClient> list,@Param("isWeCom") Integer isWeCom);
     List<Long> getNotFinishAddWxRobotic(@Param("roboticIds") Set<Long> roboticIds);
 }

+ 1 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyWxClientMapper.java

@@ -84,4 +84,5 @@ public interface CompanyWxClientMapper extends BaseMapper<CompanyWxClient> {
 
     List<CompanyWxClient> getQwAddWxList(@Param("accountIdList") List<Long> accountIdList, @Param("isWeCom") Integer isWeCom);
 
+    List<CompanyWxClient4WorkFlowVO> getQwAddWxList4Workflow(@Param("accountIdList") List<Long> accountIdList, @Param("execStatus") Integer execStatus, @Param("execNodeType") Integer execNodeType);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyWxClientService.java

@@ -74,4 +74,6 @@ public interface ICompanyWxClientService extends IService<CompanyWxClient> {
     List<CompanyWxClient4WorkFlowVO> getAddWxList4Workflow(List<Long> accountIdList);
 
     List<CompanyWxClient> getQwAddWxList(List<Long> accountIdList,Integer isWeCom);
+
+    List<CompanyWxClient4WorkFlowVO> getQwAddWxList4Workflow(List<Long> accountIdList);
 }

+ 14 - 2
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java

@@ -29,6 +29,8 @@ import com.fs.company.mapper.CompanyVoiceRoboticCalleesMapper;
 import com.fs.company.mapper.CompanyWxAccountMapper;
 import com.fs.company.service.CompanyWorkflowEngine;
 import com.fs.company.vo.CidConfigVO;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.store.config.StoreConfig;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.constant.Constant;
@@ -67,6 +69,8 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
     @Autowired
     CompanyWorkflowEngine companyWorkflowEngine;
     @Autowired
+    QwUserMapper qwUserMapper;
+    @Autowired
     @Qualifier("cidWorkFlowExecutor")
     private Executor cidWorkFlowExecutor;
 
@@ -203,8 +207,16 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
 
                 CompanyWxClient companyWxClient = companyWxClientServiceImpl.getOne(new QueryWrapper<CompanyWxClient>().eq("robotic_id", callees.getRoboticId()).eq("customer_id", callees.getUserId()));
                 CompanyVoiceRoboticWx roboticWx = companyVoiceRoboticWxServiceImpl.getById(companyWxClient.getRoboticWxId());
-                CompanyWxAccount companyWxAccount = companyWxAccountMapper.selectCompanyWxAccountById(roboticWx.getAccountId());
-                companyVoiceRoboticCallLog.setCompanyUserId(companyWxAccount.getCompanyUserId());
+                Long setCompanyUserId = null;
+                if(Integer.valueOf(1).equals(companyWxClient.getIsWeCom())){
+                    CompanyWxAccount companyWxAccount = companyWxAccountMapper.selectCompanyWxAccountById(roboticWx.getAccountId());
+                    setCompanyUserId =  companyWxAccount.getCompanyUserId();
+                }else if(Integer.valueOf(2).equals(companyWxClient.getIsWeCom())){
+                    QwUser qwUser = qwUserMapper.selectById(roboticWx.getAccountId());
+                    setCompanyUserId = qwUser.getCompanyUserId();
+                }
+
+                companyVoiceRoboticCallLog.setCompanyUserId(setCompanyUserId);
                 // 调用接口查询通话其他信息
                 TaskInfo dialogMap = aiCallService.getDialogMapNew(getDialogMap, companyVoiceRoboticCallLog.getCompanyId());
                 // 写入其他记录

+ 3 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java

@@ -185,6 +185,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
             callees.setResult(0);
             callees.setTaskFlow(companyVoiceRobotic.getTaskFlow());
             callees.setRunTaskFlow(companyVoiceRobotic.getRunTaskFlow());
+            callees.setIsWeCom(isWeCom);
             return callees;
         }).collect(Collectors.toList());
         companyVoiceRoboticCalleesService.saveBatch(callesList);
@@ -1093,7 +1094,8 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
 
     // 绑定销售
     private void bindCompany(CompanyWxClient client, List<CompanyVoiceRoboticWx> wxList) {
-        List<CompanyVoiceRoboticWx> wx = wxList.stream().filter(f -> f.getAccount() != null && f.getAccount().getAllocateNum() < f.getAccount().getAddNum()).collect(Collectors.toList());
+//         取消再分配时 最大加微限制判定 && f.getAccount().getAllocateNum() < f.getAccount().getAddNum()
+        List<CompanyVoiceRoboticWx> wx = wxList.stream().filter(f -> f.getAccount() != null).collect(Collectors.toList());
         // 绑定销售,添加值达到阈值后设置为空,等待下次绑定
         if (!wx.isEmpty()) {
             CompanyVoiceRoboticWx companyVoiceRoboticWx = wx.get(0);

+ 10 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyWxClientServiceImpl.java

@@ -246,4 +246,14 @@ public class CompanyWxClientServiceImpl extends ServiceImpl<CompanyWxClientMappe
     public List<CompanyWxClient> getQwAddWxList(List<Long> accountIdList, Integer isWeCom) {
         return baseMapper.getQwAddWxList(accountIdList,isWeCom);
     }
+
+    /**
+     * 获取添加微信列表 工作流用
+     * @param accountIdList
+     * @return
+     */
+    @Override
+    public  List<CompanyWxClient4WorkFlowVO> getQwAddWxList4Workflow(List<Long> accountIdList){
+        return baseMapper.getQwAddWxList4Workflow(accountIdList, ExecutionStatusEnum.WAITING.getValue(), NodeTypeEnum.AI_QW_ADD_WX_TASK.getValue());
+    }
 }

+ 12 - 7
fs-service/src/main/java/com/fs/company/service/impl/CompanyWxServiceImpl.java

@@ -8,10 +8,7 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.utils.DateUtils;
 import com.fs.company.domain.*;
-import com.fs.company.mapper.CompanyAiWorkflowExecLogMapper;
-import com.fs.company.mapper.CompanyAiWorkflowExecMapper;
-import com.fs.company.mapper.CompanyWxAccountMapper;
-import com.fs.company.mapper.CompanyWxClientMapper;
+import com.fs.company.mapper.*;
 import com.fs.company.service.*;
 import com.fs.company.service.impl.call.node.AiAddWxTaskNode;
 import com.fs.enums.ExecutionStatusEnum;
@@ -101,6 +98,8 @@ public class CompanyWxServiceImpl extends ServiceImpl<CompanyWxAccountMapper, Co
     @Autowired
     private CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper;
 
+    @Autowired
+    CompanyAiWorkflowServerMapper companyAiWorkflowServerMapper;
 
 
     /**
@@ -256,7 +255,13 @@ public class CompanyWxServiceImpl extends ServiceImpl<CompanyWxAccountMapper, Co
         if (addressId==null || addressId.isEmpty()){
             return R.error("请先绑定地址");
         }
-        Long serverId = cidIpadServerService.selectQwIpadServerByAddressId(addressId);
+        Long cidServerId = companyUser.getCidServerId();
+        if ( cidServerId==null ){
+            return R.error("请先绑定cid服务");
+        }
+        CompanyAiWorkflowServer cidServer = companyAiWorkflowServerMapper.selectCompanyAiWorkflowServerById(companyUser.getCidServerId());
+
+        Long serverId = cidIpadServerService.selectQwIpadServerByAddressId(addressId,cidServer.getGroupNo());
         if (serverId==null){
             return  R.error(501,"该地区服务器剩余数量不足");
         }
@@ -264,7 +269,7 @@ public class CompanyWxServiceImpl extends ServiceImpl<CompanyWxAccountMapper, Co
         account.setServerStatus(1);
         updateById(account);
 
-        cidIpadServerService.subtractServer(serverId);
+//        cidIpadServerService.subtractServer(serverId);
         CidIpadServerUser qwIpadServerUser = new CidIpadServerUser();
         qwIpadServerUser.setCompanyUserId(companyUser.getUserId());
         qwIpadServerUser.setCompanyId(companyUser.getCompanyId());
@@ -608,7 +613,7 @@ public class CompanyWxServiceImpl extends ServiceImpl<CompanyWxAccountMapper, Co
             }
 
             // 清除超时检测Key(回调成功了,不需要超时检测了)
-            AiAddWxTaskNode.clearTimeoutKey(workflowInstanceId, wxClientId);
+//            AiAddWxTaskNode.clearTimeoutKey(workflowInstanceId, wxClientId);
 
             // 触发工作流继续执行
             Map<String, Object> inputData = new HashMap<>();

+ 15 - 15
fs-service/src/main/java/com/fs/company/service/impl/call/node/AiAddWxTaskNode.java

@@ -35,7 +35,7 @@ public class AiAddWxTaskNode extends AbstractWorkflowNode {
     private static final CompanyWorkflowNodeMapper companyWorkflowNodeMapper = SpringUtils.getBean(CompanyWorkflowNodeMapper.class);
     @SuppressWarnings("unchecked")
     private static final RedisCacheT<String> redisCache = SpringUtils.getBean(RedisCacheT.class);
-    public static final String DELAY_ADD_WX_KEY = "addWxTask:delay:%s:%s:";
+    public static final String DELAY_ADD_WX_KEY = "addWxTask:delay:%s:%s:%s:";
     /**
      * 默认加微超时时间(分钟)
      */
@@ -225,17 +225,17 @@ public class AiAddWxTaskNode extends AbstractWorkflowNode {
         return true;
     }
 
-    /**
-     * 清除超时检测 Key
-     *
-     * @param workflowInstanceId 工作流实例ID
-     * @param wxClientId         加微客户ID
-     */
-    public static void clearTimeoutKey(String workflowInstanceId, Long wxClientId) {
-        String timeoutKey = Constants.WORKFLOW_ADD_WX_TIMEOUT + workflowInstanceId + ":" + wxClientId;
-        redisCache.deleteObject(timeoutKey);
-        log.info("清除加微超时检测 Key: {}", timeoutKey);
-    }
+//    /**
+//     * 清除超时检测 Key
+//     *
+//     * @param workflowInstanceId 工作流实例ID
+//     * @param wxClientId         加微客户ID
+//     */
+//    public static void clearTimeoutKey(String workflowInstanceId, Long wxClientId) {
+//        String timeoutKey = Constants.WORKFLOW_ADD_WX_TIMEOUT + workflowInstanceId + ":" + wxClientId;
+//        redisCache.deleteObject(timeoutKey);
+//        log.info("清除加微超时检测 Key: {}", timeoutKey);
+//    }
 
     /**
      * getRedisCacheKey
@@ -243,12 +243,12 @@ public class AiAddWxTaskNode extends AbstractWorkflowNode {
      * @param time
      * @return
      */
-    public static String getDelayAddWxKeyPrefix(Long time) {
+    public static String getDelayAddWxKeyPrefix(Integer cidGroupNo,Long time) {
         Date nowDay = new Date();
         if (null != time) {
             nowDay = new Date(time);
         }
-        return String.format(DELAY_ADD_WX_KEY, nowDay.getHours(), nowDay.getMinutes());
+        return String.format(DELAY_ADD_WX_KEY,cidGroupNo, nowDay.getHours(), nowDay.getMinutes());
     }
 
     /**
@@ -287,7 +287,7 @@ public class AiAddWxTaskNode extends AbstractWorkflowNode {
                 //节点包含延时条件
                 if (null != condition.getAddTime() && !condition.isAdd()) {
                     long l = System.currentTimeMillis() + condition.getAddTime() * 60 * 1000;
-                    String redisKey = getDelayAddWxKeyPrefix(l) + workflowInstanceId;
+                    String redisKey = getDelayAddWxKeyPrefix(exec.getCidGroupNo(),l) + workflowInstanceId;
                     ExecutionContext nextContext = context.clone();
                     nextContext.setCurrentNodeKey(edge.getTargetNodeKey());
                     super.redisCache.setCacheObject(redisKey, nextContext);

+ 5 - 5
fs-service/src/main/java/com/fs/company/service/impl/call/node/AiCallTaskNode.java

@@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
 public class AiCallTaskNode extends AbstractWorkflowNode {
     private static final CompanyWorkflowNodeMapper companyWorkflowNodeMapper = SpringUtils.getBean(CompanyWorkflowNodeMapper.class);
     private static final ICompanyVoiceRoboticService companyVoiceRoboticService = SpringUtils.getBean(ICompanyVoiceRoboticService.class);
-    public static final String DELAY_CALL_KEY = "aiCallTask:delay:%s:%s:";
+    public static final String DELAY_CALL_KEY = "aiCallTask:delay:%s:%s:%s:";
     private final String CALL_FROM_CALLBACK = "callBack";
     private final String CALL_FROM_TIMER = "timer";
 
@@ -110,7 +110,7 @@ public class AiCallTaskNode extends AbstractWorkflowNode {
                         ExecutionContext nextContext = context.clone();
                         nextContext.setCurrentNodeKey(edge.getTargetNodeKey());
                         //添加到延时扫描redis
-                        super.redisCache.setCacheObject(this.getDelayCallKeyPrefix(l) + exec.getWorkflowInstanceId(), nextContext, 1, TimeUnit.DAYS);
+                        super.redisCache.setCacheObject(this.getDelayCallKeyPrefix(exec.getCidGroupNo(),l) + exec.getWorkflowInstanceId(), nextContext, 1, TimeUnit.DAYS);
                         super.asyncWorkflowForBlockingNode(context.getWorkflowInstanceId(), context.getCurrentNodeKey(), context, ExecutionStatusEnum.WAITING);
                         updateLogStatusIfExist(context, ExecutionStatusEnum.PAUSED, ExecutionStatusEnum.WAITING);
                         runnableCount++;
@@ -187,16 +187,16 @@ public class AiCallTaskNode extends AbstractWorkflowNode {
 
     /**
      * getRedisCacheKey
-     *
+     * @param cidGroupNo
      * @param time
      * @return
      */
-    public static String getDelayCallKeyPrefix(Long time) {
+    public static String getDelayCallKeyPrefix(Integer cidGroupNo,Long time) {
         Date nowDay = new Date();
         if (null != time) {
             nowDay = new Date(time);
         }
-        return String.format(DELAY_CALL_KEY, nowDay.getHours(), nowDay.getMinutes());
+        return String.format(DELAY_CALL_KEY, cidGroupNo,nowDay.getHours(), nowDay.getMinutes());
     }
 
 //    @Override

+ 46 - 40
fs-service/src/main/java/com/fs/company/service/impl/call/node/AiQwAddWxTaskNode.java

@@ -1,5 +1,6 @@
 package com.fs.company.service.impl.call.node;
 
+import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.constant.Constants;
 import com.fs.common.core.redis.RedisCacheT;
@@ -65,10 +66,14 @@ public class AiQwAddWxTaskNode extends AbstractWorkflowNode {
         boolean addSuccess = wxClient != null && Integer.valueOf(1).equals(wxClient.getIsAdd());
         //回调加微成功
         if (addSuccess) {
-            List<CompanyWorkflowEdge> cList = edges.stream().filter(a ->
-                            StringUtils.isNotBlank(a.getConditionExpr()) && JSONObject.parseArray(a.getConditionExpr(), AiCallWorkflowConditionVo.class).get(0).isAdd())
-                    .collect(Collectors.toList());
-            if(!cList.isEmpty() && nodeKey.equals(exec.getCurrentNodeKey())){
+            List<CompanyWorkflowEdge> cList = edges.stream().filter(a -> {
+                if (StringUtils.isBlank(a.getConditionExpr())) {
+                    return false;
+                }
+                List<AiCallWorkflowConditionVo> list = JSONObject.parseArray(a.getConditionExpr(), AiCallWorkflowConditionVo.class);
+                return list != null && !list.isEmpty() && list.get(0).isAdd();
+            }).collect(Collectors.toList());
+            if (!cList.isEmpty() && nodeKey.equals(exec.getCurrentNodeKey())) {
                 super.runNextNode(context, cList.get(0));
             }
         }
@@ -78,7 +83,8 @@ public class AiQwAddWxTaskNode extends AbstractWorkflowNode {
                     .collect(Collectors.toList());
             // 加微失败,根据条件判断走哪条边
             CompanyWorkflowEdge edge = cList.get(0);
-                AiCallWorkflowConditionVo condition = JSONObject.parseObject(edge.getConditionExpr(), AiCallWorkflowConditionVo.class);
+            List<AiCallWorkflowConditionVo> conditions = JSONObject.parseArray(edge.getConditionExpr(), AiCallWorkflowConditionVo.class);
+             AiCallWorkflowConditionVo condition = conditions.get(0);
                 // 匹配失败条件
                 if (!condition.isAdd()) {
                     log.info("加微失败,执行失败分支 - workflowInstanceId: {}", context.getWorkflowInstanceId());
@@ -104,8 +110,8 @@ public class AiQwAddWxTaskNode extends AbstractWorkflowNode {
             return ExecutionResult.failure().nextNodeKey(null).build();
         }
         try {
-            super.asyncWorkflowForBlockingNode(context.getWorkflowInstanceId(), context.getCurrentNodeKey(), context, ExecutionStatusEnum.PAUSED);
-            return ExecutionResult.paused()
+            super.asyncWorkflowForBlockingNode(context.getWorkflowInstanceId(), context.getCurrentNodeKey(), context, ExecutionStatusEnum.WAITING);
+            return ExecutionResult.waiting()
                     .outputData(context.getVariables())
                     .nextNodeKey("").build();
         } catch (Exception e) {
@@ -184,49 +190,49 @@ public class AiQwAddWxTaskNode extends AbstractWorkflowNode {
      * getRedisCacheKey
      *
      */
-    public static String getDelayAddWxKeyPrefix(Long time) {
+    public static String getDelayAddWxKeyPrefix(Integer cidGroupNo,Long time) {
         Date nowDay;
         if (null != time) {
             nowDay = new Date(time);
         }else{
             nowDay = new Date();
         }
-        return String.format(DELAY_QW_ADD_WX_KEY, nowDay.getHours(), nowDay.getMinutes());
+        return String.format(DELAY_QW_ADD_WX_KEY,cidGroupNo, nowDay.getHours(), nowDay.getMinutes());
     }
 
     /**
      * 完成加微动作
      *
      */
-//    public void doneQwAddWx(String workflowInstanceId) {
-//        ExecutionContext context = createExecutionContext(workflowInstanceId, nodeKey);
-//        context.setVariable("lastNodeKey", nodeKey);
-//        //启动定时节点倒计时
-//        CompanyAiWorkflowExec exec = companyAiWorkflowExecMapper.selectByWorkflowInstanceId(context.getWorkflowInstanceId());
-//        if (!exec.getCurrentNodeKey().equals(nodeKey)) {
-//            //当前节点已流转
-//            log.error("当前节点已流转 ,目标:{},实际:{}", nodeKey, exec.getCurrentNodeKey());
-//            return;
-//        }
-//        //更新加微日志执行状态
-//        super.updateLogStatusIfExist(context, ExecutionStatusEnum.PAUSED, ExecutionStatusEnum.WAITING);
-//        super.asyncWorkflowForBlockingNode(context.getWorkflowInstanceId(), nodeKey, context, ExecutionStatusEnum.WAITING);
-//        List<CompanyWorkflowEdge> edges = companyWorkflowEdgeMapper.selectListByWorkflowIdAndNodeKey(exec.getWorkflowId(), nodeKey);
-//        edges.forEach(edge -> {
-//            List<AiCallWorkflowConditionVo> conditions = JSONObject.parseArray(edge.getConditionExpr(), AiCallWorkflowConditionVo.class);
-//            if (null == conditions || conditions.isEmpty()) {
-//                super.runNextNode(context, edge);
-//            } else {
-//                AiCallWorkflowConditionVo condition = conditions.get(0);
-//                //节点包含延时条件
-//                if (null != condition.getAddTime() && !condition.isAdd()) {
-//                    long l = System.currentTimeMillis() + condition.getAddTime() * 60 * 1000;
-//                    String redisKey = getDelayAddWxKeyPrefix(l) + workflowInstanceId;
-//                    ExecutionContext nextContext = context.clone();
-//                    nextContext.setCurrentNodeKey(edge.getTargetNodeKey());
-//                    super.redisCache.setCacheObject(redisKey, nextContext);
-//                }
-//            }
-//        });
-//    }
+    public void doneQwAddWx(String workflowInstanceId) {
+        ExecutionContext context = createExecutionContext(workflowInstanceId, nodeKey);
+        context.setVariable("lastNodeKey", nodeKey);
+        //启动定时节点倒计时
+        CompanyAiWorkflowExec exec = companyAiWorkflowExecMapper.selectByWorkflowInstanceId(context.getWorkflowInstanceId());
+        if (!exec.getCurrentNodeKey().equals(nodeKey)) {
+            //当前节点已流转
+            log.error("当前节点已流转 ,目标:{},实际:{}", nodeKey, exec.getCurrentNodeKey());
+            return;
+        }
+        //更新加微日志执行状态
+        super.updateLogStatusIfExist(context, ExecutionStatusEnum.WAITING, ExecutionStatusEnum.WAITING);
+        super.asyncWorkflowForBlockingNode(context.getWorkflowInstanceId(), nodeKey, context, ExecutionStatusEnum.WAITING);
+        List<CompanyWorkflowEdge> edges = companyWorkflowEdgeMapper.selectListByWorkflowIdAndNodeKey(exec.getWorkflowId(), nodeKey);
+        edges.forEach(edge -> {
+            List<AiCallWorkflowConditionVo> conditions = JSONObject.parseArray(edge.getConditionExpr(), AiCallWorkflowConditionVo.class);
+            if (CollectionUtil.isEmpty(conditions)) {
+                super.runNextNode(context, edge);
+            } else {
+                AiCallWorkflowConditionVo condition = conditions.get(0);
+                //节点包含延时条件
+                if (null != condition.getAddTime() && !condition.isAdd()) {
+                    long l = System.currentTimeMillis() + condition.getAddTime() * 60 * 1000;
+                    String redisKey = getDelayAddWxKeyPrefix(exec.getCidGroupNo(),l) + workflowInstanceId;
+                    ExecutionContext nextContext = context.clone();
+                    nextContext.setCurrentNodeKey(edge.getTargetNodeKey());
+                    super.redisCache.setCacheObject(redisKey, nextContext);
+                }
+            }
+        });
+    }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/impl/call/node/WorkflowNodeFactory.java

@@ -3,6 +3,7 @@ package com.fs.company.service.impl.call.node;
 import com.fs.company.service.IWorkflowNode;
 import com.fs.company.service.IWorkflowNodeFactory;
 import com.fs.enums.NodeTypeEnum;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.util.Map;
@@ -15,7 +16,6 @@ import java.util.Map;
 @Component
 public class WorkflowNodeFactory implements IWorkflowNodeFactory {
 
-
     @Override
     public IWorkflowNode createNode(String nodeKey, NodeTypeEnum type, String nodeName,
                                     Map<String, Object> properties) {

+ 3 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -4549,10 +4549,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
      * 小黄车商品和展示
      */
     private void getGoodsAndShow(Long videoId, FsUserCourseVideoDetailsVO vo) {
-        String show = fsDepVideoShowMapper.selectFsDepVideoShowByVideoId(videoId, null);
-        vo.setShowProduct(show);
+//        String show = fsDepVideoShowMapper.selectFsDepVideoShowByVideoId(videoId, null);
+//        vo.setShowProduct(show);
 
         FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        vo.setShowProduct(courseVideo.getIsProduct() == 1 ? "0" : "1");
         String packageJson = courseVideo.getPackageJson();
         if (StringUtils.isNotEmpty(packageJson)) {
             ObjectMapper objectMapper = new ObjectMapper();

+ 5 - 0
fs-service/src/main/java/com/fs/his/domain/FsPackage.java

@@ -104,4 +104,9 @@ public class FsPackage extends BaseEntity
     /** 节气 */
     private Long solarTerm;
     private String appIds;
+    /**
+     * 是否食品/保健品类型,1-是;0-否
+     */
+    @Excel(name = "是否食品/保健品")
+    private Integer isHealthProductType;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -516,7 +516,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         FsPatient patient=null;
         FsDoctor doctor=null;
         FsPackage fsPackage=fsPackageMapper.selectFsPackageByPackageId(param.getPackageId());
-        if(fsPackage.getProductType()!= null &&(fsPackage.getProductType()==1 || fsPackage.getProductType()==2)){
+        if(fsPackage.getProductType()!= null &&(fsPackage.getProductType()==1 || fsPackage.getProductType()==2) && fsPackage.getIsHealthProductType() == 0){
             if(param.getPatientId()!=null){
                 patient=fsPatientMapper.selectFsPatientByPatientId(param.getPatientId());
                 if (patient==null){

+ 2 - 0
fs-service/src/main/java/com/fs/his/vo/FsPackageVO.java

@@ -124,4 +124,6 @@ public class FsPackageVO {
 
     private Long solarTerm;
     private String appIds;
+    @Excel(name = "是否食品/保健品")
+    private Integer isHealthProductType;
 }

+ 12 - 4
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java

@@ -75,12 +75,11 @@ public interface FsStoreOrderItemScrmMapper
     List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long id);
 
     @Select({"<script> " +
-            "select i.*,o.user_id,psps.cost,o.pay_postage,o.total_num,o.status,fspcs.cate_name, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload,p.title as package_name,cts.name as scheduleName,os.pay_money, os.bank_transaction_id as bankTransactionId, o.delivery_send_time," +
+            "select i.*,o.user_id,psps.cost,o.pay_postage,o.total_num,o.status,fspcs.cate_name, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload,p.title as package_name,cts.name as scheduleName,sp_latest.pay_money, sp_latest.bank_transaction_id as bankTransactionId, o.delivery_send_time," +
             " o.order_code, o.pay_price, o.pay_money, o.deduction_price,o.pay_delivery, o.order_type,psps.price " +
             ", CASE o.is_audit WHEN 1 THEN '是' ELSE '否' END AS isAudit " +
             " from fs_store_order_item_scrm i " +
             " left join fs_store_order_scrm o on o.id=i.order_id" +
-            " left join fs_store_payment_scrm os on os.business_order_id = o.id " +
             " left join fs_user u on o.user_id=u.user_id  " +
             " left join fs_store_product_package_scrm p on o.package_id=p.package_id " +
             " left join company c on c.company_id=o.company_id " +
@@ -99,6 +98,12 @@ public interface FsStoreOrderItemScrmMapper
             "<if test=\"maps.bankTransactionId !=null and maps.bankTransactionId!=''\">" +
             " and sp_latest.bank_transaction_id = #{maps.bankTransactionId} " +
             "</if>" +
+            "<if test=\"maps.orderCodes != null  and maps.orderCodes.size > 0\">" +
+            " and o.order_code in" +
+            " <foreach collection=\"maps.orderCodes\" item=\"orderCode\" open=\"(\" close=\")\" separator=\",\">" +
+            "     #{orderCode}" +
+            " </foreach>" +
+            "</if>" +
             "<if test = 'maps.orderCode != null and  maps.orderCode !=\"\"    '> " +
             "and o.order_code like CONCAT('%',#{maps.orderCode},'%') " +
             "</if>" +
@@ -114,14 +119,17 @@ public interface FsStoreOrderItemScrmMapper
             "<if test = 'maps.userPhone != null and  maps.userPhone !=\"\"     '> " +
             "and o.user_phone like CONCAT('%',#{maps.userPhone},'%') " +
             "</if>" +
-            "<if test = 'maps.status != null    '> " +
+            "<if test = 'maps.status != null and maps.status != 6    '> " +
             "and o.status =#{maps.status} " +
             "</if>" +
+            "<if test = 'maps.status != null and maps.status == 6    '> " +
+            "and o.`status`= 1 and (o.extend_order_id is null or o.extend_order_id like '') " +
+            "</if>" +
             "<if test = 'maps.companyId != null    '> " +
             "and o.company_id =#{maps.companyId} " +
             "</if>" +
             "<if test = 'maps.isHealth != null and maps.isHealth !=  \"\"  '> " +
-            "and o.company_id is null " +
+            "and (o.company_id is null or o.order_type = 2 ) " +
             "</if>" +
             "<if test = 'maps.notHealth != null and maps.notHealth !=  \"\"  '> " +
             "and o.company_id is not null " +

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java

@@ -657,7 +657,7 @@ public interface FsStoreOrderScrmMapper
     List<FsStoreOrderScrm> selectFsStoreOrderListByFinish7Day();
 
     @Select({"<script> " +
-            "select o.*,cts.name as scheduleName,u.nickname,u.phone,cc.push_code,cc.create_time as customer_create_time,cc.source,cc.customer_code, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber ,p.title as package_title ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload  " +
+            "select o.*,cts.name as scheduleName,sp_latest.pay_code as hfshh,u.nickname,u.phone,cc.push_code,cc.create_time as customer_create_time,cc.source,cc.customer_code, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber ,p.title as package_title ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload  " +
             ", CASE o.is_audit WHEN 1 THEN '是' ELSE '否' END AS isAudit " +
             " from fs_store_order_scrm o  " +
             " left JOIN fs_store_product_package_scrm p on o.package_id=p.package_id " +

+ 9 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java

@@ -107,6 +107,9 @@ public interface FsStoreProductScrmMapper
             "<if test = 'maps.isAudit != null '> " +
             "and p.is_audit = #{maps.isAudit} " +
             "</if>" +
+            "<if test = 'maps.isDel != null '> " +
+            "and p.is_del = #{maps.isDel} " +
+            "</if>" +
             "<if test='maps.drugRegCertNo != null and maps.drugRegCertNo != \"\"'>" +
             "    AND p.drug_reg_cert_no LIKE CONCAT('%', #{maps.drugRegCertNo}, '%')" +
             "</if>" +
@@ -184,6 +187,12 @@ public interface FsStoreProductScrmMapper
             "<if test = 'maps.isShow != null    '> " +
             "and p.is_show =#{maps.isShow} " +
             "</if>" +
+            "<if test = 'maps.isAudit != null    '> " +
+            "and p.is_audit =#{maps.isAudit} " +
+            "</if>" +
+            "<if test = 'maps.isDel != null    '> " +
+            "and p.is_del =#{maps.isDel} " +
+            "</if>" +
             "<if test = 'maps.excludeProductIds != null '>" +
             "and p.product_id not in " +
             "<foreach collection='maps.excludeProductIds'  item='item' index='index'  open='(' separator=',' close=')'> " +

+ 3 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderParam.java

@@ -16,6 +16,9 @@ public class FsStoreOrderParam extends BaseEntity implements Serializable
     //多个订单号搜索
     private List<String> orderCodes;
 
+    /** 多个订单号搜索(逗号分隔字符串,用于GET请求) */
+    private String orderCodeList;
+
     private String nickname;
 
     private String phone;

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderExportVO.java

@@ -271,6 +271,10 @@ public class FsStoreOrderExportVO implements Serializable
     @Excel(name = "归属档期")
     private String scheduleName;
 
+    /** 汇付商户订单号 */
+    @Excel(name = "汇付商户订单号")
+    private String hfshh;
+
     @Excel(name = "是否审核")
     private String isAudit;
 

+ 2 - 2
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportZMVO.java

@@ -58,7 +58,7 @@ public class FsStoreOrderItemExportZMVO implements Serializable {
     private BigDecimal FPrice;
 
     @Excel(name = "额外运费")
-    private BigDecimal payDelivery;
+    private BigDecimal payPostage;
 
     @Excel(name = "商品分类")
     private String cateName;
@@ -108,7 +108,7 @@ public class FsStoreOrderItemExportZMVO implements Serializable {
     /** 商品分类(与 MergedOrderVO 一致,不导出) */
 
     // 以下字段供内部使用,不参与导出
-    private BigDecimal payPostage;
+    private BigDecimal payDelivery;
     private Integer totalNum;
     private String jsonInfo;
     private String packageName;

+ 7 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java

@@ -133,6 +133,13 @@ public interface LiveOrderMapper {
     @Select("select * from live_order where order_code=#{orderCode} limit 1")
     LiveOrder selectLiveOrderByOrderCode(@Param("orderCode") String orderCode);
 
+    /**
+     * 根据订单号批量查询直播订单
+     * @param orderCodes 订单号列表
+     * @return 订单列表
+     */
+    List<LiveOrder> selectLiveOrderByOrderCodes(@Param("orderCodes") List<String> orderCodes);
+
     /**
      * 查询状态为6(被拆分)的订单
      */

+ 5 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java

@@ -577,9 +577,14 @@ public class LiveDataServiceImpl implements ILiveDataService {
     @Override
     public List<LiveAppSimpleVO> listLivingLivesForApp() {
         List<LiveAppSimpleVO> list = liveDataMapper.selectLivingLivesForApp();
+
         if (list == null || list.isEmpty()) {
             return list;
         }
+        // 如果查询结果超过 3 条,进行截取
+        if (list.size() > 3) {
+            list = list.subList(0, 3);
+        }
         for (LiveAppSimpleVO vo : list) {
             if (vo.getLiveType() != null && vo.getLiveType() == 2 && vo.getLiveId() != null) {
                 try {

+ 3 - 3
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -4062,7 +4062,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         // 注意:bizOrderType 字段需要在 FsStoreOrderScrm 实体类中添加
         // storeOrder.setBizOrderType(1); // 设置为直播订单
 
-        BigDecimal payPrice = fsStoreProduct.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
+        BigDecimal totalPrice = fsStoreProduct.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
+        BigDecimal payPrice = totalPrice;
         if (attrValue != null) {
             payPrice = attrValue.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
         }
@@ -4097,7 +4098,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         // 设置商城订单字段(按照 createOrder 的逻辑)
         storeOrder.setUserId(Long.parseLong(liveOrder.getUserId()));
         storeOrder.setTotalNum(Long.parseLong(liveOrder.getTotalNum()));
-        storeOrder.setTotalPrice(payPrice);
+        storeOrder.setTotalPrice(totalPrice);
         storeOrder.setTotalPostage(deliveryMoney);
         storeOrder.setPayPostage(deliveryMoney);
         storeOrder.setPayDelivery(deliveryMoney);
@@ -4124,7 +4125,6 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
 
         // 设置支付金额
         storeOrder.setPayPrice(payPrice.subtract(discountMoney));
-        storeOrder.setPayMoney(storeOrder.getPayPrice());
 
         // 设置订单状态
         storeOrder.setStatus(0); // 待支付

+ 1 - 1
fs-service/src/main/java/com/fs/wxcid/service/ICidIpadServerService.java

@@ -60,7 +60,7 @@ public interface ICidIpadServerService extends IService<CidIpadServer>{
      */
     int deleteCidIpadServerById(Long id);
 
-    Long selectQwIpadServerByAddressId(String addressId);
+    Long selectQwIpadServerByAddressId(String addressId,Integer cidGroupNo);
 
     void subtractServer(Long serverId);
 }

+ 2 - 2
fs-service/src/main/java/com/fs/wxcid/service/impl/CidIpadServerServiceImpl.java

@@ -96,8 +96,8 @@ public class CidIpadServerServiceImpl extends ServiceImpl<CidIpadServerMapper, C
     }
 
     @Override
-    public Long selectQwIpadServerByAddressId(String addressId) {
-        CidIpadServer ipadServer = getOne(new QueryWrapper<CidIpadServer>().eq("address_id", addressId).last("limit 1"));
+    public Long selectQwIpadServerByAddressId(String addressId,Integer cidGroupNo) {
+        CidIpadServer ipadServer = getOne(new QueryWrapper<CidIpadServer>().eq("address_id", addressId).eq("group_no", cidGroupNo).last("limit 1"));
         if(ipadServer == null){
             throw new CustomException("地区PAD不足");
         }

+ 1 - 0
fs-service/src/main/resources/application-dev.yml

@@ -44,6 +44,7 @@ spring:
                 # 主库数据源
                 master:
                     url: jdbc:mysql://139.186.77.83:3306/ylrz_his_scrm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+#                    url: jdbc:mysql://139.186.77.83:3306/ylrz_his_scrm_hetai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
                     username: Rtroot
                     password: Rtroot
                 # 主库数据源

+ 1 - 1
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogAddwxMapper.xml

@@ -66,7 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createTime != null">#{createTime},</if>
             <if test="companyId != null">#{companyId},</if>
             <if test="wxAccountId != null">#{wxAccountId},</if>
-            <if test="isWeCom != null">#{is_we_com},</if>
+            <if test="isWeCom != null">#{isWeCom},</if>
          </trim>
     </insert>
 

+ 4 - 1
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCalleesMapper.xml

@@ -175,7 +175,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectExcludeList" resultType="com.fs.company.domain.CompanyVoiceRoboticCallees" >
         SELECT * FROM  company_voice_robotic_callees where 1=1
-        <if test="list != null">
+        <if test="isWeCom != null and isWeCom != ''">
+            and is_we_com = #{isWeCom}
+        </if>
+        <if test="list != null and list.size() > 0">
             and
             <foreach item="item" collection="list" separator=" or " open="(" close=")">
                 ( user_id = #{item.customerId} and robotic_id = #{item.roboticId} )

+ 2 - 0
fs-service/src/main/resources/mapper/company/CompanyWxAccountMapper.xml

@@ -56,6 +56,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="phone != null">phone,</if>
             <if test="wxNo != null">wx_no,</if>
             <if test="companyUserId != null">company_user_id,</if>
+            <if test="companyId != null">company_id,</if>
             <if test="createTime != null">create_time,</if>
             <if test="createUser != null">create_user,</if>
          </trim>
@@ -64,6 +65,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="phone != null">#{phone},</if>
             <if test="wxNo != null">#{wxNo},</if>
             <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="companyId != null">#{companyId},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="createUser != null">#{createUser},</if>
          </trim>

+ 14 - 1
fs-service/src/main/resources/mapper/company/CompanyWxClientMapper.xml

@@ -56,6 +56,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         inner join company_voice_robotic robotic on a.robotic_id = robotic.id
         <where>
             <if test="companyId != null"> and b.company_id = #{companyId}</if>
+            <if test="isWeCom != null"> and a.is_we_com = #{isWeCom}</if>
             <if test="roboticId != null "> and a.robotic_id = #{roboticId}</if>
             <if test="roboticWxId != null "> and b.id = #{roboticWxId}</if>
             <if test="customerId != null "> and a.customer_id = #{customerId}</if>
@@ -180,7 +181,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         SELECT t1.*,t3.workflow_instance_id,t3.current_node_key,t3.current_node_name,t3.current_node_type FROM company_wx_client t1
                              inner join company_voice_robotic_business t2 on t1.id = t2.wx_client_id and t1.robotic_id = t2.robotic_id
                              inner join company_ai_workflow_exec t3 on t3.business_key = t2.id
-        where t1.is_add = 0 and t1.account_id is not null
+        where t1.is_add = 0 and t1.account_id is not null and t1.is_we_com = 1
+        and t3.current_node_type = #{execNodeType} And t3.status = #{execStatus}
+        <if test="accountIdList != null and !accountIdList.isEmpty()">
+            and t1.account_id in <foreach collection="accountIdList" open="(" separator="," close=")" item="item">#{item}</foreach>
+        </if>
+        group by t1.account_id
+    </select>
+    <select id="getQwAddWxList4Workflow" resultType="com.fs.company.vo.CompanyWxClient4WorkFlowVO">
+
+        SELECT t1.*,t3.workflow_instance_id,t3.current_node_key,t3.current_node_name,t3.current_node_type FROM company_wx_client t1
+        inner join company_voice_robotic_business t2 on t1.id = t2.wx_client_id and t1.robotic_id = t2.robotic_id
+        inner join company_ai_workflow_exec t3 on t3.business_key = t2.id
+        where t1.is_add = 0 and t1.account_id is not null and t1.is_we_com = 2
         and t3.current_node_type = #{execNodeType} And t3.status = #{execStatus}
         <if test="accountIdList != null and !accountIdList.isEmpty()">
             and t1.account_id in <foreach collection="accountIdList" open="(" separator="," close=")" item="item">#{item}</foreach>

+ 5 - 1
fs-service/src/main/resources/mapper/his/FsPackageMapper.xml

@@ -49,10 +49,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="description"    column="description"    />
         <result property="solarTerm"    column="solar_term"    />
         <result property="appIds"    column="app_ids"    />
+        <result property="isHealthProductType"    column="is_health_product_type"    />
     </resultMap>
 
     <sql id="selectFsPackageVo">
-        select package_id,description,usage_per_use_count,icd_code,images,doctor_remark,second_name,follow_temp_id,product_cost_price,inquiry_cost_price,total_cost_price,follow_num,`explain`,indication,store_id,private_type,recipe_type,counts,usage_frequency_unit, package_name,img_url,is_show,total_price,cycle,duration,`desc`,product_type,price,tags,sales,disease_type,num,package_sub_type,describe_json,pay_type,package_type, sort, product_json, status, create_time, update_time, is_del,solar_term,app_ids from fs_package
+        select package_id,description,usage_per_use_count,icd_code,images,doctor_remark,second_name,follow_temp_id,product_cost_price,inquiry_cost_price,total_cost_price,follow_num,`explain`,indication,store_id,private_type,recipe_type,counts,usage_frequency_unit, package_name,img_url,is_show,total_price,cycle,duration,`desc`,product_type,price,tags,sales,disease_type,num,package_sub_type,describe_json,pay_type,package_type, sort, product_json, status, create_time, update_time, is_del,solar_term,app_ids, is_health_product_type from fs_package
     </sql>
 
     <select id="selectFsPackageList" parameterType="FsPackage" resultMap="FsPackageResult">
@@ -179,6 +180,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="description != null">description,</if>
             <if test="solarTerm != null">solar_term,</if>
             <if test="appIds != null">app_ids,</if>
+            <if test="isHealthProductType != null">is_health_product_type,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="packageName != null">#{packageName},</if>
@@ -224,6 +226,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="description != null">#{description},</if>
             <if test="solarTerm != null">#{solarTerm},</if>
             <if test="appIds != null">#{appIds},</if>
+            <if test="isHealthProductType != null">#{isHealthProductType},</if>
         </trim>
     </insert>
 
@@ -273,6 +276,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="description != null">description = #{description},</if>
             <if test="solarTerm != null">solar_term = #{solarTerm},</if>
             <if test="appIds != null ">app_ids = #{appIds},</if>
+            <if test="isHealthProductType != null ">is_health_product_type = #{isHealthProductType},</if>
         </trim>
         where package_id = #{packageId}
     </update>

+ 8 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml

@@ -173,6 +173,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
     </select>
 
+    <select id="selectFsStoreOrderByOrderCodes" resultMap="FsStoreOrderResult">
+        <include refid="selectFsStoreOrderVo"/>
+        where order_code IN
+        <foreach collection="orderCodes" item="code" open="(" separator="," close=")">
+            #{code}
+        </foreach>
+    </select>
+
     <insert id="insertFsStoreOrder" parameterType="FsStoreOrderScrm" useGeneratedKeys="true" keyProperty="id">
         insert into fs_store_order_scrm
         <trim prefix="(" suffix=")" suffixOverrides=",">

+ 8 - 0
fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml

@@ -654,6 +654,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
     </select>
 
+    <select id="selectLiveOrderByOrderCodes" resultMap="LiveOrderResult">
+        <include refid="selectLiveOrderVo"/>
+        where order_code IN
+        <foreach collection="orderCodes" item="code" open="(" separator="," close=")">
+            #{code}
+        </foreach>
+    </select>
+
     <select id="selectLiveOrderListVO" resultType="com.fs.live.vo.LiveOrderVO">
 
     select o.*,u.phone,u.register_code,u.register_date,u.source, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber

+ 45 - 13
fs-wx-task/src/main/java/com/fs/app/service/WxTaskService.java

@@ -1,14 +1,11 @@
 package com.fs.app.service;
 
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.constant.Constants;
-import com.fs.common.constant.FsConstants;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.utils.PubFun;
@@ -19,7 +16,7 @@ import com.fs.company.param.ExecutionContext;
 import com.fs.company.service.*;
 import com.fs.company.service.impl.*;
 import com.fs.company.service.impl.call.node.AiAddWxTaskNode;
-import com.fs.company.service.impl.call.node.AiCallTaskNode;
+import com.fs.company.service.impl.call.node.AiQwAddWxTaskNode;
 import com.fs.company.service.impl.call.node.WorkflowNodeFactory;
 import com.fs.company.vo.CompanyWxClient4WorkFlowVO;
 import com.fs.course.config.RedisKeyScanner;
@@ -39,19 +36,18 @@ import com.fs.wxcid.dto.friend.AddContactParam;
 import com.fs.wxcid.service.FriendService;
 import com.fs.wxcid.vo.AddContactVo;
 import com.fs.wxwork.dto.WxAddSearchDTO;
-import com.fs.wxwork.dto.WxSearchContactDTO;
-import com.fs.wxwork.dto.WxSearchContactResp;
 import com.fs.wxwork.dto.WxWorkResponseDTO;
 import com.fs.wxwork.service.WxWorkService;
 import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
@@ -62,9 +58,13 @@ import java.util.stream.Collectors;
 
 @Slf4j
 @Service
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class WxTaskService {
 
+
+    @Value("${cid-group-no:0}")
+    private Integer cidGroupNo;
+
     private final ICompanyWxAccountService companyWxAccountService;
     private final ISysConfigService sysConfigService;
     private final ICompanyWxClientService companyWxClientService;
@@ -102,6 +102,7 @@ public class WxTaskService {
     private final QwUserMapper qwUserMapper;
     private final WxWorkService wxWorkService;
     private final QwExternalContactMapper qwExternalContactMapper;
+    private final CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper;
 
     public void addWx(List<Long> accountIdList) {
         log.info("==========执行加微信任务开始==========");
@@ -110,7 +111,7 @@ public class WxTaskService {
         // 需要添加微信的列表
         List<CompanyWxClient> list = companyWxClientService.getAddWxList(accountIdList,1);
         //排除掉没到达加微步骤的人
-        List<CompanyVoiceRoboticCallees> exList = companyVoiceRoboticCalleesMapper.selectExcludeList(list);
+        List<CompanyVoiceRoboticCallees> exList = companyVoiceRoboticCalleesMapper.selectExcludeList(list, 1);
         List<CompanyVoiceRoboticCallees> collect =
                 exList.stream().filter(e -> !Constants.ADD_WX.equals(getNextTaskOptimized(e.getTaskFlow(), e.getRunTaskFlow())))
                         .collect(Collectors.toList());
@@ -295,7 +296,7 @@ public class WxTaskService {
                     if (vo.isSuccess()) {
                         e.setLastAddWxTime(LocalDateTime.now());
 //                        todo 删除还原 以下为测试所用
-//                        e.setLastAddWxTime(LocalDateTime.now().plus(-1, ChronoUnit.DAYS));
+                        e.setLastAddWxTime(LocalDateTime.now().plus(-1, ChronoUnit.DAYS));
                         e.setIsAddNum(e.getIsAddNum() + 1);
                         client.setIsAdd(2);
                         client.setAddTime(LocalDateTime.now());
@@ -826,7 +827,7 @@ public class WxTaskService {
      */
     public void cidWorkflowAddWxRun() {
         log.info("===========工作流延时任务开始扫描===========");
-        String delayAddWxKeyPrefix = AiAddWxTaskNode.getDelayAddWxKeyPrefix(null) + "*";
+        String delayAddWxKeyPrefix = AiAddWxTaskNode.getDelayAddWxKeyPrefix(cidGroupNo,null) + "*";
         Set<String> keys = redisKeyScanner.scanMatchKey(delayAddWxKeyPrefix);
         log.info("共扫描到 {} 个待处理键", keys.size());
         keys.parallelStream().forEach(key -> {
@@ -924,7 +925,38 @@ public class WxTaskService {
         log.info("==========执行企微申请加个微结果查询任务结束==========");
     }
 
-    
+
+    /**
+     * 扫描企微加微工作流延时任务
+     */
+    public void cidWorkflowQwAddWxRun() {
+        log.info("===========企微加微工作流延时任务开始扫描===========");
+        String delayAddWxKeyPrefix = AiQwAddWxTaskNode.getDelayAddWxKeyPrefix(cidGroupNo,null) + "*";
+        Set<String> keys = redisKeyScanner.scanMatchKey(delayAddWxKeyPrefix);
+        log.info("企微加微共扫描到 {} 个待处理键", keys.size());
+        keys.parallelStream().forEach(key -> {
+            try {
+                //doExec
+                CompletableFuture.runAsync(()->{
+                    try {
+                        ExecutionContext context = redisCache2.getCacheObject(key);
+                        context.setVariable("callRedisKey",key);
+                        context.setVariable("callSource","qwAddWxTimer");
+                        companyWorkflowEngine.timeDoExecute(context.getWorkflowInstanceId(),context.getCurrentNodeKey(),context.getVariables());
+                    } catch (Exception e) {
+                        log.error("处理工作流延时任务异常 - key: {}", key, e);
+                    }
+                }, cidExcutor).thenRun(()->{
+                    redisCache2.deleteObject(key);
+                });
+
+            } catch (Exception ex) {
+                log.error("处理工作流延时任务异常 - key: {}", key, ex);
+            }
+        });
+        log.info("===========工作流延时任务扫描结束===========");
+    }
+
     /**
      * 获取过滤后的企微客户列表
      */
@@ -932,7 +964,7 @@ public class WxTaskService {
         List<CompanyWxClient> list = companyWxClientService.getAddWxList(accountIdList, 2);
         
         // 排除掉没到达加微步骤的人
-        List<CompanyVoiceRoboticCallees> excludeList = companyVoiceRoboticCalleesMapper.selectExcludeList(list);
+        List<CompanyVoiceRoboticCallees> excludeList = companyVoiceRoboticCalleesMapper.selectExcludeList(list,2);
         Set<String> excludeKeys = excludeList.stream()
                 .filter(e -> !Constants.QW_ADD_WX.equals(getNextTaskOptimized(e.getTaskFlow(), e.getRunTaskFlow())))
                 .map(callee -> callee.getRoboticId() + "_" + callee.getUserId())

+ 16 - 10
fs-wx-task/src/main/java/com/fs/app/task/WxTask.java

@@ -6,8 +6,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
-import java.util.Collections;
-
 /**
  * 企业微信SOP定时任务管理类
  * 负责处理各种定时任务,包括SOP规则检查、消息发送、数据清理等
@@ -22,10 +20,10 @@ public class WxTask {
     @Autowired
     private WxTaskService taskService;
 
-    @Scheduled(cron = "0 0/30 * * * ?")
-    public void addWx() {
-        taskService.addWx(null);
-    }
+//    @Scheduled(cron = "0 0/30 * * * ?")
+//    public void addWx() {
+//        taskService.addWx(null);
+//    }
     @Scheduled(cron = "0 0/1 * * * ?")
     public void addWx4Workflow() {
         taskService.addWx4Workflow(null);
@@ -53,10 +51,10 @@ public class WxTask {
      * 工作流加微超时检测
      * 每分钟执行一次,检查是否有加微超时的工作流需要继续执行
      */
-    @Scheduled(cron = "0 0/1 * * * ?")
-    public void checkWorkflowAddWxTimeout(){
-        taskService.checkWorkflowAddWxTimeout();
-    }
+//    @Scheduled(cron = "0 0/1 * * * ?")
+//    public void checkWorkflowAddWxTimeout(){
+//        taskService.checkWorkflowAddWxTimeout();
+//    }
 
     @Scheduled(cron = "0 0/1 * * * ?")
     public void cidWorkflowAddWxRun(){
@@ -78,4 +76,12 @@ public class WxTask {
     public void qwAddWxResult() {
         taskService.qwAddWxResult(null);
     }
+    /**
+     * 企微加微工作流超时检测
+     * 每分钟执行一次,检查是否有加微超时的工作流需要继续执行
+     */
+    @Scheduled(cron = "0 0/1 * * * ?")
+    public void cidWorkflowQwAddWxRun(){
+        taskService.cidWorkflowQwAddWxRun();
+    }
 }

+ 1 - 0
fs-wx-task/src/main/resources/application.yml

@@ -14,3 +14,4 @@ spring:
 #    active: druid-sxjz
 #    active: druid-hdt
 #    active: druid-myhk-test
+cid-group-no: 1