Browse Source

红德堂-ipad群发代码同步、自动看课去除二维码弹窗代码同步

Long 3 days ago
parent
commit
b2f4287481
23 changed files with 1471 additions and 291 deletions
  1. 5 0
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  2. 5 1
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  3. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java
  4. 0 5
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  5. 6 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java
  6. 152 157
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  7. 26 4
      fs-service/src/main/java/com/fs/ipad/IpadSendUtils.java
  8. 2 1
      fs-service/src/main/java/com/fs/ipad/vo/BaseVo.java
  9. 16 1
      fs-service/src/main/java/com/fs/live/domain/LiveOrder.java
  10. 0 8
      fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java
  11. 34 0
      fs-service/src/main/java/com/fs/live/vo/LiveOrderCodeOpenIdVo.java
  12. 81 0
      fs-service/src/main/java/com/fs/live/vo/LiveOrderDeliveryNoteExportVO.java
  13. 484 0
      fs-service/src/main/java/com/fs/live/vo/LiveOrderVoZm.java
  14. 7 2
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  15. 9 0
      fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java
  16. 11 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempRulesService.java
  17. 2 0
      fs-service/src/main/java/com/fs/sop/service/ISopUserLogsService.java
  18. 39 19
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempRulesServiceImpl.java
  19. 51 2
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  20. 146 90
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsServiceImpl.java
  21. 390 1
      fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml
  22. 1 0
      fs-service/src/main/resources/mapper/qw/QwGroupChatMapper.xml
  23. 2 0
      fs-service/src/main/resources/mapper/sop/SopUserLogsMapper.xml

+ 5 - 0
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java

@@ -195,4 +195,9 @@ public class SopUserLogsController extends BaseController
         sopUserLogsService.replaceUser(vo);
         return R.ok();
     }
+
+    @GetMapping("/getShortLink")
+    public R getShortLink(String id, String sopId, String appId){
+        return sopUserLogsService.getShortLink(id, sopId, appId);
+    }
 }

+ 5 - 1
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -47,11 +47,14 @@ public class IpadSendServer {
     private final IQwUserVideoService qwUserVideoService;
     private final RedisCache redisCache;
     private final ICompanyMiniappService companyMiniappService;
-
     private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap, Long companyId) {
+        // 发送参数原本的appid
         String appid = content.getMiniprogramAppid();
+        // 判断销售工时ID不为空并且有小程序类型
         if(companyId != null && content.getMiniType() != null){
+            // 获取销售公司下面绑定的主备小程序,并且根据当前应该发送的主备类型查询出数据
             List<CompanyMiniapp> list = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().eq("company_id", companyId).eq("type", content.getMiniType()));
+            // 判断当前绑定的最新的小程序,并且覆盖以前的值(可以达到实时替换小程序的功能)
             if(!list.isEmpty() && list.get(0) != null && StringUtils.isNotEmpty(list.get(0).getAppId())){
                 appid = list.get(0).getAppId();
             }
@@ -341,6 +344,7 @@ public class IpadSendServer {
         vo.setServerId(qwUser.getServerId());
         vo.setCorpCode(parentVo.getCorpCode());
         vo.setCorpId(parentVo.getCorpId());
+        vo.setQwUserId(qwUser.getId());
         try {
             content.setSendStatus(1);
             switch (content.getContentType()) {

+ 2 - 0
fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java

@@ -13,4 +13,6 @@ public interface IFsCoursePlaySourceConfigService extends IService<FsCoursePlayS
      * 查询点播配置列表
      */
     List<FsCoursePlaySourceConfigVO> selectCoursePlaySourceConfigVOListByMap(Map<String, Object> params);
+
+    List<FsCoursePlaySourceConfig> selectByAppIds(List<String> miniAppList);
 }

+ 0 - 5
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -898,14 +898,9 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
                             }else {
                                 return R.error("获取失败:"+jsonObject.getString("errmsg"));
                             }
-                        }else {
-                            return R.error("未配置小程序id");
                         }
                     }
                 }
-
-
-
             } else {
                 return R.error("页面链接错误,获取失败");
             }

+ 6 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.course.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
@@ -24,4 +25,9 @@ public class FsCoursePlaySourceConfigServiceImpl extends ServiceImpl<FsCoursePla
     public List<FsCoursePlaySourceConfigVO> selectCoursePlaySourceConfigVOListByMap(Map<String, Object> params) {
         return baseMapper.selectCoursePlaySourceConfigVOListByMap(params);
     }
+
+    @Override
+    public List<FsCoursePlaySourceConfig> selectByAppIds(List<String> miniAppList) {
+        return baseMapper.selectList(new QueryWrapper<FsCoursePlaySourceConfig>().in("appid", miniAppList));
+    }
 }

+ 152 - 157
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -62,45 +62,34 @@ import com.fs.qw.mapper.*;
 import com.fs.qw.param.FsUserCourseRedPageParam;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.IQwExternalContactService;
-import com.fs.qw.vo.SortDayVo;
 import com.fs.qwApi.Result.QwAddContactWayResult;
-import com.fs.qwApi.Result.QwGroupChatDetailsResult;
 import com.fs.qwApi.param.QwAddContactWayParam;
 import com.fs.qwApi.service.QwApiService;
-import com.fs.sop.domain.QwSopTempDay;
 import com.fs.sop.domain.SopUserLogsInfo;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.service.ISopUserLogsInfoService;
-import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysDictDataMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
-import com.google.common.collect.Sets;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.rocketmq.spring.core.RocketMQTemplate;
-import org.jetbrains.annotations.NotNull;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
-import org.redisson.client.RedisClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.text.SimpleDateFormat;
 import java.time.*;
 import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -140,8 +129,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     @Autowired
     ICompanyService companyService;
     @Autowired
-    private CompanyMoneyLogsMapper moneyLogsMapper;
-    @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
     @Autowired
     private QwGroupChatMapper qwGroupChatMapper;
@@ -152,8 +139,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     @Autowired
     private FsUserCourseCompanyUserTimeMapper companyUserTimeMapper;
     @Autowired
-    private RocketMQTemplate rocketMQTemplate;
-    @Autowired
     private FsUserCourseStudyLogMapper courseStudyLogMapper;
 
     @Autowired
@@ -168,9 +153,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     @Autowired
     private FsCourseLinkMapper fsCourseLinkMapper;
 
-    @Autowired
-    private AsyncIsAddKfXfkService xfkService;
-
 
     @Autowired
     private RedissonClient redissonClient;
@@ -179,8 +161,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     @Autowired
     private ISysConfigService configService;
     @Autowired
-    private FsCourseSopLogsMapper courseSopLogsMapper;
-    @Autowired
     private QwApiService qwApiService;
     @Autowired
     private QwUserMapper qwUserMapper;
@@ -196,11 +176,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     private IFsStorePaymentService paymentService;
     @Autowired
     private FsCourseRedPacketLogMapper redPacketLogMapper;
-    @Autowired
-    private FsCourseFinishTempMapper fsCourseFinishTempMapper;
 
-    @Autowired
-    private QwSopLogsMapper qwSopLogsMapper;
     @Autowired
     private FsCourseLinkMapper courseLinkMapper;
     @Autowired
@@ -211,8 +187,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     @Autowired
     private CompanyUserMapper companyUserMapper;
 
-    @Autowired
-    private IFsVideoResourceService fsVideoResourceService;
     @Autowired
     private FsVideoResourceMapper fsVideoResourceMapper;
 
@@ -225,8 +199,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
     @Autowired
     private FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;
 
-    @Autowired
-    private FsUserCompanyUserMapper fsUserCompanyUserMapper;
 
     @Autowired
     private IQwExternalContactService qwExternalContactService;
@@ -251,6 +223,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
 
     @Autowired
     ConfigUtil configUtil;
+
     @Autowired
     private FsUserCoursePeriodCompanyMapper periodCompanyMapper;
 
@@ -492,7 +465,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
         //用户不存在唤起重新授权
         if (fsUser == null) {
-            return R.error(504, "未授权");
+            return R.error(401, "未授权");
         }
 
         if (fsUser.getStatus() == 0) {
@@ -513,12 +486,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
 //            }
 //            return  R.ok();
 //        }
-        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
-                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
-        //济南联志隐藏二维码
-        if ("济南联志健康".equals(signProjectName)) {
-            msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br></div>";
-        }
+        //未注册提示
+        String noRegisterMsg = "由于您还未完成注册,请联系伴学助手完成注册即可观看!";
+        //非独属链接提示
+        String noMemberMsg = "此链接已被绑定,请联系伴学助手领取您的专属链接,专属链接请勿分享哦!";
 //        try {
 //            new Thread(() -> {
 //                try {
@@ -535,10 +506,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
 
 
-        //服务号授权的,缺mpOpenId的重新登录
-        if (config.getMiniAppAuthType() == 2 && StringUtil.strIsNullOrEmpty(fsUser.getMpOpenId())) {
-            return R.error(401, "授权后可继续!");
-        }
+//        //服务号授权的,缺mpOpenId的重新登录 linkType = 4为app看课 不需要mp
+//        if (param.getLinkType() != 4 && config.getMiniAppAuthType()==2 && StringUtil.strIsNullOrEmpty(fsUser.getMpOpenId())){
+//            return R.error(401,"授权后可继续!");
+//        }
 
         boolean oneCompanyCourse = config.isOneCompanyCourse();
         if (oneCompanyCourse && fsUser.getQwExtId() != null) {
@@ -563,15 +534,15 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         Integer isRoom = param.getIsRoom();
 
         // 处理逻辑
-        if (StringUtils.isNotEmpty(param.getChatId())) {
-            return handleQwRoom(param, fsUser);
+        if(StringUtils.isNotEmpty(param.getChatId())){
+            return handleQwRoom(param, fsUser,noRegisterMsg);
         }
         if (isRoom == null || isRoom == 0) {
             // 当 isRoom 为 null 或 0 时走 handleExt
-            return handleExt(param, msg, oneCompanyCourse);
+            return handleExt(param,noMemberMsg, oneCompanyCourse);
         } else if (isRoom == 1) {
             // 当 isRoom 为 1 时走 handleRoom
-            return handleRoom(param, fsUser);
+            return handleRoom(param,fsUser,noRegisterMsg);
         } else {
             // 非法参数
             logger.warn("非法参数 isRoom: {}", isRoom);
@@ -579,11 +550,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         }
 
     }
-
-    private R handleQwRoom(FsUserCourseVideoAddKfUParam param, FsUser user) {
+    private R handleQwRoom(FsUserCourseVideoAddKfUParam param,FsUser user,String noRegisterMsg) {
         FsCourseLink courseLink = courseLinkMapper.selectFsCourseLinkByLink(param.getLink());
-        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为群会员独享<br>请长按二维码</div>\n" +
-                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
+//        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为群会员独享<br>请长按二维码</div>\n" +
+//                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
         QwGroupChat qwGroupChat = qwGroupChatMapper.selectQwGroupChatByChatId(courseLink.getChatId());
         if (qwGroupChat == null) {
             return R.error("群参数异常");
@@ -594,36 +564,94 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         if (qwGroupChatUsers == null || qwGroupChatUsers.isEmpty()) {
             return R.error("群参数异常");
         }
-        //修改成通过昵称匹配
-        QwExternalContact qwExternalContact =
-                qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+        //群聊寻找用户新逻辑
+        QwExternalContact qwExternalContact = null;
+        if (null != param.getUserId() && null == qwExternalContact) {
+            try {
+                qwExternalContact = qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
                         .eq("user_id", qwGroupChat.getOwner())
-                        .eq("name", user.getNickName())
+                        .eq("fs_user_id", param.getUserId())
                         .eq("corp_id", param.getCorpId())
                         .eq("status", 0));
-        if (qwExternalContact == null) {
-            return addCustomerService(param.getQwUserId(), msg);
+            } catch (Exception e) {
+                log.error("群聊用户id匹配异常,参数user_id:{},fs_user_id:{},corp_id:{}", qwGroupChat.getOwner(), param.getUserId(), param.getCorpId(), e);
+            }
         }
-        if (qwGroupChatUsers.stream().noneMatch(e -> e.getUserId().equals(qwExternalContact.getExternalUserId()))) {
+        //找当前群中的用户匹配
+        if (StringUtils.isNotBlank(param.getChatId()) && null == qwExternalContact) {
+            List<QwExternalContact> groupChatUserByChatIdAndUserName = qwExternalContactMapper.getGroupChatUserByChatIdAndUserName(qwGroupChat.getOwner(), user.getNickName(), param.getCorpId(), param.getChatId());
+            log.info("群聊用户查询结果,参数user_id:{},name:{},corp_id:{},chatId:{},groupChatUserByChatIdAndUserName:{}", qwGroupChat.getOwner(), user.getNickName(), param.getCorpId(), param.getChatId(), groupChatUserByChatIdAndUserName);
+            //没找到用户 || 找到的用户数量大于1 使用userid查询匹配
+            if (null == groupChatUserByChatIdAndUserName || groupChatUserByChatIdAndUserName.isEmpty() || groupChatUserByChatIdAndUserName.size() > 1) {
+                log.error("群聊用户昵称匹配异常,参数user_id:{},name:{},corp_id:{},chatId:{}", qwGroupChat.getOwner(), user.getNickName(), param.getCorpId(), param.getChatId());
+            } else {
+                qwExternalContact = groupChatUserByChatIdAndUserName.get(0);
+            }
+        }
+//        QwExternalContact qwExternalContact =  qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+//                            .eq("user_id", qwGroupChat.getOwner())
+//                            .eq("fs_user_id", param.getUserId())
+//                            .eq("corp_id", param.getCorpId())
+//                            .eq("status",0));
+//
+//        if(null == qwExternalContact){
+//            try{
+//                //修改成通过昵称匹配
+//                qwExternalContact =
+//                        qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+//                                .eq("user_id", qwGroupChat.getOwner())
+//                                .eq("name", user.getNickName())
+//                                .eq("corp_id", param.getCorpId())
+//                                .eq("status",0));
+//            } catch(Exception e){
+//                log.error("群聊用户昵称匹配异常,参数user_id:{},name:{},corp_id:{}",qwGroupChat.getOwner(),user.getNickName(),param.getCorpId(),e);
+//            }
+//
+//        }
+//        QwExternalContact qwExternalContact =
+//                qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+//                        .eq("user_id", qwGroupChat.getOwner())
+//                        .eq("fs_user_id", param.getUserId())
+//                        .eq("corp_id", param.getCorpId())
+//                        .eq("status",0));
+//        if(null == qwExternalContact){
+//            try{
+//                //修改成通过昵称匹配
+//                qwExternalContact =
+//                        qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+//                                .eq("user_id", qwGroupChat.getOwner())
+//                                .eq("name", user.getNickName())
+//                                .eq("corp_id", param.getCorpId())
+//                                .eq("status",0));
+//            } catch(Exception e){
+//                log.error("群聊用户昵称匹配异常,参数user_id:{},name:{},corp_id:{}",qwGroupChat.getOwner(),user.getNickName(),param.getCorpId(),e);
+//            }
+//
+//        }
+        if(qwExternalContact==null){
+            return R.error(noRegisterMsg);
+        }
+        QwExternalContact finalQwExternalContact = qwExternalContact;
+        if (qwGroupChatUsers.stream().noneMatch(e -> e.getUserId().equals(finalQwExternalContact.getExternalUserId()))) {
             log.error("客户不在群:{},里面:{}", qwGroupChat.getChatId(), qwExternalContact.getExternalUserId());
-            return addCustomerService(param.getQwUserId(), msg);
+            return R.error(noRegisterMsg);
         }
         Long qwExternalId = qwExternalContact.getId();
 //        addCompanyCompanyFsUser(param);
-        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(), param.getQwUserId());
-        if (log == null) {
-            return addCustomerService(param.getQwUserId(), msg);
+        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(),param.getQwUserId());
+        if (log==null ){
+            return R.error(noRegisterMsg);
         }
         //判断外部联系人有没有绑定userId
         if (qwExternalContact.getFsUserId() != null) {
             //有客户有小程序id  但 登录的小程序id和根据外部联系人id查出来的小程序id不一致
             if (!qwExternalContact.getFsUserId().equals(param.getUserId())) {
-                return addCustomerService(param.getQwUserId(), msg);
+                return R.error(noRegisterMsg);
             }
             List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByMiniUserId(param.getUserId());
             //匹配客户公司id
-            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))) {
-                return addCustomerService(param.getQwUserId(), msg);
+            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))){
+                return R.error(noRegisterMsg);
             }
 
             //看课记录中userId为0绑定userId
@@ -660,14 +688,16 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         fsUserCompanyBindService.bindFsUser(param.getUserId(), qwExternalId, log.getLogId());
         return R.error(567, "群聊通用链接").put("qwExternalId", qwExternalContact.getId());
     }
