Browse Source

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

15376779826 6 days ago
parent
commit
f27fad8a21
77 changed files with 1862 additions and 199 deletions
  1. 11 6
      README.md
  2. 27 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java
  3. 41 0
      fs-admin/src/main/java/com/fs/course/controller/CourseRedPacketStatisticsController.java
  4. 3 6
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  5. 37 0
      fs-admin/src/main/java/com/fs/course/task/RedPacketLogsTask.java
  6. 52 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  7. 43 9
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  8. 27 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  9. 7 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  10. 29 0
      fs-company/src/main/java/com/fs/company/utils/QwStatusEnum.java
  11. 2 1
      fs-company/src/main/resources/application.yml
  12. 1 1
      fs-doctor-app/src/main/resources/application.yml
  13. 27 0
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  14. 9 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  15. 9 3
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  16. 6 0
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  17. 59 4
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  18. 21 0
      fs-service/src/main/java/com/fs/company/vo/BatchUserRolesVO.java
  19. 4 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java
  20. 36 0
      fs-service/src/main/java/com/fs/course/dto/CourseRedPacketStatisticsDTO.java
  21. 7 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  22. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  23. 38 0
      fs-service/src/main/java/com/fs/course/param/CourseRedPacketStatisticsParam.java
  24. 11 0
      fs-service/src/main/java/com/fs/course/service/CourseRedPacketStatisticsService.java
  25. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseRedPacketLogService.java
  26. 28 0
      fs-service/src/main/java/com/fs/course/service/impl/CourseRedPacketStatisticsServiceImpl.java
  27. 71 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  28. 0 2
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseTrafficLogServiceImpl.java
  29. 96 4
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  30. 7 3
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java
  31. 2 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  32. 28 0
      fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountScrmStatsQueryDto.java
  33. 28 0
      fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountStatsQueryDto.java
  34. 3 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
  35. 6 4
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
  36. 5 0
      fs-service/src/main/java/com/fs/his/service/IFsStorePaymentService.java
  37. 4 4
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java
  38. 198 2
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  39. 152 68
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  40. 44 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountScrmStatsVo.java
  41. 44 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountStatsVo.java
  42. 4 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  43. 7 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java
  44. 87 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  45. 6 0
      fs-service/src/main/java/com/fs/qw/domain/QwFriendWelcome.java
  46. 1 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  47. 2 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserVideoMapper.java
  48. 7 0
      fs-service/src/main/java/com/fs/qw/param/QwFriendWelcomeParam.java
  49. 7 0
      fs-service/src/main/java/com/fs/qw/param/QwUserListParam.java
  50. 3 0
      fs-service/src/main/java/com/fs/qw/service/IQwUserVideoService.java
  51. 34 12
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  52. 4 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserVideoServiceImpl.java
  53. 2 0
      fs-service/src/main/java/com/fs/qw/vo/QwExternalContactVO.java
  54. 6 1
      fs-service/src/main/java/com/fs/qw/vo/QwFriendWelcomeVO.java
  55. 3 2
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempVoiceServiceImpl.java
  56. 8 6
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  57. 1 0
      fs-service/src/main/java/com/fs/sop/vo/SopUserLogsVo.java
  58. 10 0
      fs-service/src/main/java/com/fs/wxwork/dto/WxWorkMessageDTO.java
  59. 94 0
      fs-service/src/main/resources/application-config-dev-jnlzjk.yml
  60. 1 1
      fs-service/src/main/resources/application-config-druid-fby.yml
  61. 2 2
      fs-service/src/main/resources/application-config-druid-hcl.yml
  62. 3 3
      fs-service/src/main/resources/application-config-druid-jnlzjk.yml
  63. 153 0
      fs-service/src/main/resources/application-dev-jnlzjk.yml
  64. 1 1
      fs-service/src/main/resources/application-druid-cqtyt-test.yml
  65. 10 13
      fs-service/src/main/resources/application-druid-cqtyt.yml
  66. 1 1
      fs-service/src/main/resources/application-druid-hcl.yml
  67. 1 1
      fs-service/src/main/resources/application-druid-hdt.yml
  68. 1 1
      fs-service/src/main/resources/application-druid-jnmy-test.yml
  69. 3 1
      fs-service/src/main/resources/application-druid-sxjz.yml
  70. 38 0
      fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
  71. 30 0
      fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml
  72. 4 3
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  73. 34 0
      fs-service/src/main/resources/mapper/his/FsStoreOrderMapper.xml
  74. 28 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  75. 33 31
      fs-service/src/main/resources/mapper/hisStore/FsUserScrmMapper.xml
  76. 6 1
      fs-service/src/main/resources/mapper/qw/QwFriendWelcomeMapper.xml
  77. 1 1
      fs-user-app/src/main/resources/application.yml

+ 11 - 6
README.md

@@ -3,21 +3,26 @@
 #### 介绍
 问诊平台
 
-#### 软件架构
-软件架构说明
+#### 软件模块说明
+
+| 模块名称         | 模块描述         | 对应前端项目                  |
+|--------------|--------------|-------------------------|
+| fs-admin     | 总后台服务        | ylrz_his_scrm_adminUI   |
+| fs-company   | 销售端          | ylrz_his_scrm_companyUI |
+| fs-user-app  | 微信小程序端       | 对应某个微信小程序(前端蒲瑶清楚)       |
+| fs-framework | 主要依赖包,核心包    | /                       |
+| fs-service   | 所有的链接配置文件都在里面 | /                       |
 
 
 #### 安装教程
 
 1.  xxxx
 2.  xxxx
-3.  xxxx
 
 #### 使用说明
 
-1.  xxxx
-2.  xxxx
-3.  xxxx
+1.  注意调整Memory的大小,以及堆内存大小
+2.  对于maven仓库缺少的jar包引用,需要拷贝现有的文件(拷贝后依然出现错误,直接删除错误包下的_remote.repositories文件)。
 
 #### 参与贡献
 

+ 27 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java

@@ -19,9 +19,14 @@ import com.fs.crm.service.ICrmCustomerService;
 import com.fs.crm.service.ICrmCustomerVisitService;
 import com.fs.crm.vo.CrmCustomerStatisticsVO;
 import com.fs.crm.vo.CrmCustomerVisitStatisticsVO;
+import com.fs.his.dto.FsStoreOrderAmountScrmStatsQueryDto;
+import com.fs.his.dto.FsStoreOrderAmountStatsQueryDto;
 import com.fs.his.service.IFsStoreAfterSalesService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.vo.FsStoreOrderAmountScrmStatsVo;
+import com.fs.his.vo.FsStoreOrderAmountStatsVo;
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -67,6 +72,10 @@ public class CompanyStatisticsController extends BaseController
     private ICrmCustomerService crmCustomerService;
     @Autowired
     private ICrmCustomerVisitService crmCustomerVisitService;
+
+    //app商城订单接口Service
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderScrmService;
     @GetMapping("/storeOrder")
     public R storeOrder(FsStoreStatisticsParam param)
     {
@@ -724,4 +733,22 @@ public class CompanyStatisticsController extends BaseController
         return util.exportExcel(qwIpadTotalVos, "visit");
     }
 
+    /**
+     * 获取互联网医院订单统计数据
+     * */
+    @GetMapping("/hisOrderCountStats")
+    public AjaxResult getHisOrderCount(FsStoreOrderAmountStatsQueryDto statsQueryDto){
+        FsStoreOrderAmountStatsVo fsStoreOrderAmountStatsVo = storeOrderService.selectFsStoreOrderAmountStats(statsQueryDto);
+        return AjaxResult.success(fsStoreOrderAmountStatsVo);
+    }
+
+    /**
+     * 获取App商城订单统计数据
+     * */
+    @GetMapping("/appOrderCountStats")
+    public AjaxResult getAppOrderCount(FsStoreOrderAmountScrmStatsQueryDto statsQueryDto){
+        FsStoreOrderAmountScrmStatsVo scrmStatsVo = fsStoreOrderScrmService.selectFsStoreOrderAmountScrmStats(statsQueryDto);
+        return AjaxResult.success(scrmStatsVo);
+    }
+
 }

+ 41 - 0
fs-admin/src/main/java/com/fs/course/controller/CourseRedPacketStatisticsController.java

@@ -0,0 +1,41 @@
+package com.fs.course.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.course.dto.CourseRedPacketStatisticsDTO;
+import com.fs.course.param.CourseRedPacketStatisticsParam;
+import com.fs.course.service.CourseRedPacketStatisticsService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiModelProperty;
+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;
+
+import java.util.List;
+
+/**
+ * @description: 看客红包发送统计
+ * @author: Xgb
+ * @createDate: 2025/10/14
+ * @version: 1.0
+ */
+@RestController
+@RequestMapping("/course/courseRedPacketStatistics")
+public class CourseRedPacketStatisticsController extends BaseController {
+
+    @Autowired
+    private CourseRedPacketStatisticsService courseRedPacketStatisticsService;
+
+    @ApiModelProperty("看客红包发送统计")
+    @GetMapping("/list")
+    public R list(CourseRedPacketStatisticsParam param) {
+
+        startPage();
+        // 看客红包发送统计
+        List<CourseRedPacketStatisticsDTO> list = courseRedPacketStatisticsService.statistics(param);
+
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+}

+ 3 - 6
fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java

@@ -103,13 +103,10 @@ public class FsCourseWatchLogController extends BaseController
         if (param.getSTime()==null||param.getETime()==null){
             throw new CustomException("必须选择开始时间和结束时间!");
         }
+        startPage();
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVONew(param);
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(HttpStatus.SUCCESS);
-        rspData.setMsg("查询成功");
-        rspData.setRows(list);
-        rspData.setTotal(fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVONewCount(param));
-        return rspData;
+
+        return getDataTable(list);
     }
 
     /**

+ 37 - 0
fs-admin/src/main/java/com/fs/course/task/RedPacketLogsTask.java

@@ -0,0 +1,37 @@
+package com.fs.course.task;
+
+import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import com.fs.course.service.IFsCourseRedPacketLogService;
+import com.fs.course.service.impl.FsCourseRedPacketLogServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+/**
+ * @description: 微信红包转账回调部分没有接收到,主动自己去查询
+ * @author: Xgb
+ * @createDate: 2025/10/15
+ * @version: 1.0
+ */
+@Component("redPacketLogsTask")
+public class RedPacketLogsTask {
+
+    @Autowired
+    private IFsCourseRedPacketLogService fsCourseRedPacketLogService;
+
+    /**
+     * @Description: 查询微信红包转账结果 每10分钟查询上一个10分钟区间的红包转账结果
+     * (定时调取失败 可以启动fs-qw-task 中的 CommonController queryRedPacketResult 手动调取) 仅给内部人员使用
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/10/15 16:32
+     */
+    public void queryRedPacketResult() {
+
+        // 查询RedPacketLog表,
+        fsCourseRedPacketLogService.queryRedPacketResult(null, null);
+    }
+
+}

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

@@ -28,9 +28,13 @@ import com.fs.erp.dto.ErpOrderResponse;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.fastGpt.domain.FastGptEventTokenLog;
+import com.fs.fastGpt.domain.FastgptChatVoiceHomo;
 import com.fs.fastGpt.domain.FastgptEventLogTotal;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
+import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
 import com.fs.fastGpt.service.IFastgptEventLogTotalService;
+import com.fs.fastgptApi.util.AudioUtils;
+import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
@@ -51,6 +55,8 @@ import com.fs.im.service.IImService;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.service.*;
 import com.fs.qwApi.service.QwApiService;
+import com.fs.sop.domain.QwSopTempVoice;
+import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.google.gson.Gson;
@@ -63,6 +69,7 @@ import org.springframework.stereotype.Component;
 
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Component("task")
@@ -165,6 +172,51 @@ public class Task {
     @Autowired
     private IFastgptEventLogTotalService fastgptEventLogTotalService;
 
+    @Autowired
+    private FastgptChatVoiceHomoMapper fastgptChatVoiceHomoMapper;
+    @Autowired
+    private IQwSopTempVoiceService qwSopTempVoiceService;
+
+    public static final String SOP_TEMP_VOICE_KEY = "sop:tempVoice";
+
+    /**
+     * 一键生成语音定时任务
+     */
+    public void ConsumerSopTempVoice() {
+        try {
+            Long newCompanyUserId = redisCache.popVoiceKey(SOP_TEMP_VOICE_KEY);
+            if(newCompanyUserId != null){
+                List<QwSopTempVoice> sopTempVoices = redisCache.getVoiceAllList(SOP_TEMP_VOICE_KEY + ":" +newCompanyUserId);
+                if(sopTempVoices != null && !sopTempVoices.isEmpty()) {
+                    try {
+                        for (QwSopTempVoice qwSopTempVoice : sopTempVoices) {
+                            try {
+                                AudioVO audioVO = new AudioVO();
+                                List<FastgptChatVoiceHomo> homos = fastgptChatVoiceHomoMapper.selectFastgptChatVoiceHomoList(new FastgptChatVoiceHomo());
+                                audioVO = AudioUtils.createUserUrlAndUrl(homos,qwSopTempVoice.getCompanyUserId(), qwSopTempVoice.getVoiceTxt());
+                                if (audioVO != null && audioVO.getWavUrl() != null && audioVO.getUrl() != null) {
+                                    qwSopTempVoice.setVoiceUrl(audioVO.getUrl());
+                                    qwSopTempVoice.setUserVoiceUrl(audioVO.getWavUrl());
+                                    qwSopTempVoice.setDuration(audioVO.getDuration());
+                                    qwSopTempVoice.setRecordType(1);
+                                    qwSopTempVoiceService.updateQwSopTempVoice(qwSopTempVoice);
+                                }
+                            } catch (Exception e) {
+
+                            }
+                        }
+                    } finally {
+                        redisCache.deleteObject(SOP_TEMP_VOICE_KEY + ":" + newCompanyUserId);
+                    }
+                }
+            }else{
+                log.info("没有需要生成的语音");
+            }
+        } catch (Exception e) {
+            log.error("生成语音定时任务执行异常", e);
+        }
+    }
+
     //统计ai事件埋点
     public void eventLogTotals() {
         // 判断是否是凌晨 00:00 - 00:59

+ 43 - 9
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java

@@ -22,6 +22,8 @@ import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
 import com.fs.company.service.*;
 import com.fs.company.utils.DomainUtil;
+import com.fs.company.utils.QwStatusEnum;
+import com.fs.company.vo.BatchUserRolesVO;
 import com.fs.company.vo.CompanyUserImportVO;
 import com.fs.company.vo.CompanyUserQwListVO;
 import com.fs.company.vo.CompanyUserVO;
@@ -35,6 +37,7 @@ import com.fs.hisStore.vo.FsStoreProductExportVO;
 import com.fs.im.service.OpenIMService;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.service.IQwCompanyService;
+import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwUserVO;
 import com.fs.system.service.ISysConfigService;
@@ -46,6 +49,7 @@ import org.json.JSONArray;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.Assert;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -58,13 +62,10 @@ import java.util.stream.Collectors;
 
 /**
  * 用户信息
- *
-
  */
 @RestController
 @RequestMapping("/company/user")
-public class CompanyUserController extends BaseController
-{
+public class CompanyUserController extends BaseController {
 
     @Autowired
     private ICompanyRoleService roleService;
@@ -77,19 +78,28 @@ public class CompanyUserController extends BaseController
 
     @Autowired
     private ICompanyUserService companyUserService;
+
     @Autowired
     private ICompanyService companyService;
+
     @Autowired
     private ICompanyUserDelayTimeService companyUserDelayTimeService;
+
     @Autowired
     private ISysConfigService configService;
+
     @Autowired
     private RedisCache redisCache;
+
     @Autowired
     private OpenIMService openIMService;
+
     @Autowired
     IQwCompanyService iQwCompanyService;
 
+    @Autowired
+    private IQwUserService qwUserService;
+
     private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
 
     /**
@@ -123,24 +133,34 @@ public class CompanyUserController extends BaseController
         return getDataTable(list);
     }
     @GetMapping("/qwList")
-    public TableDataInfo qwList(CompanyUserQwParam user)
-    {
+    public TableDataInfo qwList(CompanyUserQwParam user) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         user.setCompanyId(loginUser.getCompany().getCompanyId());
         startPage();
         List<CompanyUserQwListVO> list = companyUserService.selectCompanyUserQwListVO(user);
         for (CompanyUserQwListVO companyUserQwListVO : list) {
-             CompanyUserDelayTime companyUserDelayTime = companyUserDelayTimeService.selectCompanyUserDelayTimeByCompanyUser(companyUserQwListVO.getCompanyId(),companyUserQwListVO.getUserId());
-            if (ObjectUtil.isEmpty(companyUserDelayTime)){
+            CompanyUserDelayTime companyUserDelayTime = companyUserDelayTimeService.selectCompanyUserDelayTimeByCompanyUser(companyUserQwListVO.getCompanyId(), companyUserQwListVO.getUserId());
+            if (ObjectUtil.isEmpty(companyUserDelayTime)) {
                 String json = configService.selectConfigByKey("course.config");
                 CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
                 companyUserQwListVO.setSendDelayTime(config.getSendDelayTime());
-            }else {
+            } else {
                 companyUserQwListVO.setSendDelayTime(companyUserDelayTime.getSendDelayTime());
             }
+            //是否绑定
+            if(QwStatusEnum.BOUND.getCode() == companyUserQwListVO.getQwStatus()){
+                if(!companyUserQwListVO.getQwUserId().isEmpty()){
+                    Long[] ids = Arrays.stream(companyUserQwListVO.getQwUserId().split(","))
+                            .map(Long::parseLong)
+                            .toArray(Long[]::new);
+                    List<QwUserVO> qwUserVOS = qwUserService.selectQwUserVOByIds(ids);
+                    companyUserQwListVO.setQwUsers(qwUserVOS);
+                }
+            }
         }
         return getDataTable(list);
     }
+
     @Log(title = "用户管理导出", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('company:user:export')")
     @GetMapping("/export")
@@ -565,6 +585,20 @@ public class CompanyUserController extends BaseController
         return companyUserService.bindDoctor(companyUser);
     }
 
+    /**
+     * 批量修改角色
+     * @param batchUserRolesVO
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:edit')")
+    @Log(title = "批量修改角色", businessType = BusinessType.UPDATE)
+    @PostMapping("/updateBatchUserRoles")
+    public R updateBatchUserRoles(@RequestBody BatchUserRolesVO batchUserRolesVO){
+        Assert.notEmpty(batchUserRolesVO.getRoleIds(), "角色不能为空");
+        Assert.notEmpty(batchUserRolesVO.getUserIds(), "用户不能为空");
+        return companyUserService.updateBatchUserRoles(batchUserRolesVO);
+    }
+
+
     @ApiOperation("校验客服是否注册新的im")
     @PostMapping("/accountCheck")
     public R accountCheck(@RequestBody Map<String, String> userIdMap){

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

@@ -21,6 +21,7 @@ import com.fs.crm.service.ICrmCustomerService;
 import com.fs.crm.vo.CrmMyCustomerListQueryVO;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
+import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import com.fs.qw.domain.QwContactWay;
 import com.fs.qw.domain.QwExternalContact;
@@ -36,6 +37,7 @@ import com.github.pagehelper.PageHelper;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.codehaus.jettison.json.JSONException;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -56,6 +58,7 @@ import static com.fs.his.utils.PhoneUtil.encryptPhone;
  * @author fs
  * @date 2024-06-20
  */
+@Slf4j
 @RestController
 @RequestMapping("/qw/externalContact")
 public class QwExternalContactController extends BaseController
@@ -272,10 +275,34 @@ public class QwExternalContactController extends BaseController
             if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
                 item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
             }
+            //获取用户下单次数
+            try {
+                fillOrderCount(item);
+            }catch (Exception e){
+                log.error("获取用户下单次数异常:{}",e.getMessage());
+            }
+
         });
 
         return getDataTable(list);
     }
