Bladeren bron

答题红包回调 定时发送答题SOP

wjj 1 dag geleden
bovenliggende
commit
a60b350a7b

+ 248 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -10,9 +10,16 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.app.domain.FsAppRole;
 import com.fs.app.mapper.FsAppRoleMapper;
 import com.fs.common.exception.CustomException;
+import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanySmsService;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCourseLink;
+import com.fs.course.domain.FsCourseRealLink;
+import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.mapper.FsCourseLinkMapper;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.doctor.service.IFsDoctorOnlineService;
 import com.fs.fastGpt.domain.FastgptChatVoiceHomo;
 import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
@@ -30,9 +37,14 @@ import com.fs.jd.dto.CarrierInfoDTO;
 import com.fs.jd.dto.SoQueryRequestDTO;
 import com.fs.jd.dto.SoQueryResponseDTO;
 import com.fs.jd.http.IJdHttpService;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.FsSopCompanyUserTaskMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.qw.vo.QwSopCourseFinishTempSetting;
+import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.domain.QwSopTempVoice;
+import com.fs.sop.mapper.QwSopLogsMapper;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.fs.common.core.redis.RedisCache;
@@ -94,6 +106,8 @@ import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.service.ISysConfigService;
+import com.fs.voice.utils.StringUtil;
 import com.fs.wx.domain.FsWxExpressTask;
 import com.fs.wx.dto.*;
 import com.fs.wx.mapper.FsWxExpressTaskMapper;
@@ -105,24 +119,35 @@ import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
 import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
