Parcourir la source

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

caoliqin il y a 1 jour
Parent
commit
d46a37d29e
62 fichiers modifiés avec 1826 ajouts et 169 suppressions
  1. 5 3
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  2. 5 2
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  3. 5 2
      fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactTransferCompanyAuditController.java
  4. 103 0
      fs-admin/src/main/java/com/fs/qw/controller/QwUserComplainRecordController.java
  5. 7 2
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  6. 27 0
      fs-admin/src/main/java/com/fs/task/SgTestController.java
  7. 27 0
      fs-admin/src/main/java/com/fs/task/SyncTuLinStudentInfoTask.java
  8. 5 2
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferCompanyAuditController.java
  9. 35 2
      fs-qw-api/src/main/java/com/fs/app/controller/CommonController.java
  10. 46 0
      fs-qw-api/src/main/java/com/fs/app/controller/QwUserComplainRecordController.java
  11. 59 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCompanyUserQw.java
  12. 61 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCompanyUserQwMapper.java
  13. 2 2
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  14. 61 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserQwService.java
  15. 0 1
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseComplaintRecordService.java
  16. 94 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserQwServiceImpl.java
  17. 1 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseComplaintRecordServiceImpl.java
  18. 3 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java
  19. 12 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  20. 4 6
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  21. 21 1
      fs-service/src/main/java/com/fs/hisStore/param/FsUserEditParam.java
  22. 1 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java
  23. 6 0
      fs-service/src/main/java/com/fs/qw/domain/QwExternalContactTransferCompanyAuditUser.java
  24. 4 0
      fs-service/src/main/java/com/fs/qw/domain/QwExternalContactTransferLog.java
  25. 2 0
      fs-service/src/main/java/com/fs/qw/domain/QwUser.java
  26. 56 0
      fs-service/src/main/java/com/fs/qw/domain/QwUserComplainRecord.java
  27. 3 0
      fs-service/src/main/java/com/fs/qw/dto/CompanyTransferDTO.java
  28. 4 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferCompanyAuditMapper.java
  29. 6 1
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferCompanyAuditUserMapper.java
  30. 2 1
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferLogMapper.java
  31. 61 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserComplainRecordMapper.java
  32. 33 0
      fs-service/src/main/java/com/fs/qw/param/QwUserComplaintRecordParam.java
  33. 2 0
      fs-service/src/main/java/com/fs/qw/param/ResignedTransferParam.java
  34. 2 0
      fs-service/src/main/java/com/fs/qw/param/TransferParam.java
  35. 3 0
      fs-service/src/main/java/com/fs/qw/service/IQwExternalContactTransferCompanyAuditService.java
  36. 64 0
      fs-service/src/main/java/com/fs/qw/service/IQwUserComplainRecordService.java
  37. 37 7
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  38. 59 64
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactTransferCompanyAuditServiceImpl.java
  39. 187 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserComplainRecordServiceImpl.java
  40. 16 0
      fs-service/src/main/java/com/fs/qwApi/param/QwSendMsgParam.java
  41. 77 0
      fs-service/src/main/java/com/fs/tulin/entity/QwExUserInfo.java
  42. 4 5
      fs-service/src/main/java/com/fs/tulin/entity/StudentInfo.java
  43. 48 0
      fs-service/src/main/java/com/fs/tulin/entity/TulinInfoSyncLog.java
  44. 50 0
      fs-service/src/main/java/com/fs/tulin/mapper/TulinInfoSyncLogMapper.java
  45. 20 0
      fs-service/src/main/java/com/fs/tulin/service/ITulinInfoSyncLogService.java
  46. 95 0
      fs-service/src/main/java/com/fs/tulin/service/impl/TulinInfoSyncLogServiceImpl.java
  47. 36 0
      fs-service/src/main/java/com/fs/tulin/utils/ColumnNameEnum.java
  48. 1 1
      fs-service/src/main/java/com/fs/tulin/utils/JsonSortUtils.java
  49. 1 1
      fs-service/src/main/java/com/fs/tulin/utils/PharmacyEnum.java
  50. 26 59
      fs-service/src/main/java/com/fs/tulin/utils/SyncStudentInfoService.java
  51. 1 1
      fs-service/src/main/resources/application-druid-cqtyt.yml
  52. 2 0
      fs-service/src/main/resources/application-druid-qdtst-test.yml
  53. 5 0
      fs-service/src/main/resources/db/20251011-转接增加清空标签配置.sql
  54. 3 3
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  55. 116 0
      fs-service/src/main/resources/mapper/course/FsUserCompanyUserQwMapper.xml
  56. 9 0
      fs-service/src/main/resources/mapper/qw/QwExternalContactTransferCompanyAuditMapper.xml
  57. 11 0
      fs-service/src/main/resources/mapper/qw/QwExternalContactTransferCompanyAuditUserMapper.xml
  58. 5 1
      fs-service/src/main/resources/mapper/qw/QwExternalContactTransferLogMapper.xml
  59. 94 0
      fs-service/src/main/resources/mapper/qw/QwUserComplainRecordMapper.xml
  60. 82 0
      fs-service/src/main/resources/mapper/tulin/TulinInfoSyncLogMapper.xml
  61. 8 0
      fs-service/src/test/java/com/fs/his/service/impl/FsUserServiceImplTest.java
  62. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/store/UserScrmController.java

+ 5 - 3
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -122,6 +122,9 @@ public class FsStoreOrderController extends BaseController
 
     @Autowired
     private IFsStoreOrderLogsService fsStoreOrderLogsService;
+
+    @Autowired
+    private IFsDfAccountService fsDfAccountService;
     /**
      * 查询订单列表
      */
@@ -956,10 +959,9 @@ public class FsStoreOrderController extends BaseController
     {
         List<String> list = new ArrayList<>();
         if (CloudHostUtils.hasCloudHostName("金牛明医","康年堂")){
-            List<DFConfigVo> erpAccounts = fsStoreOrderService.getErpAccount();
-            list = erpAccounts.stream().map(DFConfigVo::getLoginAccount).collect(Collectors.toList());
+                List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
+                list = erpAccounts.stream().map(FsDfAccount::getLoginAccount).collect(Collectors.toList());
         }
-
         return R.ok().put("data", list);
     }
 }