+    /**
+     * 根据用户ID查询并设置下单次数(若用户不存在或ID无效,则设为0)
+     */
+    private void fillOrderCount(QwExternalContactVO item){
+        Long fsUserId = item.getFsUserId();
+        if (fsUserId==null){
+            item.setOrderCount(0L);
+            return;
+        }
+        FsUser fsUser = fsUserService.selectFsUserById(fsUserId);
+        if (fsUser == null) {
+            item.setOrderCount(0L);
+            return;
+        }
+        Long orderCount = fsUser.getOrderCount();
+        item.setOrderCount(orderCount != null ? orderCount : 0);
+    }
 
 
     @Log(title = "同步我的企业微信客户", businessType = BusinessType.INSERT)

+ 7 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.qw;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
@@ -392,6 +393,12 @@ public class QwUserController extends BaseController
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwUser.setCompanyId(loginUser.getCompany().getCompanyId());
+        if (ObjectUtil.isNotEmpty(qwUser.getIsRemark())&&qwUser.getIsRemark().equals("1")){
+            qwUser.setCompanyUserId(loginUser.getUser().getUserId());
+        }else if (ObjectUtil.isNotEmpty(qwUser.getIsRemark())&&qwUser.getIsRemark().equals("2")){
+            qwUser.setDeptId(loginUser.getUser().getDeptId());
+            qwUser.setCorpId(null);
+        }
 
         List<QwUserVO> list = qwUserService.selectQwUserListVO(qwUser);
         return getDataTable(list);

+ 29 - 0
fs-company/src/main/java/com/fs/company/utils/QwStatusEnum.java

@@ -0,0 +1,29 @@
+package com.fs.company.utils;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/16 下午3:00
+ */
+public enum QwStatusEnum {
+
+    BOUND(1, "已绑定"),
+    UNBOUND(0, "未绑定");
+
+    private Integer code;
+
+    private String detail;
+
+    QwStatusEnum(Integer code, String detail) {
+        this.code = code;
+        this.detail = detail;
+    }
+
+    public int getCode(){
+        return this.code;
+    }
+
+    public String getDetail() {
+        return this.detail;
+    }
+}

+ 2 - 1
fs-company/src/main/resources/application.yml

@@ -4,11 +4,12 @@ server:
 spring:
   profiles:
 #    active: druid-fcky-test
-    active: druid-jnmy-test
+#    active: druid-jnmy-test
 #    active: druid-jzzx-test
 #    active: druid-hdt
 #    active: druid-sxjz
 #    active: druid-yzt
 #    active: druid-myhk
 #    active: druid-sft
+    active: dev-jnlzjk
 #    active: dev-yjb

+ 1 - 1
fs-doctor-app/src/main/resources/application.yml

@@ -6,4 +6,4 @@ server:
 spring:
   profiles:
 #    active: dev
-    active: druid-jnmy
+    active: dev-yjb

+ 27 - 0
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -16,10 +16,12 @@ import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
+import com.fs.qw.domain.QwUserVideo;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwUserService;
+import com.fs.qw.service.IQwUserVideoService;
 import com.fs.qw.service.IQwUserVoiceLogService;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.SopUserLogsInfoMapper;
@@ -57,6 +59,8 @@ public class QwMsgController {
     @Autowired
     IQwUserService qwUserService;
     @Autowired
+    IQwUserVideoService qwUserVideoService;
+    @Autowired
     IQwUserVoiceLogService qwUserVoiceLogService;
     @Autowired
     IFsStoreOrderService fsStoreOrderService;
@@ -342,6 +346,29 @@ public class QwMsgController {
                     else if (wxWorkMessageDTO.getMsgtype() == 104){
                         content = wxWorkMessageDTO.getUrl();
                         log.info("id:{}, 用户发送表情"+content, id);
+                    }//视频号
+                    else if (wxWorkMessageDTO.getMsgtype()==141){
+                        QwUser qwUserByAppKey = qwUserMapper.selectQwUserById(id);
+                        if(qwUserByAppKey.getVideoGetStatus() != null && qwUserByAppKey.getVideoGetStatus() == 1){
+                            QwUserVideo qwUserVideo = qwUserVideoService.selectByObjectId(wxWorkMessageDTO.getObjectId(), qwUserByAppKey.getId());
+                            if(qwUserVideo == null){
+                                QwUserVideo userVideo=new QwUserVideo();
+                                userVideo.setSenderName(wxWorkMessageDTO.getSender_name());
+                                userVideo.setNickName(wxWorkMessageDTO.getNickname());
+                                userVideo.setObjectId(wxWorkMessageDTO.getObjectId());
+                                userVideo.setCoverUrl(wxWorkMessageDTO.getCover_url());
+                                userVideo.setThumbUrl(wxWorkMessageDTO.getThumb_url());
+                                userVideo.setAvatar(wxWorkMessageDTO.getAvatar());
+                                userVideo.setDesc(wxWorkMessageDTO.getDesc());
+                                userVideo.setUrl(wxWorkMessageDTO.getUrl());
+                                userVideo.setExtras(wxWorkMessageDTO.getExtras());
+                                userVideo.setObjectNonceId(wxWorkMessageDTO.getObjectNonceId());
+                                userVideo.setQwUserId(qwUserByAppKey.getId());
+                                userVideo.setCompanyUserId(qwUserByAppKey.getCompanyUserId());
+                                userVideo.setCompanyId(qwUserByAppKey.getCompanyId());
+                                qwUserVideoService.insertQwUserVideo(userVideo);
+                            }
+                        }
                     }
 
                     if (2000000000000000L-receiver>0){

+ 9 - 0
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -67,6 +67,8 @@ public class CommonController {
     private IFsCourseWatchLogService watchLogService;
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
+    @Autowired
+    private IFsCourseRedPacketLogService fsCourseRedPacketLogService;
 
     @Autowired
     private IQwSopLogsService qwSopLogsService;
@@ -315,4 +317,11 @@ public class CommonController {
         }
         return R.ok();
     }
+
+    @GetMapping("/queryRedPacketResult")
+    public R queryRedPacketResult(String startTime , String  endTime) {
+        fsCourseRedPacketLogService.queryRedPacketResult(startTime, endTime);
+        return R.ok();
+    }
+
 }

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

@@ -899,6 +899,10 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                      Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config,Map<Long,
                     Map<Integer, List<CompanyMiniapp>>> miniMap,Integer grade, Integer sendMsgType,
                                      List<Company> companies) {
+        QwExternalContact contact = null;
+        if(logVo.getExternalId() != null){
+            contact = qwExternalContactMapper.selectById(logVo.getExternalId());
+        }
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         if (clonedContent == null) {
@@ -968,6 +972,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                 } else {
                                     setting.setValue(currentValue
                                             .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(welcomeText) ? "" : welcomeText)
+                                            .replaceAll("#客户称呼#", contact != null && StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(Objects.requireNonNull(contact).getStageStatus())?"同学":contact.getStageStatus())
                                             + "\n" + link);
                                 }
                             }
@@ -978,7 +983,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     } else {
                         if ("1".equals(setting.getContentType())) {
                             setting.setValue(setting.getValue()
-                                    .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(welcomeText) ? "" : welcomeText));
+                                    .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(welcomeText) ? "" : welcomeText).replaceAll("#客户称呼#", contact != null && StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(Objects.requireNonNull(contact).getStageStatus())?"同学":contact.getStageStatus()));
                         }
                     }
                     break;
