Преглед на файлове

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	fs-service-system/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
#	fs-service-system/src/main/java/com/fs/company/service/ICompanyUserService.java
#	fs-service-system/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
caoliqin преди 2 месеца
родител
ревизия
70573ea33e
променени са 47 файла, в които са добавени 2832 реда и са изтрити 523 реда
  1. 106 0
      fs-admin/src/main/java/com/fs/qw/controller/FsAppContactWayController.java
  2. 99 0
      fs-admin/src/main/java/com/fs/qw/controller/QwAppContactWayLogsController.java
  3. 106 0
      fs-admin/src/main/java/com/fs/qw/controller/QwCompanyController.java
  4. 126 0
      fs-admin/src/main/java/com/fs/qw/controller/QwInformationController.java
  5. 102 0
      fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java
  6. 102 0
      fs-admin/src/main/java/com/fs/qw/controller/QwTagController.java
  7. 27 0
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  8. 107 0
      fs-admin/src/main/java/com/fs/qw/controller/QwWorkLinkController.java
  9. 97 0
      fs-admin/src/main/java/com/fs/qw/controller/QwWorkLinkUserController.java
  10. 110 0
      fs-admin/src/main/java/com/fs/qw/controller/QwWorkUserController.java
  11. 54 0
      fs-admin/src/main/java/com/fs/qw/controller/SopUserLogsController.java
  12. 72 0
      fs-admin/src/main/java/com/fs/qw/controller/SopUserLogsInfoController.java
  13. 126 0
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  14. 3 3
      fs-admin/src/main/resources/application-dev.yml
  15. 3 3
      fs-company/src/main/resources/application-dev.yml
  16. 9 24
      fs-qw-api/src/main/resources/application-dev.yml
  17. 0 57
      fs-qw-api/src/main/resources/application-druid-bly.yml
  18. 0 91
      fs-qw-api/src/main/resources/application-druid.yml
  19. 64 17
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  20. 4 6
      fs-service-system/pom.xml
  21. 8 0
      fs-service-system/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  22. 8 0
      fs-service-system/src/main/java/com/fs/company/service/ICompanyUserService.java
  23. 10 0
      fs-service-system/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  24. 1 0
      fs-service-system/src/main/java/com/fs/course/config/CourseConfig.java
  25. 3 1
      fs-service-system/src/main/java/com/fs/course/config/RedPacketConfig.java
  26. 5 0
      fs-service-system/src/main/java/com/fs/course/domain/FsCourseRealLink.java
  27. 109 84
      fs-service-system/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  28. 63 0
      fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtBarcodeDto.java
  29. 43 0
      fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtBaseResponseDTO.java
  30. 227 0
      fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsDto.java
  31. 408 0
      fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtSpecDto.java
  32. 19 0
      fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockDTO.java
  33. 37 0
      fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockRespDTO.java
  34. 120 0
      fs-service-system/src/main/java/com/fs/erp/service/impl/WdtErpGoodsServiceImpl.java
  35. 2 0
      fs-service-system/src/main/java/com/fs/his/param/WxSendRedPacketParam.java
  36. 5 0
      fs-service-system/src/main/java/com/fs/qw/param/QwAutoTagsRulesTags.java
  37. 229 226
      fs-service-system/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  38. 19 0
      fs-service-system/src/main/java/com/fs/sop/domain/QwSop.java
  39. 3 0
      fs-service-system/src/main/java/com/fs/sop/mapper/QwSopMapper.java
  40. 7 3
      fs-service-system/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java
  41. 10 0
      fs-service-system/src/main/java/com/fs/sop/vo/SopUserLogsVo.java
  42. 10 0
      fs-service-system/src/main/java/com/fs/store/domain/FsUser.java
  43. 8 0
      fs-service-system/src/main/java/com/fs/store/service/IFsStorePaymentService.java
  44. 7 4
      fs-service-system/src/main/java/com/fs/store/service/impl/FsStoreCartServiceImpl.java
  45. 143 3
      fs-service-system/src/main/java/com/fs/store/service/impl/FsStorePaymentServiceImpl.java
  46. 10 0
      fs-service-system/src/main/resources/mapper/company/CompanyUserMapper.xml
  47. 1 1
      fs-service-system/src/main/resources/mapper/sop/SopUserLogsMapper.xml

+ 106 - 0
fs-admin/src/main/java/com/fs/qw/controller/FsAppContactWayController.java

@@ -0,0 +1,106 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.FsAppContactWay;
+import com.fs.qw.service.IFsAppContactWayService;
+import com.fs.qw.vo.FsAppContactWayListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * app客服活码上架Controller
+ *
+ * @author fs
+ * @date 2024-12-02
+ */
+@RestController
+@RequestMapping("/qw/appContactWay")
+public class FsAppContactWayController extends BaseController
+{
+    @Autowired
+    private IFsAppContactWayService fsAppContactWayService;
+
+    /**
+     * 查询app客服活码上架列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:appContactWay:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsAppContactWay fsAppContactWay)
+    {
+        startPage();
+        List<FsAppContactWayListVO> list = fsAppContactWayService.selectFsAppContactWayListVO(fsAppContactWay);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出app客服活码上架列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:appContactWay:export')")
+    @Log(title = "app客服活码上架", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsAppContactWay fsAppContactWay)
+    {
+        List<FsAppContactWay> list = fsAppContactWayService.selectFsAppContactWayList(fsAppContactWay);
+        ExcelUtil<FsAppContactWay> util = new ExcelUtil<FsAppContactWay>(FsAppContactWay.class);
+        return util.exportExcel(list, "app客服活码上架数据");
+    }
+
+    /**
+     * 获取app客服活码上架详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:appContactWay:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsAppContactWayService.selectFsAppContactWayById(id));
+    }
+
+    /**
+     * 新增app客服活码上架
+     */
+    @PreAuthorize("@ss.hasPermi('qw:appContactWay:add')")
+    @Log(title = "app客服活码上架", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsAppContactWay fsAppContactWay)
+    {
+        return toAjax(fsAppContactWayService.insertFsAppContactWay(fsAppContactWay));
+    }
+
+    /**
+     * 修改app客服活码上架
+     */
+    @PreAuthorize("@ss.hasPermi('qw:appContactWay:edit')")
+    @Log(title = "app客服活码上架", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsAppContactWay fsAppContactWay)
+    {
+        return toAjax(fsAppContactWayService.updateFsAppContactWay(fsAppContactWay));
+    }
+
+    /**
+     * 删除app客服活码上架
+     */
+    @PreAuthorize("@ss.hasPermi('qw:appContactWay:remove')")
+    @Log(title = "app客服活码上架", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsAppContactWayService.deleteFsAppContactWayByIds(ids));
+    }
+
+
+    @Log(title = "活码上架", businessType = BusinessType.UPDATE)
+    @PostMapping("/updateIsShow")
+    public AjaxResult updateIsShow(@RequestBody FsAppContactWay fsAppContactWay)
+    {
+        return toAjax(fsAppContactWayService.updateFsAppContactWay(fsAppContactWay));
+    }
+}

+ 99 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwAppContactWayLogsController.java