+import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
+import static com.fs.course.utils.LinkUtil.generateRandomStringWithLock;
+
 @Slf4j
 @Component("task")
 public class Task {
+    private static final String miniappRealLink = "pages_user/answerQues?";
+    //商城小程序appId配置常量
+    private static final String APP_ID_CONFIG_KEY = "appStore.appId.config";
 
+    private static final String DEFAULT_APP_ID = "wx50bcb040b4963a7e";
+    @Autowired
+    private ISysConfigService sysConfigService;
     @Autowired
     private FsUserInformationCollectionMapper userInformationCollectionMapper;
 
@@ -214,6 +239,9 @@ public class Task {
     @Autowired
     private IFsCourseWatchLogService fsCourseWatchLogService;
 
+    @Autowired
+    private FsCourseWatchLogMapper watchLogMapper;
+
     @Autowired
     ITencentCloudCosService tencentCloudCosService;
     @Autowired
@@ -252,6 +280,9 @@ public class Task {
     @Autowired
     private FsOrderSopLogMapper fsOrderSopLogMapper;
 
+    @Autowired
+    private QwSopLogsMapper qwSopLogsMapper;
+
     @Autowired
     private IQwExternalContactService qwExternalContactService;
 
@@ -321,6 +352,12 @@ public class Task {
     @Autowired
     private XiaoShouYiOAuthService xiaoShouYiOAuthService;
 
+    @Autowired
+    private ICompanyMiniappService companyMiniappService;
+
+    @Autowired
+    private FsCourseLinkMapper fsCourseLinkMapper;
+
     public static final String SOP_TEMP_VOICE_KEY = "sop:tempVoice";
 
     // sop升单客户类型
@@ -2626,4 +2663,215 @@ public class Task {
         }
     }
 
+    /**
+     * 发送答题SOP
+     */
+    public void sendSopLogs(){
+        String lockKey = "sendSopLogs:lock";
+        Boolean acquired = redisCache.setIfAbsent(lockKey, "1", 10, TimeUnit.MINUTES);
+        if (acquired == null || !acquired) {
+            logger.info("sendSopLogs 任务正在执行中,跳过本次执行");
+            return;
+        }
+        List<FsCourseWatchLog> watchLogs;
+        try {
+            watchLogs = watchLogMapper.selectAnswerWatchLogs();
+            if (CollectionUtils.isEmpty(watchLogs)) {
+                return;
+            }
+            List<QwSopLogs> sopLogsList = new ArrayList<>();
+            for (FsCourseWatchLog watchLog : watchLogs) {
+                try {
+                    QwUser qwUser = qwUserService.selectQwUserById(watchLog.getQwUserId());
+
+                if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
+                    throw new CustomException("员工未绑定 客服公司 或 客服 请先绑定");
+                }
+
+                QwCompany qwCompany = qwCompanyService.getQwCompanyByRedis(qwUser.getCorpId());
+                if ( qwCompany==null ) {
+                    throw new CustomException("企业不存在,请联系管理员");
+                }
+
+//                List<Long> companyIds = Arrays.stream(Optional.ofNullable(qwCompany.getCompanyIds()).orElse("").split(","))
+//                        .map(String::trim)
+//                        .filter(s -> !s.isEmpty())
+//                        .map(Long::parseLong)
+//                        .collect(Collectors.toList());
+//
+//                List<CompanyMiniapp> miniAppList = companyMiniappService.getMiniAppListByCompanyListTwo(companyIds);
+//                Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniAppList.stream()
+//                        .collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId,
+//                                Collectors.groupingBy(CompanyMiniapp::getType)));
+
+                String finalAppId = getAppId();
+
+//                if (StringUtil.strIsNullOrEmpty(finalAppId)) {
+//                    finalAppId = qwCompany.getMiniAppId();
+//                }
+
+                if (StringUtil.strIsNullOrEmpty(finalAppId)) {
+                    throw new CustomException("没有可用小程序appId");
+                }
+
+                String linkByMiniApp = createLinkByMiniApp(new Date(), watchLog.getCourseId(), watchLog.getVideoId(), qwUser, watchLog.getQwExternalContactId());
+
+                QwExternalContact qwExternalContact = qwExternalContactService.selectQwExternalContactById(watchLog.getQwExternalContactId());
+
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+                QwSopLogs sopLogs = new QwSopLogs();
+                sopLogs.setQwUserid(qwUser.getQwUserId());
+                sopLogs.setExternalUserId(qwExternalContact.getExternalUserId());
+                sopLogs.setExternalId(qwExternalContact.getId());
+                sopLogs.setLogType(2);
+                sopLogs.setSendStatus(3L);
+                sopLogs.setSendTime(sdf.format(new Date()));
+                sopLogs.setCompanyId(qwUser.getCompanyId());
+                sopLogs.setReceivingStatus(0L);
+                sopLogs.setSopId("miniSidebar");
+                sopLogs.setCorpId(qwUser.getCorpId());
+                sopLogs.setFsUserId(watchLog.getUserId());
+                sopLogs.setSort(0);
+                sopLogs.setSendType(3);
+                sopLogs.setExternalUserName(qwExternalContact.getName());
+                sopLogs.setQwUserKey(qwUser.getId());
+
+                QwSopCourseFinishTempSetting setting = new QwSopCourseFinishTempSetting();
+                List<QwSopCourseFinishTempSetting.Setting> list = new ArrayList<>();
+                QwSopCourseFinishTempSetting.Setting st = new QwSopCourseFinishTempSetting.Setting();
+                st.setContentType("4");
+                //st.setCourseId(param.getCourseId());
+                st.setVideoId(watchLog.getVideoId());
+                st.setMiniprogramAppid(finalAppId);
+                String title = "答题领取";
+                st.setMiniprogramTitle(title);
+                st.setMiniprogramPicUrl("https://ysy-1329817240.cos.ap-guangzhou.myqcloud.com/ysy/20260710/9dac8618740f460a8bb60239a8913fe4.png");
+                st.setMiniprogramPage(linkByMiniApp);
+
+                list.add(st);
+                setting.setSetting(list);
+                setting.setType(2);
+                setting.setCourseType(0);
+                setting.setCourseId(watchLog.getCourseId().intValue());
+                setting.setVideoId(watchLog.getVideoId().intValue());
+
+                sopLogs.setSendMiniAppId(finalAppId);
+                sopLogs.setContentJson(JSON.toJSONString(setting));
+                sopLogsList.add(sopLogs);
+            } catch (Exception e) {
+                log.error("发送答题SOP异常", e);
+            }
+
+        }
+        if (CollectionUtils.isNotEmpty(sopLogsList)) {
+            qwSopLogsMapper.batchInsertQwSopLogs(sopLogsList);
+        }
+        if (CollectionUtils.isNotEmpty(watchLogs)) {
+            watchLogMapper.batchUpdateAnswerSendStatus(watchLogs);
+        }
+        } finally {
+            redisCache.deleteObject(lockKey);
+        }
+    }
+
+    /**
+     * 获取 appId 的私有方法
+     */
+    private String getAppId() {
+        try {
+            String configValue = sysConfigService.selectConfigByKey(APP_ID_CONFIG_KEY);
+            if (StringUtils.isNotEmpty(configValue)) {
+                cn.hutool.json.JSONObject json = JSONUtil.parseObj(configValue);
+                String appId = json.getStr("appId");
+                if (StringUtils.isNotEmpty(appId)) {
+                    return appId;
+                } else {
+                    log.warn("配置 {} 中 appId 字段为空,使用默认值", APP_ID_CONFIG_KEY);
+                }
+            } else {
+                log.warn("未找到配置 {},使用默认值", APP_ID_CONFIG_KEY);
+            }
+        } catch (Exception e) {
+            log.error("解析 appId 配置异常,configValue={}",
+                    sysConfigService.selectConfigByKey(APP_ID_CONFIG_KEY), e);
+        }
+        //默认值
+        return DEFAULT_APP_ID;
+    }
+
+
+    private String createLinkByMiniApp(Date sendTime, Long courseId, Long videoId,
+                                       QwUser qwUser, Long externalId) {
+
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(qwUser.getCompanyId());
+        link.setQwUserId(qwUser.getId());
+        link.setCompanyUserId(qwUser.getCompanyUserId());
+        link.setVideoId(videoId);
+        link.setCorpId(qwUser.getCorpId());
+        link.setCourseId(courseId);
+        link.setQwExternalId(externalId);
+        link.setIsRoom(0);
+        link.setUNo(UUID.randomUUID().toString());
+        link.setLinkType(3);
+
+        String randomString = generateRandomStringWithLock();
+        if (StringUtil.strIsNullOrEmpty(randomString)){
+            link.setLink(UUID.randomUUID().toString().replace("-", ""));
+        }else {
+            link.setLink(randomString);
+        }
+
+        link.setCreateTime(sendTime);
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link,courseMap);
+
+        String courseJson = JSON.toJSONString(courseMap);
+
+        String realLinkFull = miniappRealLink + courseJson;
+
+
+        link.setRealLink(realLinkFull);
+
+
+        // 使用 Java 8 时间 API 计算过期时间
+        LocalDateTime sendDateTime = sendTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        LocalDateTime expireDateTime = sendDateTime.plusDays(0);
+        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
+        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
+        link.setUpdateTime(updateTime);
+
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+
+
+        return link.getRealLink();
+
+    }
+    private String getAppIdFromMiniMap(Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                       String companyId, int sendMsgType) {
+        if (miniMap.isEmpty() || sendMsgType != 1) {
+            return null;
+        }
+
+        Map<Integer, List<CompanyMiniapp>> gradeMap = miniMap.get(Long.valueOf(companyId));
+        if (gradeMap == null) {
+            return null;
+        }
+        int listIndex =  5;
+
+        List<CompanyMiniapp> miniapps = gradeMap.get(listIndex);
+
+        if (miniapps == null || miniapps.isEmpty()) {
+            return null;
+        }
+
+        CompanyMiniapp companyMiniapp = miniapps.get(0);
+        return (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId()))
+                ? companyMiniapp.getAppId()
+                : null;
+    }
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyMiniappMapper.java

