Browse Source

Merge branch 'refs/heads/master' into openImAndLive

caoliqin 1 tháng trước cách đây
mục cha
commit
6313e16e2b
25 tập tin đã thay đổi với 525 bổ sung285 xóa
  1. 0 1
      README.md
  2. 1 5
      fs-admin/src/main/java/com/fs/api/controller/StatisticManageController.java
  3. 14 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java
  4. 1 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java
  5. 34 2
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java
  6. 9 0
      fs-admin/src/main/java/com/fs/task/SgTestController.java
  7. 1 0
      fs-admin/src/main/resources/logback.xml
  8. 13 9
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  9. 2 0
      fs-service/src/main/java/com/fs/company/domain/Company.java
  10. 61 3
      fs-service/src/main/java/com/fs/company/mapper/StatisticManageMapper.java
  11. 3 0
      fs-service/src/main/java/com/fs/company/param/companyUserAddPrintParam.java
  12. 2 1
      fs-service/src/main/java/com/fs/company/service/ICompanyRechargeService.java
  13. 6 4
      fs-service/src/main/java/com/fs/company/service/IStatisticManageService.java
  14. 9 4
      fs-service/src/main/java/com/fs/company/service/impl/CompanyRechargeServiceImpl.java
  15. 72 64
      fs-service/src/main/java/com/fs/company/service/impl/StatisticManageServiceImpl.java
  16. 2 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  17. 7 4
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  18. 8 2
      fs-service/src/main/java/com/fs/wxwork/service/WxWorkServiceImpl.java
  19. 1 0
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  20. 51 176
      fs-service/src/main/resources/mapper/company/StatisticManageMapper.xml
  21. 3 2
      fs-service/src/main/resources/mapper/course/FsCourseLinkMapper.xml
  22. 2 1
      fs-service/src/main/resources/mapper/course/FsCourseTrafficLogMapper.xml
  23. 2 1
      fs-service/src/main/resources/mapper/qw/HyWorkTaskMapper.xml
  24. 2 2
      fs-service/src/main/resources/mapper/qw/QwWatchLogMapper.xml
  25. 219 1
      fs-user-app/src/main/java/com/fs/app/controller/store/CompanyUserScrmController.java

+ 0 - 1
README.md