@@ -988,7 +993,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     addWatchLogIfNeeded(sopLogs, videoId, courseId, sendTime, qwUserId, companyUserId, companyId, externalId,logVo);
 
                     String sortLink = createLinkByMiniApp(setting, logVo, sendTime, courseId, videoId,
-                            qwUserId, companyUserId, companyId, externalId,isOfficial,sopLogs.getFsUserId());
+                            qwUserId, companyUserId, companyId, externalId,isOfficial,sopLogs.getFsUserId(), isGroupChat ? groupChat.getChatId() : null);
 
                     if(sopLogs.getSendType()==1){
                         setting.setMiniprogramAppid(miniAppId);
@@ -1323,7 +1328,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
     private String createLinkByMiniApp(QwSopTempSetting.Content.Setting setting, SopUserLogsVo logVo, Date sendTime,
                                        Long courseId, Long videoId, String qwUserId,
-                                       String companyUserId, String companyId, String externalId,String isOfficial,Long fsUserId) {
+                                       String companyUserId, String companyId, String externalId,String isOfficial,Long fsUserId, String chatId) {
         // 获取缓存的配置
         CourseConfig config;
         synchronized(configLock) {
@@ -1351,6 +1356,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         link.setCourseId(courseId.longValue());
         link.setQwExternalId(Long.parseLong(externalId));
         link.setProjectCode(cloudHostProper.getProjectCode());
+        link.setChatId(chatId);
 
         if (StringUtil.strIsNullOrEmpty(isOfficial)){
             link.setLinkType(3);

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

@@ -238,4 +238,10 @@ public interface ICompanyUserService {
     R unBindDoctor(Long userId);
 
     R getBindInfo(Long companyUserId);
+
+    /**
+     * 批量修改角色
+     * @param batchUserRolesVO 批量修改角色参数
+     */
+    R updateBatchUserRoles(BatchUserRolesVO batchUserRolesVO);
 }

+ 59 - 4
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -3,6 +3,7 @@ package com.fs.company.service.impl;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.QRutils;
 import com.fs.common.annotation.DataScope;
@@ -22,8 +23,7 @@ import com.fs.company.mapper.*;
 import com.fs.company.param.CompanyUserAreaParam;
 import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
-import com.fs.company.service.ICompanyService;
-import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.*;
 import com.fs.company.vo.*;
 import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.mapper.FsUserMapper;
@@ -43,8 +43,13 @@ import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
+import com.fs.system.service.ISysConfigService;
+import com.fs.system.service.ISysRoleService;
+import com.fs.system.service.ISysUserService;
 import com.fs.voice.utils.StringUtil;
 import com.fs.wxUser.domain.CompanyWxUser;
 import org.slf4j.Logger;
@@ -72,6 +77,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 {
     @Autowired
     private CompanyUserMapper companyUserMapper;
+
     @Autowired
     private CompanyRoleMapper roleMapper;
 
@@ -99,6 +105,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 
     @Autowired
     private FsUserMapper fsUserMapper;
+
     @Autowired
     private IFsUserCompanyUserService userCompanyUserService;
 
@@ -108,10 +115,19 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Autowired
     private ICompanyService companyService;
 
-
     @Autowired
     private IQwUserService qwUserService;
 
+    @Autowired
+    private ISysRoleService sysRoleService;
+
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+
+//    @Autowired
+//    private ICompanyUserRoleService userRoleService;
+
+
     /**
      * 查询物业公司管理员信息
      *
@@ -649,7 +665,20 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Override
     @DataScope(deptAlias = "u", userAlias = "u")
     public List<CompanyUserQwListVO> selectCompanyUserQwListVO(CompanyUserQwParam user) {
-        return companyUserMapper.selectCompanyUserQwListVO(user);
+        CompanyConfig companyConfig = companyConfigService.selectCompanyConfigByKey(user.getCompanyId(), "company:admin:show");
+        boolean  isAdminShow = false;
+        if(!StringUtils.isEmpty(companyConfig.getConfigValue())){
+            isAdminShow = Boolean.parseBoolean(companyConfig.getConfigValue());
+        }
+        List<CompanyUserQwListVO> companyUserQwListVOS = companyUserMapper.selectCompanyUserQwListVO(user);
+        if(!isAdminShow){
+            Company company = companyService.selectCompanyById(user.getCompanyId());
+            Long userId = company.getUserId();
+            companyUserQwListVOS = companyUserQwListVOS.stream()
+                    .filter(vo -> !vo.getUserId().equals(userId))
+                    .collect(Collectors.toList());
+        }
+        return companyUserQwListVOS;
     }
 
     @Override
@@ -1006,4 +1035,30 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         }
         return R.error();
     }
+
+    /**
+     * 批量修改角色
+     * @param batchUserRolesVO 批量修改角色参数
+     */
+    @Override
+    public R updateBatchUserRoles(BatchUserRolesVO batchUserRolesVO) {
+        Long[] roleIds = batchUserRolesVO.getRoleIds();
+        Long[] userIds = batchUserRolesVO.getUserIds();
+        //先删除之前关联的角色
+        userRoleMapper.deleteCompanyUserRoleByIds(userIds);
+        for (Long userId : userIds){
+            try {
+                CompanyUser companyUser = selectCompanyUserById(userId);
+                companyUser.setRoleIds(roleIds);
+                //updateUser(companyUser) 直接使用这个方法后屏蔽下方代码也可以
+                insertUserRole(companyUser);
+                userPostMapper.deleteUserPostByUserId(userId);
+                insertUserPost(companyUser);
+                companyUserMapper.updateCompanyUser(companyUser);
+            }catch (Exception exception){
+                throw new CustomException("修改失败");
+            }
+        }
+        return R.ok("修改成功");
+    }
 }

+ 21 - 0
fs-service/src/main/java/com/fs/company/vo/BatchUserRolesVO.java

@@ -0,0 +1,21 @@
+package com.fs.company.vo;
+
+import lombok.*;
+
+/**
+ * @description: 批量修改用户角色入参
+ * @author: Guos
+ * @time: 2025/10/16 上午9:23
+ */
+
+@Getter
+@Setter
+@ToString
+@NoArgsConstructor
+@AllArgsConstructor
+public class BatchUserRolesVO {
+
+    private Long[] roleIds;
+
+    private Long[] userIds;
+}

+ 4 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java

@@ -5,6 +5,7 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import com.fs.company.domain.CompanyDept;
 import com.fs.company.domain.CompanyRole;
+import com.fs.qw.vo.QwUserVO;
 import lombok.Data;
 
 import java.util.Date;
@@ -133,4 +134,7 @@ public class CompanyUserQwListVO extends BaseEntity {
     /** 医生id */
     private Long doctorId;
 
+    /** 企微用户列表 */
+    List<QwUserVO> qwUsers;
+
 }

+ 36 - 0
fs-service/src/main/java/com/fs/course/dto/CourseRedPacketStatisticsDTO.java

@@ -0,0 +1,36 @@
+package com.fs.course.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @description: 看客红包发送统计
+ * @author: Xgb
+ * @createDate: 2025/10/14
+ * @version: 1.0
+ */
+@Data
+public class CourseRedPacketStatisticsDTO {
+
+    // 公司名称
+    private String companyName;
+
+    // 员工姓名
+    private String nickName;
+
+    // 员工id
+    private Long companyUserId;
+
+    // 红包数
+    private Long redPacketNum;
+
+   // 红包总金额
+    private BigDecimal redPacketTotalMoney;
+
+
+
+
+}

+ 7 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java

@@ -3,9 +3,12 @@ package com.fs.course.mapper;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.dto.CourseRedPacketStatisticsDTO;
+import com.fs.course.param.CourseRedPacketStatisticsParam;
 import com.fs.course.param.FsCourseRedPacketLogParam;
 import com.fs.course.param.FsUserCourseOrderParam;
 import com.fs.course.vo.FsCourseRedPacketLogListPVO;
@@ -171,4 +174,8 @@ public interface FsCourseRedPacketLogMapper
     List<FsCourseRedPacketLog> selectFail(@Param("userId") Long userId);
 
     List<RedPacketMoneyVO> selectFsCourseRedPacketLogHourseByCompany(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
+
+    List<CourseRedPacketStatisticsDTO> statistics(CourseRedPacketStatisticsParam param);
+
+    List<FsCourseRedPacketLog> selectFsCourseRedPacketLogListBySending(@Param("maps") Map<String, Object> map);
 }

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

@@ -137,7 +137,7 @@ public interface FsUserCourseVideoMapper
     Long selectFsUserCourseVideoByCourseSort(@Param("courseId")Long courseId, @Param("courseSort")Long courseSort);
 
 
-    @Select("select video_id dict_value, title dict_label  from fs_user_course_video where course_id=#{id} and is_del = 0 ")
+    @Select("select video_id dict_value, title dict_label  from fs_user_course_video where course_id=#{id} and is_del = 0 order by course_sort")
     List<OptionsVO> selectFsUserCourseVodeAllList(Long id);
 
     @Select({"<script> " +

+ 38 - 0
fs-service/src/main/java/com/fs/course/param/CourseRedPacketStatisticsParam.java

@@ -0,0 +1,38 @@
+package com.fs.course.param;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.models.auth.In;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @description: 看客红包发送统计
+ * @author: Xgb
+ * @createDate: 2025/10/14
+ * @version: 1.0
+ */
+@Data
+public class CourseRedPacketStatisticsParam {
+
+    // 公司id
+    private Long companyId;
+
+    // 公司用户id
+    private Long companyUserId;
+
+    // 状态 状态 0 发送中  1  已发送  2余额不足待发送
+    private Integer status;
+
+    // 开始时间
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date startTime;
+
+    // 结束时间
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date endTime;
+
+
+
+
+}

+ 11 - 0
fs-service/src/main/java/com/fs/course/service/CourseRedPacketStatisticsService.java

@@ -0,0 +1,11 @@
+package com.fs.course.service;
+
+import com.fs.course.dto.CourseRedPacketStatisticsDTO;
+import com.fs.course.param.CourseRedPacketStatisticsParam;
+
+import java.util.List;
+
+
+public interface CourseRedPacketStatisticsService {
+    List<CourseRedPacketStatisticsDTO> statistics(CourseRedPacketStatisticsParam param);
+}

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

@@ -85,4 +85,6 @@ public interface IFsCourseRedPacketLogService
     R retryCourseRedPacketLog(Long[] logIds);
 
     void sendRedPacketBf();
+
+    void queryRedPacketResult(String startTime, String endTime);
 }

+ 28 - 0
fs-service/src/main/java/com/fs/course/service/impl/CourseRedPacketStatisticsServiceImpl.java

@@ -0,0 +1,28 @@
+package com.fs.course.service.impl;
+
+import com.fs.course.dto.CourseRedPacketStatisticsDTO;
+import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import com.fs.course.param.CourseRedPacketStatisticsParam;
+import com.fs.course.service.CourseRedPacketStatisticsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @description: 看客红包统计
+ * @author: Xgb
+ * @createDate: 2025/10/14
+ * @version: 1.0
+ */
+@Service
+public class CourseRedPacketStatisticsServiceImpl implements CourseRedPacketStatisticsService {
+
+    @Autowired
+    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
+
+    @Override
+    public List<CourseRedPacketStatisticsDTO> statistics(CourseRedPacketStatisticsParam param) {
+        return fsCourseRedPacketLogMapper.statistics(param);
+    }
+}

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

@@ -1,18 +1,24 @@
 package com.fs.course.service.impl;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.course.config.CourseConfig;
+import com.fs.course.config.RedPacketConfig;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.param.FsCourseRedPacketLogParam;
@@ -22,9 +28,16 @@ import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.system.service.ISysConfigService;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsGetResult;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.TransferService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
@@ -300,6 +313,64 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
         }
     }
 
+    @Override
+    public void queryRedPacketResult(String startTime, String endTime) {
+        LocalDateTime tenMinutesAgo;
+        LocalDateTime twentyMinutesAgo;
+        if(StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)){
+            // 获取前十分钟时间 和 前二十分钟时间
+            tenMinutesAgo = LocalDateTime.now().minusMinutes(10);
+            twentyMinutesAgo = tenMinutesAgo.minusMinutes(10);
+        }else {
+            tenMinutesAgo = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            twentyMinutesAgo = LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        }
+
+        // 获取前分钟时间
+        Map<String, Object> params = new HashMap<>();
+        params.put("startTime", twentyMinutesAgo);
+        params.put("endTime",tenMinutesAgo);
+        // 获取前十分钟红包记录状态为发送中的记录
+        List<FsCourseRedPacketLog> redPacketLogs = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogListBySending(params);
+        if(redPacketLogs!=null && !redPacketLogs.isEmpty()){
+            String json = configService.selectConfigByKey("redPacket.config");
+            RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
+            //创建微信订单
+            WxPayConfig payConfig = new WxPayConfig();
+            BeanUtils.copyProperties(config,payConfig);
+            WxPayService wxPayService = new WxPayServiceImpl();
+            wxPayService.setConfig(payConfig);
+            TransferService transferService=wxPayService.getTransferService();
+            for(FsCourseRedPacketLog redPacket:redPacketLogs){
+                // 获取批次号
+                // redPacket.getResult() {"msg":"发送红包成功","code":200,"mchId":"1703311381","data":{"createTime":"2025-06-26T18:00:48+08:00","outBillNo":"fsCourse1938175604536901632","packageInfo":"ABBQO+oYAAABAAAAAABRil0NtaWxBS5JURpdaBAAAADnGpepZahT9IkJjn90+1qgtzWOmCRNZJfek1QMbZ9ktG8idrj37//0xOSt0T67XUFE+PGeXO8qZoNKHYlU3RicIHExIjZr342xE+QjrpjaHIFYoPg=","state":"WAIT_USER_CONFIRM","transferBillNo":"1330007292140242506260028904279364"},"isNew":1}
+                // 获取 transferBillNo
+                String batchId;
+                try {
+                    batchId = StringUtils.isNotEmpty(redPacket.getBatchId())?redPacket.getBatchId():JSON.parseObject(redPacket.getResult()).getJSONObject("data").getString("transferBillNo");
+                }catch (Exception e){
+                    logger.error("【红包处理】获取批次号失败,FsCourseRedPacketLog-log_id:{}",redPacket.getLogId());
+                    continue;
+                }
+
+                try {
+                    TransferBillsGetResult queryRedPacketResult = transferService.getBillsByTransferBillNo(batchId);
+                    logger.info("FsCourseRedPacketLog-log_id:{},【红包处理】查询批次结果:{}",redPacket.getLogId(),queryRedPacketResult);
+                    if(queryRedPacketResult!=null && "SUCCESS".equals(queryRedPacketResult.getState())){
+                        FsCourseRedPacketLog fsCourseRedPacketLog=new FsCourseRedPacketLog();
+                        fsCourseRedPacketLog.setLogId(redPacket.getLogId());
+                        fsCourseRedPacketLog.setStatus(1); // 已发送
+                        fsCourseRedPacketLog.setUpdateTime(new Date());
+//                        updateFsCourseRedPacketLog(fsCourseRedPacketLog);
+                    }
+                } catch (WxPayException e) {
+                    logger.error(e.getMessage());
+                }
+            }
+        }
+    }
+
+
     private void processRedPacket(FsCourseRedPacketLog redPacket, CourseConfig config) {
         // 获取用户信息
         FsUser user = fsUserMapper.selectFsUserByUserId(redPacket.getUserId());

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

@@ -185,8 +185,6 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
         }
         if (ObjectUtils.isNotEmpty(param.getTabType())&&param.getTabType().equals("common")){
             param.setCommon(param.getTabType());
-        }else if(ObjectUtils.isNotNull(param.getCompanyId())){
-            param.setCommon("company");
         }
         List<FsCourseTrafficLogListVO> fsCourseTrafficLogListVOS = fsCourseTrafficLogMapper.selectTrafficNew(param);
         for (FsCourseTrafficLogListVO log : fsCourseTrafficLogListVOS) {

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

@@ -4,6 +4,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.BeanCopyUtils;
@@ -55,6 +56,7 @@ import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qwApi.Result.QwAddContactWayResult;
+import com.fs.qwApi.Result.QwGroupChatDetailsResult;
 import com.fs.qwApi.param.QwAddContactWayParam;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.mapper.QwSopLogsMapper;
@@ -479,6 +481,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         Integer isRoom = param.getIsRoom();
 
         // 处理逻辑
+        if(StringUtils.isNotEmpty(param.getChatId())){
+            return handleQwRoom(param, fsUser);
+        }
         if (isRoom == null || isRoom == 0) {
             // 当 isRoom 为 null 或 0 时走 handleExt
             return handleExt(param,msg, oneCompanyCourse);
@@ -492,7 +497,88 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
 
     }
+    private R handleQwRoom(FsUserCourseVideoAddKfUParam param,FsUser user) {
+        FsCourseLink courseLink = courseLinkMapper.selectFsCourseLinkByLink(param.getLink());
+        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为群会员独享<br>请长按二维码</div>\n" +
+                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
+        QwGroupChatDetailsResult result = qwApiService.groupChatDetails(courseLink.getChatId(), param.getCorpId());
+        log.info("群聊参数:{},链接参数:{}, 企微返回:{}", JSON.toJSONString(param), JSON.toJSONString(courseLink), JSON.toJSONString(result));
+        if(result.getErrCode() != 0){
+            return R.error("企微接口请求失败,请联系管理员:" +result.getErrMsg());
+        }
+//            List<QwGroupChatDetailsResult.Member> collect = result.getGroupChat().getMemberList().stream().filter(e -> e.getType() == 2).collect(Collectors.toList());
+//            if(collect.isEmpty()){
+//                return addCustomerService(param.getQwUserId(),msg);
+//            }
+//            Optional<QwGroupChatDetailsResult.Member> optional = collect.stream().filter(e -> e.getName().equals(fsUser.getNickName()) || e.getName().equals(param.getNickName())).findFirst();
+//            if(!optional.isPresent()){
+//                return addCustomerService(param.getQwUserId(),msg);
+//            }
+//            QwGroupChatDetailsResult.Member member = optional.get();
+//            QwExternalContact qwExternalContact =
+//                    qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+//                    .eq("user_id", result.getGroupChat().getOwner())
+//                    .eq("external_user_id", member.getUserId())
+//                    );
+        QwExternalContact qwExternalContact =
+                qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+                        .eq("user_id", result.getGroupChat().getOwner())
+                        .eq("fs_user_id", param.getUserId())
+                        .eq("corp_id", param.getCorpId())
+                        .eq("status",0));
+        if(qwExternalContact==null){
+            return addCustomerService(param.getQwUserId(),msg);
+        }
+        log.info("外部联系人数据:{}", qwExternalContact);
+        if(result.getGroupChat().getMemberList().stream().noneMatch(e -> e.getUserId().equals(qwExternalContact.getExternalUserId()))){
+            return addCustomerService(param.getQwUserId(),msg);
+        }
+        Long qwExternalId = qwExternalContact.getId();
+//        addCompanyCompanyFsUser(param);
+        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(),param.getQwUserId());
+        if (log==null ){
+            return addCustomerService(param.getQwUserId(),msg);
+        }
+        //判断外部联系人有没有绑定userId
+        if (qwExternalContact.getFsUserId()!=null){
+            //有客户有小程序id  但 登录的小程序id和根据外部联系人id查出来的小程序id不一致
+            if (!qwExternalContact.getFsUserId().equals(param.getUserId())) {
+                return addCustomerService(param.getQwUserId(),msg);
+            }
+            List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByMiniUserId(param.getUserId());
+            //匹配客户公司id
+            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))){
+                return addCustomerService(param.getQwUserId(),msg);
+            }
+
+            //看课记录中userId为0绑定userId
+            if (log.getUserId()==null||log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())){
+                log.setUserId(param.getUserId());
+            }
+
+            log.setUpdateTime(new Date());
+//            fsUserCompanyBindService.bindFsUser(fsUser.getUserId(), qwExternalId, log.getLogId());
+            courseWatchLogMapper.updateFsCourseWatchLog(log);
 