@@ -2,6 +2,7 @@ package com.fs.company.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.company.domain.CompanyMiniapp;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -59,4 +60,6 @@ public interface CompanyMiniappMapper extends BaseMapper<CompanyMiniapp>{
      * @return 结果
      */
     int deleteCompanyMiniappByIds(Long[] ids);
+
+    List<CompanyMiniapp> getMiniAppListByCompanyListTwo(@Param("companyIds") List<Long> companyIds);
 }

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

@@ -67,4 +67,6 @@ public interface ICompanyMiniappService extends IService<CompanyMiniapp>{
 
     void setMiniAppList(List<CompanyVO> companyVOS);
     List<CompanyMiniapp> getMiniAppListByCompanyList(List<Long> companyIds);
+
+    List<CompanyMiniapp> getMiniAppListByCompanyListTwo(List<Long> companyIds);
 }

+ 6 - 4
fs-service/src/main/java/com/fs/company/service/impl/CompanyMiniappServiceImpl.java

@@ -12,10 +12,7 @@ import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.vo.CompanyVO;
 import org.springframework.stereotype.Service;
 
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiFunction;
 import java.util.stream.Collectors;
@@ -141,4 +138,9 @@ public class CompanyMiniappServiceImpl extends ServiceImpl<CompanyMiniappMapper,
     public List<CompanyMiniapp> getMiniAppListByCompanyList(List<Long> companyIds) {
         return list(new QueryWrapper<CompanyMiniapp>().in("company_id", companyIds));
     }