@@ -72,7 +72,6 @@ CREATE TABLE IF NOT EXISTS user_daily_stats (
     red_packet_amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00 COMMENT '红包金额',
     create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
     update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
-    UNIQUE KEY uk_user_date (user_id, statistics_time) COMMENT '用户+日期唯一约束',
     KEY idx_company_date (company_id, statistics_time) COMMENT '公司+日期索引',
     KEY idx_dept_date (dept_id, create_time) COMMENT '部门+日期索引'
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '用户每日统计数据表';

+ 1 - 5
fs-admin/src/main/java/com/fs/api/controller/StatisticManageController.java

@@ -1,6 +1,5 @@
 package com.fs.api.controller;
 
-
 import com.fs.common.core.domain.R;
 import com.fs.company.service.IStatisticManageService;
 import com.fs.statis.param.ComprehensiveStatisticsParam;
@@ -29,9 +28,6 @@ public class StatisticManageController {
     @PostMapping("/statisticMain")
     public R statisticMain(@RequestBody ComprehensiveStatisticsParam param) {
         Assert.notNull(param.getDimension(), "请选择统计维度");
-        statisticManageService.executeTask();
-//        return R.ok().put("data", statisticManageService.statisticMain(param));
-        return R.ok("success");
-
+        return R.ok().put("data", statisticManageService.statisticMain(param));
     }
 }

+ 14 - 1
fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java

@@ -14,6 +14,7 @@ import com.fs.company.domain.CompanyDeduct;
 import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.service.ICompanyDeductService;
 import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.service.ICompanyRechargeService;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.vo.CompanyDeductExportVO;
 import com.fs.company.vo.CompanyDeductVO;
@@ -45,6 +46,10 @@ public class CompanyDeductController extends BaseController
     private ICompanyService companyService;
     @Autowired
     private ICompanyMoneyLogsService moneyLogsService;
+
+    @Autowired
+    private ICompanyRechargeService companyRechargeService;
+
     /**
      * 查询扣款列表
      */
@@ -128,7 +133,15 @@ public class CompanyDeductController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if(deduct.getIsAudit()==1){
             Company company=companyService.selectCompanyByIdForUpdate(deduct.getCompanyId());
-            company.setMoney(company.getMoney().subtract(deduct.getMoney()));
+
+            // 同步redis缓存
+            R r = companyRechargeService.syncUpdateRedisCompanyRecharge(company, deduct.getMoney(), 2);
+            if(!"200".equals(r.get("code").toString())){
+                return r;
+            }
+            // 充值后,需要同步更新余额到数据库,否则余额与缓存中的不一致
+            String newMoney = r.get("newMoney").toString();
+            company.setMoney(new BigDecimal(newMoney));
             companyService.updateCompany(company);
             CompanyMoneyLogs log=new CompanyMoneyLogs();
             log.setCompanyId(deduct.getCompanyId());

+ 1 - 1
fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java

@@ -125,7 +125,7 @@ public class CompanyRechargeController extends BaseController
 
             // 同步redis缓存
             // 注意:在进行充值审核之前,需要先执行一下定时任务同步缓存数据到数据库,再进行后续操作,否则金额不正确
-            R r = companyRechargeService.syncUpdateRedisCompanyRecharge(company, companyRecharge.getMoney());
+            R r = companyRechargeService.syncUpdateRedisCompanyRecharge(company, companyRecharge.getMoney(), 1);
             if(!"200".equals(r.get("code").toString())){
                 return r;
             }

+ 34 - 2
fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java

@@ -28,6 +28,7 @@ import com.fs.system.service.ISysConfigService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -50,8 +51,7 @@ import com.fs.common.core.page.TableDataInfo;
  */
 @RestController
 @RequestMapping("/his/company")
-public class FsCompanyController extends BaseController
-{
+public class FsCompanyController extends BaseController {
     @Autowired
     private ICompanyService companyService;
     @Autowired
@@ -263,4 +263,36 @@ public class FsCompanyController extends BaseController
         return companyDivConfigService.setDiv(param);
     }
 
+    @PostMapping("/exitMiniProgram")
+    @Log(title = "批量修改小程序", businessType = BusinessType.UPDATE)
+    public R exitMiniProgram(@RequestBody Company company) {
+        // 1. 前置校验:核心参数非空校验
+        if (CollectionUtils.isEmpty(company.getIds())) {
+            return R.error("请选择需要修改的企业ID");
+        }
+        if (isNNull(company.getCourseMiniAppId())&&isListNull(company.getMiniAppMaster()) && isListNull(company.getMiniAppServer())) {
+            return R.error("请选择要修改的小程序");
+        } else {
+            for (Long id : company.getIds()) {
+                Company c = companyService.selectCompanyById(id);
+                c.setMoney(null);
+                c.setUpdateMiniApp(true);
+                if (company.getCourseMiniAppId()!= null&&!company.getCourseMiniAppId().isEmpty()) c.setCourseMiniAppId(company.getCourseMiniAppId());
+                if (company.getMiniAppMaster()!=null&&!company.getMiniAppMaster().isEmpty()) c.setMiniAppMaster(company.getMiniAppMaster());
+                if (company.getMiniAppServer()!=null&&!company.getMiniAppServer().isEmpty()) c.setMiniAppServer(company.getMiniAppServer());
+                companyService.updateCompany(c);
+            }
+            return R.ok();
+        }
+    }
+   public boolean isNNull(String value){
+        if (value==null)return true;
+        if (value.isEmpty())return true;
+        return false;
+    }
+    public boolean isListNull(List<String> value){
+        if (value==null)return true;
+        if (value.isEmpty())return true;
+        return false;
+    }
 }

+ 9 - 0
fs-admin/src/main/java/com/fs/task/SgTestController.java

@@ -3,6 +3,8 @@ package com.fs.task;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+ import com.fs.company.service.IStatisticManageService;
+
 import javax.annotation.Resource;
 
 /**
@@ -17,11 +19,18 @@ public class SgTestController {
     @Resource
     private SyncTuLinStudentInfoTask syncTuLinStudentInfoTask;
 
+    @Resource
+    private IStatisticManageService iStatisticManageService;
+
 
     @RequestMapping("/execute")
     public void execute(){
         syncTuLinStudentInfoTask.execute();
     }
 
+    @RequestMapping("/statistic")
+    public void executeTask(){
+        iStatisticManageService.executeTask();
+    }
 
 }

+ 1 - 0
fs-admin/src/main/resources/logback.xml

@@ -78,6 +78,7 @@
 
     <!-- log4j2.xml -->
     <Logger name="com.fs.his.mapper" level="debug"/>
+    <Logger name="com.fs.company.mapper" level="debug"/>
     <Logger name="org.apache.ibatis" level="debug"/>
 
 

+ 13 - 9
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -715,7 +715,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             ruleTimeVO.setSendType(6);
             ruleTimeVO.setType(2);
             if (groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()) {
-                QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
+                QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null,null);
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName,
                         null, true, miniAppId, groupChat,config, miniMap, null, sendMsgType,companies);
@@ -745,7 +745,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     String externalUserName = contactId.getExternalUserName();
                     Long fsUserId = contactId.getFsUserId();
                     Integer grade = contactId.getGrade();
-                    QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
+                    QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId(),contactId.getIsDaysNotStudy());
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                             type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId,
                             null,config, miniMap, grade, sendMsgType,companies);
@@ -791,7 +791,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private QwSopLogs createBaseLog(String formattedSendTime, SopUserLogsVo logVo,
                                     QwSopRuleTimeVO ruleTimeVO, String externalContactId,
                                     String externalUserName, Long fsUserId,Integer isOfficial,
-                                    Long externalId) {
+                                    Long externalId,Integer isDaysNotStudy) {
         QwSopLogs sopLogs = new QwSopLogs();
         sopLogs.setSendTime(formattedSendTime);
         sopLogs.setQwUserid(logVo.getQwUserId());
@@ -799,6 +799,15 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         sopLogs.setLogType(ruleTimeVO.getType());
         sopLogs.setTakeRecords(0);
 
+        if (isOfficial != 1 && Integer.valueOf(1).equals(isDaysNotStudy)) {
+            sopLogs.setSendStatus(5L);
+            sopLogs.setRemark("E级客户不发送");
+        }else {
+            sopLogs.setSendStatus(3L);
+        }
+
+        sopLogs.setReceivingStatus(0L);
+
         if (isOfficial == 1) {
 
             if (logVo.getIsSampSend()== 1) {
@@ -828,17 +837,12 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         }
 
 
-        sopLogs.setSendStatus(3L);
-        sopLogs.setReceivingStatus(0L);
+
 
         String[] userKey = logVo.getUserId().split("\\|");
-        log.info("sopLogVo:{}", JSON.toJSONString(logVo));
-        log.info("sop_logs -》 userId:{}", logVo.getUserId());
-        log.info("sop_logs -》 userId -》 split:{}", Arrays.asList(userKey));
         sopLogs.setCompanyId(Long.valueOf(userKey[2].trim()));
         if (StringUtils.isNotEmpty(userKey[0].trim())){
             sopLogs.setQwUserKey(Long.valueOf(userKey[0].trim()));
-            log.info("qw_sop数据:{}", JSON.toJSONString(sopLogs));
         }
         sopLogs.setSopId(logVo.getSopId());
         sopLogs.setSort(Integer.valueOf(logVo.getStartTime().replaceAll("-","")));

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

@@ -138,4 +138,6 @@ public class Company extends BaseEntity
     /**经销售归属*/
     private String companyBelongOwner;
 
+    @TableField(exist = false)
+    private List<Long> ids;
 }

+ 61 - 3
fs-service/src/main/java/com/fs/company/mapper/StatisticManageMapper.java

@@ -16,15 +16,56 @@ import java.util.List;
  */
 public interface StatisticManageMapper {
 
-    //插入数据
+    /**
+     * 插入数据
+     * @param comprehensiveDailyStats
+     */
     Integer insert(ComprehensiveDailyStats comprehensiveDailyStats);
 
+    /**
+     * 根据id更新数据
+     * @param comprehensiveDailyStats
+     */
+    Integer updateById(ComprehensiveDailyStats comprehensiveDailyStats);
+
+    /**
+     * 根据userId和日期更新数据
+     * @param comprehensiveDailyStats
+     */
+    Integer updateByUserAndDate(ComprehensiveDailyStats comprehensiveDailyStats);
+
+    /**
+     * 根据deptId和日期查询数据
+     * @param deptId
+     * @param statisticsTime
+     */
+    ComprehensiveDailyStats selectByDeptAndDate(@Param("deptId") Long deptId, @Param("statisticsTime") Date statisticsTime);
+
+    /**
+     * 根据用户id和日期查询是否有数据
+     * @param userId
+     * @param statisticsTime
+     */
+    ComprehensiveDailyStats selectByUserAndDate(@Param("userId") Long userId, @Param("statisticsTime") Date statisticsTime);
+
+    /**
+     * 根据用户id和日期查询是否有数据
+     * @param userId
+     * @param statisticsTime
+     */
+    Integer countByUserAndDate(@Param("userId") Long userId, @Param("statisticsTime") Date statisticsTime);
+
+    /**
+     * 根据id删除数据
+     * @param id
+     */
+    Integer deleteById(@Param("id") Long id);
+
     //获取公司、部门、员工信息
     List<CompanyDeptUserInfo> getCompanyAndDeptAndDeptUserList(@Param("companyId") Long companyId);
 
     List<CompanyDeptUserInfo> getCompanyInfo();
 
-
     CompanyDeptUserInfoDTO getStatisticNum(@Param("userIds") Long userIds);
 
     /**
@@ -34,5 +75,22 @@ public interface StatisticManageMapper {
      * @param endTime
      * @param userIds
      */
-    List<ComprehensiveStatisticsDTO> getStatisticNumByPersonal(@Param("dimension")Integer dimension, @Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("userIds") Long... userIds);
+    List<ComprehensiveDailyStats> getStatisticNumByPersonal(@Param("dimension")Integer dimension, @Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("userIds") Long... userIds);
+
+    /**
+     * 按照部门统计
+     * @param startTime
+     * @param endTime
+     * @param deptIds
+     */
+    List<ComprehensiveDailyStats> getStatisticNumByDeptId(@Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("deptIds") Long... deptIds);
+
+    /**
+     * 按照公司统计
+     * @param startTime
+     * @param endTime
+     * @param companyIds
+     */
+    List<ComprehensiveDailyStats> getStatisticNumByCompanyId(@Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("companyIds") Long... companyIds);
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/company/param/companyUserAddPrintParam.java

@@ -1,9 +1,12 @@
 package com.fs.company.param;
 
+import io.swagger.models.auth.In;
 import lombok.Data;
 
 @Data
 public class companyUserAddPrintParam
 {
     String  voicePrintUrl;
+    String  token;
+    Long companyUserId;
 }

+ 2 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyRechargeService.java

@@ -55,9 +55,10 @@ public interface ICompanyRechargeService
      * 同步到缓存余额
      * @param company 公司
      * @param rechargeMoney 充值金额
+     * @param type 同步类型,1-充值,2-扣款
      * @return 是否成功
      */
-    R syncUpdateRedisCompanyRecharge(Company company, BigDecimal rechargeMoney);
+    R syncUpdateRedisCompanyRecharge(Company company, BigDecimal rechargeMoney, Integer type);
 
     List<CompanyRechargeVO> selectCompanyRechargeListVO(CompanyRechargeVO companyRecharge);
     /**

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

@@ -2,9 +2,6 @@ package com.fs.company.service;
 
 import com.fs.statis.param.ComprehensiveStatisticsParam;
 
-import java.util.List;
-import java.util.Map;
-
 /**
  * @description:
  * @author: Guos
@@ -12,7 +9,12 @@ import java.util.Map;
  */
 public interface IStatisticManageService {
 
-    List<Map<String, Object>> statisticMain(ComprehensiveStatisticsParam param);
+    /**
+     * 统计主页
+     * @param param
+     * @return
+     */
+    Object statisticMain(ComprehensiveStatisticsParam param);
 
     /**
      * 用来执行定时任务

+ 9 - 4
fs-service/src/main/java/com/fs/company/service/impl/CompanyRechargeServiceImpl.java

@@ -109,9 +109,9 @@ public class CompanyRechargeServiceImpl implements ICompanyRechargeService
     }
 
     @Override
-    public R syncUpdateRedisCompanyRecharge(Company company, BigDecimal rechargeMoney) {
+    public R syncUpdateRedisCompanyRecharge(Company company, BigDecimal rechargeMoney, Integer type) {
         if(company.getCompanyId() == null){
-            log.error("公司充值-审核-同步更新到缓存,参数错误,公司id:{}, 充值余额:{}", company.getCompanyId(), rechargeMoney);
+            log.error("公司充值/扣款-审核-同步更新到缓存,参数错误,公司id:{}, 充值/扣款余额:{},类型:{}", null, rechargeMoney, type);
             return R.error("公司id为空");
         }
 
@@ -136,13 +136,18 @@ public class CompanyRechargeServiceImpl implements ICompanyRechargeService
                     redisMoney = company.getMoney();
                 }
 
-                newMoney = redisMoney.add(rechargeMoney);
+                if(type == 1){
+                    // 充值
+                    newMoney = redisMoney.add(rechargeMoney);
+                } else {
+                    newMoney = redisMoney.subtract(rechargeMoney);
+                }
 
                 redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
             }
             return R.ok().put("newMoney", newMoney);
         } catch (Exception e) {
-            log.error("公司充值-审核-同步更新到缓存,参数错误,请求异常,异常信息:{}", e.getMessage(), e);
+            log.error("公司充值/扣款-审核-同步更新到缓存,参数错误,请求异常,异常信息:{}", e.getMessage(), e);
             return R.error("审核失败,请重试");
         } finally {
             if (lockAcquired && lock.isHeldByCurrentThread()) {

+ 72 - 64
fs-service/src/main/java/com/fs/company/service/impl/StatisticManageServiceImpl.java

@@ -1,18 +1,15 @@
 package com.fs.company.service.impl;
 
-import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.date.StopWatch;
 import com.fs.common.enums.DimensionEnum;
-import com.fs.common.utils.bean.BeanUtils;
 import com.fs.company.domain.CompanyDeptUserInfo;
 import com.fs.company.domain.ComprehensiveDailyStats;
 import com.fs.company.dto.CompanyDeptUserInfoDTO;
-import com.fs.company.dto.ComprehensiveStatisticsDTO;
 import com.fs.company.mapper.StatisticManageMapper;
 import com.fs.company.service.IStatisticManageService;
 import com.fs.statis.param.ComprehensiveStatisticsParam;
-import com.google.common.collect.Maps;
 import lombok.extern.slf4j.Slf4j;
-import com.google.common.collect.Lists;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 
@@ -20,10 +17,6 @@ import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
 /**
  * @description:
  * @author: Guos
@@ -42,77 +35,92 @@ public class StatisticManageServiceImpl implements IStatisticManageService {
      * @return
      */
     @Override
-    public List<Map<String, Object>> statisticMain(ComprehensiveStatisticsParam param) {
-        List<Map<String, Object>> result = Lists.newArrayList();
-
-        if (param.getDimension() == DimensionEnum.PERSONAL.getValue()){
-            Assert.notNull(param.getId(), "按个人展示查询条件不能为空!");
-            List<CompanyDeptUserInfo> companyDeptdUserList = statisticManageMapper.getCompanyAndDeptAndDeptUserList(null);
-            //从所有数据中去匹配userId = param.getId的
-            Optional<CompanyDeptUserInfo> first = companyDeptdUserList.stream()
-                    .filter(e -> e.getUserId().equals(param.getId()))
-                    .findFirst();
-            if (!first.isPresent()) {
-                return result;
-            }
-            CompanyDeptUserInfo companyDeptUserInfo = first.get();
-            Map<String, Object> map = Maps.newHashMap();
-            map.put("id", companyDeptUserInfo.getUserId());
-            map.put("name", companyDeptUserInfo.getNickName());
-            List<ComprehensiveStatisticsDTO> statisticNumByPersonal =
-                    getStatisticNumByPersonal(DimensionEnum.PERSONAL.getValue(), param.getStartTime(), param.getEndTime(), param.getId());
-            map.put("list", statisticNumByPersonal);
-            result.add(map);
-            return result;
-        }
+    public Object statisticMain(ComprehensiveStatisticsParam param) {
         if(param.getDimension() == DimensionEnum.COMPANY.getValue()){
-            //按照公司统计,如果id为空就要展示全部公司,如果不为空就展示id查询的公司
-            if(ObjectUtil.isEmpty(param.getId())){
-                //得到所有公司信息
-                List<CompanyDeptUserInfo> companyInfo = statisticManageMapper.getCompanyInfo();
-                for (CompanyDeptUserInfo companyDeptUserInfo : companyInfo){
-                    getStatisticNumByPersonal(DimensionEnum.COMPANY.getValue(), param.getStartTime(), param.getEndTime(),
-                            companyDeptUserInfo.getCompanyId());
-                }
-            }
+            Assert.notNull(param.getId(), "按公司展示查询条件不能为空!");
+            return getStatisticNumByCompanyId(param.getStartTime(), param.getEndTime(), param.getId());
         }
         if(param.getDimension() == DimensionEnum.DEPARTMENT.getValue()){
-            Assert.notNull(param.getId(), "按部门展示公司不能为空!");
-            List<CompanyDeptUserInfo> companyDeptdUserList = statisticManageMapper.getCompanyAndDeptAndDeptUserList(param.getId());
-            //按照部门分组
-            Map<Long, List<CompanyDeptUserInfo>> deptInfos = companyDeptdUserList.stream()
-                    .collect(Collectors.groupingBy(CompanyDeptUserInfo::getDeptId));
-            deptInfos.forEach((deptId, companyDeptUserInfos) -> {
-                Long[] userIds = companyDeptUserInfos.stream().map(CompanyDeptUserInfo::getUserId).toArray(Long[]::new);
-                getStatisticNumByPersonal(DimensionEnum.PERSONAL.getValue(), param.getStartTime(), param.getEndTime(),userIds);
-            });
+            Assert.notNull(param.getId(), "按部门展示查询条件不能为空!");
+            return getStatisticNumByDeptId(param.getStartTime(), param.getEndTime(), param.getId());
+        }
+        if (param.getDimension() == DimensionEnum.PERSONAL.getValue()){
+            Assert.notNull(param.getId(), "按个人展示查询条件不能为空!");
+            return getStatisticNumByPersonal(DimensionEnum.PERSONAL.getValue(), param.getStartTime(), param.getEndTime(), param.getId());
         }
         return null;
     }
 
+    /**
+     * 获取个人统计数据
+     * @param dimension 维度
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param userIds 用户id
+     * @return
+     */
+    public List<ComprehensiveDailyStats> getStatisticNumByPersonal(Integer dimension, Date startTime, Date endTime, Long... userIds) {
+        return statisticManageMapper.getStatisticNumByPersonal(dimension, startTime, endTime, userIds);
+    }
+
+    /**
+     * 获取部门统计数据
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param deptId 用户id
+     * @return
+     */
+    public List<ComprehensiveDailyStats> getStatisticNumByDeptId(Date startTime, Date endTime, Long... deptId) {
+        return statisticManageMapper.getStatisticNumByDeptId(startTime, endTime, deptId);
+    }
+
+    /**
+     * 获取部门统计数据
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param deptId 用户id
+     * @return
+     */
+    public List<ComprehensiveDailyStats> getStatisticNumByCompanyId(Date startTime, Date endTime, Long... deptId) {
+        return statisticManageMapper.getStatisticNumByCompanyId(startTime, endTime, deptId);
+    }
+
+
+
+
+    /**
+     * 执行定时任务
+     * 还需要考虑在统计部门数据时,部门下面没有用户,某个时候这个部门下面又加入新的用户了,这个时候就会出现数据偏差
+     */
     @Override
     public void executeTask() {
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start("gs-执行数据统计任务");
         List<CompanyDeptUserInfo> companyDeptdUserList = statisticManageMapper.getCompanyAndDeptAndDeptUserList(null);
         companyDeptdUserList.forEach(companyDeptUserInfo -> {
             CompanyDeptUserInfoDTO statisticNum =  new CompanyDeptUserInfoDTO();
-            if(null != companyDeptUserInfo.getUserId()){
+            boolean empty = null == companyDeptUserInfo.getUserId(); //用户id为空返回true
+            if(!empty){
                 statisticNum = statisticManageMapper.getStatisticNum(companyDeptUserInfo.getUserId());
             }
             ComprehensiveDailyStats comprehensiveDailyStats = component(companyDeptUserInfo, statisticNum);
-            statisticManageMapper.insert(comprehensiveDailyStats);
+            ComprehensiveDailyStats selectResult = null;
+            if(!empty){
+                //用户id不为空,我们就用用户id去查询这个日期是否有数据
+                selectResult = statisticManageMapper.selectByUserAndDate(comprehensiveDailyStats.getUserId(), comprehensiveDailyStats.getStatisticsTime());
+            }else{
+                //如果用户id为空,说明部门下面没有人(没人情况下,部门id只会在当天的日期中存在一条),先按照部门去查询后删除(或者直接按照id更新就可以了)
+                selectResult = statisticManageMapper.selectByDeptAndDate(companyDeptUserInfo.getDeptId(), comprehensiveDailyStats.getStatisticsTime());
+            }
+            if(!ObjectUtils.isEmpty(selectResult)){
+                comprehensiveDailyStats.setId(selectResult.getId());
+                statisticManageMapper.updateById(comprehensiveDailyStats);
+            }else{
+                statisticManageMapper.insert(comprehensiveDailyStats);
+            }
         });
-    }
-
-    /**
-     * 获取统计数据
-     * @param dimension 维度
-     * @param startTime 开始时间
-     * @param endTime 结束时间
-     * @param userIds 用户id
-     * @return
-     */
-    public List<ComprehensiveStatisticsDTO> getStatisticNumByPersonal(Integer dimension, Date startTime, Date endTime, Long... userIds) {
-       return statisticManageMapper.getStatisticNumByPersonal(dimension, startTime, endTime, userIds);
+        stopWatch.stop();
+        log.info("gs-执行数据统计任务完成,耗时:{}", stopWatch.getTotalTimeSeconds());
     }
 
     private ComprehensiveDailyStats component(CompanyDeptUserInfo source, CompanyDeptUserInfoDTO statisticNum){

+ 2 - 1
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -347,7 +347,8 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
     @Select("SELECT * FROM fs_course_watch_log  WHERE  DATE(create_time) = CURDATE() and video_id in (select video_id from fs_user_course_video WHERE is_first=1 ) ")
     List<FsQwCourseWatchLogVO> selectFsCourseWatchLogByVideoId();
 
-    @Select("SELECT qw_external_contact_id FROM fs_course_watch_log  WHERE log_type=2 and DATE(create_time) = CURDATE() ")
+    @Select("SELECT qw_external_contact_id FROM fs_course_watch_log  WHERE log_type=2 AND create_time >= CURDATE()\n" +
+            "  AND create_time < DATE_ADD(CURDATE(), INTERVAL 1 DAY) ")
     List<Long> selectFsCourseWatchLogByFinish();
     @Select("select * from fs_course_watch_log " +
             "where video_id = #{videoId} " +

+ 7 - 4
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -496,10 +496,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return R.error(504,"未授权");
         }
 
-        if (StringUtil.strIsNullOrEmpty(fsUser.getMpOpenId())){
-            return R.error(401,"授权后可继续!");
-        }
-
         if (fsUser.getStatus()==0){
             return R.error("会员被停用,无权限,请联系客服!");
         }
@@ -534,6 +530,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+
+        //服务号授权的,缺mpOpenId的重新登录
+        if (config.getMiniAppAuthType()==2 && StringUtil.strIsNullOrEmpty(fsUser.getMpOpenId())){
+            return R.error(401,"授权后可继续!");
+        }
+
         boolean oneCompanyCourse = config.isOneCompanyCourse();
         if(oneCompanyCourse && fsUser.getQwExtId() != null){
             QwExternalContact qwExternalContact = qwExternalContactMapper.selectById(fsUser.getQwExtId());

+ 8 - 2
fs-service/src/main/java/com/fs/wxwork/service/WxWorkServiceImpl.java

@@ -120,8 +120,14 @@ public class WxWorkServiceImpl implements WxWorkService {
     @Override
     public WxWorkResponseDTO<WxwLoginOutRespDTO> LoginOut(WxWorkGetQrCodeDTO param,Long serverId) {
         String url = getUrl(serverId) + "/LoginOut";
-        return WxWorkHttpUtil.postWithType(url, param, new TypeReference<WxWorkResponseDTO<WxwLoginOutRespDTO>>() {
-        });
+        try {
+            return WxWorkHttpUtil.postWithType(url, param, new TypeReference<WxWorkResponseDTO<WxwLoginOutRespDTO>>() {
+            });
+        }catch (Exception e){
+            log.error("LoginOut error",e);
+            return null;
+        }
+
     }
 
     @Override

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

@@ -291,4 +291,5 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{company.companyId}
         </foreach>
     </update>
+
 </mapper>

+ 51 - 176
fs-service/src/main/resources/mapper/company/StatisticManageMapper.xml

@@ -58,173 +58,6 @@
         SELECT * FROM t1,t2,t3,t4,t5
     </select>
 
-    <select id="getStatisticNumByPersonal" resultType="com.fs.company.dto.ComprehensiveStatisticsDTO">
-        WITH RECURSIVE date_range AS (
-            SELECT #{startTime} AS dt
-            UNION ALL
-            SELECT DATE_ADD(dt, INTERVAL 1 DAY)
-            FROM date_range
-            WHERE dt &lt; #{endTime}
-        ),
-        t1 AS (
-            SELECT
-            COUNT(qec.id) AS t1_count,
-            d.dt AS create_time
-            FROM date_range d
-            LEFT JOIN qw_external_contact qec
-            ON DATE(qec.create_time) = d.dt
-        <if test="userIds != null">
-            <if test="dimension == 1">
-                <choose>
-                    <when test="userIds.length > 1 ">
-                        AND qec.company_user_id IN (
-                        <foreach collection="userIds" item="i" separator=",">
-                            #{i}
-                        </foreach>
-                        )
-                    </when>
-                    <otherwise>
-                        AND qec.company_user_id = #{userIds[0]}
-                    </otherwise>
-                </choose>
-            </if>
-            <if test="dimension == 2">
-                AND qec.company_id = #{userIds[0]}
-            </if>
-        </if>
-            GROUP BY d.dt
-        ),
-        t2 AS (
-            SELECT
-            COUNT(qec.id) AS t2_count,
-            d.dt AS create_time
-            FROM date_range d
-            LEFT JOIN qw_external_contact qec
-            ON DATE(qec.create_time) = d.dt
-        <if test="userIds != null">
-            <if test="dimension == 1">
-                <choose>
-                    <when test="userIds.length > 1 ">
-                        AND qec.company_user_id IN (
-                        <foreach collection="userIds" item="i" separator=",">
-                            #{i}
-                        </foreach>
-                        )
-                    </when>
-                    <otherwise>
-                        AND qec.company_user_id = #{userIds[0]}
-                    </otherwise>
-                </choose>
-            </if>
-            <if test="dimension == 2">
-                AND qec.company_id = #{userIds[0]}
-            </if>
-        </if>
-            AND qec.fs_user_id IS NOT NULL
-            GROUP BY d.dt
-        ),
-        t4 AS (
-            SELECT
-            d.dt AS create_time,
-            COUNT(fcwl.qw_external_contact_id) AS completeNum
-            FROM
-            date_range d
-            LEFT JOIN fs_course_watch_log AS fcwl
-            ON DATE(fcwl.create_time) = d.dt
-            AND fcwl.log_type = 2
-        <if test="userIds != null">
-            <if test="dimension == 1">
-                <choose>
-                    <when test="userIds.length > 1 ">
-                        AND fcwl.company_user_id IN (
-                        <foreach collection="userIds" item="i" separator=",">
-                            #{i}
-                        </foreach>
-                        )
-                    </when>
-                    <otherwise>
-                        AND fcwl.company_user_id = #{userIds[0]}
-                    </otherwise>
-                </choose>
-            </if>
-            <if test="dimension == 2">
-                AND fcwl.company_id = #{userIds[0]}
-            </if>
-        </if>
-            GROUP BY d.dt
-        ),
-        t5 AS (
-            SELECT
-            d.dt AS create_time,
-            COUNT(fcal.log_id) AS answerNum
-            FROM
-            date_range d
-            LEFT JOIN fs_course_answer_logs AS fcal
-            ON DATE(fcal.create_time) = d.dt
-        <if test="userIds != null">
-            <if test="dimension == 1">
-                <choose>
-                    <when test="userIds.length > 1 ">
-                        AND fcal.company_user_id IN (
-                        <foreach collection="userIds" item="i" separator=",">
-                            #{i}
-                        </foreach>
-                        )
-                    </when>
-                    <otherwise>
-                        AND fcal.company_user_id = #{userIds[0]}
-                    </otherwise>
-                </choose>
-            </if>
-            <if test="dimension == 2">
-                AND fcal.company_id = #{userIds[0]}
-            </if>
-        </if>
-            GROUP BY d.dt
-        ),
-        t6 AS (
-            SELECT
-            d.dt AS create_time,
-            COUNT(fcrpl.log_id) AS redPacketNum
-            FROM
-            date_range d
-            LEFT JOIN fs_course_red_packet_log AS fcrpl
-            ON DATE(fcrpl.create_time) = d.dt
-        <if test="userIds != null">
-            <if test="dimension == 1">
-                <choose>
-                    <when test="userIds.length > 1 ">
-                        AND fcrpl.company_user_id IN (
-                        <foreach collection="userIds" item="i" separator=",">
-                            #{i}
-                        </foreach>
-                        )
-                    </when>
-                    <otherwise>
-                        AND fcrpl.company_user_id = #{userIds[0]}
-                    </otherwise>
-                </choose>
-            </if>
-            <if test="dimension == 2">
-                AND fcrpl.company_id = #{userIds[0]}
-            </if>
-        </if>
-            GROUP BY d.dt
-        )
-        SELECT
-            t1.create_time as dateStr,
-            t1.t1_count as lineNum,
-            t2.t2_count as activeNum,
-            t4.completeNum,
-            t5.answerNum,
-            t6.redPacketNum
-        FROM t1
-        INNER JOIN t2 ON t1.create_time = t2.create_time
-        INNER JOIN t4 ON t1.create_time = t4.create_time
-        INNER JOIN t5 ON t1.create_time = t5.create_time
-        INNER JOIN t6 ON t1.create_time = t6.create_time
-        ORDER BY t1.create_time
-    </select>
 
     <select id="getCompanyInfo" resultType="com.fs.company.domain.CompanyDeptUserInfo">
         SELECT
@@ -244,6 +77,33 @@
         red_packet_num, red_packet_amount, create_time, update_time
     </sql>
 
+    <select id="getStatisticNumByPersonal" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        select <include refid="Base_Column_List"/> from user_daily_stats as uds
+        <where>
+            uds.user_id = #{userIds[0]}
+            and statistics_time >=date_format(#{startTime},'%y%m%d')
+            and statistics_time &lt;= date_format(#{endTime},'%y%m%d')
+        </where>
+    </select>
+
+    <select id="getStatisticNumByDeptId" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        select <include refid="Base_Column_List"/> from user_daily_stats as uds
+        <where>
+            uds.dept_id = #{deptIds[0]}
+            and statistics_time >=date_format(#{startTime},'%y%m%d')
+            and statistics_time &lt;= date_format(#{endTime},'%y%m%d')
+        </where>
+    </select>
+
+    <select id="getStatisticNumByCompanyId" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        select <include refid="Base_Column_List"/> from user_daily_stats as uds
+        <where>
+            uds.company_id = #{companyIds[0]}
+            and statistics_time >=date_format(#{startTime},'%y%m%d')
+            and statistics_time &lt;= date_format(#{endTime},'%y%m%d')
+        </where>
+    </select>
+
     <!-- 1. 插入数据(全字段插入) -->
     <insert id="insert" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
         INSERT INTO user_daily_stats (
@@ -259,7 +119,7 @@
         )
     </insert>
 
-    <!-- 2. 插入或更新(根据唯一索引uk_user_date,存在则更新,不存在则插入) -->
+    <!-- 2. 插入或更新(根据唯一索引uk_user_date,存在则更新,不存在则插入) 已经删除了索引,有时候用户id是空的 -->
     <insert id="insertOrUpdate" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
         INSERT INTO user_daily_stats (
             company_id, company_name, dept_id, dept_name,
@@ -320,7 +180,7 @@
             red_packet_num = #{redPacketNum},
             red_packet_amount = #{redPacketAmount},
             update_time = NOW()
-        WHERE user_id = #{userId} AND statistics_time = #{statisticsTime}
+        WHERE user_id = #{userId} AND statistics_time = date_format(#{statisticsTime},'%y%m%d')
     </update>
 
     <!-- 5. 根据ID查询 -->
@@ -332,16 +192,22 @@
     <select id="selectByUserAndDate" resultType="com.fs.company.domain.ComprehensiveDailyStats">
         SELECT <include refid="Base_Column_List"/>
         FROM user_daily_stats
-        WHERE user_id = #{userId} AND statistics_time = #{statisticsTime}
+        WHERE user_id = #{userId} AND statistics_time =date_format(#{statisticsTime},'%y%m%d')
     </select>
 
-    <!-- 7. 根据公司ID和日期范围查询 -->
-    <select id="selectByCompanyAndDateRange" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+    <!-- 6. 根据用户ID和统计日期查询 -->
+    <select id="countByUserAndDate" resultType="java.lang.Integer">
+        SELECT count(id)
+        FROM user_daily_stats
+        WHERE user_id = #{userId} AND statistics_time = date_format(#{statisticsTime},'%y%m%d')
+    </select>
+
+    <!-- 8. 根据部门ID和日期查询 -->
+    <select id="selectByDeptAndDate" resultType="com.fs.company.domain.ComprehensiveDailyStats">
         SELECT <include refid="Base_Column_List"/>
         FROM user_daily_stats
-        WHERE company_id = #{companyId}
-        AND statistics_time BETWEEN #{startTime} AND #{endTime}
-        ORDER BY statistics_time ASC
+        WHERE dept_id = #{deptId}
+        AND statistics_time = date_format(#{statisticsTime},'%y%m%d')
     </select>
 
     <!-- 8. 根据部门ID和日期范围查询 -->
@@ -353,6 +219,15 @@
         ORDER BY statistics_time ASC
     </select>
 
+    <!-- 7. 根据公司ID和日期范围查询 -->
+    <select id="selectByCompanyAndDateRange" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        SELECT <include refid="Base_Column_List"/>
+        FROM user_daily_stats
+        WHERE company_id = #{companyId}
+        AND statistics_time BETWEEN #{startTime} AND #{endTime}
+        ORDER BY statistics_time ASC
+    </select>
+
     <!-- 9. 删除数据(根据ID) -->
     <delete id="deleteById" parameterType="java.lang.Long">
         DELETE FROM user_daily_stats WHERE id = #{id}
@@ -360,7 +235,7 @@
 
     <!-- 10. 删除数据(根据用户ID和统计日期) -->
     <delete id="deleteByUserAndDate">
-        DELETE FROM user_daily_stats WHERE user_id = #{userId} AND statistics_time = #{statisticsTime}
+        DELETE FROM user_daily_stats WHERE user_id = #{userId} AND statistics_time = date_format(#{statisticsTime},'%y%m%d')
     </delete>
 
 </mapper>

+ 3 - 2
fs-service/src/main/resources/mapper/course/FsCourseLinkMapper.xml

@@ -135,7 +135,7 @@
         link, real_link, create_time, update_time,
         company_id, company_user_id, qw_user_id, video_id,
         corp_id, course_id, qw_external_id, link_type,
-        is_room
+        is_room,chat_id
         )
         VALUES
         <foreach collection="courseLinks" item="item" separator=",">
@@ -152,7 +152,8 @@
             #{item.courseId,jdbcType=BIGINT},
             #{item.qwExternalId,jdbcType=BIGINT},
             #{item.linkType,jdbcType=BIGINT},
-            #{item.isRoom,jdbcType=VARCHAR}
+            #{item.isRoom,jdbcType=VARCHAR},
+            #{item.chatId,jdbcType=VARCHAR}
             )
         </foreach>
     </insert>

+ 2 - 1
fs-service/src/main/resources/mapper/course/FsCourseTrafficLogMapper.xml

@@ -72,7 +72,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         FROM
         fs_course_traffic_log
         <where>
-            DATE(create_time) = CURDATE() - INTERVAL 1 DAY
+            create_time  &gt;= CURDATE() - INTERVAL 1 DAY
+            AND create_time &lt; CURDATE()
             <if test="companyId != null">
                 AND company_id = ${companyId}
             </if>

+ 2 - 1
fs-service/src/main/resources/mapper/qw/HyWorkTaskMapper.xml

@@ -101,7 +101,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 INNER JOIN
             fs_user_course_video fucv ON fcl.video_id = fucv.video_id
         WHERE
-            DATE(fcl.create_time) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
+        fcl.create_time  &gt;= DATE_SUB(CURDATE(), INTERVAL 1 DAY)
+        AND fcl.create_time &lt; CURDATE()
           AND (
             fcl.log_type = 4 -- 看课中断
            OR

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

@@ -212,8 +212,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         JOIN
         qw_user qu ON qec.qw_user_id = qu.id
         WHERE
-        DATE(qec.create_time) &gt;= DATE(#{sTime})
-        AND DATE(qec.create_time) &lt;= DATE(#{eTime})
+        qec.create_time &gt;= #{sTime}
+        AND qec.create_time &lt; DATE_ADD(#{eTime}, INTERVAL 1 DAY)
         AND qec.company_id = #{companyId}
         <if test='nickName != null and nickName != ""'>
             AND qu.qw_user_name LIKE CONCAT(#{nickName}, '%')

+ 219 - 1
fs-user-app/src/main/java/com/fs/app/controller/store/CompanyUserScrmController.java

@@ -5,38 +5,64 @@ import cn.hutool.core.img.ImgUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.extra.qrcode.QrCodeUtil;
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.controller.AppBaseController;
 import com.fs.app.param.FsBindCompanyUserParam;
 import com.fs.common.config.FSConfig;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.CustomException;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.sign.Md5Utils;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.domain.CompanyUserCard;
 import com.fs.company.domain.CompanyUserUser;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.param.CompanyUserLoginParam;
+import com.fs.company.param.companyUserAddPrintParam;
 import com.fs.company.service.ICompanyUserCardService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.service.ICompanyUserUserService;
+import com.fs.config.ai.AiHostProper;
+import com.fs.fastGpt.domain.FastgptChatVoiceHomo;
+import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
+import com.fs.fastgptApi.util.AudioUtils;
+import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.framework.security.SecurityUtils;
 import com.fs.his.dto.PayConfigDTO;
+import com.fs.his.service.IFsPrescribeService;
+import com.fs.sop.domain.QwSopTempVoice;
+import com.fs.sop.service.IQwSopTempVoiceService;
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.io.FileUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static com.fs.app.controller.CompanyUserController.SOP_TEMP_VOICE_KEY;
 
 
 @Api("销售中心")
@@ -58,6 +84,19 @@ public class CompanyUserScrmController extends AppBaseController {
     @Autowired
     private ICompanyUserUserService companyUserUserService;
 
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Autowired
+    private IFsPrescribeService fsPrescribeService;
+    @Autowired
+    private IQwSopTempVoiceService voiceService;
+    @Autowired
+    private FastgptChatVoiceHomoMapper fastgptChatVoiceHomoMapper;
+    @Autowired
+    AiHostProper aiHostProper;
+
     @PostMapping("/login")
     public R Login(@RequestBody CompanyUserLoginParam param, HttpServletRequest request){
         try {
@@ -122,7 +161,21 @@ public class CompanyUserScrmController extends AppBaseController {
         return R.ok().put("data",companyUserCard);
     }
 
-    @Login
+    @GetMapping("/query/{id}")
+    public R querySopVoiceById(@PathVariable("id") Long id){
+        QwSopTempVoice tempVoice = voiceService.selectQwSopTempVoiceById(id);
+        AudioVO audioVO = new AudioVO();
+        if(tempVoice != null){
+            audioVO.setId(tempVoice.getId());
+            audioVO.setVoiceTxt(tempVoice.getVoiceTxt());
+            audioVO.setUrl(tempVoice.getVoiceUrl());
+            audioVO.setWavUrl(tempVoice.getUserVoiceUrl());
+            audioVO.setDuration(tempVoice.getDuration());
+            audioVO.setRecordType(tempVoice.getRecordType());
+        }
+        return R.ok().put("data", audioVO);
+    }
+
     @ApiOperation("获取支付宝收款码")
     @GetMapping("/getQrImg")
     public R getQrImg(@RequestParam("token")String token,HttpServletRequest request){
@@ -219,5 +272,170 @@ public class CompanyUserScrmController extends AppBaseController {
     }
 
 
+    @ApiOperation("上传声纹")
+    @PostMapping("/addVoicePrintUrl")
+    public R addVoicePrintUrl(@RequestBody companyUserAddPrintParam param) throws Exception {
+        Long userId=param.getCompanyUserId();
+        CompanyUser companyUser = new CompanyUser();
+        companyUser.setUserId(userId);
+        companyUser.setVoicePrintUrl(param.getVoicePrintUrl());
+
+        //转换音频格式 mp3-wav
+        String s = AudioUtils.audioWAVFromUrl(param.getVoicePrintUrl());
+
+        //保存文件并且上传存储桶
+        System.out.println(s);
+        File file = new File(s);
+        FileInputStream fileInputStream = new FileInputStream(file);
+        CloudStorageService storage = OSSFactory.build();
+        String wavUrl = storage.uploadSuffix(fileInputStream, ".wav");
+
+        //更新销售员工声纹
+        companyUser.setVoicePrintUrl(wavUrl);
+        companyUserMapper.updateCompanyUser(companyUser);
+
+        try {
+            CloseableHttpClient httpClient = HttpClients.createDefault();
+            HttpPost httpPost = new HttpPost(aiHostProper.getCommonApi()+"/app/common/addCompanyAudio");
+            String json = "{\"url\":\""+wavUrl+"\",\"id\":\""+userId+"\"}";
+            StringEntity entity = new StringEntity(json);
+            httpPost.setEntity(entity);
+            httpPost.setHeader("Content-type", "application/json");
+            HttpResponse response = httpClient.execute(httpPost);
+
+            if (response.getStatusLine().getStatusCode() == 200) {
+                String responseBody = EntityUtils.toString(response.getEntity());
+                JSONObject jsonObject = JSON.parseObject(responseBody);
+                Integer code = (Integer)jsonObject.get("code");
+                if (code==200){
+                    voiceService.insertQwSopTempVoiceModel(userId);
+                    return R.ok();
+                }
+            } else {
+                return R.error();
+            }
+
+            httpClient.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return R.error();
+
+    }
+
+    @GetMapping("/querySopVoiceList")
+    public TableDataInfo querySopVoiceList(@RequestParam("companyUserId")Long companyUserId,@RequestParam("recordType") Integer recordType){
+        startPage();
+        QwSopTempVoice sopTempVoice = new QwSopTempVoice();
+        sopTempVoice.setRecordType(recordType);
+
+        Long userId=companyUserId;
+        sopTempVoice.setCompanyUserId(userId);
+        List<QwSopTempVoice> sopTempVoices = voiceService.selectQwSopTempVoiceNewList(sopTempVoice);
+        return getDataTable(sopTempVoices);
+    }
+
+    @GetMapping("/createUserAllVoice")
+    public R createUserAllVoice(@RequestParam("companyUserId")Long companyUserId){
+        QwSopTempVoice sopTempVoice = new QwSopTempVoice();
+        sopTempVoice.setRecordType(0);
+
+        if(companyUserId==null){
+            throw  new CustomException("未登录",403);
+        }
+
+        if(companyUserId != null){
+            CompanyUser companyUser = companyUserMapper.selectCompanyUserByCompanyUserId(companyUserId);
+            if(companyUser != null && companyUser.getVoicePrintUrl() == null){
+                return R.ok().put("code",201).put("msg","账号未录制声纹,请录制后再试!");
+            }
+        }
+
+        sopTempVoice.setCompanyUserId(companyUserId);
+        List<QwSopTempVoice> sopTempVoices = voiceService.selectQwSopTempVoiceNewList(sopTempVoice);
+        if(sopTempVoices != null && !sopTempVoices.isEmpty()){
+            List<Long> newCompanyUserId = redisCache.getVoiceAllList(SOP_TEMP_VOICE_KEY);
+            if(newCompanyUserId != null && newCompanyUserId.contains(companyUserId)){
+                return R.error().put("code",202).put("msg","语音还未转换完成,请完成后再添加!");
+            }else{
+                redisCache.setVoice(SOP_TEMP_VOICE_KEY,companyUserId);
+                sopTempVoices.forEach(m -> m.setVoiceTxt(m.getVoiceTxt().replace(" ","")));
+                redisCache.setVoiceList(SOP_TEMP_VOICE_KEY + ":" + companyUserId, sopTempVoices);
+                return R.ok().put("msg","语音已加入队列进行转换,请耐心等待!");
+            }
+        }
+        return null;
+    }
+
+
+    @GetMapping("/companyUserVoice")
+    public R companyUserVoice(@RequestParam("companyUserId")Long companyUserId,@RequestParam("id") Long id){
+        AudioVO audioVO = new AudioVO();
+
+
+        List<QwSopTempVoice> sopTempVoices = redisCache.getVoiceAllList(SOP_TEMP_VOICE_KEY + ":" + companyUserId);
+        if(sopTempVoices != null && !sopTempVoices.isEmpty()){
+            List<Long> collect = sopTempVoices.stream().map(QwSopTempVoice::getId).collect(Collectors.toList());
+            if (collect.contains(id)){
+                return R.ok().put("code",202).put("msg","该语音已进入转换,请完成后再试。");
+            }
+        }
+
+        if(companyUserId != null){
+            CompanyUser companyUser = companyUserMapper.selectCompanyUserByCompanyUserId(companyUserId);
+            if(companyUser != null && companyUser.getVoicePrintUrl() == null){
+                return R.ok().put("code",201).put("msg","账号未录制声纹,请录制后再试!");
+            }
+        }
+
+        QwSopTempVoice qwSopTempVoice = voiceService.selectQwSopTempVoiceById(id);
+        if(qwSopTempVoice != null && qwSopTempVoice.getCompanyUserId() != null){
+            List<FastgptChatVoiceHomo> homos = fastgptChatVoiceHomoMapper.selectFastgptChatVoiceHomoList(new FastgptChatVoiceHomo());
+            audioVO = AudioUtils.createUserUrlAndUrl(homos,qwSopTempVoice.getCompanyUserId(), qwSopTempVoice.getVoiceTxt().replace(" ",""));
+            if(audioVO != null && audioVO.getWavUrl() != null &&  audioVO.getUrl() != null){
+                qwSopTempVoice.setVoiceUrl(audioVO.getUrl());
+                qwSopTempVoice.setUserVoiceUrl(audioVO.getWavUrl());
+                qwSopTempVoice.setDuration(audioVO.getDuration());
+                qwSopTempVoice.setRecordType(1);
+                voiceService.updateQwSopTempVoice(qwSopTempVoice);
+            }
+        }
+        return R.ok().put("data", audioVO);
+    }
+
+    /**
+     * 当只有user_voice_url时,生成表中对应条的voice_url
+     * @param userVoiceUrl  wav格式的语音文件
+     * @param id            qw_sop_temp_voice的id
+     * @return
+     */
+    @GetMapping("/companyUserVoiceNew")
+    public R companyUserVoiceNew( @RequestParam("companyUserId")Long companyUserId,@RequestParam("id") Long id,@RequestParam("userVoiceUrl") String userVoiceUrl){
+
+        AudioVO audioVO = new AudioVO();
+
+        List<QwSopTempVoice> sopTempVoices = redisCache.getVoiceAllList(SOP_TEMP_VOICE_KEY + ":" + companyUserId);
+        if(sopTempVoices != null && !sopTempVoices.isEmpty()){
+            List<Long> collect = sopTempVoices.stream().map(QwSopTempVoice::getId).collect(Collectors.toList());
+            if (collect.contains(id)){
+                return R.ok().put("code",202).put("msg","该语音已进入转换,请完成后再试。");
+            }
+        }
+
+        QwSopTempVoice qwSopTempVoice = voiceService.selectQwSopTempVoiceByIdAndUserVoiceUrl(id);
+        if(qwSopTempVoice != null && qwSopTempVoice.getId() != null){
+            audioVO = AudioUtils.createVoiceUrl(qwSopTempVoice.getCompanyUserId(), userVoiceUrl);
+            if(audioVO != null && audioVO.getUrl() != null){
+                qwSopTempVoice.setVoiceUrl(audioVO.getUrl());
+                qwSopTempVoice.setUserVoiceUrl(userVoiceUrl);
+                qwSopTempVoice.setDuration(audioVO.getDuration());
+                qwSopTempVoice.setRecordType(1);
+                voiceService.updateQwSopTempVoice(qwSopTempVoice);
+            }
+        }
+        return R.ok().put("data", audioVO);
+    }
+
 
 }