Ver Fonte

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java

caoliqin há 1 semana atrás
pai
commit
3b5a65a4c1
34 ficheiros alterados com 644 adições e 212 exclusões
  1. 1 1
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  2. 35 0
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java
  3. 20 13
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyRechargeController.java
  4. 16 4
      fs-admin/src/main/java/com/fs/his/task/CompanyBalanceTask.java
  5. 1 0
      fs-common/src/main/java/com/fs/common/constant/FsConstants.java
  6. 43 0
      fs-company/src/main/java/com/fs/company/controller/company/FsRedPacketController.java
  7. 1 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java
  8. 1 1
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  9. 5 0
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/QwExternalContactRatingServiceImpl.java
  10. 1 0
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  11. 2 0
      fs-service/src/main/java/com/fs/company/domain/Company.java
  12. 3 0
      fs-service/src/main/java/com/fs/company/domain/CompanyRecharge.java
  13. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyDeptMapper.java
  14. 3 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyRechargeMapper.java
  15. 6 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  16. 139 16
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  17. 3 0
      fs-service/src/main/java/com/fs/company/vo/CompanyRechargeVO.java
  18. 2 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVO.java
  19. 8 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  20. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  21. 4 3
      fs-service/src/main/java/com/fs/course/service/impl/BalanceRollbackErrorServiceImpl.java
  22. 6 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  23. 182 154
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  24. 23 0
      fs-service/src/main/java/com/fs/his/domain/FsRedPacket.java
  25. 15 0
      fs-service/src/main/java/com/fs/his/service/IFsRedPacketService.java
  26. 45 0
      fs-service/src/main/java/com/fs/his/service/impl/FsRedPacketServiceImpl.java
  27. 3 3
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java
  28. 14 2
      fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java
  29. 1 0
      fs-service/src/main/java/com/fs/qw/param/QwWatchLogStatisticsListParam.java
  30. 36 6
      fs-service/src/main/java/com/fs/qw/service/impl/QwWatchLogServiceImpl.java
  31. 1 0
      fs-service/src/main/java/com/fs/sop/vo/SopUserLogsVo.java
  32. 8 0
      fs-service/src/main/resources/mapper/company/CompanyDeptMapper.xml
  33. 2 1
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  34. 11 8
      fs-service/src/main/resources/mapper/company/CompanyRechargeMapper.xml

+ 1 - 1
fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java

@@ -42,7 +42,7 @@ public class FsCoursePlaySourceConfigController extends BaseController {
     private final TokenService tokenService;
     private final ISysConfigService configService;
 
-    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
+//    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
     @GetMapping("/list")
     public TableDataInfo list(@RequestParam(required = false) String name,
                               @RequestParam(required = false) String appid,

+ 35 - 0
fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java

@@ -217,6 +217,41 @@ public class FsCompanyController extends BaseController {
 
     }
 
+
+    /**
+     * @Description: 红包充值功能 因公司余额的变动关联的地方太多,现在把充值红包的金额单独提出来 不合计到公司余额中
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/3 11:08
+     */
+    @PreAuthorize("@ss.hasPermi('his:company:redRecharge')")
+    @Log(title = "红包充值", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/redRecharge")
+    @Transactional
+    @RepeatSubmit
+    public R redRecharge(@RequestBody CompanyRechargeParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyRecharge redRecharge=new CompanyRecharge();
+        String orderSn =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderSn)){
+            return R.error("订单生成失败,请重试");
+        }
+        redRecharge.setRechargeNo(orderSn);
+        redRecharge.setCompanyId(param.getCompanyId());
+        redRecharge.setMoney(param.getMoney());
+        redRecharge.setCreateUserId(loginUser.getUser().getUserId());
+        redRecharge.setIsAudit(0);
+        redRecharge.setStatus(0);
+        redRecharge.setRemark(param.getRemark());
+        redRecharge.setPayType(3);
+        redRecharge.setBusinessType(1);// 红包充值
+        rechargeService.insertCompanyRecharge(redRecharge);
+        return R.ok("提交成功,等待审核");
+
+    }
+
     @PreAuthorize("@ss.hasPermi('his:company:deduct')")
     @Log(title = "企业扣款", businessType = BusinessType.INSERT)
     @PostMapping(value = "/deduct")

+ 20 - 13
fs-admin/src/main/java/com/fs/his/controller/FsCompanyRechargeController.java

@@ -137,21 +137,28 @@ public class FsCompanyRechargeController extends BaseController
         companyRecharge.setRemark(param.getRemark());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if(companyRecharge.getIsAudit()==1){
-            Company company=companyService.selectCompanyByIdForUpdate(companyRecharge.getCompanyId());
-            company.setMoney(company.getMoney().add(companyRecharge.getMoney()));
-            companyRecharge.setBalance(company.getMoney());
-            companyService.updateCompany(company);
-            //生成流水
-            CompanyMoneyLogs log=new CompanyMoneyLogs();
-            log.setCompanyId(companyRecharge.getCompanyId());
-            log.setMoney(companyRecharge.getMoney());
-            log.setRemark(companyRecharge.getRemark());
-            log.setLogsType(1);
-            log.setBalance(company.getMoney());
-            log.setCreateTime(new Date());
-            moneyLogsService.insertCompanyMoneyLogs(log);
+            if(1==companyRecharge.getBusinessType()){// 红包充值
+                // 更新红包充值余额redis字段
+                companyService.redPacketTopUpCompany(companyRecharge.getCompanyId(),companyRecharge.getMoney());
+            }else {
+                Company company=companyService.selectCompanyByIdForUpdate(companyRecharge.getCompanyId());
+                company.setMoney(company.getMoney().add(companyRecharge.getMoney()));
+                companyRecharge.setBalance(company.getMoney());
+                companyService.updateCompany(company);
+                //生成流水
+                CompanyMoneyLogs log=new CompanyMoneyLogs();
+                log.setCompanyId(companyRecharge.getCompanyId());
+                log.setMoney(companyRecharge.getMoney());
+                log.setRemark(companyRecharge.getRemark());
+                log.setLogsType(1);
+                log.setBalance(company.getMoney());
+                log.setCreateTime(new Date());
+                moneyLogsService.insertCompanyMoneyLogs(log);
+
+            }
             companyRecharge.setPayTime(new Date());
             companyRecharge.setStatus(1);
+
         }
 
         companyRecharge.setAuditTime(new Date());

+ 16 - 4
fs-admin/src/main/java/com/fs/course/task/CompanyBalanceTask.java → fs-admin/src/main/java/com/fs/his/task/CompanyBalanceTask.java

@@ -1,14 +1,13 @@
-package com.fs.course.task;
+package com.fs.his.task;
 
 import com.fs.company.service.ICompanyService;
 import com.fs.course.service.BalanceRollbackErrorService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.event.ApplicationReadyEvent;
-import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 /**
- * @description: 公司余额同步定时任务
+ * @description: 公司余额同步定时任务 (红包余额)
  * @author: Xgb
  * @createDate: 2025/10/22
  * @version: 1.0
@@ -59,6 +58,19 @@ public class CompanyBalanceTask {
 
     }
 
+    /**
+     * @Description: 每天晚上0点定时获取获取公司余额,记录到数据库中
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/4 10:43
+     */
+    public void recordRedPacketBalance() {
+        companyService.recordRedPacketBalance();
+    }
+
+
+
 
 
 }