+        }else {
+            //没绑定fsUser直接绑定fsUser
+            QwExternalContact contact = new QwExternalContact();
+            contact.setId(qwExternalId);
+            contact.setFsUserId(param.getUserId());
+            qwExternalContactMapper.updateQwExternalContact(contact);
+            FsUser fsUser = new FsUser();
+            fsUser.setUserId(user.getUserId());
+            fsUser.setIsAddQw(1);
+            fsUserMapper.updateFsUser(fsUser);
+            //绑定上之后 更新观看记录
+            //看课记录中userId为0绑定userId
+            log.setUserId(param.getUserId());
+            log.setUpdateTime(new Date());
+            courseWatchLogMapper.updateFsCourseWatchLog(log);
+        }
+//        fsUserCompanyBindService.bindFsUser(fsUser.getUserId(), qwExternalId, log.getLogId());
+        return R.error(567,"群聊通用链接").put("qwExternalId", qwExternalContact.getId());
+    }
     private R handleRoom(FsUserCourseVideoAddKfUParam param,FsUser user) {
         //查询客户列表
         List<QwExternalContact> contacts = qwExternalContactMapper.selectQwExternalContactListVOByfsUserId(user.getUserId());
@@ -1142,7 +1228,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return sendIntegralReward(param,user, log, config);
             // 红包+积分
             case 3:
-                R sendRed = sendRedPacketReward(param, user, log, video, config);
+                R sendRed = sendRedPacketRewardFsUser(param, user, log, video, config);
                 if (!Objects.equals(sendRed.get("code"), 200)) {
                     return sendRed;
                 }
@@ -1344,9 +1430,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         BigDecimal amount = BigDecimal.ZERO;
         FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId(), param.getPeriodId());
 
-        if (redPackage != null) {
+        if (redPackage != null && redPackage.getRedPacketMoney() != null) {
             amount = redPackage.getRedPacketMoney();
-        } else if (video != null) {
+        } else if (video != null && video.getRedPacketMoney() != null) {
             amount = video.getRedPacketMoney();
         }
 
@@ -1401,7 +1487,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
             Company company = companyMapper.selectCompanyById(param.getCompanyId());
             BigDecimal money = company.getMoney();
-            if (money.compareTo(BigDecimal.ZERO)<0) {
+            if (money.compareTo(BigDecimal.ZERO)<=0) {
                 return R.error("服务商余额不足,请联系群主服务器充值!");
             }
 
@@ -1414,6 +1500,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                     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());
@@ -1585,6 +1672,11 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         courseWatchLogMapper.updateFsCourseWatchLog(log);
         logger.info("发放奖励====================》看课记录,{}",log);
 
+        // 红德堂不要积分转红包
+        if (CloudHostUtils.hasCloudHostName("弘德堂")) {
+            return R.ok("奖励发放成功").put("rewardType",config.getRewardType());
+        }
+
         //转换红包
         FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
         redPacketLog.setCourseId(param.getCourseId());

+ 7 - 3
fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java

@@ -75,6 +75,13 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @Excel(name = "所属销售")
     private String companyUserName;
 
+    @Excel(name = "所属sop任务")
+    private String sopId;
+
+    @Excel(name = "营期时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date campPeriodTime;
+
     /** 所属团队 */
 //    @Excel(name = "所属团队")
     private String companyName;
@@ -105,9 +112,6 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date finishTime;
 
-    @Excel(name = "营期时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    private Date campPeriodTime;
 
     @Excel(name = "进线时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

+ 2 - 0
fs-service/src/main/java/com/fs/his/domain/FsUser.java

@@ -148,6 +148,8 @@ public class FsUser extends BaseEntity
 
     private Long qwExtId;
 
+    /** 下单次数 */
+    private Long orderCount;
     /**
      * 企微销售ID
      * **/

+ 28 - 0
fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountScrmStatsQueryDto.java

@@ -0,0 +1,28 @@
+package com.fs.his.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * app商城订单金额统计queryDto对象
+ * */
+@Data
+public class FsStoreOrderAmountScrmStatsQueryDto implements Serializable {
+    /**
+     * 销售公司id
+     * */
+    private Long companyId;
+    /**
+     * 销售人员id
+     * */
+    private Long companyUserId;
+    /**
+     * 订单开始时间
+     * */
+    private String startTime;
+    /**
+     * 订单结束时间
+     * */
+    private String endTime;
+}

+ 28 - 0
fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountStatsQueryDto.java

@@ -0,0 +1,28 @@
+package com.fs.his.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 互联网医院订单金额统计queryDto对象
+ * */
+@Data
+public class FsStoreOrderAmountStatsQueryDto  implements Serializable {
+    /**
+     * 销售公司id
+     * */
+    private Long companyId;
+    /**
+     * 销售人员id
+     * */
+    private Long companyUserId;
+    /**
+     * 订单开始时间
+     * */
+    private String startTime;
+    /**
+     * 订单结束时间
+     * */
+    private String endTime;
+}

+ 3 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java

@@ -14,6 +14,7 @@ import com.fs.his.domain.FsInquiryOrderMsg;
 import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.domain.FsStoreOrderItem;
 import com.fs.his.domain.FsStoreOrderLogs;
+import com.fs.his.dto.FsStoreOrderAmountStatsQueryDto;
 import com.fs.his.param.*;
 import com.fs.his.vo.*;
 import org.apache.ibatis.annotations.Param;
@@ -1177,4 +1178,6 @@ public interface FsStoreOrderMapper
 
 
     List<Report> selectOrderByCustomerIds(@Param("map") ReportParam param);
+
+    FsStoreOrderAmountStatsVo selectFsStoreOrderAmountStats(FsStoreOrderAmountStatsQueryDto queryDto);
 }

+ 6 - 4
fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java

@@ -15,10 +15,7 @@ import com.fs.erp.dto.df.BspOrderResponse;
 import com.fs.erp.dto.df.DFConfigVo;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.his.domain.*;
-import com.fs.his.dto.ExpressInfoDTO;
-import com.fs.his.dto.ExpressNotifyDTO;
-import com.fs.his.dto.ExpressResultDTO;
-import com.fs.his.dto.StoreOrderExpressExportDTO;
+import com.fs.his.dto.*;
 import com.fs.his.param.*;
 import com.fs.his.vo.*;
 import org.springframework.transaction.annotation.Transactional;
@@ -267,4 +264,9 @@ public interface IFsStoreOrderService
     String selectFsStoreOrderProductStatistics(FsStoreOrderParam fsStoreOrder);
 
     int afterSalesByProduct(FsStoreOrderSalesParam fsStoreOrder);
+
+    /**
+     * 查询互联网医院订单金额统计信息
+     * */
+    FsStoreOrderAmountStatsVo selectFsStoreOrderAmountStats(FsStoreOrderAmountStatsQueryDto queryDto);
 }

+ 5 - 0
fs-service/src/main/java/com/fs/his/service/IFsStorePaymentService.java

@@ -97,6 +97,10 @@ public interface IFsStorePaymentService
 
     R sendRedPacketV3(WxSendRedPacketParam param);
 
+    R sendRedPacketLimit(WxSendRedPacketParam param);
+
+    R sendRedPacketDeduction(WxSendRedPacketParam param);
+
     String transferNotify(String notifyData, HttpServletRequest request);
 
     Boolean isEntityNull(FsStorePaymentParam fsStorePayment);
@@ -120,4 +124,5 @@ public interface IFsStorePaymentService
     R paymentByWxaCode(FsStorePaymentPayParam payment);
 
     R getWxaCodeByPayment(FsStorePaymentGetWxaCodeParam param);
+
 }

+ 4 - 4
fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java

@@ -121,8 +121,8 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
     private JpushService jpushService;
     @Autowired
     IPayService payService;
-    @Autowired
-    SmsServiceImpl smsService;
+//    @Autowired
+//    SmsServiceImpl smsService;
     @Autowired
     private FsInquiryOrderMapper fsInquiryOrderMapper;
     @Autowired
@@ -908,7 +908,7 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
                 FsUser fsUser = fsUserService.selectFsUserByUserId(order.getUserId());
                 if (fsUser!=null&&fsUser.getPhone()!=null){
                     logger.info("医生接单发送短信:"+fsUser.getPhone()+patientDTO.getPatientName());
-                    smsService.sendUserSms(fsUser.getPhone(), patientDTO.getPatientName(), "3");
+//                    smsService.sendUserSms(fsUser.getPhone(), patientDTO.getPatientName(), "3");
                 }
 
             }
@@ -1044,7 +1044,7 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
                 FsUser fsUser = fsUserService.selectFsUserByUserId(order.getUserId());
                 if (fsUser!=null&&fsUser.getPhone()!=null){
                     logger.info("医生接单发送短信:"+fsUser.getPhone()+patientDTO.getPatientName());
-                    smsService.sendUserSms(fsUser.getPhone(), patientDTO.getPatientName(), "3");
+//                    smsService.sendUserSms(fsUser.getPhone(), patientDTO.getPatientName(), "3");
                 }
 
             }

+ 198 - 2
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -102,6 +102,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.util.CollectionUtils;
 
+import javax.annotation.PostConstruct;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
@@ -277,7 +278,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     private FsStoreOrderDfMapper fsStoreOrderDfMapper;
     @Autowired
     private FsUserWxMapper fsUserWxMapper;
-
+    @Autowired
+    private FsUserMapper fsUserMapper;
     @Autowired
     private IFsUserWxService userWxService;
 
@@ -287,6 +289,19 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private com.fs.gtPush.service.uniPush2Service uniPush2Service;
 
+    //ERP 类型到服务的映射
+    private Map<Integer, IErpOrderService> erpServiceMap;
+    @PostConstruct
+    public void initErpServiceMap() {
+        erpServiceMap = new HashMap<>();
+        erpServiceMap.put(1, gyOrderService);      // 管易
+        erpServiceMap.put(2, wdtOrderService);     // 旺店通
+        erpServiceMap.put(3, hzOMSOrderService);   // 瀚智OMS
+        erpServiceMap.put(4, dfOrderService);      // 代服
+        erpServiceMap.put(5, jSTOrderService);     // 聚水潭
+        erpServiceMap.put(6, k9OrderService);      // K9
+    }
+
     /**
      * 查询订单
      *
@@ -330,8 +345,151 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Override
     public int updateFsStoreOrder(FsStoreOrder fsStoreOrder) {
         fsStoreOrder.setUpdateTime(DateUtils.getNowDate());
+        //推送修改的互联网医院订单地址到聚水潭ERP
+        try {
+            pushOrderAddressToErp(fsStoreOrder);
+        }catch (Exception e){
+            log.error("修改互联网医院订单地址推送到聚水潭ERP失败,orderId: {}", fsStoreOrder.getOrderId(), e);
+        }
         return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
     }
+    /**
+     * 推送修改订单的最新地址到 ERP
+     *
+     * @param partialOrder 前端传入的部分订单对象,必须包含 id、userAddress
+     */
+    public void pushOrderAddressToErp(FsStoreOrder partialOrder){
+        if (partialOrder == null || partialOrder.getOrderId() == null) {
+            log.info("传入订单为空或ID缺失,跳过ERP同步");
+            return;
+        }
+
+        // 1. 检查 ERP 是否开启
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen == null || erpOpen == 0) {
+            log.info("ERP未开启,跳过同步");
+            return;
+        }
+        Integer erpType = sysConfig.getErpType();
+        if (erpType == null || !erpServiceMap.containsKey(erpType)) {
+            log.info("ERP类型配置无效: {}", erpType);
+            return;
+        }
+        //目前只针对聚水潭ERP推送最新的修改地址
+        if (erpType != 5){
+            return;
+        }
+        // 2. 从数据库获取完整订单(用于补全必要字段;当前是修改商城订单接口,查询fs_store_order_scrm表)
+        FsStoreOrder dbOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderId(partialOrder.getOrderId());
+        if (dbOrder == null) {
+            log.error("数据库表fs_store_order中订单不存在,orderId: {}", partialOrder.getOrderId());
+            return;
+        }
+        //判断当前是否满足推送条件(erp订单号不为空且订单状态为待发货时可推送)
+        if (StringUtils.isBlank(dbOrder.getExtendOrderId()) || dbOrder.getStatus() != 1) {
+            log.info("修改订单地址不满足推送到ERP条件: extendOrderId={}, status={}", dbOrder.getExtendOrderId(), dbOrder.getStatus());
+            return;
+        }
+        // 3. 构造用于ERP推送的订单对象:订单地址用传入的新值
+        if (StrUtil.isBlank(partialOrder.getUserAddress())){
+            log.error("修改互联网医院订单地址为空,orderId: {}", partialOrder.getOrderId());
+            return;
+        }
+        dbOrder.setUserAddress(partialOrder.getUserAddress());
+        // 4. 构建 ERP 订单对象
+        try {
+        ErpOrder erpOrder = buildErpOrder(dbOrder,sysConfig);
+
+        // 5. 调用对应 ERP 服务(当前是聚水潭ERP)
+        IErpOrderService erpService = erpServiceMap.get(erpType);
+
+        //执行互联网医院订单推送逻辑
+        ErpOrderResponse response = erpService.addOrder(erpOrder);
+        log.info("ERP地址推送结果 - 互联网医院订单: {}, ERP类型: {}, 成功: {}, 外部单号: {}",
+                dbOrder.getOrderCode(), erpType, response.getSuccess(), response.getCode());
+        } catch (Exception e) {
+            log.error("推送修改互联网医院订单地址到ERP失败,orderId: {}", partialOrder.getOrderId(), e);
+        }
+    }
+
+    /**
+     * 构建 ErpOrder 对象(仅用于修改互联网医院订单地址推送到聚水潭ERP)
+     */
+    private ErpOrder buildErpOrder(FsStoreOrder order, FsSysConfig sysConfig) {
+        ErpOrder erpOrder = new ErpOrder();
+
+        //订单号
+        erpOrder.setPlatform_code(order.getOrderCode());
+
+        // 店铺编码
+        erpOrder.setShop_code(sysConfig.getErpJstShopCode());
+        erpOrder.setBuyer_account(order.getUserName());
+        //成交时间
+        erpOrder.setDeal_datetime(order.getBeginTime());
+        //支付信息
+        List<ErpOrderPayment> payments = new ArrayList<>();
+        ErpOrderPayment payment = new ErpOrderPayment();
+        payment.setPay_type_code("weixin");
+        erpOrder.setPayments(payments);
+        //卖家留言
+        erpOrder.setBuyer_memo("");
+        //推送聚水潭erp不需要推送处方图片,这里就注释代码
+        //String s = fsPrescribeService.PrescribeImg(order.getPrescribeId());
+        //erpOrder.setSeller_memo(erpOrder.getSeller_memo() + "||" + s + "||");
+        // 收货人姓名(过滤非法字符)
+        erpOrder.setReceiver_name(order.getUserName().replaceAll("[^\\u4e00-\\u9fa5a-zA-Z0-9]", ""));
+        // 电话处理
+        String phone = null;
+        if (StrUtil.isNotBlank(order.getErpPhone())) {
+            phone = order.getErpPhone();
+        } else if (StrUtil.isNotBlank(order.getUserPhone())) {
+            // 如果手机号被加密(长度>11),需解密
+            phone = order.getUserPhone().length() > 11 ? decryptPhone(order.getUserPhone()) : order.getUserPhone();
+        }
+
+        if (StrUtil.isNotBlank(phone)) {
+            if (phone.length() > 11) {
+                erpOrder.setReceiver_phone(phone);     // 固话
+            } else {
+                erpOrder.setReceiver_mobile(phone);    // 手机
+            }
+        }
+
+        // 地址解析
+        String userAddress = order.getUserAddress();
+        try {
+            String[] parts = userAddress.split(" ");
+            if (parts.length < 3) {
+                // 调用地址解析服务(如快递鸟)
+                String kdnResult = fsUserAddressService.getKdnAddress(userAddress);
+                Map<String, Object> result = JSON.parseObject(kdnResult);
+                Map<String, String> addr = (Map<String, String>) ((Map) result.get("Data")).get("result");
+                erpOrder.setReceiver_province(addr.get("ProvinceName"));
+                erpOrder.setReceiver_city(addr.get("CityName"));
+                erpOrder.setReceiver_district(addr.get("ExpAreaName"));
+                erpOrder.setReceiver_address(addr.get("StreetName") + addr.get("Address"));
+            } else {
+                erpOrder.setReceiver_province(parts[0]);
+                erpOrder.setReceiver_city(parts[1]);
+                erpOrder.setReceiver_district(parts[2]);
+                erpOrder.setReceiver_address(parts.length > 3 ? String.join("", Arrays.copyOfRange(parts, 3, parts.length)) : parts[2]);
+            }
+
+            // 清理地址中的特殊字符
+            if (erpOrder.getReceiver_address() != null) {
+                erpOrder.setReceiver_address(
+                        erpOrder.getReceiver_address()
+                                .replace("+", "加")
+                                .replace("\n", "")
+                                .replace("\r", "")
+                );
+            }
+        } catch (Exception e) {
+            log.error("修改订单地址解析异常,订单: {}", order.getOrderCode(), e);
+        }
+        return erpOrder;
+    }
 
     /**
      * 修改订单状态-收货信息
@@ -1490,6 +1648,19 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             }
             storeOrder.setPayTime(new Date());
             fsStoreOrderMapper.updateFsStoreOrder(storeOrder);
+            try {
+                //更新用户下单次数(获取阈值,当订单总价大于等于阈值,则下单次数+1)
+                BigDecimal minThreshold = toBigDecimal(config.get("minimumThreshold"), BigDecimal.ZERO);
+                if (order.getTotalPrice().compareTo(minThreshold) >= 0) {
+                    //根据用户id获取fs_user表对应的下单次数并更新
+                    FsUser user = fsUserMapper.selectFsUserById(order.getUserId());
+                    user.setOrderCount(user.getOrderCount() + 1);
+                    fsUserMapper.updateFsUser(user);
+                }
+            } catch (Exception ex) {
+                // 仅记录日志,这个更新逻辑如果异常不回滚其他逻辑代码
+                log.error("更新用户下单次数失败,订单: {}, 用户: {}", order.getOrderCode(), order.getUserId(), ex);
+            }
             //更新优惠券状态
             if (order.getUserCouponId() != null && order.getUserCouponId() > 0) {
                 FsUserCoupon userCoupon = userCouponService.selectFsUserCouponById(order.getUserCouponId());
@@ -1515,7 +1686,27 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             return R.error();
         }
     }
-
+    public  BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        if (value instanceof String) {
+            String str = ((String) value).trim();
+            return str.isEmpty() ? defaultValue : new BigDecimal(str);
+        }
+        if (value instanceof Number) {
+            return new BigDecimal(((Number) value).toString());
+        }
+        // 兜底:toString 转换
+        try {
+            return new BigDecimal(value.toString().trim());
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
     @Override
     public Long selectFsStoreOrderTotalCount(int type, Long companyId) {
         return fsStoreOrderMapper.selectFsStoreOrderTotalCount(type, companyId);
@@ -3906,4 +4097,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         return 1;
     }
 
+    @Override
+    public FsStoreOrderAmountStatsVo selectFsStoreOrderAmountStats(FsStoreOrderAmountStatsQueryDto queryDto) {
+        return fsStoreOrderMapper.selectFsStoreOrderAmountStats(queryDto);
+    }
+
 }

+ 152 - 68
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -3,9 +3,10 @@ package com.fs.his.service.impl;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
@@ -17,8 +18,6 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.DataScope;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.CustomException;
@@ -26,7 +25,6 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.ip.IpUtils;
-import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyConfigMapper;
@@ -39,19 +37,15 @@ import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
-import com.fs.course.config.CourseConfig;
 import com.fs.course.config.RedPacketConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
-import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.IFsUserVipOrderService;
-import com.fs.erp.dto.ErpRefundUpdateRequest;
 import com.fs.his.domain.*;
 import com.fs.his.dto.PayConfigDTO;
 import com.fs.his.enums.PaymentMethodEnum;
 import com.fs.his.mapper.*;
-import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStorePaymentParam;
 import com.fs.his.param.PayOrderParam;
 import com.fs.his.param.WxSendRedPacketParam;
@@ -77,7 +71,6 @@ import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
 import com.fs.tzBankPay.TzBankService.TzBankService;
-import com.fs.tzBankPay.TzBankService.TzBankServiceImpl.TzBankServiceImpl;
 import com.fs.tzBankPay.doman.*;
 import com.fs.ybPay.domain.CreateWxOrderResult;
 import com.fs.ybPay.domain.OrderResult;
@@ -85,45 +78,35 @@ import com.fs.ybPay.dto.OrderQueryDTO;
 import com.fs.ybPay.dto.RefundDTO;
 import com.fs.ybPay.dto.WxJspayDTO;
 import com.fs.ybPay.service.IPayService;
-import com.github.binarywang.wxpay.bean.merchanttransfer.TransferCreateRequest;
-import com.github.binarywang.wxpay.bean.merchanttransfer.TransferCreateResult;
 import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
 import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
 import com.github.binarywang.wxpay.bean.notify.WxPayTransferBatchesNotifyV3Result;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
-import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
 import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
 import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
 import com.github.binarywang.wxpay.bean.transfer.*;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
-import com.github.binarywang.wxpay.service.MerchantTransferService;
-import com.github.binarywang.wxpay.service.RedpackService;
 import com.github.binarywang.wxpay.service.TransferService;
 import com.github.binarywang.wxpay.service.WxPayService;
-import com.github.binarywang.wxpay.service.impl.RedpackServiceImpl;
 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import com.google.gson.Gson;
 import com.hc.openapi.tool.fastjson.JSON;
-import com.wechat.pay.java.service.transferbatch.TransferBatchService;
-import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
-import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.api.WxMpService;
 import org.apache.commons.lang.exception.ExceptionUtils;
-import org.apache.hc.core5.concurrent.CompletedFuture;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.aop.framework.AopContext;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
 import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
@@ -137,6 +120,7 @@ import javax.servlet.http.HttpServletRequest;
  * @date 2023-08-11
  */
 @Service
