Pārlūkot izejas kodu

Merge branch 'master' into 企微聊天

# Conflicts:
#	fs-service/src/main/resources/mapper/qw/QwUserMapper.xml
ct 2 dienas atpakaļ
vecāks
revīzija
29e242745c
72 mainītis faili ar 1721 papildinājumiem un 217 dzēšanām
  1. 38 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseFinishTempController.java
  2. 55 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreAfterSalesScrmController.java
  3. 44 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
  4. 45 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  5. 8 0
      fs-admin/src/main/java/com/fs/hisStore/task/MallStoreTask.java
  6. 51 0
      fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java
  7. 18 1
      fs-admin/src/main/java/com/fs/live/controller/LiveController.java
  8. 29 1
      fs-admin/src/main/java/com/fs/live/controller/LiveOrderController.java
  9. 13 0
      fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java
  10. 35 3
      fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java
  11. 107 24
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  12. 4 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  13. 1 1
      fs-live-app/src/main/java/com/fs/framework/aspectj/RateLimiterAspect.java
  14. 3 5
      fs-live-app/src/main/java/com/fs/live/websocket/handle/LiveChatHandler.java
  15. 52 65
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  16. 69 31
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  17. 25 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseFinishTemp.java
  18. 6 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java
  19. 6 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseFinishTempMapper.java
  20. 28 0
      fs-service/src/main/java/com/fs/course/param/FsCourseAnswerLogsParam.java
  21. 26 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  22. 58 39
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  23. 5 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseFinishTempListVO.java
  24. 8 6
      fs-service/src/main/java/com/fs/his/mapper/FsStorePaymentMapper.java
  25. 16 7
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  26. 39 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsUserCompanyPackageScrm.java
  27. 5 2
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java
  28. 10 4
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  29. 2 1
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  30. 61 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsUserCompanyPackageScrmMapper.java
  31. 21 0
      fs-service/src/main/java/com/fs/hisStore/param/FsUsePackageScrmSendParam.java
  32. 5 1
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreProductPackageScrmService.java
  33. 4 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  34. 12 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  35. 32 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPackageScrmServiceImpl.java
  36. 13 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreAfterSalesVO.java
  37. 133 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportRefundZMVO.java
  38. 3 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportVO.java
  39. 124 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportZMVO.java
  40. 7 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemVO.java
  41. 3 0
      fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java
  42. 7 0
      fs-service/src/main/java/com/fs/live/service/ILiveOrderService.java
  43. 2 0
      fs-service/src/main/java/com/fs/live/service/ILiveService.java
  44. 2 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveAfterSalesServiceImpl.java
  45. 59 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java
  46. 27 5
      fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java
  47. 12 0
      fs-service/src/main/java/com/fs/live/vo/LiveAfterSalesVo.java
  48. 4 1
      fs-service/src/main/java/com/fs/live/vo/LiveOrderItemListUVO.java
  49. 10 2
      fs-service/src/main/java/com/fs/live/vo/LiveOrderVoZm.java
  50. 3 0
      fs-service/src/main/java/com/fs/qw/mapper/QwCompanyMapper.java
  51. 11 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  52. 1 1
      fs-service/src/main/java/com/fs/qw/service/IQwCompanyService.java
  53. 1 0
      fs-service/src/main/java/com/fs/qw/service/IQwUserService.java
  54. 6 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwCompanyServiceImpl.java
  55. 6 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java
  56. 28 1
      fs-service/src/main/java/com/fs/sop/domain/QwSop.java
  57. 25 0
      fs-service/src/main/java/com/fs/sop/domain/QwSopTemp.java
  58. 1 1
      fs-service/src/main/resources/application-config-druid-nmgyt.yml
  59. 6 0
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  60. 10 1
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml
  61. 14 1
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  62. 79 0
      fs-service/src/main/resources/mapper/hisStore/FsUserCompanyPackageScrmMapper.xml
  63. 1 1
      fs-service/src/main/resources/mapper/hisStore/FsUserScrmMapper.xml
  64. 3 1
      fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml
  65. 13 2
      fs-service/src/main/resources/mapper/live/LiveOrderItemMapper.xml
  66. 112 0
      fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml
  67. 3 2
      fs-service/src/main/resources/mapper/qw/QwUserMapper.xml
  68. 7 1
      fs-service/src/main/resources/mapper/sop/QwSopMapper.xml
  69. 6 0
      fs-service/src/main/resources/mapper/sop/QwSopTempMapper.xml
  70. 5 1
      fs-user-app/src/main/java/com/fs/app/controller/UserController.java
  71. 10 1
      fs-user-app/src/main/java/com/fs/app/controller/live/LiveOrderController.java
  72. 23 4
      fs-user-app/src/main/java/com/fs/app/controller/store/StoreProductPackageScrmController.java

+ 38 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseFinishTempController.java

@@ -6,14 +6,22 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyUserServiceImpl;
+import com.fs.company.vo.DocCompanyUserVO;
 import com.fs.course.domain.FsCourseFinishTemp;
 import com.fs.course.service.IFsCourseFinishTempService;
 import com.fs.course.vo.FsCourseFinishTempListVO;
+import com.fs.sop.domain.QwSopTemp;
+import com.fs.voice.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * 完课模板Controller
@@ -27,6 +35,8 @@ public class FsCourseFinishTempController extends BaseController
 {
     @Autowired
     private IFsCourseFinishTempService fsCourseFinishTempService;
+    @Autowired
+    private CompanyUserServiceImpl companyUserService;
 
     /**
      * 查询完课模板列表
@@ -37,6 +47,34 @@ public class FsCourseFinishTempController extends BaseController
     {
         startPage();
         List<FsCourseFinishTempListVO> list = fsCourseFinishTempService.selectFsCourseFinishTempListVO(fsCourseFinishTemp);
+        // 收集所有需要查询的用户ID
+        Set<Long> userIds = list.stream()
+                .map(FsCourseFinishTempListVO::getCreateBy)
+                .filter(str -> !StringUtil.strIsNullOrEmpty(str)) // 取反,保留非空值
+                .map(Long::valueOf)
+                .collect(Collectors.toSet());
+
+        if (!userIds.isEmpty()){
+            // 批量查询用户信息
+            Map<Long, DocCompanyUserVO> userMap = companyUserService
+                    .selectDocCompanyUserListByUserIds(userIds)
+                    .stream()
+                    .collect(Collectors.toMap(DocCompanyUserVO::getUserId, Function.identity()));
+
+
+            list.forEach(item->{
+
+                if (!StringUtil.strIsNullOrEmpty(item.getCreateBy())) {
+                    DocCompanyUserVO user = userMap.get(Long.valueOf(item.getCreateBy()));
+                    if (user != null) {
+                        item.setCreateByName(user.getNickName());
+                        item.setCreateByDeptName(user.getDeptName());
+                    }
+                }
+
+            });
+        }
+
         return getDataTable(list);
     }
 

+ 55 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreAfterSalesScrmController.java

@@ -1,5 +1,6 @@
 package com.fs.hisStore.controller;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -27,13 +28,18 @@ import com.fs.hisStore.service.IFsStoreAfterSalesScrmService;
 import com.fs.hisStore.service.IFsStoreAfterSalesStatusScrmService;
 import com.fs.hisStore.service.IFsStoreOrderScrmService;
 import com.fs.hisStore.vo.FsStoreAfterSalesVO;
+import com.fs.hisStore.vo.FsStoreOrderItemExportRefundZMVO;
+import com.fs.hisStore.vo.FsStoreOrderItemExportZMVO;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
 import java.text.ParseException;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * 售后记录Controller
@@ -58,6 +64,10 @@ public class FsStoreAfterSalesScrmController extends BaseController
 
     @Autowired
     private TokenService tokenService;
+
+    @Value("${cloud_host.company_name}")
+    private String signProjectName;
+
     /**
      * 查询售后记录列表
      */
@@ -91,6 +101,51 @@ public class FsStoreAfterSalesScrmController extends BaseController
         }
 
         List<FsStoreAfterSalesVO> list = fsStoreAfterSalesService.selectFsStoreAfterSalesListVO(fsStoreAfterSales);
+        if("北京卓美".equals(signProjectName)){
+            List<FsStoreOrderItemExportRefundZMVO> zmvoList = list.stream()
+                    .map(vo -> {
+                        FsStoreOrderItemExportRefundZMVO zmvo = new FsStoreOrderItemExportRefundZMVO();
+                        try {
+                            zmvo.setOrderCode(vo.getOrderCode());
+                            zmvo.setStatus(vo.getOrderStatus().toString());
+                            zmvo.setUserId(vo.getUserId());
+                            zmvo.setProductName(vo.getProductName());
+                            zmvo.setBarCode(vo.getProductBarCode());
+                            zmvo.setSku(vo.getSku());
+                            zmvo.setNum(vo.getNum());
+                            zmvo.setPrice(vo.getPrice());
+                            zmvo.setCost(vo.getCost());
+//                            zmvo.setFPrice("");
+                            zmvo.setPayMoney(vo.getPayMoney());
+                            zmvo.setPayPostage(vo.getTotalPostage());
+                            zmvo.setCateName(vo.getCateName());
+                            zmvo.setRealName(vo.getUserName());
+                            zmvo.setUserPhone(vo.getUserPhone());
+                            zmvo.setUserAddress(vo.getUserAddress());
+                            zmvo.setCreateTime(vo.getCreateTime());
+                            zmvo.setPayTime(vo.getOrderPayTime());
+                            zmvo.setDeliverySn(vo.getOrderDeliverySn());
+                            zmvo.setDeliveryName(vo.getOrderDeliveryName());
+                            zmvo.setDeliveryId(vo.getOrderDeliveryId());
+                            zmvo.setCompanyName(vo.getCompanyName());
+                            zmvo.setCompanyUserNickName(vo.getCompanyUserNickName());
+                            zmvo.setRefundTime(vo.getCreateTime());
+//                            zmvo.setAfterSalesNumber
+                            zmvo.setRefundMoney(vo.getRefundAmount());
+                            zmvo.setBankTransactionId(vo.getBankTransactionId());
+                        } catch (Exception e) {
+                            // 处理异常
+                            e.printStackTrace();
+                        }
+                        return zmvo;
+                    })
+                    .collect(Collectors.toList());
+            for (FsStoreOrderItemExportRefundZMVO vo : zmvoList){
+                vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            }
+            ExcelUtil<FsStoreOrderItemExportRefundZMVO> util = new ExcelUtil<FsStoreOrderItemExportRefundZMVO>(FsStoreOrderItemExportRefundZMVO.class);
+            return util.exportExcel(zmvoList, "退款订单导出");
+        }
         for (FsStoreAfterSalesVO vo : list){
             vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
         }

+ 44 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -28,6 +28,7 @@ import com.fs.hisStore.service.*;
 import com.fs.hisStore.vo.*;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -35,6 +36,7 @@ import org.springframework.web.multipart.MultipartFile;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("/store/store/storeOrder")
@@ -71,6 +73,9 @@ public class FsStoreHealthOrderScrmController extends BaseController {
     // 最大文件大小(5MB)
     private static final long MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
 
+    @Value("${cloud_host.company_name}")
+    private String signProjectName;
+
     /**
      * 查询健康商城订单列表
      */
@@ -342,6 +347,45 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         }
         param.setIsHealth("1");
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
+        if("北京卓美".equals(signProjectName)){
+            List<FsStoreOrderItemExportZMVO> zmvoList = list.stream()
+                    .map(vo -> {
+                        FsStoreOrderItemExportZMVO zmvo = new FsStoreOrderItemExportZMVO();
+                        try {
+                            BeanUtil.copyProperties( vo,zmvo);
+                        } catch (Exception e) {
+                            // 处理异常
+                            e.printStackTrace();
+                        }
+                        return zmvo;
+                    })
+                    .collect(Collectors.toList());
+            //对手机号脱敏
+            if (zmvoList != null) {
+                    LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+                    for (FsStoreOrderItemExportZMVO vo : zmvoList) {
+                        if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                            try {
+                                StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                                BeanUtil.copyProperties(orderProductDTO, vo);
+                            } catch (Exception e) {
+                            }
+                        }
+                        if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                            vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                        } else {
+                            vo.setPayPostage(BigDecimal.ZERO);
+                            vo.setCost(BigDecimal.ZERO);
+                            vo.setFPrice(BigDecimal.ZERO);
+                            vo.setBarCode("");
+                            vo.setCateName("");
+                            vo.setBankTransactionId("");
+                        }
+                    }
+                }
+                ExcelUtil<FsStoreOrderItemExportZMVO> util = new ExcelUtil<FsStoreOrderItemExportZMVO>(FsStoreOrderItemExportZMVO.class);
+                return util.exportExcel(zmvoList, "订单明细数据");
+        }
         //对手机号脱敏
         if (list != null) {
             LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());

+ 45 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -58,6 +58,7 @@ import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -137,6 +138,9 @@ public class FsStoreOrderScrmController extends BaseController {
     @Autowired
     private IFsStoreOrderLogsScrmService fsStoreOrderLogsService;
 
+    @Value("${cloud_host.company_name}")
+    private String signProjectName;
+
     private IErpOrderService getErpService(){
         //判断是否开启erp
         IErpOrderService erpOrderService = null;
@@ -511,6 +515,47 @@ public class FsStoreOrderScrmController extends BaseController {
         }
         param.setNotHealth(1);
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
+        if("北京卓美".equals(signProjectName)){
+            List<FsStoreOrderItemExportZMVO> zmvoList = list.stream()
+                    .map(vo -> {
+                        FsStoreOrderItemExportZMVO zmvo = new FsStoreOrderItemExportZMVO();
+                        try {
+                            BeanUtil.copyProperties( vo,zmvo);
+                        } catch (Exception e) {
+                            // 处理异常
+                            e.printStackTrace();
+                        }
+                        return zmvo;
+                    })
+                    .collect(Collectors.toList());
+            //对手机号脱敏
+            if (zmvoList != null) {
+                LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+                for (FsStoreOrderItemExportZMVO vo : zmvoList) {
+                    if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                        try {
+                            StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                            BeanUtil.copyProperties(orderProductDTO, vo);
+                        } catch (Exception e) {
+                        }
+                    }
+                    //
+                    if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                        vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                    } else {
+                        vo.setPayPostage(BigDecimal.ZERO);
+                        vo.setCost(BigDecimal.ZERO);
+                        vo.setFPrice(BigDecimal.ZERO);
+                        vo.setBarCode("");
+                        vo.setCateName("");
+                        vo.setBankTransactionId("");
+                    }
+                }
+            }
+            ExcelUtil<FsStoreOrderItemExportZMVO> util = new ExcelUtil<FsStoreOrderItemExportZMVO>(FsStoreOrderItemExportZMVO.class);
+            return util.exportExcel(zmvoList, "订单明细数据");
+        }
+
         //对手机号脱敏
         if (list != null) {
             LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());

+ 8 - 0
fs-admin/src/main/java/com/fs/hisStore/task/MallStoreTask.java

@@ -4,6 +4,7 @@ package com.fs.hisStore.task;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.DateUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
@@ -32,6 +33,7 @@ import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
 import com.fs.hisStore.param.*;
 import com.fs.hisStore.service.*;
+import com.fs.live.domain.LiveOrder;
 import com.fs.pay.pay.dto.OrderQueryDTO;
 import com.fs.pay.service.IPayService;
 import com.fs.store.config.StoreConfig;
@@ -49,6 +51,7 @@ import java.math.BigDecimal;
 import java.text.ParseException;
 import java.time.LocalTime;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
