Browse Source

Merge remote-tracking branch 'origin/master'

吴树波 6 days ago
parent
commit
48599c5343
37 changed files with 776 additions and 43 deletions
  1. 3 6
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  2. 37 0
      fs-admin/src/main/java/com/fs/course/task/RedPacketLogsTask.java
  3. 27 9
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  4. 27 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  5. 29 0
      fs-company/src/main/java/com/fs/company/utils/QwStatusEnum.java
  6. 9 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  7. 23 5
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  8. 4 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java
  9. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  10. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  11. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseRedPacketLogService.java
  12. 71 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  13. 0 2
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseTrafficLogServiceImpl.java
  14. 9 4
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  15. 2 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  16. 25 0
      fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountScrmStatsQueryDto.java
  17. 25 0
      fs-service/src/main/java/com/fs/his/dto/FsStoreOrderAmountStatsQueryDto.java
  18. 3 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
  19. 6 4
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
  20. 198 2
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  21. 44 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountScrmStatsVo.java
  22. 44 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderAmountStatsVo.java
  23. 4 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  24. 7 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java
  25. 87 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  26. 3 1
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  27. 2 0
      fs-service/src/main/java/com/fs/qw/vo/QwExternalContactVO.java
  28. 1 1
      fs-service/src/main/resources/application-config-druid-fby.yml
  29. 2 2
      fs-service/src/main/resources/application-config-druid-hcl.yml
  30. 1 1
      fs-service/src/main/resources/application-druid-hcl.yml
  31. 1 1
      fs-service/src/main/resources/application-druid-hdt.yml
  32. 2 0
      fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
  33. 5 0
      fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml
  34. 3 3
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  35. 34 0
      fs-service/src/main/resources/mapper/his/FsStoreOrderMapper.xml
  36. 28 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  37. 4 1
      fs-service/src/main/resources/mapper/hisStore/FsUserScrmMapper.xml

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

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

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

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

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

@@ -22,6 +22,7 @@ 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;
@@ -36,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;
@@ -60,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;
@@ -79,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=";
 
     /**
@@ -125,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")

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

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

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

+ 23 - 5
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -3,6 +3,7 @@ package com.fs.company.service.impl;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.QRutils;
 import com.fs.common.annotation.DataScope;
@@ -22,10 +23,7 @@ import com.fs.company.mapper.*;
 import com.fs.company.param.CompanyUserAreaParam;
 import com.fs.company.param.CompanyUserCodeParam;
 import com.fs.company.param.CompanyUserQwParam;
-import com.fs.company.service.ICompanyRoleService;
-import com.fs.company.service.ICompanyService;
-import com.fs.company.service.ICompanyUserRoleService;
-import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.*;
 import com.fs.company.vo.*;
 import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.mapper.FsUserMapper;
@@ -45,8 +43,11 @@ import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
+import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysRoleService;
 import com.fs.system.service.ISysUserService;
 import com.fs.voice.utils.StringUtil;
@@ -104,6 +105,7 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 
     @Autowired
     private FsUserMapper fsUserMapper;
+
     @Autowired
     private IFsUserCompanyUserService userCompanyUserService;
 
@@ -119,6 +121,9 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Autowired
     private ISysRoleService sysRoleService;
 
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+
 //    @Autowired
 //    private ICompanyUserRoleService userRoleService;
 
@@ -660,7 +665,20 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Override
     @DataScope(deptAlias = "u", userAlias = "u")
     public List<CompanyUserQwListVO> selectCompanyUserQwListVO(CompanyUserQwParam user) {
-        return companyUserMapper.selectCompanyUserQwListVO(user);
+        CompanyConfig companyConfig = companyConfigService.selectCompanyConfigByKey(user.getCompanyId(), "company:admin:show");
+        boolean  isAdminShow = false;
+        if(!StringUtils.isEmpty(companyConfig.getConfigValue())){
+            isAdminShow = Boolean.parseBoolean(companyConfig.getConfigValue());
+        }
+        List<CompanyUserQwListVO> companyUserQwListVOS = companyUserMapper.selectCompanyUserQwListVO(user);
+        if(!isAdminShow){
+            Company company = companyService.selectCompanyById(user.getCompanyId());
+            Long userId = company.getUserId();
+            companyUserQwListVOS = companyUserQwListVOS.stream()
+                    .filter(vo -> !vo.getUserId().equals(userId))
+                    .collect(Collectors.toList());
+        }
+        return companyUserQwListVOS;
     }
 
     @Override

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

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

@@ -3,6 +3,7 @@ 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;
@@ -175,4 +176,6 @@ public interface FsCourseRedPacketLogMapper
     List<RedPacketMoneyVO> selectFsCourseRedPacketLogHourseByCompany(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
 
     List<CourseRedPacketStatisticsDTO> statistics(CourseRedPacketStatisticsParam param);
+
+    List<FsCourseRedPacketLog> selectFsCourseRedPacketLogListBySending(@Param("maps") Map<String, Object> map);
 }

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

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

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

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

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

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

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

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

@@ -1228,7 +1228,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return sendIntegralReward(param,user, log, config);
             // 红包+积分
             case 3:
-                R sendRed = sendRedPacketReward(param, user, log, video, config);
+                R sendRed = sendRedPacketRewardFsUser(param, user, log, video, config);
                 if (!Objects.equals(sendRed.get("code"), 200)) {
                     return sendRed;
                 }
@@ -1430,9 +1430,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         BigDecimal amount = BigDecimal.ZERO;
         FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId(), param.getPeriodId());
 
-        if (redPackage != null) {
+        if (redPackage != null && redPackage.getRedPacketMoney() != null) {
             amount = redPackage.getRedPacketMoney();
-        } else if (video != null) {
+        } else if (video != null && video.getRedPacketMoney() != null) {
             amount = video.getRedPacketMoney();
         }
 
@@ -1487,7 +1487,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
             Company company = companyMapper.selectCompanyById(param.getCompanyId());
             BigDecimal money = company.getMoney();
-            if (money.compareTo(BigDecimal.ZERO)<0) {
+            if (money.compareTo(BigDecimal.ZERO)<=0) {
                 return R.error("服务商余额不足,请联系群主服务器充值!");
             }
 
@@ -1672,6 +1672,11 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         courseWatchLogMapper.updateFsCourseWatchLog(log);
         logger.info("发放奖励====================》看课记录,{}",log);
 
+        // 红德堂不要积分转红包
+        if (CloudHostUtils.hasCloudHostName("弘德堂")) {
+            return R.ok("奖励发放成功").put("rewardType",config.getRewardType());
+        }
+
         //转换红包
         FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
         redPacketLog.setCourseId(param.getCourseId());

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

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

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

+ 3 - 1
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -1058,6 +1058,8 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                     } else {
                         qwExternalContactMapper.insertQwExternalContact(qwExternalContact);
                     }
+
+                    logger.info("成功同步一个用户");
                 }
 
             }else {
@@ -4891,7 +4893,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         for (QwOptionsVO qwOptionsVO : qwOptionsVOS) {
             String corpId = qwOptionsVO.getCorpId();
 //            System.out.println("同步的"+corpId);
-//            logger.info("同步的"+corpId);
+            logger.info("同步的"+corpId);
             executor.execute(() ->  qwExternalContactSyncByCorpId(corpId));
         }
         executor.shutdown();

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

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

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

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

@@ -206,5 +206,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        </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>

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

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

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

+ 4 - 1
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,6 +511,7 @@
             <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>