+@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
 public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     Logger logger = LoggerFactory.getLogger(getClass());
     @Autowired
@@ -207,10 +191,23 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     @Value("${enableRedPackAccount:0}")
     private String ENABLE_RED_PACK_ACCOUNT;
 
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Autowired
+    private RedPacketLogMapper redPacketLogMapper;
+
     /**
      * 红包账户锁
      */
     private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+    /**
+     * 红包锁
+     */
+    private static final String REDPACKET_LOCK = "redpacket_lock:%d";
 
     /**
      * 公司红包金额
@@ -222,6 +219,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
      */
     private static final String REDPACKET_USER_LIMIT = "redpacket_user_limit:%s:%d";
 
+
+
     /**
      * 查询支付明细
      *
@@ -525,18 +524,111 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         return fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
     }
 
-    @Autowired
-    private ICompanyConfigService companyConfigService;
 
-    @Autowired
-    private RedissonClient redissonClient;
-
-    @Autowired
-    private RedPacketLogMapper redPacketLogMapper;
     @Override
     @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
     public R sendRedPacket(WxSendRedPacketParam param) {
+        IFsStorePaymentService service = (IFsStorePaymentService) AopContext.currentProxy();
+
+        if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+            return service.sendRedPacketDeduction(param);
+        } else {
+            return service.sendRedPacketLimit(param);
+        }
+    }
+
+
+    @Override
+    public R sendRedPacketLimit(WxSendRedPacketParam param){
+        FsUser user = param.getUser();
+
+        if(user == null) {
+            throw new IllegalArgumentException("[发送红包] 用户id为必传参数!");
+        }
+        Long userId = user.getUserId();
 
+        String key = String.format(REDPACKET_LOCK,userId);
+        RLock lock = redissonClient.getLock(key);
+
+        try{
+            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+            if (!locked) {
+                logger.error("获取锁失败");
+                return R.error("[红包领取] 系统繁忙,请重试!");
+            }
+
+
+            // 判断当前用户是否限流
+            String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
+            String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, userId);
+            Integer userCount =  redisTemplateInteger.opsForValue().get(userLimitKey);
+
+
+            // 首次领取
+            if(userCount == null) {
+                userCount = 0;
+                long expireSeconds = getExpireSeconds();
+                redisTemplateInteger.opsForValue().set(userLimitKey, userCount, expireSeconds, TimeUnit.SECONDS);
+            }
+
+            if(userCount >= RED_PACKET_LIMIT_COUNT){
+                logger.info("[红包领取] 用户{} 领取红包已经达到最大限制!",userId);
+                return R.error("[红包领取] 当前用户当前已经领取红包已经达到限制!");
+            }
+
+            String json;
+            RedPacketConfig config = new RedPacketConfig();
+            // 根据红包模式获取配置
+            switch (param.getRedPacketMode()){
+                case 1:
+                    json = configService.selectConfigByKey("redPacket.config");
+                    config = JSONUtil.toBean(json, RedPacketConfig.class);
+                    break;
+                case 2:
+                    json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
+                    config = JSONUtil.toBean(json, RedPacketConfig.class);
+                    break;
+                default:
+                    throw new UnsupportedOperationException("当前红包模式不支持!");
+            }
+            //H5的用公众号的appid发,小程序的用小程序的appid来发
+            if (param.getSource()==2){
+                // 传参appId为空时,仍然使用配置里面的
+                String appId = StringUtils.isBlank(param.getAppId()) ? config.getMiniappId() : param.getAppId();
+                config.setAppId(appId);
+            }
+            logger.info("最终传参 {}",config);
+            //组合返回参数
+            R result = new R();
+            // 根据 isNew 判断使用哪种发红包方式
+            if (config.getIsNew() != null && config.getIsNew() == 1) {
+                result = sendRedPacketV3Internal(param, config);
+            } else {
+                result= sendRedPacketLegacyInternal(param, config);
+            }
+            result.put("mchId", config.getMchId());
+            result.put("isNew",config.getIsNew());
+            logger.info("红包返回:{}",result);
+
+            // 用户领取红包次数+1
+            redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
+            return result;
+        }catch (Exception e){
+            logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+            throw new RuntimeException(e);
+        }finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+
+    /**
+     * 开启红包账户扣减-发红包
+     */
+    @Override
+    public R sendRedPacketDeduction(WxSendRedPacketParam param){
         //---------------发红包前先判断润天账户余额是否足够---------
         RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
         RedPacketLog redPacketLog = null;
@@ -558,8 +650,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             Long userId = user.getUserId();
 
             // 判断当前用户是否限流
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
-            String today = sdf.format(new Date());
+            String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
             String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, userId);
             Integer userCount =  redisTemplateInteger.opsForValue().get(userLimitKey);
 
@@ -577,37 +668,33 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             }
 
 
-            BigDecimal companyMoney = null;
-
-            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
-
-                if(ObjectUtils.isNull(companyMoney)){
-                    SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
-                    if(ObjectUtils.isNull(sysConfig)){
-                        throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
-                    }
-                    String configValue = sysConfig.getConfigValue();
-                    companyMoney = new BigDecimal(configValue);
-                    logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
-                }
+            BigDecimal companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
 
-                if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
-                    logger.info("润天账户余额: {} 不足!", companyMoney);
-                    return R.error("[红包领取] 账户余额不足,请联系管理员!");
+            if(ObjectUtils.isNull(companyMoney)){
+                SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
+                if(ObjectUtils.isNull(sysConfig)){
+                    throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
                 }
+                String configValue = sysConfig.getConfigValue();
+                companyMoney = new BigDecimal(configValue);
+                logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
+            }
 
-                redPacketLog = new RedPacketLog();
-                redPacketLog.setRedPacketMode(param.getRedPacketMode());
-                redPacketLog.setAmount(param.getAmount());
-                redPacketLog.setAppId(param.getAppId());
-                redPacketLog.setCompanyId(param.getCompanyId());
-                redPacketLog.setCreateTime(LocalDateTime.now());
-                redPacketLog.setUserId(userId);
-                redPacketLog.setAccBalanceBefore(companyMoney);
-                redPacketLog.setSource(param.getSource());
+            if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
+                logger.info("润天账户余额: {} 不足!", companyMoney);
+                return R.error("[红包领取] 账户余额不足,请联系管理员!");
             }
 
+            redPacketLog = new RedPacketLog();
+            redPacketLog.setRedPacketMode(param.getRedPacketMode());
+            redPacketLog.setAmount(param.getAmount());
+            redPacketLog.setAppId(param.getAppId());
+            redPacketLog.setCompanyId(param.getCompanyId());
+            redPacketLog.setCreateTime(LocalDateTime.now());
+            redPacketLog.setUserId(userId);
+            redPacketLog.setAccBalanceBefore(companyMoney);
+            redPacketLog.setSource(param.getSource());
+
             String json;
             RedPacketConfig config = new RedPacketConfig();
             // 根据红包模式获取配置
@@ -620,6 +707,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
                     json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
                     config = JSONUtil.toBean(json, RedPacketConfig.class);
                     break;
+                default:
+                    throw new UnsupportedOperationException("当前红包模式不支持!");
             }
             //H5的用公众号的appid发,小程序的用小程序的appid来发
             if (param.getSource()==2){
@@ -640,20 +729,17 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             result.put("isNew",config.getIsNew());
             logger.info("红包返回:{}",result);
 
+            // 更新账户余额
+            logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
 
-            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                // 更新账户余额
-                logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
+            companyMoney = companyMoney.subtract(amount);
+            redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
 
-                companyMoney = companyMoney.subtract(amount);
-                redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
+            redPacketLog.setAccBalanceAfter(companyMoney);
+            redPacketLog.setUpdateTime(LocalDateTime.now());
+            redPacketLog.setStatus(1);
 
 
-                redPacketLog.setAccBalanceAfter(companyMoney);
-                redPacketLog.setUpdateTime(LocalDateTime.now());
-                redPacketLog.setStatus(1);
-            }
-
             // 用户领取红包次数+1
             redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
 
@@ -1386,8 +1472,6 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         }
     }
 
-
-
     @Override
     public R paymentByWxaCode(FsStorePaymentPayParam param) {
         FsUser user = userMapper.selectFsUserById(param.getUserId());

+ 44 - 0
fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountScrmStatsVo.java

@@ -0,0 +1,44 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+/**
+ *  app商城订单金额统计Vo对象
+ * */
+@Data
+public class FsStoreOrderAmountScrmStatsVo {
+    /**
+     * 订单总数
+     * */
+    private Integer totalOrderCount;
+    /**
+     * 全款支付订单数
+     * */
+    private Integer fullPayOrderCount;
+    /**
+     * 物流代收支付订单数
+     * */
+    private Integer codOrderCount;
+
+    /**
+     * 付定金的物流代收订单数
+     * */
+    private Integer depositCodOrderCount;
+    /**
+     * 0定金的物流代收订单数
+     * */
+    private Integer noDepositCodOrderCount;
+    /**
+     * 订单总金额
+     * */
+    private BigDecimal totalOrderAmount;
+    /**
+     * 定金总金额
+     * */
+    private BigDecimal depositAmount;
+    /**
+     * 物流代收总金额
+     * */
+    private BigDecimal codAmount;
+}

+ 44 - 0
fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountStatsVo.java

@@ -0,0 +1,44 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+/**
+ *  互联网医院订单金额统计Vo对象
+ * */
+@Data
+public class FsStoreOrderAmountStatsVo {
+    /**
+     * 订单总数
+     * */
+    private Integer totalOrderCount;
+    /**
+     * 全款支付订单数
+     * */
+    private Integer fullPayOrderCount;
+    /**
+     * 物流代收支付订单数
+     * */
+    private Integer codOrderCount;
+
+    /**
+     * 付定金的物流代收订单数
+     * */
+    private Integer depositCodOrderCount;
+    /**
+     * 0定金的物流代收订单数
+     * */
+    private Integer noDepositCodOrderCount;
+    /**
+     * 订单总金额
+     * */
+    private BigDecimal totalOrderAmount;
+    /**
+     * 定金总金额
+     * */
+    private BigDecimal depositAmount;
+    /**
+     * 物流代收总金额
+     * */
+    private BigDecimal codAmount;
+}

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java

@@ -10,6 +10,8 @@ import com.fs.api.vo.OrderListVO;
 import com.fs.company.param.CompanyStatisticsParam;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.dto.FsStoreOrderAmountScrmStatsQueryDto;
+import com.fs.his.vo.FsStoreOrderAmountScrmStatsVo;
 import com.fs.his.vo.FsStoreOrderExcelVO;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.domain.FsStoreOrderItemScrm;
@@ -1217,4 +1219,6 @@ public interface FsStoreOrderScrmMapper
             "        where order_code = #{orderCode}"+
             "</script>"})
     int updateFsStoreOrderByOrderCode(FsStoreOrderScrm fsStoreOrder);