@@ -0,0 +1,99 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwAppContactWayLogs;
+import com.fs.qw.param.QwAppContactWayLogsParam;
+import com.fs.qw.service.IQwAppContactWayLogsService;
+import com.fs.qw.vo.QwAppContactWayLogsListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 联系我日志Controller
+ *
+ * @author fs
+ * @date 2024-12-19
+ */
+@RestController
+@RequestMapping("/qw/qwAppContactWayLogs")
+public class QwAppContactWayLogsController extends BaseController
+{
+    @Autowired
+    private IQwAppContactWayLogsService qwAppContactWayLogsService;
+
+    /**
+     * 查询联系我日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwAppContactWayLogs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwAppContactWayLogsParam qwAppContactWayLogs)
+    {
+        startPage();
+        List<QwAppContactWayLogsListVO> list = qwAppContactWayLogsService.selectQwAppContactWayLogsListVO(qwAppContactWayLogs);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出联系我日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwAppContactWayLogs:export')")
+    @Log(title = "联系我日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwAppContactWayLogsParam qwAppContactWayLogs)
+    {
+        List<QwAppContactWayLogsListVO> list = qwAppContactWayLogsService.selectQwAppContactWayLogsListVO(qwAppContactWayLogs);
+        ExcelUtil<QwAppContactWayLogsListVO> util = new ExcelUtil<QwAppContactWayLogsListVO>(QwAppContactWayLogsListVO.class);
+        return util.exportExcel(list, "联系我日志数据");
+    }
+
+    /**
+     * 获取联系我日志详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwAppContactWayLogs:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwAppContactWayLogsService.selectQwAppContactWayLogsById(id));
+    }
+
+    /**
+     * 新增联系我日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwAppContactWayLogs:add')")
+    @Log(title = "联系我日志", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwAppContactWayLogs qwAppContactWayLogs)
+    {
+        return toAjax(qwAppContactWayLogsService.insertQwAppContactWayLogs(qwAppContactWayLogs));
+    }
+
+    /**
+     * 修改联系我日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwAppContactWayLogs:edit')")
+    @Log(title = "联系我日志", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwAppContactWayLogs qwAppContactWayLogs)
+    {
+        return toAjax(qwAppContactWayLogsService.updateQwAppContactWayLogs(qwAppContactWayLogs));
+    }
+
+    /**
+     * 删除联系我日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwAppContactWayLogs:remove')")
+    @Log(title = "联系我日志", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwAppContactWayLogsService.deleteQwAppContactWayLogsByIds(ids));
+    }
+}

+ 106 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwCompanyController.java

@@ -0,0 +1,106 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwCompany;
+import com.fs.qw.service.IQwCompanyService;
+import com.fs.qw.vo.QwOptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企微主体Controller
+ *
+ * @author fs
+ * @date 2024-10-09
+ */
+@RestController
+@RequestMapping("/qw/qwCompany")
+public class QwCompanyController extends BaseController
+{
+    @Autowired
+    private IQwCompanyService qwCompanyService;
+
+    /**
+     * 查询企微主体列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwCompany:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwCompany qwCompany)
+    {
+        startPage();
+        List<QwCompany> list = qwCompanyService.selectQwCompanyList(qwCompany);
+        return getDataTable(list);
+    }
+
+
+    @GetMapping("/all")
+    public R all()
+    {
+        List<QwOptionsVO> list = qwCompanyService.selectQwCompanyListOptionsVO();
+        return R.ok().put("data", list);
+    }
+    /**
+     * 导出企微主体列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwCompany:export')")
+    @Log(title = "企微主体", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwCompany qwCompany)
+    {
+        List<QwCompany> list = qwCompanyService.selectQwCompanyList(qwCompany);
+        ExcelUtil<QwCompany> util = new ExcelUtil<QwCompany>(QwCompany.class);
+        return util.exportExcel(list, "企微主体数据");
+    }
+
+    /**
+     * 获取企微主体详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwCompany:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwCompanyService.selectQwCompanyById(id));
+    }
+
+    /**
+     * 新增企微主体
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwCompany:add')")
+    @Log(title = "企微主体", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwCompany qwCompany)
+    {
+        return toAjax(qwCompanyService.insertQwCompany(qwCompany));
+    }
+
+    /**
+     * 修改企微主体
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwCompany:edit')")
+    @Log(title = "企微主体", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwCompany qwCompany)
+    {
+        return toAjax(qwCompanyService.updateQwCompany(qwCompany));
+    }
+
+    /**
+     * 删除企微主体
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwCompany:remove')")
+    @Log(title = "企微主体", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwCompanyService.deleteQwCompanyByIds(ids));
+    }
+}

+ 126 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwInformationController.java

@@ -0,0 +1,126 @@
+package com.fs.qw.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.TimeUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwInformation;
+import com.fs.qw.param.QwStatisticsParam;
+import com.fs.qw.service.IQwInformationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 信息流管理Controller
+ *
+ * @author fs
+ * @date 2024-11-11
+ */
+@RestController
+@RequestMapping("/qw/qwInformation")
+public class QwInformationController extends BaseController
+{
+    @Autowired
+    private IQwInformationService qwInformationService;
+
+    /**
+     * 查询信息流管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwInformation:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwInformation qwInformation)
+    {
+        startPage();
+        List<QwInformation> list = qwInformationService.selectQwInformationList(qwInformation);
+        return getDataTable(list);
+    }
+    @GetMapping("/statistics")
+    public R statistics(QwStatisticsParam param)
+    {
+//        List<QwWayStatisticsListVO> list= qwContactWayService.QwWayStatisticsListVO(param);
+        TimeUtils.TimeEntity timeEntity= TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+        timeEntity.setCompanyId(param.getId());
+        Integer cycleNum = timeEntity.getCycleNum();
+        Integer beginTime = timeEntity.getBeginTime();
+        List<Integer> timeList = new ArrayList<>();
+        for (int i = 1; i <= cycleNum; i++) {
+            timeList.add(beginTime);
+            beginTime = TimeUtils.formatTime(beginTime);
+        }
+        List<JSONObject> jsonObjectList = qwInformationService.selectQwWayStatisticsCounts(timeEntity.toMap());
+        List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+        List<Integer> addNum = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("addNum")).collect(Collectors.toList());
+        List<Integer> deleteNum = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("deleteNum")).collect(Collectors.toList());
+        List<Integer> num = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("num")).collect(Collectors.toList());
+        return R.ok().put("list",jsonObjectList).put("dates",dates).put("addNum",addNum).put("deleteNum",deleteNum).put("num",num);
+
+    }
+    /**
+     * 导出信息流管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwInformation:export')")
+    @Log(title = "信息流管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwInformation qwInformation)
+    {
+        List<QwInformation> list = qwInformationService.selectQwInformationList(qwInformation);
+        ExcelUtil<QwInformation> util = new ExcelUtil<QwInformation>(QwInformation.class);
+        return util.exportExcel(list, "信息流管理数据");
+    }
+
+    /**
+     * 获取信息流管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwInformation:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwInformationService.selectQwInformationById(id));
+    }
+
+    /**
+     * 新增信息流管理
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwInformation:add')")
+    @Log(title = "信息流管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwInformation qwInformation)
+    {
+        return toAjax(qwInformationService.insertQwInformation(qwInformation));
+    }
+
+    /**
+     * 修改信息流管理
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwInformation:edit')")
+    @Log(title = "信息流管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwInformation qwInformation)
+    {
+        qwInformation.setAddNum(null);
+        qwInformation.setNum(null);
+        qwInformation.setDeleteNum(null);
+        return toAjax(qwInformationService.updateQwInformation(qwInformation));
+    }
+
+    /**
+     * 删除信息流管理
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwInformation:remove')")
+    @Log(title = "信息流管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwInformationService.deleteQwInformationByIds(ids));
+    }
+}

+ 102 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java

@@ -0,0 +1,102 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.sop.domain.QwSopTemp;
+import com.fs.sop.service.IQwSopTempService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * sop模板Controller
+ *
+ * @author fs
+ * @date 2024-09-26
+ */
+@RestController
+@RequestMapping("/qw/sopTemp")
+public class QwSopTempController extends BaseController
+{
+    @Autowired
+    private IQwSopTempService qwSopTempService;
+    /**
+     * 查询sop模板列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(QwSopTemp qwSopTemp)
+    {
+        startPage();
+        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出sop模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:export')")
+    @Log(title = "sop模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwSopTemp qwSopTemp)
+    {
+        List<QwSopTemp> list = qwSopTempService.selectQwSopTempList(qwSopTemp);
+        ExcelUtil<QwSopTemp> util = new ExcelUtil<QwSopTemp>(QwSopTemp.class);
+        return util.exportExcel(list, "sop模板数据");
+    }
+
+    /**
+     * 获取sop模板详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return AjaxResult.success(qwSopTempService.selectQwSopTempById(id));
+    }
+
+    /**
+     * 新增sop模板
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:add')")
+    @Log(title = "sop模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwSopTemp qwSopTemp)
+    {
+        return toAjax(qwSopTempService.insertQwSopTemp(qwSopTemp));
+    }
+
+    /**
+     * 修改sop模板
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:edit')")
+    @Log(title = "sop模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwSopTemp qwSopTemp)
+    {
+
+        SimpleDateFormat slf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+        qwSopTemp.setUpdateTime(slf.format(new Date()));
+        return toAjax(qwSopTempService.updateQwSopTemp(qwSopTemp));
+    }
+
+    /**
+     * 删除sop模板
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopTemp:remove')")
+    @Log(title = "sop模板", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids)
+    {
+        ;
+//        qwSopTempService.deleteQwSopTempByIds(ids);
+        return toAjax(qwSopTempService.updateQwSopTempByIds(ids));
+    }
+}

+ 102 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwTagController.java

@@ -0,0 +1,102 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwTag;
+import com.fs.qw.param.QwTagParam;
+import com.fs.qw.service.IQwTagService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企微客户标签Controller
+ *
+ * @author fs
+ * @date 2024-06-20
+ */
+@RestController
+@RequestMapping("/qw/tag")
+public class QwTagController extends BaseController
+{
+    @Autowired
+    private IQwTagService qwTagService;
+    /**
+     * 查询企微客户标签列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(QwTag qwTag)
+    {
+        startPage();
+
+        List<QwTag> list = qwTagService.selectQwTagList(qwTag);
+        return getDataTable(list);
+    }
+
+    @PostMapping("/searchTags")
+    public TableDataInfo  searchTags(@RequestBody QwTagParam tagParam)
+    {
+        return getDataTable(qwTagService.searchTags(tagParam));
+    }
+    /**
+     * 导出企微客户标签列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:tag:export')")
+    @Log(title = "企微客户标签", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwTag qwTag)
+    {
+        List<QwTag> list = qwTagService.selectQwTagList(qwTag);
+        ExcelUtil<QwTag> util = new ExcelUtil<QwTag>(QwTag.class);
+        return util.exportExcel(list, "企微客户标签数据");
+    }
+
+    /**
+     * 获取企微客户标签详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:tag:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwTagService.selectQwTagById(id));
+    }
+
+    /**
+     * 新增企微客户标签
+     */
+    @PreAuthorize("@ss.hasPermi('qw:tag:add')")
+    @Log(title = "企微客户标签", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwTag qwTag)
+    {
+        return toAjax(qwTagService.insertQwTag(qwTag));
+    }
+
+    /**
+     * 修改企微客户标签
+     */
+    @PreAuthorize("@ss.hasPermi('qw:tag:edit')")
+    @Log(title = "企微客户标签", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwTag qwTag)
+    {
+        return toAjax(qwTagService.updateQwTag(qwTag));
+    }
+
+    /**
+     * 删除企微客户标签
+     */
+    @PreAuthorize("@ss.hasPermi('qw:tag:remove')")
+    @Log(title = "企微客户标签", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwTagService.deleteQwTagByIds(ids));
+    }
+}

+ 27 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java

@@ -0,0 +1,27 @@
+package com.fs.qw.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.qw.service.IQwUserService;
+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;
+
+/**
+ * 企微用户Controller
+ *
+ * @author fs
+ * @date 2024-06-20
+ */
+@RestController
+@RequestMapping("/qw/user")
+public class QwUserController extends BaseController {
+    @Autowired
+    private IQwUserService qwUserService;
+
+    @GetMapping("/getQwUserAll")
+    public AjaxResult getQwUserAll(){
+        return AjaxResult.success(qwUserService.getQwUserAll());
+    }
+}

+ 107 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwWorkLinkController.java

@@ -0,0 +1,107 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwWorkLink;
+import com.fs.qw.service.IQwWorkLinkService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企微获客链接管理Controller
+ *
+ * @author fs
+ * @date 2025-01-10
+ */
+@RestController
+@RequestMapping("/qw/workLink")
+public class QwWorkLinkController extends BaseController
+{
+    @Autowired
+    private IQwWorkLinkService qwWorkLinkService;
+
+    /**
+     * 查询企微获客链接管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwWorkLink qwWorkLink)
+    {
+        startPage();
+        List<QwWorkLink> list = qwWorkLinkService.selectQwWorkLinkList(qwWorkLink);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询企微获客链接管理列表-不分页
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:listAll')")
+    @GetMapping("/listAll")
+    public AjaxResult listAll(QwWorkLink qwWorkLink)
+    {
+        List<QwWorkLink> qwWorkLinks = qwWorkLinkService.selectQwWorkLinkListAll(qwWorkLink);
+        return AjaxResult.success(qwWorkLinks);
+    }
+
+    /**
+     * 导出企微获客链接管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:export')")
+    @Log(title = "企微获客链接管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwWorkLink qwWorkLink)
+    {
+        List<QwWorkLink> list = qwWorkLinkService.selectQwWorkLinkList(qwWorkLink);
+        ExcelUtil<QwWorkLink> util = new ExcelUtil<QwWorkLink>(QwWorkLink.class);
+        return util.exportExcel(list, "企微获客链接管理数据");
+    }
+
+    /**
+     * 获取企微获客链接管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwWorkLinkService.selectQwWorkLinkById(id));
+    }
+
+    /**
+     * 新增企微获客链接管理
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:add')")
+    @Log(title = "企微获客链接管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwWorkLink qwWorkLink)
+    {
+        return toAjax(qwWorkLinkService.insertQwWorkLink(qwWorkLink));
+    }
+
+    /**
+     * 修改企微获客链接管理
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:edit')")
+    @Log(title = "企微获客链接管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwWorkLink qwWorkLink){
+        return toAjax(qwWorkLinkService.updateQwWorkLink(qwWorkLink));
+    }
+
+    /**
+     * 删除企微获客链接管理
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLink:remove')")
+    @Log(title = "企微获客链接管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwWorkLinkService.deleteQwWorkLinkByIds(ids));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwWorkLinkUserController.java

@@ -0,0 +1,97 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwWorkLinkUser;
+import com.fs.qw.service.IQwWorkLinkUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企微获客链接用户关联Controller
+ *
+ * @author fs
+ * @date 2025-01-10
+ */
+@RestController
+@RequestMapping("/qw/workLinkUser")
+public class QwWorkLinkUserController extends BaseController
+{
+    @Autowired
+    private IQwWorkLinkUserService qwWorkLinkUserService;
+
+    /**
+     * 查询企微获客链接用户关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLinkUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwWorkLinkUser qwWorkLinkUser)
+    {
+        startPage();
+        List<QwWorkLinkUser> list = qwWorkLinkUserService.selectQwWorkLinkUserList(qwWorkLinkUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企微获客链接用户关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLinkUser:export')")
+    @Log(title = "企微获客链接用户关联", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwWorkLinkUser qwWorkLinkUser)
+    {
+        List<QwWorkLinkUser> list = qwWorkLinkUserService.selectQwWorkLinkUserList(qwWorkLinkUser);
+        ExcelUtil<QwWorkLinkUser> util = new ExcelUtil<QwWorkLinkUser>(QwWorkLinkUser.class);
+        return util.exportExcel(list, "企微获客链接用户关联数据");
+    }
+
+    /**
+     * 获取企微获客链接用户关联详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLinkUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwWorkLinkUserService.selectQwWorkLinkUserById(id));
+    }
+
+    /**
+     * 新增企微获客链接用户关联
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLinkUser:add')")
+    @Log(title = "企微获客链接用户关联", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwWorkLinkUser qwWorkLinkUser)
+    {
+        return toAjax(qwWorkLinkUserService.insertQwWorkLinkUser(qwWorkLinkUser));
+    }
+
+    /**
+     * 修改企微获客链接用户关联
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLinkUser:edit')")
+    @Log(title = "企微获客链接用户关联", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwWorkLinkUser qwWorkLinkUser)
+    {
+        return toAjax(qwWorkLinkUserService.updateQwWorkLinkUser(qwWorkLinkUser));
+    }
+
+    /**
+     * 删除企微获客链接用户关联
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workLinkUser:remove')")
+    @Log(title = "企微获客链接用户关联", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwWorkLinkUserService.deleteQwWorkLinkUserByIds(ids));
+    }
+}

+ 110 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwWorkUserController.java

@@ -0,0 +1,110 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwWorkUser;
+import com.fs.qw.service.IQwWorkUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企微获客添加的用户Controller
+ *
+ * @author fs
+ * @date 2025-01-10
+ */
+@RestController
+@RequestMapping("/qw/workUser")
+public class QwWorkUserController extends BaseController
+{
+    @Autowired
+    private IQwWorkUserService qwWorkUserService;
+
+    /**
+     * 查询企微获客添加的用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwWorkUser qwWorkUser)
+    {
+        startPage();
+        List<QwWorkUser> list = qwWorkUserService.selectQwWorkUserList(qwWorkUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企微获客添加的用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workUser:export')")
+    @Log(title = "企微获客添加的用户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwWorkUser qwWorkUser)
+    {
+        List<QwWorkUser> list = qwWorkUserService.selectQwWorkUserList(qwWorkUser);
+        ExcelUtil<QwWorkUser> util = new ExcelUtil<QwWorkUser>(QwWorkUser.class);
+        return util.exportExcel(list, "企微获客添加的用户数据");
+    }
+
+    /**
+     * 获取企微获客添加的用户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwWorkUserService.selectQwWorkUserById(id));
+    }
+
+    /**
+     * 新增企微获客添加的用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workUser:add')")
+    @Log(title = "企微获客添加的用户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwWorkUser qwWorkUser)
+    {
+        return toAjax(qwWorkUserService.insertQwWorkUser(qwWorkUser));
+    }
+
+    /**
+     * 修改企微获客添加的用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workUser:edit')")
+    @Log(title = "企微获客添加的用户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwWorkUser qwWorkUser)
+    {
+        return toAjax(qwWorkUserService.updateQwWorkUser(qwWorkUser));
+    }
+
+    /**
+     * 删除企微获客添加的用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:workUser:remove')")
+    @Log(title = "企微获客添加的用户", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwWorkUserService.deleteQwWorkUserByIds(ids));
+    }
+
+
+//    @GetMapping("/syncUsers")
+    public R syncUsers(){
+        qwWorkUserService.syncUsers();
+        return R.ok();
+    }
+//    @GetMapping("/uploadBd")
+    public R uploadBd(){
+        qwWorkUserService.uploadBd();
+        return R.ok();
+    }
+}

+ 54 - 0
fs-admin/src/main/java/com/fs/qw/controller/SopUserLogsController.java

@@ -0,0 +1,54 @@
+package com.fs.qw.controller;
+
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.qw.param.SopUserLogsVO;
+import com.fs.sop.params.SopUserLogsParam;
+import com.fs.sop.service.ISopUserLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * sopUserLogsController
+ *
+ * @author fs
+ * @date 2024-12-27
+ */
+@RestController
+@RequestMapping("/qwSop/sopUserLogs")
+public class SopUserLogsController extends BaseController
+{
+    @Autowired
+    private ISopUserLogsService sopUserLogsService;
+
+    /**
+     * 查询sopUserLogs列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(SopUserLogsParam sopUserLogs)
+    {
+        startPage();
+        List<SopUserLogsVO> list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 获取sopUserLogs详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sop:list')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return AjaxResult.success(sopUserLogsService.selectSopUserLogsById(id));
+    }
+
+}

+ 72 - 0
fs-admin/src/main/java/com/fs/qw/controller/SopUserLogsInfoController.java

@@ -0,0 +1,72 @@
+package com.fs.qw.controller;
+
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.sop.params.SendUserLogsInfoMsgParam;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * sopUserLogsInfoController
+ *
+ * @author fs
+ * @date 2024-12-27
+ */
+@RestController
+@RequestMapping("/qwSop/sopUserLogsInfo")
+public class SopUserLogsInfoController extends BaseController
+{
+    @Autowired
+    private ISopUserLogsInfoService sopUserLogsInfoService;
+
+    /**
+     * 查询sopUserLogsInfo列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(SopUserLogsInfo sopUserLogsInfo)
+    {
+        startPage();
+        List<SopUserLogsInfo> list = sopUserLogsInfoService.selectSopUserLogsInfoList(sopUserLogsInfo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取sopUserLogsInfo详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return AjaxResult.success(sopUserLogsInfoService.selectSopUserLogsInfoById(id));
+    }
+
+    /**
+     * 修改sopUserLogsInfo
+     */
+    @Log(title = "updateSopUserLogsInfo", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R edit(@RequestBody SopUserLogsInfo sopUserLogsInfo)
+    {
+        return sopUserLogsInfoService.updateSopUserLogsInfoToTime(sopUserLogsInfo);
+    }
+
+    /**
+     * 一键群发sopUserLogsInfo
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopUserLogsInfo:msg')")
+    @Log(title = "sendMsgSopUserLogsInfo", businessType = BusinessType.INSERT,isSaveRequestData=false)
+    @PostMapping("/sendUserLogsInfoMsg")
+    public R sendUserLogsInfoMsg(@RequestBody SendUserLogsInfoMsgParam param)
+    {
+        return sopUserLogsInfoService.sendUserLogsInfoMsg(param);
+    }
+}

+ 126 - 0
fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java

@@ -0,0 +1,126 @@
+package com.fs.qw.qwTask;
+
+import com.fs.course.service.IFsUserCourseService;
+import com.fs.qw.mapper.QwCompanyMapper;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwGroupMsgService;
+import com.fs.qw.service.impl.QwUserServiceImpl;
+import com.fs.qw.vo.QwOptionsVO;
+import com.fs.sop.service.ISopUserLogsService;
+import com.fs.sop.service.impl.QwSopLogsServiceImpl;
+import com.fs.sop.service.impl.QwSopServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component("qwTask")
+public class qwTask {
+
+    @Autowired
+    private QwSopServiceImpl qwSopService;
+
+    @Autowired
+    private QwSopLogsServiceImpl qwSopLogsService;
+
+    @Autowired
+    private IQwGroupMsgService qwGroupMsgService;
+
+    @Autowired
+    private ISopUserLogsService sopUserLogsService;
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+    @Autowired
+    private QwUserServiceImpl qwUserServiceImpl;
+    @Autowired
+    QwCompanyMapper qwCompanyMapper;
+
+    @Autowired
+    private IFsUserCourseService iFsUserCourseService;
+
+    //正在使用
+    public void qwExternalContact()
+    {
+        qwExternalContactService.qwExternalContactSync();
+    }
+    public void syncQwUser()
+    {  List<QwOptionsVO> vos = qwCompanyMapper.selectQwCompanyListOptionsVO();
+        for (QwOptionsVO vo : vos) {
+            qwUserServiceImpl.syncQwUser(vo.getCorpId());
+        }
+
+    }
+    //正在使用
+    public void qwExternalContactAddAndDel()
+    {
+        qwExternalContactService.qwExternalContactSyncAddAndDel();
+    }
+    //正在使用
+    public void qwExternalContactSyncAddRedis()
+    {
+        qwExternalContactService.qwExternalContactSyncAddRedis();
+    }
+    //正在使用
+    public void qwExternalContactAddRedis()
+    {
+        qwExternalContactService.qwExternalContactAddRedis();
+    }
+    //正在使用
+    public void qwExternalContactAddAndDelByRedis()
+    {
+        qwExternalContactService.qwExternalContactAddAndDelByRedis();
+    }
+    //正在使用
+    public void qwExternalContactAddTag()
+    {
+        qwExternalContactService.qwExternalContactAddCourseTag();
+    }
+
+    /**
+    * 定时任务 将 qw_sop任务 符合条件的录入到sop_user_Logs(clickHouse)
+    */
+    public void qwCheckSopRuleTime()
+    {
+        qwSopService.checkSopRuleTime();
+    }
+
+    /**
+    * 定时任务 将 clickHouse的sopUserLogs(营期表)按每小时的巡回 录入clickHouse的qw_sop_logs(消息发送表)
+    */
+    public void selectSopUserLogsListByTime(){
+        sopUserLogsService.selectSopUserLogsListByTime();
+    }
+
+    /**
+    * 定时 发送 通过调用 企业微信接口 发送的 SOP 群发消息
+    */
+    public void SendQwApiSopLogTimer(){
+        qwSopLogsService.checkQwSopLogs();
+    }
+
+    /**
+    * 定时获取 通过调用 企业微信接口 发送的 SOP 客户群发消息 的反馈结果
+    */
+    public void GetQwApiSopLogResultTimer(){
+        qwSopLogsService.qwSopLogsResult();
+    }
+
+    /**
+    * 定时群发API接口的 客户/群 群发
+    */
+    public void sendQwGroupMsgTask(){
+        qwGroupMsgService.qwGroupMsgTask();
+    }
+
+    /**
+    *  定时更新 待发送中已经算过期了的不能发的消息
+    */
+    public void updateQwSopLogsBySendStatusTask(){
+        qwSopLogsService.updateQwSopLogsBySendStatus();
+    }
+
+    /**
+     * 2天跑一次 将 课程的封面 上传企业微信 并上传到redis
+     */
+
+}

+ 3 - 3
fs-admin/src/main/resources/application-dev.yml

@@ -83,9 +83,9 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                    url: jdbc:mysql://42.194.245.189:3306/test_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                    username: root
-                    password: YJF_2024
+                    url: jdbc:mysql://139.186.77.83:3306/sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: Rtroot
+                    password: Rtroot
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量

+ 3 - 3
fs-company/src/main/resources/application-dev.yml

@@ -81,9 +81,9 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                    url: jdbc:mysql://42.194.245.189:3306/test_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                    username: root
-                    password: YJF_2024
+                    url: jdbc:mysql://139.186.77.83:3306/sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: Rtroot
+                    password: Rtroot
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量

+ 9 - 24
fs-qw-api/src/main/resources/application-dev.yml

@@ -6,12 +6,10 @@ spring:
         host: localhost
         # 端口,默认为6379
         port: 6379
-        # 数据库索引
-        database: 0
         # 密码
         password:
         # 连接超时时间
-        timeout: 20s
+        timeout: 10s
         lettuce:
             pool:
                 # 连接池中的最小空闲连接
@@ -23,33 +21,21 @@ spring:
                 # #连接池最大阻塞等待时间(使用负值表示没有限制)
                 max-wait: -1ms
     datasource:
-        clickhouse:
-            type: com.alibaba.druid.pool.DruidDataSource
-#            driverClassName: ru.yandex.clickhouse.ClickHouseDriver
-            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
-            url: jdbc:clickhouse://1.14.104.71:8123/sop_test?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
-            username: default
-            password: rt2024
-            initialSize: 10
-            maxActive: 100
-            minIdle: 10
-            maxWait: 6000
         mysql:
             type: com.alibaba.druid.pool.DruidDataSource
             driverClassName: com.mysql.cj.jdbc.Driver
             druid:
                 # 主库数据源
                 master:
-                    url: jdbc:mysql://42.194.245.189:3306/rt_fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                    username: root
-                    password: YJF_2024
+                    url: jdbc:mysql://139.186.77.83:3306/ylrz_scrm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: Rtroot
+                    password: Rtroot
                 # 从库数据源
                 slave:
                     # 从数据源开关/默认关闭
-                    enabled: false
-                    url:
-                    username:
-                    password:
+                    url: jdbc:mysql://139.186.77.83:3306/ylrz_scrm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: Rtroot
+                    password: Rtroot
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量
@@ -77,8 +63,8 @@ spring:
                     allow:
                     url-pattern: /druid/*
                     # 控制台管理用户名和密码
-                    login-username: fs
-                    login-password: 123456
+                    login-username:
+                    login-password:
                 filter:
                     stat:
                         enabled: true
@@ -148,4 +134,3 @@ rocketmq:
         group: test-group
         access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
         secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
-

+ 0 - 57
fs-qw-api/src/main/resources/application-druid-bly.yml

@@ -1,57 +0,0 @@
-# 数据源配置
-spring:
-    datasource:
-        type: com.alibaba.druid.pool.DruidDataSource
-        driverClassName: com.mysql.cj.jdbc.Driver
-        druid:
-            # 主库数据源
-            master:
-                url: jdbc:mysql://cq-cdb-95qvu08p.sql.tencentcdb.com:63998/fs_his_rt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                username: root
-                password: Rtyy_2023
-            # 从库数据源
-            slave:
-                # 从数据源开关/默认关闭
-                enabled: false
-                url:
-                username:
-                password:
-            # 初始连接数
-            initialSize: 5
-            # 最小连接池数量
-            minIdle: 10
-            # 最大连接池数量
-            maxActive: 20
-            # 配置获取连接等待超时的时间
-            maxWait: 60000
-            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
-            timeBetweenEvictionRunsMillis: 60000
-            # 配置一个连接在池中最小生存的时间,单位是毫秒
-            minEvictableIdleTimeMillis: 300000
-            # 配置一个连接在池中最大生存的时间,单位是毫秒
-            maxEvictableIdleTimeMillis: 900000
-            # 配置检测连接是否有效
-            validationQuery: SELECT 1 FROM DUAL
-            testWhileIdle: true
-            testOnBorrow: false
-            testOnReturn: false
-            webStatFilter:
-                enabled: true
-            statViewServlet:
-                enabled: true
-                # 设置白名单,不填则允许所有访问
-                allow:
-                url-pattern: /druid/*
-                # 控制台管理用户名和密码
-                login-username: fs
-                login-password: 123456
-            filter:
-                stat:
-                    enabled: true
-                    # 慢SQL记录
-                    log-slow-sql: true
-                    slow-sql-millis: 1000
-                    merge-sql: true
-                wall:
-                    config:
-                        multi-statement-allow: true

+ 0 - 91
fs-qw-api/src/main/resources/application-druid.yml

@@ -1,91 +0,0 @@
-# 数据源配置
-spring:
-    # redis 配置
-    redis:
-        # 地址  localhost
-        host: 127.0.0.1
-        # 端口,默认为6379
-        port: 6379
-        # 数据库索引
-        database: 0
-        # 密码
-        password:
-        #        password:
-        # 连接超时时间
-        timeout: 10s
-        lettuce:
-            pool:
-                # 连接池中的最小空闲连接
-                min-idle: 0
-                # 连接池中的最大空闲连接
-                max-idle: 8
-                # 连接池的最大数据库连接数
-                max-active: 8
-                # #连接池最大阻塞等待时间(使用负值表示没有限制)
-                max-wait: -1ms
-    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
-            druid:
-                # 主库数据源
-                master:
-                    url: jdbc:mysql://cq-cdb-95qvu08p.sql.tencentcdb.com:63998/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                    username: root
-                    password: Rtyy_2023
-                # 从库数据源
-                slave:
-                    # 从数据源开关/默认关闭
-                    enabled: false
-                    url:
-                    username:
-                    password:
-                # 初始连接数
-                initialSize: 5
-                # 最小连接池数量
-                minIdle: 10
-                # 最大连接池数量
-                maxActive: 20
-                # 配置获取连接等待超时的时间
-                maxWait: 60000
-                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
-                timeBetweenEvictionRunsMillis: 60000
-                # 配置一个连接在池中最小生存的时间,单位是毫秒
-                minEvictableIdleTimeMillis: 300000
-                # 配置一个连接在池中最大生存的时间,单位是毫秒
-                maxEvictableIdleTimeMillis: 900000
-                # 配置检测连接是否有效
-                validationQuery: SELECT 1 FROM DUAL
-                testWhileIdle: true
-                testOnBorrow: false
-                testOnReturn: false
-                webStatFilter:
-                    enabled: true
-                statViewServlet:
-                    enabled: true
-                    # 设置白名单,不填则允许所有访问
-                    allow:
-                    url-pattern: /druid/*
-                    # 控制台管理用户名和密码
-                    login-username: fs
-                    login-password: 123456
-                filter:
-                    stat:
-                        enabled: true
-                        # 慢SQL记录
-                        log-slow-sql: true
-                        slow-sql-millis: 1000
-                        merge-sql: true
-                    wall:
-                        config:
-                            multi-statement-allow: true

+ 64 - 17
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -2,10 +2,14 @@ package com.fs.app.taskService.impl;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.app.taskService.SopLogsTaskService;
 import com.fs.common.utils.BatchUtils;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
@@ -17,6 +21,7 @@ import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qw.vo.QwSopRuleTimeVO;
 import com.fs.qw.vo.QwSopTempSetting;
@@ -78,6 +83,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private QwSopTagMapper qwSopTagMapper ;
     @Autowired
     private QwSopMapper sopMapper;
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
 
     @Autowired
     private FsCourseWatchLogMapper fsCourseWatchLogMapper;
@@ -122,6 +129,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     @Autowired
     private QwSopTempMapper qwSopTempMapper;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
 
     @PostConstruct
     public void init() {
@@ -244,7 +253,35 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             return;
         }
 
+        // 查询销售二级域名
+        Set<Long> ids = sopUserLogsVos.stream().map(s -> {
+            String[] userKey = s.getUserId().split("\\|");
+            if (userKey.length < 3) {
+                return null;
+            }
+            return Long.parseLong(userKey[1]);
+        }).filter(Objects::nonNull).collect(Collectors.toSet());
+        List<CompanyUser> companyUserList;
+        if (ids.isEmpty()) {
+            companyUserList = new ArrayList<>();
+        } else {
+            companyUserList = companyUserService.selectCompanyUserByIds(ids);
+        }
+
         Map<String, List<SopUserLogsVo>> sopLogsGroupedById = sopUserLogsVos.stream()
+                .peek(s -> {
+                    String[] userKey = s.getUserId().split("\\|");
+                    if (userKey.length < 3) {
+                        return;
+                    }
+
+                    // 销售ID
+                    Long companyUserId = Long.parseLong(userKey[1]);
+                    CompanyUser companyUser = companyUserList.stream().filter(cu -> Objects.equals(cu.getUserId(), companyUserId)).findFirst().orElse(null);
+                    if (Objects.nonNull(companyUser)) {
+                        s.setDomain(companyUser.getDomain());
+                    }
+                })
                 .collect(Collectors.groupingBy(SopUserLogsVo::getSopId));
 
         log.info("共分组 {} 个 SOP ID 进行处理。", sopLogsGroupedById.size());
@@ -465,6 +502,25 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         userLogsInfo.setUserLogsId(logVo.getId());
 
                         List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoList(userLogsInfo);
+                        if(logVo.getIsRegister() == 1){
+                            List<Long> externalContactIdList = PubFun.listToNewList(sopUserLogsInfos, SopUserLogsInfo::getExternalId);
+                            List<QwExternalContact> list = qwExternalContactService.list(new QueryWrapper<QwExternalContact>().isNotNull("fs_user_id").in("id", externalContactIdList));
+                            Map<Long, QwExternalContact> map = PubFun.listToMapByGroupObject(list, QwExternalContact::getId);
+                            sopUserLogsInfos = sopUserLogsInfos.stream().filter(e -> map.containsKey(e.getExternalId())).collect(Collectors.toList());
+                        }
+
+
+                        // 获取fsUserId
+                        Set<Long> externalIds = sopUserLogsInfos.stream().map(SopUserLogsInfo::getExternalId).collect(Collectors.toSet());
+                        if (!externalIds.isEmpty()) {
+                            List<QwExternalContact> externalContactList = qwExternalContactService.list(Wrappers.<QwExternalContact>lambdaQuery().in(QwExternalContact::getId, externalIds));
+                            sopUserLogsInfos.forEach(s -> {
+                                QwExternalContact qwExternalContact = externalContactList.stream().filter(e -> Objects.equals(s.getExternalId(), e.getId())).findFirst().orElse(null);
+                                if (Objects.nonNull(qwExternalContact)) {
+                                    s.setFsUserId(qwExternalContact.getFsUserId());
+                                }
+                            });
+                        }
 
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content);
 
@@ -570,7 +626,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                 Long fsUserId = contactId.getFsUserId();
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId);
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
-                        type, qwUserId, companyUserId, companyId, externalId);
+                        type, qwUserId, companyUserId, companyId, externalId, fsUserId);
             } catch (Exception e) {
                 log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
             }
@@ -622,14 +678,14 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private void handleLogBasedOnType(QwSopLogs sopLogs, QwSopTempSetting.Content content,
                                       SopUserLogsVo logVo, Date sendTime, Long courseId,
                                       Long videoId, int type, String qwUserId,
-                                      String companyUserId, String companyId, String externalId) {
+                                      String companyUserId, String companyId, String externalId, Long fsUserId) {
         switch (type) {
             case 1:
                 handleNormalMessage(sopLogs, content,companyUserId);
                 break;
             case 2:
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
-                        qwUserId, companyUserId, companyId, externalId);
+                        qwUserId, companyUserId, companyId, externalId, fsUserId);
                 break;
             case 3:
                 handleOrderMessage(sopLogs, content);
@@ -661,7 +717,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private void handleCourseMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content,
                                      SopUserLogsVo logVo, Date sendTime, Long courseId,
                                      Long videoId, String qwUserId, String companyUserId,
-                                     String companyId, String externalId) {
+                                     String companyId, String externalId, Long fsUserId) {
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         if (clonedContent == null) {
@@ -684,7 +740,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             if ("1".equals(setting.getIsBindUrl())&&("3".equals(setting.getContentType())||"1".equals(setting.getContentType()))) {
                 addWatchLogIfNeeded(sopLogs, videoId, courseId, sendTime, qwUserId, companyUserId, companyId, externalId,logVo);
                 String sortLink = generateShortLink(setting, logVo, sendTime, courseId, videoId,
-                        qwUserId, companyUserId, companyId, externalId);
+                        qwUserId, companyUserId, companyId, externalId, fsUserId);
                 if (StringUtils.isNotEmpty(sortLink)) {
                     if ("3".equals(setting.getContentType())) {
                         setting.setLinkUrl(sortLink);
@@ -725,7 +781,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
     private String generateShortLink(QwSopTempSetting.Content.Setting setting, SopUserLogsVo logVo, Date sendTime,
                                      Long courseId, Long videoId, String qwUserId,
-                                     String companyUserId, String companyId, String externalId) {
+                                     String companyUserId, String companyId, String externalId, Long fsUserId) {
         // 获取缓存的配置
         CourseConfig config;
         synchronized(configLock) {
@@ -757,6 +813,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         courseMap.setCourseId(link.getCourseId());
         courseMap.setQwExternalId(link.getQwExternalId());
         courseMap.setLinkType(0);
+        courseMap.setFsUserId(fsUserId);
 
         String courseJson = JSON.toJSONString(courseMap);
         String realLinkFull = REAL_LINK_PREFIX + courseJson;
@@ -777,17 +834,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
         link.setUpdateTime(updateTime);
 
-        // 从缓存中随机选择一个域名
-        FsCourseDomainName fsCourseDomainName;
-        if (cachedDomainNames == null || cachedDomainNames.isEmpty()) {
-            log.error("No domain names available for short link generation.");
-            return "";
-        }
-
-        int randomIndex = ThreadLocalRandom.current().nextInt(cachedDomainNames.size());
-        fsCourseDomainName = cachedDomainNames.get(randomIndex);
-
-        String sortLink = "https://" + fsCourseDomainName.getDomainName() + "/s/" + link.getLink();
+        String sortLink = "https://" + logVo.getDomain() + "/s/" + link.getLink();
         enqueueCourseLink(link);
         return sortLink;
     }

+ 4 - 6
fs-service-system/pom.xml

@@ -16,11 +16,9 @@
     </description>
 
     <properties>
-        <weixin-java-cp.version>4.4.0</weixin-java-cp.version>
-        <weixin-java-miniapp.version>4.4.0</weixin-java-miniapp.version>
-        <weixin-java-cp.version>4.4.0</weixin-java-cp.version>
-        <weixin-java-miniapp.version>4.4.0</weixin-java-miniapp.version>
-        <weixin-java-mp.version>4.4.0</weixin-java-mp.version>
+        <weixin-java-cp.version>4.7.0</weixin-java-cp.version>
+        <weixin-java-miniapp.version>4.7.0</weixin-java-miniapp.version>
+        <weixin-java-mp.version>4.7.0</weixin-java-mp.version>
     </properties>
     <dependencies>
         <!-- 通用工具-->
@@ -89,7 +87,7 @@
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-pay</artifactId>
-            <version>4.6.5.B</version>
+            <version>4.7.2.B</version>
         </dependency>
         <dependency>
             <groupId>com.github.binarywang</groupId>

+ 8 - 0
fs-service-system/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * 物业公司管理员信息Mapper接口
@@ -248,5 +249,12 @@ public interface CompanyUserMapper
     @Select("select * from company_user where company_id=#{companyId} and del_flag=0")
     List<CompanyUser> selectCompanyUserByCompanyId(Long companyId);
 
+    /**
+     * 查询公司销售列表
+     * @param ids 销售ID集合
+     * @return  list
+     */
+    List<CompanyUser> selectCompanyUserByIds(Set<Long> ids);
+
     List<CompanyUser> selectAllCompanyUserByParentId(Long parentId);
 }

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

@@ -12,6 +12,7 @@ import com.fs.his.vo.OptionsVO;;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * 物业公司管理员信息Service接口
@@ -127,5 +128,12 @@ public interface ICompanyUserService {
 
     CompanyUser selectCompanyUserByUserId(Long userId);
 
+    /**
+     * 查询公司销售列表
+     * @param ids 销售ID集合
+     * @return  list
+     */
+    List<CompanyUser> selectCompanyUserByIds(Set<Long> ids);
+
     List<CompanyUser> selectAllCompanyUserByParentId(Long parentId);
 }

+ 10 - 0
fs-service-system/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -386,6 +386,16 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         return companyUserMapper.selectCompanyUserByUserId(userId);
     }
 
+    /**
+     * 查询公司销售列表
+     * @param ids 销售ID集合
+     * @return  list
+     */
+    @Override
+    public List<CompanyUser> selectCompanyUserByIds(Set<Long> ids) {
+        return companyUserMapper.selectCompanyUserByIds(ids);
+    }
+
     @Override
     public  List<CompanyUser> selectAllCompanyUserByParentId(Long parentId) {
         return companyUserMapper.selectAllCompanyUserByParentId(parentId);

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

@@ -16,5 +16,6 @@ public class CourseConfig implements Serializable {
     private String realLinkDomainName;//真链域名
     private String courseDomainName;//链接域名
     private Integer rewardType; // 奖励类型 1红包 2积分
+    private Integer redPacketMode;//红包模式 1总公司 2销售公司
 
 }

+ 3 - 1
fs-service-system/src/main/java/com/fs/course/config/RedPacketConfig.java

@@ -6,7 +6,9 @@ import java.io.Serializable;
 
 @Data
 public class RedPacketConfig implements Serializable {
-    private String appId;
+    private String appId;//公众号appId
+
+    private String miniappId;//小程序appId
     /**
      * 商户号.
      */

+ 5 - 0
fs-service-system/src/main/java/com/fs/course/domain/FsCourseRealLink.java

@@ -29,4 +29,9 @@ public class FsCourseRealLink implements Serializable
 
     private Long linkId;
 
+    /**
+     * 用户ID (fs_user表)
+     */
+    private Long fsUserId;
+
 }

+ 109 - 84
fs-service-system/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.course.service.impl;
 
+import cn.hutool.core.util.NumberUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.BeanCopyUtils;
@@ -561,110 +562,134 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Override
     @Transactional
     public R sendReward(FsCourseSendRewardUParam param) {
+        // 获取用户信息
         FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
-        if (StringUtils.isEmpty(user.getMpOpenId())){
-            return R.error("未识别到领取信息");
-        }
+//        if (StringUtils.isEmpty(user.getMpOpenId())){
+//            return R.error("未识别到领取信息");
+//        }
         FsCourseWatchLog log = new FsCourseWatchLog();
 
-        //判断链接类型
-        if (param.getLinkType()!=null&&param.getLinkType()==1){
-            FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(),param.getUserId());
-            if (packetLog!=null){
+        // 根据链接类型判断是否已发放奖励
+        if (param.getLinkType() != null && param.getLinkType() == 1) {
+            FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(), param.getUserId());
+            if (packetLog != null) {
                 return R.error("奖励已发放");
             }
-        }else {
-            log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(),param.getVideoId(),param.getQwUserId(),param.getQwExternalId());
-            if (log==null){
+        } else {
+            log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+            if (log == null) {
                 return R.error("无记录");
             }
-            if (log.getRewardType()!=null){
+            if (log.getRewardType() != null) {
                 return R.error("奖励已发放");
             }
         }
 
+        // 获取视频信息
         FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
 
-        // 获取配置
+        // 获取配置信息
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
 
-        //发放奖励
-        switch (config.getRewardType()){
-            //红包奖励
+        // 根据奖励类型发放不同奖励
+        switch (config.getRewardType()) {
+            // 红包奖励
             case 1:
-                BigDecimal amount = BigDecimal.ZERO;
-                FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId());
-                WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-
-                if (redPackage!=null){
-                    amount = redPackage.getRedPacketMoney();
-                }else if (video!=null){
-                    amount = new BigDecimal(video.getRedPacketMoney());
-                }
-                packetParam.setOpenId(user.getMpOpenId());
-                packetParam.setAmount(amount);
-                R sendRedPacket = paymentService.sendRedPacket(packetParam);
-                if (sendRedPacket.get("code").equals(200)){
-                    //添加红包记录
-                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                    redPacketLog.setCourseId(param.getCourseId());
-                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                    redPacketLog.setCompanyId(param.getCompanyId());
-                    redPacketLog.setUserId(param.getUserId());
-                    redPacketLog.setVideoId(param.getVideoId());
-                    redPacketLog.setStatus(0);
-                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
-                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                    redPacketLog.setCreateTime(new Date());
-                    redPacketLog.setAmount(amount);
-                    redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
-                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-                    if (param.getLinkType()==null || param.getLinkType()==0){
-                        log.setRewardType(config.getRewardType());
-                        courseWatchLogMapper.updateFsCourseWatchLog(log);
-                    }
-                    return R.ok("奖励发放成功");
-                }else {
-                    return R.error("奖励发送失败,请联系客服");
-                }
-            //积分奖励
+                return sendRedPacketReward(param, user, log, video, config);
+            // 积分奖励
             case 2:
-                //增加积分
-                FsUser userMap=new FsUser();
-                userMap.setUserId(user.getUserId());
-//                userMap.setIntegral(user.getIntegral()+config.getAnswerIntegral());
-                fsUserMapper.updateFsUser(userMap);
-                FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
-//                integralLogs.setIntegral(config.getAnswerIntegral().longValue());
-                integralLogs.setUserId(user.getUserId());
-                integralLogs.setBalance(userMap.getIntegral());
-                integralLogs.setLogType(17);
-                integralLogs.setBusinessId(StringUtils.isNotEmpty(log.getLogId().toString()) ? log.getLogId().toString() : null);
-                integralLogs.setCreateTime(new Date());
-                fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
-                if (param.getLinkType()==null || param.getLinkType()==0 ){
-                    log.setRewardType(config.getRewardType());
-                    courseWatchLogMapper.updateFsCourseWatchLog(log);
-                    //转换红包
-                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                    redPacketLog.setCourseId(param.getCourseId());
-                    redPacketLog.setOutBatchNo(integralLogs.getId().toString());
-                    redPacketLog.setCompanyId(param.getCompanyId());
-                    redPacketLog.setUserId(param.getUserId());
-                    redPacketLog.setVideoId(param.getVideoId());
-                    redPacketLog.setStatus(1);
-                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
-                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                    redPacketLog.setCreateTime(new Date());
-                    redPacketLog.setAmount(BigDecimal.valueOf(config.getAnswerIntegral()).divide(BigDecimal.valueOf(1000)));
-                    redPacketLog.setRemark("点播答题领取积分转");
-                    redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
-                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-                }
-                return R.ok("奖励发放成功");
+                return sendIntegralReward(user, log, config);
             default:
                 return R.error("参数错误!");
         }
     }
+    
+    /**
+     * 发放红包奖励
+     * 
+     * @param param 请求参数
+     * @param user 用户信息
+     * @param log 观看日志
+     * @param video 视频信息
+     * @param config 配置信息
+     * @return 处理结果
+     */
+    private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
+        // 确定红包金额
+        BigDecimal amount = BigDecimal.ZERO;
+        FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId());
+        
+        if (redPackage != null) {
+            amount = redPackage.getRedPacketMoney();
+        } else if (video != null) {
+            amount = new BigDecimal(video.getRedPacketMoney());
+        }
+        
+        // 准备发送红包参数
+        WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
+        packetParam.setOpenId(user.getMpOpenId());
+        // 来源是小程序切换openId
+        if (param.getSource() == 2) {
+            packetParam.setOpenId(user.getCourseMaOpenId());
+        }
+        packetParam.setAmount(amount);
+        packetParam.setSource(param.getSource());
+        
+        // 发送红包
+        R sendRedPacket = paymentService.sendRedPacket(packetParam);
+        if (sendRedPacket.get("code").equals(200)) {
+            // 添加红包记录
+            FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+            redPacketLog.setCourseId(param.getCourseId());
+            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+            redPacketLog.setCompanyId(param.getCompanyId());
+            redPacketLog.setUserId(param.getUserId());
+            redPacketLog.setVideoId(param.getVideoId());
+            redPacketLog.setStatus(0);
+            redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+            redPacketLog.setCompanyUserId(param.getCompanyUserId());
+            redPacketLog.setCreateTime(new Date());
+            redPacketLog.setAmount(amount);
+            redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+            redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+            
+            // 更新观看记录的奖励类型
+            if (param.getLinkType() == null || param.getLinkType() == 0) {
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+            }
+            return R.ok("奖励发放成功");
+        } else {
+            return R.error("奖励发送失败,请联系客服");
+        }
+    }
+    
+    /**
+     * 发放积分奖励
+     * 
+     * @param user 用户信息
+     * @param log 观看日志
+     * @param config 配置信息
+     * @return 处理结果
+     */
+    private R sendIntegralReward(FsUser user, FsCourseWatchLog log, CourseConfig config) {
+        // 更新用户积分
+        FsUser userMap = new FsUser();
+        userMap.setUserId(user.getUserId());
+        userMap.setIntegral(NumberUtil.add(user.getIntegral(), config.getAnswerIntegral()));
+        fsUserMapper.updateFsUser(userMap);
+        
+        // 记录积分日志
+        FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
+        integralLogs.setIntegral(new BigDecimal(config.getAnswerIntegral()));
+        integralLogs.setUserId(user.getUserId());
+        integralLogs.setBalance(userMap.getIntegral());
+        integralLogs.setLogType(17);
+        integralLogs.setBusinessId(StringUtils.isNotEmpty(log.getLogId().toString()) ? log.getLogId().toString() : null);
+        integralLogs.setCreateTime(new Date());
+        fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
+        
+        return R.ok("奖励发放成功");
+    }
 }

+ 63 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtBarcodeDto.java

@@ -0,0 +1,63 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 条码信息 DTO
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtBarcodeDto {
+
+    /**
+     * 货品ID
+     */
+    @JsonProperty("goods_id")
+    private String goodsId;
+
+    /**
+     * 规格ID
+     */
+    @JsonProperty("spec_id")
+    private String specId;
+
+    /**
+     * 条码信息
+     */
+    @JsonProperty("barcode")
+    private String barcode;
+
+    /**
+     * target_id的类型 1普通规格 2组合装
+     */
+    @JsonProperty("type")
+    private String type;
+
+    /**
+     * 是否为主条码 0 否 1 是
+     */
+    @JsonProperty("is_master")
+    private String isMaster;
+
+    /**
+     * 扫码一次对应出库数量
+     */
+    @JsonProperty("out_target_num")
+    private String outTargetNum;
+
+    /**
+     * 扫码一次对应入库货品数量
+     */
+    @JsonProperty("target_num")
+    private String targetNum;
+
+    /**
+     * 最后修改时间
+     */
+    @JsonProperty("modified")
+    private String modified;
+}

+ 43 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtBaseResponseDTO.java

@@ -0,0 +1,43 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Base API Response Structure
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtBaseResponseDTO {
+
+    /**
+     * 状态码:0表示成功,其他表示失败
+     */
+    @JsonProperty("code")
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    @JsonProperty("message")
+    private String message;
+
+    /**
+     * 符合条件的数据条数,用来分页 当page_no = 0时返回
+     */
+    @JsonProperty("total_count")
+    private Integer totalCount;
+
+    /**
+     * 货品节点列表
+     */
+    @JsonProperty("goods_list")
+    private List<ErpWdtGoodsDto> goodsList;
+
+}

+ 227 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsDto.java

@@ -0,0 +1,227 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 货品节点 (SPU) DTO
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtGoodsDto {
+
+    /**
+     * 货品ID (货品表主键)
+     */
+    @JsonProperty("goods_id")
+    private Integer goodsId;
+
+    /**
+     * 货品编号 (代表SPU所有属性的唯一编号)
+     */
+    @JsonProperty("goods_no")
+    private String goodsNo;
+
+    /**
+     * 货品名称
+     */
+    @JsonProperty("goods_name")
+    private String goodsName;
+
+    /**
+     * 简称
+     */
+    @JsonProperty("short_name")
+    private String shortName;
+
+    /**
+     * 货品别名
+     */
+    @JsonProperty("alias")
+    private String alias;
+
+    /**
+     * 货品类别 0:其它, 1:销售货品, 2:原材料, 3:包装物, 4:周转材料, 5:虚拟商品, 6:固定资产,7:保修配件 8:虚拟代发货品
+     */
+    @JsonProperty("goods_type")
+    private Integer goodsType; // tinyint mapped to Integer
+
+    /**
+     * 规格数
+     */
+    @JsonProperty("spec_count")
+    private Integer specCount;
+
+    /**
+     * 拼音
+     */
+    @JsonProperty("pinyin")
+    private String pinyin;
+
+    /**
+     * 品牌编号
+     */
+    @JsonProperty("brand_no")
+    private String brandNo;
+
+    /**
+     * 品牌名称
+     */
+    @JsonProperty("brand_name")
+    private String brandName;
+
+    /**
+     * 备注
+     */
+    @JsonProperty("remark")
+    private String remark;
+
+    /**
+     * 自定义属性1
+     */
+    @JsonProperty("prop1")
+    private String prop1;
+
+    /**
+     * 自定义属性2
+     */
+    @JsonProperty("prop2")
+    private String prop2;
+
+    /**
+     * 自定义属性3
+     */
+    @JsonProperty("prop3")
+    private String prop3;
+
+    /**
+     * 自定义属性4
+     */
+    @JsonProperty("prop4")
+    private String prop4;
+
+    /**
+     * 自定义属性5
+     */
+    @JsonProperty("prop5")
+    private String prop5;
+
+    /**
+     * 自定义属性6
+     */
+    @JsonProperty("prop6")
+    private String prop6;
+
+    /**
+     * 产地
+     */
+    @JsonProperty("origin")
+    private String origin;
+
+    /**
+     * 分类id
+     */
+    @JsonProperty("class_id")
+    private String classId;
+
+    /**
+     * 分类名称
+     */
+    @JsonProperty("class_name")
+    private String className;
+
+    /**
+     * 品牌ID
+     */
+    @JsonProperty("brand_id")
+    private String brandId;
+
+    /**
+     * 基本单位id
+     */
+    @JsonProperty("unit")
+    private String unit;
+
+    /**
+     * 辅助单位id
+     */
+    @JsonProperty("aux_unit")
+    private String auxUnit;
+
+    /**
+     * 标记
+     */
+    @JsonProperty("flag_id")
+    private String flagId;
+
+    /**
+     * 属性
+     */
+    @JsonProperty("properties")
+    private String properties;
+
+    /**
+     * 版本号,用来检查同时修改的
+     */
+    @JsonProperty("version_id")
+    private String versionId;
+
+    /**
+     * 最后修改时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("modified")
+    private String modified; // Keep as String for direct mapping
+
+    /**
+     * 创建时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("created")
+    private String created; // Keep as String for direct mapping
+
+    /**
+     * 基本单位名称
+     */
+    @JsonProperty("unit_name")
+    private String unitName;
+
+    /**
+     * 辅助单位名称
+     */
+    @JsonProperty("aux_unit_name")
+    private String auxUnitName;
+
+    /**
+     * 标记名称
+     */
+    @JsonProperty("flag_name")
+    private String flagName;
+
+    /**
+     * 创建时间 (ERP客户端需升级至V2.3.8.6及以上版本可获取此字段) 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("goods_created")
+    private String goodsCreated; // Keep as String
+
+    /**
+     * 最后修改时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("goods_modified")
+    private String goodsModified; // Keep as String
+
+    /**
+     * 是否已删除: 0:未删除 >0代表已删除
+     */
+    @JsonProperty("deleted")
+    private Integer deleted;
+
+    /**
+     * 单品节点列表 (SKU)
+     */
+    @JsonProperty("spec_list")
+    private List<ErpWdtSpecDto> specList;
+}

+ 408 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtSpecDto.java

@@ -0,0 +1,408 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 单品节点 (SKU) DTO
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtSpecDto {
+
+    /**
+     * 规格ID
+     */
+    @JsonProperty("spec_id")
+    private String specId;
+
+    /**
+     * 商家编码 (代表单品(SKU)所有属性的唯一编号)
+     */
+    @JsonProperty("spec_no")
+    private String specNo;
+
+    /**
+     * 规格码
+     */
+    @JsonProperty("spec_code")
+    private String specCode;
+
+    /**
+     * 主条码,单品下如果有多个条码,会随机返回其中一条条码
+     */
+    @JsonProperty("barcode")
+    private String barcode;
+
+    /**
+     * 规格名称
+     */
+    @JsonProperty("spec_name")
+    private String specName;
+
+    /**
+     * 货品ID
+     */
+    @JsonProperty("goods_id")
+    private Integer goodsId;
+
+    /**
+     * 最低价
+     */
+    @JsonProperty("lowest_price")
+    private BigDecimal lowestPrice;
+
+    /**
+     * 零售价
+     */
+    @JsonProperty("retail_price")
+    private BigDecimal retailPrice;
+
+    /**
+     * 批发价
+     */
+    @JsonProperty("wholesale_price")
+    private BigDecimal wholesalePrice;
+
+    /**
+     * 会员价
+     */
+    @JsonProperty("member_price")
+    private BigDecimal memberPrice;
+
+    /**
+     * 市场价
+     */
+    @JsonProperty("market_price")
+    private BigDecimal marketPrice;
+
+    /**
+     * 自定义价格1
+     */
+    @JsonProperty("custom_price1")
+    private BigDecimal customPrice1;
+
+    /**
+     * 自定义价格2
+     */
+    @JsonProperty("custom_price2")
+    private BigDecimal customPrice2;
+
+    /**
+     * 销售积分
+     */
+    @JsonProperty("sale_score")
+    private Integer saleScore;
+
+    /**
+     * 打包积分
+     */
+    @JsonProperty("pack_score")
+    private Integer packScore;
+
+    /**
+     * 拣货积分
+     */
+    @JsonProperty("pick_score")
+    private Integer pickScore;
+
+    /**
+     * 有效期天数 (保质期)
+     */
+    @JsonProperty("validity_days")
+    private Integer validityDays;
+
+    /**
+     * 最佳销售天数
+     */
+    @JsonProperty("sales_days")
+    private Integer salesDays;
+
+    /**
+     * 最佳收获天数
+     */
+    @JsonProperty("receive_days")
+    private Integer receiveDays;
+
+    /**
+     * 重量
+     */
+    @JsonProperty("weight")
+    private BigDecimal weight;
+
+    /**
+     * 长(CM)
+     */
+    @JsonProperty("length")
+    private BigDecimal length;
+
+    /**
+     * 宽(CM)
+     */
+    @JsonProperty("width")
+    private BigDecimal width;
+
+    /**
+     * 高(CM)
+     */
+    @JsonProperty("height")
+    private BigDecimal height;
+
+    /**
+     * 是否启用序列号 0不启用序列号 1强序列号 2弱序列号
+     */
+    @JsonProperty("is_sn_enable")
+    private Integer isSnEnable; // tinyint mapped to Integer
+
+    /**
+     * 是否允许负库存 0(不允许负库存);1(允许负库存)
+     */
+    @JsonProperty("is_allow_neg_stock")
+    private Integer isAllowNegStock; // tinyint mapped to Integer
+
+    /**
+     * 是否出库不验货 0(出库不验货);1(出库必须验货)
+     */
+    @JsonProperty("is_not_need_examine")
+    private Integer isNotNeedExamine; // tinyint mapped to Integer
+
+    /**
+     * 是否允许0成本 0(不允许0成本);1(允许0成本)
+     */
+    @JsonProperty("is_zero_cost")
+    private Integer isZeroCost; // tinyint mapped to Integer
+
+    /**
+     * 是否允许低于成本价 0(不允许低于成本价);1(允许低于成本价)
+     */
+    @JsonProperty("is_lower_cost")
+    private Integer isLowerCost; // tinyint mapped to Integer
+
+    /**
+     * 是否航空禁运 0(航空不禁运) 1(航空禁运)
+     */
+    @JsonProperty("is_not_use_air")
+    private Integer isNotUseAir; // tinyint mapped to Integer
+
+    /**
+     * 税率
+     */
+    @JsonProperty("tax_rate")
+    private BigDecimal taxRate;
+
+    /**
+     * 大件类别 0非大件1普通大件2独立大件
+     */
+    @JsonProperty("large_type")
+    private Integer largeType; // tinyint mapped to Integer
+
+    /**
+     * 备注
+     */
+    @JsonProperty("remark")
+    private String remark;
+
+    /**
+     * 创建时间 格式:YYYY-MM-DD HH:MM:SS
+     */
+    @JsonProperty("spec_created")
+    private String specCreated; // Keep as String
+
+    /**
+     * 最后修改时间 格式:YYYY-MM-DD HH:MM:SS
+     */
+    @JsonProperty("spec_modified")
+    private String specModified; // Keep as String
+
+    /**
+     * 自定义1
+     */
+    @JsonProperty("prop1")
+    private String prop1;
+
+    /**
+     * 自定义2
+     */
+    @JsonProperty("prop2")
+    private String prop2;
+
+    /**
+     * 自定义3
+     */
+    @JsonProperty("prop3")
+    private String prop3;
+
+    /**
+     * 自定义4
+     */
+    @JsonProperty("prop4")
+    private String prop4;
+
+    /**
+     * 自定义5
+     */
+    @JsonProperty("prop5")
+    private String prop5;
+
+    /**
+     * 自定义6
+     */
+    @JsonProperty("prop6")
+    private String prop6;
+
+    /**
+     * 图片url
+     */
+    @JsonProperty("img_url")
+    private String imgUrl;
+
+    /**
+     * 关联税务表税务编码
+     */
+    @JsonProperty("tax_code_id")
+    private String taxCodeId;
+
+    /**
+     * 是否启用同一批次出库 0,不使用同一批次,1,使用同一批次
+     */
+    @JsonProperty("is_single_batch")
+    private Integer isSingleBatch; // tinyint mapped to Integer
+
+    /**
+     * 水洗标
+     */
+    @JsonProperty("washing_label")
+    private String washingLabel;
+
+    /**
+     * 基本单位
+     */
+    @JsonProperty("unit")
+    private String unit;
+
+    /**
+     * 辅助单位
+     */
+    @JsonProperty("aux_unit")
+    private String auxUnit;
+
+    /**
+     * 标记
+     */
+    @JsonProperty("flag_id")
+    private String flagId;
+
+    /**
+     * 图片在外部空间的key 比如说 云盘的一个 外链
+     */
+    @JsonProperty("img_key")
+    private String imgKey;
+
+    /**
+     * 条码个数
+     */
+    @JsonProperty("barcode_count")
+    private Integer barcodeCount; // smallint mapped to Integer
+
+    /**
+     * 平台货品数量(不包含删除的)
+     */
+    @JsonProperty("plat_spec_count")
+    private Integer platSpecCount; // smallint mapped to Integer
+
+    /**
+     * sn自增数
+     */
+    @JsonProperty("postfix_val")
+    private String postfixVal;
+
+    /**
+     * 最后日期 格式:yyyy-MM-dd
+     */
+    @JsonProperty("last_date")
+    private String lastDate; // Keep as String (Date type)
+
+    /**
+     * 补货方式 0持续补货 1不补货 2低于警戒库存补货
+     */
+    @JsonProperty("replenish_type")
+    private Integer replenishType;
+
+    /**
+     * 是否畅销 0非畅销 1畅销
+     */
+    @JsonProperty("is_popular")
+    private Integer isPopular;
+
+    /**
+     * 备注换货匹配码
+     */
+    @JsonProperty("replace_no")
+    private String replaceNo;
+
+    /**
+     * 单品标记二进制位 1同款备注换货虚拟规格 2是否在备注换货界面展示 4递交自动生成货品
+     */
+    @JsonProperty("spec_mask")
+    private String specMask;
+
+    /**
+     * 同款备注换货--虚拟货品换货比例
+     */
+    @JsonProperty("replace_proportion")
+    private String replaceProportion;
+
+    /**
+     * 扩展字段
+     */
+    @JsonProperty("extra_3")
+    private String extra3;
+
+    /**
+     * 税务编码
+     */
+    @JsonProperty("tax_code")
+    private String taxCode;
+
+    /**
+     * 最后修改时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("modified")
+    private String modified; // Keep as String
+
+    /**
+     * 创建时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("created")
+    private String created; // Keep as String
+
+    /**
+     * 基本单位名称
+     */
+    @JsonProperty("spec_unit_name")
+    private String specUnitName;
+
+    /**
+     * 辅助单位名称
+     */
+    @JsonProperty("spec_aux_unit_name")
+    private String specAuxUnitName;
+
+    /**
+     * 是否已删除:0:未删除 >0代表已删除
+     */
+    @JsonProperty("deleted")
+    private Integer deleted;
+
+    /**
+     * 条码列表
+     */
+    @JsonProperty("barcode_list")
+    private List<ErpWdtBarcodeDto> barcodeList;
+}

+ 19 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockDTO.java

@@ -0,0 +1,19 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+@Data
+public class ErpWdtStockDTO {
+    /**
+     * sku
+     */
+    private String sepc_no;
+    /**
+     * 库存量
+     */
+    private String stock_num;
+    /**
+     * 可用库存量
+     */
+    private String avaliable_num;
+}

+ 37 - 0
fs-service-system/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockRespDTO.java

@@ -0,0 +1,37 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class ErpWdtStockRespDTO implements Serializable {
+    /**
+     * 错误码,状态码:0表示成功,其他表示失败
+     */
+    @JsonProperty("code")
+    @NotNull
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    @JsonProperty("message")
+    @NotNull
+    private String message;
+
+    /**
+     * 数据条数,只有,page_no = 0 时才返回的符合条件的数据总条数,用来分页
+     */
+    @JsonProperty("total_count")
+    private Integer totalCount;
+
+    /**
+     * 订单列表节点,响应参数的1级数据节点,包含当前页的订单及其明细的数据节点
+     */
+    @JsonProperty("stocks")
+    private List<ErpWdtStockDTO> stocks;
+}

+ 120 - 0
fs-service-system/src/main/java/com/fs/erp/service/impl/WdtErpGoodsServiceImpl.java

@@ -0,0 +1,120 @@
+package com.fs.erp.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.PropertyNamingStrategy;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.fs.erp.domain.ErpGoods;
+import com.fs.erp.domain.ErpGoodsStock;
+import com.fs.erp.dto.*;
+import com.fs.erp.dto.sdk.wangdian.api.WdtClient;
+import com.fs.erp.dto.wdt.*;
+import com.fs.erp.service.IErpGoodsService;
+import com.hc.openapi.tool.util.ObjectUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+@Primary
+public class WdtErpGoodsServiceImpl implements IErpGoodsService {
+    @Autowired
+    private WdtClient client;
+
+    @Override
+    public BaseResponse addGoods(ErpGoods goods) {
+        return null;
+    }
+
+    @Override
+    public ErpGoodsQueryResponse getGoods(ErpGoodsQueryRequert param) {
+        Map<String,String> map = new HashMap<>();
+        map.put("spec_no",param.getCode());
+        Asserts.notBlank(param.getCode(),"barcode不能为空!");
+
+        try {
+            String response = client.execute("goods_query.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtBaseResponseDTO erpWdtBaseResponseDTO =
+                    JSON.parseObject(response, ErpWdtBaseResponseDTO.class, config);
+            if(ObjectUtils.equals(0, erpWdtBaseResponseDTO.getCode())){
+                List<ErpGoods> list = new ArrayList<>();
+
+                List<ErpWdtGoodsDto> goodsList = erpWdtBaseResponseDTO.getGoodsList();
+                for (ErpWdtGoodsDto goodsDto : goodsList) {
+                    ErpGoods erpGoods = new ErpGoods();
+                    erpGoods.setCode(param.getCode());
+                    erpGoods.setName(goodsDto.getGoodsName());
+                    erpGoods.setSimple_name(goodsDto.getShortName());
+                    erpGoods.setCategory_code(String.valueOf(goodsDto.getGoodsType()));
+                    List<ErpWdtSpecDto> specList = goodsDto.getSpecList();
+                    ErpWdtSpecDto erpWdtSpecDto = specList.get(0);
+
+                    // 市场价
+                    erpGoods.setCost_price(erpWdtSpecDto.getMarketPrice());
+                    // 零售价
+                    erpGoods.setSales_price(erpWdtSpecDto.getRetailPrice());
+                    list.add(erpGoods);
+                }
+
+                ErpGoodsQueryResponse erpGoodsQueryResponse = new ErpGoodsQueryResponse();
+                erpGoodsQueryResponse.setItems(list);
+                return erpGoodsQueryResponse;
+            } else {
+                log.info("获取erp商品失败! 错误原因: {}", JSON.toJSONString(erpWdtBaseResponseDTO));
+                throw new RuntimeException(erpWdtBaseResponseDTO.getMessage());
+            }
+
+        } catch (IOException e) {
+            log.info("获取erp商品失败! 错误原因: {}", ExceptionUtils.getStackTrace(e));
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    @Override
+    public ErpGoodsStockQueryResponse getGoodsStock(ErpGoodsStockQueryRequert param) {
+        String barcode = param.getBarcode();
+        Asserts.notBlank(barcode,"barcode不能为空!");
+
+        Map<String,String> map = new HashMap<>();
+        map.put("spec_no",barcode);
+        try {
+            String response = client.execute("stock_query.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtStockRespDTO erpWdtStockRespDTO = JSON.parseObject(response, ErpWdtStockRespDTO.class,config);
+            List<ErpGoodsStock> list = new ArrayList<>();
+            if(ObjectUtils.equals(0,erpWdtStockRespDTO.getCode())){
+                List<ErpWdtStockDTO> stocks = erpWdtStockRespDTO.getStocks();
+                for (ErpWdtStockDTO stock : stocks) {
+                    ErpGoodsStock erpGoodsStock = new ErpGoodsStock();
+                    erpGoodsStock.setBarcode(barcode);
+                    erpGoodsStock.setQty(stock.getStock_num());
+                    erpGoodsStock.setSalable_qty(stock.getAvaliable_num());
+                    list.add(erpGoodsStock);
+                }
+            } else {
+                log.info("获取erp库存失败! 错误原因: {}", JSON.toJSONString(erpWdtStockRespDTO));
+                throw new RuntimeException(erpWdtStockRespDTO.getMessage());
+            }
+            ErpGoodsStockQueryResponse erpGoodsStockQueryResponse = new ErpGoodsStockQueryResponse();
+            erpGoodsStockQueryResponse.setStocks(list);
+            return erpGoodsStockQueryResponse;
+        } catch (IOException e) {
+            log.info("获取erp库存失败! 错误原因: {}", ExceptionUtils.getStackTrace(e));
+            throw new RuntimeException(e);
+        }
+    }
+}
+

+ 2 - 0
fs-service-system/src/main/java/com/fs/his/param/WxSendRedPacketParam.java

@@ -14,5 +14,7 @@ public class WxSendRedPacketParam implements Serializable {
 
     private Long companyId;
 
+    private Integer source=1;//来源 1:h5  2:看课小程序
+
 
 }

+ 5 - 0
fs-service-system/src/main/java/com/fs/qw/param/QwAutoTagsRulesTags.java

@@ -2,14 +2,19 @@ package com.fs.qw.param;
 
 import lombok.Data;
 
+import java.time.LocalDate;
 import java.util.List;
 
 @Data
 public class QwAutoTagsRulesTags {
     private List<String> tags;
+    private List<LocalDate> date;
+    private LocalDate startDate;
+    private LocalDate endDate;
     private List<Integer> week;
     private String startTime;
     private String endTime;
     private String remarks;
     private Integer isDay;
+    private Integer everyDay;
 }

Файловите разлики са ограничени, защото са твърде много
+ 229 - 226
fs-service-system/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java


+ 19 - 0
fs-service-system/src/main/java/com/fs/sop/domain/QwSop.java

@@ -1,5 +1,7 @@
 package com.fs.sop.domain;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import lombok.Data;
@@ -17,6 +19,7 @@ public class QwSop implements Serializable
 {
 
     /** id */
+    @TableId(type = IdType.UUID)
     private String id;
 
     /** 规则名称 */
@@ -91,4 +94,20 @@ public class QwSop implements Serializable
 
     private Integer courseDay;
 
+
+    // 是否固定营期
+    private Integer isFixed;
+    // 是否只发送注册用户
+    private Integer isRegister;
+    // 进入营期打标签开始时间
+    private Integer startDayNum;
+    // 进入营期打标签结束时间
+    private Integer endDayNum;
+    // 添加的标签
+    private String addTags;
+    // 第几天开始发课
+    private Integer courseDateNum;
+    // 新课对话模板
+    private String newTemplateId;
+
 }

+ 3 - 0
fs-service-system/src/main/java/com/fs/sop/mapper/QwSopMapper.java

@@ -360,4 +360,7 @@ public interface QwSopMapper extends BaseMapper<QwSop> {
     @DataSource(DataSourceType.SOP)
     @Select("select * FROM qw_sop where is_rating = 1 and send_type in(2,3) and min_conversion_day is not null and max_conversion_day is not null order by create_time desc")
     List<QwSop> selectQwSopByIsRatingNotNull();
+
+
+
 }

+ 7 - 3
fs-service-system/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java

@@ -1,7 +1,9 @@
 package com.fs.sop.service.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.common.annotation.DataSource;
 import com.fs.common.core.domain.R;
+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;
@@ -149,12 +151,13 @@ public class QwSopServiceImpl implements IQwSopService
      * @return 结果
      */
     @Override
+    @DataSource(DataSourceType.SOP)
     public int insertQwSop(QwSop qwSop)
     {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         qwSop.setCreateTime(sdf.format(new Date()));
 
-        return qwSopMapper.insertQwSop(qwSop);
+        return qwSopMapper.insert(qwSop);
     }
 
     /**
@@ -164,13 +167,14 @@ public class QwSopServiceImpl implements IQwSopService
      * @return 结果
      */
     @Override
+    @DataSource(DataSourceType.SOP)
     public R updateQwSop(QwSop qwSop)
     {
 
         try {
 
             if (qwSop.getExpiryTime()!=null||qwSop.getIsRating()!=null){
-                qwSopMapper.updateQwSop(qwSop);
+                qwSopMapper.updateById(qwSop);
                 return R.ok("修改成功");
             }
 
@@ -178,7 +182,7 @@ public class QwSopServiceImpl implements IQwSopService
                 return R.error("sop编号或模板编号不能为空");
             }
 
-            int i = qwSopMapper.updateQwSop(qwSop);
+            int i = qwSopMapper.updateById(qwSop);
             if (i > 0) {
 
                     try {

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

@@ -29,4 +29,14 @@ public class SopUserLogsVo  {
      */
     private Integer status;
 
+    /**
+     * 销售二级域名
+     */
+    private String domain;
+
+    // 是否固定营期
+    private Integer isFixed;
+    // 是否只发送注册用户
+    private Integer isRegister;
+
 }

+ 10 - 0
fs-service-system/src/main/java/com/fs/store/domain/FsUser.java

@@ -137,6 +137,16 @@ public class FsUser extends BaseEntity
 
     private Integer isShow;//是否展示购买以及订单状态
 
+    private String courseMaOpenId;//看课小程序openId
+
+    public String getCourseMaOpenId() {
+        return courseMaOpenId;
+    }
+
+    public void setCourseMaOpenId(String courseMaOpenId) {
+        this.courseMaOpenId = courseMaOpenId;
+    }
+
     public Integer getIsAddQw() {
         return isAddQw;
     }

+ 8 - 0
fs-service-system/src/main/java/com/fs/store/service/IFsStorePaymentService.java

@@ -13,6 +13,8 @@ import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.store.vo.FsStorePaymentStatisticsVO;
 import com.fs.store.vo.FsStorePaymentVO;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * 支付明细Service接口
  *
@@ -100,4 +102,10 @@ public interface IFsStorePaymentService
     FsStorePayment selectFsStorePaymentByTradeNo(String tradeNo);
 
     R sendRedPacket(WxSendRedPacketParam param);
+
+    R sendRedPacketV3(WxSendRedPacketParam param);
+
+    String transferNotify(String notifyData, HttpServletRequest request);
+
+    String v3TransferNotify(String notifyData, HttpServletRequest request);
 }

+ 7 - 4
fs-service-system/src/main/java/com/fs/store/service/impl/FsStoreCartServiceImpl.java

@@ -22,6 +22,7 @@ import com.fs.store.param.FsStoreCartDelParam;
 import com.fs.store.param.FsStoreCartNumParam;
 import com.fs.store.param.FsStoreCartParam;
 import com.fs.store.vo.FsStoreCartVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.store.domain.FsStoreCart;
@@ -34,6 +35,7 @@ import com.fs.store.service.IFsStoreCartService;
  * @date 2022-03-21
  */
 @Service
+@Slf4j
 public class FsStoreCartServiceImpl implements IFsStoreCartService
 {
     @Autowired
@@ -135,7 +137,7 @@ public class FsStoreCartServiceImpl implements IFsStoreCartService
                     .isBuy(cartParam.getIsBuy())
                     .build();
             storeCart.setCreateTime(new Date());
-//            checkProductStock(cartParam.getProductId(),storeCart.getProductAttrValueId());
+            checkProductStock(cartParam.getProductId(),storeCart.getProductAttrValueId());
             fsStoreCartMapper.insertFsStoreCart(storeCart);
             return R.ok().put("id",storeCart.getId());
 
@@ -161,7 +163,7 @@ public class FsStoreCartServiceImpl implements IFsStoreCartService
                         .isBuy(0)
                         .build();
                 storeCart.setCreateTime(new Date());
-//                checkProductStock(cartParam.getProductId(),storeCart.getProductAttrValueId());
+                checkProductStock(cartParam.getProductId(),storeCart.getProductAttrValueId());
                 fsStoreCartMapper.insertFsStoreCart(storeCart);
                 return R.ok().put("id",storeCart.getId());
             }
@@ -169,7 +171,7 @@ public class FsStoreCartServiceImpl implements IFsStoreCartService
                 storeCart=cart.get(0);
                 storeCart.setCartNum(cartParam.getCartNum() + cart.get(0).getCartNum());
                 storeCart.setUpdateTime(new Date());
-//                checkProductStock(cartParam.getProductId(),storeCart.getProductAttrValueId());
+                checkProductStock(cartParam.getProductId(),storeCart.getProductAttrValueId());
                 fsStoreCartMapper.updateFsStoreCart(storeCart);
                 return R.ok().put("id",storeCart.getId());
             }
@@ -191,7 +193,7 @@ public class FsStoreCartServiceImpl implements IFsStoreCartService
     @Override
     public R changeNum(long userId, FsStoreCartNumParam cartParam) {
         FsStoreCart cart=fsStoreCartMapper.selectFsStoreCartById(cartParam.getId());
-//        checkProductStock(cart.getProductId(),cart.getProductAttrValueId());
+        checkProductStock(cart.getProductId(),cart.getProductAttrValueId());
         cart.setCartNum(cartParam.getNumber());
         cart.setUpdateTime(new Date());
         fsStoreCartMapper.updateFsStoreCart(cart);
@@ -200,6 +202,7 @@ public class FsStoreCartServiceImpl implements IFsStoreCartService
 
     @Override
     public void checkProductStock(Long productId, Long productAttrValueId) {
+        log.info("检查库存 {} {}",productId,productAttrValueId);
         FsStoreProductAttrValue productAttrValue=valueMapper.selectFsStoreProductAttrValueById(productAttrValueId);
         if(StringUtils.isEmpty(productAttrValue.getGroupBarCode())){
             //单品

+ 143 - 3
fs-service-system/src/main/java/com/fs/store/service/impl/FsStorePaymentServiceImpl.java

@@ -19,6 +19,7 @@ import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.course.config.RedPacketConfig;
+import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.pay.pay.config.PayConfig;
 import com.fs.pay.pay.domain.CreateWxOrderResult;
 import com.fs.pay.pay.dto.WxJspayDTO;
@@ -38,14 +39,18 @@ import com.fs.pay.service.IPayService;
 import com.fs.pay.service.dto.CreatePayDTO;
 import com.fs.pay.service.dto.PayDTO;
 import com.fs.pay.service.dto.TradeOrder;
+import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
+import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
+import com.github.binarywang.wxpay.bean.notify.WxPayTransferBatchesNotifyV3Result;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
-import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
-import com.github.binarywang.wxpay.bean.transfer.TransferBatchesResult;
+import com.github.binarywang.wxpay.bean.transfer.*;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.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;
@@ -54,6 +59,8 @@ import com.fs.store.domain.FsStorePayment;
 import com.fs.store.service.IFsStorePaymentService;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * 支付明细Service业务层处理
  *
@@ -63,7 +70,7 @@ import org.springframework.transaction.annotation.Transactional;
 @Service
 public class FsStorePaymentServiceImpl implements IFsStorePaymentService
 {
-
+    Logger logger = LoggerFactory.getLogger(getClass());
     @Autowired
     private WxMaProperties properties;
     @Autowired
@@ -85,6 +92,9 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService
     PayService ybPayService;
     @Autowired
     private ISysConfigService configService;
+
+    @Autowired
+    private IFsCourseRedPacketLogService redPacketLogService;
     /**
      * 查询支付明细
      *
@@ -384,4 +394,134 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService
             return R.error("发送失败");
         }
     }
+
+
+    @Override
+    public String transferNotify(String notifyData, HttpServletRequest request) {
+        logger.info("zyp \n【收到转账回调】:{}",notifyData);
+        try {
+            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);
+            SignatureHeader signatureHeader = new SignatureHeader();
+            signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
+            signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
+            signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
+            signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
+            WxPayTransferBatchesNotifyV3Result result = wxPayService.parseTransferBatchesNotifyV3Result(notifyData,signatureHeader);
+            logger.info("到零钱回调:{}",result.getResult());
+            if (result.getResult().getBatchStatus().equals("FINISHED")) {
+                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBatchNo());
+                logger.info("result:{}",r);
+                if (r.get("code").equals(200)){
+                    return WxPayNotifyResponse.success("处理成功");
+                }else {
+                    return WxPayNotifyResponse.fail("");
+                }
+            }else {
+                return WxPayNotifyResponse.fail("");
+            }
+        } catch (WxPayException e) {
+            logger.error("zyp \n【转账回调异常】:{}", e.getReturnMsg());
+            return WxPayNotifyResponse.fail(e.getMessage());
+        }
+    }
+
+    @Override
+    public R sendRedPacketV3(WxSendRedPacketParam param) {
+        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();
+
+        //商家转账请求
+        TransferBillsRequest request = new TransferBillsRequest();
+        request.setAppid(config.getAppId());
+        request.setOpenid(param.getOpenId());
+
+//        String code =  OrderCodeUtils.getH5RedPacketOrderSn();
+//        if(StringUtils.isEmpty(code)){
+//            return R.error("订单生成失败,请重试");
+//        }
+        String code = String.valueOf(IdUtil.getSnowflake(0, 0).nextId());
+        request.setOutBillNo("fsCourse"+code);
+        //转账金额
+        Integer amount = WxPayUnifiedOrderRequest.yuanToFen(param.getAmount()!=null ? param.getAmount().toString() : "0.1");
+        request.setTransferAmount(amount);
+        request.setTransferRemark("活动奖励");
+        //用户感知
+        request.setUserRecvPerception("活动奖励");
+        request.setNotifyUrl(config.getNotifyUrl());
+        request.setTransferSceneId("1000");
+        List<TransferBillsRequest.TransferSceneReportInfo> transferSceneReportInfos = new ArrayList<>();
+        // 添加第一条数据
+        TransferBillsRequest.TransferSceneReportInfo info1 = new TransferBillsRequest.TransferSceneReportInfo();
+        info1.setInfoType("活动名称");
+        info1.setInfoContent("新会员有礼");
+        transferSceneReportInfos.add(info1);
+
+        // 添加第二条数据
+        TransferBillsRequest.TransferSceneReportInfo info2 = new TransferBillsRequest.TransferSceneReportInfo();
+        info2.setInfoType("奖励说明");
+        info2.setInfoContent("注册会员抽奖一等奖");
+        transferSceneReportInfos.add(info2);
+        request.setTransferSceneReportInfos(transferSceneReportInfos);
+
+        //发起商家转账API(新)
+        TransferBillsResult transferBillsResult=null;
+        try {
+            transferBillsResult = transferService.transferBills(request);
+            logger.info("商家转账支付完成:[msg:{}]",transferBillsResult);
+            return R.ok("发送红包成功").put("data",transferBillsResult);
+        } catch (WxPayException e) {
+            e.printStackTrace();
+            logger.info("商家转账支付失败:[msg:{}]",e.getMessage());
+            return R.error("发送失败");
+        }
+    }
+
+
+    @Override
+    public String v3TransferNotify(String notifyData, HttpServletRequest request) {
+        logger.info("zyp \n【收到转账回调】:{}",notifyData);
+        try {
+            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);
+            SignatureHeader signatureHeader = new SignatureHeader();
+            signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
+            signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
+            signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
+            signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
+            TransferBillsNotifyResult result = wxPayService.parseTransferBillsNotifyV3Result(notifyData,signatureHeader);
+            logger.info("到零钱回调:{}",result.getResult());
+            if (result.getResult().getState().equals("SUCCESS")) {
+                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBillNo());
+                logger.info("result:{}",r);
+                if (r.get("code").equals(200)){
+                    return WxPayNotifyResponse.success("处理成功");
+                }else {
+                    return WxPayNotifyResponse.fail("");
+                }
+            }else {
+                return WxPayNotifyResponse.fail("");
+            }
+        } catch (WxPayException e) {
+            logger.error("zyp \n【转账回调异常】:{}", e.getReturnMsg());
+            return WxPayNotifyResponse.fail(e.getMessage());
+        }
+    }
 }

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

@@ -328,6 +328,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         and b.voice_print_url is not null
     </select>
 
+    <select id="selectCompanyUserByIds" resultType="com.fs.company.domain.CompanyUser">
+        select cu.*
+        from company_user cu
+        where cu.user_id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+
+    </select>
+
 
     <resultMap type="com.fs.company.vo.CompanyUserVO" id="CompanyUserVOResult">
         <result property="userId"    column="user_id"    />

+ 1 - 1
fs-service-system/src/main/resources/mapper/sop/SopUserLogsMapper.xml

@@ -158,7 +158,7 @@
 
 
     <select id="selectSopUserLogsListByTime" resultType="com.fs.sop.vo.SopUserLogsVo">
-        select a.*,b.min_conversion_day,b.max_conversion_day,b.min_send,b.max_send from sop_user_logs a
+        select a.*,b.min_conversion_day,b.max_conversion_day,b.min_send,b.max_send,b.is_fixed,b.is_register from sop_user_logs a
         inner join qw_sop b on a.sop_id = b.id
         where a.start_time &lt;= Now() and a.status = 1 and b.send_type != 4 and b.status in (2,3)
     </select>

Някои файлове не бяха показани, защото твърде много файлове са промени