Browse Source

Merge remote-tracking branch 'origin/master'

xgb 1 week ago
parent
commit
3deeb1fbaa
60 changed files with 1268 additions and 93 deletions
  1. 11 6
      README.md
  2. 41 0
      fs-admin/src/main/java/com/fs/course/controller/CourseRedPacketStatisticsController.java
  3. 37 0
      fs-admin/src/main/java/com/fs/course/task/RedPacketLogsTask.java
  4. 52 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  5. 43 9
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  6. 27 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  7. 7 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  8. 29 0
      fs-company/src/main/java/com/fs/company/utils/QwStatusEnum.java
  9. 27 0
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  10. 9 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  11. 6 0
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  12. 38 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  13. 21 0
      fs-service/src/main/java/com/fs/company/vo/BatchUserRolesVO.java
  14. 4 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java
  15. 36 0
      fs-service/src/main/java/com/fs/course/dto/CourseRedPacketStatisticsDTO.java
  16. 7 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  17. 38 0
      fs-service/src/main/java/com/fs/course/param/CourseRedPacketStatisticsParam.java
  18. 11 0
      fs-service/src/main/java/com/fs/course/service/CourseRedPacketStatisticsService.java
  19. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseRedPacketLogService.java
  20. 28 0
      fs-service/src/main/java/com/fs/course/service/impl/CourseRedPacketStatisticsServiceImpl.java
  21. 71 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  22. 9 3
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  23. 2 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  24. 25 0
      fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountScrmStatsQueryDto.java
  25. 25 0
      fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountStatsQueryDto.java
  26. 3 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
  27. 6 4
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
  28. 1 0
      fs-service/src/main/java/com/fs/his/service/IFsStorePaymentService.java
  29. 198 2
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  30. 1 2
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  31. 44 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountScrmStatsVo.java
  32. 44 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountStatsVo.java
  33. 4 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  34. 7 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java
  35. 87 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  36. 6 0
      fs-service/src/main/java/com/fs/qw/domain/QwFriendWelcome.java
  37. 1 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  38. 2 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserVideoMapper.java
  39. 7 0
      fs-service/src/main/java/com/fs/qw/param/QwFriendWelcomeParam.java
  40. 7 0
      fs-service/src/main/java/com/fs/qw/param/QwUserListParam.java
  41. 3 0
      fs-service/src/main/java/com/fs/qw/service/IQwUserVideoService.java
  42. 30 11
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  43. 4 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserVideoServiceImpl.java
  44. 2 0
      fs-service/src/main/java/com/fs/qw/vo/QwExternalContactVO.java
  45. 6 1
      fs-service/src/main/java/com/fs/qw/vo/QwFriendWelcomeVO.java
  46. 3 2
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempVoiceServiceImpl.java
  47. 10 0
      fs-service/src/main/java/com/fs/wxwork/dto/WxWorkMessageDTO.java
  48. 1 1
      fs-service/src/main/resources/application-config-druid-fby.yml
  49. 2 2
      fs-service/src/main/resources/application-config-druid-hcl.yml
  50. 1 1
      fs-service/src/main/resources/application-druid-cqtyt-test.yml
  51. 10 13
      fs-service/src/main/resources/application-druid-cqtyt.yml
  52. 1 1
      fs-service/src/main/resources/application-druid-hcl.yml
  53. 1 1
      fs-service/src/main/resources/application-druid-hdt.yml
  54. 1 1
      fs-service/src/main/resources/application-druid-jnmy-test.yml
  55. 38 0
      fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
  56. 30 0
      fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml
  57. 34 0
      fs-service/src/main/resources/mapper/his/FsStoreOrderMapper.xml
  58. 28 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  59. 33 31
      fs-service/src/main/resources/mapper/hisStore/FsUserScrmMapper.xml
  60. 6 1
      fs-service/src/main/resources/mapper/qw/QwFriendWelcomeMapper.xml

+ 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文件)。
 
 #### 参与贡献
 

+ 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));
+    }
+
+}

+ 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;
+    }
+}

+ 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();
+    }
+
 }

+ 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);
 }

+ 38 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -22,7 +22,9 @@ 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.ICompanyRoleService;
 import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserRoleService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.*;
 import com.fs.course.service.IFsUserCompanyUserService;
@@ -45,6 +47,8 @@ import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
+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 +76,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 {
     @Autowired
     private CompanyUserMapper companyUserMapper;
+
     @Autowired
     private CompanyRoleMapper roleMapper;
 
@@ -108,10 +113,16 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Autowired
     private ICompanyService companyService;
 
-
     @Autowired
     private IQwUserService qwUserService;
 
+    @Autowired
+    private ISysRoleService sysRoleService;
+
+//    @Autowired
+//    private ICompanyUserRoleService userRoleService;
+
+
     /**
      * 查询物业公司管理员信息
      *
@@ -1006,4 +1017,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);
 }

+ 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());

+ 9 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1142,7 +1142,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 +1344,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();
         }
 
@@ -1414,6 +1414,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 +1586,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());

+ 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
      * **/

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

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

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

@@ -0,0 +1,25 @@
+package com.fs.his.dto;
+
+import lombok.Data;
+/**
+ * 互联网医院订单金额统计queryDto对象
+ * */
+@Data
+public class FsStoreOrderAmountStatsQueryDto {
+    /**
+     * 销售公司id
+     * */
+    private String companyId;
+    /**
+     * 销售人员id
+     * */
+    private String 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);
 }

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

@@ -124,4 +124,5 @@ public interface IFsStorePaymentService
     R paymentByWxaCode(FsStorePaymentPayParam payment);
 
     R getWxaCodeByPayment(FsStorePaymentGetWxaCodeParam param);
+
 }

+ 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);
+    }
+
 }

+ 1 - 2
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -38,6 +38,7 @@ import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.config.RedPacketConfig;
+import com.fs.course.domain.FsCourseRedPacketLog;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.IFsUserVipOrderService;
@@ -1471,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);
 }

+ 30 - 11
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;
@@ -2175,7 +2176,9 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
     @Override
     public QwUser getQwUserByRedisForId(String qwUserId) {
-
+        if(qwUserId==null|| !qwUserId.isEmpty()){
+            return  null;
+        }
         String redisKey = "qwUserRdById:" + qwUserId;
 
         // 直接从Redis获取JSON字符串
@@ -2249,6 +2252,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) {
@@ -2604,8 +2622,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 +2695,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());
-                            }
+//                            }
 
                         }
                     }

+ 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);

+ 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;//视频号扩展字段
 }

+ 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:  #爱链接

+ 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@.
                 # 从库数据源

+ 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>

+ 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>