+ 5 - 2
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -890,8 +890,11 @@ public class FsStoreOrderScrmController extends BaseController {
     @GetMapping("/getErpAccount")
     public R getErpAccount()
     {
-        List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
-        List<String> list = erpAccounts.stream().map(FsDfAccount::getLoginAccount).collect(Collectors.toList());
+        List<String> list = new ArrayList<>();
+        if (CloudHostUtils.hasCloudHostName("金牛明医","康年堂")) {
+            List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
+            list = erpAccounts.stream().map(FsDfAccount::getLoginAccount).collect(Collectors.toList());
+        }
         return R.ok().put("data", list);
     }
 

+ 5 - 2
fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactTransferCompanyAuditController.java

@@ -6,6 +6,7 @@ import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.qw.domain.QwExternalContactTransferCompanyAudit;
+import com.fs.qw.domain.QwExternalContactTransferCompanyAuditUser;
 import com.fs.qw.dto.CompanyTransferAuditDTO;
 import com.fs.qw.service.IQwExternalContactTransferCompanyAuditService;
 import com.fs.qw.service.IQwExternalContactTransferCompanyAuditUserService;
@@ -35,8 +36,10 @@ public class QwExternalContactTransferCompanyAuditController extends BaseControl
 
     @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:detail')")
     @GetMapping("/detail/{auditId}")
-    public AjaxResult detail(@PathVariable Long auditId) {
-        return AjaxResult.success(auditUserService.getListByAuditId(auditId));
+    public TableDataInfo detail(@PathVariable Long auditId) {
+        startPage();
+        List<QwExternalContactTransferCompanyAuditUser> listByAuditId = auditUserService.getListByAuditId(auditId);
+        return getDataTable(listByAuditId);
     }
 
     @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:audit')")

+ 103 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwUserComplainRecordController.java

@@ -0,0 +1,103 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.qw.domain.QwUserComplainRecord;
+import com.fs.qw.service.IQwUserComplainRecordService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 企微员工投诉记录Controller
+ *
+ * @author fs
+ * @date 2025-10-22
+ */
+@RestController
+@RequestMapping("/qw/record")
+public class QwUserComplainRecordController extends BaseController
+{
+    @Autowired
+    private IQwUserComplainRecordService qwUserComplainRecordService;
+
+    /**
+     * 查询企微员工投诉记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:record:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwUserComplainRecord qwUserComplainRecord)
+    {
+        startPage();
+        List<QwUserComplainRecord> list = qwUserComplainRecordService.selectQwUserComplainRecordList(qwUserComplainRecord);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企微员工投诉记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:record:export')")
+    @Log(title = "企微员工投诉记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwUserComplainRecord qwUserComplainRecord)
+    {
+        List<QwUserComplainRecord> list = qwUserComplainRecordService.selectQwUserComplainRecordList(qwUserComplainRecord);
+        ExcelUtil<QwUserComplainRecord> util = new ExcelUtil<QwUserComplainRecord>(QwUserComplainRecord.class);
+        return util.exportExcel(list, "企微员工投诉记录数据");
+    }
+
+    /**
+     * 获取企微员工投诉记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:record:query')")
+    @GetMapping(value = "/{recordId}")
+    public AjaxResult getInfo(@PathVariable("recordId") Long recordId)
+    {
+        return AjaxResult.success(qwUserComplainRecordService.selectQwUserComplainRecordByRecordId(recordId));
+    }
+
+    /**
+     * 新增企微员工投诉记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:record:add')")
+    @Log(title = "企微员工投诉记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwUserComplainRecord qwUserComplainRecord)
+    {
+        return toAjax(qwUserComplainRecordService.insertQwUserComplainRecord(qwUserComplainRecord));
+    }
+
+    /**
+     * 修改企微员工投诉记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:record:edit')")
+    @Log(title = "企微员工投诉记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwUserComplainRecord qwUserComplainRecord)
+    {
+        return toAjax(qwUserComplainRecordService.updateQwUserComplainRecord(qwUserComplainRecord));
+    }
+
+    /**
+     * 删除企微员工投诉记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:record:remove')")
+    @Log(title = "企微员工投诉记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{recordIds}")
+    public AjaxResult remove(@PathVariable Long[] recordIds)
+    {
+        return toAjax(qwUserComplainRecordService.deleteQwUserComplainRecordByRecordIds(recordIds));
+    }
+}

+ 7 - 2
fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java

@@ -3,12 +3,17 @@ package com.fs.qw.controller;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
+import com.fs.qw.domain.QwExternalContactTransferCompanyAudit;
 import com.fs.qw.param.QwFsUserParam;
+import com.fs.qw.service.IQwExternalContactTransferCompanyAuditService;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.QwOptionsVO;
 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.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
@@ -24,7 +29,8 @@ import java.util.List;
 public class QwUserController extends BaseController {
     @Autowired
     private IQwUserService qwUserService;
-
+    @Autowired
+    private IQwExternalContactTransferCompanyAuditService auditService;
     @GetMapping("/getQwUserAll")
     public AjaxResult getQwUserAll(){
         return AjaxResult.success(qwUserService.getQwUserAll());
@@ -38,7 +44,6 @@ public class QwUserController extends BaseController {
         return R.ok().put("data",qwUserService.getQwUserInfo(param));
     }
 
-
    @GetMapping("/getMyQwCompanyList")
     public R getMyQwCompanyList()
     {

+ 27 - 0
fs-admin/src/main/java/com/fs/task/SgTestController.java

@@ -0,0 +1,27 @@
+package com.fs.task;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/23 下午2:18
+ */
+@RestController
+@RequestMapping("/sg/test")
+public class SgTestController {
+
+    @Resource
+    private SyncTuLinStudentInfoTask syncTuLinStudentInfoTask;
+
+
+    @RequestMapping("/execute")
+    public void execute(){
+        syncTuLinStudentInfoTask.execute();
+    }
+
+
+}

+ 27 - 0
fs-admin/src/main/java/com/fs/task/SyncTuLinStudentInfoTask.java

@@ -0,0 +1,27 @@
+package com.fs.task;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fs.tulin.service.ITulinInfoSyncLogService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * @description: 同步TuLin学生信息定时任务
+ * @author: Guos
+ * @time: 2025/10/23 上午10:26
+ */
+@AllArgsConstructor
+@Component("syncTuLinStudentInfoTask")
+public class SyncTuLinStudentInfoTask {
+
+
+    @Resource
+    private final ITulinInfoSyncLogService tulinInfoSyncLogService;
+
+    public void execute() {
+        tulinInfoSyncLogService.syncInfo();
+    }
+
+}

+ 5 - 2
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferCompanyAuditController.java

@@ -10,6 +10,7 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwExternalContactTransferCompanyAudit;
+import com.fs.qw.domain.QwExternalContactTransferCompanyAuditUser;
 import com.fs.qw.service.IQwExternalContactTransferCompanyAuditService;
 import com.fs.qw.service.IQwExternalContactTransferCompanyAuditUserService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,7 +51,9 @@ public class QwExternalContactTransferCompanyAuditController extends BaseControl
 
     @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:detail')")
     @GetMapping("/detail/{auditId}")
-    public AjaxResult detail(@PathVariable Long auditId) {
-        return AjaxResult.success(auditUserService.getListByAuditId(auditId));
+    public TableDataInfo detail(@PathVariable Long auditId) {
+        startPage();
+        List<QwExternalContactTransferCompanyAuditUser> list = auditUserService.getListByAuditId(auditId);
+        return getDataTable(list);
     }
 }

+ 35 - 2
fs-qw-api/src/main/java/com/fs/app/controller/CommonController.java

@@ -1,8 +1,21 @@
 package com.fs.app.controller;
 
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.file.OssException;
+import com.fs.course.param.UserCourseComplaintRecordParam;
+import com.fs.course.service.IFsUserCourseComplaintTypeService;
+import com.fs.course.vo.FsUserCourseComplaintTypeListVO;
+import com.fs.qw.param.QwUserComplaintRecordParam;
+import com.fs.qw.service.IQwUserComplainRecordService;
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
 import io.swagger.annotations.Api;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
 
 
 @Api("公共接口")
@@ -10,6 +23,26 @@ import org.springframework.web.bind.annotation.RestController;
 @RequestMapping(value="/app/common")
 public class CommonController {
 
+    @Autowired
+    private IQwUserComplainRecordService qwUserComplainRecordService;
+
+    @Autowired
+    private IFsUserCourseComplaintTypeService fsUserCourseComplaintTypeService;
+
+    @PostMapping("uploadOSS")
+    public R uploadOSS(@RequestParam("file") MultipartFile file) throws Exception
+    {
 
+        if (file.isEmpty())
+        {
+            throw new OssException("上传文件不能为空");
+        }
+        // 上传文件
+        String fileName = file.getOriginalFilename();
+        String suffix = fileName.substring(fileName.lastIndexOf("."));
+        CloudStorageService storage = OSSFactory.build();
+        String url = storage.uploadSuffix(file.getBytes(), suffix);
+        return R.ok().put("url",url);
+    }
 
 }

+ 46 - 0
fs-qw-api/src/main/java/com/fs/app/controller/QwUserComplainRecordController.java

@@ -0,0 +1,46 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.course.service.IFsUserCourseComplaintTypeService;
+import com.fs.course.vo.FsUserCourseComplaintTypeListVO;
+import com.fs.qw.param.QwUserComplaintRecordParam;
+import com.fs.qw.service.IQwUserComplainRecordService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Api("企微员工投诉接口")
+@RestController
+@RequestMapping(value="/app/record")
+public class QwUserComplainRecordController {
+
+
+    @Autowired
+    private IQwUserComplainRecordService qwUserComplainRecordService;
+
+    @Autowired
+    private IFsUserCourseComplaintTypeService fsUserCourseComplaintTypeService;
+
+
+    @ApiOperation("获取投诉类型")
+    @GetMapping("/getTypeTree")
+    public R getTypeTree() {
+        List<FsUserCourseComplaintTypeListVO> allComplaintTypeTree = fsUserCourseComplaintTypeService.getAllComplaintTypeTree();
+        return R.ok().put("data", allComplaintTypeTree);
+    }
+
+
+    @ApiOperation("提交企微员工反馈记录")
+    @PostMapping("/recordByQwUser")
+    public R submitByQwUser(@RequestBody QwUserComplaintRecordParam param) {
+        int i = qwUserComplainRecordService.submitRecordByQwUser(param);
+        if (i > 0) {
+            return R.ok("提交成功");
+        } else {
+            return R.error("提交失败");
+        }
+    }
+}

+ 59 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCompanyUserQw.java

@@ -0,0 +1,59 @@
+package com.fs.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 微信用户和销售关系-企业微信自动的对象 fs_user_company_user_qw
+ *
+ * @author fs
+ * @date 2025-10-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserCompanyUserQw extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 用户id(关联fs_user表user_id) */
+    @Excel(name = "用户id", readConverterExp = "关=联fs_user表user_id")
+    private Long userId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 公司ID */
+    @Excel(name = "公司ID")
+    private Long companyId;
+
+    /** 是否重粉,1-是;0-否 */
+    @Excel(name = "是否重粉,1-是;0-否")
+    private Long isRepeatFans;
+
+    /** 课程项目ID */
+    @Excel(name = "课程项目ID")
+    private Long projectId;
+
+    /** 企微用户ID */
+    @Excel(name = "企微用户ID")
+    private Long qwUserId;
+
+    /** 企微外部联系人ID */
+    @Excel(name = "企微外部联系人ID")
+    private Long qwExternalContactId;
+
+    /** 企微主体ID */
+    @Excel(name = "企微主体ID")
+    private Long qwCompanyId;
+
+    /** 状态 0小黑屋 1正常 2拉黑 */
+    @Excel(name = "状态 0小黑屋 1正常 2拉黑")
+    private Long status;
+
+
+}

+ 61 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCompanyUserQwMapper.java

@@ -0,0 +1,61 @@
+package com.fs.course.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsUserCompanyUserQw;
+
+/**
+ * 微信用户和销售关系-企业微信自动的Mapper接口
+ * 
+ * @author fs
+ * @date 2025-10-23
+ */
+public interface FsUserCompanyUserQwMapper extends BaseMapper<FsUserCompanyUserQw>{
+    /**
+     * 查询微信用户和销售关系-企业微信自动的
+     * 
+     * @param id 微信用户和销售关系-企业微信自动的主键
+     * @return 微信用户和销售关系-企业微信自动的
+     */
+    FsUserCompanyUserQw selectFsUserCompanyUserQwById(Long id);
+
+    /**
+     * 查询微信用户和销售关系-企业微信自动的列表
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 微信用户和销售关系-企业微信自动的集合
+     */
+    List<FsUserCompanyUserQw> selectFsUserCompanyUserQwList(FsUserCompanyUserQw fsUserCompanyUserQw);
+
+    /**
+     * 新增微信用户和销售关系-企业微信自动的
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 结果
+     */
+    int insertFsUserCompanyUserQw(FsUserCompanyUserQw fsUserCompanyUserQw);
+
+    /**
+     * 修改微信用户和销售关系-企业微信自动的
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 结果
+     */
+    int updateFsUserCompanyUserQw(FsUserCompanyUserQw fsUserCompanyUserQw);
+
+    /**
+     * 删除微信用户和销售关系-企业微信自动的
+     * 
+     * @param id 微信用户和销售关系-企业微信自动的主键
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserQwById(Long id);
+
+    /**
+     * 批量删除微信用户和销售关系-企业微信自动的
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserQwByIds(Long[] ids);
+}

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

@@ -37,10 +37,10 @@ public class FsCourseWatchLogListParam implements Serializable {
     private Integer sendType;
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date eTime;
+    private String eTime;
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date sTime;
+    private String sTime;
 
     @JsonFormat(pattern = "yyyy-MM-dd")
     private String upSTime;

+ 61 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserQwService.java

@@ -0,0 +1,61 @@
+package com.fs.course.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.FsUserCompanyUserQw;
+
+/**
+ * 微信用户和销售关系-企业微信自动的Service接口
+ * 
+ * @author fs
+ * @date 2025-10-23
+ */
+public interface IFsUserCompanyUserQwService extends IService<FsUserCompanyUserQw>{
+    /**
+     * 查询微信用户和销售关系-企业微信自动的
+     * 
+     * @param id 微信用户和销售关系-企业微信自动的主键
+     * @return 微信用户和销售关系-企业微信自动的
+     */
+    FsUserCompanyUserQw selectFsUserCompanyUserQwById(Long id);
+
+    /**
+     * 查询微信用户和销售关系-企业微信自动的列表
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 微信用户和销售关系-企业微信自动的集合
+     */
+    List<FsUserCompanyUserQw> selectFsUserCompanyUserQwList(FsUserCompanyUserQw fsUserCompanyUserQw);
+
+    /**
+     * 新增微信用户和销售关系-企业微信自动的
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 结果
+     */
+    int insertFsUserCompanyUserQw(FsUserCompanyUserQw fsUserCompanyUserQw);
+
+    /**
+     * 修改微信用户和销售关系-企业微信自动的
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 结果
+     */
+    int updateFsUserCompanyUserQw(FsUserCompanyUserQw fsUserCompanyUserQw);
+
+    /**
+     * 批量删除微信用户和销售关系-企业微信自动的
+     * 
+     * @param ids 需要删除的微信用户和销售关系-企业微信自动的主键集合
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserQwByIds(Long[] ids);
+
+    /**
+     * 删除微信用户和销售关系-企业微信自动的信息
+     * 
+     * @param id 微信用户和销售关系-企业微信自动的主键
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserQwById(Long id);
+}

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

@@ -70,5 +70,4 @@ public interface IFsUserCourseComplaintRecordService extends IService<FsUserCour
      * @return int
      */
     int submitRecord(UserCourseComplaintRecordParam userCourseComplaintRecordParam);
-
 }

+ 94 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserQwServiceImpl.java

@@ -0,0 +1,94 @@
+package com.fs.course.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.course.mapper.FsUserCompanyUserQwMapper;
+import com.fs.course.domain.FsUserCompanyUserQw;
+import com.fs.course.service.IFsUserCompanyUserQwService;
+
+/**
+ * 微信用户和销售关系-企业微信自动的Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-10-23
+ */
+@Service
+public class FsUserCompanyUserQwServiceImpl extends ServiceImpl<FsUserCompanyUserQwMapper, FsUserCompanyUserQw> implements IFsUserCompanyUserQwService {
+
+    /**
+     * 查询微信用户和销售关系-企业微信自动的
+     * 
+     * @param id 微信用户和销售关系-企业微信自动的主键
+     * @return 微信用户和销售关系-企业微信自动的
+     */
+    @Override
+    public FsUserCompanyUserQw selectFsUserCompanyUserQwById(Long id)
+    {
+        return baseMapper.selectFsUserCompanyUserQwById(id);
+    }
+
+    /**
+     * 查询微信用户和销售关系-企业微信自动的列表
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 微信用户和销售关系-企业微信自动的
+     */
+    @Override
+    public List<FsUserCompanyUserQw> selectFsUserCompanyUserQwList(FsUserCompanyUserQw fsUserCompanyUserQw)
+    {
+        return baseMapper.selectFsUserCompanyUserQwList(fsUserCompanyUserQw);
+    }
+
+    /**
+     * 新增微信用户和销售关系-企业微信自动的
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 结果
+     */
+    @Override
+    public int insertFsUserCompanyUserQw(FsUserCompanyUserQw fsUserCompanyUserQw)
+    {
+        fsUserCompanyUserQw.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsUserCompanyUserQw(fsUserCompanyUserQw);
+    }
+
+    /**
+     * 修改微信用户和销售关系-企业微信自动的
+     * 
+     * @param fsUserCompanyUserQw 微信用户和销售关系-企业微信自动的
+     * @return 结果
+     */
+    @Override
+    public int updateFsUserCompanyUserQw(FsUserCompanyUserQw fsUserCompanyUserQw)
+    {
+        fsUserCompanyUserQw.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsUserCompanyUserQw(fsUserCompanyUserQw);
+    }
+
+    /**
+     * 批量删除微信用户和销售关系-企业微信自动的
+     * 
+     * @param ids 需要删除的微信用户和销售关系-企业微信自动的主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserCompanyUserQwByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsUserCompanyUserQwByIds(ids);
+    }
+
+    /**
+     * 删除微信用户和销售关系-企业微信自动的信息
+     * 
+     * @param id 微信用户和销售关系-企业微信自动的主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserCompanyUserQwById(Long id)
+    {
+        return baseMapper.deleteFsUserCompanyUserQwById(id);
+    }
+}

+ 1 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseComplaintRecordServiceImpl.java

@@ -135,4 +135,5 @@ public class FsUserCourseComplaintRecordServiceImpl extends ServiceImpl<FsUserCo
         fsUserCourseComplaintRecord.setCreateTime(DateUtils.getNowDate());
         return baseMapper.insertFsUserCourseComplaintRecord(fsUserCourseComplaintRecord);
     }
+
 }

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

@@ -63,6 +63,9 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @Excel(name = "记录类型" ,dictType = "sys_course_watch_log_type")
     private Integer logType;
 
+    @Excel(name = "奖励类型 1红包 2积分")
+    private Integer rewardType;
+
 //    @Excel(name = "企微外部联系人id")
     private String qwExternalContactId;
 

+ 12 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -3897,6 +3897,18 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                     failureMsg.append(msg).append("该状态不支持修改为待推送");
                     continue;
                 }
+                if ("-1".equals(vo.getStatus())) {
+                    failureNum++;
+                    String msg = "<br/>" + failureNum + "、订单编号 " + vo.getOrderCode() + " 导入失败:";
+                    failureMsg.append(msg).append("该状态不支持修改为退款中,需要手动申请退款");
+                    continue;
+                }
+                if ("-2".equals(vo.getStatus())) {
+                    failureNum++;
+                    String msg = "<br/>" + failureNum + "、订单编号 " + vo.getOrderCode() + " 导入失败:";
+                    failureMsg.append(msg).append("该状态不支持修改为退款中,需要审核完成退款");
+                    continue;
+                }
 
                 Integer status = o.getStatus();
 

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

@@ -1446,15 +1446,13 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         }
         byte[] file;
         try {
-            file = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes(
-                    scene,
-                    "pages_user/user/pay",
-                    true,
+            file = wxMaService.getQrcodeService().createWxaCodeBytes(
+                    "pages_user/user/pay?companyId="+param.getCompanyId(),
                     "release",
                     430,
                     true,
                     null,
-                    false);
+                    true);
 
             // 上传图片到存储桶
             String suffix = ".png";
@@ -1575,7 +1573,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         storePayment.setPayMoney(param.getPayMoney());
         storePayment.setCreateTime(new Date());
         storePayment.setPayTypeCode("weixin");
-        storePayment.setBusinessType(1);
+        storePayment.setBusinessType(7);//微信收款
         storePayment.setRemark("商城收款订单支付");
         storePayment.setOpenId(openId);
         storePayment.setUserId(user.getUserId());

+ 21 - 1
fs-service/src/main/java/com/fs/hisStore/param/FsUserEditParam.java

@@ -11,11 +11,31 @@ public class FsUserEditParam implements Serializable
 
     @NotNull(message = "用户昵称不能为空!")
     private String nickname;
+    // 兼容前端 因为大小写传值问题 先取nickName再取nickname
+    private String nickName;
 
 //    @NotBlank(message = "用户头像不能为空!")
     private String avatar;
 
     private Long userId;
 
-
+    // 添加兼容方法
+    public String getNickName() {
+        return this.nickName != null ? this.nickName : this.nickname;
+    }
+
+    public String getNickname() {
+        return this.nickname != null ? this.nickname : this.nickName;
+    }
+
+    // 也可以统一设置器
+    public void setNickName(String nickName) {
+        this.nickName = nickName;
+        this.nickname = nickName;
+    }
+
+    public void setNickname(String nickname) {
+        this.nickname = nickname;
+        this.nickName = nickname;
+    }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java

@@ -878,7 +878,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         storePayment.setPayMoney(param.getPayMoney());
         storePayment.setCreateTime(new Date());
         storePayment.setPayTypeCode("weixin");
-        storePayment.setBusinessType(1);
+        storePayment.setBusinessType(7);//微信收款
         storePayment.setRemark("商城收款订单支付");
         storePayment.setOpenId(user.getMaOpenId());
         storePayment.setUserId(user.getUserId());

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

@@ -1,5 +1,7 @@
 package com.fs.qw.domain;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -11,6 +13,7 @@ import java.time.LocalDateTime;
 public class QwExternalContactTransferCompanyAuditUser {
 
     @ApiModelProperty("主键ID")
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     @ApiModelProperty("审核记录ID")
@@ -57,4 +60,7 @@ public class QwExternalContactTransferCompanyAuditUser {
 
     @ApiModelProperty("接替时间")
     private LocalDateTime replaceTime;
+
+    @ApiModelProperty("是否需要清除标签")
+    private Integer needClearTag;
 }

+ 4 - 0
fs-service/src/main/java/com/fs/qw/domain/QwExternalContactTransferLog.java

@@ -60,4 +60,8 @@ public class QwExternalContactTransferLog
     private Long qwUserId;
     private Long handoverQwUserId;
     private Long fsUserId;
+    /**
+     * 是否需要清除标签
+     */
+    private Integer needClearTag;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/qw/domain/QwUser.java

@@ -1,6 +1,7 @@
 package com.fs.qw.domain;
 
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
@@ -110,5 +111,6 @@ public class QwUser extends BaseEntity
     private String isAuto;
     private Integer videoGetStatus;
 
+    @TableField(exist = false)
     private Integer disableCompanyId;
 }

+ 56 - 0
fs-service/src/main/java/com/fs/qw/domain/QwUserComplainRecord.java

@@ -0,0 +1,56 @@
+package com.fs.qw.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 企微员工投诉记录对象 qw_user_complain_record
+ *
+ * @author fs
+ * @date 2025-10-22
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class QwUserComplainRecord extends BaseEntity{
+
+    /** 投诉记录id */
+    @TableId(type = IdType.AUTO)
+    private Long recordId;
+
+    /** 用户手机号 */
+    @Excel(name = "用户手机号")
+    private String phone;
+
+    /** 投诉类型id */
+    @Excel(name = "投诉类型id")
+    private Long complaintTypeId;
+
+    /** 投诉内容 */
+    @Excel(name = "投诉内容")
+    private String complaintContent;
+
+    /** 投诉上传图片 */
+    @Excel(name = "投诉上传图片")
+    private String complaintUrl;
+
+    /** 企微员工id */
+    @Excel(name = "企微员工id")
+    private Long qwUserId;
+
+    /** 外部联系人id */
+    @Excel(name = "外部联系人id")
+    private Long extId;
+
+    /** fs_user_id */
+    @Excel(name = "fs_user_id")
+    private Long userId;
+
+    //位置
+    private String position;
+
+
+}

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

@@ -29,4 +29,7 @@ public class CompanyTransferDTO {
 
     @ApiModelProperty("原员工企微ID")
     private Long oldQwUserId;
+
+    @ApiModelProperty("是否需要清除标签")
+    private Integer needClearTag = 0;
 }

+ 4 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferCompanyAuditMapper.java

@@ -11,4 +11,8 @@ public interface QwExternalContactTransferCompanyAuditMapper extends BaseMapper<
      * 查询审核记录列表
      */
     List<QwExternalContactTransferCompanyAudit> selectQwExternalContactTransferCompanyAuditList(QwExternalContactTransferCompanyAudit param);
+
+    List<QwExternalContactTransferCompanyAudit> selectQwExternalContactTransferCompanyAuditLists();
+
+
 }

+ 6 - 1
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferCompanyAuditUserMapper.java

@@ -14,7 +14,12 @@ public interface QwExternalContactTransferCompanyAuditUserMapper extends BaseMap
     List<QwExternalContactTransferCompanyAuditUser> getExistAuditByExtIds(@Param("ids") List<Long> ids);
 
     /**
-     * 查询接替记录
+     * 查询接替记录 (接替)
      */
     List<QwExternalContactTransferCompanyAuditUser> selectListByExtIdAndTakeoverUserIdAndCorpId(@Param("externalUserID") String externalUserID, @Param("takeoverUserId") String takeoverUserId, @Param("corpId") String corpId);
+
+    /**
+     * 查询接替记录 (转出)
+     */
+    List<QwExternalContactTransferCompanyAuditUser> selectListByExtIdAndHandoverUserIdAndCorpId(@Param("externalUserID") String externalUserID, @Param("handoverUserId") String handoverUserId, @Param("corpId") String corpId);
 }

+ 2 - 1
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferLogMapper.java

@@ -96,10 +96,11 @@ public interface QwExternalContactTransferLogMapper extends BaseMapper<QwExterna
             "LEFT JOIN company_user cu on cu.user_id=qu.company_user_id " +
             "<where>  \n" +
             "            <if test=\"corpId != null  and corpId != ''\"> and l.corp_id = #{corpId}</if>\n" +
+            "            <if test=\"name != null  and name != ''\"> and c.name like concat( #{name}, '%')</if>\n" +
             "            <if test=\"companyId != null \"> and l.company_id = #{companyId}</if>\n" +
             "            <if test=\"companyUserId != null \"> and l.company_user_id = #{companyUserId}</if>\n" +
             "            <if test=\"externalUserId != null  and externalUserId != ''\"> and l.external_user_id = #{externalUserId}</if>\n" +
-            "            <if test=\"companyUserNickName != null  and companyUserNickName != ''\"> and qu.qw_user_name = #{companyUserNickName}</if>\n" +
+            "            <if test=\"companyUserNickName != null  and companyUserNickName != ''\"> and qu.qw_user_name like concat( #{companyUserNickName}, '%')</if>\n" +
             "            <if test=\"customerId != null \"> and l.customer_id = #{customerId}</if>\n" +
             "            <if test=\"externalContactId != null \"> and l.external_contact_id = #{externalContactId}</if>\n" +
             "            <if test=\"status != null  and status != ''\"> and l.status = #{status}</if>\n" +

+ 61 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserComplainRecordMapper.java

@@ -0,0 +1,61 @@
+package com.fs.qw.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.qw.domain.QwUserComplainRecord;
+
+/**
+ * 企微员工投诉记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-10-22
+ */
+public interface QwUserComplainRecordMapper extends BaseMapper<QwUserComplainRecord>{
+    /**
+     * 查询企微员工投诉记录
+     *
+     * @param recordId 企微员工投诉记录主键
+     * @return 企微员工投诉记录
+     */
+    QwUserComplainRecord selectQwUserComplainRecordByRecordId(Long recordId);
+
+    /**
+     * 查询企微员工投诉记录列表
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 企微员工投诉记录集合
+     */
+    List<QwUserComplainRecord> selectQwUserComplainRecordList(QwUserComplainRecord qwUserComplainRecord);
+
+    /**
+     * 新增企微员工投诉记录
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 结果
+     */
+    int insertQwUserComplainRecord(QwUserComplainRecord qwUserComplainRecord);
+
+    /**
+     * 修改企微员工投诉记录
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 结果
+     */
+    int updateQwUserComplainRecord(QwUserComplainRecord qwUserComplainRecord);
+
+    /**
+     * 删除企微员工投诉记录
+     *
+     * @param recordId 企微员工投诉记录主键
+     * @return 结果
+     */
+    int deleteQwUserComplainRecordByRecordId(Long recordId);
+
+    /**
+     * 批量删除企微员工投诉记录
+     *
+     * @param recordIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteQwUserComplainRecordByRecordIds(Long[] recordIds);
+}

+ 33 - 0
fs-service/src/main/java/com/fs/qw/param/QwUserComplaintRecordParam.java

@@ -0,0 +1,33 @@
+package com.fs.qw.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class QwUserComplaintRecordParam {
+
+    @ApiModelProperty(value = "fsUserId")
+    private Long userId;
+
+    @ApiModelProperty(value = "投诉类型id")
+    private Long complaintTypeId;
+
+    @ApiModelProperty(value = "投诉内容")
+    private String complaintContent;
+
+    @ApiModelProperty(value = "投诉上传图片")
+    private String complaintUrl;
+
+    //企微员工主键ID
+    private Long qwUserId;
+
+    //外部联系人ID
+    private Long extId;
+
+    //用户手机号
+    private String phone;
+
+    //位置
+    private String position;
+
+}

+ 2 - 0
fs-service/src/main/java/com/fs/qw/param/ResignedTransferParam.java

@@ -11,4 +11,6 @@ public class ResignedTransferParam {
     String corpId;
     String  qwUserName;
     String type;
+    // 是否需要清除标签
+    private Integer needClearTag = 0;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/qw/param/TransferParam.java

@@ -12,4 +12,6 @@ public class TransferParam {
     String corpId;
     String content;
     String type;
+    // 是否需要清除标签
+    private Integer needClearTag = 0;
 }

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

@@ -32,4 +32,7 @@ public interface IQwExternalContactTransferCompanyAuditService extends IService<
      * 同步最新状态
      */
     void syncTransfer(Long auditId);
+
+    List<QwExternalContactTransferCompanyAudit> selectQwExternalContactTransferCompanyAuditLists();
+
 }

+ 64 - 0
fs-service/src/main/java/com/fs/qw/service/IQwUserComplainRecordService.java

@@ -0,0 +1,64 @@
+package com.fs.qw.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.qw.domain.QwUserComplainRecord;
+import com.fs.qw.param.QwUserComplaintRecordParam;
+
+/**
+ * 企微员工投诉记录Service接口
+ *
+ * @author fs
+ * @date 2025-10-22
+ */
+public interface IQwUserComplainRecordService extends IService<QwUserComplainRecord>{
+    /**
+     * 查询企微员工投诉记录
+     *
+     * @param recordId 企微员工投诉记录主键
+     * @return 企微员工投诉记录
+     */
+    QwUserComplainRecord selectQwUserComplainRecordByRecordId(Long recordId);
+
+    /**
+     * 查询企微员工投诉记录列表
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 企微员工投诉记录集合
+     */
+    List<QwUserComplainRecord> selectQwUserComplainRecordList(QwUserComplainRecord qwUserComplainRecord);
+
+    /**
+     * 新增企微员工投诉记录
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 结果
+     */
+    int insertQwUserComplainRecord(QwUserComplainRecord qwUserComplainRecord);
+
+    /**
+     * 修改企微员工投诉记录
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 结果
+     */
+    int updateQwUserComplainRecord(QwUserComplainRecord qwUserComplainRecord);
+
+    /**
+     * 批量删除企微员工投诉记录
+     *
+     * @param recordIds 需要删除的企微员工投诉记录主键集合
+     * @return 结果
+     */
+    int deleteQwUserComplainRecordByRecordIds(Long[] recordIds);
+
+    /**
+     * 删除企微员工投诉记录信息
+     *
+     * @param recordId 企微员工投诉记录主键
+     * @return 结果
+     */
+    int deleteQwUserComplainRecordByRecordId(Long recordId);
+
+    int submitRecordByQwUser(QwUserComplaintRecordParam param);
+}

+ 37 - 7
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -1143,6 +1143,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                                     qwExternalContactTransferLog.setTakeoverUserId(qwUser.getQwUserId());
                                     qwExternalContactTransferLog.setCorpId(param.getCorpId());
                                     qwExternalContactTransferLog.setExternalUserId(qwCustomer.getExternal_userid());
+                                    qwExternalContactTransferLog.setNeedClearTag(param.getNeedClearTag());
                                     qwExternalContactTransferLogMapper.insertQwExternalContactTransferLog(qwExternalContactTransferLog);
                                     QwExternalContact qwExternal = new QwExternalContact();
                                     qwExternal.setStatus(2);
@@ -1209,6 +1210,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                                     qwExternalContactTransferLog.setExternalUserId(qwCustomer.getExternal_userid());
                                     qwExternalContactTransferLog.setHandoverQwUserId(qwExternalContact.getQwUserId());
                                     qwExternalContactTransferLog.setFsUserId(qwExternalContact.getFsUserId());
+                                    qwExternalContactTransferLog.setNeedClearTag(param.getNeedClearTag());
                                     qwExternalContactTransferLogMapper.insertQwExternalContactTransferLog(qwExternalContactTransferLog);
                                     QwExternalContact qwExternal = new QwExternalContact();
                                     qwExternal.setStatus(2);
@@ -2488,6 +2490,26 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                 }
             }
         }