+
+    @Override
+    public List<CompanyMiniapp> getMiniAppListByCompanyListTwo(List<Long> companyIds) {
+        return baseMapper.getMiniAppListByCompanyListTwo(companyIds);
+    }
 }

+ 10 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseWatchLog.java

@@ -91,4 +91,14 @@ public class FsCourseWatchLog extends BaseEntity
     /** im发送消息详情id */
     private Long imMsgSendDetailId;
 
+    /**
+     * 答题发送状态 0-待发送 1-已发送
+     */
+    private Integer answerSendStatus;
+
+    /**
+     * 红包发送状态 0-待发送 1-已发送
+     */
+    private Integer redPacketStatus;
+
 }

+ 9 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -611,4 +611,13 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
                                                        @Param("batchSize") int batchSize,
                                                        @Param("maxId") Long maxId);
 
+    /**
+     * 获取所有答题课的观看记录
+     */
+    List<FsCourseWatchLog> selectAnswerWatchLogs();
+
+    FsCourseWatchLog selectAnswerWatchLog(@Param("userId") Long userId);
+
+    void batchUpdateAnswerSendStatus(@Param("list") List<FsCourseWatchLog> list);
+
 }

+ 4 - 4
fs-service/src/main/java/com/fs/course/service/IFsCourseWatchLogService.java

@@ -1,12 +1,10 @@
 package com.fs.course.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.param.*;
-import com.fs.course.vo.FsCourseOverVO;
-import com.fs.course.vo.FsCourseUserStatisticsListVO;
-import com.fs.course.vo.FsCourseWatchLogListVO;
-import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
+import com.fs.course.vo.*;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
 import com.fs.qw.vo.QwWatchLogStatisticsListVO;
 
@@ -149,4 +147,6 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
      * 检查飞书看课状态
      */
     void checkFeiShuWatchStatus();
+
+    R getUserAnswer(Long userId);
 }

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

@@ -19,6 +19,8 @@ import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.system.service.ISysConfigService;
 import lombok.Getter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -38,6 +40,7 @@ import java.util.stream.Collectors;
 @Service
 public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankService
 {
+    Logger logger= LoggerFactory.getLogger(getClass());
     @Autowired
     private FsCourseQuestionBankMapper fsCourseQuestionBankMapper;
     @Autowired
@@ -375,7 +378,9 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
             if(isH5User){
                 log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
             } else {
+                logger.info("查询看课记录入参:userId={},videoId={},qwUserId={},exId={}",param.getUserId(),param.getVideoId(),param.getQwUserId(),param.getQwExternalId());
                 log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+                logger.info("查询看课记录结果:{}",log);
             }
             if (log==null){
                 return R.error("无记录");

+ 10 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java

@@ -208,6 +208,16 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
                 log.setUpdateTime(new Date());
                 log.setBatchId(batchId);
                 fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(log);
+
+
+                //更新看课记录是否领取红包
+                FsCourseWatchLog watchLog = courseWatchLogMapper.selectFsCourseWatchLogByLogId(log.getWatchLogId());
+                if (watchLog!=null) {
+                    FsCourseWatchLog mapLog  = new FsCourseWatchLog();
+                    mapLog.setLogId(watchLog.getLogId());
+                    mapLog.setRedPacketStatus(1);
+                    courseWatchLogMapper.updateFsCourseWatchLog(mapLog);
+                }
                 return R.ok();
             }
         }