-
-    private R handleRoom(FsUserCourseVideoAddKfUParam param, FsUser user) {
+    private R handleRoom(FsUserCourseVideoAddKfUParam param,FsUser user,String noRegisterMsg) {
         //查询客户列表
         List<QwExternalContact> contacts = qwExternalContactMapper.selectQwExternalContactListVOByfsUserId(user.getUserId());
-        log.info("查出来的企微客户数量:" + contacts.size());
-        if (!contacts.isEmpty()) {
+        List<QwExternalContact> nonNullContacts = contacts.stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        log.info("查出来的企微客户数量:" + nonNullContacts.size());
+        if (!nonNullContacts.isEmpty()) {
             //找出对应销售匹配的客户
-            QwExternalContact matchedContact = contacts.stream()
+            QwExternalContact matchedContact = nonNullContacts.stream()
                     .filter(contact -> contact.getQwUserId().equals(Long.parseLong(param.getQwUserId())))
                     .findFirst()
                     .orElse(null);
@@ -683,85 +713,50 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
                     createWatchLog(param);
                 }
                 return R.error(567, "群聊通用链接").put("qwExternalId", matchedContact.getId());
+            } else {
+                QwExternalContact contact = nonNullContacts.get(0);
+                log.info("匹配到的第一个企微用户:" + contact.getUserId());
+                log.info("企微id:" + contact.getId());
+                log.info("用户:" + param.getVideoId());
+                log.info("企微用户:" + param.getQwUserId());
+                param.setQwExternalId(contact.getId());
+                FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(contact.getId(), param.getVideoId(), param.getQwUserId());
+                if (log == null) {
+                    createWatchLog(param);
+                }
+                return R.error(567, "群聊通用链接").put("qwExternalId", contact.getId());
+            }
+        }
+        if ("今正科技".equals(cloudHostProper.getCompanyName())) {
+            QwExternalContact UnionEXt = qwExternalContactMapper.selectQwExternalByUnionID(user.getUnionId());
+            if (UnionEXt != null) {
+                log.info("匹配到的第一个企微用户:" + UnionEXt.getUserId());
+                log.info("企微id:" + UnionEXt.getId());
+                log.info("用户:" + param.getVideoId());
+                log.info("企微用户:" + param.getQwUserId());
+                param.setQwExternalId(UnionEXt.getId());
+                FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(UnionEXt.getId(), param.getVideoId(), param.getQwUserId());
+                if (log == null) {
+                    param.setUserId(user.getUserId());
+                    createWatchLog(param);
+                } else {
+                    if (log.getUserId() == null || log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())) {
+                        log.setUserId(param.getUserId());
+                    }
+                    log.setUpdateTime(new Date());
+                    courseWatchLogMapper.updateFsCourseWatchLog(log);
+                }
+                return R.error(567, "群聊通用链接").put("qwExternalId", UnionEXt.getId());
             }
         }
 
-        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为群会员独享<br>请长按二维码</div>\n" +
-                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
 
-        return addCustomerService(param.getQwUserId(), msg);
+     /*   String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为群会员独享<br>请长按二维码</div>\n" +
+                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";*/
+
+        return R.error(noRegisterMsg);
+
 
-//        QwGroupChatDetailsResult result = qwApiService.groupChatDetails(courseLink.getChatId(), param.getCorpId());
-//        if(result.getErrCode() != 0){
-//            log.info("企微接口请求失败,请联系管理员:" +result.getErrMsg());
-//            return R.error("不是此群成员");
-//        }
-//        List<QwGroupChatDetailsResult.Member> collect = result.getGroupChat().getMemberList().stream().filter(e -> e.getType() == 2).collect(Collectors.toList());
-//        if(collect.isEmpty()){
-//            logger.info("群聊里面为空弹二维码:"+param.getCorpId()+":"+param.getQwUserId()+":"+param.getChatId()+":"+param.getUserId());
-//            return addCustomerService(param.getQwUserId(),msg);
-//        }
-//        Optional<QwGroupChatDetailsResult.Member> optional = collect.stream().filter(e -> e.getName().equals(user.getNickName()) || e.getName().equals(param.getNickName())).findFirst();
-//        if(!optional.isPresent()){
-//            logger.info("昵称未匹配上弹二维码:"+param.getCorpId()+":"+param.getQwUserId()+":"+param.getChatId()+":"+param.getUserId());
-//
-//            return addCustomerService(param.getQwUserId(),msg);
-//        }
-//        QwGroupChatDetailsResult.Member member = optional.get();
-//        QwExternalContact qwExternalContact = qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>().eq("user_id", result.getGroupChat().getOwner()).eq("external_user_id", member.getUserId()));
-//        if(qwExternalContact==null){
-//            logger.info("外部联系人为空弹二维码:"+param.getCorpId()+":"+param.getQwUserId()+":"+param.getChatId()+":"+param.getUserId()+":"+member.getUserId()+param.getNickName());
-//            return addCustomerService(param.getQwUserId(),msg);
-//        }
-//        Long qwExternalId = qwExternalContact.getId();
-//        log.info("外部联系人数据:{}", qwExternalContact);
-////        addCompanyCompanyFsUser(param);
-//        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(),param.getQwUserId());
-//        if (log==null ){
-//            logger.info("看课记录为空弹二维码:"+param.getCorpId()+":"+param.getQwUserId()+":"+param.getChatId()+":"+param.getUserId()+qwExternalId+":"+param.getVideoId()+":"+param.getQwUserId());
-//            return addCustomerService(param.getQwUserId(),msg);
-//        }
-//        //判断外部联系人有没有绑定userId
-//        if (qwExternalContact.getFsUserId()!=null){
-//            //有客户有小程序id  但 登录的小程序id和根据外部联系人id查出来的小程序id不一致
-//            if (!qwExternalContact.getFsUserId().equals(param.getUserId())) {
-//                logger.info("小程序id不一致空弹二维码:"+param.getCorpId()+":"+param.getQwUserId()+":"+param.getChatId()+":"+param.getUserId());
-//                return addCustomerService(param.getQwUserId(),msg);
-//            }
-//            List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByMiniUserId(param.getUserId());
-//            //匹配客户公司id
-//            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))){
-//                logger.info("未匹配上公司空弹二维码:"+param.getCorpId()+":"+param.getQwUserId()+":"+param.getChatId()+":"+param.getUserId());
-//                return addCustomerService(param.getQwUserId(),msg);
-//            }
-//
-//            //看课记录中userId为0绑定userId
-//            if (log.getUserId()==null||log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())){
-//                log.setUserId(param.getUserId());
-//            }
-//
-//            log.setUpdateTime(new Date());
-//            courseWatchLogMapper.updateFsCourseWatchLog(log);
-//
-//            iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
-//        }else {
-//            //没绑定fsUser直接绑定fsUser
-//            QwExternalContact contact = new QwExternalContact();
-//            contact.setId(qwExternalId);
-//            contact.setFsUserId(param.getUserId());
-//            qwExternalContactMapper.updateQwExternalContact(contact);
-//            FsUser fsUser = new FsUser();
-//            fsUser.setUserId(user.getUserId());
-//            fsUser.setIsAddQw(1);
-//            fsUserMapper.updateFsUser(fsUser);
-//            //绑定上之后 更新观看记录
-//            //看课记录中userId为0绑定userId
-//            log.setUserId(param.getUserId());
-//            log.setUpdateTime(new Date());
-//            courseWatchLogMapper.updateFsCourseWatchLog(log);
-//        }
-//
-//        return R.error(567,"群聊通用链接").put("qwExternalId", qwExternalContact.getId());
     }
 
     private void createWatchLog(FsUserCourseVideoAddKfUParam param) {
@@ -811,15 +806,15 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         if (param.getLinkType() != null && param.getLinkType() == 5) {
             log = courseWatchLogMapper.selectFsCourseWatchLogByCourseSopIdAndVideoId(param.getUserId(), param.getVideoId(), param.getQwUserId());
             if (log == null) {
-                return addCustomerService(param.getQwUserId(), msg);
-            } else {
-                qwExternalId = log.getQwExternalContactId();
+                return R.error(msg);
+            }else {
+                qwExternalId=log.getQwExternalContactId();
             }
 
-        } else {
-            log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(), param.getQwUserId());
-            if (log == null) {
-                return addCustomerService(param.getQwUserId(), msg);
+        }else {
+            log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(),param.getQwUserId());
+            if (log==null ){
+                return R.error(msg);
             }
         }
 
@@ -836,19 +831,19 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
 
 
         //如果查不出来客户信息,加好友