+ 1 - 0
fs-common/src/main/java/com/fs/common/constant/FsConstants.java

@@ -14,6 +14,7 @@ public interface FsConstants {
 
     // 公司余额redis key "company:money:" + company.getCompanyId()
     String COMPANY_MONEY_KEY = "company:money:";
+    String COMPANY_MONEY_DATE_KEY = "company:money:date:";
     // 公司余额redis 锁
     String COMPANY_MONEY_LOCK = "company_money_lock:";
     // 看客统计  按公司分组 按TimeType 0-今天,1-昨天,2-本周,3-本月,4-上月;

+ 43 - 0
fs-company/src/main/java/com/fs/company/controller/company/FsRedPacketController.java

@@ -0,0 +1,43 @@
+package com.fs.company.controller.company;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.Company;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.his.domain.FsRedPacket;
+import com.fs.his.service.IFsRedPacketService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @description: 红包信息
+ * @author: Xgb
+ * @createDate: 2025/11/4
+ * @version: 1.0
+ */
+@RestController
+@RequestMapping("/his/redPacket")
+public class FsRedPacketController extends BaseController {
+
+    @Autowired
+    private IFsRedPacketService fsRedPacketService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @GetMapping("/info")
+    public R info() {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        Company company = loginUser.getCompany();
+        FsRedPacket redPacket=fsRedPacketService.getInfo(company.getCompanyId());
+        return  R.ok().put("data",redPacket);
+    }
+
+
+
+}

+ 1 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java

@@ -241,6 +241,7 @@ public class QwSopTempController extends BaseController
     }
 
     @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit') or @ss.hasPermi('qw:sopTemp:myEdit') or @ss.hasPermi('qw:sopTemp:deptEdit')")