+ 83 - 4
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java

@@ -8,7 +8,9 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DictUtils;
 import com.fs.company.cache.ICompanyCacheService;
@@ -20,6 +22,7 @@ import com.fs.course.constant.CourseConstant;
 import com.fs.course.domain.*;
 import com.fs.course.mapper.*;
 import com.fs.course.param.*;
+import com.fs.course.service.IFsCourseQuestionBankService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.cache.IFsUserCourseVideoCacheService;
 import com.fs.course.vo.*;
@@ -31,15 +34,14 @@ import com.fs.his.vo.OptionsVO;
 import com.fs.qw.Bean.MsgBean;
 import com.fs.qw.cache.IQwExternalContactCacheService;
 import com.fs.qw.cache.IQwUserCacheService;
-import com.fs.qw.domain.QwExternalContact;
-import com.fs.qw.domain.QwExternalContactInfo;
-import com.fs.qw.domain.QwUser;
-import com.fs.qw.domain.QwWatchLog;
+import com.fs.qw.domain.*;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.mapper.QwWatchLogMapper;
 import com.fs.qw.param.SendSopParamDetails;
 import com.fs.qw.param.SopUserLogsVO;
+import com.fs.qw.service.IQwCompanyService;
+import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qw.vo.QwSopTempSetting;
 import com.fs.sop.domain.QwSopLogs;
@@ -55,8 +57,10 @@ import com.hc.openapi.tool.util.StringUtils;
 import org.apache.ibatis.session.ExecutorType;
 import org.apache.ibatis.session.SqlSession;
 import org.apache.ibatis.session.SqlSessionFactory;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
@@ -69,6 +73,7 @@ import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -133,6 +138,15 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
     @Autowired
     private SysDictDataMapper sysDictDataMapper;
 