-        if (externalContact == null) {
-            return addCustomerService(param.getQwUserId(), msg);
+        if(externalContact==null){
+            return R.error(msg);
         }
 
         //判断外部联系人有没有绑定userId
         if (externalContact.getFsUserId() != null) {
             //有客户有小程序id  但 登录的小程序id和根据外部联系人id查出来的小程序id不一致
             if (!externalContact.getFsUserId().equals(param.getUserId())) {
-                return addCustomerService(param.getQwUserId(), msg);
+                return R.error(msg);
             }
             //匹配客户公司id
-            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))) {
-                return addCustomerService(param.getQwUserId(), msg);
+            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))){
+                return R.error(msg);
             }
 
             //看课记录中userId为0绑定userId
@@ -935,7 +930,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
             qwAddContactWayParam.setType(1);
             qwAddContactWayParam.setScene(2);
             qwAddContactWayParam.setUser(users);
-            qwAddContactWayParam.setSkip_verify(true);
+            qwAddContactWayParam.setSkip_verify(false);
             QwAddContactWayResult qwAddContactWayResult = qwApiService.addContactWay(qwAddContactWayParam, qwUser.getCorpId());
             if (qwAddContactWayResult.getErrcode() == 0) {
                 qwUser.setContactWay(qwAddContactWayResult.getQr_code());
@@ -1363,10 +1358,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService {
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
 
         // 判断来源是否是app,如是app,则发放积分奖励
-        int sourceApp = 3;
-        if (sourceApp == param.getSource()) {
-            return sendIntegralReward(param, user, log, config);
-        }
+//        int sourceApp = 3;
+//        if (sourceApp == param.getSource()) {
+//            return sendIntegralReward(param, user, log, config);
+//        }
 
         // 根据奖励类型发放不同奖励
         switch (config.getRewardType()) {

+ 26 - 4
fs-service/src/main/java/com/fs/ipad/IpadSendUtils.java

@@ -3,6 +3,7 @@ package com.fs.ipad;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.exception.base.BaseException;
@@ -17,6 +18,7 @@ import com.fs.qw.domain.QwGroupChat;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwGroupChatMapper;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.SopUserLogs;
 import com.fs.sop.mapper.QwSopMapper;
@@ -53,8 +55,10 @@ public class IpadSendUtils {
     private final QwSopMapper qwSopMapper;
     private final QwExternalContactMapper qwExternalContactMapper;
     private final SopUserLogsMapper sopUserLogsMapper;
+    private final QwUserMapper qwUserMapper;
     private final RedisCache redisCacheUrl;
     private final String FILE_KEY = "ipad:upload:";
+    private final String USER_KEY = "ipad:user:";
 
     /**
      * 发送卡片消息
@@ -241,11 +245,22 @@ public class IpadSendUtils {
      * @return 返回的userid
      */
     private Long chatIds(BaseVo vo){
+        // 实时查询群聊信息
+        QwGroupChat qwGroupChat = qwGroupChatMapper.selectQwGroupChatByChatId(vo.getExId());
+        if(qwGroupChat == null){
+            throw new BaseException("未找到群聊,检查SOP任务数据");
+        }
+        if(qwGroupChat.getRoomid() != null){
+            return qwGroupChat.getRoomid();
+        }
+        // 找到对应的企业微信
+        QwUser qwUser = qwUserMapper.selectQwUserById(vo.getQwUserId());
         WxWorkChatIdToRoomIdDTO tdo = new WxWorkChatIdToRoomIdDTO();
-        tdo.setChatid(vo.getExId());
-        tdo.setCorpid(vo.getCorpId());
-        tdo.setUuid(vo.getUuid());
-        WxWorkResponseDTO<WxWorkChatIdToRoomIdResp> result = wxWorkService.ChatIdToRoomId(tdo, vo.getServerId());
+        // 重新组装数据
+        tdo.setChatid(qwGroupChat.getChatId());
+//        tdo.setCorpid(vo.getCorpId());
+        tdo.setUuid(qwUser.getUid());
+        WxWorkResponseDTO<WxWorkChatIdToRoomIdResp> result = wxWorkService.ChatIdToRoomId(tdo, qwUser.getServerId());
         if(result.getErrcode() != 0){
             throw new BaseException(result.getErrmsg());
         }
@@ -254,6 +269,13 @@ public class IpadSendUtils {
             log.error("未找到群聊数据,请求数据:{},返回数据:{}", JSON.toJSONString(tdo), JSON.toJSONString(result));
             throw new BaseException("未找到群聊:" + vo.getId());
         }
+        try {
+            qwGroupChat.setRoomid(data.getRoom_id());
+            qwGroupChatMapper.updateQwGroupChat(qwGroupChat);
+            redisCache.setCacheObject(USER_KEY + vo.getExId(), data.getRoom_id().toString());
+        }catch (Exception e){
+            log.error("存储群ID失败", e);
+        }
         return data.getRoom_id();
     }
 

+ 2 - 1
fs-service/src/main/java/com/fs/ipad/vo/BaseVo.java

@@ -15,7 +15,7 @@ public class BaseVo{
     private String corpId;
     private String corpCode;
     private boolean isRoom;
-
+    private Long qwUserId;
 
     public void setBase(BaseVo vo){
         this.uuid = vo.getUuid();
@@ -24,5 +24,6 @@ public class BaseVo{
         this.corpCode = vo.getCorpCode();
         this.exId = vo.getExId();
         this.isRoom = vo.isRoom();
+        this.qwUserId = vo.qwUserId;
     }
 }

+ 16 - 1
fs-service/src/main/java/com/fs/live/domain/LiveOrder.java

@@ -1,5 +1,6 @@
 package com.fs.live.domain;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
@@ -335,6 +336,20 @@ public class LiveOrder extends BaseEntity {
 
     /** 优惠券金额 */
     private BigDecimal couponPrice;
-
+    // 卓美新增筛选条件
+    private String productName;
+    private String productSpec;
+    private String productNum;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTimeStart;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTimeEnd;
+
+    private Integer price;
+    private Integer cost;
+    @TableField(exist = false)
+    private String bankTransactionId;
+    @TableField(exist = false)
+    private Long attrValueId;
 
 }

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

@@ -29,14 +29,6 @@ public interface LiveOrderMapper {
      */
     LiveOrder selectLiveOrderByOrderId(String orderId);
 
-    /**
-     * 查询订单
-     *
-     * @param orderId 订单主键
-     * @return 订单
-     */
-    @Select("select * from live_order where order_id=#{orderId}")
-    LiveOrder selectLiveOrderByOrderId(Long orderId);
 
     @Select("select order_code from live_order where order_id=#{orderId}")
     String selectLiveOrderCodeByOrderId(@Param("orderId") String orderId);

+ 34 - 0
fs-service/src/main/java/com/fs/live/vo/LiveOrderCodeOpenIdVo.java

@@ -0,0 +1,34 @@
+package com.fs.live.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class LiveOrderCodeOpenIdVo implements Serializable {
+    /**
+     * 订单id
+     * **/
+    private String id;
+
+    /**
+     * 用户openId
+     * **/
+    private String openId;
+
+    /**
+     * 用户手机号
+     * **/
+    private String phone;
+
+    /**
+     * 商品详情信息
+     * **/
+    private String jsonInfo;
+
+    /**
+     * 交易单号
+     * **/
+    private String outTransId;
+}
+

+ 81 - 0
fs-service/src/main/java/com/fs/live/vo/LiveOrderDeliveryNoteExportVO.java

@@ -0,0 +1,81 @@
+package com.fs.live.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 发货单导出(直播订单)
+ * **/
+@Data
+public class LiveOrderDeliveryNoteExportVO implements Serializable {
+    //系统订单号
+    @Excel(name = "原始单号",width = 20,sort = 1)
+    private String orderNumber;
+
+    @Excel(name = "收件人",width = 10,sort = 2)
+    private String recipient;
+
+    @Excel(name = "收件人手机",width = 20,sort = 3)
+    private String recipientPhone;
+
+    @Excel(name = "收件人电话",width = 20,sort = 4)
+    private String recipientTelephone;
+
+    //具体到某个街道和小区
+    @Excel(name = "收件人详细地址",width = 30,sort = 5)
+    private String recipientAddress;
+
+    //编号和数量:662551*2
+    @Excel(name = "组合编号及数量",width = 20,sort = 7)
+    private String number;
+
+    //名称和数量:商品名称*2
+    @Excel(name = "组合名称及数量",width = 20,sort = 8)
+    private String nameAndNumber;
+
+    @Excel(name = "代收金额",width = 10,sort = 9)
+    private BigDecimal collectionAmount;
+
+    @Excel(name = "物流公司",width = 10,sort = 10)
+    private String logisticsCompany;
+
+    @Excel(name = "物流产品",width = 10,sort = 11)
+    private String logisticsProduct;
+
+    @Excel(name = "物流付款方式",width = 15,sort = 12)
+    private String logisticsPayMethod;
+
+    @Excel(name = "包裹数",width = 10,sort = 13)
+    private Long packageNum;
+
+    @Excel(name = "寄件人",width = 10,sort = 14)
+    private String sender;
+
+    @Excel(name = "寄件人手机",width = 20,sort = 15)
+    private String senderPhone;
+
+    @Excel(name = "寄件人电话",width = 20,sort = 16)
+    private String senderTelephone;
+
+    @Excel(name = "寄件公司",width = 10,sort = 17)
+    private String senderCompany;
+
+    //具体到某个街道和小区
+    @Excel(name = "寄件人详细地址",width = 30,sort = 18)
+    private String senderAddress;
+
+    @Excel(name = "出库仓库",width = 10,sort = 19)
+    private String outboundWarehouse;
+
+    @Excel(name = "订单付款方式",width = 10,sort = 20)
+    private String payMethod;
+
+    @Excel(name = "订单备注",width = 20,sort = 21)
+    private String orderNotes;
+
+    private String keyword;
+}
+

+ 484 - 0
fs-service/src/main/java/com/fs/live/vo/LiveOrderVoZm.java

@@ -0,0 +1,484 @@
+package com.fs.live.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * 订单对象 live_order
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@Data
+public class LiveOrderVoZm{
+
+
+    /** 订单号 */
+    @Excel(name = "订单号")
+    private String orderCode;
+
+    /** 订单ID */
+    private Long orderId;
+
+    /** 公司员工id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 绑定销售昵称 */
+    @Excel(name = "绑定销售昵称")
+    private String companyUserNickName;
+
+    /** 客户编码 */
+//    @Excel(name = "客户编码")
+    private String userCode;
+
+    /** 会员等级 */
+    @Excel(name = "会员等级")
+    private Integer userLevel;
+
+
+    /** 销售绑定手机号 */
+    @Excel(name = "销售手机号")
+    private String companyUserPhone;
+
+    /** 销售加入时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "销售加入时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date companyUserCreateTime;
+
+
+    /** 用户id */
+    @Excel(name = "客户ID")
+    private String userId;
+
+    /** 客户昵称 */
+    @Excel(name = "客户昵称")
+    private String nickName;
+
+    /** 客户绑定手机号 */
+    @Excel(name = "客户手机号")
+    private String userBindPhone;
+
+    /** 收货人电话 */
+    @Excel(name = "收货手机号")
+    private String userPhone;
+
+
+    /** 累计成交笔数 */
+    @Excel(name = "累计成交笔数")
+    private Long totalOrderCount;
+
+
+
+    /** 累计成交总额 */
+    @Excel(name = "累计成交总额", cellType = Excel.ColumnType.NUMERIC)
+    private BigDecimal totalOrderAmount;
+
+    /** 最新绑定时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "最新绑定时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date latestBindTime;
+
+
+    /** 客户状态 */
+    @Excel(name = "客户状态")
+    private Integer userStatus;
+
+    @Excel(name = "所属店铺")
+    private Long storeId;
+
+
+    /** 所属门店名称 */
+    @Excel(name = "所属店铺名称")
+    private String storeName;
+
+
+    @Excel(name = "商品ID")
+    private Long productId;
+
+    /** 商品名称 */
+    @Excel(name = "商品名称")
+    private String productName;
+
+
+    /** 商品规格 */
+    @Excel(name = "商品规格")
+    private String productSpec;
+
+    /** 订单商品总数 */
+    @Excel(name = "商品数量")
+    private String totalNum;
+
+    @Excel(name = "销售价格")
+    private BigDecimal price;
+
+    @Excel(name = "成本价格")
+    private BigDecimal cost;
+
+    @Excel(name = "结算价格")
+    private BigDecimal fPrice;
+
+    /** 支付运费 */
+    @Excel(name = "支付运费")
+    private BigDecimal payDelivery;
+
+    @Excel(name = "商品编码")
+    private String barCode;
+
+    @Excel(name = "商品分类")
+    private String cateName;
+
+    /** 支付金额 */
+    @Excel(name = "支付金额")
+    private BigDecimal payMoney;
+
+    /** 详细地址 */
+    @Excel(name = "收货地址")
+    private String userAddress;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime payTime;
+
+
+
+
+    /** 直播ID */
+//    @Excel(name = "直播ID")
+    private Long liveId;
+
+
+
+
+
+
+
+    /** 收货人 */
+//    @Excel(name = "收货人")
+    private String userName;
+
+
+
+
+    /** 购物车id */
+//    @Excel(name = "购物车id")
+    private String cartId;
+
+
+
+    /** 订单总价 */
+//    @Excel(name = "订单总价")
+    private BigDecimal totalPrice;
+
+    /** 实际支付金额 */
+//    @Excel(name = "实际支付金额")
+    private BigDecimal payPrice;
+
+
+
+    /** 支付状态 待支付 1已支付 */
+//    @Excel(name = "支付状态 待支付 1已支付")
+    private String isPay;
+
+    /** 取消理由*/
+//    @Excel(name = "取消理由")
+    private String cancelReason;
+
+
+
+    // 支付开始时间
+    private String payStartTime;
+    // 支付结束时间
+    private String payEndTime;
+
+    /** 支付方式 1微信 */
+//    @Excel(name = "支付方式 1微信")
+    private String payType;
+
+    /** 订单状态(-1 : 申请退款 -2 : 退货成功 0:已取消 1:待支付 2:待发货;3:待收货;4:待评价;5:已完成) */
+    @Excel(name = "订单状态",dictType="sys_live_order_status")
+    private Integer status;
+
+    /** 对应供应商 */
+    @Excel(name = "对应供应商")
+    private String supplierName;
+
+    /** 0 未退款 1 申请中 2 已退款 */
+//    @Excel(name = "0 未退款 1 申请中 2 已退款")
+    private String refundStatus;
+    /** 收货人 */
+//    @Excel(name = "收货人")
+    private String realName;
+
+
+    /** 退款图片 */
+//    @Excel(name = "退款图片")
+    private String refundImg;
+
+    /** 退款用户说明 */
+//    @Excel(name = "退款用户说明")
+    private String refundExplain;
+
+    /** 退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "退款时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 不退款的理由 */
+//    @Excel(name = "不退款的理由")
+    private String refundReason;
+
+    /** 退款金额 */
+//    @Excel(name = "退款金额")
+    private BigDecimal refundMoney;
+
+    /** 快递公司编号 */
+//    @Excel(name = "快递公司编号")
+    private String deliveryCode;
+
+    /** 快递名称 */
+//    @Excel(name = "快递名称")
+    private String deliveryName;
+
+    /** 快递单号 */
+//    @Excel(name = "快递单号")
+    private String deliverySn;
+
+    /** 是否删除 */
+//    @Excel(name = "是否删除")
+    private String isDel;
+
+    /** 成本价 */
+//    @Excel(name = "成本价")
+    private BigDecimal costPrice;
+
+    /** 核销码 */
+//    @Excel(name = "核销码")
+    private String verifyCode;
+
+    /** 配送方式 1=快递 ,2=门店自提 */
+//    @Excel(name = "配送方式 1=快递 ,2=门店自提")
+    private Integer shippingType;
+
+    /** 支付渠道(1微信小程序) */
+//    @Excel(name = "支付渠道(1微信小程序)")
+    private String isChannel;
+
+    /** $column.columnComment */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "支付渠道(1微信小程序)", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date finishTime;
+
+    // 完成时间-开始
+    private String finishTimeStart;
+    // 完成时间-结束
+    private String finishTimeEnd;
+
+    /** 发货时间 */
+//    @Excel(name = "发货时间")
+    private String deliveryTime;
+
+    /** 推广佣金 */
+//    @Excel(name = "推广佣金")
+    private BigDecimal tuiMoney;
+
+    /** 推广佣金状态 1已发放 0待发放 */
+//    @Excel(name = "推广佣金状态 1已发放 0待发放")
+    private Integer tuiMoneyStatus;
+
+    /** 上级推荐人ID */
+//    @Excel(name = "上级推荐人ID")
+    private Long tuiUserId;
+
+    /** orderItem字符串 */
+//    @Excel(name = "orderItem字符串")
+    private String itemJson;
+
+    /** 优惠金额 */
+//    @Excel(name = "优惠金额")
+    private BigDecimal discountMoney;
+
+    /** $column.columnComment */
+//    @Excel(name = "优惠金额")
+    private Long userCouponId;
+
+    /** 公司id */
+//    @Excel(name = "公司id")
+    private Long companyId;
+
+
+
+    /** 仓库代码 */
+//    @Excel(name = "仓库代码")
+    private String storeHouseCode;
+
+    /** 扩展订单ID */
+//    @Excel(name = "扩展订单ID")
+    private String extendOrderId;
+
+
+    /** 剩余金额 */
+//    @Excel(name = "剩余金额")
+    private BigDecimal payRemain;
+
+    /** 物流状态 */
+//    @Excel(name = "物流状态")
+    private Integer deliveryStatus;
+
+    /** 物流结算状态 */
+//    @Excel(name = "物流结算状态")
+    private Integer deliveryPayStatus;
+
+    /** $column.columnComment */
+//    @Excel(name = "物流结算状态")
+    private String deliveryPayTime;
+
+    /** 物流跟踪状态 */
+//    @Excel(name = "物流跟踪状态")
+    private String deliveryType;
+
+    /** 物流结算金额 */
+//    @Excel(name = "物流结算金额")
+    private BigDecimal deliveryPayMoney;
+
+    /** 回单导入时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "回单导入时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date deliveryImportTime;
+
+    /** 发货时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "发货时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date deliverySendTime;
+
+    /** 是否可售后 */
+//    @Excel(name = "是否可售后")
+    private Integer isAfterSales;
+
+    /** 部门id */
+//    @Excel(name = "部门id")
+    private Long deptId;
+
+    /** 渠道 */
+//    @Excel(name = "渠道")
+    private String channel;
+
+    /** 订单来源 */
+//    @Excel(name = "订单来源")
+    private Long source;
+
+    /** 开票金额 */
+//    @Excel(name = "开票金额")
+    private BigDecimal billPrice;
+
+    /** 邮费 */
+//    @Excel(name = "邮费")
+    private BigDecimal totalPostage;
+
+    /** 支付邮费 */
+//    @Excel(name = "支付邮费")
+    private BigDecimal payPostage;
+
+    /** 消费赚取积分 */
+//    @Excel(name = "消费赚取积分")
+    private BigDecimal gainIntegral;
+
+    /** 使用积分 */
+//    @Excel(name = "使用积分")
+    private BigDecimal useIntegral;
+
+    /** 实际支付积分 */
+//    @Excel(name = "实际支付积分")
+    private BigDecimal payIntegral;
+
+    /** 给用户退了多少积分 */
+//    @Excel(name = "给用户退了多少积分")
+    private BigDecimal backIntegral;
+
+    /** 是否改价 */
+//    @Excel(name = "是否改价")
+    private Integer isEditMoney;
+
+    /** 创建时间 (下单时间)*/
+    @Excel(name = "下单时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 更新时间*/
+//    @Excel(name = "更新时间")
+    private Date updateTime;
+
+    /** 备注*/
+//    @Excel(name = "备注")
+    private String remark;
+
+    /** 备注*/
+//    @Excel(name = "订单名称")
+    private String orderName;
+
+    /** 备注*/
+//    @Excel(name = "订单名称")
+    private String productIntroduce;
+
+    /** 备注*/
+//    @Excel(name = "订单key")
+    private String orderKey;
+
+    /** 城市Id*/
+    private Long cityId;
+
+    private String companyName;
+    private String companyUserName;
+
+    private Long customerId;
+    private Long couponUserId;
+    private Long recordId;
+
+    /** 优惠券金额 */
+    private BigDecimal couponPrice;
+
+    // ========== 新增字段 ==========
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    // 筛选条件字段
+    private String productNameQuery;
+    private String productSpecQuery;
+    private String supplierNameQuery;
+    private String createTimeStart;
+    private String createTimeEnd;
+
+    /** 银行交易流水号 */
+    @Excel(name = "银行交易流水号")
+    private String bankTransactionId;
+
+
+}

+ 7 - 2
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java

@@ -404,8 +404,8 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
     @Select("SELECT id,external_user_id,name,avatar,remark,description,fs_user_id FROM  qw_external_contact " +
             " WHERE user_id = #{map.userId}   " +
             "AND corp_id =#{map.corpId} " +
-            "AND external_user_id = #{map.externalUserId}" +
-            "AND `status` != 4 " +
+            "AND external_user_id = #{map.externalUserId} " +
+            "AND `status` != 4 AND `status` != 5 " +
             "ORDER BY id desc " +
             "limit 1 ")
     QwExternalContact getQwExternalContactDetails(@Param("map")QwExternalContactHParam param);
@@ -539,4 +539,9 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
     QwExternalContact selectQwUserListVOByQwUserIdAndCorpIdAndExternalUserId(ExternalContactParam externalContactParam);
 
     void updateJoinGroup(List<Long> longs);
+
+
+    List<QwExternalContact> getGroupChatUserByChatIdAndUserName(@Param("userId")String userId,@Param("userName")String userName,@Param("corpId") String corpId,@Param("chatId") String chatId);
+    @Select("select * from qw_external_contact where unionid = #{unionID} order by create_time asc limit 1 ")
+    QwExternalContact selectQwExternalByUnionID(String unionId);
 }

+ 9 - 0
fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java

@@ -80,6 +80,9 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
         /** 小程序page路径 */
         private String miniprogramPage;
 
+        /** 直播间ID */
+        private String liveId;
+
         //链接标题
         private String linkTitle;
         //链接描述
@@ -116,6 +119,12 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
 
         //课程id
         private Long courseId;
+
+        //封面图片地址 app用的参数
+        private String courseUrl;
+
+        //app显示标题 app用的参数
+        private String title;
         @Override
         public Setting clone() {
             try {

+ 11 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopTempRulesService.java

@@ -1,12 +1,15 @@
 package com.fs.sop.service;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.enums.DataSourceType;
 import com.fs.sop.domain.QwSopTempDay;
 import com.fs.sop.domain.QwSopTempRules;
 
+import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 /**
  * sop任务模板规则Service接口
@@ -88,4 +91,12 @@ public interface IQwSopTempRulesService extends IService<QwSopTempRules>{
     List<QwSopTempRules> listById(List<Long> rulesIds);
 
     void updateSiFenTemp();
+
+    List<QwSopTempRules> listByCourseId(Long courseId);
+
+    void removeByTempIds(Collection<String> tempIds);
+
+    void removeByWrapper(LambdaQueryWrapper<QwSopTempRules> wrapper);
+
+    List<QwSopTempRules> selectListByDayId(Long id);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/sop/service/ISopUserLogsService.java

@@ -66,4 +66,6 @@ public interface ISopUserLogsService {
     public List<SopUserLogs> meetsTherestoreByIsDaysNotStudy(int offset,int pageSize,Integer notStudyDays);
 
     void replaceUser(ReplaceUserDto vo);
+
+    R getShortLink(String id, String sopId, String appId);
 }

+ 39 - 19
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempRulesServiceImpl.java

@@ -1,6 +1,7 @@
 package com.fs.sop.service.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.annotation.DataSource;
@@ -25,6 +26,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -59,8 +61,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return sop任务模板规则
      */
     @Override
-    public QwSopTempRules selectQwSopTempRulesById(String id)
-    {
+    public QwSopTempRules selectQwSopTempRulesById(String id) {
         return baseMapper.selectQwSopTempRulesById(id);
     }
 
@@ -71,8 +72,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return sop任务模板规则
      */
     @Override
-    public List<QwSopTempRules> selectQwSopTempRulesList(QwSopTempRules qwSopTempRules)
-    {
+    public List<QwSopTempRules> selectQwSopTempRulesList(QwSopTempRules qwSopTempRules) {
         return baseMapper.selectQwSopTempRulesList(qwSopTempRules);
     }
 
@@ -83,8 +83,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int insertQwSopTempRules(QwSopTempRules qwSopTempRules)
-    {
+    public int insertQwSopTempRules(QwSopTempRules qwSopTempRules) {
         return baseMapper.insertQwSopTempRules(qwSopTempRules);
     }
 
@@ -95,8 +94,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int updateQwSopTempRules(QwSopTempRules qwSopTempRules)
-    {
+    public int updateQwSopTempRules(QwSopTempRules qwSopTempRules) {
         return baseMapper.updateQwSopTempRules(qwSopTempRules);
     }
 
@@ -107,8 +105,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int deleteQwSopTempRulesByIds(String[] ids)
-    {
+    public int deleteQwSopTempRulesByIds(String[] ids) {
         return baseMapper.deleteQwSopTempRulesByIds(ids);
     }
 
@@ -119,8 +116,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int deleteQwSopTempRulesById(String id)
-    {
+    public int deleteQwSopTempRulesById(String id) {
         return baseMapper.deleteQwSopTempRulesById(id);
     }
 
@@ -140,7 +136,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
     @DataSource(DataSourceType.SOP)
     public List<QwSopTempRules> listByTempId(String id) {
         List<QwSopTempDay> dayList = qwSopTempDayService.list(new QueryWrapper<QwSopTempDay>().eq("temp_id", id).orderByAsc("day_num"));
-        if(dayList.isEmpty()) return Collections.emptyList();
+        if (dayList.isEmpty()) return Collections.emptyList();
         Map<Long, Integer> collect = dayList.stream().collect(Collectors.toMap(QwSopTempDay::getId, QwSopTempDay::getDayNum));
         List<QwSopTempRules> rulesList = list(new QueryWrapper<QwSopTempRules>().in("day_id", PubFun.listToNewList(dayList, QwSopTempDay::getId)));
         rulesList.forEach(r -> {
@@ -148,7 +144,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
         });
         List<QwSopTempContent> ts = qwSopTempContentService.list(new QueryWrapper<QwSopTempContent>().in("rules_id", PubFun.listToNewList(rulesList, QwSopTempRules::getId)));
         Map<Long, List<QwSopTempContent>> map = PubFun.listToMapByGroupList(ts, QwSopTempContent::getRulesId);
-        rulesList.stream().filter( e -> map.containsKey(e.getId())).forEach(e -> e.setSettingList(map.get(e.getId())));
+        rulesList.stream().filter(e -> map.containsKey(e.getId())).forEach(e -> e.setSettingList(map.get(e.getId())));
         return rulesList;
     }
 
@@ -202,9 +198,9 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
     public void updateRulesDayNumIsNull() {
         List<QwSopTempRules> rules = qwSopTempRulesMapper.rulesNull();
         log.info("时间为空的有:{}", rules.size());
-        for (QwSopTempRules rule : rules){
+        for (QwSopTempRules rule : rules) {
             QwSopTempDay day = dayMapper.info(rule.getDayId());
-            if (day!=null){
+            if (day != null) {
                 QwSopTempRules rules1 = new QwSopTempRules();
                 rules1.setDayNum(day.getDayNum());
                 rules1.setId(rule.getId());
@@ -226,14 +222,14 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
     @Override
     public void updateSiFenTemp() {
         List<QwSopTempContentVO> contents = contentMapper.updateSiFenTemp();
-        for(QwSopTempContentVO content : contents){
-            if (content.getVideoId()==null){
+        for (QwSopTempContentVO content : contents) {
+            if (content.getVideoId() == null) {
                 continue;
             }
             QwSopTempContent content1 = new QwSopTempContent();
             FsUserCourseVideo video = videoMapper.selectFsUserCourseVideoByVideoId(content.getVideoId());
             QwSopTempSetting.Content.Setting settingMap = new QwSopTempSetting.Content.Setting();
-            QwSopTempSetting.Content.Setting setting = JSON.parseObject(content.getContent(),QwSopTempSetting.Content.Setting.class);
+            QwSopTempSetting.Content.Setting setting = JSON.parseObject(content.getContent(), QwSopTempSetting.Content.Setting.class);
             settingMap.setContentType("4");
             settingMap.setMiniprogramAppid("wx73f85f8d62769119");
             settingMap.setMiniprogramPicUrl(setting.getLinkImageUrl());
@@ -245,4 +241,28 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
             contentMapper.updateQwSopTempContent(content1);
         }
     }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public List<QwSopTempRules> listByCourseId(Long courseId) {
+        return list(new QueryWrapper<QwSopTempRules>().eq("course_id", courseId));
+    }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public void removeByTempIds(Collection<String> tempIds) {
+        this.remove(new QueryWrapper<QwSopTempRules>().in("temp_id", tempIds));
+    }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public List<QwSopTempRules> selectListByDayId(Long id) {
+        return list(new QueryWrapper<QwSopTempRules>().eq("day_id", id));
+    }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public void removeByWrapper(LambdaQueryWrapper<QwSopTempRules> wrapper) {
+        this.remove(wrapper);
+    }
 }

+ 51 - 2
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.common.config.FSSysConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
@@ -663,6 +664,15 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             case "7":
                                 createVoiceUrl(st, companyUserId, qwSop);
                                 break;
+                            //直播小程序单独
+                            case "12":
+                                String sortLiveLink = "/pages_course/living?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + companyUserId + "&liveId=" + st.getLiveId();
+                                st.setContentType("4");
+                                String js = configService.selectConfigByKey("his.config");
+                                FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
+                                st.setMiniprogramAppid(sysConfig.getAppId());
+                                st.setMiniprogramPage(sortLiveLink);
+                                break;
                         }
                     }
                     setting.setSetting(list);
@@ -797,6 +807,15 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                     createVoiceUrl(st, String.valueOf(qwUser.getCompanyUserId()), qwSop);
                                 }
                                 break;
+                            //直播小程序单独
+                            case "12":
+                                String sortLiveLink = "/pages_course/living?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + qwUser.getCompanyUserId() + "&liveId=" + st.getLiveId();
+                                st.setContentType("4");
+                                String js = configService.selectConfigByKey("his.config");
+                                FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
+                                st.setMiniprogramAppid(sysConfig.getAppId());
+                                st.setMiniprogramPage(sortLiveLink);
+                                break;
                         }
                     }
                     setting.setSetting(list);
@@ -991,6 +1010,15 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
                             }
 
+                            break;
+                        //直播小程序单独
+                        case "12":
+                            String sortLiveLink = "/pages_course/living?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + qwUser.getCompanyUserId() + "&liveId=" + st.getLiveId();
+                            st.setContentType("4");
+                            String js = configService.selectConfigByKey("his.config");
+                            FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
+                            st.setMiniprogramAppid(sysConfig.getAppId());
+                            st.setMiniprogramPage(sortLiveLink);
                             break;
                         default:
                             break;
@@ -1442,6 +1470,27 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                         st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
                     }
 
+                    break;
+                //直播小程序单独
+                case "12":
+                    String sortLiveLink;
+                    sortLiveLink = "/pages_course/living?companyId=" + companyId + "&companyUserId=" + companyUserId + "&liveId=" + st.getLiveId();
+
+
+                    String miniprogramLiveTitle = st.getMiniprogramTitle();
+                    int maxLiveLength = 17;
+                    st.setMiniprogramTitle(miniprogramLiveTitle.length() > maxLiveLength ? miniprogramLiveTitle.substring(0, maxLiveLength) + "..." : miniprogramLiveTitle);
+                    String json = configService.selectConfigByKey("his.config");
+                    FSSysConfig sysConfig= JSON.parseObject(json,FSSysConfig.class);
+                    st.setMiniprogramAppid(sysConfig.getAppId());
+                    st.setMiniprogramPage(sortLiveLink);
+                    st.setContentType("4");
+                    try {
+                        st.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(st.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : st.getMiniprogramPicUrl());
+                    } catch (Exception e) {
+                        log.error("赋值-小程序封面地址失败-" + e);
+                    }
+
                     break;
                 default:
                     break;
@@ -1498,7 +1547,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     }
 
     //插入观看记录
-    private void addWatchLogIfNeeded(String sopId, Integer videoId, Integer courseId,
+    public void addWatchLogIfNeeded(String sopId, Integer videoId, Integer courseId,
                                      Long fsUserId, String qwUserId, String companyUserId,
                                      String companyId, Long externalId, String startTime,Date createTime) {
 
@@ -1554,7 +1603,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return sortLink.replaceAll("^[\\s\\u2005]+", "");
     }
 
-    private String createLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
+    public String createLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
                                      Integer courseId, Integer videoId, Long qwUserId,
                                      String companyUserId, String companyId, Long externalId,CourseConfig config, String chatId) {
 

+ 146 - 90
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsServiceImpl.java

@@ -8,6 +8,7 @@ import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.param.FsCourseLinkCreateParam;
@@ -16,18 +17,17 @@ import com.fs.crm.domain.CrmMsg;
 import com.fs.crm.mapper.CrmMsgMapper;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwGroupChat;
+import com.fs.qw.domain.QwGroupChatUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.qw.mapper.QwGroupChatMapper;
+import com.fs.qw.mapper.QwGroupChatUserMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.SopUserLogsVO;
 import com.fs.qw.service.IQwGroupChatService;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.*;
-import com.fs.qwApi.service.QwApiService;
-import com.fs.sop.domain.QwSop;
-import com.fs.sop.domain.QwSopLogs;
-import com.fs.sop.domain.SopUserLogs;
-import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.sop.domain.*;
 import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.mapper.SopUserLogsMapper;
@@ -35,9 +35,7 @@ import com.fs.sop.params.QwRatingConfig;
 import com.fs.sop.params.SopUserLogsList;
 import com.fs.sop.params.SopUserLogsParam;
 import com.fs.sop.params.SopUserLogsParamByDate;
-import com.fs.sop.service.IQwSopLogsService;
-import com.fs.sop.service.IQwSopTempDayService;
-import com.fs.sop.service.ISopUserLogsService;
+import com.fs.sop.service.*;
 import com.fs.sop.vo.QwRatingVO;
 import com.fs.sop.vo.ReplaceUserDto;
 import com.fs.sop.vo.SopUserLogsInfoVo;
@@ -69,7 +67,7 @@ import java.util.stream.Collectors;
 
 @Slf4j
 @Service
-public class SopUserLogsServiceImpl  implements ISopUserLogsService {
+public class SopUserLogsServiceImpl implements ISopUserLogsService {
 
     private static final Logger logger = LoggerFactory.getLogger(SopUserLogsServiceImpl.class);
 
@@ -85,7 +83,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
     @Autowired
     private QwSopMapper sopMapper;
     @Autowired
-    private QwApiService qwApiService;
+    private IFsCourseLinkService linkService;
 
     @Autowired
     private RedisCache redisCache;
@@ -99,6 +97,17 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
     @Autowired
     private IQwSopTempDayService qwSopTempDayService;
 
+    @Autowired
+    private SopUserLogsInfoServiceImpl sopUserLogsInfoService;
+    @Autowired
+    private IQwSopTempService sopTempService;
+    @Autowired
+    private IQwSopTempRulesService qwSopTempRulesService;
+    @Autowired
+    private QwGroupChatUserMapper qwGroupChatUserMapper;
+    @Autowired
+    private QwGroupChatMapper qwGroupChatMapper;
+
 
     @Autowired
     private ISysConfigService configService;
@@ -152,6 +161,57 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         sopUserLogsMapper.replaceUser(vo);
     }
 
+    @Override
+    public R getShortLink(String id, String sopId, String appId) {
+        QwSop qwSop = sopMapper.selectQwSopById(sopId);
+        QwSopTemp qwSopTemp = sopTempService.selectQwSopTempById(qwSop.getTempId());
+        SopUserLogs sopUserLogs = sopUserLogsMapper.selectSopUserLogsById(id);
+        String[] userKey = sopUserLogs.getUserId().split("\\|");
+        String qwUserId = userKey[0].trim();
+        QwUser qwUser = qwUserMapper.selectById(qwUserId);
+        Optional<QwSopTempDay> dayOptional = qwSopTemp.getList().stream().filter(e -> Objects.equals(e.getDayNum(), sopUserLogs.getCountDays())).findFirst();
+        if (dayOptional.isPresent()) {
+            List<QwSopTempRules> rulesList = qwSopTempRulesService.selectListByDayId(dayOptional.get().getId());
+            Optional<QwSopTempRules> rulesOptional = rulesList.stream().filter(r -> r.getCourseId() != null).findFirst();
+            if (rulesOptional.isPresent()) {
+                QwSopTempRules rules = rulesOptional.get();
+                QwGroupChat groupChat = qwGroupChatMapper.selectQwGroupChatByChatId(sopUserLogs.getChatId());
+                List<QwGroupChatUser> groupUserList = qwGroupChatUserMapper.selectQwGroupChatUserByChatIds(new String[]{sopUserLogs.getChatId()});
+                List<String> groupChatUserIds = PubFun.listToNewList(groupUserList, QwGroupChatUser::getUserId);
+                if (!groupChatUserIds.isEmpty()) {
+                    List<GroupUserExternalVo> userList = qwExternalContactMapper.selectByGroupUser(groupChatUserIds);
+                    Map<String, List<GroupUserExternalVo>> userMap = PubFun.listToMapByGroupList(userList, GroupUserExternalVo::getExternalUserId);
+                    groupUserList.forEach(e -> {
+                        e.setUserList(userMap.getOrDefault(e.getUserId(), Collections.emptyList()));
+                    });
+                }
+                try {
+                    groupUserList.stream().filter(e -> e.getUserList() != null && !e.getUserList().isEmpty()).forEach(e -> {
+                        Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(e.getUserList(), GroupUserExternalVo::getUserId);
+                        GroupUserExternalVo vo = userMap.get(groupChat.getOwner());
+                        if (vo != null && vo.getId() != null) {
+                            sopUserLogsInfoService.addWatchLogIfNeeded(sopId, rules.getVideoId().intValue(), rules.getCourseId().intValue(), vo.getFsUserId(), qwUser.getId().toString(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), vo.getId(), sopUserLogs.getStartTime(), new Date());
+                        }
+                    });
+                } catch (Exception e) {
+                    log.error("群聊创建看课记录失败!", e);
+                }
+                QwSopCourseFinishTempSetting.Setting st = new QwSopCourseFinishTempSetting.Setting();
+                st.setExpiresDays(1);
+                String json = configService.selectConfigByKey("course.config");
+                CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+                String linkByMiniApp = sopUserLogsInfoService.createLinkByMiniApp(st, sopUserLogs.getCorpId(), new Date(), rules.getCourseId().intValue(), rules.getVideoId().intValue(),
+                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, sopUserLogs.getChatId());
+                if(StringUtils.isNotEmpty(linkByMiniApp)){
+                    linkByMiniApp = linkByMiniApp.replaceAll(".html", "");
+                }
+                String link = linkService.getGotoWxAppLink(linkByMiniApp, appId);
+                return R.ok().put("urlLink", link);
+            }
+        }
+        return R.error("系统错误❌");
+    }
+
     @Override
     public int deleteSopUserLogsBySopId(String sopId) {
         return sopUserLogsMapper.deleteSopUserLogsBySopId(sopId);
@@ -181,20 +241,20 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             //如果为空,则任务删除了 ,则全部营期删除
             if (ruleTimeVO == null) {
                 sopUserLogsMapper.deleteSopUserLogsBySopId(key);
-            }else if (ruleTimeVO.getStatus()==0){
+            } else if (ruleTimeVO.getStatus() == 0) {
                 SopUserLogs sopUserLogs = new SopUserLogs();
                 sopUserLogs.setSopId(key);
                 sopUserLogs.setStatus(2);
                 sopUserLogsMapper.updateSopUserLogsByStatus(sopUserLogs);
-            }else {
+            } else {
 
                 //如果模板停用了,也改这个营期记录
-                if (ruleTimeVO.getTempStatus().equals("0")){
+                if (ruleTimeVO.getTempStatus().equals("0")) {
                     SopUserLogs sopUserLogs = new SopUserLogs();
                     sopUserLogs.setSopId(key);
                     sopUserLogs.setStatus(2);
                     sopUserLogsMapper.updateSopUserLogsByStatus(sopUserLogs);
-                }else {
+                } else {
 
                     // 分组的 key
                     List<SopUserLogsVo> userLogsVos = entry.getValue(); // 分组对应的日志列表
@@ -202,24 +262,24 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
                     // 处理日志数据
                     userLogsVos.forEach(log -> {
 
-                            // 获取开始时间和间隔天数
-                            Date startTime = null; // 假设 startTime 是 java.util.Date 类型
-                            try {
-                                startTime = formatter.parse(log.getStartTime());
-                            } catch (ParseException e) {
-                                logger.error("selectSopUserLogsListByTime解析开始时间失败: {}", e.getMessage());
-                            }
+                        // 获取开始时间和间隔天数
+                        Date startTime = null; // 假设 startTime 是 java.util.Date 类型
+                        try {
+                            startTime = formatter.parse(log.getStartTime());
+                        } catch (ParseException e) {
+                            logger.error("selectSopUserLogsListByTime解析开始时间失败: {}", e.getMessage());
+                        }
 
-                            Integer tempGap = ruleTimeVO.getTempGap();
+                        Integer tempGap = ruleTimeVO.getTempGap();
 
-                            // 将 startTime 转换为 LocalDate
-                            LocalDate startLocalDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+                        // 将 startTime 转换为 LocalDate
+                        LocalDate startLocalDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
 
-                            // 计算当前时间距离开始时间的天数差
-                            long daysBetween = ChronoUnit.DAYS.between(startLocalDate, currentDate);
+                        // 计算当前时间距离开始时间的天数差
+                        long daysBetween = ChronoUnit.DAYS.between(startLocalDate, currentDate);
 
-                            // TODO 修改
-                            // 获取 QwSopTempSetting 内容
+                        // TODO 修改
+                        // 获取 QwSopTempSetting 内容
 //                            List<QwSopTempSetting> qwSopTempSettings = JSON.parseArray(ruleTimeVO.getTempSetting(), QwSopTempSetting.class);
 //
 //                            // 计算当前天数属于第几天,第一天就是 startLocalDate,后续递增
@@ -293,9 +353,6 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             }
 
 
-
-
-
         }
 
         // 遍历分组数据
@@ -454,7 +511,8 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
 //        }
     }
 
-    private void insertSopUserLogs(List<SopUserLogsInfo> list,SopUserLogsVo log,Date sendTime,QwSopRuleTimeVO ruleTimeVO,QwSopTempSetting.Content element) {
+    private void insertSopUserLogs(List<SopUserLogsInfo> list, SopUserLogsVo log, Date sendTime, QwSopRuleTimeVO
+            ruleTimeVO, QwSopTempSetting.Content element) {
 
         QwSopLogs sopLogs = new QwSopLogs();
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -574,7 +632,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
 
 
                             //如果要推短链-则必须要绑定了小程序-才会有观看记录
-                            if (sopLogs.getFsUserId() != null && sopLogs.getFsUserId()!= 0 ) {
+                            if (sopLogs.getFsUserId() != null && sopLogs.getFsUserId() != 0) {
 
                                 FsCourseWatchLog watchLog = new FsCourseWatchLog();
                                 watchLog.setUserId(sopLogs.getFsUserId());
@@ -643,9 +701,9 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         return resultSopUserLogsList(list);
     }
 
-    private List<SopUserLogsVO> resultSopUserLogsList( List<SopUserLogsVO> list){
+    private List<SopUserLogsVO> resultSopUserLogsList(List<SopUserLogsVO> list) {
         List<String> chatIdList = PubFun.listToNewList(list, SopUserLogsVO::getChatId);
-        if(!chatIdList.isEmpty()){
+        if (!chatIdList.isEmpty()) {
             List<QwGroupChat> qwGroupChatList = qwGroupChatService.selectQwGroupChatByChatIds(chatIdList.toArray(new String[0]));
             Map<String, QwGroupChat> groupChatMap = PubFun.listToMapByGroupObject(qwGroupChatList, QwGroupChat::getChatId);
             list.stream().filter(e -> groupChatMap.containsKey(e.getChatId())).forEach(e -> {
@@ -703,9 +761,9 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
                 // 获取名称
                 String names = voList.stream().peek(v -> {
                     // 标识那些是发送了,发送了到时候要更新状态不会查出数据进入此方法
-                    if(type == 0){
+                    if (type == 0) {
                         v.setMinIsSend(true);
-                    }else{
+                    } else {
                         v.setMaxIsSend(true);
                     }
                 }).map(SopUserLogsInfoVo::getExternalUserName).collect(Collectors.joining(","));
@@ -726,11 +784,11 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         // 打转换消息
         List<CrmMsg> maxList = toFun.apply(list, 1);
         // 不为空添加
-        if(!minList.isEmpty()){
+        if (!minList.isEmpty()) {
             msgList.addAll(minList);
         }
         // 不为空添加
-        if(!maxList.isEmpty()){
+        if (!maxList.isEmpty()) {
             msgList.addAll(maxList);
         }
         msgList.forEach(crmMsgMapper::insertCrmMsg);
@@ -756,8 +814,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
      * @return sopUserLogs
      */
     @Override
-    public SopUserLogs selectSopUserLogsById(String id)
-    {
+    public SopUserLogs selectSopUserLogsById(String id) {
         return sopUserLogsMapper.selectSopUserLogsById(id);
     }
 
@@ -768,14 +825,14 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         if (qwUser != null) {
             Long companyUserId = qwUser.getCompanyUserId();
             Long companyId = qwUser.getCompanyId();
-            if (companyUserId==null) {
+            if (companyUserId == null) {
                 return R.error("用户未绑定销售,请先绑定");
             }
-            if (companyId==null) {
+            if (companyId == null) {
                 return R.error("用户未绑定销售公司,请先绑定");
             }
 
-            param.setUserId(qwUser.getId()+"|"+companyUserId+"|"+companyId);
+            param.setUserId(qwUser.getId() + "|" + companyUserId + "|" + companyId);
             sopUserLogsMapper.updateSopUserLogsByCompanyInfo(param);
         }
 
@@ -789,26 +846,26 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
 
             Map<String, QwUser> qwUserMap = sopUserLogs.stream()
                     .collect(Collectors.toMap(
-                            item -> item.getCorpId() + "|" + item.getQwUserId()+"|"+item.getId(),
+                            item -> item.getCorpId() + "|" + item.getQwUserId() + "|" + item.getId(),
                             item -> Optional.ofNullable(qwUserMapper.selectQwUserByCorpIdAndUserId(item.getCorpId(), item.getQwUserId()))
                                     .orElse(new QwUser())
                     ));
             List<String> errorMessages = new ArrayList<>();
 
             sopUserLogs.forEach(item -> {
-                String key = item.getCorpId() + "|" + item.getQwUserId()+"|"+item.getId();
+                String key = item.getCorpId() + "|" + item.getQwUserId() + "|" + item.getId();
                 QwUser qwUser = qwUserMap.get(key);
 
-                if (qwUser != null && qwUser.getId()!=null) {
+                if (qwUser != null && qwUser.getId() != null) {
                     Long companyUserId = qwUser.getCompanyUserId();
                     Long companyId = qwUser.getCompanyId();
 
                     if (companyUserId == null) {
-                        errorMessages.add("用户 " + item.getQwUserId() +"|"+item.getCorpId()+ " 未绑定销售,请先绑定");
+                        errorMessages.add("用户 " + item.getQwUserId() + "|" + item.getCorpId() + " 未绑定销售,请先绑定");
                         return;
                     }
                     if (companyId == null) {
-                        errorMessages.add("用户 " + item.getQwUserId()+"|" +item.getCorpId()+ " 未绑定销售公司,请先绑定");
+                        errorMessages.add("用户 " + item.getQwUserId() + "|" + item.getCorpId() + " 未绑定销售公司,请先绑定");
                         return;
                     }
 
@@ -826,10 +883,10 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             });
 
             if (!errorMessages.isEmpty()) {
-                logger.error("定时处理 营期异常的数据 出错:"+String.join(";", errorMessages));
+                logger.error("定时处理 营期异常的数据 出错:" + String.join(";", errorMessages));
             }
-        }catch (Exception e){
-            logger.error("定时处理 营期异常的数据 出错2:"+e.getMessage());
+        } catch (Exception e) {
+            logger.error("定时处理 营期异常的数据 出错2:" + e.getMessage());
         }
 
 
@@ -842,21 +899,21 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         QwRatingConfig config = JSON.parseObject(json, QwRatingConfig.class);
 
         List<SopUserLogs> sopUserLogs = sopUserLogsMapper.meetsTheRatingByUserInfoBySopId(sopId);
-        sopUserLogs.stream().forEach(item->{
+        sopUserLogs.stream().forEach(item -> {
 
             Integer countDays = item.getCountDays();
 
-           Integer sopTemIdNum=redisCache.getCacheObject("sop-tempId:"+item.getSopTempId());
+            Integer sopTemIdNum = redisCache.getCacheObject("sop-tempId:" + item.getSopTempId());
 
-           if (sopTemIdNum==null){
-               sopTemIdNum= qwSopTempDayService.getDayNumByIdLimitOne(item.getSopTempId());
-               redisCache.setCacheObject("sop-tempId:"+item.getSopTempId(),sopTemIdNum,3, TimeUnit.HOURS);
-           }
+            if (sopTemIdNum == null) {
+                sopTemIdNum = qwSopTempDayService.getDayNumByIdLimitOne(item.getSopTempId());
+                redisCache.setCacheObject("sop-tempId:" + item.getSopTempId(), sopTemIdNum, 3, TimeUnit.HOURS);
+            }
 
 
             //如果当前营期的伦次中,模板天数不足。则不评级
-            if (sopTemIdNum< countDays){
-                logger.info("当前营期的伦次中,模板天数不足。不评级:"+item.getSopTempId()+"|sopId:"+item.getSopId());
+            if (sopTemIdNum < countDays) {
+                logger.info("当前营期的伦次中,模板天数不足。不评级:" + item.getSopTempId() + "|sopId:" + item.getSopId());
                 return;
             }
 
@@ -864,7 +921,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             List<SopUserLogsInfo> sopUserLogsInfosList = sopUserLogsInfoMapper.selectSopUserLogsInfoListBySopId(item.getSopId(), item.getId());
             if (sopUserLogsInfosList != null && !sopUserLogsInfosList.isEmpty()) {
 
-                List<QwExternalContact> batchQwExternalContact=new ArrayList<>();
+                List<QwExternalContact> batchQwExternalContact = new ArrayList<>();
 
                 sopUserLogsInfosList.forEach(logsInfo -> {
                     try {
@@ -875,8 +932,8 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
                                     .selectFsCourseWatchLogByExtIdRating(externalId, config.getLevelDay());
 
                             if (ratingVOS.isEmpty()) {
-                                log.error("没有看课记录不评级。则不评级:"+externalId);
-                                return ;
+                                log.error("没有看课记录不评级。则不评级:" + externalId);
+                                return;
                             }
 
                             int scoreLevel = getScoreLevel(ratingVOS, config);
@@ -894,17 +951,15 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
                             batchQwExternalContact.add(externalContact);
 
 
-
-
                         }
-                    }catch (Exception e){
+                    } catch (Exception e) {
                         logger.error("计算用户积分异常,用户id:{}", logsInfo, e);
                     }
                 });
 
                 batchUpdateQwExternalContact(batchQwExternalContact);
 
-            }else {
+            } else {
                 logger.error("当前营期没有客户-sopId:{},营期id:{}", item.getSopId(), item.getId());
             }
         });
@@ -915,10 +970,10 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
 
     @Override
     public R updateLogDate(UpdateSopUserLogDateVo vo) {
-        if(vo.getDate() == null){
+        if (vo.getDate() == null) {
             throw new BaseException("修改时间不能为空");
         }
-        if(vo.getIds() == null || vo.getIds().isEmpty()){
+        if (vo.getIds() == null || vo.getIds().isEmpty()) {
             throw new BaseException("营期ID不能为空");
         }
 //        sopUserLogsMapper.updateSopuserLogsDateById(vo);
@@ -948,16 +1003,17 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
 
         // 记录剔除的重复ID
         if (!duplicateIds.isEmpty()) {
-            log.error("根据sopId、qwUserId、corpId、startTime组合检查,剔除重复ID: {},时间:{}", duplicateIds,targetDateStr);
+            log.error("根据sopId、qwUserId、corpId、startTime组合检查,剔除重复ID: {},时间:{}", duplicateIds, targetDateStr);
         }
 
-        return  R.ok().put("data",duplicateIds);
+        return R.ok().put("data", duplicateIds);
     }
 
     /**
      * 检查是否存在相同组合的数据
      */
-    private boolean checkDuplicateCombination(SopUserLogs currentLog, List<SopUserLogs> allLogs, String targetDate) {
+    private boolean checkDuplicateCombination(SopUserLogs currentLog, List<SopUserLogs> allLogs, String
+            targetDate) {
         for (SopUserLogs log : allLogs) {
             // 跳过自身比较
             if (log.getId().equals(currentLog.getId())) {
@@ -1003,7 +1059,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             sopUserLogs.setStartTime(qwSop.getStartTime());
             sopUserLogs.setStatus(1);
             QwUserVO qwUserVO = qwUserMap.get(groupChat.getOwner());
-            if(qwUserVO != null){
+            if (qwUserVO != null) {
                 sopUserLogs.setUserId(qwUserVO.getId() + "|" + qwUserVO.getCompanyUserId() + "|" + qwUserVO.getCompanyId());
             }
             return sopUserLogs;
@@ -1013,7 +1069,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
 
     @Override
     public List<SopUserLogs> meetsTherestoreByIsDaysNotStudy(int offset, int pageSize, Integer notStudyDays) {
-        return sopUserLogsMapper.meetsTherestoreByIsDaysNotStudy(offset,pageSize,notStudyDays);
+        return sopUserLogsMapper.meetsTherestoreByIsDaysNotStudy(offset, pageSize, notStudyDays);
     }
 
     //批量更新
@@ -1030,7 +1086,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             // 直接使用批次数据进行批量更新,不需要额外的 List
             try {
                 qwExternalContactMapper.batchUpdateQwExternalContact(batchList);
-                logger.info("成功更新了评级批次数据,起始索引为:{},数量:{} ", i,batchList.size());
+                logger.info("成功更新了评级批次数据,起始索引为:{},数量:{} ", i, batchList.size());
             } catch (Exception e) {
                 // 记录异常日志,方便后续排查问题
                 logger.error("批量更新数据时发生异常,处理的批次起始索引为: " + i, e);
@@ -1041,7 +1097,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
     //评级
     public int getScoreLevel(List<QwRatingVO> qwRatingVOS, QwRatingConfig config) {
 
-        AtomicDouble watchCount= new AtomicDouble();
+        AtomicDouble watchCount = new AtomicDouble();
 
         qwRatingVOS.forEach(vo -> {
             // 计算 watchDuration 除以 allDuration,并保留2位小数,四舍五入
@@ -1080,20 +1136,21 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
             throw new IllegalArgumentException("分数不在任何等级范围内: " + score);
         }
     }
+
     //升降等级
-    public int getLevelUpFall(int scoreLevel,int levelUpFall){
+    public int getLevelUpFall(int scoreLevel, int levelUpFall) {
 
         if (scoreLevel > levelUpFall) {
-            return  1;//升级
-        }else if (scoreLevel < levelUpFall) {
-            return  2;//降级
-        }else {
-            return  3;//不变
+            return 1;//升级
+        } else if (scoreLevel < levelUpFall) {
+            return 2;//降级
+        } else {
+            return 3;//不变
         }
     }
 
     //计算最晚看课时间
-    public int getLatestTime(List<QwRatingVO> qwRatingVOS){
+    public int getLatestTime(List<QwRatingVO> qwRatingVOS) {
 
         // 定义日期时间格式
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@@ -1102,21 +1159,21 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         // 用于存储提取出的时分
         List<String> timeOnlyList = new ArrayList<>();
 
-        qwRatingVOS.forEach(vos->{
+        qwRatingVOS.forEach(vos -> {
 
             String finishTime = vos.getFinishTime();
 
-            if (!StringUtil.strIsNullOrEmpty(finishTime)){
+            if (!StringUtil.strIsNullOrEmpty(finishTime)) {
                 LocalTime localTime = LocalTime.parse(finishTime, formatter);
                 String formattedTime = localTime.format(outputFormatter);
                 timeOnlyList.add(formattedTime);
             }
 
         });
-        String latestTime=null;
-        if (!timeOnlyList.isEmpty()){
-            latestTime  = Collections.max(timeOnlyList);
-        }else {
+        String latestTime = null;
+        if (!timeOnlyList.isEmpty()) {
+            latestTime = Collections.max(timeOnlyList);
+        } else {
             latestTime = "0";
         }
 
@@ -1125,5 +1182,4 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
     }
 
 
-
 }

+ 390 - 1
fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml

@@ -214,6 +214,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="orderCode != null and orderCode != ''">order_code,</if>
             <if test="userId != null and userId != ''">user_id,</if>
             <if test="realName != null">real_name,</if>
+            <if test="userName != null">user_name,</if>
             <if test="userPhone != null">user_phone,</if>
             <if test="userAddress != null">user_address,</if>
             <if test="cartId != null">cart_id,</if>
@@ -285,6 +286,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="orderCode != null and orderCode != ''">#{orderCode},</if>
             <if test="userId != null and userId != ''">#{userId},</if>
             <if test="realName != null">#{realName},</if>
+            <if test="userName != null">#{userName},</if>
             <if test="userPhone != null">#{userPhone},</if>
             <if test="userAddress != null">#{userAddress},</if>
             <if test="cartId != null">#{cartId},</if>
@@ -360,6 +362,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="orderCode != null and orderCode != ''">order_code = #{orderCode},</if>
             <if test="userId != null and userId != ''">user_id = #{userId},</if>
             <if test="realName != null">real_name = #{realName},</if>
+            <if test="userName != null">user_name = #{userName},</if>
             <if test="userPhone != null">user_phone = #{userPhone},</if>
             <if test="userAddress != null">user_address = #{userAddress},</if>
             <if test="cartId != null">cart_id = #{cartId},</if>
@@ -479,7 +482,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectLiveOrderListVO" resultType="com.fs.live.vo.LiveOrderVO">
 
     select o.*,u.phone,u.register_code,u.register_date,u.source, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber
-    , csc.name miniProgramName
+    , csc.name miniProgramName, sp_latest.bank_transaction_id as bankTransactionId
     from live_order o
     left join fs_user u on o.user_id=u.user_id
     left join company c on c.company_id=o.company_id
@@ -513,6 +516,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="maps.orderCode != null and  maps.orderCode !=''">
             and o.order_code like CONCAT('%',#{maps.orderCode},'%')
         </if>
+        <if test="maps.bankTransactionId != null and  maps.bankTransactionId !=''">
+            and sp_latest.bank_transaction_id like CONCAT('%',#{maps.bankTransactionId},'%')
+        </if>
         <if test="maps.isPayRemain != null">
             and o.is_pay_remain =#{maps.isPayRemain}
         </if>
@@ -528,6 +534,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="maps.realName != null and  maps.realName !=''">
             and o.user_name like CONCAT('%',#{maps.realName},'%')
         </if>
+        <if test="maps.userName != null and  maps.userName !=''">
+            and o.user_name like CONCAT('%',#{maps.userName},'%')
+        </if>
         <if test="maps.phone != null and  maps.phone !=''">
             and u.phone like CONCAT('%',#{maps.phone},'%')
         </if>
@@ -687,6 +696,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="maps.realName != null and  maps.realName !=''">
                 and o.user_name like CONCAT('%',#{maps.realName},'%')
             </if>
+            <if test="maps.userName != null and  maps.userName !=''">
+                and o.user_name like CONCAT('%',#{maps.userName},'%')
+            </if>
             <if test="maps.phone != null and  maps.phone !=''">
                 and u.phone like CONCAT('%',#{maps.phone},'%')
             </if>
@@ -828,6 +840,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="maps.realName != null and  maps.realName !=''">
                 and o.user_name like CONCAT('%',#{maps.realName},'%')
             </if>
+            <if test="maps.userName != null and  maps.userName !=''">
+                and o.user_name like CONCAT('%',#{maps.userName},'%')
+            </if>
             <if test="maps.phone != null and  maps.phone !=''">
                 and u.phone like CONCAT('%',#{maps.phone},'%')
             </if>
@@ -917,4 +932,378 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         ${maps.params.dataScope} GROUP BY sp.product_id
         ) AS t
     </select>
+
+    <!-- 查询订单列表Zm -->
+    <select id="selectLiveOrderListZm" parameterType="LiveOrder" resultType="com.fs.live.vo.LiveOrderVoZm">
+        SELECT
+            o.order_id,
+            o.live_id,
+            o.store_id,
+            o.order_code,
+            o.user_id,
+            o.user_name,
+            o.user_phone,
+            o.user_address,
+            o.cart_id,
+            o.total_num,
+            o.total_price,
+            o.pay_price,
+            o.is_pay,
+            o.pay_time,
+            o.pay_type,
+            o.pay_money,
+            o.pay_delivery,
+            o.create_time,
+            o.update_time,
+            o.status,
+            o.refund_status,
+            o.refund_img,
+            o.refund_explain,
+            o.refund_time,
+            o.refund_reason,
+            o.refund_money,
+            o.delivery_code,
+            o.delivery_name,
+            o.delivery_sn,
+            o.remark,
+            o.is_del,
+            o.cost_price,
+            o.company_id,
+            o.company_user_id,
+            o.product_id,
+            o.customer_id,
+            o.coupon_price,
+            o.cancel_reason,
+
+
+            cu.nick_name AS companyUserNickName,
+            cu.phonenumber AS companyUserPhone,
+            cu.create_time AS companyUserCreateTime,
+
+
+            u.user_code AS userCode,
+            u.level AS userLevel,
+            u.nick_name AS nickName,
+            u.phone AS userBindPhone,
+            u.order_count AS totalOrderCount,
+            u.total_amount AS totalOrderAmount,
+            u.status AS userStatus,
+            u.update_time AS latestBindTime,
+
+
+            p.product_name AS productName,
+            p.cost AS costPrice,
+            p.price AS price,
+            p.cost AS cost,
+            p.prescribe_spec AS productSpec,
+            p.prescribe_factory AS supplierName,
+
+
+            s.store_name AS storeName,
+            s.store_id AS storeId,
+
+
+            GROUP_CONCAT(DISTINCT spavs.bar_code SEPARATOR ',') AS bar_codes,
+            spcs.cate_name,
+
+            lop.bank_transaction_id AS bankTransactionId
+
+        FROM
+            live_order o
+            LEFT JOIN fs_user u ON o.user_id = u.user_id
+            LEFT JOIN company_user cu ON o.company_user_id = cu.user_id
+            LEFT JOIN fs_store_product_scrm p ON o.product_id = p.product_id
+            LEFT JOIN fs_store_scrm s ON p.store_id = s.store_id
+            LEFT JOIN fs_store_product_attr_value_scrm spavs ON p.product_id = spavs.product_id
+            LEFT JOIN fs_store_product_category_scrm spcs ON p.cate_id = spcs.cate_id
+            LEFT JOIN (
+                SELECT
+                    sp.*,
+                    ROW_NUMBER() OVER (PARTITION BY sp.business_code ORDER BY sp.create_time DESC) as rn
+                FROM live_order_payment sp
+                WHERE sp.business_code IS NOT NULL
+            ) lop ON lop.business_code = o.order_code AND lop.rn = 1
+
+        <where>
+            o.is_del = 0 and p.product_id IS NOT NULL
+            <if test="orderId != null">
+                AND o.order_id = #{orderId}
+            </if>
+            <if test="liveId != null">
+                AND o.live_id = #{liveId}
+            </if>
+            <if test="storeId != null">
+                AND o.store_id = #{storeId}
+            </if>
+            <if test="orderCode != null and orderCode != ''">
+                AND o.order_code LIKE CONCAT('%', #{orderCode}, '%')
+            </if>
+            <if test="userId != null and userId != ''">
+                AND o.user_id = #{userId}
+            </if>
+            <if test="status != null">
+                AND o.status = #{status}
+            </if>
+            <if test="companyId != null">
+                AND o.company_id = #{companyId}
+            </if>
+            <if test="totalNum != null">
+                AND o.total_num = #{totalNum}
+            </if>
+            <if test="price != null">
+                AND p.price = #{price}
+            </if>
+            <if test="cost != null">
+                AND p.cost = #{cost}
+            </if>
+            <if test="companyUserId != null">
+                AND o.company_user_id = #{companyUserId}
+            </if>
+            <if test="productId != null">
+                AND o.product_id = #{productId}
+            </if>
+            <!-- 新增筛选条件 -->
+            <if test="productName != null and productName != ''">
+                AND p.product_name LIKE CONCAT('%', #{productName}, '%')
+            </if>
+            <if test="productSpec != null and productSpec != ''">
+                AND p.prescribe_spec LIKE CONCAT('%', #{productSpec}, '%')
+            </if>
+            <if test="storeId != null and storeId != ''">
+                AND p.store_id = #{storeId}
+            </if>
+            <if test="userAddress != null and userAddress != ''">
+                AND o.user_address LIKE CONCAT('%', #{userAddress}, '%')
+            </if>
+            <if test="userName != null and userName != ''">
+                AND o.user_name LIKE CONCAT('%', #{userName}, '%')
+            </if>
+            <if test="createTimeStart != null ">
+                AND o.create_time &gt;= #{createTimeStart}
+            </if>
+            <if test="createTimeEnd != null ">
+                AND o.create_time &lt;= #{createTimeEnd}
+            </if>
+            <if test="payStartTime != null ">
+                AND o.pay_time &gt;= #{payStartTime}
+            </if>
+            <if test="payEndTime != null ">
+                AND o.pay_time &lt;= #{payEndTime}
+            </if>
+            <if test="userPhone != null and userPhone != ''">
+                AND o.user_phone = #{userPhone}
+            </if>
+        </where>
+        GROUP BY o.order_id
+        ORDER BY o.create_time DESC
+    </select>
+
+    <select id="getUnsettledOrder" resultType="com.fs.live.domain.LiveOrder">
+        SELECT
+            sos.*,
+            sps.bank_transaction_id
+        FROM
+            live_order sos
+                INNER JOIN live_order_payment sps ON sos.id = sps.order_id
+        WHERE
+            sos.is_del = 0 and
+            sos.is_pay = 1
+          AND sps.business_type = 2
+          AND sos.`status` = 2
+          AND sps.`status`=1
+          AND DATEDIFF(
+                      NOW(),
+                      sos.delivery_send_time
+              ) >= 3
+    </select>
+
+    <select id="getDeliveryNote" resultType="com.fs.live.vo.LiveOrderDeliveryNoteExportVO">
+        SELECT
+        CONCAT('AC', o.order_id) AS orderNumber,
+        o.user_name AS recipient,
+        o.user_phone AS recipientPhone,
+        o.user_address AS recipientAddress,
+        GROUP_CONCAT(
+        DISTINCT IFNULL(
+        CASE WHEN LENGTH(sps.product_name) > 0
+        THEN CONCAT(sps.product_name, '*', sois.num)
+        END, ''
+        )
+        SEPARATOR '+'
+        ) AS nameAndNumber,
+        sps.keyword
+        FROM
+        live_order o
+        LEFT JOIN live_order_item sois
+        ON sois.order_id = o.order_id
+        LEFT JOIN fs_store_product_scrm sps
+        ON sps.product_id = sois.product_id
+        LEFT JOIN fs_user u
+        ON o.user_id = u.user_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 (
+        SELECT DISTINCT business_id as order_id
+        FROM live_order_payment
+        WHERE  STATUS != 0
+        ) fp
+        ON o.order_id = fp.order_id
+        WHERE
+        o.is_del = 0 and
+        1 = 1
+        <if test="maps.orderCode != null and maps.orderCode != ''">
+            AND o.order_code LIKE CONCAT('%', #{maps.orderCode}, '%')
+        </if>
+        <if test="maps.userId != null">
+            AND o.user_id = #{maps.userId}
+        </if>
+        <if test="maps.deliveryId != null and maps.deliveryId != ''">
+            AND o.delivery_id = #{maps.deliveryId}
+        </if>
+        <if test="maps.nickname != null and maps.nickname != ''">
+            AND u.nickname LIKE CONCAT('%', #{maps.nickname}, '%')
+        </if>
+        <if test="maps.realName != null and maps.realName != ''">
+            AND o.user_name LIKE CONCAT('%', #{maps.realName}, '%')
+        </if>
+        <if test="maps.phone != null and maps.phone != ''">
+            AND u.phone LIKE CONCAT('%', #{maps.phone}, '%')
+        </if>
+        <if test="maps.userPhone != null and maps.userPhone != ''">
+            AND o.user_phone LIKE CONCAT('%', #{maps.userPhone}, '%')
+        </if>
+        <if test="maps.status == null">
+            AND o.status = 1
+        </if>
+        <if test="maps.status != null">
+            AND o.status = #{maps.status}
+        </if>
+        <if test="maps.deliveryStatus != null">
+            AND o.delivery_status = #{maps.deliveryStatus}
+        </if>
+        <if test="maps.deliveryPayStatus != null">
+            AND o.delivery_pay_status = #{maps.deliveryPayStatus}
+        </if>
+        <if test="maps.companyId != null">
+            AND o.company_id = #{maps.companyId}
+        </if>
+        <if test="maps.isHealth != null and maps.isHealth != ''">
+            AND o.company_id IS NULL
+        </if>
+        <if test="maps.notHealth != null and maps.notHealth != ''">
+            AND o.company_id IS NOT NULL
+        </if>
+        <if test="maps.companyUserId != null">
+            AND o.company_user_id = #{maps.companyUserId}
+        </if>
+        <if test="maps.companyUserNickName != null and maps.companyUserNickName != ''">
+            AND cu.nick_name LIKE CONCAT('%', #{maps.companyUserNickName}, '%')
+        </if>
+        <if test="maps.orderType != null">
+            AND o.order_type = #{maps.orderType}
+        </if>
+        <if test="maps.payType != null">
+            AND o.pay_type = #{maps.payType}
+        </if>
+        <if test="maps.createTimeList != null">
+            AND o.create_time >= STR_TO_DATE(#{maps.createTimeList[0]}, '%Y%m%d')
+            AND o.create_time &lt; DATE_ADD(STR_TO_DATE(#{maps.createTimeList[1]}, '%Y%m%d'), INTERVAL 1 DAY)
+        </if>
+        <if test="maps.payTimeList != null">
+            AND o.pay_time >= STR_TO_DATE(#{maps.payTimeList[0]}, '%Y%m%d')
+            AND o.pay_time &lt; DATE_ADD(STR_TO_DATE(#{maps.payTimeList[1]}, '%Y%m%d'), INTERVAL 1 DAY)
+        </if>
+        <if test="maps.deliverySendTimeList != null">
+            AND o.delivery_send_time >= STR_TO_DATE(#{maps.deliverySendTimeList[0]}, '%Y%m%d')
+            AND o.delivery_send_time &lt; DATE_ADD(STR_TO_DATE(#{maps.deliverySendTimeList[1]}, '%Y%m%d'), INTERVAL 1 DAY)
+        </if>
+        <if test="maps.deliveryImportTimeList != null">
+            AND o.delivery_import_time >= STR_TO_DATE(#{maps.deliveryImportTimeList[0]}, '%Y%m%d')
+            AND o.delivery_import_time &lt; DATE_ADD(STR_TO_DATE(#{maps.deliveryImportTimeList[1]}, '%Y%m%d'), INTERVAL 1 DAY)
+        </if>
+        <if test="maps.deptId != null">
+            AND (o.dept_id = #{maps.deptId}
+            OR o.dept_id IN (SELECT t.dept_id FROM company_dept t WHERE FIND_IN_SET(#{maps.deptId}, t.ancestors)))
+        </if>
+        <if test="maps.isUpload != null and maps.isUpload == 0">
+            AND o.certificates IS NULL
+        </if>
+        <if test="maps.scheduleId != null">
+            AND o.schedule_id = #{maps.scheduleId}
+        </if>
+        <if test="maps.isUpload != null and maps.isUpload == 1">
+            AND o.certificates IS NOT NULL
+        </if>
+        ${maps.params.dataScope}
+        AND o.paid = 1
+        GROUP BY o.id
+        LIMIT 10000;
+    </select>
+
+    <select id="selectLiveOrderCodeOpenIdInOrderCode" resultType="com.fs.live.vo.LiveOrderCodeOpenIdVo">
+        SELECT
+        os.order_id as id,
+        fu.phone,
+        fu.ma_open_id openId,
+        ois.json_info,
+        lop.bank_transaction_id outTransId
+        FROM
+        live_order os
+        INNER JOIN fs_user fu ON os.user_id = fu.user_id
+        INNER JOIN live_order_item ois ON ois.order_id = os.order_id
+        INNER JOIN live_order_payment lop ON os.order_id = lop.business_id
+        WHERE os.is_del = 0 and os.order_code IN
+        <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        AND lop.`status` = 1
+    </select>
+
+    <update id="batchUpdateInOrderCode">
+        UPDATE live_order
+        <set>
+            delivery_sn = CASE
+            <foreach collection="list" item="item">
+                WHEN order_code = #{item.orderNumber} THEN #{item.deliverySn}
+            </foreach>
+            ELSE delivery_sn
+            END,
+            delivery_name = CASE
+            <foreach collection="list" item="item">
+                WHEN order_code = #{item.orderNumber} THEN #{item.logisticsCompany}
+            </foreach>
+            ELSE delivery_name
+            END,
+            delivery_id = CASE
+            <foreach collection="list" item="item">
+                WHEN order_code = #{item.orderNumber} THEN #{item.deliveryId}
+            </foreach>
+            ELSE delivery_id
+            END,
+            status = CASE
+            WHEN status = 1 THEN 2
+            ELSE status
+            END,
+            delivery_send_time = NOW()
+        </set>
+        WHERE order_code IN
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.orderNumber}
+        </foreach>
+    </update>
+
+    <update id="batchUpdateTime">
+        UPDATE live_order
+        SET update_time = CASE
+        <foreach collection="list" item="item" separator="">
+            WHEN order_id = #{item.orderId} THEN #{item.updateTime}
+        </foreach>
+        END
+        WHERE order_id IN
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.orderId}
+        </foreach>
+    </update>
 </mapper>

+ 1 - 0
fs-service/src/main/resources/mapper/qw/QwGroupChatMapper.xml

@@ -203,6 +203,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="todayJoin != null">today_join = #{todayJoin},</if>
             <if test="todayOut != null">today_out = #{todayOut},</if>
             <if test="allOutGroup != null">all_out_group = #{allOutGroup},</if>
+            <if test="roomid != null">roomid = #{roomid},</if>
         </trim>
         where chat_id = #{chatId}
     </update>

+ 2 - 0
fs-service/src/main/resources/mapper/sop/SopUserLogsMapper.xml

@@ -14,6 +14,7 @@
         <result property="startTime"    column="start_time"  jdbcType="TIMESTAMP"   />
         <result property="status"    column="status"    />
         <result property="userId"    column="user_id"    />
+        <result property="chatId"    column="chat_id"    />
         <result property="countDays" column="count_days" />
     </resultMap>
 
@@ -25,6 +26,7 @@
             qw_user_id,
             corp_id,
             start_time,
+            chat_id,
             status,
             user_id,
             DATEDIFF(CURRENT_DATE, start_time) + 1 AS count_days