+    @Log(title = "SOP模板天数调整", businessType = BusinessType.UPDATE)
     @PostMapping("/sortDay")
     public AjaxResult sortDay(@RequestBody List<SortDayVo> list){
         qwSopTempService.sortDay(list);

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

@@ -296,7 +296,7 @@ public class IpadSendServer {
             return false;
         }
 
-        if (qwSopLogs.getSendType() != 12 && noSop) {
+        if (qwSopLogs.getSendType() != 12 && qwSopLogs.getSendType() != 6 && noSop) {
             // 客户的信息
 //            QwExternalContactHParam contactHParam = new QwExternalContactHParam();
 //            contactHParam.setUserId(qwUser.getQwUserId().trim());

+ 5 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/impl/QwExternalContactRatingServiceImpl.java

@@ -13,6 +13,7 @@ import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.params.QwRatingConfig;
 import com.fs.sop.service.IQwSopTempDayService;
+import com.fs.sop.service.ISopUserLogsInfoService;
 import com.fs.sop.vo.QwRatingVO;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
@@ -61,6 +62,9 @@ public class QwExternalContactRatingServiceImpl implements QwExternalContactRati
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @Autowired
     private ExecutorService sopRatingExecutor;  // 自定义线程池
 
@@ -247,6 +251,7 @@ public class QwExternalContactRatingServiceImpl implements QwExternalContactRati
             CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                 try {
                     qwExternalContactMapper.batchUpdateQwExternalContact(batchList);
+                    iSopUserLogsInfoService.batchUpdateSopUserLogsInfoByLevel(batchList);
                     log.info("成功更新评级数据,起始索引: {}, 数量: {}", finalI, batchList.size());
                 } catch (Exception e) {
                     log.error("批量更新异常,批次起始索引: {}", finalI, e);

+ 1 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -298,6 +298,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             log.info("没有需要处理的 SOP 用户日志。");
             return;
         }
+        sopUserLogsVos = sopUserLogsVos.stream().filter(e -> e.getFilterMode() == 1 || (e.getFilterMode() == 2 && StringUtils.isNotEmpty(e.getChatId()))).collect(Collectors.toList());
 
         String[] array = sopUserLogsVos.stream().map(SopUserLogsVo::getChatId).filter(StringUtils::isNotEmpty).toArray(String[]::new);
         Map<String, QwGroupChat> groupChatMap = new HashMap<>();

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

@@ -136,6 +136,8 @@ public class Company extends BaseEntity
     /** 所属部门id */
     private Long deptId;
 
+    private BigDecimal redPackageMoney;
+
     @TableField(exist = false)
     private List<Long> ids;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyRecharge.java

@@ -75,4 +75,7 @@ public class CompanyRecharge extends BaseEntity
 
     private String remark;
     private String imgs;
+
+    /** 业务类型 1普通 2-红包充值 */
+    private Integer businessType;
 }

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

@@ -118,4 +118,6 @@ public interface CompanyDeptMapper
     CompanyDept selectDeptNameBydeptName(@Param("deptName") String deptName);
 
     void deleteCompanyDeptByCompanyIds(Long[] companyIds);
+
+    List<CompanyDept> selectCompanyDeptByIds(@Param("depts")List<Long> deptIds);
 }

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

@@ -150,6 +150,9 @@ public interface CompanyRechargeMapper
             "<if test = 'maps.payType != null  '> " +
             "and r.pay_type = #{maps.payType}" +
             "</if>" +
+            "<if test = 'maps.businessType != null  '> " +
+            "and r.business_type = #{maps.businessType}" +
+            "</if>" +
 
             "<if test = 'maps.createTime != null  '> " +
             "and   DATE(r.create_time) = DATE(#{maps.createTime})" +

+ 6 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyService.java

@@ -170,6 +170,12 @@ public interface ICompanyService
 
     void syncCompanyBalance();
 
+    void redPacketTopUpCompany(Long companyId, BigDecimal money);
+
+    void asyncRecordBalanceLog(Long companyId, BigDecimal money,Integer logType, BigDecimal balance, String remark);
+
+    void recordRedPacketBalance();
+
     /**
      * 批量更新公司余额
      * @param list 公司列表

+ 139 - 16
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -107,6 +107,9 @@ public class CompanyServiceImpl implements ICompanyService
     @Autowired
     private RedisCache redisCache;
 
+    @Autowired
+    private RedissonClient redissonClient;
+
     @Autowired
     private TransactionTemplate transactionTemplate;
 
@@ -678,7 +681,16 @@ public class CompanyServiceImpl implements ICompanyService
 
     @Override
     public List<CompanyVO> selectCompanyListVO(Company company) {
-        return companyMapper.selectCompanyListVO(company);
+
+        List<CompanyVO> companyVOList=companyMapper.selectCompanyListVO(company);
+        companyVOList.forEach(companyVO -> {
+            String redPackageMoney = redisCache.getCacheObject(FsConstants.COMPANY_MONEY_KEY+companyVO.getCompanyId());
+            if(redPackageMoney!=null){
+                companyVO.setRedPackageMoney(new BigDecimal(redPackageMoney));
+
+            }
+        });
+        return companyVOList;
     }
 
     @Override
@@ -1355,12 +1367,12 @@ public class CompanyServiceImpl implements ICompanyService
                             String moneyStr = redisCache.getCacheObject(FsConstants.COMPANY_MONEY_KEY + company.getCompanyId());
                             if (StringUtils.isNotEmpty(moneyStr)) {
                                 BigDecimal redisMoney = new BigDecimal(moneyStr);
-                                BigDecimal dbMoney = company.getMoney();
+                                BigDecimal dbMoney = company.getRedPackageMoney();
                                 BigDecimal amount = redisMoney.subtract(dbMoney); // 计算差额
 
                                 // 只有当余额不一致时才更新
                                 if (amount.compareTo(BigDecimal.ZERO) != 0) {
-                                    company.setMoney(redisMoney);
+                                    company.setRedPackageMoney(redisMoney);
                                     int updateResult = companyMapper.updateCompany(company);
                                     if(updateResult != 1){
                                         logger.error("更新公司余额失败,公司ID: {}", company.getCompanyId());
@@ -1368,19 +1380,9 @@ public class CompanyServiceImpl implements ICompanyService
                                     }
 
                                     // 记录余额变更日志
-                                    CompanyMoneyLogs log = new CompanyMoneyLogs();
-                                    log.setCompanyId(company.getCompanyId());
-                                    log.setRemark("同步公司余额,差额: " + amount);
-                                    log.setMoney(amount);
-                                    log.setLogsType(15);
-                                    log.setBalance(redisMoney);
-                                    log.setCreateTime(new Date());
-
-                                    int logResult = moneyLogsMapper.insertCompanyMoneyLogs(log);
-                                    if(logResult != 1){
-                                        logger.error("添加公司余额日志失败,公司ID: {}", company.getCompanyId());
-                                        throw new RuntimeException("添加公司余额日志失败");
-                                    }
+                                    String remark = "同步公司余额,差额: " + amount+"(正数为增加,负数为扣减)";
+                                    // 实际不发生交易只是从缓存同步金额到数据库中 交易金额登记为0,备注清楚同步的金额
+                                    asyncRecordBalanceLog(company.getCompanyId(),new BigDecimal(0),17,redisMoney,remark);
                                 }
                             }
                             return null;
@@ -1391,6 +1393,127 @@ public class CompanyServiceImpl implements ICompanyService
                 }));
     }
 
+    /**
+     * @Description: 红包充值
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/3 14:01
+     */
+    @Override
+    public void redPacketTopUpCompany(Long companyId, BigDecimal money) {
+
+        String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + companyId;
+
+        // 加锁:增加余额
+        RLock lock1 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + companyId);
+        boolean lockAcquired = false;
+        try {
+            if (lock1.tryLock(3, 10, TimeUnit.SECONDS)) {
+                lockAcquired = true;
+                BigDecimal originalMoney;
+                // 获取当前余额
+                String moneyStr = redisCache.getCacheObject(companyMoneyKey);
+                if (StringUtils.isNotEmpty(moneyStr)) {
+                    originalMoney = new BigDecimal(moneyStr);
+                }else {
+                    // 缓存没有值,重启系统恢复redis数据 保证数据正确性
+                    logger.error("红包余额充值获取redis余额缓存异常,异常请求参数companyId:{},money:{}",companyId,money);
+                    throw new RuntimeException("红包余额充值获取redis余额缓存异常");
+                }
+
+                // 增加余额
+                BigDecimal newMoney = originalMoney.add(money);
+                redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
+
+                // 异步登记余额添加日志
+                asyncRecordBalanceLog(companyId,money,16,newMoney,"红包充值");
+
+            } else {
+                logger.error("获取redis锁失败,异常请求参数companyId:{},money:{}",companyId,money);
+                throw new RuntimeException("服务繁忙,请稍后重试");
+            }
+        } catch (Exception e) {
+            logger.error("增加余额失败: 异常请求参数companyId:{},money:{}",companyId,money, e);
+            throw new RuntimeException("系统异常,请稍后重试");
+        }finally {
+            // 只有在成功获取锁的情况下才释放锁
+            if (lockAcquired && lock1.isHeldByCurrentThread()) {
+                try {
+                    lock1.unlock();
+                } catch (IllegalMonitorStateException e) {
+                    logger.error("尝试释放非当前线程持有的锁: 异常请求参数companyId:{},money:{}",companyId,money);
+                }
+            }
+        }
+
+
+    }
+
+
+    /**
+     * 异步登记余额添加日志  xgb
+     * @param companyId 公司ID
+     * @param money 变更金额
+     * @param balance 当前余额
+     * @param remark 备注信息
+     * @param logType 16-红包余额充值 15-红包余额扣除 17-同步公司余额
+     */
+    @Async
+    @Override
+    public void asyncRecordBalanceLog(Long companyId, BigDecimal money,Integer logType, BigDecimal balance, String remark) {
+        try {
+            CompanyMoneyLogs log = new CompanyMoneyLogs();
+            log.setCompanyId(companyId);
+            log.setRemark(remark);
+            log.setMoney(money);
+            log.setLogsType(logType); // 同步余额
+            log.setBalance(balance);
+            log.setCreateTime(new Date());
+            moneyLogsMapper.insertCompanyMoneyLogs(log);
+            logger.info("异步登记余额日志成功 - 公司ID: {}, 金额: {}, 余额: {}, 备注: {}",
+                    companyId, money, balance, remark);
+        } catch (Exception e) {
+            logger.error("异步登记余额日志失败 - 公司ID: {}, 金额: {}, 余额: {}, 备注: {}",
+                    companyId, money, balance, remark, e);
+        }
+    }
+
+    /**
+     * @Description: 每天晚上0点定时获取获取公司余额,记录到数据库中
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/4 10:51
+     */
+    @Override
+    public void recordRedPacketBalance() {
+        Company query = new Company();
+        query.setIsDel(0);
+        // 查询公司列表 同步公司余额
+        List<Company> companyList = companyMapper.selectCompanyList(query);
+        Optional.ofNullable(companyList).ifPresent(list -> list.forEach(company -> {
+            transactionTemplate.execute(status -> {
+                String time=DateUtils.getTime();
+                String moneyStr = redisCache.getCacheObject(FsConstants.COMPANY_MONEY_KEY + company.getCompanyId());
+                if (StringUtils.isNotEmpty(moneyStr)) {
+                    // 存到缓存中,有效期25小时
+                    redisCache.setCacheObject(FsConstants.COMPANY_MONEY_DATE_KEY + company.getCompanyId()+":"+DateUtils.getDate(), moneyStr, 25, TimeUnit.HOURS);
+                    // 实际不发生交易只是从缓存获取当天余额报错25小时 交易金额登记为0,备注清楚同步的金额
+                    String remark = "时间:" + time +",当前公司余额,金额: " + moneyStr;
+                    BigDecimal money = new BigDecimal(moneyStr);
+                    asyncRecordBalanceLog(company.getCompanyId(),new BigDecimal(0),18,money,remark);
+                }
+                return null;
+            });
+
+
+        }));
+
+
+    }
+
+
     @Override
     public void batchUpdateCompany(List<Company> list) {
         companyMapper.batchUpdateCompany(list);

+ 3 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyRechargeVO.java

@@ -85,6 +85,9 @@ public class CompanyRechargeVO implements Serializable {
     @Excel(name = "备注")
     private String remark;
 
+    /** 业务类型 0-普通 1-红包充值 */
+    private Integer businessType;
+
 
 
 }

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

@@ -95,4 +95,6 @@ public class CompanyVO implements Serializable
     private Integer usedNum;
     /** 所属部门id */
     private Long deptId;
+
+    private BigDecimal redPackageMoney;
 }