@@ -217,6 +220,11 @@ public class MallStoreTask
         if (list != null && list.size() > 50) {
             list = list.subList(0, 50);
         }
+        Date nowDate = DateUtils.getNowDate();
+        for (FsStoreOrderScrm order : list) {
+            order.setUpdateTime(nowDate);
+        }
+        fsStoreOrderMapper.batchUpdateTime(list);
         for (FsStoreOrderScrm order : list){
             ErpOrderQueryRequert request = new ErpOrderQueryRequert();
             request.setCode(order.getExtendOrderId());

+ 51 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java

@@ -16,6 +16,7 @@ import com.fs.his.domain.FsStoreAfterSalesLogs;
 import com.fs.his.domain.FsUser;
 import com.fs.his.enums.FsStoreAfterSalesStatusEnum;
 import com.fs.his.service.IFsUserService;
+import com.fs.hisStore.vo.FsStoreOrderItemExportRefundZMVO;
 import com.fs.live.domain.LiveAfterSales;
 import com.fs.live.domain.LiveAfterSalesItem;
 import com.fs.live.domain.LiveAfterSalesLogs;
@@ -31,11 +32,13 @@ import com.fs.live.service.ILiveOrderService;
 import com.fs.live.vo.LiveAfterSalesVo;
 import com.github.pagehelper.PageHelper;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.text.ParseException;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 售后记录Controller
@@ -60,6 +63,9 @@ public class LiveAfterSalesController extends BaseController
     private IFsUserService userService;
     @Autowired
     private ILiveOrderService orderService;
+    @Value("${cloud_host.company_name}")
+    private String signProjectName;
+
 
     /**
      * 获取售后记录详细信息
@@ -105,6 +111,51 @@ public class LiveAfterSalesController extends BaseController
         PageHelper.clearPage();
         PageHelper.startPage(1, 10000, "");
         List<LiveAfterSalesVo> list = liveAfterSalesService.selectLiveAfterSalesVoList(liveAfterSales);
+        if("北京卓美".equals(signProjectName)){
+            List<FsStoreOrderItemExportRefundZMVO> zmvoList = list.stream()
+                    .map(vo -> {
+                        FsStoreOrderItemExportRefundZMVO zmvo = new FsStoreOrderItemExportRefundZMVO();
+                        try {
+                            zmvo.setOrderCode(vo.getOrderCode());
+                            zmvo.setStatus(vo.getOrderStatus().toString());
+                            zmvo.setUserId(vo.getUserId());
+                            zmvo.setProductName(vo.getProductName());
+                            zmvo.setBarCode(vo.getProductBarCode());
+                            zmvo.setSku(vo.getSku());
+                            zmvo.setNum(vo.getNum());
+                            zmvo.setPrice(vo.getPrice());
+                            zmvo.setCost(vo.getCost());
+//                            zmvo.setFPrice("");
+                            zmvo.setPayMoney(vo.getPayMoney());
+                            zmvo.setPayPostage(vo.getTotalPostage());
+                            zmvo.setCateName(vo.getCateName());
+                            zmvo.setRealName(vo.getUserName());
+                            zmvo.setUserPhone(vo.getUserPhone());
+                            zmvo.setUserAddress(vo.getUserAddress());
+                            zmvo.setCreateTime(vo.getCreateTime());
+                            zmvo.setPayTime(vo.getOrderPayTime());
+                            zmvo.setDeliverySn(vo.getOrderDeliverySn());
+                            zmvo.setDeliveryName(vo.getOrderDeliveryName());
+                            zmvo.setDeliveryId(vo.getOrderDeliveryId());
+                            zmvo.setCompanyName(vo.getCompanyName());
+                            zmvo.setCompanyUserNickName(vo.getCompanyUserNickName());
+                            zmvo.setRefundTime(vo.getCreateTime());
+//                            zmvo.setAfterSalesNumber
+                            zmvo.setRefundMoney(vo.getRefundAmount());
+                            zmvo.setBankTransactionId(vo.getBankTransactionId());
+                        } catch (Exception e) {
+                            // 处理异常
+                            e.printStackTrace();
+                        }
+                        return zmvo;
+                    })
+                    .collect(Collectors.toList());
+            for (FsStoreOrderItemExportRefundZMVO vo : zmvoList){
+                vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            }
+            ExcelUtil<FsStoreOrderItemExportRefundZMVO> util = new ExcelUtil<FsStoreOrderItemExportRefundZMVO>(FsStoreOrderItemExportRefundZMVO.class);
+            return util.exportExcel(zmvoList, "退款订单导出");
+        }
         for (LiveAfterSalesVo liveAfterSalesVo : list) {
             liveAfterSalesVo.setUserPhone(liveAfterSalesVo.getUserPhone() == null ? "" : liveAfterSalesVo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
             liveAfterSalesVo.setPhoneNumber(liveAfterSalesVo.getPhoneNumber() == null ? "" : liveAfterSalesVo.getPhoneNumber().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));

+ 18 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveController.java

@@ -4,14 +4,19 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.framework.web.service.TokenService;
 import com.fs.hisStore.task.LiveTask;
 import com.fs.hisStore.task.MallStoreTask;
 import com.fs.live.domain.Live;
 import com.fs.live.service.ILiveService;
 import com.fs.live.vo.LiveListVo;
+import com.hc.openapi.tool.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -28,10 +33,14 @@ import java.util.Map;
  */
 @RestController
 @RequestMapping("/live/live")
+@Slf4j
 public class LiveController extends BaseController {
     @Autowired
     private ILiveService liveService;
 
+    @Autowired
+    private TokenService tokenService;
+
 
     /**
      * 查询直播列表
@@ -63,7 +72,7 @@ public class LiveController extends BaseController {
     @PreAuthorize("@ss.hasPermi('live:live:query')")
     @GetMapping(value = "/{liveId}")
     public AjaxResult getInfo(@PathVariable("liveId") Long liveId) {
-        return AjaxResult.success(liveService.selectLiveByLiveId(liveId));
+        return AjaxResult.success(liveService.selectLiveDbByLiveId(liveId));
     }
 
     /**
@@ -83,6 +92,8 @@ public class LiveController extends BaseController {
     @Log(title = "直播", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody Live live) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        log.warn("loginUser:{},update:{}", loginUser.getUserId(), JSON.toJSONString( live));
         return toAjax(liveService.updateLive(live));
     }
 
@@ -93,6 +104,8 @@ public class LiveController extends BaseController {
     @Log(title = "直播", businessType = BusinessType.DELETE)
     @DeleteMapping("/{liveIds}")
     public AjaxResult remove(@PathVariable Long[] liveIds) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        log.warn("loginUser:{},update:{}", loginUser.getUserId(), JSON.toJSONString( liveIds));
         return toAjax(liveService.deleteLiveByLiveIds(liveIds, new Live()));
     }
 
@@ -116,6 +129,8 @@ public class LiveController extends BaseController {
     @PreAuthorize("@ss.hasPermi('live:live:edit')")
     @PostMapping("/handleShelfOrUn")
     public R handleShelfOrUn(@RequestBody LiveListVo listVo) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        log.warn("loginUser:{},update:{}", loginUser.getUserId(), JSON.toJSONString( listVo));
         return liveService.handleShelfOrUnAdmin(listVo);
     }
 
@@ -125,6 +140,8 @@ public class LiveController extends BaseController {
     @PreAuthorize("@ss.hasPermi('live:live:edit')")
     @PostMapping("/handleDeleteSelected")
     public R handleDeleteSelected(@RequestBody LiveListVo listVo) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        log.warn("loginUser:{},update:{}", loginUser.getUserId(), JSON.toJSONString( listVo));
         return liveService.handleDeleteSelectedAdmin(listVo);
     }
     /**

+ 29 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveOrderController.java

@@ -38,6 +38,7 @@ import com.fs.hisStore.param.*;
 import com.fs.hisStore.service.IFsExpressScrmService;
 import com.fs.hisStore.task.ExpressTask;
 import com.fs.hisStore.task.LiveTask;
+import com.fs.hisStore.vo.FsStoreOrderItemExportZMVO;
 import com.fs.hisStore.vo.FsStoreOrderVO;
 import com.fs.live.domain.*;
 import com.fs.live.dto.LiveOrderCustomerExportDTO;
@@ -242,7 +243,34 @@ public class LiveOrderController extends BaseController
         return util.exportExcel(list, "订单数据");
     }
 
-
+    /**
+     * 导出订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:export')")
+    @Log(title = "订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportZmNew")
+    public AjaxResult exportZmNew(LiveOrder liveOrder){
+        List<FsStoreOrderItemExportZMVO> list = liveOrderService.selectLiveOrderListZmNew(liveOrder);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        for (FsStoreOrderItemExportZMVO vo : list){
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+//            vo.setCompanyUserPhone(ParseUtils.parsePhone(vo.getCompanyUserPhone()));
+//            vo.setUserBindPhone(ParseUtils.parsePhone(vo.getUserBindPhone()));
+            vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+            // 财务独特字段
+            if (loginUser.getPermissions().contains("live:liveOrder:finance") || loginUser.getPermissions().contains("*:*:*")) {
+//                vo.setCostPrice(vo.getCost());
+                vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getNum())));
+            } else {
+                vo.setCost(BigDecimal.ZERO);
+                vo.setFPrice(BigDecimal.ZERO);
+                vo.setBankTransactionId("");
+            }
+//            vo.setCost(vo.getCostPrice());
+        }
+        ExcelUtil<FsStoreOrderItemExportZMVO> util = new ExcelUtil<FsStoreOrderItemExportZMVO>(FsStoreOrderItemExportZMVO.class);
+        return util.exportExcel(list, "订单数据");
+    }
     /**
      * 获取订单详细信息
      */

+ 13 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java

@@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -53,6 +54,7 @@ public class QwSopController extends BaseController
     @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
 
+
     /**
      * 查询企微sop列表
      */
@@ -60,6 +62,17 @@ public class QwSopController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(QwSop qwSop)
     {
+        List<String> userIds = qwSop.getUserIds();
+        if (userIds != null && !userIds.isEmpty()) {
+            List<Long> longs = qwUserService.selectQwUserListByCompanyUserIdS(userIds);
+            if (longs != null && !longs.isEmpty()) {
+                qwSop.getQwUserIdList().addAll(longs);
+            }else {
+                return getDataTable(new ArrayList<>());
+            }
+        }
+
+
         startPage();
         List<QwSop> list = qwSopService.selectQwSopList(qwSop);
         return getDataTable(list);

+ 35 - 3
fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java

@@ -12,6 +12,8 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.TimeUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyUserServiceImpl;
+import com.fs.company.vo.DocCompanyUserVO;
 import com.fs.framework.web.service.TokenService;
 import com.fs.qw.vo.SortDayVo;
 import com.fs.sop.domain.QwSopTemp;
@@ -19,14 +21,14 @@ import com.fs.sop.domain.QwSopTempDay;
 import com.fs.sop.params.QwSopShareTempParam;
 import com.fs.sop.service.IQwSopTempService;
 import com.fs.sop.vo.UpdateRedVo;
+import com.fs.voice.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -43,6 +45,8 @@ public class QwSopTempController extends BaseController
     private IQwSopTempService qwSopTempService;
     @Autowired
     private TokenService tokenService;
+    @Autowired
+    private CompanyUserServiceImpl companyUserService;
     /**
      * 查询sop模板列表
      */
@@ -53,6 +57,34 @@ public class QwSopTempController extends BaseController
         startPage();
 //        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
         List<QwSopTemp> list = qwSopTempService.selectQwSopTempListNew(qwSopTemp);
+        // 收集所有需要查询的用户ID
+        Set<Long> userIds = list.stream()
+                .map(QwSopTemp::getCreateBy)
+                .filter(str -> !StringUtil.strIsNullOrEmpty(str)) // 取反,保留非空值
+                .map(Long::valueOf)
+                .collect(Collectors.toSet());
+
+        if (!userIds.isEmpty()){
+            // 批量查询用户信息
+            Map<Long, DocCompanyUserVO> userMap = companyUserService
+                    .selectDocCompanyUserListByUserIds(userIds)
+                    .stream()
+                    .collect(Collectors.toMap(DocCompanyUserVO::getUserId, Function.identity()));
+
+
+            list.forEach(item->{
+
+                if (!StringUtil.strIsNullOrEmpty(item.getCreateBy())) {
+                    DocCompanyUserVO user = userMap.get(Long.valueOf(item.getCreateBy()));
+                    if (user != null) {
+                        item.setCreateByName(user.getNickName());
+                        item.setCreateByDeptName(user.getDeptName());
+                    }
+                }
+
+            });
+        }
+
         return getDataTable(list);
     }
 

+ 107 - 24
fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java

@@ -4,6 +4,7 @@ import com.fs.course.service.IFsUserCourseService;
 import com.fs.qw.domain.QwIpadServerLog;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.param.QwMandatoryRegistrParam;
 import com.fs.qw.service.*;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
 import com.fs.sop.service.impl.QwSopServiceImpl;
@@ -15,10 +16,14 @@ import com.fs.wxwork.service.WxWorkService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import java.time.Duration;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.Date;
 import java.util.List;
+import java.util.Optional;
 
 @Component("qwTask")
 public class qwTask {
@@ -73,6 +78,10 @@ public class qwTask {
     private WxWorkService wxWorkService;
 
 
+    @Autowired
+    private IQwCompanyService iQwCompanyService;
+
+
     //正在使用
     public void qwExternalContact()
     {
@@ -240,37 +249,41 @@ public class qwTask {
      * 定时清除 占着茅坑不拉屎的ipad 账号
      */
     public void selectQwUserByUnbindIpad(){
+
+        //查询所有状态为 绑定了AI主机的
         List<QwUser> list = qwUserMapper.selectQwUserByTest();
         for (QwUser qwUser : list) {
             try {
-                Integer serverStatus = qwUser.getServerStatus();
+
                 Long serverId = qwUser.getServerId();
-                if (serverStatus==0){
-                    System.out.println("不需要解绑");
-                }
+
                 if (serverId==null){
                     System.out.println("serverId不存在");
+                }else {
+                    //没绑定销售 或者 已经离职
+                    if (qwUser.getStatus()==0 || qwUser.getIsDel()==2){
+
+                        updateIpadStatus(qwUser,serverId);
+                    }
+
+                    //绑定了销售-也绑定了ipad,但是长时间离线的(离线状态,无操作超过2天的,也自动解绑)
+                    if(qwUser.getCreateTime()!=null){
+                        Date createTime = qwUser.getCreateTime();
+                        Integer serverStatus = qwUser.getServerStatus();
+                        Integer ipadStatus = qwUser.getIpadStatus();
+
+                        boolean result = isCreateTimeMoreThanDaysWithOptional(createTime, 2);
+                        //大于2天 ,绑定了ipad,离线
+                        if(result && serverStatus==1 && ipadStatus==0){
+                            updateIpadStatus(qwUser,serverId);
+
+                        }
+                    }
+
+
                 }
-                QwUser u = new QwUser();
-                u.setId(qwUser.getId());
-                u.setServerId(null);
-                u.setServerStatus(0);
-                qwUserMapper.updateQwUser(u);
-                ipadServerService.addServer(serverId);
-                QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
-                qwIpadServerLog.setType(2);
-                qwIpadServerLog.setTilie("解绑");
-                qwIpadServerLog.setServerId(serverId);
-                qwIpadServerLog.setQwUserId(qwUser.getId());
-                qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
-                qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
-                qwIpadServerLog.setCreateTime(new Date());
-                qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
-                qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
-                WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
-                wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
-                wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
-                updateIpadStatus(qwUser.getId(),0);
+
+
             } catch (Exception e) {
                 System.out.println("解绑ipad报错"+e);
 
@@ -278,6 +291,41 @@ public class qwTask {
         }
     }
 
+    public void updateIpadStatus(QwUser qwUser,Long serverId){
+        QwUser u = new QwUser();
+        u.setId(qwUser.getId());
+        u.setServerId(null);
+        u.setServerStatus(0);
+        qwUserMapper.updateQwUser(u);
+        ipadServerService.addServer(serverId);
+        QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
+        qwIpadServerLog.setType(2);
+        qwIpadServerLog.setTilie("解绑");
+        qwIpadServerLog.setServerId(serverId);
+        qwIpadServerLog.setQwUserId(qwUser.getId());
+        qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
+        qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
+        qwIpadServerLog.setCreateTime(new Date());
+        qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
+        qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
+        WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
+        wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
+        wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
+        updateIpadStatus(qwUser.getId(),0);
+    }
+
+    public static boolean isCreateTimeMoreThanDaysWithOptional(Date createTime, int days) {
+        return Optional.ofNullable(createTime)
+                .map(time -> {
+                    LocalDateTime createDateTime = time.toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDateTime();
+                    LocalDateTime now = LocalDateTime.now();
+                    Duration duration = Duration.between(createDateTime, now);
+                    return duration.toDays() > days;
+                })
+                .orElse(false); // 为null时返回false,可根据需求调整
+    }
 
     void updateIpadStatus(Long id ,Integer status){
         QwUser u = new QwUser();
@@ -286,4 +334,39 @@ public class qwTask {
         qwUserMapper.updateQwUser(u);
     }
 
+
+    /**
+     * 强制注册-2025-11-12 之后的 更新
+     */
+    public void QwExternalContactMandatoryRegistration(){
+        try {
+//            List<String> longs = qwExternalContactService.selectQwExternalContactMandatoryRegistration();
+            List<String> longs = iQwCompanyService.selectQwCompanyListFormCorpId();
+            longs.forEach(item->{
+                List<QwMandatoryRegistrParam> registrParamList = qwExternalContactService.selectQwExternalContactMandatoryRegistrationByIds(String.valueOf(item));
+
+                batchUpdateQwExternalContactMandatoryRegistration(registrParamList);
+
+            });
+        }catch (Exception e){
+
+        }
+
+    }
+
+
+    private void batchUpdateQwExternalContactMandatoryRegistration(List<QwMandatoryRegistrParam> registrParamList) {
+        // 定义批量插入的大小
+        int batchSize = 300;
+
+        // 循环处理外部用户 ID,每次处理批量大小的子集
+        for (int i = 0; i < registrParamList.size(); i += batchSize) {
+
+            int endIndex = Math.min(i + batchSize, registrParamList.size());
+            List<QwMandatoryRegistrParam> batchList = registrParamList.subList(i, endIndex);  // 获取当前批次的子集
+
+            qwExternalContactService.batchUpdateQwExternalContactMandatoryRegistration(batchList);
+
+        }
+    }
 }

+ 4 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java

@@ -347,6 +347,10 @@ public class QwExternalContactController extends BaseController
         List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
 
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
+        if(StringUtils.isNotEmpty(qwExternalContact.getStatuses())){
+            String[] split = qwExternalContact.getStatuses().split(",");
+            qwExternalContact.setStatusCondition(split);
+        }
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
 

+ 1 - 1
fs-live-app/src/main/java/com/fs/framework/aspectj/RateLimiterAspect.java

@@ -73,7 +73,7 @@ public class RateLimiterAspect
             {
                 throw new ServiceException("访问过于频繁,请稍后再试");
             }
-            log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key);
+
         }
         catch (ServiceException e)
         {

+ 3 - 5
fs-live-app/src/main/java/com/fs/live/websocket/handle/LiveChatHandler.java

@@ -53,7 +53,7 @@ public class LiveChatHandler extends SimpleChannelInboundHandler<TextWebSocketFr
      */
     @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-        log.debug("事件");
+
         // 处理 WebSocket 握手完成事件
         if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
             Long userId = ctx.channel().attr(AttrConstant.ATTR_USER_ID).get();
@@ -100,7 +100,6 @@ public class LiveChatHandler extends SimpleChannelInboundHandler<TextWebSocketFr
                 adminRoom.add(ctx.channel());
             }
 
-            log.debug("加入webSocket liveId: {}, userId: {}, 直播间人数: {}", liveId, userId, room.size());
         }
     }
 
@@ -157,7 +156,7 @@ public class LiveChatHandler extends SimpleChannelInboundHandler<TextWebSocketFr
      */
     @Override
     protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
-        log.debug("接收到消息 data: {}", textWebSocketFrame.text());
+
         Long liveId = channelHandlerContext.channel().attr(AttrConstant.ATTR_LIVE_ID).get();
         Long userType = channelHandlerContext.channel().attr(AttrConstant.ATTR_USER_TYPE).get();
 
@@ -207,7 +206,7 @@ public class LiveChatHandler extends SimpleChannelInboundHandler<TextWebSocketFr
      */
     @Override
     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-        log.debug("断开连接");
+
         Long userId = ctx.channel().attr(AttrConstant.ATTR_USER_ID).get();
         Long liveId = ctx.channel().attr(AttrConstant.ATTR_LIVE_ID).get();
         Long userType = ctx.channel().attr(AttrConstant.ATTR_USER_TYPE).get();
@@ -254,7 +253,6 @@ public class LiveChatHandler extends SimpleChannelInboundHandler<TextWebSocketFr
             roomGroups.remove(liveId);
         }
 
-        log.debug("断开webSocket liveId: {}, userId: {}, 直播间人数: {}", liveId, userId, room.size());
 
     }
 

+ 52 - 65
fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java

@@ -49,7 +49,7 @@ public class WebSocketServer {
     private final static ConcurrentHashMap<Long, ConcurrentHashMap<Long, Session>> rooms = new ConcurrentHashMap<>();
     // 管理端连接
     private final static ConcurrentHashMap<Long, CopyOnWriteArrayList<Session>> adminRooms = new ConcurrentHashMap<>();
-    
+
     // Session发送锁,避免同一会话并发发送消息
     private final static ConcurrentHashMap<String, Lock> sessionLocks = new ConcurrentHashMap<>();
     // 心跳超时缓存:key=sessionId,value=最后心跳时间戳
@@ -58,7 +58,7 @@ public class WebSocketServer {
     private final static long HEARTBEAT_TIMEOUT = 3 * 60 * 1000;
     // admin房间消息发送线程池(单线程,保证串行化)
     private final static ConcurrentHashMap<Long, ExecutorService> adminExecutors = new ConcurrentHashMap<>();
-    
+
     private final RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
     private final ILiveMsgService liveMsgService = SpringUtils.getBean(ILiveMsgService.class);
     private final ILiveService liveService = SpringUtils.getBean(ILiveService.class);
@@ -72,6 +72,7 @@ public class WebSocketServer {
     private final ILiveUserFirstEntryService liveUserFirstEntryService =  SpringUtils.getBean(ILiveUserFirstEntryService.class);
     private final ILiveCouponIssueService liveCouponIssueService =  SpringUtils.getBean(ILiveCouponIssueService.class);
     private final LiveCouponMapper liveCouponMapper = SpringUtils.getBean(LiveCouponMapper.class);
+    private static Random random = new Random();
 
     // 直播间在线用户缓存
 //    private static final ConcurrentHashMap<Long, Integer> liveOnlineUsers = new ConcurrentHashMap<>();
@@ -145,17 +146,19 @@ public class WebSocketServer {
                 redisCache.incr(UNIQUE_VIEWERS_KEY + liveId, 1);
             }
             liveWatchUserVO.setMsgStatus(liveWatchUserVO.getMsgStatus());
-            SendMsgVo sendMsgVo = new SendMsgVo();
-            sendMsgVo.setLiveId(liveId);
-            sendMsgVo.setUserId(userId);
-            sendMsgVo.setUserType(userType);
-            sendMsgVo.setCmd("entry");
-            sendMsgVo.setMsg("用户进入");
-            sendMsgVo.setData(JSONObject.toJSONString(liveWatchUserVO));
-            sendMsgVo.setNickName(fsUser.getNickname());
-            sendMsgVo.setAvatar(fsUser.getAvatar());
-            // 广播连接消息
-            broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+            if (1 == random.nextInt(4)) {
+                SendMsgVo sendMsgVo = new SendMsgVo();
+                sendMsgVo.setLiveId(liveId);
+                sendMsgVo.setUserId(userId);
+                sendMsgVo.setUserType(userType);
+                sendMsgVo.setCmd("entry");
+                sendMsgVo.setMsg("用户进入");
+                sendMsgVo.setData(JSONObject.toJSONString(liveWatchUserVO));
+                sendMsgVo.setNickName(fsUser.getNickname());
+                sendMsgVo.setAvatar(fsUser.getAvatar());
+                // 广播连接消息
+                broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+            }
 
             LiveUserFirstEntry liveUserFirstEntry = liveUserFirstEntryService.selectEntityByLiveIdUserId(liveId, userId);
             if (liveUserFirstEntry != null) {
@@ -190,13 +193,12 @@ public class WebSocketServer {
             // 为admin房间创建单线程执行器,保证串行化发送
             adminExecutors.computeIfAbsent(liveId, k -> Executors.newSingleThreadExecutor());
         }
-        
+
         // 初始化Session锁
         sessionLocks.putIfAbsent(session.getId(), new ReentrantLock());
         // 初始化心跳时间
         heartbeatCache.put(session.getId(), System.currentTimeMillis());
 
-        log.debug("加入webSocket liveId: {}, userId: {}, 直播间人数: {}, 管理端人数: {}", liveId, userId, room.size(), adminRoom.size());
     }
 
     //关闭连接时调用
@@ -227,18 +229,22 @@ public class WebSocketServer {
             String onlineUsersSetKey = ONLINE_USERS_SET_KEY + liveId;
             redisCache.redisTemplate.opsForSet().remove(onlineUsersSetKey, String.valueOf(userId));
             LiveWatchUser liveWatchUserVO = liveWatchUserService.close(fsUser,liveId, userId);
-            SendMsgVo sendMsgVo = new SendMsgVo();
-            sendMsgVo.setLiveId(liveId);
-            sendMsgVo.setUserId(userId);
-            sendMsgVo.setUserType(userType);
-            sendMsgVo.setCmd("out");
-            sendMsgVo.setMsg("用户离开");
-            sendMsgVo.setData(JSONObject.toJSONString(liveWatchUserVO));
-            sendMsgVo.setNickName(fsUser.getNickname());
-            sendMsgVo.setAvatar(fsUser.getAvatar());
-
-            // 广播离开消息
-            broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+
+
+            // 广播离开消息 添加一个概率问题 摇塞子,1-4 当为1的时候广播消息
+            if (1 == new Random().nextInt(4)) {
+                SendMsgVo sendMsgVo = new SendMsgVo();
+                sendMsgVo.setLiveId(liveId);
+                sendMsgVo.setUserId(userId);
+                sendMsgVo.setUserType(userType);
+                sendMsgVo.setCmd("out");
+                sendMsgVo.setMsg("用户离开");
+                sendMsgVo.setData(JSONObject.toJSONString(liveWatchUserVO));
+                sendMsgVo.setNickName(fsUser.getNickname());
+                sendMsgVo.setAvatar(fsUser.getAvatar());
+                broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+            }
+
         } else {
             adminRoom.remove(session);
             // 如果admin房间为空,关闭并清理执行器
@@ -250,12 +256,10 @@ public class WebSocketServer {
                 adminRooms.remove(liveId);
             }
         }
-        
+
         // 清理Session相关资源
         heartbeatCache.remove(session.getId());
         sessionLocks.remove(session.getId());
-
-        log.debug("离开webSocket liveId: {}, userId: {}, 直播间人数: {}, 管理端人数: {}", liveId, userId, room.size(), adminRoom.size());
     }
 
     //收到客户端信息
@@ -467,7 +471,6 @@ public class WebSocketServer {
      * 处理红包变动消息
      */
     private void processRed(Long liveId, SendMsgVo msg) {
-        log.debug("redData: {}", msg);
         JSONObject jsonObject = JSON.parseObject(msg.getData());
         Integer status = jsonObject.getInteger("status");
         msg.setStatus( status);
@@ -483,7 +486,6 @@ public class WebSocketServer {
      * 处理抽奖变动消息
      */
     private void processLottery(Long liveId, SendMsgVo msg) {
-        log.debug("lotteryData: {}", msg);
         JSONObject jsonObject = JSON.parseObject(msg.getData());
         Integer status = jsonObject.getInteger("status");
         msg.setStatus( status);
@@ -502,12 +504,7 @@ public class WebSocketServer {
         try {
             this.onClose(session);
         } catch (Exception e) {
-            log.error("webSocket 错误 onError", e);
-        }
-        if (throwable instanceof EOFException) {
-            log.info("WebSocket连接被客户端正常关闭(EOF),sessionId: {}", session.getId());
-        } else {
-            log.error("WebSocket连接错误", throwable);
+            log.error("webSocket 错误处理失败", e);
         }
     }
 
@@ -532,17 +529,16 @@ public class WebSocketServer {
     //发送消息(带锁机制,避免并发发送)
     public void sendMessage(Session session, String message) throws IOException {
         if (session == null || !session.isOpen()) {
-            log.warn("WebSocket 会话已关闭,跳过发送");
             return;
         }
-        
+
         // 获取Session锁
         Lock lock = sessionLocks.get(session.getId());
         if (lock == null) {
             // 如果锁不存在,创建一个新锁
             lock = sessionLocks.computeIfAbsent(session.getId(), k -> new ReentrantLock());
         }
-        
+
         // 使用锁保证同一Session的消息串行发送
         lock.lock();
         try {
@@ -558,7 +554,6 @@ public class WebSocketServer {
         ConcurrentHashMap<Long, Session> room = getRoom(liveId);
         Session session = room.get(userId);
         if (session == null || !session.isOpen()) {
-            log.warn("WebSocket 会话已关闭,跳过发送");
             return;
         }
         SendMsgVo sendMsgVo = new SendMsgVo();
@@ -578,7 +573,6 @@ public class WebSocketServer {
         ConcurrentHashMap<Long, Session> room = getRoom(liveId);
         Session session = room.get(userId);
         if (session == null || !session.isOpen()) {
-            log.warn("WebSocket 会话已关闭,跳过发送");
             return;
         }
 
@@ -609,7 +603,7 @@ public class WebSocketServer {
                 sendWithRetry(v,message,1);
             }
         });
-        
+
         // admin房间:串行发送,使用单线程执行器
         if (!adminRoom.isEmpty()) {
             ExecutorService executor = adminExecutors.get(liveId);
@@ -649,7 +643,6 @@ public class WebSocketServer {
                 String valueStr = cacheObject.toString().trim();
                 current = Integer.parseInt(valueStr);
             } catch (NumberFormatException e) {
-                log.error("点赞数格式错误,liveId: {}, value: {}", liveId, cacheObject, e);
                 continue;
             }
             Integer last = lastLikeCountCache.getOrDefault(liveId, 0);
@@ -684,8 +677,6 @@ public class WebSocketServer {
 
             // 广播当前直播间的在线人数
             broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
-
-            log.debug("广播直播间在线人数: liveId={}, onlineCount={}", liveId, onlineCount);
         }
     }
 
@@ -697,66 +688,64 @@ public class WebSocketServer {
     public void cleanInactiveSessions() {
         long currentTime = System.currentTimeMillis();
         int cleanedCount = 0;
-        
+
         // 遍历所有直播间
         for (Map.Entry<Long, ConcurrentHashMap<Long, Session>> roomEntry : rooms.entrySet()) {
             Long liveId = roomEntry.getKey();
             ConcurrentHashMap<Long, Session> room = roomEntry.getValue();
-            
+
             // 检查普通用户会话
             List<Long> toRemove = new ArrayList<>();
             room.forEach((userId, session) -> {
                 Long lastHeartbeat = heartbeatCache.get(session.getId());
                 if (lastHeartbeat != null && (currentTime - lastHeartbeat) > HEARTBEAT_TIMEOUT) {
-                    log.warn("会话心跳超时,即将关闭: sessionId={}, liveId={}, userId={}, 超时时长={}ms", 
-                            session.getId(), liveId, userId, currentTime - lastHeartbeat);
                     toRemove.add(userId);
                     try {
                         if (session.isOpen()) {
                             session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "心跳超时"));
                         }
                     } catch (Exception e) {
-                        log.error("关闭超时会话失败: sessionId={}, liveId={}, userId={}", 
+                        log.error("关闭超时会话失败: sessionId={}, liveId={}, userId={}",
                                 session.getId(), liveId, userId, e);
                     }
                 }
             });
-            
+
             // 移除超时的会话
             toRemove.forEach(room::remove);
             cleanedCount += toRemove.size();
         }
-        
+
         // 检查admin房间
         for (Map.Entry<Long, CopyOnWriteArrayList<Session>> adminEntry : adminRooms.entrySet()) {
             Long liveId = adminEntry.getKey();
             CopyOnWriteArrayList<Session> adminRoom = adminEntry.getValue();
-            
+
             List<Session> toRemoveAdmin = new ArrayList<>();
             for (Session session : adminRoom) {
                 Long lastHeartbeat = heartbeatCache.get(session.getId());
                 if (lastHeartbeat != null && (currentTime - lastHeartbeat) > HEARTBEAT_TIMEOUT) {
-                    log.warn("admin会话心跳超时,即将关闭: sessionId={}, liveId={}, 超时时长={}ms", 
-                            session.getId(), liveId, currentTime - lastHeartbeat);
                     toRemoveAdmin.add(session);
                     try {
                         if (session.isOpen()) {
                             session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "心跳超时"));
                         }
                     } catch (Exception e) {
-                        log.error("关闭admin超时会话失败: sessionId={}, liveId={}", 
+                        log.error("关闭admin超时会话失败: sessionId={}, liveId={}",
                                 session.getId(), liveId, e);
                     }
                 }
             }
-            
+
             // 移除超时的admin会话
             toRemoveAdmin.forEach(adminRoom::remove);
             cleanedCount += toRemoveAdmin.size();
         }
-        
+
         if (cleanedCount > 0) {
-            log.info("清理无效会话完成,共清理 {} 个超时会话", cleanedCount);
+            if (random.nextInt(10) == 1) {
+                log.info("已清理 {} 个无效会话", cleanedCount);
+            }
         }
     }
 
@@ -777,10 +766,9 @@ public class WebSocketServer {
 
     private void sendWithRetry(Session session, String message, int maxRetries) {
         if (session == null || !session.isOpen()) {
-            log.warn("WebSocket 会话已关闭,跳过发送");
             return;
         }
-        
+
         int attempts = 0;
         while (attempts < maxRetries) {
             try {
@@ -790,7 +778,6 @@ public class WebSocketServer {
             } catch (Exception e) {
                 if (e.getMessage() != null && e.getMessage().contains("TEXT_FULL_WRITING")) {
                     attempts++;
-                    log.warn("发送消息遇到TEXT_FULL_WRITING错误,第{}次重试, sessionId={}", attempts, session.getId());
                     try {
                         TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(5, 100));
                     } catch (InterruptedException ie) {
@@ -803,7 +790,7 @@ public class WebSocketServer {
                 }
             }
         }
-        
+
         if (attempts >= maxRetries) {
             log.warn("超过重试次数({}),放弃发送消息: sessionId={}", maxRetries, session.getId());
         }

+ 69 - 31
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -46,13 +46,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.fs.app.task.qwTask;
 
+import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 @Api("公共接口")
 @RestController
@@ -164,36 +163,39 @@ public class CommonController {
             List<QwUser> list = qwUserMapper.selectQwUserByTest();
             for (QwUser qwUser : list) {
                 try {
-                    Integer serverStatus = qwUser.getServerStatus();
-                    Long serverId = qwUser.getServerId();
-                    if (serverStatus==0){
-                        log.error("不需要解绑");
-                    }
+
+                     Long serverId = qwUser.getServerId();
+
                     if (serverId==null){
-                        log.error("serverId不存在");
+                        System.out.println("serverId不存在");
+                    }else {
+                        //没绑定销售 或者 已经离职
+                        if (qwUser.getStatus()==0 || qwUser.getIsDel()==2){
+
+                            updateIpadStatus(qwUser,serverId);
+                        }
+
+                        //绑定了销售-也绑定了ipad,但是长时间离线的(离线状态,无操作超过2天的,也自动解绑)
+                        if(qwUser.getUpdateTime()!=null){
+                            Date createTime = qwUser.getUpdateTime();
+                            Integer serverStatus = qwUser.getServerStatus();
+                            Integer ipadStatus = qwUser.getIpadStatus();
+
+                            boolean result = isCreateTimeMoreThanDaysWithOptional(createTime, 2);
+                            //大于2天 ,绑定了ipad,离线
+                            if(result && serverStatus==1 && ipadStatus==0){
+                                updateIpadStatus(qwUser,serverId);
+
+                            }
+                        }
+
+
                     }
-                    QwUser u = new QwUser();
-                    u.setId(qwUser.getId());
-                    u.setServerId(null);
-                    u.setServerStatus(0);
-                    qwUserMapper.updateQwUser(u);
-                    ipadServerService.addServer(serverId);
-                    QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
-                    qwIpadServerLog.setType(2);
-                    qwIpadServerLog.setTilie("解绑");
-                    qwIpadServerLog.setServerId(serverId);
-                    qwIpadServerLog.setQwUserId(qwUser.getId());
-                    qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
-                    qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
-                    qwIpadServerLog.setCreateTime(new Date());
-                    qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
-                    qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
-                    WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
-                    wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
-                    wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
-                    updateIpadStatus(qwUser.getId(),0);
+
+
                 } catch (Exception e) {
-                    log.error("解绑ipad报错",e);
+                    System.out.println("解绑ipad报错"+e);
+
                 }
             }
         } catch (Exception e) {
@@ -203,6 +205,42 @@ public class CommonController {
     }
 
 
+    public void updateIpadStatus(QwUser qwUser,Long serverId){
+        QwUser u = new QwUser();
+        u.setId(qwUser.getId());
+        u.setServerId(null);
+        u.setServerStatus(0);
+        qwUserMapper.updateQwUser(u);
+        ipadServerService.addServer(serverId);
+        QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
+        qwIpadServerLog.setType(2);
+        qwIpadServerLog.setTilie("解绑");
+        qwIpadServerLog.setServerId(serverId);
+        qwIpadServerLog.setQwUserId(qwUser.getId());
+        qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
+        qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
+        qwIpadServerLog.setCreateTime(new Date());
+        qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
+        qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
+        WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
+        wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
+        wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
+        updateIpadStatus(qwUser.getId(),0);
+    }
+
+    public static boolean isCreateTimeMoreThanDaysWithOptional(Date createTime, int days) {
+        return Optional.ofNullable(createTime)
+                .map(time -> {
+                    LocalDateTime createDateTime = time.toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDateTime();
+                    LocalDateTime now = LocalDateTime.now();
+                    Duration duration = Duration.between(createDateTime, now);
+                    return duration.toDays() > days;
+                })
+                .orElse(false); // 为null时返回false,可根据需求调整
+    }
+
     void updateIpadStatus(Long id ,Integer status){
         QwUser u = new QwUser();
         u.setId(id);

+ 25 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseFinishTemp.java

@@ -5,6 +5,7 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -66,4 +67,28 @@ public class FsCourseFinishTemp extends BaseEntity
      */
     @TableField(exist = false)
     private List<Long> ids;
+
+    @TableField(exist = false)
+    private List<String> userIds = new ArrayList<>();
+
+    public List<String> getUserIds() {
+        if (userIds == null || userIds.isEmpty()) {
+            return userIds;
+        }
+
+        // 直接在原始列表上修改
+        for (int i = 0; i < userIds.size(); i++) {
+            String id = userIds.get(i);
+            if (id != null) {
+                if (id.startsWith("dept_")) {
+                    userIds.set(i, id.substring(5));
+                } else if (id.startsWith("company_")) {
+                    userIds.set(i, id.substring(8));
+                } else if (id.startsWith("user_")) {
+                    userIds.set(i, id.substring(5));
+                }
+            }
+        }
+        return userIds;
+    }
 }

+ 6 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java

@@ -65,6 +65,12 @@ public interface FsCourseAnswerLogsMapper
             "            <if test=\"map.createTime != null \"> and Date(cal.create_time) = #{map.createTime}</if>\n" +
             "<if test=\"map.sTime != null \">  and DATE(cal.create_time) &gt;= DATE(#{map.sTime})</if>\n" +
             "<if test=\"map.eTime != null \">  and DATE(cal.create_time) &lt;= DATE(#{map.eTime})</if>\n" +
+            "            <if test=\"map.companyUserIds != null and !map.companyUserIds.isEmpty()\">\n" +
+            "                AND cal.company_user_id IN\n" +
+            "                <foreach collection='map.companyUserIds' item='item' open='(' separator=',' close=')'>\n" +
+            "                    #{item}\n" +
+            "                </foreach>\n" +
+            "            </if>" +
             "        </where>  " +
             "order by cal.log_id desc  " +
             " </script>")

+ 6 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseFinishTempMapper.java

@@ -87,6 +87,12 @@ public interface FsCourseFinishTempMapper
             "<if test = ' maps.status !=null '> " +
             "and t.status = #{maps.status} " +
             "</if>" +
+            "            <if test=\"userIds != null and !userIds.isEmpty()\">\n" +
+            "                AND create_by IN\n" +
+            "                <foreach collection='userIds' item='item' open='(' separator=',' close=')'>\n" +
+            "                    #{item}\n" +
+            "                </foreach>\n" +
+            "            </if>" +
             " order by t.id desc  "+
             "</script>"})
     List<FsCourseFinishTempListVO> selectFsCourseFinishTempListVO(@Param("maps") FsCourseFinishTemp fsCourseFinishTemp);

+ 28 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseAnswerLogsParam.java

@@ -1,10 +1,13 @@
 package com.fs.course.param;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 
 @Data
@@ -45,4 +48,29 @@ public class FsCourseAnswerLogsParam  extends BaseEntity  {
      */
     private Set<Long> userIds;
 
+    @TableField(exist = false)
+    private List<String> companyUserIds=new ArrayList<>();
+
+
+    public List<String> getCompanyUserIds() {
+        if (companyUserIds == null || companyUserIds.isEmpty()) {
+            return companyUserIds;
+        }
+
+        // 直接在原始列表上修改
+        for (int i = 0; i < companyUserIds.size(); i++) {
+            String id = companyUserIds.get(i);
+            if (id != null) {
+                if (id.startsWith("dept_")) {
+                    companyUserIds.set(i, id.substring(5));
+                } else if (id.startsWith("company_")) {
+                    companyUserIds.set(i, id.substring(8));
+                } else if (id.startsWith("user_")) {
+                    companyUserIds.set(i, id.substring(5));
+                }
+            }
+        }
+        return companyUserIds;
+    }
+
 }

+ 26 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java

@@ -1,9 +1,11 @@
 package com.fs.course.param;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -107,4 +109,28 @@ public class FsCourseWatchLogListParam implements Serializable {
     private Long deptId;
     private List<Long> deptIds;
     private String ids;
+
+    @TableField(exist = false)
+    private List<String> userIds = new ArrayList<>();
+
+    public List<String> getUserIds() {
+        if (userIds == null || userIds.isEmpty()) {
+            return userIds;
+        }
+
+        // 直接在原始列表上修改
+        for (int i = 0; i < userIds.size(); i++) {
+            String id = userIds.get(i);
+            if (id != null) {
+                if (id.startsWith("dept_")) {
+                    userIds.set(i, id.substring(5));
+                } else if (id.startsWith("company_")) {
+                    userIds.set(i, id.substring(8));
+                } else if (id.startsWith("user_")) {
+                    userIds.set(i, id.substring(5));
+                }
+            }
+        }
+        return userIds;
+    }
 }

+ 58 - 39
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1218,10 +1218,17 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                 return R.error("公司不存在");
             }
 
+            // 实际流量传输消耗是大于文件的,添加倍数计算流量消耗 配置 course.data.usage.multiple
+            BigDecimal multiple = new BigDecimal("1"); // 默认一倍
+            String config=configService.selectConfigByKey("course.data.usage.multiple");
+            if(StringUtils.isNotEmpty(config)){
+                multiple=new BigDecimal(config);
+            }
+
             // 计算流量
             BigDecimal result = param.getBufferRate().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
             BigDecimal longAsBigDecimal = BigDecimal.valueOf(video.getFileSize());
-            long roundedResult = result.multiply(longAsBigDecimal).setScale(0, RoundingMode.HALF_UP).longValue();
+            long roundedResult = result.multiply(longAsBigDecimal).multiply(multiple).setScale(0, RoundingMode.HALF_UP).longValue();
             trafficLog.setInternetTraffic(roundedResult);
             // 获取课程所属项目id
             FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
@@ -1995,44 +2002,49 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                     return R.error("服务商余额不足,请联系群主服务器充值!");
                 }
 
-                // 发送红包
-                R sendRedPacket = paymentService.sendRedPacket(packetParam);
-                if (sendRedPacket.get("code").equals(200)) {
-                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                    TransferBillsResult transferBillsResult;
-                    if (sendRedPacket.get("isNew").equals(1)) {
-                        transferBillsResult = (TransferBillsResult) sendRedPacket.get("data");
-                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                        redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
-                    } else {
-                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                        redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
-                    }
-                    // 添加红包记录
-                    redPacketLog.setCourseId(param.getCourseId());
-                    redPacketLog.setCompanyId(param.getCompanyId());
-                    redPacketLog.setUserId(param.getUserId());
-                    redPacketLog.setVideoId(param.getVideoId());
-                    redPacketLog.setStatus(0);
-                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                    redPacketLog.setCreateTime(new Date());
-                    redPacketLog.setAmount(amount);
-                    redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                    redPacketLog.setPeriodId(param.getPeriodId());
-                    redPacketLog.setAppId(param.getAppId());
+             try{
+                 // 发送红包
+                 R sendRedPacket = paymentService.sendRedPacket(packetParam);
+                 if (sendRedPacket.get("code").equals(200)) {
+                     FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                     TransferBillsResult transferBillsResult;
+                     if (sendRedPacket.get("isNew").equals(1)) {
+                         transferBillsResult = (TransferBillsResult) sendRedPacket.get("data");
+                         redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                         redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                         redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
+                     } else {
+                         redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                         redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+                     }
+                     // 添加红包记录
+                     redPacketLog.setCourseId(param.getCourseId());
+                     redPacketLog.setCompanyId(param.getCompanyId());
+                     redPacketLog.setUserId(param.getUserId());
+                     redPacketLog.setVideoId(param.getVideoId());
+                     redPacketLog.setStatus(0);
+                     redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                     redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                     redPacketLog.setCreateTime(new Date());
+                     redPacketLog.setAmount(amount);
+                     redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                     redPacketLog.setPeriodId(param.getPeriodId());
+                     redPacketLog.setAppId(param.getAppId());
+
+                     redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                     // 更新观看记录的奖励类型
+                     log.setRewardType(config.getRewardType());
+                     courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+                     return sendRedPacket;
+                 } else {
+                     return R.error("奖励发送失败,请联系客服");
+                 }
+             }catch (Exception e){
+                 return R.error("发放奖励失败,请联系客服");
+             }
 
-                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-
-                    // 更新观看记录的奖励类型
-                    log.setRewardType(config.getRewardType());
-                    courseWatchLogMapper.updateFsCourseWatchLog(log);
-
-                    return sendRedPacket;
-                } else {
-                    return R.error("奖励发送失败,请联系客服");
-                }
             }
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
@@ -3481,10 +3493,17 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                 return R.error("视频不存在");
             }
 
+            // 实际流量传输消耗是大于文件的,添加倍数计算流量消耗 配置 course.data.usage.multiple
+            BigDecimal multiple = new BigDecimal("1"); // 默认一倍
+            String config=configService.selectConfigByKey("course.data.usage.multiple");
+            if(config!= null){
+                multiple=new BigDecimal(config);
+            }
+
             // 计算流量
             BigDecimal result = param.getBufferRate().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
             BigDecimal longAsBigDecimal = BigDecimal.valueOf(video.getFileSize());
-            long roundedResult = result.multiply(longAsBigDecimal).setScale(0, RoundingMode.HALF_UP).longValue();
+            long roundedResult = result.multiply(longAsBigDecimal).multiply(multiple).setScale(0, RoundingMode.HALF_UP).longValue();
             trafficLog.setInternetTraffic(roundedResult);
 
             //扣除流量

+ 5 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseFinishTempListVO.java

@@ -42,6 +42,7 @@ public class FsCourseFinishTempListVO implements Serializable
     private Long courseId;
 
     private String courseName;
+    private String createBy;
 
     private String videoName;
 
@@ -64,4 +65,8 @@ public class FsCourseFinishTempListVO implements Serializable
     private Date updateTime;
 
     private Integer isAllCompanyUser;
+
+    private String createByName;
+
+    private String createByDeptName;
 }

+ 8 - 6
fs-service/src/main/java/com/fs/his/mapper/FsStorePaymentMapper.java

@@ -199,12 +199,14 @@ public interface FsStorePaymentMapper
             " LEFT JOIN fs_store s ON s.store_id=sp.store_id " +
             " left join fs_store_order fso on fso.order_code = sp.business_code " +
             " left join fs_inquiry_order fio on fio.order_sn = sp.business_code " +
-            "LEFT JOIN company c ON \n" +
-            "    ( c.company_id = fso.company_id) OR\n" +
-            "    ( c.company_id = fio.company_id)\n" +
-            "LEFT JOIN company_user cu ON \n" +
-            "    ( cu.user_id = fso.company_user_id) OR\n" +
-            "    (cu.user_id = fio.company_user_id) " +
+            " left join company c on c.company_id = sp.company_id " +
+            " left join company_user cu on cu.user_id = sp.company_user_id " +
+//            "LEFT JOIN company c ON \n" +
+//            "    ( c.company_id = fso.company_id) OR\n" +
+//            "    ( c.company_id = fio.company_id)\n" +
+//            "LEFT JOIN company_user cu ON \n" +
+//            "    ( cu.user_id = fso.company_user_id) OR\n" +
+//            "    (cu.user_id = fio.company_user_id) " +
             "LEFT JOIN fs_course_play_source_config csc ON csc.appid = sp.app_id" +
             " where 1=1 " +
             "            <if test=\"maps.payCode != null  and maps.payCode != ''\"> and sp.pay_code = #{maps.payCode}</if>\n" +

+ 16 - 7
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -24,6 +24,7 @@ import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.FsStoreOrderStatisticsVO;
 import com.fs.company.vo.FsStoreProductStatisticsVO;
+import com.fs.config.ai.AiHostProper;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
@@ -265,6 +266,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private ApplicationEventPublisher publisher;
 
+    @Autowired
+    AiHostProper aiHostProper;
+
     @Autowired
     private IFsUserWatchService fsUserWatchService;
     @Autowired
@@ -302,7 +306,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
     //ERP 类型到服务的映射
     private Map<Integer, IErpOrderService> erpServiceMap;
-
+    @Autowired
     private IFsStoreOrderScrmService orderScrmService;
     @PostConstruct
     public void initErpServiceMap() {
@@ -2194,8 +2198,13 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                                 }
                                 //app派件通知
                                 if (dto.getState().equals("2") && (dto.getStateEx().equals("211"))) {
-                                    //ai向客户发送发货物流信息
-                                    requestExpressInfo(order.getOrderId());
+                                    try {
+                                        //ai向客户发送发货物流信息
+                                        requestExpressInfo(order.getOrderId(),aiHostProper.getIpadUrl());
+                                    }catch (Exception e){
+                                        log.error("app派件通知推送失败:{}", e.getMessage());
+                                    }
+
                                 }
                                 //app派件通知
                                 if (dto.getState().equals("2") && (dto.getStateEx().equals("202"))) {
@@ -2235,9 +2244,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
                     }
                 }
-
+                logger.info("dto对象:{}", dto);
                 List<FsStoreOrderScrm> orders2 = orderScrmService.selectFsStoreOrderListByDeliveryId(dto.getLogisticCode());
-                if (orders != null) {
+                if (orders2 != null) {
                     for (FsStoreOrderScrm order : orders2) {
                         logger.info("订单信息:" + JSONUtil.toJsonStr(order));
                         logger.info("运单号:" + dto.getLogisticCode());
@@ -2267,8 +2276,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         return fsStoreOrderMapper.selectFsStoreOrderListByDeliverySn(logisticCode);
     }
 
-    public static R requestExpressInfo(Long orderId){
-        String fileUrl = "http://ipad.cdwjyyh.com/msg/sendExpressInfo/" + orderId;
+    public static R requestExpressInfo(Long orderId,String ipadUrl){
+        String fileUrl = ipadUrl + "/msg/sendExpressInfo/" + orderId;
 
         try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
             HttpGet httpGet = new HttpGet(fileUrl);

+ 39 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsUserCompanyPackageScrm.java

@@ -0,0 +1,39 @@
+package com.fs.hisStore.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 销售套餐用户绑定对象 fs_user_company_package_scrm
+ *
+ * @author fs
+ * @date 2025-12-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserCompanyPackageScrm extends BaseEntity{
+
+    @TableId
+    private Long id;
+
+    /** 销售公司id */
+    @Excel(name = "销售公司id")
+    private Long companyId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 套餐id */
+    @Excel(name = "套餐id")
+    private Long packageId;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+
+}

+ 5 - 2
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java

@@ -88,13 +88,16 @@ public interface FsStoreAfterSalesScrmMapper
 
     @Select({"<script> " +
             "select s.*,o.delivery_status,o.delivery_id,u.phone as user_phone,c.company_name ,cu.nick_name as company_user_nick_name ," +
-            "cu.phonenumber as company_usere_phonenumber,o.id as orderId,o.real_name as userName,o.item_json,o.user_address,o.pay_time as orderPayTime,o.pay_price,o.total_postage,fsps.bank_serial_no  " +
+            "cu.phonenumber as company_usere_phonenumber,o.pay_money,o.id as orderId,o.create_time as orderCreateTime,o.user_phone," +
+            "o.real_name as userName,o.item_json,o.user_address,o.pay_time as orderPayTime,o.pay_price,o.total_postage," +
+            "fsps.bank_serial_no,fsps.bank_transaction_id,o.delivery_id as orderDeliveryId,o.delivery_name as orderDeliveryName,o.delivery_sn as orderDeliverySn," +
+            "o.status as orderStatus " +
             " from fs_store_after_sales_scrm s " +
             " INNER join fs_store_order_scrm o on o.order_code=s.order_code " +
             " left join fs_user u on s.user_id=u.user_id " +
             " left join company c on c.company_id=s.company_id " +
             " left join company_user cu on cu.user_id=s.company_user_id " +
-            " left join fs_store_payment_scrm fsps on fsps.business_order_id = s.id and fsps.status in (-1,1) " +
+            " left join fs_store_payment_scrm fsps on fsps.business_order_id = o.id and fsps.status in (-1,1) " +
             " where 1=1 " +
             "<if test = 'maps.status != null    '> " +
             "and s.status = #{maps.status} " +

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

@@ -76,12 +76,18 @@ public interface FsStoreOrderItemScrmMapper
 
     @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.bank_transaction_id as bankTransactionId from fs_store_order_item_scrm i left join fs_store_order_scrm o on o.id=i.order_id" +
+            " ,p.title as package_name,cts.name as scheduleName,os.pay_money, os.bank_transaction_id as bankTransactionId " +
+            " 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 left join company_user cu on cu.user_id=o.company_user_id left join company_tcm_schedule cts on cts.id = o.schedule_id " +
-            " left join fs_store_product_scrm psps on i.product_id=psps.product_id left join fs_store_product_category_scrm fspcs on fspcs.cate_id=psps.cate_id " +
-            "where 1=1 " +
+            " 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 " +
+            " left join company_user cu on cu.user_id=o.company_user_id " +
+            " left join company_tcm_schedule cts on cts.id = o.schedule_id " +
+            " left join fs_store_product_scrm psps on i.product_id=psps.product_id " +
+            " left join fs_store_product_category_scrm fspcs on fspcs.cate_id=psps.cate_id " +
+            " where 1=1 " +
             "<if test = 'maps.orderCode != null and  maps.orderCode !=\"\"    '> " +
             "and o.order_code like CONCAT('%',#{maps.orderCode},'%') " +
             "</if>" +

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

@@ -1029,7 +1029,7 @@ public interface FsStoreOrderScrmMapper
     @Select("select id from fs_store_order_scrm WHERE `status`= 1  and  extend_order_id is null ")
     List<Long> selectFsStoreOrderNoCreateOms();
 
-    @Select("select * from fs_store_order_scrm where status = 1 and extend_order_id is not null and extend_order_id != '' and delivery_id is null ")
+    @Select("select * from fs_store_order_scrm where status = 1 and extend_order_id is not null and extend_order_id != '' and delivery_id is null order by update_time")
     List<FsStoreOrderScrm> selectUpdateExpress();
 
     @Select("select fso.id from fs_store_order_scrm fso inner join fs_store_order_audit_scrm fsoa on fsoa.order_id = fso.id where fso.`status`= 1 and fso.extend_order_id is null and fsoa.audit_status = 4")
@@ -1395,4 +1395,5 @@ public interface FsStoreOrderScrmMapper
      * **/
     List<FsStoreOrderScrm> getUnsettledOrder();
 
+    void batchUpdateTime(@Param("list") List<FsStoreOrderScrm> list);
 }

+ 61 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsUserCompanyPackageScrmMapper.java

@@ -0,0 +1,61 @@
+package com.fs.hisStore.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.hisStore.domain.FsUserCompanyPackageScrm;
+
+/**
+ * 销售套餐用户绑定Mapper接口
+ * 
+ * @author fs
+ * @date 2025-12-04
+ */
+public interface FsUserCompanyPackageScrmMapper extends BaseMapper<FsUserCompanyPackageScrm>{
+    /**
+     * 查询销售套餐用户绑定
+     * 
+     * @param id 销售套餐用户绑定主键
+     * @return 销售套餐用户绑定
+     */
+    FsUserCompanyPackageScrm selectFsUserCompanyPackageScrmById(Long id);
+
+    /**
+     * 查询销售套餐用户绑定列表
+     * 
+     * @param fsUserCompanyPackageScrm 销售套餐用户绑定
+     * @return 销售套餐用户绑定集合
+     */
+    List<FsUserCompanyPackageScrm> selectFsUserCompanyPackageScrmList(FsUserCompanyPackageScrm fsUserCompanyPackageScrm);
+
+    /**
+     * 新增销售套餐用户绑定
+     * 
+     * @param fsUserCompanyPackageScrm 销售套餐用户绑定
+     * @return 结果
+     */
+    int insertFsUserCompanyPackageScrm(FsUserCompanyPackageScrm fsUserCompanyPackageScrm);
+
+    /**
+     * 修改销售套餐用户绑定
+     * 
+     * @param fsUserCompanyPackageScrm 销售套餐用户绑定
+     * @return 结果
+     */
+    int updateFsUserCompanyPackageScrm(FsUserCompanyPackageScrm fsUserCompanyPackageScrm);
+
+    /**
+     * 删除销售套餐用户绑定
+     * 
+     * @param id 销售套餐用户绑定主键
+     * @return 结果
+     */
+    int deleteFsUserCompanyPackageScrmById(Long id);
+
+    /**
+     * 批量删除销售套餐用户绑定
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserCompanyPackageScrmByIds(Long[] ids);
+}

+ 21 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsUsePackageScrmSendParam.java

@@ -0,0 +1,21 @@
+package com.fs.hisStore.param;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+@Data
+public class FsUsePackageScrmSendParam {
+
+    /** 优惠劵id */
+    @Excel(name = "套餐id")
+    private Long packageId;
+
+    @Excel(name = "会员ID")
+    private Long userId;
+
+    //发送销售id
+    private Long companyUserId;
+
+    //发送销售公司id
+    private Long companyId;
+}

+ 5 - 1
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreProductPackageScrmService.java

@@ -1,8 +1,11 @@
 package com.fs.hisStore.service;
 
 import java.util.List;
+
+import com.fs.common.core.domain.R;
 import com.fs.hisStore.domain.FsStoreProductPackageScrm;
 import com.fs.hisStore.param.FsStoreProductPackageQueryParam;
+import com.fs.hisStore.param.FsUsePackageScrmSendParam;
 import com.fs.hisStore.vo.FsStoreProductPacketVO;
 
 /**
@@ -68,9 +71,10 @@ public interface IFsStoreProductPackageScrmService
     /**
      * 批量修改商品组合套餐
      *
-     * @param packageIds 需要修改的数据ID
+     * @param orderIds 需要修改的数据ID
      * @return 结果
      */
     public int updateFsStoreProductPackages(Long[] orderIds,Long status,Long companyId);
 
+    R sendPackage(FsUsePackageScrmSendParam param);
 }

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java

@@ -580,6 +580,10 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
                             item.setSku(StringUtils.isNotBlank(item.getSku()) ? item.getSku() + "," + jsO.getString("sku") : jsO.getString("sku"));
                             item.setNum(StringUtils.isNotBlank(item.getNum()) ? item.getNum() + "," + jsO.getString("num") : jsO.getString("num"));
                             item.setPrice(StringUtils.isNotBlank(item.getPrice()) ? item.getPrice() + "," + jsO.getString("price") : jsO.getString("price"));
+                            item.setBarCode(StringUtils.isNotBlank(item.getBarCode()) ? item.getBarCode() + "," + jsO.getString("barCode") : jsO.getString("barCode"));
+                            item.setCost(StringUtils.isNotBlank(item.getCost()) ? item.getCost() + "," + orderItem.getCost() : orderItem.getCost());
+                            item.setCateName(StringUtils.isNotBlank(item.getCateName()) ? item.getCateName() + "," + orderItem.getCateName() : orderItem.getCateName());
+
                         } catch (Exception ex) {
                             logger.error("售后订单商品信息转换异常",ex);
                         }

+ 12 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -390,6 +390,8 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     private IFsUserIntegralLogsService userIntegralLogsService;
     @Autowired
     private FsStoreProductPackageScrmMapper fsStoreProductPackageMapper;
+    @Autowired
+    private FsUserCompanyPackageScrmMapper fsUserCompanyPackageScrmMapper;
 
     @PostConstruct
     public void initErpServiceMap() {
@@ -1606,6 +1608,16 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             if (storeProductPackage.getStatus().equals(0)) {
                 return R.error("此套餐已下架");
             }
+            //只允许销售分享下单
+            if (CloudHostUtils.hasCloudHostName("康年堂")){
+                FsUserCompanyPackageScrm fsUserCompanyPackageScrm = new FsUserCompanyPackageScrm();
+                fsUserCompanyPackageScrm.setUserId(uid);
+                fsUserCompanyPackageScrm.setPackageId(param.getPackageId());
+                List<FsUserCompanyPackageScrm> fsUserCompanyPackageList = fsUserCompanyPackageScrmMapper.selectFsUserCompanyPackageScrmList(fsUserCompanyPackageScrm);
+                if (fsUserCompanyPackageList == null || fsUserCompanyPackageList.isEmpty()) {
+                    return R.error("商品链接无效");
+                }
+            }
             //限购处理
             if (storeProductPackage.getLimitCount() != null && storeProductPackage.getLimitCount() > 0) {
                 //查看是否已购买

+ 32 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPackageScrmServiceImpl.java

@@ -1,17 +1,24 @@
 package com.fs.hisStore.service.impl;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONUtil;
+import com.fs.common.core.domain.R;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.hisStore.domain.FsStoreProductScrm;
 import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsUserCompanyPackageScrm;
 import com.fs.hisStore.dto.StoreOrderProductDTO;
 import com.fs.hisStore.dto.StorePackageProductDTO;
 import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
 import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
+import com.fs.hisStore.mapper.FsUserCompanyPackageScrmMapper;
 import com.fs.hisStore.param.FsStoreProductPackageQueryParam;
+import com.fs.hisStore.param.FsUsePackageScrmSendParam;
 import com.fs.hisStore.vo.FsStoreProductPacketVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -34,6 +41,10 @@ public class FsStoreProductPackageScrmServiceImpl implements IFsStoreProductPack
     private FsStoreProductAttrValueScrmMapper fsStoreProductAttrValueMapper;
     @Autowired
     private FsStoreProductScrmMapper fsStoreProductMapper;
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+    @Autowired
+    private FsUserCompanyPackageScrmMapper fsUserCompanyPackageScrmMapper;
     /**
      * 查询商品组合套餐
      *
@@ -152,4 +163,25 @@ public class FsStoreProductPackageScrmServiceImpl implements IFsStoreProductPack
         return fsStoreProductPackageMapper.updateFsStoreProductPackages(orderIds,status,companyId);
     }
 
+    @Override
+    public R sendPackage(FsUsePackageScrmSendParam param) {
+        Long companyUserId = param.getCompanyUserId();
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(companyUserId);
+        if (companyUser.getCompanyId()==null){
+            return R.error("销售信息错误");
+        }
+        FsUserCompanyPackageScrm fsUserCompanyPackageScrm = new FsUserCompanyPackageScrm();
+        fsUserCompanyPackageScrm.setCompanyId(companyUser.getCompanyId());
+        fsUserCompanyPackageScrm.setCompanyUserId(param.getCompanyUserId());
+        fsUserCompanyPackageScrm.setUserId(param.getUserId());
+        fsUserCompanyPackageScrm.setPackageId(param.getPackageId());
+        List<FsUserCompanyPackageScrm> fsUserCompanyPackageScrms = fsUserCompanyPackageScrmMapper.selectFsUserCompanyPackageScrmList(fsUserCompanyPackageScrm);
+        if (fsUserCompanyPackageScrms == null || fsUserCompanyPackageScrms.isEmpty()){
+            fsUserCompanyPackageScrm.setCreateTime(new Date());
+            fsUserCompanyPackageScrmMapper.insertFsUserCompanyPackageScrm(fsUserCompanyPackageScrm);
+        }
+        return R.ok();
+
+    }
+
 }

+ 13 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreAfterSalesVO.java

@@ -114,6 +114,8 @@ public class FsStoreAfterSalesVO implements Serializable
     private String num;
     @Excel(name ="产品价格")
     private String price;
+    @Excel(name ="产品编码")
+    private String barCode;
     @Excel(name="额外运费")
     private BigDecimal totalPostage;
     @Excel(name="实付金额")
@@ -127,7 +129,18 @@ public class FsStoreAfterSalesVO implements Serializable
     @Excel(name ="银行交易流水号")
     private String bankSerialNo;
 
+    private String bankTransactionId;
+
     private Long orderId;
 
+    private String cost;
+
+    private BigDecimal payMoney;
+
+    private String cateName;
+    private Date orderCreateTime;
 
+    private String orderDeliverySn;
+    private String orderDeliveryName;
+    private String orderDeliveryId;
 }

+ 133 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportRefundZMVO.java

@@ -0,0 +1,133 @@
+package com.fs.hisStore.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author MixLiu
+ * @date 2025/12/4 上午11:43)
+ */
+
+@Data
+public class FsStoreOrderItemExportRefundZMVO implements Serializable  {
+
+
+    private Long itemId;
+
+    /** 订单号 */
+    @Excel(name = "订单号",sort = 1)
+    private String orderCode;
+
+    @Excel(name = "订单状态", dictType = "store_order_status",sort = 10)
+    private String status;
+
+    @Excel(name = "会员ID" ,sort = 20)
+    private Long userId;
+
+    @Excel(name = "产品名称",sort = 30)
+    private String productName;
+
+    @Excel(name = "产品编码",sort =40)
+    private String barCode;
+
+
+    @Excel(name = "规格",sort =50)
+    private String sku;
+
+    @Excel(name = "产品数量",sort =60)
+    private String num;
+
+
+    @Excel(name = "产品价格",sort =70)
+    private String price;
+
+    @Excel(name = "成本价",sort =80)
+    private String cost;
+    @Excel(name = "结算价",sort =90)
+    private BigDecimal FPrice;
+
+    @Excel(name = "实付金额",sort =91)
+    private BigDecimal payMoney;
+
+    @Excel(name = "额外运费",sort =100)
+    private BigDecimal payPostage;
+    private Integer totalNum;
+    @Excel(name = "商品分类",sort =100)
+    private String cateName;
+
+
+    private String jsonInfo;
+
+    /** 用户姓名 */
+    @Excel(name = "收货人姓名",sort =110)
+    private String realName;
+
+    /** 用户电话 */
+    @Excel(name = "收货人电话",sort =120)
+    private String userPhone;
+
+    /** 详细地址 */
+    @Excel(name = "详细地址",sort =130)
+    private String userAddress;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "下单时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 140)
+    private Date createTime;
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 150)
+    private Date payTime;
+
+    /** 快递公司编号 */
+    @Excel(name = "快递公司编号",sort = 160)
+    private String deliverySn;
+
+    /** 快递名称/送货人姓名 */
+    @Excel(name = "快递公司",sort = 170)
+    private String deliveryName;
+
+    /** 快递单号/手机号 */
+    @Excel(name = "快递单号",sort = 180)
+    private String deliveryId;
+
+    @Excel(name = "所属公司",sort = 190)
+    private String companyName;
+    @Excel(name = "所属销售",sort = 200)
+    private String companyUserNickName;
+
+    @Excel(name = "套餐名称",sort = 210)
+    private String packageName;
+
+    @Excel(name = "组合码",sort = 210)
+    private String groupBarCode;
+
+    @Excel(name = "是否上传凭证 0:未上传 1:已上传",sort = 210)
+    private Integer isUpload;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "上传时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 220)
+    private Date uploadTime;
+
+    @Excel(name = "归属档期",sort = 230)
+    private String scheduleName;
+
+    //银行交易流水号
+    @Excel(name = "银行交易流水号",sort = 240)
+    private String bankTransactionId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "退款时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 220)
+    private Date refundTime;
+
+    @Excel(name = "退款数量" ,sort = 230)
+    private Integer afterSalesNumber;
+
+    @Excel(name = "退款金额" ,sort = 240)
+    private BigDecimal refundMoney;
+
+}

+ 3 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportVO.java

@@ -45,6 +45,9 @@ public class FsStoreOrderItemExportVO implements Serializable
     private BigDecimal cost;
     @Excel(name = "结算价")
     private BigDecimal FPrice;
+
+    private BigDecimal payMoney;
+
     @Excel(name = "额外运费")
     private BigDecimal payPostage;
     private Integer totalNum;

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

@@ -0,0 +1,124 @@
+package com.fs.hisStore.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author MixLiu
+ * @date 2025/12/4 上午11:43)
+ */
+
+@Data
+public class FsStoreOrderItemExportZMVO implements Serializable  {
+
+
+    private Long itemId;
+
+    /** 订单号 */
+    @Excel(name = "订单号",sort = 1)
+    private String orderCode;
+
+    @Excel(name = "订单状态", dictType = "store_order_status",sort = 10)
+    private String status;
+
+    @Excel(name = "会员ID" ,sort = 20)
+    private Long userId;
+
+    @Excel(name = "产品名称",sort = 30)
+    private String productName;
+
+    @Excel(name = "产品编码",sort =40)
+    private String barCode;
+
+
+    @Excel(name = "规格",sort =50)
+    private String sku;
+
+    @Excel(name = "产品数量",sort =60)
+    private Integer num;
+
+
+    @Excel(name = "产品价格",sort =70)
+    private BigDecimal price;
+
+    @Excel(name = "成本价",sort =80)
+    private BigDecimal cost;
+    @Excel(name = "结算价",sort =90)
+    private BigDecimal FPrice;
+
+    @Excel(name = "实付金额",sort =91)
+    private BigDecimal payMoney;
+
+    @Excel(name = "额外运费",sort =100)
+    private BigDecimal payPostage;
+    private Integer totalNum;
+    @Excel(name = "商品分类",sort =100)
+    private String cateName;
+
+
+    private String jsonInfo;
+
+    /** 用户姓名 */
+    @Excel(name = "收货人姓名",sort =110)
+    private String realName;
+
+    /** 用户电话 */
+    @Excel(name = "收货人电话",sort =120)
+    private String userPhone;
+
+    /** 详细地址 */
+    @Excel(name = "详细地址",sort =130)
+    private String userAddress;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "下单时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 140)
+    private Date createTime;
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 150)
+    private Date payTime;
+
+    /** 快递公司编号 */
+    @Excel(name = "快递公司编号",sort = 160)
+    private String deliverySn;
+
+    /** 快递名称/送货人姓名 */
+    @Excel(name = "快递公司",sort = 170)
+    private String deliveryName;
+
+    /** 快递单号/手机号 */
+    @Excel(name = "快递单号",sort = 180)
+    private String deliveryId;
+
+    @Excel(name = "所属公司",sort = 190)
+    private String companyName;
+    @Excel(name = "所属销售",sort = 200)
+    private String companyUserNickName;
+
+    @Excel(name = "套餐名称",sort = 210)
+    private String packageName;
+
+    @Excel(name = "组合码",sort = 210)
+    private String groupBarCode;
+
+    @Excel(name = "是否上传凭证 0:未上传 1:已上传",sort = 210)
+    private Integer isUpload;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "上传时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 220)
+    private Date uploadTime;
+
+    @Excel(name = "归属档期",sort = 230)
+    private String scheduleName;
+
+    //银行交易流水号
+    @Excel(name = "银行交易流水号",sort = 240)
+    private String bankTransactionId;
+
+
+}

+ 7 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemVO.java

@@ -4,6 +4,7 @@ import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 @Data
 public class FsStoreOrderItemVO  implements Serializable
@@ -47,5 +48,11 @@ public class FsStoreOrderItemVO  implements Serializable
     private Integer isPrescribe;
 
     private Integer isDrug; //是否为药品
+    //成本
+    private String cost;
+    //商品分类
+    private String cateName;
+
+
 
 }

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

@@ -1,6 +1,7 @@
 package com.fs.live.mapper;
 
 
+import com.fs.hisStore.vo.FsStoreOrderItemExportZMVO;
 import com.fs.live.domain.LiveOrder;
 import com.fs.live.dto.LiveOrderDeliveryNoteDTO;
 import com.fs.live.param.FsMyLiveOrderQueryParam;
@@ -418,6 +419,8 @@ public interface LiveOrderMapper {
 
     List<LiveOrderVoZm> selectLiveOrderListZm(LiveOrder liveOrder);
 
+    List<FsStoreOrderItemExportZMVO> selectLiveOrderListZmNew(LiveOrder liveOrder);
+
     @Select(" SELECT * from live_order WHERE item_json is NULL ORDER BY create_time DESC  LIMIT 30")
     List<LiveOrder> selectLiveOrderItemJson();
 

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

@@ -5,6 +5,7 @@ import com.fs.erp.domain.ErpOrder;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.param.FsStoreOrderAddTuiMoneyParam;
 import com.fs.hisStore.param.FsStoreOrderScrmSetErpPhoneParam;
+import com.fs.hisStore.vo.FsStoreOrderItemExportZMVO;
 import com.fs.hisStore.vo.FsStoreOrderVO;
 import com.fs.live.domain.LiveAfterSales;
 import com.fs.live.domain.LiveOrder;
@@ -237,6 +238,8 @@ public interface ILiveOrderService {
 
     List<LiveOrderVoZm> selectLiveOrderListZm(LiveOrder liveOrder);
 
+    List<FsStoreOrderItemExportZMVO> selectLiveOrderListZmNew(LiveOrder liveOrder);
+
     R handleLiveOrderPay(LiveOrderPayParam param);
 
     List<LiveOrder> selectLiveOrderItemJson();
@@ -263,4 +266,8 @@ public interface ILiveOrderService {
     void batchUpdateTime(List<LiveOrder> list);
 
     void batchUpdateTimeIds(List<Long> ids);
+
+    Long isExistPayedRecord(Long orderId);
+
+    void payConfirmPayment(Long existPayedRecordId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/live/service/ILiveService.java

@@ -195,4 +195,6 @@ public interface ILiveService
     R liveListAll(PageRequest pageRequest);
 
     List<Live> listToLiveNoEnd(Live live);
+
+    Live selectLiveDbByLiveId(Long liveId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveAfterSalesServiceImpl.java

@@ -237,6 +237,8 @@ public class LiveAfterSalesServiceImpl implements ILiveAfterSalesService {
                         item.setSku(StringUtils.isNotBlank(item.getSku()) ? item.getSku() + "," + jsO.getString("sku") : jsO.getString("sku"));
                         item.setNum(StringUtils.isNotBlank(item.getNum()) ? item.getNum() + "," + jsO.getString("num") : jsO.getString("num"));
                         item.setPrice(StringUtils.isNotBlank(item.getPrice()) ? item.getPrice() + "," + jsO.getString("price") : jsO.getString("price"));
+                        item.setCost(StringUtils.isNotBlank(item.getCost()) ? item.getCost() + "," + liveOrderItemListUVO.getCost() : liveOrderItemListUVO.getCost());
+                        item.setCateName(StringUtils.isNotBlank(item.getCateName()) ? item.getCateName() + "," + liveOrderItemListUVO.getCateName() : liveOrderItemListUVO.getCateName());
                     } catch (Exception ex) {
                         log.error("售后订单商品信息转换异常",ex);
                     }

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

@@ -82,8 +82,10 @@ import com.fs.hisStore.param.*;
 import com.fs.hisStore.service.*;
 import com.fs.hisStore.vo.*;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
+import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
 import com.fs.huifuPay.domain.HuiFuRefundResult;
 import com.fs.huifuPay.domain.HuifuCreateOrderResult;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest;
 import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
 import com.fs.huifuPay.service.HuiFuService;
 import com.fs.live.domain.*;
@@ -98,8 +100,13 @@ import com.fs.live.service.*;
 import com.fs.live.vo.*;
 import com.fs.store.domain.*;
 import com.fs.system.service.ISysConfigService;
+import com.fs.tzBankPay.doman.QueryOrderResult;
+import com.fs.tzBankPay.doman.TzBankResult;
+import com.fs.tzBankPay.doman.payQueryOrder;
 import com.fs.wx.order.domain.FsWxExpressTask;
 import com.fs.wx.order.mapper.FsWxExpressTaskMapper;
+import com.fs.ybPay.domain.OrderResult;
+import com.fs.ybPay.dto.OrderQueryDTO;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
@@ -2944,6 +2951,16 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         return baseMapper.selectLiveOrderListZm(liveOrder);
     }
 
+    /**
+     * 导出新模板改动
+     * @param liveOrder
+     * @return
+     */
+    @Override
+    public List<FsStoreOrderItemExportZMVO> selectLiveOrderListZmNew(LiveOrder liveOrder){
+        return baseMapper.selectLiveOrderListZmNew(liveOrder);
+    }
+
     @Override
     @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
     public R handleLiveOrderPay(LiveOrderPayParam param) {
@@ -3385,6 +3402,48 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         baseMapper.batchUpdateTimeIds(ids);
     }
 
+    @Override
+    public Long isExistPayedRecord(Long orderId) {
+        LiveOrder liveOrder = baseMapper.selectLiveOrderByOrderId(String.valueOf(orderId));
+        if (liveOrder != null) {
+            List<LiveOrderPayment> paymentList = liveOrderPaymentMapper.selectLiveOrderPaymentByOrderId(orderId);
+            if (null != paymentList && !paymentList.isEmpty()) {
+                for (LiveOrderPayment payment : paymentList) {
+                    V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
+                    request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
+                    request.setOrgHfSeqId(payment.getTradeNo());
+                    HuiFuQueryOrderResult queryOrderResult = null;
+                    try {
+                        queryOrderResult = huiFuService.queryOrder(request);
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    if ("00000000".equals(queryOrderResult.getResp_code())) {
+                        if (queryOrderResult.getTrans_stat().equals("S")) {
+                            return payment.getPaymentId();
+                        }
+                    }
+                }
+            }
+
+        } else {
+            throw new RuntimeException("直播订单不存在");
+        }
+        return null;
+    }
+
+    @Override
+    @Transactional
+    public void payConfirmPayment(Long existPayedRecordId) {
+        LiveOrderPayment payment = liveOrderPaymentMapper.selectLiveOrderPaymentByPaymentId(existPayedRecordId);
+        if (payment == null) {
+            log.error("支付单不存在");
+            return;
+        }
+        log.info("手动查询单号:" + existPayedRecordId + ":" + payment);
+        this.payConfirm(1, null, payment.getPayCode(), payment.getTradeNo(), payment.getBankSerialNo(), payment.getBankSerialNo());
+    }
+
 
     @Override
     @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)

+ 27 - 5
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -128,6 +128,28 @@ public class LiveServiceImpl implements ILiveService
     private static volatile Integer version = 0;
 
 
+    @Override
+    public Live selectLiveDbByLiveId(Long liveId) {
+        // 缓存中没有,从数据库查询
+        Live byId = baseMapper.selectLiveByLiveId(liveId);
+        if (byId == null) {
+            return null;
+        }
+
+        List<LiveVideo> videos = liveVideoService.listByLiveId(liveId, 1);
+        if(!videos.isEmpty()){
+            LiveVideo liveVideo = videos.get(0);
+            byId.setVideoUrl(liveVideo.getVideoUrl());
+            byId.setDuration(liveVideo.getDuration());
+            byId.setVideoId(liveVideo.getVideoId());
+            byId.setVideoType(liveVideo.getVideoType());
+            byId.setVideoFileSize(liveVideo.getFileSize());
+            byId.setVideoDuration(liveVideo.getDuration());
+        }
+
+        return byId;
+    }
+
 
     /**
      * 查询直播
@@ -143,13 +165,13 @@ public class LiveServiceImpl implements ILiveService
         if (cachedLive != null) {
             return cachedLive;
         }
-        
+
         // 缓存中没有,从数据库查询
         Live byId = baseMapper.selectLiveByLiveId(liveId);
         if (byId == null) {
             return null;
         }
-        
+
         List<LiveVideo> videos = liveVideoService.listByLiveId(liveId, 1);
         if(!videos.isEmpty()){
             LiveVideo liveVideo = videos.get(0);
@@ -160,10 +182,10 @@ public class LiveServiceImpl implements ILiveService
             byId.setVideoFileSize(liveVideo.getFileSize());
             byId.setVideoDuration(liveVideo.getDuration());
         }
-        
+
         // 将结果存入缓存
         redisCache.setCacheObject(cacheKey, byId, LiveKeysConstant.LIVE_DATA_CACHE_EXPIRE, TimeUnit.SECONDS);
-        
+
         return byId;
     }
 
@@ -551,7 +573,7 @@ public class LiveServiceImpl implements ILiveService
         log.error("updateLive:" + live.getLiveId());
         int result = baseMapper.updateLive(live);
         liveAutoTaskService.recalcLiveAutoTask(live);
-        
+
         // 清除缓存
         clearLiveCache(live.getLiveId());
 

+ 12 - 0
fs-service/src/main/java/com/fs/live/vo/LiveAfterSalesVo.java

@@ -172,7 +172,19 @@ public class LiveAfterSalesVo {
     @Excel(name ="银行交易流水号")
     private String bankSerialNo;
 
+    private String bankTransactionId;
 
 
+    private String cost;
+
+    private BigDecimal payMoney;
+
+    private String cateName;
+    private Date orderCreateTime;
+
+    private String orderDeliverySn;
+    private String orderDeliveryName;
+    private String orderDeliveryId;
+
 
 }

+ 4 - 1
fs-service/src/main/java/com/fs/live/vo/LiveOrderItemListUVO.java

@@ -19,5 +19,8 @@ public class LiveOrderItemListUVO implements Serializable {
     /** 数量 */
     private Long num;
 
-
+    //成本
+    private String cost;
+    //商品分类
+    private String cateName;
 }

+ 10 - 2
fs-service/src/main/java/com/fs/live/vo/LiveOrderVoZm.java

@@ -479,6 +479,14 @@ public class LiveOrderVoZm{
     /** 银行交易流水号 */
     @Excel(name = "银行交易流水号")
     private String bankTransactionId;
-
-
+    //统一导出模板内容新增字段
+    private Integer num;
+    private String sku;
+//    private BigDecimal FPrice;
+    private String deliveryId;
+    private String packageName;
+    private String groupBarCode;
+    private Integer isUpload;
+    private Date uploadTime;
+    private String scheduleName;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwCompanyMapper.java

@@ -76,4 +76,7 @@ public interface QwCompanyMapper
     List<QwOptionsVO> selectQwCompanyListOptionsVO(@Param("userId") Long userId, @Param("deptId") Long deptId);
 
     List<QwCompany> selectByCorpIds(@Param("corpIds") List<String> corpIds);
+
+    @Select("select DISTINCT corp_id from qw_company ")
+    List<String> selectQwCompanyListFormCorpId();
 }

+ 11 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -496,4 +496,15 @@ public interface QwUserMapper extends BaseMapper<QwUser>
     List<QwUser> selectQwUserByIds(@Param("qwUserIdList") List<Long> qwUserIdList);
 
     List<QwUser> selectQwUserByTest();
+
+    @Select("<script>" +
+            "select id from qw_user where 1=1 " +
+            "            <if test=\"userIds != null and userIds.size() > 0\">\n" +
+            "                AND company_user_id IN\n" +
+            "                <foreach collection=\"userIds\" open=\"(\" close=\")\" separator=\",\" item=\"item\">\n" +
+            "                    ${item}\n" +
+            "                </foreach>\n" +
+            "            </if>" +
+            "</script>")
+    List<Long> selectQwUserListByCompanyUserIdS(@Param("userIds") List<String> userIds);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/qw/service/IQwCompanyService.java

@@ -66,5 +66,5 @@ public interface IQwCompanyService
 
     List<QwOptionsVO> selectQwCompanyListOptionsVO(Long userId, Long deptId);
 
-
+    List<String>  selectQwCompanyListFormCorpId();
 }

+ 1 - 0
fs-service/src/main/java/com/fs/qw/service/IQwUserService.java

@@ -214,4 +214,5 @@ public interface IQwUserService
     QwUser selectQwUserByVid(Long vid);
 
     List<QwUser> selectQwUserByIds(List<Long> qwUserIdList);
+    List<Long> selectQwUserListByCompanyUserIdS(List<String> userIds);
 }

+ 6 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwCompanyServiceImpl.java

@@ -11,6 +11,7 @@ import com.fs.voice.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -132,4 +133,9 @@ public class QwCompanyServiceImpl implements IQwCompanyService
     public List<QwOptionsVO> selectQwCompanyListOptionsVO(Long userId, Long deptId) {
         return qwCompanyMapper.selectQwCompanyListOptionsVO(userId, deptId);
     }
+
+    @Override
+    public List<String> selectQwCompanyListFormCorpId() {
+        return qwCompanyMapper.selectQwCompanyListFormCorpId();
+    }
 }

+ 6 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java

@@ -1563,6 +1563,12 @@ public class QwUserServiceImpl implements IQwUserService
     public List<QwUser> selectQwUserByIds(List<Long> qwUserIdList) {
         return qwUserMapper.selectQwUserByIds(qwUserIdList);
     }
+
+    @Override
+    public List<Long> selectQwUserListByCompanyUserIdS(List<String> userIds) {
+        return qwUserMapper.selectQwUserListByCompanyUserIdS(userIds);
+    }
+
     /**
      * 根据销售公司和企微ID查询企微用户
      */

+ 28 - 1
fs-service/src/main/java/com/fs/sop/domain/QwSop.java

@@ -8,7 +8,9 @@ import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 企微sop对象 qw_sop
@@ -135,7 +137,7 @@ public class QwSop implements Serializable
     private String userType;
 
     @TableField(exist = false)
-    private List<Long> qwUserIdList;
+    private List<Long> qwUserIdList = new ArrayList<>();  // 初始化
 
     @Excel(name = "开启评论或者弹幕,1-开启评论;2-开启弹幕;3-都关闭")
     @TableField(exist = false)
@@ -154,4 +156,29 @@ public class QwSop implements Serializable
     private Integer autoUserReg;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private String pullTime;
+
+
+    @TableField(exist = false)
+    private List<String> userIds = new ArrayList<>();
+
+    public List<String> getUserIds() {
+        if (userIds == null || userIds.isEmpty()) {
+            return userIds;
+        }
+
+        // 直接在原始列表上修改
+        for (int i = 0; i < userIds.size(); i++) {
+            String id = userIds.get(i);
+            if (id != null) {
+                if (id.startsWith("dept_")) {
+                    userIds.set(i, id.substring(5));
+                } else if (id.startsWith("company_")) {
+                    userIds.set(i, id.substring(8));
+                } else if (id.startsWith("user_")) {
+                    userIds.set(i, id.substring(5));
+                }
+            }
+        }
+        return userIds;
+    }
 }

+ 25 - 0
fs-service/src/main/java/com/fs/sop/domain/QwSopTemp.java

@@ -111,6 +111,31 @@ public class QwSopTemp implements Serializable
     @TableField(exist = false)
     private List<Long> userIds;
 
+    @TableField(exist = false)
+    private List<String> companyUserIds=new ArrayList<>();
+
+
+    public List<String> getCompanyUserIds() {
+        if (companyUserIds == null || companyUserIds.isEmpty()) {
+            return companyUserIds;
+        }
+
+        // 直接在原始列表上修改
+        for (int i = 0; i < companyUserIds.size(); i++) {
+            String id = companyUserIds.get(i);
+            if (id != null) {
+                if (id.startsWith("dept_")) {
+                    companyUserIds.set(i, id.substring(5));
+                } else if (id.startsWith("company_")) {
+                    companyUserIds.set(i, id.substring(8));
+                } else if (id.startsWith("user_")) {
+                    companyUserIds.set(i, id.substring(5));
+                }
+            }
+        }
+        return companyUserIds;
+    }
+
     /**
      * 部门类型 00 管理员 01 员工
      */

+ 1 - 1
fs-service/src/main/resources/application-config-druid-nmgyt.yml

@@ -96,6 +96,6 @@ ipad:
 wx_miniapp_temp:
   pay_order_temp_id: V
   inquiry_temp_id: 9
-enableRedPackAccount: 1
+enableRedPackAccount: 0
 
 

+ 6 - 0
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -172,6 +172,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     #{item}
                 </foreach>
             </if>
+           <if test="maps.userIds != null and !maps.userIds.isEmpty()">
+            AND l.company_user_id IN
+               <foreach collection='maps.userIds' item='item' open='(' separator=',' close=')'>
+                  #{item}
+               </foreach>
+            </if>
         </where>
          order by l.finish_time desc,l.update_time desc,l.create_time desc
     </select>

+ 10 - 1
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml

@@ -96,7 +96,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <select id="selectFsStoreOrderItemListByOrderIds" resultType="com.fs.hisStore.vo.FsStoreOrderItemVO" parameterType="java.util.List" >
-        select * from fs_store_order_item_scrm where order_id in
+        select
+        t1.order_id,
+        t1.order_code,
+        t1.json_info,
+        t2.cost,
+        t3.cate_name
+        from fs_store_order_item_scrm t1
+        left join fs_store_product_scrm t2 on t1.product_id = t2.product_id
+        left join fs_store_product_category_scrm t3 on t3.cate_id = t2.cate_id
+        where t1.order_id in
         <foreach item="itemId" collection="orderIds" open="(" separator="," close=")">
             #{itemId}
         </foreach>

+ 14 - 1
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml

@@ -1610,7 +1610,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         ROW_NUMBER() OVER (PARTITION BY sp.business_code ORDER BY sp.create_time DESC) as rn
         FROM fs_store_payment_scrm sp
         WHERE sp.business_code IS NOT NULL
-        ) sp_latest ON sp_latest.business_code = o.order_code AND sp_latest.rn = 1
+        ) sp_latest ON sp_latest.business_order_id = o.id AND sp_latest.rn = 1
         LEFT JOIN fs_course_play_source_config csc ON csc.appid = sp_latest.app_id
         <where>
             <if test="maps.appId != null and maps.appId != ''">
@@ -2082,4 +2082,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
               ) >= 3
     </select>
 
+    <update id="batchUpdateTime">
+        UPDATE fs_store_order_scrm
+        SET update_time = CASE
+        <foreach collection="list" item="item" separator="">
+            WHEN id = #{item.id} THEN #{item.updateTime}
+        </foreach>
+        END
+        WHERE id IN
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.id}
+        </foreach>
+    </update>
+
 </mapper>

+ 79 - 0
fs-service/src/main/resources/mapper/hisStore/FsUserCompanyPackageScrmMapper.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.hisStore.mapper.FsUserCompanyPackageScrmMapper">
+    
+    <resultMap type="FsUserCompanyPackageScrm" id="FsUserCompanyPackageScrmResult">
+        <result property="id"    column="id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="packageId"    column="package_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectFsUserCompanyPackageScrmVo">
+        select id, company_id, company_user_id, package_id, user_id, create_time, update_time from fs_user_company_package_scrm
+    </sql>
+
+    <select id="selectFsUserCompanyPackageScrmList" parameterType="FsUserCompanyPackageScrm" resultMap="FsUserCompanyPackageScrmResult">
+        <include refid="selectFsUserCompanyPackageScrmVo"/>
+        <where>  
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="packageId != null "> and package_id = #{packageId}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
+        </where>
+    </select>
+    
+    <select id="selectFsUserCompanyPackageScrmById" parameterType="Long" resultMap="FsUserCompanyPackageScrmResult">
+        <include refid="selectFsUserCompanyPackageScrmVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertFsUserCompanyPackageScrm" parameterType="FsUserCompanyPackageScrm" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_user_company_package_scrm
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="packageId != null">package_id,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="packageId != null">#{packageId},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsUserCompanyPackageScrm" parameterType="FsUserCompanyPackageScrm">
+        update fs_user_company_package_scrm
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="packageId != null">package_id = #{packageId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsUserCompanyPackageScrmById" parameterType="Long">
+        delete from fs_user_company_package_scrm where id = #{id}
+    </delete>
+
+    <delete id="deleteFsUserCompanyPackageScrmByIds" parameterType="String">
+        delete from fs_user_company_package_scrm where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 1 - 1
fs-service/src/main/resources/mapper/hisStore/FsUserScrmMapper.xml

@@ -522,7 +522,7 @@
     <update id="updateFsUser" parameterType="FsUserScrm">
         update fs_user
         <trim prefix="SET" suffixOverrides=",">
-            <if test="nickName != null">nick_name = #{nickName},</if>
+            <if test="nickname != null">nick_name = #{nickname},</if>
             <if test="nickname != null">nickname = #{nickname},</if>
             <if test="avatar != null">avatar = #{avatar},</if>
             <if test="phone != null">phone = #{phone},</if>

+ 3 - 1
fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml

@@ -66,7 +66,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select las.id, las.live_id, las.store_id, las.order_id, las.refund_amount,
         las.refund_type, las.reasons, las.explains, las.explain_img, las.delivery_code, las.delivery_sn, las.delivery_name, las.status, las.sales_status,
         las.order_status, las.create_time, las.is_del, las.user_id, las.consignee, las.phone_number, las.address, las.company_id, las.company_user_id, las.dept_id,
-        cu.nick_name as company_user_nick_name, c.company_name,lo.order_id,lo.order_code,lo.user_phone,las.user_id,lo.item_json,lo.pay_time as orderPayTime,lo.user_address,lo.user_name,lo.pay_price,lo.total_postage,lop.bank_serial_no
+        cu.nick_name as company_user_nick_name, c.company_name,lo.order_id,lo.order_code,lo.user_phone,las.user_id,lo.item_json,lo.pay_time as orderPayTime,
+        lo.user_address,lo.user_name,lo.pay_price,lo.total_postage,lop.bank_serial_no,lo.delivery_sn as orderDeliveryId,lo.delivery_name as orderDeliveryName,
+        lo.delivery_code as orderDeliverySn,lo.status as orderStatus,lop.bank_transaction_id,lo.pay_money
         from live_after_sales las
         left join live_order lo on lo.order_id = las.order_id
         left join company_user cu on cu.user_id = las.company_user_id

+ 13 - 2
fs-service/src/main/resources/mapper/live/LiveOrderItemMapper.xml

@@ -150,8 +150,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <select id="selectLiveOrderItemListUVOByOrderIds" resultType="com.fs.live.vo.LiveOrderItemListUVO"  parameterType="java.util.List">
-        select product_id,json_info,order_code,item_id,num,order_id from live_order_item
-        where order_id in
+        select
+        t1.product_id,
+        t1.json_info,
+        t1.order_code,
+        t1.item_id,
+        t1.num,
+        t1.order_id,
+        t2.cost,
+        t3.cate_name
+        from live_order_item t1
+        left join fs_store_product_scrm t2 on t1.product_id = t2.product_id
+        left join fs_store_product_category_scrm t3 on t3.cate_id = t2.cate_id
+        where t1.order_id in
         <foreach item="itemId" collection="orderIds" open="(" separator="," close=")">
             #{itemId}
         </foreach>

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

@@ -1098,6 +1098,118 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         ORDER BY o.create_time DESC
     </select>
 
+    <select id="selectLiveOrderListZmNew" parameterType="LiveOrder" resultType="com.fs.hisStore.vo.FsStoreOrderItemExportZMVO">
+        select
+            t1.order_code as orderCode,
+            t1.status,
+            t1.user_id as userId,
+            if(JSON_VALID(t2.json_info),t2.json_info->>'$.productName','') as productName,
+            if(JSON_VALID(t2.json_info),t2.json_info->>'$.barCode','') as barCode,
+            if(JSON_VALID(t2.json_info),t2.json_info->>'$.sku','') as sku,
+            if(JSON_VALID(t2.json_info),t2.json_info->>'$.price','') as price,
+            t2.num,
+            fsps.cost,
+            fspcs.cate_name as cateName,
+            t1.user_name as realName,
+            t1.user_phone as userPhone,
+            t1.user_address as userAddress,
+            t1.create_time as createTime,
+            t1.pay_time as payTime,
+            t1.delivery_sn as deliveryId,
+            t1.delivery_name as deliveryName,
+            t1.delivery_code as deliverySn,
+            t3.company_name as companyName,
+            t4.nick_name as companyUserNickName,
+            lop.bank_transaction_id as  bankTransactionId,
+            t1.pay_money,
+            t1.pay_delivery as payPostage
+        from
+            live_order t1
+                left join live_order_item t2 on t1.order_id = t2.order_id
+                left join fs_store_product_scrm fsps on fsps.product_id = t2.product_id
+                left join fs_store_product_category_scrm fspcs on fspcs.cate_id = fsps.cate_id
+                left join company t3 on t1.company_id = t3.company_id
+                left join company_user  t4 on t4.user_id = t1.company_user_id
+                LEFT JOIN (
+                SELECT
+                    t5.*,
+                    ROW_NUMBER() OVER (PARTITION BY t5.business_code ORDER BY t5.status desc,t5.create_time DESC) as rn
+                FROM live_order_payment t5
+                WHERE t5.business_id IS NOT NULL
+            ) lop ON lop.business_id = t1.order_id AND lop.rn = 1
+        <where>
+            t1.is_del = 0 and fsps.product_id IS NOT NULL
+            <if test="orderId != null">
+                AND t1.order_id = #{orderId}
+            </if>
+            <if test="liveId != null">
+                AND t1.live_id = #{liveId}
+            </if>
+            <if test="storeId != null">
+                AND t1.store_id = #{storeId}
+            </if>
+            <if test="orderCode != null and orderCode != ''">
+                AND t1.order_code LIKE CONCAT('%', #{orderCode}, '%')
+            </if>
+            <if test="userId != null and userId != ''">
+                AND t1.user_id = #{userId}
+            </if>
+            <if test="status != null">
+                AND t1.status = #{status}
+            </if>
+            <if test="companyId != null">
+                AND t1.company_id = #{companyId}
+            </if>
+            <if test="totalNum != null">
+                AND t1.total_num = #{totalNum}
+            </if>
+            <if test="price != null">
+                AND fsps.price = #{price}
+            </if>
+            <if test="cost != null">
+                AND fsps.cost = #{cost}
+            </if>
+            <if test="companyUserId != null">
+                AND t1.company_user_id = #{companyUserId}
+            </if>
+            <if test="productId != null">
+                AND t1.product_id = #{productId}
+            </if>
+            <!-- 新增筛选条件 -->
+            <if test="productName != null and productName != ''">
+                AND fsps.product_name LIKE CONCAT('%', #{productName}, '%')
+            </if>
+            <if test="productSpec != null and productSpec != ''">
+                AND fsps.prescribe_spec LIKE CONCAT('%', #{productSpec}, '%')
+            </if>
+            <if test="storeId != null and storeId != ''">
+                AND fsps.store_id = #{storeId}
+            </if>
+            <if test="userAddress != null and userAddress != ''">
+                AND t1.user_address LIKE CONCAT('%', #{userAddress}, '%')
+            </if>
+            <if test="userName != null and userName != ''">
+                AND t1.user_name LIKE CONCAT('%', #{userName}, '%')
+            </if>
+            <if test="createTimeStart != null ">
+                AND t1.create_time &gt;= #{createTimeStart}
+            </if>
+            <if test="createTimeEnd != null ">
+                AND t1.create_time &lt;= #{createTimeEnd}
+            </if>
+            <if test="payStartTime != null ">
+                AND t1.pay_time &gt;= #{payStartTime}
+            </if>
+            <if test="payEndTime != null ">
+                AND t1.pay_time &lt;= #{payEndTime}
+            </if>
+            <if test="userPhone != null and userPhone != ''">
+                AND t1.user_phone = #{userPhone}
+            </if>
+        </where>
+        GROUP BY t1.order_id
+    </select>
+
     <select id="getUnsettledOrder" resultType="com.fs.live.domain.LiveOrder">
         SELECT
             sos.*,

+ 3 - 2
fs-service/src/main/resources/mapper/qw/QwUserMapper.xml

@@ -35,10 +35,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="isAuto"    column="is_auto"    />
         <result property="videoGetStatus"    column="video_get_status"    />
         <result property="avatar"    column="avatar"    />
+        <result property="updateTime"    column="update_time"    />
     </resultMap>
 
     <sql id="selectQwUserVo">
-        select id,is_auto, video_get_status, qw_user_id,server_id,server_status,ipad_status,config_id,vid,uid,contact_way,app_key, qw_user_name, department, openid, company_id, company_user_id, corp_id, status, is_del, welcome_text, welcome_image, is_send_msg,app_key,qw_hook_id,fastGpt_role_id,login_status,tool_status,login_code_url,version,avatar from qw_user
+        select id,is_auto, video_get_status, qw_user_id,server_id,server_status,ipad_status,config_id,vid,uid,contact_way,app_key, qw_user_name, department, openid, company_id, company_user_id, corp_id, status, is_del, welcome_text, welcome_image, is_send_msg,app_key,qw_hook_id,fastGpt_role_id,login_status,tool_status,login_code_url,version,avatar,update_time from qw_user
         </sql>
 
     <select id="selectQwUserList" parameterType="QwUser" resultMap="QwUserResult">
@@ -321,7 +322,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectQwUserByTest" resultMap="QwUserResult">
         <include refid="selectQwUserVo"/>
-        where status = 0 and server_status = 1
+        where  server_status = 1
     </select>
 
 </mapper>

+ 7 - 1
fs-service/src/main/resources/mapper/sop/QwSopMapper.xml

@@ -236,7 +236,13 @@
             <if test="minSend != null "> and min_send = #{minSend}</if>
             <if test="maxSend != null "> and max_send = #{maxSend}</if>
             <if test="stopTime != null "> and stop_time = #{stopTime}</if>
-            <!-- 加入固定条件 -->
+            <if test="qwUserIdList != null and !qwUserIdList.isEmpty() ">
+              and (
+                <foreach collection='qwUserIdList' item='item' index='index' separator=' or '>
+                   find_in_set( #{item} , REGEXP_REPLACE(qw_user_ids,  '[\"\\\\[\\\\]]', '' ) )
+                </foreach>
+                )
+            </if>
             and status != 6
         </where>
         order by create_time desc

+ 6 - 0
fs-service/src/main/resources/mapper/sop/QwSopTempMapper.xml

@@ -56,6 +56,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     #{item}
                 </foreach>
             </if>
+            <if test="companyUserIds != null and !companyUserIds.isEmpty()">
+                AND create_by IN
+                <foreach collection='companyUserIds' item='item' open='(' separator=',' close=')'>
+                    #{item}
+                </foreach>
+            </if>
         </where>
         order by sort,create_time desc
     </select>

+ 5 - 1
fs-user-app/src/main/java/com/fs/app/controller/UserController.java

@@ -26,6 +26,8 @@ import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserCouponCountUVO;
 import com.fs.his.vo.FsUserCouponListUVO;
 import com.fs.his.vo.UserVo;
+import com.fs.hisStore.domain.FsUserScrm;
+import com.fs.hisStore.service.IFsUserScrmService;
 import com.fs.qw.service.IQwAppContactWayService;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
@@ -77,6 +79,8 @@ public class UserController extends  AppBaseController {
     private IQwAppContactWayService qwAppContactWayService;
     @Autowired
     private IFsUserCourseVideoService courseVideoService;
+    @Autowired
+    private IFsUserScrmService fsUserScrmService;
 
 
     @Autowired
@@ -116,7 +120,7 @@ public class UserController extends  AppBaseController {
     @GetMapping("/getUserInfo")
     public R getUserInfo(HttpServletRequest request){
         try {
-            FsUser user=userService.selectFsUserByUserId(Long.parseLong(getUserId()));
+            FsUserScrm user=fsUserScrmService.selectFsUserByUserId(Long.parseLong(getUserId()));
             if (user.getPhone()!=null&&user.getPhone().length()>11&&!user.getPhone().matches("\\d+")){
                 user.setPhone(decryptPhoneMk(user.getPhone()));
             }

+ 10 - 1
fs-user-app/src/main/java/com/fs/app/controller/live/LiveOrderController.java

@@ -644,13 +644,22 @@ public class LiveOrderController extends AppBaseController
     {
         Long orderId = param.getOrderId();
         logger.info("开始处理支付请求, 订单号: {}, 支付类型: {}", orderId, param.getPayType());
+        try{
+            Long existPayedRecordId = orderService.isExistPayedRecord(param.getOrderId());
+            if (null != existPayedRecordId) {
+                orderService.payConfirmPayment(existPayedRecordId);
+                return R.error("当前订单已支付");
+            }
+        } catch(Exception ex){
+            log.error("校验当前订单是否存在已经支付的支付记录异常,param:{}",param,ex);
+        }
+
 
         RLock lock = redissonClient.getLock(String.format(LOCK_KEY_PAY,orderId));
         R result = null;
 
         try {
             boolean locked = lock.tryLock(100, 30000, TimeUnit.MILLISECONDS);
-
             if (!locked) {
                 logger.warn("订单正在处理中,获取锁失败, 订单号: {}", orderId);
                 return R.error("订单正在处理中,请勿重复提交");

+ 23 - 4
fs-user-app/src/main/java/com/fs/app/controller/store/StoreProductPackageScrmController.java

@@ -12,6 +12,7 @@ import com.fs.hisStore.domain.FsStoreProductScrm;
 import com.fs.hisStore.dto.StoreOrderProductDTO;
 import com.fs.hisStore.dto.StorePackageProductDTO;
 import com.fs.hisStore.param.FsStoreProductPackageQueryParam;
+import com.fs.hisStore.param.FsUsePackageScrmSendParam;
 import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
 import com.fs.hisStore.service.IFsStoreProductPackageScrmService;
 import com.fs.hisStore.service.IFsStoreProductScrmService;
@@ -21,10 +22,7 @@ import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
@@ -83,4 +81,25 @@ public class StoreProductPackageScrmController extends AppBaseController {
         return R.ok().put("data",storeProductPackage);
     }
 
+    /**
+     * 销售分享套餐
+     */
+    @Login
+    @ApiOperation("销售分享套餐")
+    @PostMapping("/sendPackage")
+    public R sendPackage(@RequestBody FsUsePackageScrmSendParam param)
+    {
+        Long companyUserId = getCompanyUserId();
+        if(companyUserId==null){
+            return R.error("销售未登录!");
+        }
+        Long userId = param.getUserId();
+        if (userId == null) {
+            return R.error("未选择分享用户!");
+        }
+        param.setCompanyUserId(companyUserId);
+        return productPackageService.sendPackage(param);
+    }
+
+
 }