+
+    FsStoreOrderAmountScrmStatsVo selectFsStoreOrderAmountScrmStats(FsStoreOrderAmountScrmStatsQueryDto queryDto);
 }

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

@@ -13,7 +13,9 @@ import com.fs.company.domain.CompanyUser;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.erp.domain.ErpOrder;
 import com.fs.his.domain.FsStorePayment;
+import com.fs.his.dto.FsStoreOrderAmountScrmStatsQueryDto;
 import com.fs.his.param.FsStoreOrderSalesParam;
+import com.fs.his.vo.FsStoreOrderAmountScrmStatsVo;
 import com.fs.his.vo.FsStoreOrderExcelVO;
 import com.fs.hisStore.domain.FsStoreOrderItemScrm;
 import com.fs.hisStore.domain.FsStoreOrderLogsScrm;
@@ -282,4 +284,9 @@ public interface IFsStoreOrderScrmService
      * @param dtoList 订单数据
      * **/
     R importDeliveryNoteExpress(List<FsOrderDeliveryNoteDTO> dtoList);
+
+    /**
+     * 查询app商城订单金额统计信息
+     * */
+    FsStoreOrderAmountScrmStatsVo selectFsStoreOrderAmountScrmStats(FsStoreOrderAmountScrmStatsQueryDto queryDto);
 }

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

@@ -47,6 +47,7 @@ import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.dto.FsPrescribeUsageDTO;
 import com.fs.his.dto.FsProdItemDTO;
+import com.fs.his.dto.FsStoreOrderAmountScrmStatsQueryDto;
 import com.fs.his.dto.FsStoreOrderItemDTO;
 import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.enums.FsStoreOrderStatusEnum;
@@ -56,6 +57,7 @@ import com.fs.his.service.IFsPrescribeService;
 import com.fs.his.service.IFsUserWatchService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsInquiryOrderVO;
+import com.fs.his.vo.FsStoreOrderAmountScrmStatsVo;
 import com.fs.his.vo.FsStoreOrderExcelVO;
 import com.fs.hisStore.config.FsErpConfig;
 import com.fs.hisStore.dto.*;
@@ -104,6 +106,7 @@ import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
+import javax.annotation.PostConstruct;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.nio.charset.Charset;
@@ -314,6 +317,18 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Autowired
     private FsPackageOrderMapper fsPackageOrderMapper;
 
+    //ERP 类型到服务的映射
+    private Map<Integer, IErpOrderService> erpServiceMap;
+    @PostConstruct
+    public void initErpServiceMap() {
+        erpServiceMap = new HashMap<>();
+        erpServiceMap.put(1, gyOrderService);      // 管易
+        erpServiceMap.put(2, wdtOrderService);     // 旺店通
+        erpServiceMap.put(3, hzOMSOrderService);   // 瀚智OMS
+        erpServiceMap.put(4, dfOrderService);      // 代服
+        erpServiceMap.put(5, jSTOrderService);     // 聚水潭
+        erpServiceMap.put(6, k9OrderService);      // K9
+    }
     /**
      * 查询订单
      *
@@ -357,9 +372,75 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Override
     public int updateFsStoreOrder(FsStoreOrderScrm fsStoreOrder) {
         fsStoreOrder.setUpdateTime(DateUtils.getNowDate());
+        //推送修改的商城订单地址到聚水潭ERP
+        try {
+            pushOrderAddressToErp(fsStoreOrder);
+        }catch (Exception e){
+            log.error("修改商城订单地址推送到聚水潭ERP失败,orderId: {}", fsStoreOrder.getId(), e);
+        }
+
         return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
     }
 
+    /**
+     * 推送修改订单的最新地址到 ERP
+     *
+     * @param partialOrder 前端传入的部分订单对象,必须包含 id、userAddress
+     */
+    public void pushOrderAddressToErp(FsStoreOrderScrm partialOrder) {
+        if (partialOrder == null || partialOrder.getId() == null) {
+            log.info("传入订单为空或ID缺失,跳过ERP同步");
+            return;
+        }
+
+        // 1. 检查 ERP 是否开启
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen == null || erpOpen == 0) {
+            log.info("ERP未开启,跳过同步");
+            return;
+        }
+        Integer erpType = sysConfig.getErpType();
+        if (erpType == null || !erpServiceMap.containsKey(erpType)) {
+            log.info("ERP类型配置无效: {}", erpType);
+            return;
+        }
+        //目前只针对聚水潭ERP推送最新的修改地址
+        if (erpType != 5){
+            return;
+        }
+        // 2. 从数据库获取完整订单(用于补全必要字段;当前是修改商城订单接口,查询fs_store_order_scrm表)
+        FsStoreOrderScrm dbOrder = fsStoreOrderMapper.selectFsStoreOrderById(partialOrder.getId());
+        if (dbOrder == null) {
+            log.error("数据库表fs_store_order_scrm中订单不存在,orderId: {}", partialOrder.getId());
+            return;
+        }
+        //判断当前是否满足推送条件(erp订单号不为空且订单状态为待发货时可推送)
+        if (StringUtils.isBlank(dbOrder.getExtendOrderId()) || dbOrder.getStatus() != 1) {
+            log.info("不满足修改订单地址推送到ERP条件: extendOrderId={}, status={}", dbOrder.getExtendOrderId(), dbOrder.getStatus());
+            return;
+        }
+        // 3. 构造用于ERP推送的订单对象:订单地址用传入的新值
+        if (StrUtil.isBlank(partialOrder.getUserAddress())){
+            log.error("修改商城订单地址为空,orderId: {}", partialOrder.getId());
+            return;
+        }
+        dbOrder.setUserAddress(partialOrder.getUserAddress());
+        try {
+        // 4. 构建 ERP 订单对象
+        ErpOrder erpOrder = getErpOrder(dbOrder);
+
+        // 5. 调用对应 ERP 服务(当前是聚水潭ERP)
+        IErpOrderService erpService = erpServiceMap.get(erpType);
+        //执行商城订单推送逻辑
+        ErpOrderResponse response = erpService.addOrderScrm(erpOrder);
+        log.info("ERP地址推送结果 - 商城订单: {}, ERP类型: {}, 成功: {}, 外部单号: {}",
+                dbOrder.getOrderCode(), erpType, response.getSuccess(), response.getCode());
+        } catch (Exception e) {
+            log.error("修改商城订单地址推送到ERP失败,orderId: {}", partialOrder.getId(), e);
+        }
+    }
+
     /**
      * 批量删除订单
      *
@@ -3701,4 +3782,10 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         map.put("DBL", "德邦");
         return map;
     }
+
+
+    @Override
+    public FsStoreOrderAmountScrmStatsVo selectFsStoreOrderAmountScrmStats(FsStoreOrderAmountScrmStatsQueryDto queryDto) {
+        return fsStoreOrderMapper.selectFsStoreOrderAmountScrmStats(queryDto);
+    }
 }

+ 6 - 0
fs-service/src/main/java/com/fs/qw/domain/QwFriendWelcome.java

@@ -45,6 +45,12 @@ public class QwFriendWelcome extends BaseEntity
     @Excel(name = "开启分时段之后的存储")
     private String daypartingItemlist;
 
+    /**
+     * 欢迎语标题
+     */
+    @Excel(name = "欢迎语标题")
+    private String welcomeTitle;
+
     /** 公司id */
     @Excel(name = "公司id")
     private Long companyId;

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

@@ -206,6 +206,7 @@ public interface QwUserMapper extends BaseMapper<QwUser>
             "            <if test=\"qwUserName != null  and qwUserName != ''\"> and qu.qw_user_uame like concat( #{qwUserName}, '%') </if>\n" +
             "            <if test=\"companyUserId != null \"> and qu.company_user_id = #{companyUserId}</if>\n" +
             "            <if test=\"corpId != null \"> and qu.corp_id = #{corpId}</if>\n" +
+            "            <if test=\"deptId != null \"> and qd.dept_id = #{deptId}</if>\n" +
             "            <if test=\"status != null \"> and qu.status = #{status}</if>\n" +
             "            <if test=\"type != null and sendType !=null and type==2 and (sendType==2 or sendType==4 or sendType==11) \"> and qu.app_key IS NOT NULL  </if>\n" +
             "</script>"})

+ 2 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserVideoMapper.java

@@ -72,4 +72,6 @@ public interface QwUserVideoMapper
      * @return 结果
      */
     public int deleteQwUserVideoByIds(Long[] ids);
+
+    QwUserVideo selectByObjectId(@Param("objectId") String objectId, @Param("id") Long id);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/qw/param/QwFriendWelcomeParam.java

@@ -72,4 +72,11 @@ public class QwFriendWelcomeParam extends BaseEntity {
      */
     private String userType;
 
+    /**
+     * 欢迎语标题
+     * ALTER TABLE qw_friend_welcome ADD welcome_title varchar(100) NULL COMMENT '标题';
+     */
+    private String welcomeTitle;
+
+
 }

+ 7 - 0
fs-service/src/main/java/com/fs/qw/param/QwUserListParam.java

@@ -62,4 +62,11 @@ public class QwUserListParam {
      */
     private String userType;
 
+    /**
+     * 0:好友欢迎语
+     * 1:我的欢迎语
+     * 2、部门欢迎语
+     */
+    private String isRemark;
+
 }

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

@@ -62,4 +62,7 @@ public interface IQwUserVideoService
      * @return 结果
      */
     public int deleteQwUserVideoById(Long id);
+
+
+    QwUserVideo selectByObjectId(String objectId, Long id);
 }

+ 34 - 12
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -50,6 +50,7 @@ import com.fs.qwApi.domain.*;
 import com.fs.qwApi.domain.inner.*;
 import com.fs.qwApi.param.*;
 import com.fs.qwApi.service.QwApiService;
+import com.fs.repeat.vo.RepeatUploadVo;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.SopUserLogs;
 import com.fs.sop.domain.SopUserLogsInfo;
@@ -1057,6 +1058,8 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                     } else {
                         qwExternalContactMapper.insertQwExternalContact(qwExternalContact);
                     }
+
+                    logger.info("成功同步一个用户");
                 }
 
             }else {
@@ -2175,7 +2178,9 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
     @Override
     public QwUser getQwUserByRedisForId(String qwUserId) {
-
+        if(StringUtils.isEmpty(qwUserId)){
+            return null;
+        }
         String redisKey = "qwUserRdById:" + qwUserId;
 
         // 直接从Redis获取JSON字符串
@@ -2249,6 +2254,21 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 //            logger.error("重粉提交mq失败", e);
 //        }
 //        iAdHtmlClickLogService.upload(state, AdUploadType.ADD_WX, e -> finalQwExternalContact.setUploadAddWxStatus(1));
+        //重粉问题
+        try {
+            new Thread(() -> {
+                try {
+                    Thread.sleep(3000);
+                } catch (InterruptedException e) {
+                    logger.error("添加等待时长错误", e);
+                }
+                rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(0).externalUserId(externalUserID).build()));
+            }).start();
+        }catch (Exception e){
+            logger.error("重粉提交mq失败", e);
+        }
+
+
 
         //先入一次库
         if (isNewQwExternalContact) {
@@ -2430,6 +2450,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
                     if (wayLogs==null){
 
+
                         QwAppContactWayLogs qwAppContactWayLogs = new QwAppContactWayLogs();
                         qwAppContactWayLogs.setAppWayId(qwAppContactWay.getId());
                         qwAppContactWayLogs.setUserId(qwAppContactWay.getUserId());
@@ -2604,8 +2625,9 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                                 //渠道活码的标签
                                 List<String> wayTags = JSON.parseArray(wayId.getTags(), String.class);
                                 //总添加标签
-                                combinedTagsSet.addAll(wayTags);
-                                logger.info("渠道活码标签,{}===============", wayTags);
+//                                combinedTagsSet.addAll(wayTags);
+                                combinedTagsSet = new HashSet<>(wayTags);
+                                logger.info("渠道活码标签,{}===============,打的标签={}", wayTags,combinedTagsSet);
                             }
 
                             //总标签 转换回列表
@@ -2676,18 +2698,18 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                     }
                     if (wayId.getIsRemark() == 1) {
                         if (wayId.getRemarkStatus() == 1) {
-                            if (!StringUtil.strIsNullOrEmpty(tagRemark)){
-                                qwExternalContact.setRemark(externalContact.getName() + "-" + wayId.getRemark()+"-"+tagRemark);
-                            }else {
+//                            if (!StringUtil.strIsNullOrEmpty(tagRemark)){
+//                                qwExternalContact.setRemark(externalContact.getName() + "-" + wayId.getRemark()+"-"+tagRemark);
+//                            }else {
                                 qwExternalContact.setRemark(externalContact.getName() + "-" + wayId.getRemark());
-                            }
+//                            }
 
                         } else {
-                            if (!StringUtil.strIsNullOrEmpty(tagRemark)){
-                                qwExternalContact.setRemark(tagRemark+"-"+wayId.getRemark() + "-" + externalContact.getName());
-                            }else {
+//                            if (!StringUtil.strIsNullOrEmpty(tagRemark)){
+//                                qwExternalContact.setRemark(tagRemark+"-"+wayId.getRemark() + "-" + externalContact.getName());
+//                            }else {
                                 qwExternalContact.setRemark(wayId.getRemark() + "-" + externalContact.getName());
-                            }
+//                            }
 
                         }
                     }
@@ -4871,7 +4893,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         for (QwOptionsVO qwOptionsVO : qwOptionsVOS) {
             String corpId = qwOptionsVO.getCorpId();
 //            System.out.println("同步的"+corpId);
-//            logger.info("同步的"+corpId);
+            logger.info("同步的"+corpId);
             executor.execute(() ->  qwExternalContactSyncByCorpId(corpId));
         }
         executor.shutdown();

+ 4 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserVideoServiceImpl.java

@@ -100,4 +100,8 @@ public class QwUserVideoServiceImpl implements IQwUserVideoService
     {
         return qwUserVideoMapper.deleteQwUserVideoById(id);
     }
+    @Override
+    public QwUserVideo selectByObjectId(String objectId, Long id) {
+        return qwUserVideoMapper.selectByObjectId(objectId, id);
+    }
 }

+ 2 - 0
fs-service/src/main/java/com/fs/qw/vo/QwExternalContactVO.java

@@ -120,6 +120,8 @@ public class QwExternalContactVO {
     private Long fsUserId;
     @Excel(name = "客户等级")
     private Long level;
+    //下单次数
+    private Long orderCount;
     @Excel(name = "等级升降")
     private Long levelType;
 

+ 6 - 1
fs-service/src/main/java/com/fs/qw/vo/QwFriendWelcomeVO.java

@@ -10,7 +10,7 @@ import java.util.List;
 
 /**
  * 好友欢迎语对象 qw_friend_welcome
- * 
+ *
  * @author fs
  * @date 2024-07-20
  */
@@ -60,6 +60,11 @@ public class QwFriendWelcomeVO extends BaseEntity
     /** 分时段欢迎语 */
     private String daypartingItemlist;
 
+    /**
+     * 欢迎语标题
+     */
+    private String welcomeTitle;
+
     public List<QwUserVO> userSelectList;
 
 }

+ 3 - 2
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempVoiceServiceImpl.java

@@ -10,6 +10,7 @@ import com.fs.common.enums.DataSourceType;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.CompanyQwUserByIdsVo;
 import com.fs.fastgptApi.util.AudioUtils;
@@ -46,7 +47,7 @@ public class QwSopTempVoiceServiceImpl extends ServiceImpl<QwSopTempVoiceMapper,
     private final IQwSopTempContentService qwSopTempContentService;
     private final QwSopMapper qwSopMapper;
     private final QwSopTempDayMapper qwSopTempDayMapper;