+
+        // 判断是否需要清除标签
+        boolean needClearTag = false;
+
+        //更新在职继承(可能有 可能没有)
+        QwExternalContactTransferLog transferLog=new QwExternalContactTransferLog();
+        transferLog.setCorpId(corpId);
+        transferLog.setTakeoverUserId(userID);
+        transferLog.setExternalUserId(externalUserID);
+        QwExternalContactTransferLog transferLogListByCheck = qwExternalContactTransferLogMapper.selectQwExternalContactTransferLogListByCheck(transferLog);
+        if (Objects.nonNull(transferLogListByCheck)) {
+            needClearTag = transferLogListByCheck.getNeedClearTag() == 1;
+        }
+
+        // 跨公司接替回调处理
+        List<QwExternalContactTransferCompanyAuditUser> auditUserList = transferCompanyAuditUserMapper.selectListByExtIdAndTakeoverUserIdAndCorpId(externalUserID, userID, corpId);
+        if (!auditUserList.isEmpty()) {
+            needClearTag = auditUserList.stream().anyMatch(t -> t.getNeedClearTag() == 1);
+        }
+
         for (FollowUser followUser : followUsers) {
             if (followUser.getUserid().equals(userID)) {
                 qwExternalContact.setUserId(followUser.getUserid()); // 设置属于用户ID
@@ -2507,7 +2529,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                 List<Tag> tags = followUser.getTags();
                 Set<String> combinedTagsSet = new HashSet<>();
 
-                if (tags != null && tags.size() > 0) {
+                if (tags != null && tags.size() > 0 && !needClearTag) {
                     List<String> tagArr = new ArrayList<>();
                     for (Tag tag : tags) {
                         tagArr.add(tag.getTag_id());
@@ -2802,11 +2824,6 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         }
 
         //更新在职继承(可能有 可能没有)
-        QwExternalContactTransferLog transferLog=new QwExternalContactTransferLog();
-        transferLog.setCorpId(corpId);
-        transferLog.setTakeoverUserId(userID);
-        transferLog.setExternalUserId(externalUserID);
-        QwExternalContactTransferLog transferLogListByCheck = qwExternalContactTransferLogMapper.selectQwExternalContactTransferLogListByCheck(transferLog);
         if (transferLogListByCheck!=null){
             transferLogListByCheck.setStatus(1);
             qwExternalContactTransferLogMapper.updateQwExternalContactTransferLog(transferLogListByCheck);
@@ -2821,7 +2838,6 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         }
 
         // 跨公司接替回调处理
-        List<QwExternalContactTransferCompanyAuditUser> auditUserList = transferCompanyAuditUserMapper.selectListByExtIdAndTakeoverUserIdAndCorpId(externalUserID, userID, corpId);
         if (!auditUserList.isEmpty()) {
             for (QwExternalContactTransferCompanyAuditUser auditUser : auditUserList) {
                 auditUser.setStatus(1);
@@ -4278,6 +4294,11 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
             qwExternal.setId(qwExternalContact.getId());
             qwExternal.setStatus(4);
             qwExternal.setDelTime(new Date());
+
+            // 是否存在转接记录
+            if (isTransfer(transferLogVO, externalUserID, userID, corpId)) {
+                qwExternal.setTransferStatus(1);
+            }
 //            logger.info("删除用户客户更改状态");
             qwExternalContactMapper.updateQwExternalContact(qwExternal);
 
@@ -4294,6 +4315,15 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         }
     }
 
+    /**
+     * 是否存在转接记录
+     */
+    private boolean isTransfer(QwExternalContactTransferLog transferLogVO, String externalUserID, String handoverUserId, String corpId) {
+        // 跨公司接替回调处理
+        List<QwExternalContactTransferCompanyAuditUser> auditUserList = transferCompanyAuditUserMapper.selectListByExtIdAndHandoverUserIdAndCorpId(externalUserID, handoverUserId, corpId);
+        return Objects.nonNull(transferLogVO) || !auditUserList.isEmpty();
+    }
+
     @Override
     public void deletefollowUserByExternalUserId(String externalUserID, String userID, String corpId) {
 

+ 59 - 64
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactTransferCompanyAuditServiceImpl.java

@@ -72,6 +72,10 @@ public class QwExternalContactTransferCompanyAuditServiceImpl extends ServiceImp
             throw new ServiceException("接替员工不能为本公司员工");
         }
 
+        if (qwUser.getCompanyUserId() == null) {
+            throw new ServiceException("接替员工必须绑定销售");
+        }
+
         List<QwExternalContact> qwExternalContacts = new ArrayList<>();
         // 为1转移员工下客户 其余转移转递的客户
         if (param.getType() == 1) {
@@ -90,6 +94,11 @@ public class QwExternalContactTransferCompanyAuditServiceImpl extends ServiceImp
             throw new ServiceException("只能转移本公司下的客户");
         }
 
+        boolean hasNotCorpId = qwExternalContacts.stream().anyMatch(c -> !c.getCorpId().equals(qwUser.getCorpId()));
+        if (hasNotCorpId) {
+            throw new ServiceException("只能转移同主体下的客户");
+        }
+
         if (qwExternalContacts.isEmpty()) {
             throw new ServiceException("请选择需要分配的客户");
         }
@@ -145,6 +154,7 @@ public class QwExternalContactTransferCompanyAuditServiceImpl extends ServiceImp
                 auditUser.setQwUserExtId(userQwUser.getQwUserId());
                 auditUser.setQwUserName(userQwUser.getQwUserName());
                 auditUser.setCreateTime(LocalDateTime.now());
+                auditUser.setNeedClearTag(param.getNeedClearTag());
 
                 return auditUser;
             }).collect(Collectors.toList());
@@ -195,58 +205,32 @@ public class QwExternalContactTransferCompanyAuditServiceImpl extends ServiceImp
      * 转接用户
      */
     private void transferCustomer(QwExternalContactTransferCompanyAudit auditInfo) {
+        String content = StringUtils.isNotBlank(auditInfo.getContent()) ? auditInfo.getContent() :
+                "您好,您的服务已升级,后续将由我的同事接替我的工作,继续为您服务。";
         List<QwExternalContactTransferCompanyAuditUser> auditUserList = auditUserService.getListByAuditId(auditInfo.getId());
-        outer:
-        for (QwExternalContactTransferCompanyAuditUser auditUser : auditUserList) {
+        auditUserList.parallelStream().forEach(auditUser -> {
             try {
                 // 已提交的不再处理
                 if (auditUser.getStatus() != 0) {
-                    continue;
+                    return;
                 }
 
+                List<QwCustomer> customer;
+                int code;
+                String message;
+
                 // 在职
                 if (auditInfo.getTransferType() == 1) {
                     QwTransferCustomerParam qwTransferCustomerParam = new QwTransferCustomerParam();
-                    String content = auditInfo.getContent();
-                    if(StringUtils.isBlank(content)){
-                        content = "您好,您的服务已升级,后续将由我的同事接替我的工作,继续为您服务。";
-                    }
                     qwTransferCustomerParam.setTransfer_success_msg(content);
                     qwTransferCustomerParam.setHandover_userid(auditUser.getQwUserExtId());
                     qwTransferCustomerParam.setTakeover_userid(auditInfo.getQwUserExtId());
                     qwTransferCustomerParam.setExternal_userid(Collections.singletonList(auditUser.getExternalUserId()));
                     QwTransferCustomerResult qwTransferCustomerResult = qwApiService.transferCustomer(qwTransferCustomerParam, auditInfo.getCorpId());
 
-                    if (qwTransferCustomerResult.getErrcode() != 0) {
-                        auditUser.setRemark("接替失败: " + qwTransferCustomerResult.getErrmsg());
-                        auditUserService.updateById(auditUser);
-                        continue;
-                    }
-
-                    List<QwCustomer> customer = qwTransferCustomerResult.getCustomer();
-                    if (Objects.isNull(customer) || customer.isEmpty()) {
-                        auditUser.setRemark("接替失败: 未获取到数据");
-                        auditUserService.updateById(auditUser);
-                        continue;
-                    }
-
-                    for (QwCustomer qwCustomer : customer) {
-                        if (qwCustomer.getErrcode() != 0) {
-                            auditUser.setRemark("接替失败: " + qwCustomer.getErrcode());
-                            auditUserService.updateById(auditUser);
-                            continue outer;
-                        }
-
-                        QwExternalContact qwExternal = new QwExternalContact();
-                        qwExternal.setStatus(2);
-                        qwExternal.setTransferStatus(2);
-                        qwExternal.setId(auditUser.getExternalId());
-                        contactMapper.updateQwExternalContact(qwExternal);
-
-                        auditUser.setStatus(2);
-                        auditUser.setReplaceTime(LocalDateTime.now());
-                        auditUserService.updateById(auditUser);
-                    }
+                    code = qwTransferCustomerResult.getErrcode();
+                    message = qwTransferCustomerResult.getErrmsg();
+                    customer = qwTransferCustomerResult.getCustomer();
                 }
                 // 离职
                 else if (auditInfo.getTransferType() == 2) {
@@ -254,44 +238,50 @@ public class QwExternalContactTransferCompanyAuditServiceImpl extends ServiceImp
                     qwTransferCustomerParam.setHandover_userid(auditUser.getQwUserExtId());
                     qwTransferCustomerParam.setTakeover_userid(auditInfo.getQwUserExtId());
                     qwTransferCustomerParam.setExternal_userid(Collections.singletonList(auditUser.getExternalUserId()));
-                    QwTransferCustomerResignedResult qwTransferCustomerResignedParam = qwApiService.resignedTransferCustomer(qwTransferCustomerParam, auditInfo.getCorpId());
+                    QwTransferCustomerResignedResult qwTransferCustomerResignedResult = qwApiService.resignedTransferCustomer(qwTransferCustomerParam, auditInfo.getCorpId());
+
+                    code = qwTransferCustomerResignedResult.getErrcode();
+                    message = qwTransferCustomerResignedResult.getErrmsg();
+                    customer = qwTransferCustomerResignedResult.getCustomer();
+                } else {
+                    auditUser.setRemark("接替失败: 接替类型错误");
+                    auditUserService.updateById(auditUser);
+                    return;
+                }
 
-                    if (qwTransferCustomerResignedParam.getErrcode() != 0) {
-                        auditUser.setRemark("接替失败: " + qwTransferCustomerResignedParam.getErrmsg());
-                        auditUserService.updateById(auditUser);
-                        continue;
-                    }
+                if (code != 0) {
+                    auditUser.setRemark("接替失败: " + message);
+                    auditUserService.updateById(auditUser);
+                    return;
+                }
+
+                if (Objects.isNull(customer) || customer.isEmpty()) {
+                    auditUser.setRemark("接替失败: 未获取到数据");
+                    auditUserService.updateById(auditUser);
+                    return;
+                }
 
-                    List<QwCustomer> customer = qwTransferCustomerResignedParam.getCustomer();
-                    if (Objects.isNull(customer) || customer.isEmpty()) {
-                        auditUser.setRemark("接替失败: 未获取到数据");
+                for (QwCustomer qwCustomer : customer) {
+                    if (qwCustomer.getErrcode() != 0) {
+                        auditUser.setRemark("接替失败: " + qwCustomer.getErrcode());
                         auditUserService.updateById(auditUser);
-                        continue;
+                        return;
                     }
 
-                    for (QwCustomer qwCustomer : customer) {
-                        if (qwCustomer.getErrcode() != 0) {
-                            auditUser.setRemark("接替失败: " + qwCustomer.getErrcode());
-                            auditUserService.updateById(auditUser);
-                            continue outer;
-                        }
-
-                        QwExternalContact qwExternal = new QwExternalContact();
-                        qwExternal.setStatus(2);
-                        qwExternal.setTransferStatus(2);
-                        qwExternal.setId(auditUser.getExternalId());
-                        contactMapper.updateQwExternalContact(qwExternal);
+                    QwExternalContact qwExternal = new QwExternalContact();
+                    qwExternal.setStatus(2);
+                    qwExternal.setTransferStatus(2);
+                    qwExternal.setId(auditUser.getExternalId());
+                    contactMapper.updateQwExternalContact(qwExternal);
 
-                        auditUser.setStatus(2);
-                        auditUser.setReplaceTime(LocalDateTime.now());
-                        auditUserService.updateById(auditUser);
-                    }
+                    auditUser.setStatus(2);
+                    auditUserService.updateById(auditUser);
                 }
             } catch (Exception e) {
                 auditUser.setRemark("接替失败: " + e.getMessage());
                 auditUserService.updateById(auditUser);
             }
-        }
+        });
     }
 
     /**
@@ -335,4 +325,9 @@ public class QwExternalContactTransferCompanyAuditServiceImpl extends ServiceImp
             }
         }
     }
+
+    @Override
+    public List<QwExternalContactTransferCompanyAudit> selectQwExternalContactTransferCompanyAuditLists() {
+        return baseMapper.selectQwExternalContactTransferCompanyAuditLists();
+    }
 }

+ 187 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserComplainRecordServiceImpl.java

@@ -0,0 +1,187 @@
+package com.fs.qw.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.domain.FsUserCourseComplaintRecord;
+import com.fs.qw.domain.QwCompany;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwCompanyMapper;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.param.QwUserComplaintRecordParam;
+import com.fs.qwApi.Result.QwSendMsgResult;
+import com.fs.qwApi.param.QwSendMsgParam;
+import com.fs.qwApi.service.QwApiService;
+import org.checkerframework.checker.units.qual.A;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.qw.mapper.QwUserComplainRecordMapper;
+import com.fs.qw.domain.QwUserComplainRecord;
+import com.fs.qw.service.IQwUserComplainRecordService;
+
+/**
+ * 企微员工投诉记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-10-22
+ */
+@Service
+public class QwUserComplainRecordServiceImpl extends ServiceImpl<QwUserComplainRecordMapper, QwUserComplainRecord> implements IQwUserComplainRecordService {
+
+
+    private static final Logger log = LoggerFactory.getLogger(QwUserComplainRecordServiceImpl.class);
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private QwApiService qwApiService;
+
+    @Autowired
+    private QwCompanyMapper qwCompanyMapper;
+
+    /**
+     * 查询企微员工投诉记录
+     *
+     * @param recordId 企微员工投诉记录主键
+     * @return 企微员工投诉记录
+     */
+    @Override
+    public QwUserComplainRecord selectQwUserComplainRecordByRecordId(Long recordId)
+    {
+        return baseMapper.selectQwUserComplainRecordByRecordId(recordId);
+    }
+
+    /**
+     * 查询企微员工投诉记录列表
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 企微员工投诉记录
+     */
+    @Override
+    public List<QwUserComplainRecord> selectQwUserComplainRecordList(QwUserComplainRecord qwUserComplainRecord)
+    {
+        return baseMapper.selectQwUserComplainRecordList(qwUserComplainRecord);
+    }
+
+    /**
+     * 新增企微员工投诉记录
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 结果
+     */
+    @Override
+    public int insertQwUserComplainRecord(QwUserComplainRecord qwUserComplainRecord)
+    {
+        qwUserComplainRecord.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertQwUserComplainRecord(qwUserComplainRecord);
+    }
+
+    /**
+     * 修改企微员工投诉记录
+     *
+     * @param qwUserComplainRecord 企微员工投诉记录
+     * @return 结果
+     */
+    @Override
+    public int updateQwUserComplainRecord(QwUserComplainRecord qwUserComplainRecord)
+    {
+        return baseMapper.updateQwUserComplainRecord(qwUserComplainRecord);
+    }
+
+    /**
+     * 批量删除企微员工投诉记录
+     *
+     * @param recordIds 需要删除的企微员工投诉记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteQwUserComplainRecordByRecordIds(Long[] recordIds)
+    {
+        return baseMapper.deleteQwUserComplainRecordByRecordIds(recordIds);
+    }
+
+    /**
+     * 删除企微员工投诉记录信息
+     *
+     * @param recordId 企微员工投诉记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteQwUserComplainRecordByRecordId(Long recordId)
+    {
+        return baseMapper.deleteQwUserComplainRecordByRecordId(recordId);
+    }
+
+    @Override
+    public int submitRecordByQwUser(QwUserComplaintRecordParam param) {
+        QwUserComplainRecord qwUserComplainRecord = new QwUserComplainRecord();
+        BeanUtils.copyProperties(param, qwUserComplainRecord);
+        qwUserComplainRecord.setCreateTime(DateUtils.getNowDate());
+        String description = createDescription(qwUserComplainRecord);
+        //抛出发送消息出现的异常
+        try {
+            log.info("发送应用提醒:{},{}", param.getQwUserId(),description);
+            sendQwMsg(param.getQwUserId(), description);
+        }catch (Exception e){
+
+        }
+        return baseMapper.insertQwUserComplainRecord(qwUserComplainRecord);
+
+    }
+
+
+
+
+    /**
+     * 给企业微信的应用发送消息
+     */
+    private void sendQwMsg(Long qwUserId ,String msg){
+        //查询企微用户
+        QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+        //查询主体信息
+        QwCompany qwCompany = qwCompanyMapper.selectQwCompanyByCorpId(qwUser.getCorpId());
+        //应用消息组装
+        QwSendMsgParam sendMsgParam = new QwSendMsgParam();
+        sendMsgParam.setAgentid(Integer.parseInt(qwCompany.getServerAgentId().trim()));
+        sendMsgParam.setTouser(qwUser.getQwUserId());
+        sendMsgParam.setMsgtype("textcard");
+        //组合文本卡片消息
+        QwSendMsgParam.TextCard textCard = new QwSendMsgParam.TextCard();
+        textCard.setTitle("工单提醒");
+        textCard.setDescription(msg);
+        textCard.setUrl("https://www.baidu.com/");
+        textCard.setBtntxt("详情");
+        sendMsgParam.setTextcard(textCard);
+        log.info("发送投诉信息请求体:{}",sendMsgParam);
+        //发送消息
+        QwSendMsgResult result = qwApiService.sendMsg(sendMsgParam, qwCompany.getCorpId());
+        log.info("发送投诉应用消息返回:{}",result);
+        if (result.getErrcode()!=0 && !result.getErrmsg().equals("ok")) {
+            log.error("发送投诉应用消息返回失败:{}",result);
+        }
+    }
+
+    /**
+     * 创建描述信息
+     * @param record
+     * @return
+     */
+    private String createDescription(QwUserComplainRecord record){
+        String content = "点击下方'详情'查看投诉内容";
+        int picCount = 0;
+        String complaintUrl = record.getComplaintUrl();
+        if (complaintUrl != null && !complaintUrl.trim().isEmpty()) {
+            picCount = complaintUrl.split(",").length;
+        }
+//        String position = record.getPosition();
+        String position = "中国境内";
+
+//        String recordDescription = "<div class=\\\"gray\\\">内容</div><div class=\\\"normal\\\">"+content+"</div><br><div class=\\\"gray\\\">图片</div><div class=\\\"normal\\\">"+picCount+"张</div><br><div class=\\\"gray\\\">位置</div><div class=\\\"normal\\\">"+position+"</div><br><div class=\\\"gray\\\">分类</div><div class=\\\"normal\\\">"+record.getComplaintContent()+"</div><br>";
+
+        String recordDescription = "<div class=\\\"gray\\\">2016年9月26日</div> <div class=\\\"normal\\\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\\\"highlight\\\">请于2016年10月10日前联系行政同事领取</div>";
+        return recordDescription;
+    }
+}

+ 16 - 0
fs-service/src/main/java/com/fs/qwApi/param/QwSendMsgParam.java

@@ -11,6 +11,7 @@ public class QwSendMsgParam {
     private int agentid; // 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口获取企业授权信息获取该参数值。
     private Text text; // 消息内容,最长不超过2048个字节,超过将截断(支持id转译)。
     private Markdown markdown;
+    private TextCard textcard;
     private int safe; // 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0。
     private int enable_id_trans; // 表示是否开启id转译,0表示否,1表示是,默认0。
     private int enable_duplicate_check; // 表示是否开启重复消息检查,0表示否,1表示是,默认0。
@@ -26,4 +27,19 @@ public class QwSendMsgParam {
         private String content;
     }
 
+    /**
+     * 文本卡片消息类型
+     */
+    @Data
+    public static class TextCard {
+        //标题,不超过128个字符,超过会自动截断(支持id转译)
+        private String title;
+        //描述,不超过512个字符,超过会自动截断(支持id转译)
+        private String description;
+        //点击后跳转的链接。最长2048字节,请确保包含了协议头(http/https)
+        private String url;
+        //按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
+        private String btntxt;
+    }
+
 }

+ 77 - 0
fs-service/src/main/java/com/fs/tulin/entity/QwExUserInfo.java

@@ -0,0 +1,77 @@
+package com.fs.tulin.entity;
+
+import lombok.Data;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/23 下午3:08
+ */
+@Data
+public class QwExUserInfo {
+
+
+    private Long fs_user_id;
+
+    /**
+     * 必填 union_id
+     * 小程序union_id
+     */
+    private String union_id;
+
+    /**
+     * 必填 open_id
+     * 小程序open_id
+     */
+    private String open_id;
+
+    /**
+     * 必填 appid
+     * 微信小程序appid
+     */
+    private String appid;
+
+    /**
+     * 必填 nickname
+     * 昵称
+     */
+    private String nickname;
+
+    /**
+     * 必填 column_name
+     * 栏目名称
+     */
+    private String column_name;
+
+    /**
+     * 必填 pharmacy_id
+     * 药店ID
+     */
+    private String pharmacy_id;
+
+    /**
+     * 必填 service_phone
+     * 客服手机号
+     */
+    private String service_phone;
+
+    /**
+     * 可选 period_name
+     * 学员所属期名称(可选)
+     */
+    private String period_name;
+
+    /**
+     * 可选 name
+     * 学员名称(可选)
+     */
+    private String name;
+
+    /**
+     * 可选 avatar
+     * 学员头像 (可选)
+     */
+    private String avatar;
+
+
+}

+ 4 - 5
fs-service/src/main/java/com/fs/tulin/StudentInfo.java → fs-service/src/main/java/com/fs/tulin/entity/StudentInfo.java

@@ -1,11 +1,8 @@
-package com.fs.tulin;
+package com.fs.tulin.entity;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
+import lombok.*;
 
 /**
  * @description:
@@ -16,6 +13,8 @@ import lombok.ToString;
 @Getter
 @Builder
 @ToString
+@NoArgsConstructor
+@AllArgsConstructor
 @JsonPropertyOrder(alphabetic = true)
 @JsonInclude(JsonInclude.Include.NON_NULL)
 public class StudentInfo {

+ 48 - 0
fs-service/src/main/java/com/fs/tulin/entity/TulinInfoSyncLog.java

@@ -0,0 +1,48 @@
+package com.fs.tulin.entity;
+
+/**
+ * @description: 信息同步实体类
+ * @author: Guos
+ * @time: 2025/10/23 下午1:04
+ */
+import java.util.Date;
+import lombok.Data;
+
+@Data
+public class TulinInfoSyncLog {
+    /**
+     * fs_user表的user_id
+     */
+    private Long fsUserId;
+
+    /**
+     * 请求的url
+     */
+    private String requestUrl;
+
+    /**
+     * 请求体
+     */
+    private String sendBody;
+
+    /**
+     * 请求返回结果体
+     */
+    private String resultBody;
+
+    /**
+     * 是否成功:1成功、0失败
+     */
+    private Integer result;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+}
+

+ 50 - 0
fs-service/src/main/java/com/fs/tulin/mapper/TulinInfoSyncLogMapper.java

@@ -0,0 +1,50 @@
+package com.fs.tulin.mapper;
+
+import com.fs.tulin.entity.QwExUserInfo;
+import com.fs.tulin.entity.StudentInfo;
+import com.fs.tulin.entity.TulinInfoSyncLog;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @description: 信息同步Mapper
+ * @author: Guos
+ * @time: 2025/10/23 上午11:45
+ */
+@Mapper
+public interface TulinInfoSyncLogMapper {
+
+
+    /**
+     * 插入记录
+     */
+    int insert(TulinInfoSyncLog record);
+
+    /**
+     * 根据主键更新记录
+     */
+    int updateByPrimaryKey(TulinInfoSyncLog record);
+
+    /**
+     * 根据主键删除记录
+     */
+    int deleteByPrimaryKey(@Param("fsUserId") Long fsUserId);
+
+    /**
+     * 根据主键查询记录
+     */
+    TulinInfoSyncLog selectByPrimaryKey(@Param("fsUserId") Long fsUserId);
+
+    /**
+     * 查询所有记录
+     */
+    List<TulinInfoSyncLog> selectAll();
+
+    /**
+     * 查询学生信息
+     */
+    List<QwExUserInfo> selectStudentInfo();
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/tulin/service/ITulinInfoSyncLogService.java

@@ -0,0 +1,20 @@
+package com.fs.tulin.service;
+
+import com.fs.tulin.entity.TulinInfoSyncLog;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/23 上午11:44
+ */
+public interface ITulinInfoSyncLogService {
+
+    /**
+     * 同步信息
+     */
+    void syncInfo();
+
+    Integer insert(TulinInfoSyncLog record);
+
+
+}

+ 95 - 0
fs-service/src/main/java/com/fs/tulin/service/impl/TulinInfoSyncLogServiceImpl.java

@@ -0,0 +1,95 @@
+package com.fs.tulin.service.impl;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fs.tulin.entity.QwExUserInfo;
+import com.fs.tulin.entity.StudentInfo;
+import com.fs.tulin.entity.TulinInfoSyncLog;
+import com.fs.tulin.mapper.TulinInfoSyncLogMapper;
+import com.fs.tulin.service.ITulinInfoSyncLogService;
+import com.fs.tulin.utils.ColumnNameEnum;
+import com.fs.tulin.utils.PharmacyEnum;
+import com.fs.tulin.utils.SyncStudentInfoService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @description: 信息同步Service
+ * @author: Guos
+ * @time: 2025/10/23 上午11:44
+ */
+@Slf4j
+@Service
+@AllArgsConstructor
+public class TulinInfoSyncLogServiceImpl implements ITulinInfoSyncLogService {
+
+    @Resource
+    private TulinInfoSyncLogMapper tulinInfoSyncLogMapper;
+
+    private final Environment environment;
+
+    @Override
+    public void syncInfo() {
+        // 获取当前激活的profile
+        String activeProfile = "dev";
+        String[] activeProfiles = environment.getActiveProfiles();
+        if (activeProfiles.length > 0) {
+            activeProfile = activeProfiles[0];
+        }
+        log.info("当前环境:{}", activeProfile);
+        List<QwExUserInfo> qwExUserInfos = tulinInfoSyncLogMapper.selectStudentInfo();
+        if(!activeProfile.equals("dev")){
+            log.info("线上开始执行数据同步");
+            for (QwExUserInfo qwExUserInfo : qwExUserInfos) {
+                StudentInfo studentInfo = new StudentInfo();
+                BeanUtils.copyProperties(qwExUserInfo, studentInfo);
+                studentInfo.setAppid("wx6688e6b9b6fb8700");
+                studentInfo.setColumn_name(ColumnNameEnum.GYBNX.getName());
+                studentInfo.setPharmacy_id(PharmacyEnum.YJKYSY.getPharmacyId());
+                try {
+                    TulinInfoSyncLog tulinInfoSyncLog = SyncStudentInfoService.send("PNBnO6MajM0tAd8t", studentInfo);
+                    tulinInfoSyncLog.setFsUserId(qwExUserInfo.getFs_user_id());
+                    insert(tulinInfoSyncLog);
+                } catch (JsonProcessingException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+//        if(activeProfile.equals("dev")) {
+//            log.info("线下开始执行数据同步");
+//            for (QwExUserInfo qwExUserInfo : qwExUserInfos) {
+//                StudentInfo studentInfo = new StudentInfo();
+//                BeanUtils.copyProperties(qwExUserInfo, studentInfo);
+//                studentInfo.setAppid("wx6688e6b9b6fb8700");
+//                studentInfo.setColumn_name(ColumnNameEnum.GYBNX.getName());
+//                studentInfo.setPharmacy_id(PharmacyEnum.YJKYSY.getPharmacyId());
+//                try {
+//                    TulinInfoSyncLog tulinInfoSyncLog = SyncStudentInfoService.send("PNBnO6MajM0tAd8t", studentInfo);
+//                    tulinInfoSyncLog.setFsUserId(qwExUserInfo.getFs_user_id());
+//                    insert(tulinInfoSyncLog);
+//                } catch (JsonProcessingException e) {
+//                    throw new RuntimeException(e);
+//                }
+//            }
+//        }
+    }
+
+
+    @Override
+    public Integer insert(TulinInfoSyncLog tulinInfoSyncLog) {
+        TulinInfoSyncLog oldObj = tulinInfoSyncLogMapper.selectByPrimaryKey(tulinInfoSyncLog.getFsUserId());
+        if(ObjectUtils.isEmpty(oldObj)){
+            return tulinInfoSyncLogMapper.insert(tulinInfoSyncLog);
+        }else {
+            tulinInfoSyncLog.setUpdateTime(new Date());
+            return tulinInfoSyncLogMapper.updateByPrimaryKey(tulinInfoSyncLog);
+        }
+    }
+}

+ 36 - 0
fs-service/src/main/java/com/fs/tulin/utils/ColumnNameEnum.java

@@ -0,0 +1,36 @@
+package com.fs.tulin.utils;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/10/23 上午11:19
+ */
+public enum ColumnNameEnum {
+
+    YYJD("医言九鼎","正式", "prod"),
+    GYBNX("国医伴你行","正式", "prod"),
+    CSLM("测试栏目0921","测试", "dev");
+
+    private String name;
+
+    private String description;
+
+    private String useEnvironment;
+
+    ColumnNameEnum(String name, String description, String useEnvironment){
+        this.name = name;
+        this.description = description;
+        this.useEnvironment = useEnvironment;
+    }
+    public String getName() {
+        return this.name;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
+    public String getUseEnvironment() {
+        return this.useEnvironment;
+    }
+}

+ 1 - 1
fs-service/src/main/java/com/fs/tulin/JsonSortUtils.java → fs-service/src/main/java/com/fs/tulin/utils/JsonSortUtils.java

@@ -1,4 +1,4 @@
-package com.fs.tulin;
+package com.fs.tulin.utils;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 

+ 1 - 1
fs-service/src/main/java/com/fs/tulin/PharmacyEnum.java → fs-service/src/main/java/com/fs/tulin/utils/PharmacyEnum.java

@@ -1,4 +1,4 @@
-package com.fs.tulin;
+package com.fs.tulin.utils;
 
 /**
  * @description: 这个后面要放到数据库去方便动态添加

+ 26 - 59
fs-service/src/main/java/com/fs/tulin/SyncStudentInfoService.java → fs-service/src/main/java/com/fs/tulin/utils/SyncStudentInfoService.java

@@ -1,9 +1,11 @@
-package com.fs.tulin;
+package com.fs.tulin.utils;
 
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fs.tulin.entity.StudentInfo;
+import com.fs.tulin.entity.TulinInfoSyncLog;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -12,6 +14,9 @@ import java.util.logging.Logger;
 
 /**
  * @description:
+ * 正确与错误返回结果示例:
+ * {"data":{"status":"ok","err_msg":"","execute_log":[***]}
+ * {"msg":"******","code":*****}
  * @author: Guos
  * @time: 2025/10/21 下午3:40
  */
@@ -34,39 +39,7 @@ public class SyncStudentInfoService {
      */
     private static final String CORP_ID = "PNBnO6MajM0tAd8t";
 
-
-    public static void main(String[] args) throws JsonProcessingException {
-//第一种方式
-//        Map<String, Object> requestBody = new HashMap<>();
-//        requestBody.put("corp_id", "PNBnO6MajM0tAd8t");
-//        List<Map<String, Object>> dataList = new ArrayList<>();
-//        Map<String, Object> dataItem = new HashMap<>();
-//        dataItem.put("union_id", "oLH_O648dcNgoZdQT4CN2Qft8i7k");
-//        dataItem.put("open_id", "ozzk-19AxQC5D3X9Wqpb-I3_Y3EQ");
-//        dataItem.put("appid", "wx6688e6b9b6fb8700");
-//        dataItem.put("nickname", "@冰阔落");
-//        dataItem.put("column_name", "测试栏目0921");
-//        dataItem.put("pharmacy_id", "26ee29ce-35aa-46c8-9650-3fe46014690c");
-//        dataItem.put("service_phone", "13760648472");
-//        dataList.add(dataItem);
-//        String sort = sortRequestBody(dataItem);
-//        requestBody.put("data", dataList);
-//      // 生成签名
-//        long timestamp = generateTimestamp();
-//        String sign = generateSign("PNBnO6MajM0tAd8t", sort, timestamp);
-//        System.out.println("时间戳: " + timestamp);
-//        System.out.println("签名: " + sign);
-//        // 构建完整的请求URL          "https://api.xiangyue.life/api/v1/mp/sync/student
-//        String url = String.format("https://api.xiangyue.life/api/v1/mp/sync/student?sign=%s&t=%d", sign, timestamp);
-//        HttpRequest httpRequest = HttpUtil.createPost(url);
-//        httpRequest.header("Content-Type", "application/json");
-//        System.out.println("url: " + url);
-//        System.out.println("排序后的"+sortRequestBody(requestBody));
-//        httpRequest.body(sortRequestBody(requestBody));
-//        HttpResponse execute = httpRequest.execute();
-//        String body = execute.body();
-//        System.out.println("响应结果: " + body);
-//第二种方式
+//    public static void main(String[] args) throws JsonProcessingException {
 //        StudentInfo student = StudentInfo.builder()
 //                .union_id("oLH_O648dcNgoZdQT4CN2Qft8i7k")
 //                .open_id("ozzk-19AxQC5D3X9Wqpb-I3_Y3EQ")
@@ -74,28 +47,8 @@ public class SyncStudentInfoService {
 //                .nickname("@冰阔落")
 //                .column_name("测试栏目0921")
 //                .pharmacy_id(PHARMACY_ID).service_phone("13760648472").build();
-//        //排序
-//        String sortedJson = JsonSortUtils.toSortedJson(student);
-//        long timestamp = generateTimestamp();
-//        String sign = generateSign(CORP_ID, sortedJson, timestamp);
-//        String url = String.format("https://api.xiangyue.life/api/v1/mp/sync/student?sign=%s&t=%d", sign, timestamp);
-//        Map<String, Object> request = new HashMap<>();
-//        request.put("corp_id", CORP_ID);
-//        request.put("data", Collections.singletonList(student));
-//        String jsonBody = mapper.writeValueAsString(request);
-//        System.out.println("正确JSON:");
-//        System.out.println(jsonBody);
-//        sendHttpPost(url, jsonBody);
-
-        StudentInfo student = StudentInfo.builder()
-                .union_id("oLH_O648dcNgoZdQT4CN2Qft8i7k")
-                .open_id("ozzk-19AxQC5D3X9Wqpb-I3_Y3EQ")
-                .appid("wx6688e6b9b6fb8700")
-                .nickname("@冰阔落")
-                .column_name("测试栏目0921")
-                .pharmacy_id(PHARMACY_ID).service_phone("13760648472").build();
-        String result = send(CORP_ID, student);
-    }
+//        String result = send(CORP_ID, student);
+//    }
 
     /**
      * @param corpId 企业ID
@@ -103,7 +56,7 @@ public class SyncStudentInfoService {
      * @return 请求结果
      * @throws JsonProcessingException
      */
-    public static String send(String corpId, StudentInfo studentInfo) throws JsonProcessingException {
+    public static TulinInfoSyncLog send(String corpId, StudentInfo studentInfo) throws JsonProcessingException {
         String sortedJson = JsonSortUtils.toSortedJson(studentInfo);
         long timestamp = generateTimestamp();
         String sign = generateSign(corpId, sortedJson, timestamp);
@@ -121,7 +74,7 @@ public class SyncStudentInfoService {
      * @param jsonBody 请求体JSON字符串
      * @return 响应结果
      */
-    private static String sendHttpPost(String url, String jsonBody) {
+    private static TulinInfoSyncLog sendHttpPost(String url, String jsonBody) {
         logger.info("云联学生信息同步接口");
         logger.info("请求URL:"+ url);
         logger.info("请求Body:"+ jsonBody);
@@ -131,7 +84,14 @@ public class SyncStudentInfoService {
         HttpResponse execute = httpRequest.execute();
         String result = execute.body();
         logger.info("请求结果:"+ result);
-        return result;
+        TulinInfoSyncLog tulinInfoSyncLog = new TulinInfoSyncLog();
+        tulinInfoSyncLog.setRequestUrl(url);
+        tulinInfoSyncLog.setResultBody(result);
+        tulinInfoSyncLog.setCreateTime(new Date());
+        tulinInfoSyncLog.setUpdateTime(new Date());
+        tulinInfoSyncLog.setSendBody(jsonBody);
+        tulinInfoSyncLog.setResult(containsOk(result));
+        return tulinInfoSyncLog;
     }
 
     /**
@@ -179,4 +139,11 @@ public class SyncStudentInfoService {
         return System.currentTimeMillis() / 1000;
     }
 
+    /**
+     * 判断结果是否成功
+     */
+    private static int containsOk(String resultStr) {
+        return resultStr.contains("ok")? 1 : 0;
+    }
+
 }

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

@@ -5,7 +5,7 @@ spring:
     # redis 配置
     redis:
         # 地址
-        host: r-2zexagt5g4z7arviu5.redis.rds.aliyuncs.com
+        host: r-2zevrvnmu1iu1e6ye3pd.redis.rds.aliyuncs.com
         # 端口,默认为6379
         port: 6379
         # 密码

+ 2 - 0
fs-service/src/main/resources/application-druid-qdtst-test.yml

@@ -166,3 +166,5 @@ token:
 openIM:
     secret:
     userID:
+#是否为新商户,新商户不走mpOpenId
+isNewWxMerchant: false

+ 5 - 0
fs-service/src/main/resources/db/20251011-转接增加清空标签配置.sql

@@ -0,0 +1,5 @@
+alter table qw_external_contact_transfer_log
+    add column need_clear_tag tinyint default 0 comment '是否需要清空标签 0否 1是';
+
+alter table qw_external_contact_transfer_company_audit_user
+    add column need_clear_tag tinyint default 0 comment '是否需要清空标签 0否 1是';

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

@@ -60,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         l.log_type,SEC_TO_TIME(l.duration) as duration,c.company_name,l.camp_period_time,l.finish_time,
         cu.nick_name as company_user_name ,l.send_type,l.create_time,l.update_time,l.last_heartbeat_time,
         qu.qw_user_name,qec.name as external_user_name,c.company_id,u.avatar as fsAvatar,u.nick_name as fsNickName,qec.create_time as qec_create_time,
-        u.is_vip isVip
+        u.is_vip isVip,l.reward_type
          from fs_course_watch_log l
          left join fs_user_course_video v on v.video_id = l.video_id
          left join fs_user_course uc on uc.course_id = l.course_id
@@ -122,10 +122,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 and DATE(qec.create_time) &lt;= DATE(#{maps.qecETime})
             </if>
             <if test= 'maps.sTime != null '>
-                and DATE(l.create_time) &gt;= DATE(#{maps.sTime})
+                and l.create_time &gt;= #{maps.sTime}
             </if>
             <if test='maps.eTime != null '>
-                and DATE(l.create_time) &lt;= DATE(#{maps.eTime})
+                and l.create_time &lt;= #{maps.eTime}
             </if>
             <if test= 'maps.scheduleStartTime != null '>
                 and DATE(l.camp_period_time) &gt;= DATE(#{maps.scheduleStartTime})

+ 116 - 0
fs-service/src/main/resources/mapper/course/FsUserCompanyUserQwMapper.xml

@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.course.mapper.FsUserCompanyUserQwMapper">
+
+    <resultMap type="FsUserCompanyUserQw" id="FsUserCompanyUserQwResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="isRepeatFans"    column="is_repeat_fans"    />
+        <result property="projectId"    column="project_id"    />
+        <result property="qwUserId"    column="qw_user_id"    />
+        <result property="qwExternalContactId"    column="qw_external_contact_id"    />
+        <result property="qwCompanyId"    column="qw_company_id"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="status"    column="status"    />
+        <result property="remark"    column="remark"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectFsUserCompanyUserQwVo">
+        select id, user_id, company_user_id, company_id, is_repeat_fans, project_id, qw_user_id, qw_external_contact_id, qw_company_id, create_by, update_by, create_time, status, remark, update_time from fs_user_company_user_qw
+    </sql>
+
+    <select id="selectFsUserCompanyUserQwList" parameterType="FsUserCompanyUserQw" resultMap="FsUserCompanyUserQwResult">
+        <include refid="selectFsUserCompanyUserQwVo"/>
+        <where>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="isRepeatFans != null "> and is_repeat_fans = #{isRepeatFans}</if>
+            <if test="projectId != null "> and project_id = #{projectId}</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+            <if test="qwExternalContactId != null "> and qw_external_contact_id = #{qwExternalContactId}</if>
+            <if test="qwCompanyId != null "> and qw_company_id = #{qwCompanyId}</if>
+            <if test="status != null "> and status = #{status}</if>
+        </where>
+    </select>
+
+    <select id="selectFsUserCompanyUserQwById" parameterType="Long" resultMap="FsUserCompanyUserQwResult">
+        <include refid="selectFsUserCompanyUserQwVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFsUserCompanyUserQw" parameterType="FsUserCompanyUserQw" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_user_company_user_qw
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="isRepeatFans != null">is_repeat_fans,</if>
+            <if test="projectId != null">project_id,</if>
+            <if test="qwUserId != null">qw_user_id,</if>
+            <if test="qwExternalContactId != null">qw_external_contact_id,</if>
+            <if test="qwCompanyId != null">qw_company_id,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="status != null">status,</if>
+            <if test="remark != null">remark,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="isRepeatFans != null">#{isRepeatFans},</if>
+            <if test="projectId != null">#{projectId},</if>
+            <if test="qwUserId != null">#{qwUserId},</if>
+            <if test="qwExternalContactId != null">#{qwExternalContactId},</if>
+            <if test="qwCompanyId != null">#{qwCompanyId},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="status != null">#{status},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsUserCompanyUserQw" parameterType="FsUserCompanyUserQw">
+        update fs_user_company_user_qw
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="isRepeatFans != null">is_repeat_fans = #{isRepeatFans},</if>
+            <if test="projectId != null">project_id = #{projectId},</if>
+            <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
+            <if test="qwExternalContactId != null">qw_external_contact_id = #{qwExternalContactId},</if>
+            <if test="qwCompanyId != null">qw_company_id = #{qwCompanyId},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsUserCompanyUserQwById" parameterType="Long">
+        delete from fs_user_company_user_qw where id = #{id}
+    </delete>
+
+    <delete id="deleteFsUserCompanyUserQwByIds" parameterType="String">
+        delete from fs_user_company_user_qw where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 9 - 0
fs-service/src/main/resources/mapper/qw/QwExternalContactTransferCompanyAuditMapper.xml

@@ -8,6 +8,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select *
         from qw_external_contact_transfer_company_audit
         <where>
+            <if test="corpId != null">
+                and corp_id = #{corpId}
+            </if>
             <if test="corpName != null and corpName != ''">
                 and corp_name like concat('%', #{corpName}, '%')
             </if>
@@ -26,4 +29,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
         order by create_time desc,id desc
     </select>
+
+    <select id="selectQwExternalContactTransferCompanyAuditLists" resultType="com.fs.qw.domain.QwExternalContactTransferCompanyAudit">
+        select DISTINCT corp_name ,corp_id
+        from qw_external_contact_transfer_company_audit
+        order by create_time desc,id desc
+    </select>
 </mapper>

+ 11 - 0
fs-service/src/main/resources/mapper/qw/QwExternalContactTransferCompanyAuditUserMapper.xml

@@ -25,4 +25,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           and ca.corp_id = #{corpId}
           and ca.qw_user_ext_id = #{takeoverUserId}
     </select>
+
+    <select id="selectListByExtIdAndHandoverUserIdAndCorpId" resultType="com.fs.qw.domain.QwExternalContactTransferCompanyAuditUser">
+        select
+            au.*
+        from qw_external_contact_transfer_company_audit_user au
+        inner join qw_external_contact_transfer_company_audit ca on au.audit_id = ca.id and ca.status = 2
+        where au.status in (1,2)
+          and au.external_user_id = #{externalUserID}
+          and ca.corp_id = #{corpId}
+          and au.qw_user_ext_id = #{handoverUserId}
+    </select>
 </mapper>

+ 5 - 1
fs-service/src/main/resources/mapper/qw/QwExternalContactTransferLogMapper.xml

@@ -19,10 +19,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="qwUserId"    column="qw_user_id"    />
         <result property="handoverQwUserId"    column="handover_qw_user_id"    />
         <result property="fsUserId"    column="fs_user_id"    />
+        <result property="needClearTag"    column="need_clear_tag"    />
     </resultMap>
 
     <sql id="selectQwExternalContactTransferLogVo">
-        select id, corp_id, qw_user_id,handover_qw_user_id,company_id,takeover_user_id,handover_user_id, company_user_id, external_user_id, customer_id, external_contact_id, status, create_time,fs_user_id from qw_external_contact_transfer_log
+        select id, corp_id, qw_user_id,handover_qw_user_id,company_id,takeover_user_id,handover_user_id, company_user_id, external_user_id, customer_id, external_contact_id, status, create_time,fs_user_id, need_clear_tag from qw_external_contact_transfer_log
     </sql>
 
     <select id="selectQwExternalContactTransferLogList" parameterType="QwExternalContactTransferLog" resultMap="QwExternalContactTransferLogResult">
@@ -83,6 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="qwUserId != null">qw_user_id,</if>
             <if test="handoverQwUserId != null">handover_qw_user_id,</if>
             <if test="fsUserId != null">fs_user_id,</if>
+            <if test="needClearTag != null">need_clear_tag,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">#{id},</if>
@@ -99,6 +101,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="qwUserId != null">#{qwUserId},</if>
             <if test="handoverQwUserId != null">#{handoverQwUserId},</if>
             <if test="fsUserId != null">#{fsUserId},</if>
+            <if test="needClearTag != null">#{needClearTag},</if>
          </trim>
     </insert>
 
@@ -117,6 +120,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="handoverUserId != null">handover_user_id = #{handoverUserId},</if>
             <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
             <if test="handoverQwUserId != null">handover_qw_user_id = #{handoverQwUserId},</if>
+            <if test="needClearTag != null">need_clear_tag = #{needClearTag},</if>
         </trim>
         where id = #{id}
     </update>

+ 94 - 0
fs-service/src/main/resources/mapper/qw/QwUserComplainRecordMapper.xml

@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.qw.mapper.QwUserComplainRecordMapper">
+
+    <resultMap type="QwUserComplainRecord" id="QwUserComplainRecordResult">
+        <result property="recordId"    column="record_id"    />
+        <result property="phone"    column="phone"    />
+        <result property="complaintTypeId"    column="complaint_type_id"    />
+        <result property="complaintContent"    column="complaint_content"    />
+        <result property="complaintUrl"    column="complaint_url"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="qwUserId"    column="qw_user_id"    />
+        <result property="extId"    column="ext_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="position"    column="position"    />
+    </resultMap>
+
+    <sql id="selectQwUserComplainRecordVo">
+        select record_id,position, phone, complaint_type_id, complaint_content, complaint_url, create_time, qw_user_id, ext_id, user_id from qw_user_complain_record
+    </sql>
+
+    <select id="selectQwUserComplainRecordList" parameterType="QwUserComplainRecord" resultMap="QwUserComplainRecordResult">
+        <include refid="selectQwUserComplainRecordVo"/>
+        <where>
+            <if test="phone != null  and phone != ''"> and phone = #{phone}</if>
+            <if test="complaintTypeId != null "> and complaint_type_id = #{complaintTypeId}</if>
+            <if test="complaintContent != null  and complaintContent != ''"> and complaint_content = #{complaintContent}</if>
+            <if test="complaintUrl != null  and complaintUrl != ''"> and complaint_url = #{complaintUrl}</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+            <if test="extId != null "> and ext_id = #{extId}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
+        </where>
+    </select>
+
+    <select id="selectQwUserComplainRecordByRecordId" parameterType="Long" resultMap="QwUserComplainRecordResult">
+        <include refid="selectQwUserComplainRecordVo"/>
+        where record_id = #{recordId}
+    </select>
+
+    <insert id="insertQwUserComplainRecord" parameterType="QwUserComplainRecord" useGeneratedKeys="true" keyProperty="recordId">
+        insert into qw_user_complain_record
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="phone != null">phone,</if>
+            <if test="complaintTypeId != null">complaint_type_id,</if>
+            <if test="complaintContent != null">complaint_content,</if>
+            <if test="complaintUrl != null">complaint_url,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="qwUserId != null">qw_user_id,</if>
+            <if test="extId != null">ext_id,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="position != null">position,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="phone != null">#{phone},</if>
+            <if test="complaintTypeId != null">#{complaintTypeId},</if>
+            <if test="complaintContent != null">#{complaintContent},</if>
+            <if test="complaintUrl != null">#{complaintUrl},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="qwUserId != null">#{qwUserId},</if>
+            <if test="extId != null">#{extId},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="position != null">#{position},</if>
+        </trim>
+    </insert>
+
+    <update id="updateQwUserComplainRecord" parameterType="QwUserComplainRecord">
+        update qw_user_complain_record
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="phone != null">phone = #{phone},</if>
+            <if test="complaintTypeId != null">complaint_type_id = #{complaintTypeId},</if>
+            <if test="complaintContent != null">complaint_content = #{complaintContent},</if>
+            <if test="complaintUrl != null">complaint_url = #{complaintUrl},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
+            <if test="extId != null">ext_id = #{extId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="position != null">user_id = #{position},</if>
+        </trim>
+        where record_id = #{recordId}
+    </update>
+
+    <delete id="deleteQwUserComplainRecordByRecordId" parameterType="Long">
+        delete from qw_user_complain_record where record_id = #{recordId}
+    </delete>
+
+    <delete id="deleteQwUserComplainRecordByRecordIds" parameterType="String">
+        delete from qw_user_complain_record where record_id in
+        <foreach item="recordId" collection="array" open="(" separator="," close=")">
+            #{recordId}
+        </foreach>
+    </delete>
+</mapper>

+ 82 - 0
fs-service/src/main/resources/mapper/tulin/TulinInfoSyncLogMapper.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.tulin.mapper.TulinInfoSyncLogMapper">
+
+    <resultMap id="BaseResultMap" type="com.fs.tulin.entity.TulinInfoSyncLog">
+        <id column="fs_user_id" property="fsUserId" />
+        <result column="request_url" property="requestUrl" />
+        <result column="send_body" property="sendBody" />
+        <result column="result_body" property="resultBody" />
+        <result column="result" property="result" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        fs_user_id, request_url, send_body, result_body, result, create_time, update_time
+    </sql>
+
+    <select id="selectByPrimaryKey" parameterType="long" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List" />
+        FROM tulin_info_sync_log
+        WHERE fs_user_id = #{fsUserId}
+    </select>
+
+    <insert id="insert" parameterType="com.fs.tulin.entity.TulinInfoSyncLog">
+        INSERT INTO tulin_info_sync_log
+        (fs_user_id, request_url, send_body, result_body, result, create_time, update_time)
+        VALUES
+            (#{fsUserId}, #{requestUrl}, #{sendBody}, #{resultBody}, #{result}, #{createTime}, #{updateTime})
+    </insert>
+
+    <update id="updateByPrimaryKey" parameterType="com.fs.tulin.entity.TulinInfoSyncLog">
+        UPDATE tulin_info_sync_log
+        SET
+            request_url = #{requestUrl},
+            send_body = #{sendBody},
+            result_body = #{resultBody},
+            result = #{result},
+            update_time = #{updateTime}
+        WHERE fs_user_id = #{fsUserId}
+    </update>
+
+    <delete id="deleteByPrimaryKey" parameterType="long">
+        DELETE FROM tulin_info_sync_log
+        WHERE fs_user_id = #{fsUserId}
+    </delete>
+
+    <select id="selectAll" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List" />
+        FROM tulin_info_sync_log
+    </select>
+
+    <resultMap id="selectStudentInfoMap" type="com.fs.tulin.entity.QwExUserInfo">
+        <id column="fs_user_id" property="fs_user_id" />
+        <result column="nickname" property="nickname" />
+        <result column="service_phone" property="service_phone" />
+        <result column="union_id" property="union_id" />
+        <result column="open_id" property="open_id" />
+        <result column="avatar" property="avatar" />
+        <result column="name" property="name" />
+    </resultMap>
+
+    <select id="selectStudentInfo" resultMap="selectStudentInfoMap">
+        SELECT
+            fu.user_id as fs_user_id,
+            fu.nick_name as nickname,
+            fu.phone as service_phone,
+            fu.union_id as union_id,
+            fu.ma_open_id as open_id,
+            fu.avatar as avatar,
+            qec.name as name
+        FROM qw_user AS qu
+        INNER JOIN qw_external_contact AS qec ON qu.id = qec.qw_user_id
+        inner join fs_user as fu on fu.qw_ext_id = qec.id
+        left join tulin_info_sync_log as tisl on tisl.fs_user_id = fu.user_id
+        where fu.union_id is not null and fu.ma_open_id is not null
+        and tisl.result = 0
+    </select>
+
+</mapper>

+ 8 - 0
fs-service/src/test/java/com/fs/his/service/impl/FsUserServiceImplTest.java

@@ -1,9 +1,17 @@
 package com.fs.his.service.impl;
 
 
+import com.fs.tulin.service.ITulinInfoSyncLogService;
+
+import javax.annotation.Resource;
+
 class FsUserServiceImplTest {
 
+    @Resource
+    private ITulinInfoSyncLogService tulinInfoSyncLogService;
+
 
     void selectFsUserPageListNew() {
+        tulinInfoSyncLogService.syncInfo();
     }
 }

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/controller/store/UserScrmController.java

@@ -310,7 +310,7 @@ public class UserScrmController extends AppBaseController {
         FsUserScrm user=new FsUserScrm();
         user.setUserId(Long.parseLong(getUserId()));
         user.setAvatar(param.getAvatar());
-        user.setNickname(param.getNickname());
+        user.setNickname(StringUtils.isNotBlank(param.getNickname())?param.getNickName():param.getNickname());
         if(userService.updateFsUser(user)>0){
             return R.ok("修改成功");
         }