+ 8 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -79,11 +79,19 @@ public class CourseConfig implements Serializable {
      */
     private boolean oneCompanyCourse;
 
+    //
+    private boolean moreCompanyCourse;
+
     /**
      * 是否开启IM
      */
     private Boolean isOpenIM;
 
+    /**
+     * 是否红包余额抵扣 1是 0否
+     */
+    private String isRedPackageBalanceDeduction;
+
 
     @Data
     public static class DisabledTimeVo{

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

@@ -103,5 +103,6 @@ public class FsCourseWatchLogListParam implements Serializable {
      */
     private String qwUserName;
     private Long deptId;
+    private List<Long> deptIds;
     private String ids;
 }

+ 4 - 3
fs-service/src/main/java/com/fs/course/service/impl/BalanceRollbackErrorServiceImpl.java

@@ -89,8 +89,7 @@ public class BalanceRollbackErrorServiceImpl extends ServiceImpl<BalanceRollback
     }
 
     @Override
-    // todo
-//    @EventListener(ApplicationReadyEvent.class)
+    @EventListener(ApplicationReadyEvent.class)
     public void initCompanyBalance() {
 
         // 查询公司表 Company
@@ -104,7 +103,9 @@ public class BalanceRollbackErrorServiceImpl extends ServiceImpl<BalanceRollback
             String moneyStr = redisCache.getCacheObject(companyMoneyKey);
             if (StringUtils.isEmpty(moneyStr)) {
                 // 初始化余额
-                redisCache.setCacheObject(companyMoneyKey, company.getMoney().toString());
+                if(company.getRedPackageMoney() != null){
+                    redisCache.setCacheObject(companyMoneyKey, company.getRedPackageMoney().toString());
+                }
             }
         }
     }

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

@@ -643,6 +643,12 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
 
     @Override
     public List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVO(FsCourseWatchLogListParam param) {
+
+        // 因为selectFsCourseWatchLogListVO 这个方法中查询了看课日志记录表 需要限制创建时间必传
+        if(StringUtils.isEmpty(param.getSTime()) || StringUtils.isEmpty(param.getETime())){
+            throw new RuntimeException("请输入创建时间");
+        }
+
         // 待看课-未注册
         if(ObjectUtil.equal(param.getLogType(),5)){
             param.setLogType(3);

+ 182 - 154
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -15,6 +15,7 @@ import com.fs.common.core.domain.entity.SysDictData;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.enums.BizResponseEnum;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.ServiceException;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.DateUtils;
@@ -544,6 +545,19 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return R.error(500, "该用户("+fsUser.getUserId() + ")已成为其他销售会员");
             }
         }
+
+        // 重粉问题,关闭单销售重粉检测 打开公司销售重粉检测 允许不同公司销售重粉
+        if(!oneCompanyCourse && config.isMoreCompanyCourse()){
+            QwExternalContact query=new QwExternalContact();
+            query.setFsUserId(param.getUserId());
+            query.setCompanyId(param.getCompanyId());
+            List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactList(query);
+            if(qwExternalContacts != null && !qwExternalContacts.isEmpty() && !Objects.equals(qwExternalContacts.get(0).getCompanyUserId(), param.getCompanyUserId())){
+                String msgInfo= "该用户("+fsUser.getUserId() + ")已在公司"+param.getCompanyId()+"成为其他销售会员";
+                return R.error(500, msgInfo);
+            }
+        }
+
         Integer isRoom = param.getIsRoom();
 
         // 处理逻辑
@@ -1595,174 +1609,183 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
 