-    private final ICompanyUserService companyUserService;
+    private final CompanyUserMapper companyUserMapper;
     private final QwSopTempVoiceMapper qwSopTempVoiceMapper;
     /**
      * 查询模板对应的销售语音文件
@@ -177,7 +178,7 @@ public class QwSopTempVoiceServiceImpl extends ServiceImpl<QwSopTempVoiceMapper,
             return;
         }
         List<Long> qwUserIdList = sopList.stream().flatMap(e -> Arrays.stream(e.getQwUserIds().split(","))).distinct().filter(StringUtils::isNotEmpty).map(Long::parseLong).collect(Collectors.toList());
-        List<CompanyQwUserByIdsVo> companyUserList = companyUserService.selectCompanyQwUserByIds(qwUserIdList);
+        List<CompanyQwUserByIdsVo> companyUserList = companyUserMapper.selectCompanyQwUserByIds(qwUserIdList);
         if (companyUserList.isEmpty()) {
             log.info("sop任务里面的销售为空跳过生成");
             qwSopTempDayMapper.updateVoice(dayId);

+ 8 - 6
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -545,6 +545,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     sopLogs.setSort(30000001);
                     sopLogs.setSendType(6);
                     sopLogs.setExternalUserName(groupUser.getName());
+                    sopLogs.setQwUserKey(qwUser.getId());
                     //域名
                     String companyUserId = qwUser.getCompanyUserId().toString();
                     String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
@@ -608,7 +609,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             //小程序单独
                             case "4":
                                 String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
-                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
+                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, qwGroupChat.getChatId());
 
                                 if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())) {
                                     log.error("配置中无小程序id,采用默认的");
@@ -655,6 +656,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     sopLogs.setSort(2);
                     sopLogs.setSendType(12);
                     sopLogs.setExternalUserName(groupChat.getName());
+                    sopLogs.setQwUserKey(qwUser.getId());
 
                     QwSopCourseFinishTempSetting setting = new QwSopCourseFinishTempSetting();
 
@@ -712,7 +714,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             //小程序单独
                             case "4":
                                 String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
-                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
+                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, groupChat.getChatId());
 
                                 if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())) {
                                     log.error("配置中无小程序id,采用默认的");
@@ -869,7 +871,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );
 
                             String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config);
+                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config, null);
 
                             String miniAppId = null;
 
@@ -1304,7 +1306,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             item.getExternalId(),item.getStartTime(),dataTime );
 
                     String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
-                            qwUser.getId(), companyUserId, companyId, item.getExternalId(), config);
+                            qwUser.getId(), companyUserId, companyId, item.getExternalId(), config, null);
 
 
                     String miniAppId = null;
@@ -1480,10 +1482,10 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
     private String createLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
                                      Integer courseId, Integer videoId, Long qwUserId,
-                                     String companyUserId, String companyId, Long externalId,CourseConfig config) {
+                                     String companyUserId, String companyId, Long externalId,CourseConfig config, String chatId) {
 
         FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
-                                                companyUserId, companyId, externalId,3,null);
+                                                companyUserId, companyId, externalId,3,chatId);
 
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link,courseMap);

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

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

+ 10 - 0
fs-service/src/main/java/com/fs/wxwork/dto/WxWorkMessageDTO.java

@@ -33,4 +33,14 @@ public class WxWorkMessageDTO {
     // 语音
     private String voice_id;
     private Integer voice_size;
+
+    // 视频号
+    String objectId;//视频号ID
+    String nickname;//标题
+    String thumb_url;//视频号封面
+    String cover_url;//视频号切图
+    String avatar;//视频号头像
+    String desc;//视频号描述
+    String extras;//视频号扩展字段
+    String objectNonceId;//视频号扩展字段
 }

+ 94 - 0
fs-service/src/main/resources/application-config-dev-jnlzjk.yml

@@ -0,0 +1,94 @@
+baidu:
+  token: 12313231232
+  back-domain: https://www.xxxx.com
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  miniapp:
+    configs:
+      - appid: wx94951f52d3ac5e25   #北京存在文化
+        secret: bfe27b20c6e3c4232a1d4ef36228e84b #北京存在文化
+        token: Ncbnd7lJvkripxxna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+  cp:
+    corpId: wwa46ffb9ff6ac35b8 #企业ID北京存在文化
+    appConfigs:
+      - agentId: 1000070       #北京存在文化
+        secret: pu2EFz6gY2Fo2K-aRUxLPaAkKIaMJJRp8ES9JdpHkp4 #北京存在文化
+        token: PPKOdAlCoMO
+        aesKey: PKvaxtpSv8NGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
+  pay:
+    appId:  #微信公众号或者小程序等的appid
+    mchId:  #微信支付商户号
+    mchKey:  #微信支付商户密钥
+    subAppId:  #服务商模式下的子商户公众账号ID
+    subMchId:  #服务商模式下的子商户号
+    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl: https://userapp.his.runtzh.com/app/wxpay/wxPayNotify
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId: wxd6905bed94e45ef0 # 第一个公众号的appid  //公众号名称:济南联智健康
+        secret: a7a59d1536e9eae16108a5ad627fa4a3 # 公众号的appsecret--济南联智健康
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+aifabu:  #爱链接
+  appKey: 7b471be905ab17e00f3b858c6710dd117601d008
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+  #  account: tcloud
+  #  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  commonApi: http://127.0.0.1:7771
+  h5CommonApi: http://127.0.0.1:7771
+nuonuo:
+  key: 10924508
+  secret: A2EB20764D304D16
+
+# 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: jnlzjk-1323137866
+  app_id: 1323137866
+  region: ap-chongqing
+  proxy: jnlzjk
+tmp_secret_config:
+  secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
+  secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
+  bucket: fs-1319721001
+  app_id: 1319721001
+  region: ap-chongqing
+  proxy: fs
+cloud_host:
+  company_name: 济南联志健康
+  projectCode: LZJK
+headerImg:
+  imgUrl:
+
+ipad:
+  ipadUrl: http://ipadjnlzjk.ylrztop.com
+  aiApi: http://49.232.181.28:3000/
+  voiceApi:
+  commonApi:
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+
+

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

@@ -54,7 +54,7 @@ wx:
       port: 6379
       timeout: 2000
     configs:
-      - appId: wx961fadab9bcb792b # 第一个公众号的appid  //公众号名称:云联
+      - appId: wx961fadab9bcb792b # 第一个公众号的appid  //公众号名称:壹道正气
         secret: 8adb2a7533921449ef6e60814c2ff075
         token: PPKOdAlCoMO # 接口配置里的Token值
         aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值

+ 2 - 2
fs-service/src/main/resources/application-config-druid-hcl.yml

@@ -42,8 +42,8 @@ wx:
       port: 6379
       timeout: 2000
     configs:
-      - appId: wx2f17bb412271cfe6 # 第一个公众号的appid  //公众号名称:
-        secret: 47b6d65c45719e3e40392e19996587b3 # 公众号的appsecret
+      - appId: wx5d3e8c6791f0676d # 第一个公众号的appid  //公众号名称:善德佑
+        secret: d336ec63efd88b47f89b6a329a41c98d # 公众号的appsecret
         token: PPKOdAlCoMO # 接口配置里的Token值
         aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
 aifabu:  #爱链接

+ 3 - 3
fs-service/src/main/resources/application-config-druid-jnlzjk.yml

@@ -84,9 +84,9 @@ headerImg:
 
 ipad:
   ipadUrl: http://ipadjnlzjk.ylrztop.com
-  aiApi: http://49.232.181.28:3000/
-  voiceApi:
-  commonApi:
+  aiApi: http://49.232.181.28:3000/api
+  voiceApi: http://129.28.187.88:8667
+  commonApi: http://129.28.187.88:7771
 wx_miniapp_temp:
   pay_order_temp_id:
   inquiry_temp_id:

+ 153 - 0
fs-service/src/main/resources/application-dev-jnlzjk.yml

@@ -0,0 +1,153 @@
+# 数据源配置
+spring:
+    profiles:
+        include: config-dev-jnlzjk,common
+    # redis 配置
+    redis:
+        host: localhost
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password:
+        # 连接超时时间
+        timeout: 30s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 100
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+#        clickhouse:
+#            type: com.alibaba.druid.pool.DruidDataSource
+#            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+#            url: jdbc:clickhouse://1.14.104.71:8123/sop_test?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+#            username: rt_2024
+#            password: Yzx_19860213
+#            initialSize: 10
+#            maxActive: 100
+#            minIdle: 10
+#            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                  url: jdbc:mysql://nj-cdb-22nvjajz.sql.tencentcdb.com:29237/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                  username: root
+                  password: Ylrz_1q2w3e4r5t6y
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    enabled: false
+                    url:
+                    username:
+                    password:
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://nj-cdb-22nvjajz.sql.tencentcdb.com:29237/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_1q2w3e4r5t6y
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+rocketmq:
+    name-server: rmq-16xj8o92zp.rocketmq.cd.qcloud.tencenttdmq.com:8080
+    producer:
+        group: my-producer-group
+        access-key: ak16xj8o92zp984557f83ba2 # 替换为实际的 accessKey
+        secret-key: sk2ff1c6b15b74b888 # 替换为实际的 secretKey
+    consumer:
+        group: common-group
+        access-key: ak16xj8o92zp984557f83ba2 # 替换为实际的 accessKey
+        secret-key: sk2ff1c6b15b74b888 # 替换为实际的 secretKey
+openIM:
+    secret: openIM123
+    userID: imAdmin
+#是否为新商户,新商户不走mpOpenId
+isNewWxMerchant: true

+ 1 - 1
fs-service/src/main/resources/application-druid-cqtyt-test.yml

@@ -11,7 +11,7 @@ spring:
         # 数据库索引
         database: 0
         # 密码
-#        password: Ylrz_c123232014^$
+        password:
         # 连接超时时间
         timeout: 20s
         lettuce:

+ 10 - 13
fs-service/src/main/resources/application-druid-cqtyt.yml

@@ -8,12 +8,10 @@ spring:
         host: r-2zexagt5g4z7arviu5.redis.rds.aliyuncs.com
         # 端口,默认为6379
         port: 6379
-        # 数据库索引
-        database: 0
         # 密码
         password: Ylrz_c123232014^$
         # 连接超时时间
-        timeout: 20s
+        timeout: 30s
         lettuce:
             pool:
                 # 连接池中的最小空闲连接
@@ -24,17 +22,8 @@ spring:
                 max-active: 8
                 # #连接池最大阻塞等待时间(使用负值表示没有限制)
                 max-wait: -1ms
+        database: 0
     datasource:
-        #        clickhouse:
-        #            type: com.alibaba.druid.pool.DruidDataSource
-        #            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
-        #            url: jdbc:clickhouse://cc-2vc8zzo26w0l7m2l6.public.clickhouse.ads.aliyuncs.com/sop?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
-        #            username: rt_2024
-        #            password: Yzx_19860213
-        #            initialSize: 10
-        #            maxActive: 100
-        #            minIdle: 10
-        #            maxWait: 6000
         mysql:
             type: com.alibaba.druid.pool.DruidDataSource
             driverClassName: com.mysql.cj.jdbc.Driver
@@ -142,6 +131,14 @@ spring:
                     wall:
                         config:
                             multi-statement-allow: true
+redisson:
+    config: |
+        singleServerConfig:
+          address: "redis://r-2zexagt5g4z7arviu5.redis.rds.aliyuncs.com:6379"
+          password: "Ylrz_c123232014^$"
+          database: 0
+        checkKeysEventsConfig: false
+
 rocketmq:
     name-server: rmq-1243b25nj.rocketmq.gz.public.tencenttdmq.com:8080 # RocketMQ NameServer 地址
     producer:

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

@@ -152,4 +152,4 @@ openIM:
     secret: op
     userID: im
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false

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

@@ -154,4 +154,4 @@ openIM:
     secret: openIM123
     userID: imAdmin
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false

+ 1 - 1
fs-service/src/main/resources/application-druid-jnmy-test.yml

@@ -41,7 +41,7 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                    url: jdbc:mysql://120.46.174.121:2345/fs_his_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    url: jdbc:mysql://120.46.174.121:2345/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                     username: root
                     password: Ylrztek250218!3@.
                 # 从库数据源

+ 3 - 1
fs-service/src/main/resources/application-druid-sxjz.yml

@@ -165,4 +165,6 @@ openIM:
     secret: openIM123
     userID: imAdmin
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false
+
+enableRedPackAccount: 0

+ 38 - 0
fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml

@@ -54,6 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="companyId" column="company_id"/>
         <result property="status" column="status"/>
         <result property="qwStatus" column="qw_status"/>
+        <result property="qwUserId" column="qw_user_id"/>
         <result property="phonenumber" column="phonenumber"/>
         <result property="createTime" column="create_time"/>
         <result property="deptId" column="dept_id"/>
@@ -91,6 +92,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         u.qw_status, u.phonenumber, u.create_time, u.dept_id,
         u.qr_code_weixin, u.user_type, u.qr_code_wecom, u.jpush_id,
         u.avatar,
+        u.qw_user_id,
         d.dept_name,
         d.leader,
         cr.role_name as role_name
@@ -302,6 +304,42 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where user_id = #{userId}
     </update>
 
+    <update id="updateAllCompanyUser" parameterType="CompanyUser">
+        update company_user
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="userName != null and userName != ''">user_name = #{userName},</if>
+            <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
+            <if test="email != null">email = #{email},</if>
+            <if test="phonenumber != null">phonenumber = #{phonenumber},</if>
+            <if test="sex != null">sex = #{sex},</if>
+            <if test="avatar != null">avatar = #{avatar},</if>
+            <if test="idCard != null">id_card = #{idCard},</if>
+            <if test="password != null and password != '' ">password = #{password},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="delFlag != null">del_flag = #{delFlag},</if>
+            <if test="loginIp != null">login_ip = #{loginIp},</if>
+            <if test="loginDate != null">login_date = #{loginDate},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="token != null">token = #{token},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="qrCodeWeixin != null">qr_code_weixin = #{qrCodeWeixin},</if>
+            <if test="qrCodeWecom != null">qr_code_wecom = #{qrCodeWecom},</if>
+            <if test="jpushId != null">jpush_id = #{jpushId},</if>
+            <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
+            <if test="qwStatus != null">qw_status = #{qwStatus},</if>
+            <if test="domain != null">`domain` = #{domain},</if>
+            <if test="isAudit != null">`is_audit` = #{isAudit},</if>
+            <if test="addressId != null">`address_id` = #{addressId},</if>
+            <if test="maOpenId != null">`ma_open_id` = #{maOpenId},</if>
+        </trim>
+        where company_id = #{companyId}
+    </update>
+
     <delete id="deleteCompanyUserById" parameterType="Long">
         delete from company_user where user_id = #{userId}
     </delete>

+ 30 - 0
fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml

@@ -182,4 +182,34 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectFsCourseRedPacketLogHourseByCompany" resultType="com.fs.company.vo.RedPacketMoneyVO">
         SELECT a.company_id, SUM(amount) as money  FROM fs_course_red_packet_log a WHERE a.create_time &gt;= #{startTime} AND a.create_time &lt;= #{endTime} GROUP BY a.company_id
     </select>
+    <!-- 看客红包统计   -->
+    <select id="statistics" resultType="com.fs.course.dto.CourseRedPacketStatisticsDTO">
+       select c.company_name,cu.nick_name,pl.company_user_id,cu.company_id,sum(pl.amount) as redPacketTotalMoney,count(pl.log_id) as redPacketNum from fs_course_red_packet_log pl
+           left join  company_user cu on pl.company_user_id = cu.user_id
+       left join company c on cu.company_id=c.company_id
+       <where>
+           <if test="companyId != null">
+               and cu.company_id = #{companyId}
+           </if>
+           <if test="companyUserId != null">
+               and pl.company_user_id = #{companyUserId}
+           </if>
+            <if test="status != null">
+               and pl.status = #{status}
+           </if>
+           <if test="startTime != null">
+               and date_format(pl.create_time,'%Y-%m-%d') &gt;= date_format(#{startTime},'%Y-%m-%d')
+           </if>
+            <if test="endTime != null">
+               and date_format(pl.create_time,'%Y-%m-%d') &lt;= date_format(#{endTime},'%Y-%m-%d')
+           </if>
+       </where>
+       group by pl.company_user_id order by c.company_name
+    </select>
+    <!-- 获取当前时间前十分钟到前二十分钟红包记录状态为发送中的记录   -->
+    <select id="selectFsCourseRedPacketLogListBySending"
+            resultType="com.fs.course.domain.FsCourseRedPacketLog">
+        <include refid="selectFsCourseRedPacketLogVo"/> where status != 1 and create_time &gt;= #{maps.startTime} and create_time &lt;= #{maps.endTime}
+
+    </select>
 </mapper>

+ 4 - 3
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -459,10 +459,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 and o.company_id=#{companyId}
             </if>
             <if test= 'sTime != null '>
-                and o.create_time &gt;= #{sTime}
+                and DATE(o.create_time) &gt;= #{sTime}
             </if>
             <if test='eTime != null '>
-                and o.create_time &lt;= #{eTime}
+                and DATE(o.create_time) &lt;= #{eTime}
             </if>
             <if test ='courseId !=null'>
                 and o.course_id = #{courseId}
@@ -484,7 +484,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY o.video_id,o.user_id,DATE(o.create_time),o.project,o.course_id
         ORDER BY o.video_id ,DATE(o.create_time)
 
-        limit ${(pageNum-1)*pageSize},${pageSize}
+<!--        limit ${(pageNum-1)*pageSize},${pageSize}-->
     </select>
     <select id="selectFsCourseWatchLogStatisticsListVONewCount" resultType="java.lang.Long">
         SELECT COUNT(*)
@@ -756,6 +756,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         l.video_id,
         l.qw_user_id,
         l.qw_external_contact_id,
+        l.sop_id,
         qec.create_time as qec_create_time
         FROM
         fs_course_watch_log l LEFT JOIN qw_external_contact qec on l.qw_external_contact_id = qec.id

+ 34 - 0
fs-service/src/main/resources/mapper/his/FsStoreOrderMapper.xml

@@ -2100,5 +2100,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             AND pay_time &lt; DATE_ADD(STR_TO_DATE(#{map.payTime}, '%Y-%m-%d'), INTERVAL 1 DAY)
         </if>
     </select>
+    <select id="selectFsStoreOrderAmountStats" resultType="com.fs.his.vo.FsStoreOrderAmountStatsVo">
+        SELECT
+        COUNT(*) AS totalOrderCount,
+        COUNT(CASE WHEN pay_type = '1' THEN 1 END) AS fullPayOrderCount,
+        COUNT(CASE WHEN pay_type IN ('2', '3') THEN 1 END) AS codOrderCount,
+        COUNT(CASE WHEN pay_type IN ('2', '3') AND COALESCE(pay_money, 0) > 0 THEN 1 END) AS depositCodOrderCount,
+        COUNT(CASE WHEN pay_type IN ('2', '3') AND COALESCE(pay_money, 0) =0 THEN 1 END) AS noDepositCodOrderCount,
+        SUM(pay_price) AS totalOrderAmount,
+        SUM(
+        CASE
+        WHEN pay_type IN ('2', '3')
+        THEN COALESCE(pay_money, 0)
+        ELSE 0
+        END
+        ) AS depositAmount,
+
+        SUM(COALESCE(pay_remain, 0)) AS codAmount
+
+        FROM fs_store_order
+        WHERE is_del = 0 AND status > 1
+        <if test="startTime != null">
+            AND create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null">
+            AND create_time &lt;= #{endTime}
+        </if>
+
+        <if test="companyId != null">
+            AND company_id = #{companyId}
+        </if>
+        <if test="companyUserId != null">
+            AND company_user_id = #{companyUserId}
+        </if>
+    </select>
 
 </mapper>

+ 28 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml

@@ -971,4 +971,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{item}
     </foreach>
     </select>
+    <select id="selectFsStoreOrderAmountScrmStats" resultType="com.fs.his.vo.FsStoreOrderAmountScrmStatsVo">
+        SELECT
+        COUNT(*) AS totalOrderCount,
+        COUNT(CASE WHEN pay_type = '1' THEN 1 END) AS fullPayOrderCount,
+        COUNT(CASE WHEN pay_type IN ('2', '3') THEN 1 END) AS codOrderCount,
+        COUNT(CASE WHEN pay_type IN ('2', '3') AND COALESCE(pay_money, 0) > 0 THEN 1 END) AS depositCodOrderCount,
+        COUNT(CASE WHEN pay_type IN ('2', '3') AND COALESCE(pay_money, 0) = 0 THEN 1 END) AS noDepositCodOrderCount,
+        SUM(pay_price) AS totalOrderAmount,
+        SUM(CASE WHEN pay_type IN ('2', '3') THEN COALESCE(pay_money, 0) ELSE 0 END) AS depositAmount,
+
+        SUM(CASE WHEN pay_type IN ('2', '3') THEN COALESCE(pay_price, 0) ELSE 0 END)
+        -
+        SUM(CASE WHEN pay_type IN ('2', '3') THEN COALESCE(pay_money, 0) ELSE 0 END) AS codAmount
+        FROM fs_store_order_scrm
+        WHERE is_del = 0 AND status > 0
+        <if test="startTime != null">
+            AND create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null">
+            AND create_time &lt;= #{endTime}
+        </if>
+        <if test="companyId != null">
+            AND company_id = #{companyId}
+        </if>
+        <if test="companyUserId != null">
+            AND company_user_id = #{companyUserId}
+        </if>
+    </select>
 </mapper>

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

@@ -69,10 +69,11 @@
         <result property="qwExtId"    column="qw_ext_id"    />
         <result property="rank"    column="rank"    />
         <result property="react"    column="react"    />
+        <result property="orderCount"    column="order_count"    />
     </resultMap>
 
     <sql id="selectFsUserVo">
-        select user_id, username, nick_name, avatar, phone, integral, status, `level`, spread_user_id, spread_time, user_type, is_promoter, pay_count, spread_count, addres, tui_user_id, tui_time, tui_user_count, ma_open_id, mp_open_id, union_id, is_del, user_code, remark, nickname, create_time, update_time, last_ip, now_money, brokerage_price, balance, sign_num, integral_status, is_buy, password, real_name, birthday, id_card, jpush_id, is_vip, vip_start_date, vip_end_date, vip_level, vip_status, sex, store_open_id, is_official_account_auth, is_push, is_individuation_push, is_weixin_auth, company_id, company_user_id, register_date, register_code, test, login_device, source, is_add_qw, qw_user_id, is_show, parent_id, course_ma_open_id, history_app, qw_ext_id, `rank`, react from fs_user
+        select user_id, username, nick_name, avatar, phone, integral, status, `level`, spread_user_id, spread_time, user_type, is_promoter, pay_count, spread_count, addres, tui_user_id, tui_time, tui_user_count, ma_open_id, mp_open_id, union_id, is_del, user_code, remark, nickname, create_time, update_time, last_ip, now_money, brokerage_price, balance, sign_num, integral_status, is_buy, password, real_name, birthday, id_card, jpush_id, is_vip, vip_start_date, vip_end_date, vip_level, vip_status, sex, store_open_id, is_official_account_auth, is_push, is_individuation_push, is_weixin_auth, company_id, company_user_id, register_date, register_code, test, login_device, source, is_add_qw, qw_user_id, is_show, parent_id, course_ma_open_id, history_app, qw_ext_id, `rank`, react,order_count from fs_user
     </sql>
 
     <select id="selectFsUserList" parameterType="FsUserScrm" resultMap="FsUserResult">
@@ -444,6 +445,7 @@
             <if test="qwExtId != null">qw_ext_id,</if>
             <if test="rank != null">rank,</if>
             <if test="react != null">react,</if>
+            <if test="orderCount != null">order_count,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="username != null">#{username},</if>
@@ -509,55 +511,55 @@
             <if test="qwExtId != null">#{qwExtId},</if>
             <if test="rank != null">#{rank},</if>
             <if test="react != null">#{react},</if>
+            <if test="orderCount != null">#{orderCount},</if>
         </trim>
     </insert>
 
     <update id="updateFsUser" parameterType="FsUserScrm">
         update fs_user
         <trim prefix="SET" suffixOverrides=",">
-            <if test="username != null">username = #{username},</if>
-            <if test="password != null">password = #{password},</if>
-            <if test="realName != null">real_name = #{realName},</if>
-            <if test="birthday != null">birthday = #{birthday},</if>
-            <if test="idCard != null">id_card = #{idCard},</if>
-            <if test="remark != null">remark = #{remark},</if>
+            <if test="nickName != null">nick_name = #{nickName},</if>
             <if test="nickname != null">nickname = #{nickname},</if>
             <if test="avatar != null">avatar = #{avatar},</if>
             <if test="phone != null">phone = #{phone},</if>
-            <if test="createTime != null">create_time = #{createTime},</if>
-            <if test="updateTime != null">update_time = #{updateTime},</if>
-            <if test="lastIp != null">last_ip = #{lastIp},</if>
-            <if test="nowMoney != null">now_money = #{nowMoney},</if>
-            <if test="brokeragePrice != null">brokerage_price = #{brokeragePrice},</if>
             <if test="integral != null">integral = #{integral},</if>
             <if test="signNum != null">sign_num = #{signNum},</if>
             <if test="status != null">status = #{status},</if>
-            <if test="level != null">level = #{level},</if>
-            <if test="spreadUserId != null">spread_user_id = #{spreadUserId},</if>
-            <if test="spreadTime != null">spread_time = #{spreadTime},</if>
-            <if test="userType != null and userType != ''">user_type = #{userType},</if>
-            <if test="isPromoter != null">is_promoter = #{isPromoter},</if>
-            <if test="payCount != null">pay_count = #{payCount},</if>
-            <if test="spreadCount != null">spread_count = #{spreadCount},</if>
-            <if test="addres != null and addres != ''">addres = #{addres},</if>
+            <if test="tuiUserId != null">tui_user_id = #{tuiUserId},</if>
+            <if test="tuiTime != null">tui_time = #{tuiTime},</if>
+            <if test="tuiUserCount != null">tui_user_count = #{tuiUserCount},</if>
             <if test="maOpenId != null">ma_open_id = #{maOpenId},</if>
             <if test="mpOpenId != null">mp_open_id = #{mpOpenId},</if>
             <if test="unionId != null">union_id = #{unionId},</if>
             <if test="isDel != null">is_del = #{isDel},</if>
+            <if test="userCode != null">user_code = #{userCode},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="lastIp != null">last_ip = #{lastIp},</if>
+            <if test="balance != null">balance = #{balance},</if>
+            <if test="integralStatus != null">integral_status = #{integralStatus},</if>
+            <if test="isBuy != null">is_buy = #{isBuy},</if>
+            <if test="password != null">password = #{password},</if>
+            <if test="jpushId != null">jpush_id = #{jpushId},</if>
+            <if test="isVip != null">is_vip = #{isVip},</if>
+            <if test="vipStartDate != null">vip_start_date = #{vipStartDate},</if>
+            <if test="vipEndDate != null">vip_end_date = #{vipEndDate},</if>
+            <if test="vipLevel != null">vip_level = #{vipLevel},</if>
+            <if test="vipStatus != null">vip_status = #{vipStatus},</if>
+            <if test="sex != null">sex = #{sex},</if>
+            <if test="storeOpenId != null">store_open_id = #{storeOpenId},</if>
+            <if test="isPush != null">is_push = #{isPush},</if>
+            <if test="isIndividuationPush != null">is_individuation_push = #{isIndividuationPush},</if>
             <if test="isWeixinAuth != null">is_weixin_auth = #{isWeixinAuth},</if>
-            <if test="companyId != null">company_id = #{companyId},</if>
-            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
-            <if test="registerDate != null">register_date = #{registerDate},</if>
-            <if test="registerCode != null">register_code = #{registerCode},</if>
+            <if test="loginDevice != null">login_device = #{loginDevice},</if>
             <if test="source != null">source = #{source},</if>
-            <if test="userCode != null">user_code = #{userCode},</if>
-            <if test="isShow != null">is_show = #{isShow},</if>
-            <if test="qwExtId != null">qw_ext_id = #{qwExtId},</if>
             <if test="isAddQw != null">is_add_qw = #{isAddQw},</if>
-            <!--<if test="qwRepeat != null">qw_repeat = #{qwRepeat},</if>
-            <if test="userRepeat != null">user_repeat = #{userRepeat},</if>
-            <if test="payOrder != null">pay_order = #{payOrder},</if>
-            <if test="isBecomeMember != null">is_become_member = #{isBecomeMember},</if>-->
+            <if test="courseMaOpenId != null">course_ma_open_id = #{courseMaOpenId},</if>
+            <if test="parentId != null">parent_id = #{parentId},</if>
+            <if test="qwExtId != null">qw_ext_id = #{qwExtId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
         </trim>
         where user_id = #{userId}
     </update>

+ 6 - 1
fs-service/src/main/resources/mapper/qw/QwFriendWelcomeMapper.xml

@@ -16,10 +16,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="createTime"    column="create_time"    />
         <result property="updateTime"    column="update_time"    />
         <result property="corpId"    column="corp_id"    />
+        <result property="welcomeTitle"    column="welcome_title"    />
     </resultMap>
 
     <sql id="selectQwFriendWelcomeVo">
-        select id, qw_user_ids,corp_id, is_send_msg, welcome_text, attachments, is_dayparting, dayparting_ItemList, company_id, create_time, update_time from qw_friend_welcome
+        select id, qw_user_ids,corp_id,welcome_title, is_send_msg, welcome_text, attachments, is_dayparting, dayparting_ItemList, company_id, create_time, update_time from qw_friend_welcome
     </sql>
 
     <select id="selectQwFriendWelcomeListVO" parameterType="QwFriendWelcome" resultMap="QwFriendWelcomeResult">
@@ -33,6 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createTime != null "> and create_time = #{createTime}</if>
             <if test="corpId != null "> and corp_id = #{corpId}</if>
             <if test="updateTime != null "> and update_time = #{updateTime}</if>
+            <if test="welcomeTitle != null "> and welcome_title = #{welcomeTitle}</if>
         </where>
     </select>
 
@@ -77,6 +79,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <insert id="insertQwFriendWelcomeVO" parameterType="QwFriendWelcome" useGeneratedKeys="true" keyProperty="id">
         insert into qw_friend_welcome
         <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="welcomeTitle != null">welcome_title,</if>
             <if test="qwUserIds != null">qw_user_ids,</if>
             <if test="isSendMsg != null">is_send_msg,</if>
             <if test="welcomeText != null">welcome_text,</if>
@@ -91,6 +94,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="corpId != null">corp_id,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="welcomeTitle != null">#{welcomeTitle},</if>
             <if test="qwUserIds != null">#{qwUserIds},</if>
             <if test="isSendMsg != null">#{isSendMsg},</if>
             <if test="welcomeText != null">#{welcomeText},</if>
@@ -109,6 +113,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <update id="updateQwFriendWelcome" parameterType="QwFriendWelcome">
         update qw_friend_welcome
         <trim prefix="SET" suffixOverrides=",">
+            <if test="welcomeTitle != null">welcome_title = #{welcomeTitle},</if>
             <if test="qwUserIds != null">qw_user_ids = #{qwUserIds},</if>
             <if test="isSendMsg != null">is_send_msg = #{isSendMsg},</if>
             <if test="welcomeText != null">welcome_text = #{welcomeText},</if>

+ 1 - 1
fs-user-app/src/main/resources/application.yml

@@ -13,4 +13,4 @@ spring:
 #    active: druid-sxjz
 #    active: druid-qdtst
 #    active: druid-yzt
-    active: druid-knt-test
+    active: dev-jnlzjk