+    @Autowired
+    private IQwUserService qwUserService;
+
+    @Autowired
+    private IQwCompanyService qwCompanyService;
+
+    @Autowired
+    private IFsCourseQuestionBankService questionBankService;
+
     /**
      * 查询短链课程看课记录
      *
@@ -1324,6 +1338,71 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
         }
     }
 
+    @Override
+    public R getUserAnswer(Long userId) {
+        FsCourseWatchLog watchLog = fsCourseWatchLogMapper.selectAnswerWatchLog(userId);
+        if (watchLog == null) {
+            return R.error("没有看课记录,请完成看课");
+        }
+        if (watchLog.getRedPacketStatus() == 1) {
+            return R.error("已领取红包");
+        }
+        FsUserCourseVideo courseVideo = fsUserCourseVideoCacheService.selectFsUserCourseVideoByVideoId(watchLog.getVideoId());
+        if (courseVideo==null) {
+            return R.error("课程不存在");
+        }
+        QwUser qwUser = qwUserService.selectQwUserById(watchLog.getQwUserId());
+
+        if (qwUser==null||qwUser.getCompanyId()==null||qwUser.getCompanyUserId()==null){
+            return R.error ("员工未绑定 客服公司 或 客服 请先绑定");
+        }
+
+        QwCompany qwCompany = qwCompanyService.getQwCompanyByRedis(qwUser.getCorpId());
+        if ( qwCompany==null ) {
+            return R.error("企业不存在,请联系管理员");
+        }
+        UserAnswerVO userAnswerVO = getUserAnswerVO(watchLog, qwUser);
+
+        //获取题库
+        List<FsUserCourseVideoQuestionVO> questionVOList = null;
+        try
+        {
+            questionVOList=redisCache.getCacheObject("cache:question:"+watchLog.getVideoId());
+            if(questionVOList==null|| questionVOList.isEmpty()){
+                questionVOList = new ArrayList<>();
+                if (com.fs.common.utils.StringUtils.isNotEmpty(courseVideo.getQuestionBankId())){
+                    String[] questionIds = courseVideo.getQuestionBankId().split(",");
+                    for (String questionId : questionIds){
+                        FsUserCourseVideoQuestionVO vo = new FsUserCourseVideoQuestionVO();
+                        FsCourseQuestionBank questionBank = questionBankService.selectFsCourseQuestionBankById(Long.parseLong(questionId));
+                        if (questionBank!=null&&questionBank.getStatus()!=0){
+                            BeanUtils.copyProperties(questionBank,vo);
+                            questionVOList.add(vo);
+                        }
+                    }
+                }
+                redisCache.setCacheObject("cache:question:"+watchLog.getVideoId(),questionVOList, 10, TimeUnit.MINUTES);
+            }
+        }
+        catch (Exception e){
+
+        }
+        return R.ok().put("data", userAnswerVO).put("questions", questionVOList);
+    }
+
+    private UserAnswerVO getUserAnswerVO(FsCourseWatchLog watchLog, QwUser qwUser) {
+        UserAnswerVO userAnswerVO = new UserAnswerVO();
+        userAnswerVO.setUserId(watchLog.getUserId());
+        userAnswerVO.setCompanyUserId(watchLog.getCompanyUserId());
+        userAnswerVO.setCorpId(qwUser.getCorpId());
+        userAnswerVO.setCourseId(watchLog.getCourseId());
+        userAnswerVO.setVideoId(watchLog.getVideoId());
+        userAnswerVO.setQwExternalId(watchLog.getQwExternalContactId());
+        userAnswerVO.setQwUserId(watchLog.getQwUserId());
+        userAnswerVO.setCompanyId(watchLog.getCompanyId());
+        return userAnswerVO;
+    }
+
     @Autowired
     private SqlSessionFactory sqlSessionFactory;
 

+ 15 - 0
fs-service/src/main/java/com/fs/course/vo/UserAnswerVO.java

@@ -0,0 +1,15 @@
+package com.fs.course.vo;
+
+import lombok.Data;
+
+@Data
+public class UserAnswerVO {
+    private Long companyId;
+    private Long companyUserId;
+    private String corpId;
+    private Long courseId;
+    private Long videoId;
+    private Long qwExternalId;
+    private Long qwUserId;
+    private Long userId;
+}

+ 12 - 0
fs-service/src/main/resources/mapper/CompanyMiniappMapper.xml

@@ -88,4 +88,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{id}
         </foreach>
     </delete>
+
+    <select id="getMiniAppListByCompanyListTwo" resultType="com.fs.company.domain.CompanyMiniapp">
+        <include refid="selectCompanyMiniappVo"/>
+        <where>
+            <if test="companyIds != null ">
+                company_id in
+                <foreach item="companyId" collection="companyIds" open="(" separator="," close=")">
+                    #{companyId}
+                </foreach>
+            </if>
+        </where>
+    </select>
 </mapper>

+ 35 - 1
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -25,10 +25,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="campPeriodTime"    column="camp_period_time"    />
         <result property="lastHeartbeatTime"    column="last_heartbeat_time"    />
         <result property="project"    column="project"    />
+        <result property="answerSendStatus" column="answer_send_status" />
+        <result property="redPacketStatus" column="red_packet_status" />
     </resultMap>
 
     <sql id="selectFsCourseWatchLogVo">
-        select log_id, user_id,finish_time,send_finish_msg,sop_id,video_id,reward_type, log_type, create_time, update_time, qw_external_contact_id, duration, qw_user_id, company_user_id, company_id, course_id,camp_period_time,project from fs_course_watch_log
+        select log_id, user_id,finish_time,send_finish_msg,sop_id,video_id,reward_type, log_type, create_time, update_time, qw_external_contact_id, duration, qw_user_id, company_user_id, company_id, course_id,camp_period_time,project, answer_send_status,red_packet_status from fs_course_watch_log
     </sql>
 
     <select id="selectFsCourseWatchLogList" parameterType="FsCourseWatchLog" resultMap="FsCourseWatchLogResult">
@@ -335,6 +337,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="campPeriodTime != null">camp_period_time,</if>
             <if test="periodId != null">period_id,</if>
             <if test="project != null">project,</if>
+            <if test="answerSendStatus != null"> answer_send_status,</if>
+            <if test="redPacketStatus != null"> red_packet_status,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="userId != null">#{userId},</if>
@@ -356,6 +360,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="campPeriodTime != null">#{campPeriodTime},</if>
             <if test="periodId != null">#{periodId},</if>
             <if test="project != null">#{project},</if>
+            <if test="answerSendStatus != null">#{answerSendStatus},</if>
+            <if test="redPacketStatus != null">#{redPacketStatus},</if>
         </trim>
     </insert>
 
@@ -380,6 +386,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="sendFinishMsg != null">send_finish_msg,</if>
             <if test="campPeriodTime != null">camp_period_time,</if>
             <if test="project != null">project,</if>
+            <if test="answerSendStatus != null"> answer_send_status,</if>
+            <if test="redPacketStatus != null"> red_packet_status,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="userId != null">#{userId},</if>
@@ -400,6 +408,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="sendFinishMsg != null">#{sendFinishMsg},</if>
             <if test="campPeriodTime != null">#{campPeriodTime},</if>
             <if test="project != null">#{project},</if>
+            <if test="answerSendStatus != null">#{answerSendStatus},</if>
+            <if test="redPacketStatus != null">#{redPacketStatus},</if>
         </trim>
         on duplicate key update
         <trim suffixOverrides=",">
@@ -482,6 +492,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="lastHeartbeatTime != null">last_heartbeat_time = #{lastHeartbeatTime},</if>
             <if test="periodId != null">period_id = #{periodId},</if>
             <if test="project != null">project = #{project},</if>
+            <if test="answerSendStatus != null"> answer_send_status = #{answerSendStatus},</if>
+            <if test="redPacketStatus != null"> red_packet_status = #{redPacketStatus},</if>
         </trim>
         where log_id = #{logId}
     </update>
@@ -1131,4 +1143,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             LIMIT #{batchSize}
     </select>
 
+    <select id="selectAnswerWatchLogs" resultMap="FsCourseWatchLogResult">
+        SELECT *
+        FROM fs_course_watch_log
+        WHERE answer_send_status = 0 AND log_type = 2
+    </select>
+
+    <select id="selectAnswerWatchLog" resultMap="FsCourseWatchLogResult">
+        SELECT *
+            FROM fs_course_watch_log
+            WHERE  log_type = 2  AND user_id = #{userId}
+        order by log_id desc limit 1
+    </select>
+
+    <update id="batchUpdateAnswerSendStatus" parameterType="java.util.List">
+        UPDATE fs_course_watch_log
+        SET answer_send_status = 1
+        WHERE log_id IN
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.logId}
+        </foreach>
+    </update>
+
 </mapper>

+ 14 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseController.java

@@ -48,6 +48,8 @@ public class CourseController extends  AppBaseController{
     private IFsUserCourseStudyLogService courseStudyLogService;
     @Autowired
     private IFsCourseSopAppLinkService courseSopAppLinkService;
+    @Autowired
+    private IFsCourseWatchLogService courseWatchLogService;
 
 
 //    @Cacheable(value="getCourseCate" )
@@ -362,4 +364,16 @@ public class CourseController extends  AppBaseController{
         return courseService.getIntegralByCourseVideo(param);
     }
 
+    @Login
+    @ApiOperation("获取客户答题")
+    @GetMapping("/getCourseAnswer")
+    public R getCourseAnswer(HttpServletRequest request){
+        try {
+            Long userId = Long.parseLong(getUserId());
+            return courseWatchLogService.getUserAnswer(userId);
+        } catch (NumberFormatException e) {
+            return R.error(401, "用户登录信息异常");
+        }
+    }
+
 }