-            Company company = companyMapper.selectCompanyById(param.getCompanyId());
-            BigDecimal money = company.getMoney();
-            if (money.compareTo(BigDecimal.ZERO)<=0) {
-                return R.error("服务商余额不足,请联系群主服务器充值!");
-            }
-
-            // 发送红包
-            R sendRedPacket = paymentService.sendRedPacket(packetParam);
-            if (sendRedPacket.get("code").equals(200)) {
-                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                TransferBillsResult transferBillsResult;
-                if (sendRedPacket.get("isNew").equals(1)){
-                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                    redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                    redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
-                }else {
-                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                    redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+            // 打开红包扣减功能
+            if("1".equals(config.getIsRedPackageBalanceDeduction())){
+                // 先注释 20251024 redis 余额 充值没有考虑 其余扣减没有考虑
+                // ===================== 20251022 xgb 修改 本次修改目的为了实时扣减公司余额=====================
+                // 1 使用redis缓存加锁 预扣减余额 红包发送失败 恢复redis缓存余额,如果回滚失败登记异常记录表 定时任务重新回滚余额
+                // 2 另起定时任务 同步缓存余额到redis中
+                // 3 注意!!!!! 启动系统时查询公司账户余额(这个时候要保证余额正确)启动会自动保存到redis缓存中
+                // 注意!!!!! 打开这个开关前记得检测redis缓存余额是否正确 若不正确 修改数据库字段red_package_money,删除redis缓存,重启系统,
+
+
+                // 预设值异常对象
+
+                BalanceRollbackError balanceRollbackError = new BalanceRollbackError();
+                balanceRollbackError.setCompanyId(packetParam.getCompanyId());
+                balanceRollbackError.setUserId(user.getUserId());
+                balanceRollbackError.setLogId(log.getLogId());
+                balanceRollbackError.setVideoId(log.getVideoId());
+                balanceRollbackError.setStatus(0);
+                balanceRollbackError.setMoney(amount);
+
+                if(packetParam.getCompanyId()== null){
+                    logger.error("发送红包参数错误,公司不能为空,异常请求参数{}",packetParam);
+                    return R.error("发送红包失败,请联系管理员");
                 }
-                // 添加红包记录
-                redPacketLog.setCourseId(param.getCourseId());
-                redPacketLog.setCompanyId(param.getCompanyId());
-                redPacketLog.setUserId(param.getUserId());
-                redPacketLog.setVideoId(param.getVideoId());
-                redPacketLog.setStatus(0);
-                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                redPacketLog.setCreateTime(new Date());
-                redPacketLog.setAmount(amount);
-                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                redPacketLog.setPeriodId(param.getPeriodId());
-                redPacketLog.setAppId(param.getAppId());
-
-                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-
-                // 更新观看记录的奖励类型
-                log.setRewardType(config.getRewardType());
-                courseWatchLogMapper.updateFsCourseWatchLog(log);
-
-                return sendRedPacket;
-            } else {
-                return R.error("奖励发送失败,请联系客服");
-            }
-
-            // 先注释 20251024 redis 余额 充值没有考虑 其余扣减没有考虑
-            // ===================== 20251022 xgb 修改 本次修改目的为了实时扣减公司余额=====================
-            // 1 使用redis缓存加锁 预扣减余额 红包发送失败 恢复redis缓存余额,如果回滚失败登记异常记录表 定时任务重新回滚余额
-            // 2 另起定时任务 同步缓存余额到redis中
-            // 3 启动系统时查询公司账户余额(这个时候要保证余额正确)保存到redis缓存中
-
-
-            // 预设值异常对象
-            /*
-            BalanceRollbackError balanceRollbackError = new BalanceRollbackError();
-            balanceRollbackError.setCompanyId(packetParam.getCompanyId());
-            balanceRollbackError.setUserId(user.getUserId());
-            balanceRollbackError.setLogId(log.getLogId());
-            balanceRollbackError.setVideoId(log.getVideoId());
-            balanceRollbackError.setStatus(0);
-            balanceRollbackError.setMoney(amount);
-
-            if(packetParam.getCompanyId()== null){
-                logger.error("发送红包参数错误,公司不能为空,异常请求参数{}",packetParam);
-                return R.error("发送红包失败,请联系管理员");
-            }
-            String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + packetParam.getCompanyId();
-
-            // 第一次加锁:预扣减余额
-            RLock lock1 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + packetParam.getCompanyId());
-            boolean lockAcquired = false;
-            try {
-                if (lock1.tryLock(3, 10, TimeUnit.SECONDS)) {
-                    lockAcquired = true;
-                    BigDecimal originalMoney;
-                    // 获取当前余额
-                    String moneyStr = redisCache.getCacheObject(companyMoneyKey);
-                    if (StringUtils.isNotEmpty(moneyStr)) {
-                        originalMoney = new BigDecimal(moneyStr);
-                    }else {
-                        // 缓存没有值,重启系统恢复redis数据 保证数据正确性
-                        logger.error("发送红包获取redis余额缓存异常,异常请求参数{}",packetParam);
-                        return R.error("系统异常,请稍后重试");
-                    }
+                String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + packetParam.getCompanyId();
 
-                    if (originalMoney.compareTo(BigDecimal.ZERO) < 0) {
-                        logger.error("服务商余额不足,异常请求参数{}",packetParam);
-                        return R.error("服务商余额不足,请联系群主服务器充值!");
+                // 第一次加锁:预扣减余额
+                RLock lock1 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + packetParam.getCompanyId());
+                boolean lockAcquired = false;
+                BigDecimal newMoney;
+                try {
+                    if (lock1.tryLock(3, 10, TimeUnit.SECONDS)) {
+                        lockAcquired = true;
+                        BigDecimal originalMoney;
+                        // 获取当前余额
+                        String moneyStr = redisCache.getCacheObject(companyMoneyKey);
+                        if (StringUtils.isNotEmpty(moneyStr)) {
+                            originalMoney = new BigDecimal(moneyStr);
+                        }else {
+                            // 缓存没有值,重启系统恢复redis数据 保证数据正确性
+                            logger.error("发送红包获取redis余额缓存异常,异常请求参数{}",packetParam);
+                            return R.error("系统异常,请稍后重试");
+                        }
+
+                        if (originalMoney.compareTo(BigDecimal.ZERO) < 0) {
+                            logger.error("服务商余额不足,异常请求参数{}",packetParam);
+                            return R.error("服务商余额不足,请联系群主服务器充值!");
+                        }
+
+                        // 预扣减金额
+                        newMoney = originalMoney.subtract(amount);
+                        redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
+                    } else {
+                        logger.error("获取redis锁失败,异常请求参数{}",packetParam);
+                        return R.error("系统繁忙,请稍后重试");
                     }
-
-                    // 预扣减金额
-                    BigDecimal newMoney = originalMoney.subtract(amount);
-                    redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
-                } else {
-                    logger.error("获取redis锁失败,异常请求参数{}",packetParam);
-                    return R.error("系统繁忙,请稍后重试");
-                }
-            } catch (Exception e) {
-                logger.error("预扣减余额失败: 异常请求参数{},异常信息{}", packetParam, e.getMessage(), e);
-                return R.error("系统异常,请稍后重试");
-            }finally {
-                // 只有在成功获取锁的情况下才释放锁
-                if (lockAcquired && lock1.isHeldByCurrentThread()) {
-                    try {
-                        lock1.unlock();
-                    } catch (IllegalMonitorStateException e) {
-                        logger.warn("尝试释放非当前线程持有的锁: companyId={}", packetParam.getCompanyId());
+                } catch (Exception e) {
+                    logger.error("预扣减余额失败: 异常请求参数{},异常信息{}", packetParam, e.getMessage(), e);
+                    return R.error("系统异常,请稍后重试");
+                }finally {
+                    // 只有在成功获取锁的情况下才释放锁
+                    if (lockAcquired && lock1.isHeldByCurrentThread()) {
+                        try {
+                            lock1.unlock();
+                        } catch (IllegalMonitorStateException e) {
+                            logger.warn("尝试释放非当前线程持有的锁: companyId={}", packetParam.getCompanyId());
+                        }
                     }
                 }
-            }
 
 
 
-            // 调用第三方接口(锁外操作)
-            R sendRedPacket;
-            try {
-                sendRedPacket= paymentService.sendRedPacket(packetParam);
-            } catch (Exception e) {
-                logger.error("红包发送异常: 异常请求参数{}",packetParam, e);
-                // 异常时回滚余额
+                // 调用第三方接口(锁外操作)
+                R sendRedPacket;
+                try {
+                    sendRedPacket= paymentService.sendRedPacket(packetParam);
+                } catch (Exception e) {
+                    logger.error("红包发送异常: 异常请求参数{}",packetParam, e);
+                    // 异常时回滚余额
 
-//                rollbackBalance(balanceRollbackError);
-                return R.error("奖励发送失败,请联系客服");
-            }
+                    rollbackBalance(balanceRollbackError);
+                    return R.error("奖励发送失败,请联系客服");
+                }
 
-            // 红包发送成功处理
-            if (sendRedPacket.get("code").equals(200)) {
-                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                TransferBillsResult transferBillsResult;
-                if (sendRedPacket.get("isNew").equals(1)){
-                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                    redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                    redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
-                }else {
-                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                    redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+                // 红包发送成功处理
+                if (sendRedPacket.get("code").equals(200)) {
+                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                    TransferBillsResult transferBillsResult;
+                    if (sendRedPacket.get("isNew").equals(1)){
+                        transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                        redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
+                    }else {
+                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                        redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+                    }
+                    // 添加红包记录
+                    redPacketLog.setCourseId(param.getCourseId());
+                    redPacketLog.setCompanyId(param.getCompanyId());
+                    redPacketLog.setUserId(param.getUserId());
+                    redPacketLog.setVideoId(param.getVideoId());
+                    redPacketLog.setStatus(0);
+                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                    redPacketLog.setCreateTime(new Date());
+                    redPacketLog.setAmount(amount);
+                    redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                    redPacketLog.setPeriodId(param.getPeriodId());
+                    redPacketLog.setAppId(param.getAppId());
+
+                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                    // 更新观看记录的奖励类型
+                    log.setRewardType(config.getRewardType());
+                    courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+                    // 异步登记余额扣减日志
+                    BigDecimal money=amount.multiply(BigDecimal.valueOf(-1));
+                    companyService.asyncRecordBalanceLog(param.getCompanyId(), money, 15, newMoney, "发放红包");
+                    // 发送成功,记录日志等操作
+                    return sendRedPacket;
+
+
+                } else {
+                    // 发送失败,回滚余额
+                    rollbackBalance(balanceRollbackError);
+                    return R.error("奖励发送失败,请联系客服");
                 }
-                // 添加红包记录
-                redPacketLog.setCourseId(param.getCourseId());
-                redPacketLog.setCompanyId(param.getCompanyId());
-                redPacketLog.setUserId(param.getUserId());
-                redPacketLog.setVideoId(param.getVideoId());
-                redPacketLog.setStatus(0);
-                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                redPacketLog.setCreateTime(new Date());
-                redPacketLog.setAmount(amount);
-                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                redPacketLog.setPeriodId(param.getPeriodId());
-                redPacketLog.setAppId(param.getAppId());
-
-                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-
-                // 更新观看记录的奖励类型
-                log.setRewardType(config.getRewardType());
-                courseWatchLogMapper.updateFsCourseWatchLog(log);
-                // 发送成功,记录日志等操作
-                return sendRedPacket;
 
+                // ===================== 本次修改目的为了实时扣减公司余额=====================
+            }else {
+                Company company = companyMapper.selectCompanyById(param.getCompanyId());
+                BigDecimal money = company.getMoney();
+                if (money.compareTo(BigDecimal.ZERO)<=0) {
+                    return R.error("服务商余额不足,请联系群主服务器充值!");
+                }
 
-            } else {
-                // 发送失败,回滚余额
-//                rollbackBalance(balanceRollbackError);
-                return R.error("奖励发送失败,请联系客服");
+                // 发送红包
+                R sendRedPacket = paymentService.sendRedPacket(packetParam);
+                if (sendRedPacket.get("code").equals(200)) {
+                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                    TransferBillsResult transferBillsResult;
+                    if (sendRedPacket.get("isNew").equals(1)){
+                        transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                        redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
+                    }else {
+                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                        redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+                    }
+                    // 添加红包记录
+                    redPacketLog.setCourseId(param.getCourseId());
+                    redPacketLog.setCompanyId(param.getCompanyId());
+                    redPacketLog.setUserId(param.getUserId());
+                    redPacketLog.setVideoId(param.getVideoId());
+                    redPacketLog.setStatus(0);
+                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                    redPacketLog.setCreateTime(new Date());
+                    redPacketLog.setAmount(amount);
+                    redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                    redPacketLog.setPeriodId(param.getPeriodId());
+                    redPacketLog.setAppId(param.getAppId());
+
+                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                    // 更新观看记录的奖励类型
+                    log.setRewardType(config.getRewardType());
+                    courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+                    return sendRedPacket;
+                } else {
+                    return R.error("奖励发送失败,请联系客服");
+                }
             }
-             */
-            // ===================== 本次修改目的为了实时扣减公司余额=====================
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
@@ -2649,6 +2672,11 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     }
 
+    public static void main(String[] args) {
+        BigDecimal a=new BigDecimal(22.01);
+        System.out.println(a.multiply(new BigDecimal(-1)));
+    }
+
 
     //插入观看记录
     private void addWatchLogIfNeeded(Long videoId, Long courseId,

+ 23 - 0
fs-service/src/main/java/com/fs/his/domain/FsRedPacket.java

@@ -0,0 +1,23 @@
+package com.fs.his.domain;
+
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @description: 红包
+ * @author: Xgb
+ * @createDate: 2025/11/4
+ * @version: 1.0
+ */
+@Data
+public class FsRedPacket extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    // 红包余额
+    private BigDecimal redBalance;
+    // 今日消耗
+    private BigDecimal redTodayComsumption;
+
+}

+ 15 - 0
fs-service/src/main/java/com/fs/his/service/IFsRedPacketService.java

@@ -0,0 +1,15 @@
+package com.fs.his.service;
+
+import com.fs.his.domain.FsRedPacket;
+
+/**
+ * 红包Service接口
+ *
+ * @author fs
+ * @date 2023-10-23
+ */
+public interface IFsRedPacketService
+{
+
+    FsRedPacket getInfo(Long companyId);
+}

+ 45 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsRedPacketServiceImpl.java

@@ -0,0 +1,45 @@
+package com.fs.his.service.impl;
+
+import com.fs.common.constant.FsConstants;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsRedPacket;
+import com.fs.his.service.IFsRedPacketService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+
+/**
+ * 红包Service业务层处理
+ *
+ * @author fs
+ * @date 2023-10-23
+ */
+@Service
+public class FsRedPacketServiceImpl implements IFsRedPacketService
+{
+
+    @Autowired
+    private RedisCache redisCache;
+    /**
+     * @Description: 获取红包余额相关信息
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/4 11:52
+     */
+    @Override
+    public FsRedPacket getInfo(Long companyId) {
+       String yesterdayBalance =redisCache.getCacheObject(FsConstants.COMPANY_MONEY_DATE_KEY+companyId+":"+ DateUtils.getDate());
+       String balance = redisCache.getCacheObject(FsConstants.COMPANY_MONEY_KEY+companyId);
+       FsRedPacket fsRedPacket = new FsRedPacket();
+       if(balance!=null){
+           fsRedPacket.setRedBalance(new BigDecimal( balance));
+           if(yesterdayBalance!=null){
+               fsRedPacket.setRedTodayComsumption(fsRedPacket.getRedBalance().subtract(new BigDecimal(yesterdayBalance)));
+           }
+       }
+       return fsRedPacket;
+    }
+}

+ 3 - 3
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java

@@ -349,9 +349,9 @@ public class FsStoreProductScrmServiceImpl implements IFsStoreProductScrmService
                     case 1://非处方
                         break;
                     case 2://处方
-                        if("".equals(store.getDrugLicense()) ||  LocalDate.now().isBefore(store.getDrugLicenseExpiryEnd())){
-                            return R.error("店铺药品资质为空或已过期,请完善后再添加");
-                        }
+//                        if("".equals(store.getDrugLicense()) ||  LocalDate.now().isBefore(store.getDrugLicenseExpiryEnd())){
+//                            return R.error("店铺药品资质为空或已过期,请完善后再添加");
+//                        }
                         break;
                     case 3://食品
                         if("".equals(store.getFoodLicense()) ||  LocalDate.now().isBefore(store.getFoodLicenseExpiryEnd())){

+ 14 - 2
fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java

@@ -93,7 +93,13 @@ public interface QwWatchLogMapper extends BaseMapper<QwWatchLog>{
             "<if test ='nickName !=null and nickName!=\"\"'>\n" +
             "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
             "</if>" +
-            "<if test ='deptId !=null and deptId!=\"\"'>\n" +
+            "<if test ='deptIds !=null and deptIds.size > 0'>\n" +
+            "and cu.dept_id in" +
+            "<foreach collection=\"deptIds\" item=\"deptId\" index=\"index\"  separator=\",\" open=\"(\" close=\")\">\n" +
+            "     #{deptId}\n" +
+            "</foreach>" +
+            "</if>" +
+            "<if test ='(deptIds ==null or deptIds.size = 0) and deptId !=null and deptId!=\"\"'>\n" +
             "   and cu.dept_id = #{deptId}\n" +
             "</if>" +
             "<if test ='ids !=null and ids!=\"\"'>\n" +
@@ -176,7 +182,13 @@ public interface QwWatchLogMapper extends BaseMapper<QwWatchLog>{
             "<if test ='nickName !=null and nickName!=\"\"'>\n" +
             "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
             "</if>" +
-            "<if test ='deptId !=null and deptId!=\"\"'>\n" +
+            "<if test ='deptIds !=null and deptIds.size > 0'>\n" +
+            "and cu.dept_id in" +
+            "<foreach collection=\"deptIds\" item=\"deptId\" index=\"index\"  separator=\",\" open=\"(\" close=\")\">\n" +
+            "     #{deptId}\n" +
+            "</foreach>" +
+            "</if>" +
+            "<if test ='(deptIds == null or deptIds.size == 0) and deptId !=null and deptId!=\"\"'>\n" +
             "   and cu.dept_id = #{deptId}\n" +
             "</if>" +
             "<if test ='ids !=null and ids!=\"\"'>\n" +

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

@@ -36,6 +36,7 @@ public class QwWatchLogStatisticsListParam {
     private Long courseId;
     private Long videoId;
     private Long deptId;
+    private List<Long> deptIds; //多选
 
     private Long pageNum;
     private Long pageSize;

+ 36 - 6
fs-service/src/main/java/com/fs/qw/service/impl/QwWatchLogServiceImpl.java

@@ -148,10 +148,26 @@ public class QwWatchLogServiceImpl extends ServiceImpl<QwWatchLogMapper, QwWatch
 
     @Override
     public List<QwWatchLogStatisticsListVO> selectQwWatchLogStatisticsListVOExport(FsCourseWatchLogListParam param) {
-        CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(param.getDeptId());
-        if (ObjectUtils.isNotEmpty(companyDept)&&companyDept.getParentId()==0L){
-            param.setDeptId(null);
+        List<Long> deptIds = param.getDeptIds();
+        if (deptIds !=null && !deptIds.isEmpty()){
+            List<CompanyDept> companyDeptList  = companyDeptMapper.selectCompanyDeptByIds(deptIds);
+            if (companyDeptList!=null && !companyDeptList.isEmpty()){
+                for (CompanyDept c : companyDeptList) {
+                    if (c.getParentId() == 0L) {
+                        param.setDeptId(null);
+                        param.setDeptIds(null);
+                        break;
+                    }
+                }
+            }
+        } else {
+            CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(param.getDeptId());
+            if (ObjectUtils.isNotEmpty(companyDept)&&companyDept.getParentId()==0L){
+                param.setDeptId(null);
+            }
         }
+
+
         if (param.getCompanyUserId()!=null){
             param.setIds(companyUserMapper.selectQwUserIdsByCompany(param.getCompanyUserId()));
         }
@@ -170,9 +186,23 @@ public class QwWatchLogServiceImpl extends ServiceImpl<QwWatchLogMapper, QwWatch
 
     @Override
     public TableDataInfo selectQwWatchLogStatisticsListVO(QwWatchLogStatisticsListParam param) {
-        CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(param.getDeptId());
-        if (ObjectUtils.isNotEmpty(companyDept)&&companyDept.getParentId()==0L){
-            param.setDeptId(null);
+        List<Long> deptIds = param.getDeptIds();
+        if (deptIds !=null && !deptIds.isEmpty()){
+            List<CompanyDept> companyDeptList  = companyDeptMapper.selectCompanyDeptByIds(deptIds);
+            if (companyDeptList!=null && !companyDeptList.isEmpty()){
+                for (CompanyDept c : companyDeptList) {
+                    if (c.getParentId() == 0L) {
+                        param.setDeptId(null);
+                        param.setDeptIds(null);
+                        break;
+                    }
+                }
+            }
+        } else {
+            CompanyDept companyDept = companyDeptMapper.selectCompanyDeptById(param.getDeptId());
+            if (ObjectUtils.isNotEmpty(companyDept)&&companyDept.getParentId()==0L){
+                param.setDeptId(null);
+            }
         }
         TableDataInfo rspData = new TableDataInfo();
         rspData.setCode(HttpStatus.SUCCESS);

+ 1 - 0
fs-service/src/main/java/com/fs/sop/vo/SopUserLogsVo.java

@@ -21,6 +21,7 @@ public class SopUserLogsVo  {
     private Integer minSend;
     private Long externalId;
     private Integer maxSend;
+    private Integer filterMode;
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private String startTime;

+ 8 - 0
fs-service/src/main/resources/mapper/company/CompanyDeptMapper.xml

@@ -170,5 +170,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectChildrenDeptById" parameterType="Long" resultMap="CompanyDeptResult">
         select * from company_dept where find_in_set(#{deptId}, ancestors)
     </select>
+    <select id="selectCompanyDeptByIds" resultType="com.fs.company.domain.CompanyDept">
+        <include refid="selectCompanyDeptVo"/>
+        where dept_id in
+        <foreach collection="depts" item="deptId" index="index"
+                 separator="," open="(" close=")">
+            #{deptId}
+        </foreach>
+    </select>
 
 </mapper>

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

@@ -200,6 +200,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="groupName != null">group_name = #{groupName},</if>
             <if test="maxPadNum != null">max_pad_num = #{maxPadNum},</if>
             <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="redPackageMoney != null">red_package_money = #{redPackageMoney},</if>
         </trim>
         where company_id = #{companyId}
     </update>
@@ -264,7 +265,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
 
     <select id="selectCompanyMoneyAllList" resultType="com.fs.company.domain.Company">
-        select company_id,company_name,money from company where is_del= 0
+        select company_id,company_name,money,red_package_money from company where is_del= 0
     </select>
 
     <update id="batchUpdateCompany" parameterType="java.util.List">

+ 11 - 8
fs-service/src/main/resources/mapper/company/CompanyRechargeMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.company.mapper.CompanyRechargeMapper">
-    
+
     <resultMap type="CompanyRecharge" id="CompanyRechargeResult">
         <result property="rechargeId"    column="recharge_id"    />
         <result property="companyId"    column="company_id"    />
@@ -20,15 +20,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="auditUserId"    column="audit_user_id"    />
         <result property="auditTime"    column="audit_time"    />
         <result property="remark"    column="remark"    />
+        <result property="businessType"    column="business_type"    />
     </resultMap>
 
     <sql id="selectCompanyRechargeVo">
-        select recharge_id, company_id, recharge_no, money, create_time, pay_time, status, pay_type, trade_no, balance, create_user_id, is_audit, audit_user_id, audit_time,remark from company_recharge
+        select recharge_id, company_id, recharge_no, money, create_time, pay_time, status, pay_type, trade_no, balance, create_user_id, is_audit, audit_user_id, audit_time,remark, business_type from company_recharge
     </sql>
 
     <select id="selectCompanyRechargeList" parameterType="CompanyRecharge" resultMap="CompanyRechargeResult">
         <include refid="selectCompanyRechargeVo"/>
-        <where>  
+        <where>
             <if test="companyId != null "> and company_id = #{companyId}</if>
             <if test="rechargeNo != null  and rechargeNo != ''"> and recharge_no = #{rechargeNo}</if>
             <if test="money != null "> and money = #{money}</if>
@@ -43,12 +44,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="auditTime != null "> and audit_time = #{auditTime}</if>
         </where>
     </select>
-    
+
     <select id="selectCompanyRechargeById" parameterType="Long" resultMap="CompanyRechargeResult">
         <include refid="selectCompanyRechargeVo"/>
         where recharge_id = #{rechargeId}
     </select>
-        
+
     <insert id="insertCompanyRecharge" parameterType="CompanyRecharge" useGeneratedKeys="true" keyProperty="rechargeId">
         insert into company_recharge
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -66,6 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="auditUserId != null">audit_user_id,</if>
             <if test="auditTime != null">audit_time,</if>
             <if test="remark != null">remark,</if>
+            <if test="businessType != null">business_type,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="companyId != null">#{companyId},</if>
@@ -82,6 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="auditUserId != null">#{auditUserId},</if>
             <if test="auditTime != null">#{auditTime},</if>
             <if test="remark != null">#{remark},</if>
+            <if test="businessType != null">#{businessType},</if>
          </trim>
     </insert>
 
@@ -111,10 +114,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <delete id="deleteCompanyRechargeByIds" parameterType="String">
-        delete from company_recharge where recharge_id in 
+        delete from company_recharge where recharge_id in
         <foreach item="rechargeId" collection="array" open="(" separator="," close=")">
             #{rechargeId}
         </foreach>
     </delete>
-    
-</mapper>
+
+</mapper>