Ver código fonte

Merge remote-tracking branch 'origin/master'

吴树波 2 meses atrás
pai
commit
346cdd31ed
65 arquivos alterados com 2926 adições e 261 exclusões
  1. 8 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java
  2. 104 0
      fs-admin/src/main/java/com/fs/transfer/CustomerTransferApprovalController.java
  3. 49 6
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  4. 58 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  5. 1 1
      fs-company-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java
  6. 29 0
      fs-company-app/src/main/java/com/fs/app/param/UserCourseVideoParam.java
  7. 8 1
      fs-company/src/main/java/com/fs/core/exception/FSExceptionHandler.java
  8. 0 1
      fs-company/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  9. 104 0
      fs-company/src/main/java/com/fs/transfer/CustomerTransferApprovalController.java
  10. 84 0
      fs-company/src/main/java/com/fs/users/controller/MyCompanyCustomerController.java
  11. 66 0
      fs-service-system/src/main/java/com/fs/company/domain/CompanyTag.java
  12. 94 0
      fs-service-system/src/main/java/com/fs/company/domain/CompanyTagUser.java
  13. 61 0
      fs-service-system/src/main/java/com/fs/company/mapper/CompanyTagMapper.java
  14. 66 0
      fs-service-system/src/main/java/com/fs/company/mapper/CompanyTagUserMapper.java
  15. 5 2
      fs-service-system/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  16. 61 0
      fs-service-system/src/main/java/com/fs/company/service/ICompanyTagService.java
  17. 71 0
      fs-service-system/src/main/java/com/fs/company/service/ICompanyTagUserService.java
  18. 4 0
      fs-service-system/src/main/java/com/fs/company/service/ICompanyUserService.java
  19. 95 0
      fs-service-system/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java
  20. 124 0
      fs-service-system/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java
  21. 11 0
      fs-service-system/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  22. 20 2
      fs-service-system/src/main/java/com/fs/course/HuaweiCloudTest.java
  23. 2 0
      fs-service-system/src/main/java/com/fs/course/config/RedPacketConfig.java
  24. 3 0
      fs-service-system/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  25. 4 0
      fs-service-system/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  26. 22 0
      fs-service-system/src/main/java/com/fs/course/param/newfs/FsUserCourseListParam.java
  27. 29 0
      fs-service-system/src/main/java/com/fs/course/param/newfs/UserCourseVideoPageParam.java
  28. 7 0
      fs-service-system/src/main/java/com/fs/course/service/IFsUserCourseService.java
  29. 16 0
      fs-service-system/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  30. 1 0
      fs-service-system/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  31. 6 6
      fs-service-system/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  32. 57 11
      fs-service-system/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  33. 3 1
      fs-service-system/src/main/java/com/fs/course/vo/FsUserCourseListPVO.java
  34. 37 0
      fs-service-system/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoDetailsVO.java
  35. 47 0
      fs-service-system/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoPageListVO.java
  36. 38 0
      fs-service-system/src/main/java/com/fs/course/vo/newfs/FsUserVideoQuestionVO.java
  37. 2 0
      fs-service-system/src/main/java/com/fs/his/param/WxSendRedPacketParam.java
  38. 102 0
      fs-service-system/src/main/java/com/fs/qw/domain/CustomerTransferApproval.java
  39. 62 0
      fs-service-system/src/main/java/com/fs/qw/mapper/CustomerTransferApprovalMapper.java
  40. 14 0
      fs-service-system/src/main/java/com/fs/qw/param/TransferParam.java
  41. 62 0
      fs-service-system/src/main/java/com/fs/qw/service/ICustomerTransferApprovalService.java
  42. 269 0
      fs-service-system/src/main/java/com/fs/qw/service/impl/CustomerTransferApprovalServiceImpl.java
  43. 30 0
      fs-service-system/src/main/java/com/fs/qw/vo/TransferCustomDTO.java
  44. 16 0
      fs-service-system/src/main/java/com/fs/store/domain/FsUser.java
  45. 14 0
      fs-service-system/src/main/java/com/fs/store/domain/FsUserCourseCount.java
  46. 31 0
      fs-service-system/src/main/java/com/fs/store/dto/FsUserTransferParamDTO.java
  47. 13 0
      fs-service-system/src/main/java/com/fs/store/mapper/FsUserMapper.java
  48. 26 0
      fs-service-system/src/main/java/com/fs/store/param/SelectCusListPageParam.java
  49. 7 1
      fs-service-system/src/main/java/com/fs/store/param/h5/FsUserPageListParam.java
  50. 28 0
      fs-service-system/src/main/java/com/fs/store/param/h5/TagListParam.java
  51. 10 0
      fs-service-system/src/main/java/com/fs/store/service/IFsUserService.java
  52. 88 69
      fs-service-system/src/main/java/com/fs/store/service/impl/FsStorePaymentServiceImpl.java
  53. 76 3
      fs-service-system/src/main/java/com/fs/store/service/impl/FsUserServiceImpl.java
  54. 19 0
      fs-service-system/src/main/java/com/fs/store/vo/h5/CompanyUserTagListVO.java
  55. 2 0
      fs-service-system/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java
  56. 8 0
      fs-service-system/src/main/java/com/fs/store/vo/h5/UserDetailsVO.java
  57. 66 0
      fs-service-system/src/main/resources/mapper/company/CompanyTagMapper.xml
  58. 98 0
      fs-service-system/src/main/resources/mapper/company/CompanyTagUserMapper.xml
  59. 25 1
      fs-service-system/src/main/resources/mapper/company/CompanyUserMapper.xml
  60. 20 0
      fs-service-system/src/main/resources/mapper/course/FsUserCourseMapper.xml
  61. 25 0
      fs-service-system/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  62. 121 0
      fs-service-system/src/main/resources/mapper/qw/CustomerTransferApprovalMapper.xml
  63. 21 1
      fs-service-system/src/main/resources/mapper/store/FsUserCourseCountMapper.xml
  64. 268 122
      fs-service-system/src/main/resources/mapper/store/FsUserMapper.xml
  65. 8 32
      fs-user-app/src/main/java/com/fs/app/controller/WxPayController.java

+ 8 - 1
fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java

@@ -20,7 +20,7 @@ import com.fs.common.core.page.TableDataInfo;
 
 /**
  * 企业员工信息Controller
- * 
+ *
  * @author fs
  * @date 2021-10-04
  */
@@ -112,6 +112,13 @@ public class CompanyUserController extends BaseController
         return R.ok().put("data",list);
     }
 
+    @GetMapping("/getAllUserListLimit")
+    public R getAllUserListLimit(@RequestParam(required = false) Long companyId,
+                                 @RequestParam(required = false) String keywords){
+        List<CompanyUser> list = companyUserService.getAllUserListLimit(companyId,keywords);
+        return R.ok().put("data", list);
+    }
+
     @GetMapping("/getUserListByDeptId")
     public R getUserListByDeptId(CompanyUser user)
     {

+ 104 - 0
fs-admin/src/main/java/com/fs/transfer/CustomerTransferApprovalController.java

@@ -0,0 +1,104 @@
+package com.fs.transfer;
+
+import java.util.List;
+
+import com.fs.qw.domain.CustomerTransferApproval;
+import com.fs.qw.service.ICustomerTransferApprovalService;
+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.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 客户转移审批Controller
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+@RestController
+@RequestMapping("/system/approval")
+public class CustomerTransferApprovalController extends BaseController
+{
+    @Autowired
+    private ICustomerTransferApprovalService customerTransferApprovalService;
+
+    /**
+     * 查询客户转移审批列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CustomerTransferApproval customerTransferApproval)
+    {
+        startPage();
+        List<CustomerTransferApproval> list = customerTransferApprovalService.selectCustomerTransferApprovalList(customerTransferApproval);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出客户转移审批列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:export')")
+    @Log(title = "客户转移审批", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CustomerTransferApproval customerTransferApproval)
+    {
+        List<CustomerTransferApproval> list = customerTransferApprovalService.selectCustomerTransferApprovalList(customerTransferApproval);
+        ExcelUtil<CustomerTransferApproval> util = new ExcelUtil<CustomerTransferApproval>(CustomerTransferApproval.class);
+        return util.exportExcel(list, "approval");
+    }
+
+    /**
+     * 获取客户转移审批详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(customerTransferApprovalService.selectCustomerTransferApprovalById(id));
+    }
+
+    /**
+     * 新增客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:add')")
+    @Log(title = "客户转移审批", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CustomerTransferApproval customerTransferApproval)
+    {
+        return toAjax(customerTransferApprovalService.insertCustomerTransferApproval(customerTransferApproval));
+    }
+
+    /**
+     * 修改客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:edit')")
+    @Log(title = "客户转移审批", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CustomerTransferApproval customerTransferApproval)
+    {
+        return toAjax(customerTransferApprovalService.updateCustomerTransferApproval(customerTransferApproval));
+    }
+
+    /**
+     * 删除客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:remove')")
+    @Log(title = "客户转移审批", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(customerTransferApprovalService.deleteCustomerTransferApprovalByIds(ids));
+    }
+}

+ 49 - 6
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -3,11 +3,15 @@ package com.fs.app.controller;
 
 import com.fs.app.annotation.Login;
 import com.fs.common.core.domain.ResponseResult;
-import com.fs.qw.service.IQwExternalContactService;
-import com.fs.qw.vo.newvo.ExternalContactDetailsVO;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyTagUserService;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.store.param.h5.FsUserPageListParam;
+import com.fs.store.param.h5.TagListParam;
 import com.fs.store.service.IFsUserService;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
 import com.fs.store.vo.h5.FsUserPageListVO;
+import com.fs.store.vo.h5.UserDetailsVO;
 import com.fs.store.vo.h5.UserListPageVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -28,6 +32,12 @@ public class FsUserController extends AppBaseController {
 
     @Autowired
     private IFsUserService fsUserService;
+
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    private ICompanyTagUserService companyTagUserService;
 //
 //    @Autowired
 //    private IQwTagService tagService;
@@ -43,6 +53,13 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok(pageInfo);
     }
 
+    @GetMapping("/allCompanyUser")
+    @ApiOperation("获取所有公司销售")
+    public ResponseResult<List<CompanyUser>> getAllCompanyUser(){
+        List<CompanyUser> companyUsers = companyUserService.selectAllCompanyUserByParentId(Long.parseLong(getUserId()));
+        return ResponseResult.ok(companyUsers);
+    }
+
     @Login
     @GetMapping("/totalNumber")
     @ApiOperation("用户会员数量统计")
@@ -54,12 +71,38 @@ public class FsUserController extends AppBaseController {
     @Login
     @GetMapping("/details")
     @ApiOperation("用户会员详情")
-    public ResponseResult<ExternalContactDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
-                                                                   @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam String dateTag) {
-//        qwExternalContactService.getUserDetails(Long.parseLong(getUserId()), contactId, dateTag)
-        return ResponseResult.ok();
+    public ResponseResult<UserDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
+                                                                   @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam(required = false) String dateTag) {
+        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag);
+        return ResponseResult.ok(userDetails);
     }
 
+    @Login
+    @GetMapping("/tagList")
+    @ApiOperation("用户会员标签列表")
+    public ResponseResult<PageInfo<CompanyUserTagListVO>> getTagList(TagListParam param) {
+        param.setUserId(Long.parseLong(getUserId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<CompanyUserTagListVO> tagList = companyTagUserService.getTagList(param);
+        PageInfo<CompanyUserTagListVO> pageInfo = new PageInfo<>(tagList);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @PostMapping("/disabled")
+    @ApiOperation("批量禁用会员")
+    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        Boolean r = fsUserService.disabledUser(ids, false);
+        return ResponseResult.ok(r);
+    }
+
+    @Login
+    @PostMapping("/enabled")
+    @ApiOperation("批量启用会员")
+    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        Boolean r = fsUserService.disabledUser(ids, true);
+        return ResponseResult.ok(r);
+    }
 
 
 }

+ 58 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -0,0 +1,58 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.ResponseResult;
+import com.fs.course.param.newfs.FsUserCourseListParam;
+import com.fs.course.param.newfs.UserCourseVideoPageParam;
+import com.fs.course.service.IFsUserCourseService;
+import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.vo.FsUserCourseListPVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@Api("课程库相关接口")
+@RestController
+@RequestMapping("/app/fs/course")
+@Slf4j
+public class FsUserCourseVideoController extends AppBaseController {
+
+    @Autowired
+    private IFsUserCourseVideoService fsUserCourseVideoService;
+
+    @Autowired
+    private IFsUserCourseService  fsUserCourseService;
+
+    @GetMapping("/pageList")
+    @ApiOperation("课程分页列表")
+    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> list(UserCourseVideoPageParam param) {
+        PageHelper.startPage(param.getPageNum(),param.getPageSize());
+        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
+        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @ApiOperation("课程视频详情")
+    @GetMapping(value = "/videoDetails")
+    public ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId) {
+        return fsUserCourseVideoService.getVideoDetails(videoId);
+    }
+
+    @GetMapping("/courseList")
+    @ApiOperation("获取课程下拉列表")
+    public ResponseResult<PageInfo<FsUserCourseListPVO>> getAllCompanyUser(FsUserCourseListParam param){
+        PageHelper.startPage(param.getPageNum(),param.getPageSize());
+        param.setCompanyId(getCompanyId());
+        List<FsUserCourseListPVO> fsUserCourseList = fsUserCourseService.getFsUserCourseList(param);
+        PageInfo<FsUserCourseListPVO> pageInfo = new PageInfo<>(fsUserCourseList);
+        return ResponseResult.ok(pageInfo);
+    }
+}

+ 1 - 1
fs-company-app/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -62,7 +62,7 @@ public class FSExceptionHandler {
 
 			return R.error(defaultMessage);
 		}else {
-			return R.error();
+			return R.error(e.getMessage());
 		}
 
 	}

+ 29 - 0
fs-company-app/src/main/java/com/fs/app/param/UserCourseVideoParam.java

@@ -0,0 +1,29 @@
+package com.fs.app.param;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 课堂视频对象 fs_user_course_video
+ *
+ * @author fs
+ * @date 2024-05-17
+ */
+@Data
+public class UserCourseVideoParam extends BaseEntity
+{
+
+    /** 课程ID */
+    @Excel(name = "课程ID")
+    @ApiModelProperty(value = "课程ID")
+    private Long courseId;
+
+    /** 视频状态 1:草稿,2:待审核,3:发布 */
+    @Excel(name = "视频状态 1:草稿,2:待审核,3:发布")
+    @ApiModelProperty(value = "视频状态 1:草稿,2:待审核,3:发布")
+    private Long status;
+
+
+}

+ 8 - 1
fs-company/src/main/java/com/fs/core/exception/FSExceptionHandler.java

@@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.servlet.NoHandlerFoundException;
 
+import java.sql.SQLSyntaxErrorException;
+
 
 /**
  * 异常处理器
@@ -53,11 +55,16 @@ public class FSExceptionHandler {
 		return R.error("数据库中已存在该记录");
 	}
 
+	@ExceptionHandler(SQLSyntaxErrorException.class)
+	public R handleSQLSyntaxErrorException(SQLSyntaxErrorException e){
+		logger.error(e.getMessage(), e);
+		return R.error("SQL语法错误,请联系管理员!");
+	}
 
 	@ExceptionHandler(Exception.class)
 	public R handleException(Exception e){
 		logger.error(e.getMessage(), e);
-		return R.error();
+		return R.error(e.getMessage());
 	}
 
 

+ 0 - 1
fs-company/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java

@@ -185,7 +185,6 @@ public class FsCourseWatchLogController extends BaseController
     @GetMapping("/myList")
     public TableDataInfo myList(FsCourseWatchLogListParam param)
     {
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);

+ 104 - 0
fs-company/src/main/java/com/fs/transfer/CustomerTransferApprovalController.java

@@ -0,0 +1,104 @@
+package com.fs.transfer;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.core.security.LoginUser;
+import com.fs.core.web.service.TokenService;
+import com.fs.qw.domain.CustomerTransferApproval;
+import com.fs.qw.service.ICustomerTransferApprovalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 客户转移审批Controller
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+@RestController
+@RequestMapping("/system/approval")
+public class CustomerTransferApprovalController extends BaseController
+{
+    @Autowired
+    private ICustomerTransferApprovalService customerTransferApprovalService;
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询客户转移审批列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CustomerTransferApproval customerTransferApproval)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        customerTransferApproval.setInitiatorUserId(loginUser.getUser().getUserId());
+        List<CustomerTransferApproval> list = customerTransferApprovalService.selectCustomerTransferApprovalList(customerTransferApproval);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出客户转移审批列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:export')")
+    @Log(title = "客户转移审批", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CustomerTransferApproval customerTransferApproval)
+    {
+        List<CustomerTransferApproval> list = customerTransferApprovalService.selectCustomerTransferApprovalList(customerTransferApproval);
+        ExcelUtil<CustomerTransferApproval> util = new ExcelUtil<CustomerTransferApproval>(CustomerTransferApproval.class);
+        return util.exportExcel(list, "approval");
+    }
+
+    /**
+     * 获取客户转移审批详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(customerTransferApprovalService.selectCustomerTransferApprovalById(id));
+    }
+
+    /**
+     * 新增客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:add')")
+    @Log(title = "客户转移审批", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CustomerTransferApproval customerTransferApproval)
+    {
+        return toAjax(customerTransferApprovalService.insertCustomerTransferApproval(customerTransferApproval));
+    }
+
+    /**
+     * 修改客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:edit')")
+    @Log(title = "客户转移审批", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CustomerTransferApproval customerTransferApproval)
+    {
+        return toAjax(customerTransferApprovalService.updateCustomerTransferApproval(customerTransferApproval));
+    }
+
+    /**
+     * 删除客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:remove')")
+    @Log(title = "客户转移审批", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(customerTransferApprovalService.deleteCustomerTransferApprovalByIds(ids));
+    }
+}

+ 84 - 0
fs-company/src/main/java/com/fs/users/controller/MyCompanyCustomerController.java

@@ -0,0 +1,84 @@
+package com.fs.users.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.ServletUtils;
+import com.fs.core.security.LoginUser;
+import com.fs.core.web.service.TokenService;
+import com.fs.qw.domain.CustomerTransferApproval;
+import com.fs.qw.service.ICustomerTransferApprovalService;
+import com.fs.store.dto.FsUserTransferParamDTO;
+import com.fs.store.param.SelectCusListPageParam;
+import com.fs.store.service.IFsUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+
+/**
+ * 客户转移审批Controller
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+@Slf4j
+@RestController
+@RequestMapping("/fsuser/user")
+public class MyCompanyCustomerController {
+
+    @Autowired
+    private ICustomerTransferApprovalService transferApprovalService;
+
+    @Autowired
+    private IFsUserService fsUserService;
+
+    @Autowired
+    private TokenService tokenService;
+
+
+    /**
+     * 列出当前公司的客户
+     * @param param 参数
+     * @return 返回数据
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(SelectCusListPageParam param){
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getCompany().getCompanyId();
+        param.setCompanyId(companyId);
+        return fsUserService.selectCusListPage(param);
+    }
+    /**
+     * 导出
+     */
+    @PostMapping("/export")
+    public void export(){
+
+    }
+    /**
+     * 转移
+     * @param param
+     */
+    @PostMapping("/transfer")
+    public R transfer(@RequestBody FsUserTransferParamDTO param){
+        log.info("客户转移: {}",param);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setSourceCompanyUserId(loginUser.getUser().getUserId());
+        CustomerTransferApproval customerTransferApproval = new CustomerTransferApproval();
+        customerTransferApproval.setCorpId(String.valueOf(loginUser.getCompany().getCompanyId()));
+        customerTransferApproval.setCustomerIds(JSON.toJSONString(param.getUserIds()));
+        customerTransferApproval.setOriginalUserId(param.getSourceCompanyUserId());
+        customerTransferApproval.setTargetUserId(param.getTargetCompanyUserId());
+        customerTransferApproval.setInitiatorUserId(param.getSourceCompanyUserId());
+        customerTransferApproval.setContent(param.getContent());
+        customerTransferApproval.setCreatedAt(new Date());
+        customerTransferApproval.setUpdatedAt(new Date());
+        customerTransferApproval.setApprovalStatus(0);
+        customerTransferApproval.setTransferType(2);
+        transferApprovalService.insertCustomerTransferApproval(customerTransferApproval);
+        return R.ok("转移申请已经提交,等待总后台审核!");
+    }
+
+}

+ 66 - 0
fs-service-system/src/main/java/com/fs/company/domain/CompanyTag.java

@@ -0,0 +1,66 @@
+package com.fs.company.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * company对象 company_tag
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public class CompanyTag extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long tagId;
+
+    /** 企业id */
+    @Excel(name = "企业id")
+    private Long companyId;
+
+    /** 标签 */
+    @Excel(name = "标签")
+    private String tag;
+
+    public void setTagId(Long tagId)
+    {
+        this.tagId = tagId;
+    }
+
+    public Long getTagId()
+    {
+        return tagId;
+    }
+    public void setCompanyId(Long companyId)
+    {
+        this.companyId = companyId;
+    }
+
+    public Long getCompanyId()
+    {
+        return companyId;
+    }
+    public void setTag(String tag)
+    {
+        this.tag = tag;
+    }
+
+    public String getTag()
+    {
+        return tag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+            .append("tagId", getTagId())
+            .append("companyId", getCompanyId())
+            .append("tag", getTag())
+            .append("createTime", getCreateTime())
+            .toString();
+    }
+}

+ 94 - 0
fs-service-system/src/main/java/com/fs/company/domain/CompanyTagUser.java

@@ -0,0 +1,94 @@
+package com.fs.company.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * company对象 company_tag_user
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public class CompanyTagUser extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 标签id */
+    @Excel(name = "标签id")
+    private String tagIds;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 员工id */
+    @Excel(name = "员工id")
+    private Long companyUserId;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setTagIds(String tagIds)
+    {
+        this.tagIds = tagIds;
+    }
+
+    public String getTagIds()
+    {
+        return tagIds;
+    }
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+    public void setCompanyId(Long companyId)
+    {
+        this.companyId = companyId;
+    }
+
+    public Long getCompanyId()
+    {
+        return companyId;
+    }
+    public void setCompanyUserId(Long companyUserId)
+    {
+        this.companyUserId = companyUserId;
+    }
+
+    public Long getCompanyUserId()
+    {
+        return companyUserId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("tagIds", getTagIds())
+            .append("userId", getUserId())
+            .append("companyId", getCompanyId())
+            .append("companyUserId", getCompanyUserId())
+            .append("createTime", getCreateTime())
+            .toString();
+    }
+}

+ 61 - 0
fs-service-system/src/main/java/com/fs/company/mapper/CompanyTagMapper.java

@@ -0,0 +1,61 @@
+package com.fs.company.mapper;
+
+import java.util.List;
+import com.fs.company.domain.CompanyTag;
+
+/**
+ * companyMapper接口
+ * 
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface CompanyTagMapper 
+{
+    /**
+     * 查询company
+     * 
+     * @param tagId companyID
+     * @return company
+     */
+    public CompanyTag selectCompanyTagById(Long tagId);
+
+    /**
+     * 查询company列表
+     * 
+     * @param companyTag company
+     * @return company集合
+     */
+    public List<CompanyTag> selectCompanyTagList(CompanyTag companyTag);
+
+    /**
+     * 新增company
+     * 
+     * @param companyTag company
+     * @return 结果
+     */
+    public int insertCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 修改company
+     * 
+     * @param companyTag company
+     * @return 结果
+     */
+    public int updateCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 删除company
+     * 
+     * @param tagId companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagById(Long tagId);
+
+    /**
+     * 批量删除company
+     * 
+     * @param tagIds 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteCompanyTagByIds(Long[] tagIds);
+}

+ 66 - 0
fs-service-system/src/main/java/com/fs/company/mapper/CompanyTagUserMapper.java

@@ -0,0 +1,66 @@
+package com.fs.company.mapper;
+
+import java.util.List;
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * companyMapper接口
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface CompanyTagUserMapper
+{
+    /**
+     * 查询company
+     *
+     * @param id companyID
+     * @return company
+     */
+    public CompanyTagUser selectCompanyTagUserById(Long id);
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTagUser company
+     * @return company集合
+     */
+    public List<CompanyTagUser> selectCompanyTagUserList(CompanyTagUser companyTagUser);
+
+    /**
+     * 新增company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int insertCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 修改company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int updateCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 删除company
+     *
+     * @param id companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserById(Long id);
+
+    /**
+     * 批量删除company
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserByIds(Long[] ids);
+
+    List<CompanyUserTagListVO> getTagList(@Param("param") TagListParam param, @Param("keywords") String[] keywords, @Param("userIds") List<Long> userIds);
+}

+ 5 - 2
fs-service-system/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -240,8 +240,6 @@ public interface CompanyUserMapper
     @Select("select qw_user_id FROM company_user where user_id=#{companyUserId}")
     String selectQwUserIdsByCompany(Long companyUserId);
 
-    List<String> selectCompanyUserNameByIds(@Param("companyUserIds")String companyUserIds);
-
     @Select("select * from company_user where user_id=#{userId}")
     CompanyUser selectCompanyUserByUserId(Long userId);
 
@@ -255,4 +253,9 @@ public interface CompanyUserMapper
      * @return  list
      */
     List<CompanyUser> selectCompanyUserByIds(Set<Long> ids);
+
+    List<CompanyUser> selectAllCompanyUserByParentId(Long parentId);
+
+    List<CompanyUser> getAllUserListLimit(@Param("companyId") Long companyId,
+                                          @Param("keywords") String keywords);
 }

+ 61 - 0
fs-service-system/src/main/java/com/fs/company/service/ICompanyTagService.java

@@ -0,0 +1,61 @@
+package com.fs.company.service;
+
+import java.util.List;
+import com.fs.company.domain.CompanyTag;
+
+/**
+ * companyService接口
+ * 
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface ICompanyTagService 
+{
+    /**
+     * 查询company
+     * 
+     * @param tagId companyID
+     * @return company
+     */
+    public CompanyTag selectCompanyTagById(Long tagId);
+
+    /**
+     * 查询company列表
+     * 
+     * @param companyTag company
+     * @return company集合
+     */
+    public List<CompanyTag> selectCompanyTagList(CompanyTag companyTag);
+
+    /**
+     * 新增company
+     * 
+     * @param companyTag company
+     * @return 结果
+     */
+    public int insertCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 修改company
+     * 
+     * @param companyTag company
+     * @return 结果
+     */
+    public int updateCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 批量删除company
+     * 
+     * @param tagIds 需要删除的companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagByIds(Long[] tagIds);
+
+    /**
+     * 删除company信息
+     * 
+     * @param tagId companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagById(Long tagId);
+}

+ 71 - 0
fs-service-system/src/main/java/com/fs/company/service/ICompanyTagUserService.java

@@ -0,0 +1,71 @@
+package com.fs.company.service;
+
+import java.util.List;
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+
+/**
+ * companyService接口
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface ICompanyTagUserService
+{
+    /**
+     * 查询company
+     *
+     * @param id companyID
+     * @return company
+     */
+    public CompanyTagUser selectCompanyTagUserById(Long id);
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTagUser company
+     * @return company集合
+     */
+    public List<CompanyTagUser> selectCompanyTagUserList(CompanyTagUser companyTagUser);
+
+    /**
+     * 新增company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int insertCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 修改company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int updateCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 批量删除company
+     *
+     * @param ids 需要删除的companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserByIds(Long[] ids);
+
+    /**
+     * 删除company信息
+     *
+     * @param id companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserById(Long id);
+
+    /**
+     * 标签分页列表
+     * @param param 分页参数
+     * @return
+     */
+    List<CompanyUserTagListVO> getTagList(TagListParam param);
+
+}

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

@@ -134,4 +134,8 @@ public interface ICompanyUserService {
      * @return  list
      */
     List<CompanyUser> selectCompanyUserByIds(Set<Long> ids);
+
+    List<CompanyUser> selectAllCompanyUserByParentId(Long parentId);
+
+    List<CompanyUser> getAllUserListLimit(Long companyId, String keywords);
 }

+ 95 - 0
fs-service-system/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java

@@ -0,0 +1,95 @@
+package com.fs.company.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.company.mapper.CompanyTagMapper;
+import com.fs.company.domain.CompanyTag;
+import com.fs.company.service.ICompanyTagService;
+
+/**
+ * companyService业务层处理
+ * 
+ * @author fs
+ * @date 2025-04-02
+ */
+@Service
+public class CompanyTagServiceImpl implements ICompanyTagService 
+{
+    @Autowired
+    private CompanyTagMapper companyTagMapper;
+
+    /**
+     * 查询company
+     * 
+     * @param tagId companyID
+     * @return company
+     */
+    @Override
+    public CompanyTag selectCompanyTagById(Long tagId)
+    {
+        return companyTagMapper.selectCompanyTagById(tagId);
+    }
+
+    /**
+     * 查询company列表
+     * 
+     * @param companyTag company
+     * @return company
+     */
+    @Override
+    public List<CompanyTag> selectCompanyTagList(CompanyTag companyTag)
+    {
+        return companyTagMapper.selectCompanyTagList(companyTag);
+    }
+
+    /**
+     * 新增company
+     * 
+     * @param companyTag company
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyTag(CompanyTag companyTag)
+    {
+        companyTag.setCreateTime(DateUtils.getNowDate());
+        return companyTagMapper.insertCompanyTag(companyTag);
+    }
+
+    /**
+     * 修改company
+     * 
+     * @param companyTag company
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyTag(CompanyTag companyTag)
+    {
+        return companyTagMapper.updateCompanyTag(companyTag);
+    }
+
+    /**
+     * 批量删除company
+     * 
+     * @param tagIds 需要删除的companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagByIds(Long[] tagIds)
+    {
+        return companyTagMapper.deleteCompanyTagByIds(tagIds);
+    }
+
+    /**
+     * 删除company信息
+     * 
+     * @param tagId companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagById(Long tagId)
+    {
+        return companyTagMapper.deleteCompanyTagById(tagId);
+    }
+}

+ 124 - 0
fs-service-system/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java

@@ -0,0 +1,124 @@
+package com.fs.company.service.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.company.mapper.CompanyTagUserMapper;
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.company.service.ICompanyTagUserService;
+
+/**
+ * companyService业务层处理
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+@Service
+public class CompanyTagUserServiceImpl implements ICompanyTagUserService
+{
+    @Autowired
+    private CompanyTagUserMapper companyTagUserMapper;
+
+    @Autowired
+    private CompanyUserMapper  companyUserMapper;
+
+    /**
+     * 查询company
+     *
+     * @param id companyID
+     * @return company
+     */
+    @Override
+    public CompanyTagUser selectCompanyTagUserById(Long id)
+    {
+        return companyTagUserMapper.selectCompanyTagUserById(id);
+    }
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTagUser company
+     * @return company
+     */
+    @Override
+    public List<CompanyTagUser> selectCompanyTagUserList(CompanyTagUser companyTagUser)
+    {
+        return companyTagUserMapper.selectCompanyTagUserList(companyTagUser);
+    }
+
+    /**
+     * 新增company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyTagUser(CompanyTagUser companyTagUser)
+    {
+        companyTagUser.setCreateTime(DateUtils.getNowDate());
+        return companyTagUserMapper.insertCompanyTagUser(companyTagUser);
+    }
+
+    /**
+     * 修改company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyTagUser(CompanyTagUser companyTagUser)
+    {
+        return companyTagUserMapper.updateCompanyTagUser(companyTagUser);
+    }
+
+    /**
+     * 批量删除company
+     *
+     * @param ids 需要删除的companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagUserByIds(Long[] ids)
+    {
+        return companyTagUserMapper.deleteCompanyTagUserByIds(ids);
+    }
+
+    /**
+     * 删除company信息
+     *
+     * @param id companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagUserById(Long id)
+    {
+        return companyTagUserMapper.deleteCompanyTagUserById(id);
+    }
+
+    @Override
+    public List<CompanyUserTagListVO> getTagList(TagListParam param) {
+        String[] keywords = new String[0];
+        if (param != null) {
+            if (StringUtils.isNotEmpty(param.getKeyword())) {
+                keywords = param.getKeyword().split(",");
+            }
+        }
+        //获取所有销售
+        List<CompanyUser> companyUsers = companyUserMapper.selectAllCompanyUserByParentId(param != null ? param.getUserId() : null);
+        List<Long> userIds = Collections.emptyList();
+        if(companyUsers != null && !companyUsers.isEmpty()){
+            userIds = companyUsers.stream().map(CompanyUser::getUserId).collect(Collectors.toList());
+        }
+
+        return companyTagUserMapper.getTagList(param, keywords, userIds);
+    }
+}

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

@@ -396,4 +396,15 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         return companyUserMapper.selectCompanyUserByIds(ids);
     }
 
+    @Override
+    public  List<CompanyUser> selectAllCompanyUserByParentId(Long parentId) {
+        return companyUserMapper.selectAllCompanyUserByParentId(parentId);
+    }
+
+    @Override
+    public List<CompanyUser> getAllUserListLimit(Long companyId, String keywords) {
+
+        return companyUserMapper.getAllUserListLimit(companyId,keywords);
+    }
+
 }

+ 20 - 2
fs-service-system/src/main/java/com/fs/course/HuaweiCloudTest.java

@@ -1,5 +1,7 @@
 package com.fs.course;
 
+import com.fs.common.core.domain.R;
+import com.fs.course.config.RedPacketConfig;
 import lombok.extern.slf4j.Slf4j;
 
 
@@ -13,11 +15,27 @@ import java.util.*;
 public class HuaweiCloudTest {
 
     public static void main(String[] args) {
-        String testUrl = "https://tcpv.ylrzcloud.com/course/20241015/1728981064466.mp4";
-        String result = extractPathByRegex(testUrl);
+        RedPacketConfig config = new RedPacketConfig();
+        config.setIsNew(1);
+        R result = new R();
+        // 根据 isNew 判断使用哪种发红包方式
+        if (config.getIsNew() != null && config.getIsNew() == 1) {
+            result = test1();
+        } else {
+            result= test2();
+        }
+        result.put("isNew",config.getIsNew());
         System.out.println(result);
     }
 
+    public static R test1(){
+        return R.ok().put("code",1);
+    }
+
+    public static R test2(){
+        return R.ok().put("data",2);
+    }
+
     public static String extractPathByRegex(String urlString) {
         // ^https?://   匹配 http:// 或 https:// 开头
         // [^/]+        匹配域名部分(直到遇到第一个 '/')

+ 2 - 0
fs-service-system/src/main/java/com/fs/course/config/RedPacketConfig.java

@@ -48,4 +48,6 @@ public class RedPacketConfig implements Serializable {
     private String publicKeyPath;
 
     private String notifyUrl;
+
+    private Integer isNew;//0:老商户 商家转账到零钱 1:新商户 商家转账
 }

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

@@ -5,6 +5,7 @@ import com.fs.course.domain.FsUserCourse;
 import com.fs.course.param.FsUserCourseAddStudyCourseParam;
 import com.fs.course.param.FsUserCourseListUParam;
 import com.fs.course.param.FsUserCourseParam;
+import com.fs.course.param.newfs.FsUserCourseListParam;
 import com.fs.course.vo.*;
 import com.fs.his.vo.OptionsVO;
 import org.apache.ibatis.annotations.Param;
@@ -227,4 +228,6 @@ public interface FsUserCourseMapper
     @Select("select course_id ,img_url   from fs_user_course where is_del = 0 and is_private = 1")
     List<FsUserCourse> selectFsUserCourseAllCourseByQw();
 
+    List<FsUserCourseListPVO> getFsUserCourseList(FsUserCourseListParam param);
+
 }

+ 4 - 0
fs-service-system/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java

@@ -4,8 +4,10 @@ import java.util.List;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.param.FsUserCourseVideoListUParam;
 import com.fs.course.param.FsUserCourseVideoParam;
+import com.fs.course.param.newfs.UserCourseVideoPageParam;
 import com.fs.course.vo.FsUserCourseVideoListUVO;
 import com.fs.course.vo.FsUserCourseVideoVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.his.vo.OptionsVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
@@ -160,4 +162,6 @@ public interface FsUserCourseVideoMapper
     @Select("select video_id from fs_user_course_video WHERE is_first=1")
     List<Long> selectVideoByFirst();
 
+    List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoPageList(UserCourseVideoPageParam param);
+
 }

+ 22 - 0
fs-service-system/src/main/java/com/fs/course/param/newfs/FsUserCourseListParam.java

@@ -0,0 +1,22 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class FsUserCourseListParam {
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum = 1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "模糊搜索,通过视频名称来匹配")
+    private String keyword;
+
+    @ApiModelProperty(value = "公司id,不用传")
+    private Long companyId;
+
+
+}

+ 29 - 0
fs-service-system/src/main/java/com/fs/course/param/newfs/UserCourseVideoPageParam.java

@@ -0,0 +1,29 @@
+package com.fs.course.param.newfs;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel
+public class UserCourseVideoPageParam implements Serializable {
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum = 1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "模糊搜索,通过视频名称来匹配")
+    private String keyword;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+//    @ApiModelProperty(value = "视频状态 1:草稿,2:待审核,3:发布")
+//    private Long status;
+
+}

+ 7 - 0
fs-service-system/src/main/java/com/fs/course/service/IFsUserCourseService.java

@@ -8,6 +8,7 @@ import com.fs.course.param.FsUserCourseAddStudyCourseParam;
 import com.fs.course.param.FsUserCourseGetIntegralParam;
 import com.fs.course.param.FsUserCourseListUParam;
 import com.fs.course.param.FsUserCourseParam;
+import com.fs.course.param.newfs.FsUserCourseListParam;
 import com.fs.course.vo.*;
 import com.fs.his.vo.OptionsVO;
 
@@ -102,4 +103,10 @@ public interface IFsUserCourseService
     FsUserCourseVideoH5DVO selectFsUserCourseVideoH5DVOByVideoId(Long videoId);
 
     List<FsUserCourseListPVO> selectFsUserCourseListCompanyPVO(FsUserCourseParam fsUserCourse);
+
+    /**
+     * h5 获取用户课程下拉列表
+     * @return
+     */
+    List<FsUserCourseListPVO> getFsUserCourseList(FsUserCourseListParam param);
 }

+ 16 - 0
fs-service-system/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -1,9 +1,13 @@
 package com.fs.course.service;
 
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.param.*;
+import com.fs.course.param.newfs.UserCourseVideoPageParam;
 import com.fs.course.vo.FsUserCourseVideoListUVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.FsUserCourseVideoQVO;
 import com.fs.course.vo.FsUserCourseVideoVO;
 
@@ -88,4 +92,16 @@ public interface IFsUserCourseVideoService
 
     R sendReward(FsCourseSendRewardUParam param);
 
+    /**
+     * 获取课程视频分页列表
+     * @return FsUserCourseVideoPageListVO
+     */
+    List<FsUserCourseVideoPageListVO> pageListCourseVideo(UserCourseVideoPageParam param);
+
+    /**
+     * 获取课程视频详情
+     * @return FsUserCourseVideoDetailsVO
+     */
+    ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId);
+
 }

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

@@ -52,6 +52,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 

+ 6 - 6
fs-service-system/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -14,18 +14,13 @@ import com.fs.course.param.FsUserCourseAddStudyCourseParam;
 import com.fs.course.param.FsUserCourseGetIntegralParam;
 import com.fs.course.param.FsUserCourseListUParam;
 import com.fs.course.param.FsUserCourseParam;
+import com.fs.course.param.newfs.FsUserCourseListParam;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.vo.*;
-import com.fs.store.domain.FsUser;
-import com.fs.store.domain.FsUserIntegralLogs;
-import com.fs.store.mapper.FsUserIntegralLogsMapper;
-import com.fs.store.mapper.FsUserMapper;
 import com.fs.his.vo.OptionsVO;
-import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
@@ -368,4 +363,9 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
     public List<FsUserCourseListPVO> selectFsUserCourseListCompanyPVO(FsUserCourseParam fsUserCourse) {
         return fsUserCourseMapper.selectFsUserCourseListCompanyPVO(fsUserCourse);
     }
+
+    @Override
+    public List<FsUserCourseListPVO> getFsUserCourseList(FsUserCourseListParam param) {
+        return fsUserCourseMapper.getFsUserCourseList(param);
+    }
 }

+ 57 - 11
fs-service-system/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
@@ -13,10 +14,14 @@ import com.fs.course.domain.*;
 import com.fs.course.dto.CoursePackageDTO;
 import com.fs.course.mapper.*;
 import com.fs.course.param.*;
+import com.fs.course.param.newfs.UserCourseVideoPageParam;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.vo.FsUserCourseVideoListUVO;
 import com.fs.course.vo.FsUserCourseVideoQVO;
 import com.fs.course.vo.FsUserCourseVideoVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
+import com.fs.course.vo.newfs.FsUserVideoQuestionVO;
 import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.store.domain.FsUser;
 import com.fs.store.domain.FsUserIntegralLogs;
@@ -33,6 +38,7 @@ import com.fs.qwApi.param.QwAddContactWayParam;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.system.service.ISysConfigService;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -43,9 +49,11 @@ import org.springframework.transaction.annotation.Transactional;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDateTime;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * 课堂视频Service业务层处理
@@ -604,10 +612,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return R.error("参数错误!");
         }
     }
-    
+
     /**
      * 发放红包奖励
-     * 
+     *
      * @param param 请求参数
      * @param user 用户信息
      * @param log 观看日志
@@ -619,13 +627,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
         FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId());
-        
+
         if (redPackage != null) {
             amount = redPackage.getRedPacketMoney();
         } else if (video != null) {
             amount = new BigDecimal(video.getRedPacketMoney());
         }
-        
+
         // 准备发送红包参数
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
         packetParam.setOpenId(user.getMpOpenId());
@@ -635,12 +643,22 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
         packetParam.setAmount(amount);
         packetParam.setSource(param.getSource());
-        
+        packetParam.setRedPacketMode(config.getRedPacketMode());
+        packetParam.setCompanyId(param.getCompanyId());
+
+
         // 发送红包
         R sendRedPacket = paymentService.sendRedPacket(packetParam);
         if (sendRedPacket.get("code").equals(200)) {
-            // 添加红包记录
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+            TransferBillsResult transferBillsResult;
+            if (sendRedPacket.get("isNew").equals(1)){
+                transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+            }else {
+                redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+            }
+            // 添加红包记录
             redPacketLog.setCourseId(param.getCourseId());
             redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
             redPacketLog.setCompanyId(param.getCompanyId());
@@ -653,7 +671,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             redPacketLog.setAmount(amount);
             redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-            
+
             // 更新观看记录的奖励类型
             if (param.getLinkType() == null || param.getLinkType() == 0) {
                 log.setRewardType(config.getRewardType());
@@ -664,10 +682,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return R.error("奖励发送失败,请联系客服");
         }
     }
-    
+
     /**
      * 发放积分奖励
-     * 
+     *
      * @param user 用户信息
      * @param log 观看日志
      * @param config 配置信息
@@ -679,7 +697,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         userMap.setUserId(user.getUserId());
         userMap.setIntegral(NumberUtil.add(user.getIntegral(), config.getAnswerIntegral()));
         fsUserMapper.updateFsUser(userMap);
-        
+
         // 记录积分日志
         FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
         integralLogs.setIntegral(new BigDecimal(config.getAnswerIntegral()));
@@ -689,7 +707,35 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         integralLogs.setBusinessId(StringUtils.isNotEmpty(log.getLogId().toString()) ? log.getLogId().toString() : null);
         integralLogs.setCreateTime(new Date());
         fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
-        
+
         return R.ok("奖励发放成功");
     }
+
+    @Override
+    public List<FsUserCourseVideoPageListVO> pageListCourseVideo(UserCourseVideoPageParam param) {
+        return fsUserCourseVideoMapper.selectFsUserCourseVideoPageList(param);
+    }
+
+    @Override
+    public ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId) {
+        FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        FsUserCourseVideoDetailsVO fsUserCourseVideoDetailsVO = new FsUserCourseVideoDetailsVO();
+        BeanUtils.copyProperties(fsUserCourseVideo, fsUserCourseVideoDetailsVO);
+
+        // 获取课程相关的题库
+        String questionBankId = fsUserCourseVideo.getQuestionBankId();
+        List<FsUserVideoQuestionVO> questionList = Collections.emptyList();
+        if (StringUtils.isNotEmpty(questionBankId)) {
+            String[] questionBankIds = questionBankId.split(",");
+            List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(questionBankIds);
+            questionList = fsCourseQuestionBanks.stream().map(v -> {
+                FsUserVideoQuestionVO fsUserVideoQuestionVO = new FsUserVideoQuestionVO();
+                BeanUtils.copyProperties(v, fsUserVideoQuestionVO);
+                return fsUserVideoQuestionVO;
+            }).collect(Collectors.toList());
+        }
+
+        fsUserCourseVideoDetailsVO.setQuestionBankList(questionList);
+        return ResponseResult.ok(fsUserCourseVideoDetailsVO);
+    }
 }

+ 3 - 1
fs-service-system/src/main/java/com/fs/course/vo/FsUserCourseListPVO.java

@@ -1,6 +1,7 @@
 package com.fs.course.vo;
 
 import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.math.BigDecimal;
@@ -16,9 +17,10 @@ public class FsUserCourseListPVO extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
 
+    @ApiModelProperty(value = "课程id")
     private Long courseId;
 
-    /** 课程名称 */
+    @ApiModelProperty(value = "课程名称")
     private String courseName;
 
     /** 课程封面 */

+ 37 - 0
fs-service-system/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoDetailsVO.java

@@ -0,0 +1,37 @@
+package com.fs.course.vo.newfs;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@ApiModel
+public class FsUserCourseVideoDetailsVO {
+
+    @ApiModelProperty(value = "课程视频id")
+    private Long videoId;
+
+    @ApiModelProperty(value = "视频标题")
+    private String title;
+
+    @ApiModelProperty(value = "视频描述")
+    private String description;
+
+    @ApiModelProperty(value = "视频URL")
+    private String videoUrl;
+
+    @ApiModelProperty(value = "视频缩略图")
+    private String thumbnail;
+
+    @ApiModelProperty(value = "视频时长")
+    private Long duration;
+
+    @ApiModelProperty(value = "课程ID")
+    private Long courseId;
+
+    @ApiModelProperty(value = "题库内容")
+    private List<FsUserVideoQuestionVO> questionBankList;
+
+}

+ 47 - 0
fs-service-system/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoPageListVO.java

@@ -0,0 +1,47 @@
+package com.fs.course.vo.newfs;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsUserCourseVideoPageListVO extends BaseEntity {
+
+    @ApiModelProperty(value = "课程视频id")
+    private Long videoId;
+
+    @ApiModelProperty(value = "视频标题")
+    private String title;
+
+    @ApiModelProperty(value = "视频描述")
+    private String description;
+
+    @ApiModelProperty(value = "视频缩略图")
+    private String thumbnail;
+
+    @ApiModelProperty(value = "视频时长")
+    private Long duration;
+
+    @ApiModelProperty(value = "课程ID")
+    private Long courseId;
+
+    @ApiModelProperty(value = "视频状态 1:草稿,2:待审核,3:发布")
+    private Long status;
+
+    @ApiModelProperty(value = "课程排序")
+    private Long courseSort;
+
+    @ApiModelProperty(value = "课程名称")
+    private String courseName;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+
+
+}

+ 38 - 0
fs-service-system/src/main/java/com/fs/course/vo/newfs/FsUserVideoQuestionVO.java

@@ -0,0 +1,38 @@
+package com.fs.course.vo.newfs;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 课程视频题库
+ */
+@Data
+@ApiModel
+public class FsUserVideoQuestionVO {
+
+    @ApiModelProperty(value = "id")
+    private Long id;
+
+    @ApiModelProperty(value = "问题")
+    private String title;
+
+    @ApiModelProperty(value = "排序")
+    private Long sort;
+
+    @ApiModelProperty(value = "类别,1-单选,2-多选 ")
+    private Long type;
+
+    @ApiModelProperty(value = "状态")
+    private Long status;
+
+    @ApiModelProperty(value = "问题类别")
+    private String questionType;
+
+    @ApiModelProperty(value = "选项")
+    private String question;
+
+    @ApiModelProperty(value = "答案")
+    private String answer;
+
+}

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

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

+ 102 - 0
fs-service-system/src/main/java/com/fs/qw/domain/CustomerTransferApproval.java

@@ -0,0 +1,102 @@
+package com.fs.qw.domain;
+
+import java.util.Date;
+import java.util.List;
+
+import cn.hutool.core.lang.Pair;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import com.fs.qw.vo.TransferCustomDTO;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 客户转移审批对象 customer_transfer_approval
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CustomerTransferApproval extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 唯一主键 ID */
+    private Long id;
+
+    /** 企业 ID */
+    @Excel(name = "企业 ID")
+    private String corpId;
+    private String companyName;
+
+    /** 转移类型: 1=离职继承, 2=在职转接 */
+    @Excel(name = "转移类型: 1=离职继承, 2=在职转接")
+    private Integer transferType;
+    private String transferTypeText;
+
+    /** 客户 ID 列表 (JSON 数组字符串或逗号分隔) */
+    @Excel(name = "客户 ID 列表 (JSON 数组字符串或逗号分隔)")
+    private String customerIds;
+    private List<TransferCustomDTO> customerList;
+
+    /** 原负责人用户 ID (离职继承时为离职人员ID,在职转接时为转出人员ID) */
+    @Excel(name = "原负责人用户 ID (离职继承时为离职人员ID,在职转接时为转出人员ID)")
+    private Long originalUserId;
+    private String originalUserName;
+
+    /** 目标接收销售用户 ID */
+    @Excel(name = "目标接收销售用户 ID")
+    private Long targetUserId;
+    private String targetUserName;
+
+    /** 发起此转移请求的用户 ID */
+    @Excel(name = "发起此转移请求的用户 ID")
+    private Long initiatorUserId;
+    private String initiatorUserName;
+
+    /**
+     * 转移前数据
+     */
+    private String transferBefore;
+
+    /** 转移提示内容/原因 */
+    @Excel(name = "转移提示内容/原因")
+    private String content;
+
+    /** 审批状态: 0=待审批, 1=审批通过, 2=审批驳回, 3=已撤销 */
+    @Excel(name = "审批状态: 0=待审批, 1=审批通过, 2=审批驳回, 3=已撤销")
+    private Integer approvalStatus;
+    private String approvalStatusText;
+
+    /** 审批人用户 ID */
+    @Excel(name = "审批人用户 ID")
+    private Long approverUserId;
+
+    /** 审批意见/备注 */
+    @Excel(name = "审批意见/备注")
+    private String approvalRemark;
+
+    /** 审批处理时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "审批处理时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date processedAt;
+
+    /** 记录创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "记录创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date createdAt;
+
+    /** 记录最后更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "记录最后更新时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date updatedAt;
+
+}

+ 62 - 0
fs-service-system/src/main/java/com/fs/qw/mapper/CustomerTransferApprovalMapper.java

@@ -0,0 +1,62 @@
+package com.fs.qw.mapper;
+
+import com.fs.qw.domain.CustomerTransferApproval;
+
+import java.util.List;
+
+/**
+ * 客户转移审批Mapper接口
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+public interface CustomerTransferApprovalMapper
+{
+    /**
+     * 查询客户转移审批
+     *
+     * @param id 客户转移审批ID
+     * @return 客户转移审批
+     */
+    public CustomerTransferApproval selectCustomerTransferApprovalById(Long id);
+
+    /**
+     * 查询客户转移审批列表
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 客户转移审批集合
+     */
+    public List<CustomerTransferApproval> selectCustomerTransferApprovalList(CustomerTransferApproval customerTransferApproval);
+
+    /**
+     * 新增客户转移审批
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 结果
+     */
+    public int insertCustomerTransferApproval(CustomerTransferApproval customerTransferApproval);
+
+    /**
+     * 修改客户转移审批
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 结果
+     */
+    public int updateCustomerTransferApproval(CustomerTransferApproval customerTransferApproval);
+
+    /**
+     * 删除客户转移审批
+     *
+     * @param id 客户转移审批ID
+     * @return 结果
+     */
+    public int deleteCustomerTransferApprovalById(Long id);
+
+    /**
+     * 批量删除客户转移审批
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteCustomerTransferApprovalByIds(Long[] ids);
+}

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

@@ -6,8 +6,22 @@ import java.util.List;
 
 @Data
 public class TransferParam {
+
+    /**
+     * 客户id列表
+     */
     List<Long> ids;
+    /**
+     * 销售id
+     */
     Long  userId;
+
+    /**
+     * 企业id
+     */
     String corpId;
+    /**
+     * 转移提示内容
+     */
     String content;
 }

+ 62 - 0
fs-service-system/src/main/java/com/fs/qw/service/ICustomerTransferApprovalService.java

@@ -0,0 +1,62 @@
+package com.fs.qw.service;
+
+import com.fs.qw.domain.CustomerTransferApproval;
+
+import java.util.List;
+
+/**
+ * 客户转移审批Service接口
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+public interface ICustomerTransferApprovalService
+{
+    /**
+     * 查询客户转移审批
+     *
+     * @param id 客户转移审批ID
+     * @return 客户转移审批
+     */
+    public CustomerTransferApproval selectCustomerTransferApprovalById(Long id);
+
+    /**
+     * 查询客户转移审批列表
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 客户转移审批集合
+     */
+    public List<CustomerTransferApproval> selectCustomerTransferApprovalList(CustomerTransferApproval customerTransferApproval);
+
+    /**
+     * 新增客户转移审批
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 结果
+     */
+    public int insertCustomerTransferApproval(CustomerTransferApproval customerTransferApproval);
+
+    /**
+     * 修改客户转移审批
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 结果
+     */
+    public int updateCustomerTransferApproval(CustomerTransferApproval customerTransferApproval);
+
+    /**
+     * 批量删除客户转移审批
+     *
+     * @param ids 需要删除的客户转移审批ID
+     * @return 结果
+     */
+    public int deleteCustomerTransferApprovalByIds(Long[] ids);
+
+    /**
+     * 删除客户转移审批信息
+     *
+     * @param id 客户转移审批ID
+     * @return 结果
+     */
+    public int deleteCustomerTransferApprovalById(Long id);
+}

+ 269 - 0
fs-service-system/src/main/java/com/fs/qw/service/impl/CustomerTransferApprovalServiceImpl.java

@@ -0,0 +1,269 @@
+package com.fs.qw.service.impl;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.utils.DictUtils;
+import com.fs.company.cache.ICompanyCacheService;
+import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.qw.domain.CustomerTransferApproval;
+import com.fs.qw.mapper.CustomerTransferApprovalMapper;
+import com.fs.qw.service.ICustomerTransferApprovalService;
+import com.fs.qw.vo.TransferCustomDTO;
+import com.fs.store.domain.FsUser;
+import com.fs.store.dto.FsUserTransferParamDTO;
+import com.fs.store.service.IFsUserService;
+import com.fs.store.service.cache.IFsUserCacheService;
+import com.hc.openapi.tool.util.StringUtils;
+import org.apache.http.util.Asserts;
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 客户转移审批Service业务层处理
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+@Service
+@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)
+public class CustomerTransferApprovalServiceImpl implements ICustomerTransferApprovalService
+{
+    @Autowired
+    private CustomerTransferApprovalMapper customerTransferApprovalMapper;
+
+    @Autowired
+    private ICompanyUserCacheService companyUserCacheService;
+
+    @Autowired
+    private ICompanyCacheService companyCacheService;
+
+    @Autowired
+    private IFsUserCacheService fsUserCacheService;
+
+    @Autowired
+    private IFsUserService fsUserService;
+
+    /**
+     * 查询客户转移审批
+     *
+     * @param id 客户转移审批ID
+     * @return 客户转移审批
+     */
+    @Override
+    public CustomerTransferApproval selectCustomerTransferApprovalById(Long id)
+    {
+        CustomerTransferApproval item = customerTransferApprovalMapper.selectCustomerTransferApprovalById(id);
+
+        if(ObjectUtils.isNotNull(item.getCorpId())){
+            Company company = companyCacheService.selectCompanyById(Long.valueOf(item.getCorpId()));
+            if(ObjectUtils.isNotNull(company)){
+                item.setCompanyName(String.format("%s_%s",company.getCompanyName(),company.getCompanyId()));
+            }
+        }
+        if(ObjectUtils.isNotNull(item.getTransferType())){
+            String transferType = DictUtils.getDictLabel("transfer_type", String.valueOf(item.getTransferType()));
+            if(ObjectUtils.isNotEmpty(transferType)){
+                item.setTransferTypeText(transferType);
+            }
+        }
+        if(ObjectUtils.isNotNull(item.getApprovalStatus())){
+            String approvalStatus = DictUtils.getDictLabel("transfer_approval_status", String.valueOf(item.getApprovalStatus()));
+            if(ObjectUtils.isNotEmpty(approvalStatus)){
+                item.setApprovalStatusText(approvalStatus);
+            }
+        }
+
+        if(ObjectUtils.isNotNull(item.getOriginalUserId())){
+            CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getOriginalUserId());
+            if(ObjectUtils.isNotNull(companyUser)){
+                item.setOriginalUserName(String.format("%s_%d",companyUser.getUserName(),companyUser.getUserId()));
+            }
+        }
+
+        // 目标接收销售用户
+        if(ObjectUtils.isNotNull(item.getTargetUserId())){
+            CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getTargetUserId());
+            if(ObjectUtils.isNotNull(companyUser)){
+                item.setTargetUserName(String.format("%s_%d", companyUser.getUserName(), companyUser.getUserId()));
+            }
+        }
+
+        // 发起此转移请求的用户
+        if(ObjectUtils.isNotNull(item.getInitiatorUserId())){
+            CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getInitiatorUserId());
+            if(ObjectUtils.isNotNull(companyUser)){
+                item.setInitiatorUserName(String.format("%s_%d", companyUser.getUserName(), companyUser.getUserId()));
+            }
+        }
+
+        if(StringUtils.isBlank(item.getTransferBefore()) && StringUtils.isNotBlank(item.getCustomerIds())){
+            List<Long> customerIds = JSON.parseArray(item.getCustomerIds(), Long.class);
+            List<TransferCustomDTO> customerList = getCustomerList(customerIds, item);
+            item.setCustomerList(customerList);
+        } else {
+            List<TransferCustomDTO> customerList = JSON.parseArray(item.getTransferBefore(), TransferCustomDTO.class);
+            item.setCustomerList(customerList);
+        }
+        return item;
+    }
+
+    private List<TransferCustomDTO> getCustomerList(List<Long> customerIds, CustomerTransferApproval item) {
+        List<TransferCustomDTO> customerList = new ArrayList<>();
+
+        for (Long customerId : customerIds) {
+
+            FsUser fsUser = fsUserCacheService.selectFsUserById(customerId);
+            if(ObjectUtils.isNotNull(fsUser)){
+                String companyUserName = "无";
+                if(ObjectUtils.isNotNull(fsUser.getCompanyUserId())){
+                    CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(fsUser.getCompanyUserId());
+                    companyUserName = String.format("%s_%d", companyUser.getUserName(), companyUser.getUserId());
+                }
+
+                customerList.add(TransferCustomDTO.builder()
+                        .userName(String.format("%s_%d", fsUser.getNickname(), fsUser.getUserId()))
+                        .userId(fsUser.getUserId())
+                        .beforeCompanyUserName(companyUserName)
+                        .beforeCompanyUserId(fsUser.getCompanyUserId())
+                        .afterCompanyUserName(item.getTargetUserName())
+                        .afterCompanyUserId(item.getTargetUserId())
+                        .build());
+            }
+        }
+        return customerList;
+    }
+
+    /**
+     * 查询客户转移审批列表
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 客户转移审批
+     */
+    @Override
+    public List<CustomerTransferApproval> selectCustomerTransferApprovalList(CustomerTransferApproval customerTransferApproval)
+    {
+        List<CustomerTransferApproval> list = customerTransferApprovalMapper.selectCustomerTransferApprovalList(customerTransferApproval);
+        for (CustomerTransferApproval item : list) {
+            if(ObjectUtils.isNotNull(item.getCorpId())){
+                Company company = companyCacheService.selectCompanyById(Long.valueOf(item.getCorpId()));
+                if(ObjectUtils.isNotNull(company)){
+                    item.setCompanyName(String.format("%s_%s",company.getCompanyName(),company.getCompanyId()));
+                }
+            }
+            if(ObjectUtils.isNotNull(item.getTransferType())){
+                String transferType = DictUtils.getDictLabel("transfer_type", String.valueOf(item.getTransferType()));
+                if(ObjectUtils.isNotEmpty(transferType)){
+                    item.setTransferTypeText(transferType);
+                }
+            }
+            if(ObjectUtils.isNotNull(item.getApprovalStatus())){
+                String approvalStatus = DictUtils.getDictLabel("transfer_approval_status", String.valueOf(item.getApprovalStatus()));
+                if(ObjectUtils.isNotEmpty(approvalStatus)){
+                    item.setApprovalStatusText(approvalStatus);
+                }
+            }
+
+            if(ObjectUtils.isNotNull(item.getOriginalUserId())){
+                CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getOriginalUserId());
+                if(ObjectUtils.isNotNull(companyUser)){
+                    item.setOriginalUserName(String.format("%s_%d",companyUser.getUserName(),companyUser.getUserId()));
+                }
+            }
+
+            if(ObjectUtils.isNotNull(item.getTargetUserId())){
+                CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getTargetUserId());
+                if(ObjectUtils.isNotNull(companyUser)){
+                    item.setTargetUserName(String.format("%s_%d", companyUser.getUserName(), companyUser.getUserId()));
+                }
+            }
+
+            if(ObjectUtils.isNotNull(item.getInitiatorUserId())){
+                CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getInitiatorUserId());
+                if(ObjectUtils.isNotNull(companyUser)){
+                    item.setInitiatorUserName(String.format("%s_%d", companyUser.getUserName(), companyUser.getUserId()));
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 新增客户转移审批
+     *
+     * @param customerTransferApproval 客户转移审批
+     * @return 结果
+     */
+    @Override
+    public int insertCustomerTransferApproval(CustomerTransferApproval customerTransferApproval)
+    {
+        return customerTransferApprovalMapper.insertCustomerTransferApproval(customerTransferApproval);
+    }
+
+    /**
+     * 修改客户转移审批
+     *
+     * @param item 客户转移审批
+     * @return 结果
+     */
+    @Override
+    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
+    public int updateCustomerTransferApproval(CustomerTransferApproval item)
+    {
+        item.setProcessedAt(new Date());
+//        审批状态: 0=待审批, 1=审批通过, 2=审批驳回, 3=已撤销
+        // 如果审批通过 进行转移
+        if(ObjectUtil.equal(1,item.getApprovalStatus())){
+            FsUserTransferParamDTO transferParam = new FsUserTransferParamDTO();
+            transferParam.setContent(item.getContent());
+            transferParam.setTargetCompanyUserId(item.getTargetUserId());
+
+            Asserts.check(StringUtils.isNotBlank(item.getCustomerIds()),"转移客户不能为空!");
+            List<Long> customerIds = JSON.parseArray(item.getCustomerIds(), Long.class);
+            transferParam.setUserIds(customerIds);
+            transferParam.setSourceCompanyUserId(item.getOriginalUserId());
+
+            fsUserService.transfer(transferParam);
+        }
+        List<Long> customerIds = JSON.parseArray(item.getCustomerIds(), Long.class);
+        List<TransferCustomDTO> customerList = getCustomerList(customerIds, item);
+        item.setTransferBefore(JSON.toJSONString(customerList));
+        return customerTransferApprovalMapper.updateCustomerTransferApproval(item);
+    }
+
+    /**
+     * 批量删除客户转移审批
+     *
+     * @param ids 需要删除的客户转移审批ID
+     * @return 结果
+     */
+    @Override
+    public int deleteCustomerTransferApprovalByIds(Long[] ids)
+    {
+        return customerTransferApprovalMapper.deleteCustomerTransferApprovalByIds(ids);
+    }
+
+    /**
+     * 删除客户转移审批信息
+     *
+     * @param id 客户转移审批ID
+     * @return 结果
+     */
+    @Override
+    public int deleteCustomerTransferApprovalById(Long id)
+    {
+        return customerTransferApprovalMapper.deleteCustomerTransferApprovalById(id);
+    }
+}

+ 30 - 0
fs-service-system/src/main/java/com/fs/qw/vo/TransferCustomDTO.java

@@ -0,0 +1,30 @@
+package com.fs.qw.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class TransferCustomDTO implements Serializable {
+    /**
+     * 用户名
+     */
+    private String userName;
+    private Long userId;
+    /**
+     * 转移前销售
+     */
+    private String beforeCompanyUserName;
+    private Long beforeCompanyUserId;
+    /**
+     * 转移后销售
+     */
+    private String afterCompanyUserName;
+    private Long afterCompanyUserId;
+}

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

@@ -73,6 +73,7 @@ public class FsUser extends BaseEntity
     /** 1为正常,0为禁止 */
     @Excel(name = "状态:1为正常,0为禁止")
     private Integer status;
+    private String statusText;
 
     /** 等级 */
     private Integer level;
@@ -113,6 +114,7 @@ public class FsUser extends BaseEntity
     private Long companyId;
 
     private Long companyUserId;
+    private String companyUserName;
 
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "推线日期", width = 30, dateFormat = "yyyy-MM-dd")
@@ -146,7 +148,21 @@ public class FsUser extends BaseEntity
     public void setCourseMaOpenId(String courseMaOpenId) {
         this.courseMaOpenId = courseMaOpenId;
     }
+    public String getStatusText() {
+        return statusText;
+    }
+
+    public void setStatusText(String statusText) {
+        this.statusText = statusText;
+    }
 
+    public String getCompanyUserName() {
+        return companyUserName;
+    }
+
+    public void setCompanyUserName(String companyUserName) {
+        this.companyUserName = companyUserName;
+    }
     public Integer getIsAddQw() {
         return isAddQw;
     }

+ 14 - 0
fs-service-system/src/main/java/com/fs/store/domain/FsUserCourseCount.java

@@ -36,6 +36,10 @@ public class FsUserCourseCount extends BaseEntity
     @Excel(name = "缺课状态,1-已缺课;2-未缺课")
     private Long missCourseStatus;
 
+    /** 缺课天数 */
+    @Excel(name = "缺课天数")
+    private Long missCourseDays;
+
     /** 关联课程(营期)id */
     @Excel(name = "关联课程", readConverterExp = "营=期")
     private Long courseId;
@@ -115,6 +119,15 @@ public class FsUserCourseCount extends BaseEntity
     {
         return missCourseStatus;
     }
+    public void setMissCourseDays(Long missCourseDays)
+    {
+        this.missCourseDays = missCourseDays;
+    }
+
+    public Long getMissCourseDays()
+    {
+        return missCourseDays;
+    }
     public void setCourseId(Long courseId)
     {
         this.courseId = courseId;
@@ -196,6 +209,7 @@ public class FsUserCourseCount extends BaseEntity
             .append("watchCourseCount", getWatchCourseCount())
             .append("missCourseCount", getMissCourseCount())
             .append("missCourseStatus", getMissCourseStatus())
+            .append("missCourseDays", getMissCourseDays())
             .append("courseId", getCourseId())
             .append("partCourseCount", getPartCourseCount())
             .append("lastWatchDate", getLastWatchDate())

+ 31 - 0
fs-service-system/src/main/java/com/fs/store/dto/FsUserTransferParamDTO.java

@@ -0,0 +1,31 @@
+package com.fs.store.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 客户转移dto
+ */
+@Data
+public class FsUserTransferParamDTO implements Serializable {
+
+    /**
+     * 来源销售id
+     */
+    private Long sourceCompanyUserId;
+    /**
+     * 目标销售id
+     */
+    private Long targetCompanyUserId;
+    /**
+     * 客户id
+     */
+    private List<Long> userIds;
+
+    /**
+     * 转移提示内容/原因
+     */
+    private String content;
+}

+ 13 - 0
fs-service-system/src/main/java/com/fs/store/mapper/FsUserMapper.java

@@ -7,6 +7,8 @@ import com.fs.qw.vo.QwFsUserVO;
 import com.fs.qw.vo.newvo.ExternalContactNumVO;
 import com.fs.store.domain.FsStorePayment;
 import com.fs.store.domain.FsUser;
+import com.fs.store.dto.FsUserTransferParamDTO;
+import com.fs.store.param.SelectCusListPageParam;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.vo.FSUserVO;
 
@@ -217,4 +219,15 @@ public interface FsUserMapper
 
     UserDetailsVO getCountRedPacket(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
 
+    int batchUpdateFsUserByIds(@Param("ids") String[] ids, @Param("status") Integer status);
+
+    /**
+     * 分页获取客户
+     * @param param 参数
+     * @return 结果
+     */
+    List<FsUser> selectCusListPage(SelectCusListPageParam param);
+    Long selectCusListPageCount(SelectCusListPageParam param);
+
+    void transferCompanyUser(FsUserTransferParamDTO param);
 }

+ 26 - 0
fs-service-system/src/main/java/com/fs/store/param/SelectCusListPageParam.java

@@ -0,0 +1,26 @@
+package com.fs.store.param;
+
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SelectCusListPageParam extends BaseEntity {
+    /**
+     * 公司id
+     */
+    private Long companyId;
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 手机号码
+     */
+    private String phone;
+
+    private Long pageNum;
+    private Long pageSize;
+}

+ 7 - 1
fs-service-system/src/main/java/com/fs/store/param/h5/FsUserPageListParam.java

@@ -25,6 +25,9 @@ public class FsUserPageListParam implements Serializable {
     @ApiModelProperty(value = "是否是黑名单,默认是false", required = true)
     private Boolean isBlack = false;
 
+    @ApiModelProperty(value = "销售id")
+    private String companyUserId;
+
     @ApiModelProperty(value = "注册时间-开始")
     private String registerStartTime;
 
@@ -40,8 +43,11 @@ public class FsUserPageListParam implements Serializable {
     @ApiModelProperty(value = "看课状态,0全部;1未看过课;2正常看课;3停止看课")
     private String watchCourseType;
 
-    @ApiModelProperty(value = "缺课状态,1-已缺课;2-未缺课")
+    @ApiModelProperty(value = "缺课状态,0全部;1-已缺课;2-未缺课")
     private String missCourseStatus;
 
+    @ApiModelProperty(value = "连续停课排序,0-连续缺课天数多到少;1-连续缺课天数少到多;2-按注册时间晚到早;3-会员姓名0-9-A-Z")
+    private String continueMissCourseSort;
+
 }
 

+ 28 - 0
fs-service-system/src/main/java/com/fs/store/param/h5/TagListParam.java

@@ -0,0 +1,28 @@
+package com.fs.store.param.h5;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 标签列表 入参对象
+ */
+@Data
+public class TagListParam implements Serializable {
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum =1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "用户id,不用传")
+    private Long userId;
+
+    @ApiModelProperty(value = "模糊搜索名称,多个用逗号隔开")
+    private String keyword;
+
+}
+

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

@@ -3,6 +3,7 @@ package com.fs.store.service;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.qw.param.QwFsUserParam;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.qw.vo.newvo.ExternalContactDetailsVO;
@@ -11,6 +12,8 @@ import com.fs.store.domain.FsStoreOrder;
 import com.fs.store.domain.FsStoreOrderItem;
 import com.fs.store.domain.FsUser;
 
+import com.fs.store.dto.FsUserTransferParamDTO;
+import com.fs.store.param.SelectCusListPageParam;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.vo.FSUserVO;
 import com.fs.store.vo.FsCompanyUserListQueryVO;
@@ -99,6 +102,8 @@ public interface IFsUserService
 
     FsUser selectFsUserByPhone(String phone);
 
+    TableDataInfo selectCusListPage(SelectCusListPageParam param);
+
     List<FsCompanyUserListQueryVO> selectFsCompanyUserListQuery(FsUser fsUser);
 
     List<FsUserTuiVO> selectFsUserTuiList(String userId);
@@ -136,4 +141,9 @@ public interface IFsUserService
     UserListPageVO getUserNumber(Long userId);
 
     UserDetailsVO getUserDetails(Long userId, Long fsUserId, String dateTag);
+
+    Boolean disabledUser(String[] ids, boolean status);
+
+    void transfer(FsUserTransferParamDTO param);
+
 }

+ 88 - 69
fs-service-system/src/main/java/com/fs/store/service/impl/FsStorePaymentServiceImpl.java

@@ -15,7 +15,9 @@ import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.IPUtils;
 import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyConfig;
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyConfigMapper;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.course.config.RedPacketConfig;
@@ -95,6 +97,9 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService
 
     @Autowired
     private IFsCourseRedPacketLogService redPacketLogService;
+
+    @Autowired
+    private CompanyConfigMapper companyConfigMapper;
     /**
      * 查询支付明细
      *
@@ -355,46 +360,119 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService
     @Override
     @Transactional
     public R sendRedPacket(WxSendRedPacketParam param) {
+        String json;
+        RedPacketConfig config = new RedPacketConfig();
+        // 根据红包模式获取配置
+        switch (param.getRedPacketMode()){
+            case 1:
+                json = configService.selectConfigByKey("redPacket.config");
+                config = JSONUtil.toBean(json, RedPacketConfig.class);
+                break;
+            case 2:
+                json = companyConfigMapper.selectRedPacketConfigByKey(param.getCompanyId());
+                config = JSONUtil.toBean(json, RedPacketConfig.class);
+                break;
+        }
+        //组合返回参数
+        R result = new R();
+        // 根据 isNew 判断使用哪种发红包方式
+        if (config.getIsNew() != null && config.getIsNew() == 1) {
+            result = sendRedPacketV3Internal(param, config);
+        } else {
+            result= sendRedPacketLegacyInternal(param, config);
+        }
+        result.put("isNew",config.getIsNew());
+        return result;
+    }
 
-        String json = configService.selectConfigByKey("redPacket.config");
-        RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
-        //创建微信订单
+    // 内部方法:处理新版本的发红包逻辑
+    private R sendRedPacketV3Internal(WxSendRedPacketParam param, RedPacketConfig config) {
         WxPayConfig payConfig = new WxPayConfig();
-        BeanUtils.copyProperties(config,payConfig);
+        BeanUtils.copyProperties(config, payConfig);
         WxPayService wxPayService = new WxPayServiceImpl();
         wxPayService.setConfig(payConfig);
         TransferService transferService = wxPayService.getTransferService();
 
-        TransferBatchesRequest request = new TransferBatchesRequest();
+        TransferBillsRequest request = new TransferBillsRequest();
+        request.setAppid(config.getAppId());
+        request.setOpenid(param.getOpenId());
+
+        String code = String.valueOf(IdUtil.getSnowflake(0, 0).nextId());
+        request.setOutBillNo("fsCourse" + code);
 
+        Integer amount = WxPayUnifiedOrderRequest.yuanToFen(param.getAmount() != null ? param.getAmount().toString() : "0.1");
+        request.setTransferAmount(amount);
+        request.setTransferRemark("活动奖励");
+        request.setUserRecvPerception("活动奖励");
+        request.setNotifyUrl(config.getNotifyUrl());
+        request.setTransferSceneId("1000");
+
+        // 设置场景信息
+        List<TransferBillsRequest.TransferSceneReportInfo> transferSceneReportInfos = new ArrayList<>();
+        TransferBillsRequest.TransferSceneReportInfo info1 = new TransferBillsRequest.TransferSceneReportInfo();
+        info1.setInfoType("活动名称");
+        info1.setInfoContent("新会员有礼");
+        transferSceneReportInfos.add(info1);
+
+        TransferBillsRequest.TransferSceneReportInfo info2 = new TransferBillsRequest.TransferSceneReportInfo();
+        info2.setInfoType("奖励说明");
+        info2.setInfoContent("注册会员抽奖一等奖");
+        transferSceneReportInfos.add(info2);
+        request.setTransferSceneReportInfos(transferSceneReportInfos);
+
+        try {
+            TransferBillsResult transferBillsResult = transferService.transferBills(request);
+            logger.info("商家转账支付完成:[msg:{}]", transferBillsResult);
+            return R.ok("发送红包成功").put("data", transferBillsResult);
+        } catch (WxPayException e) {
+            e.printStackTrace();
+            logger.info("商家转账支付失败:[msg:{}]", e.getMessage());
+            return R.error("发送失败");
+        }
+    }
+
+    // 内部方法:处理旧版本的发红包逻辑
+    private R sendRedPacketLegacyInternal(WxSendRedPacketParam param, RedPacketConfig config) {
+        WxPayConfig payConfig = new WxPayConfig();
+        BeanUtils.copyProperties(config, payConfig);
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(payConfig);
+        TransferService transferService = wxPayService.getTransferService();
+
+        TransferBatchesRequest request = new TransferBatchesRequest();
         request.setAppid(config.getAppId());
         String code = IdUtil.getSnowflake(0, 0).nextIdStr();
-        request.setOutBatchNo("fsCourse"+code);
+        request.setOutBatchNo("fsCourse" + code);
         request.setBatchRemark("课堂答题奖励");
         request.setBatchName("课堂答题奖励");
         Integer amount = WxPayUnifiedOrderRequest.yuanToFen(param.getAmount().toString());
         request.setTotalAmount(amount);
         request.setTotalNum(1);
         request.setNotifyUrl(config.getNotifyUrl());
+
         ArrayList<TransferBatchesRequest.TransferDetail> transferDetailList = new ArrayList<>();
         TransferBatchesRequest.TransferDetail transferDetail = new TransferBatchesRequest.TransferDetail();
         transferDetail.setOpenid(param.getOpenId());
         String code1 = IdUtil.getSnowflake(0, 0).nextIdStr();
-        transferDetail.setOutDetailNo("fsCourse"+code1);
+        transferDetail.setOutDetailNo("fsCourse" + code1);
         transferDetail.setTransferAmount(amount);
         transferDetail.setTransferRemark("恭喜同学,认真听课,奖励你一朵小红花!");
         transferDetailList.add(transferDetail);
         request.setTransferDetailList(transferDetailList);
-        TransferBatchesResult transferBatchesResult=null;
+
         try {
-            transferBatchesResult = transferService.transferBatches(request);
-            return R.ok("发送红包成功").put("orderCode",transferBatchesResult.getOutBatchNo());
+            TransferBatchesResult transferBatchesResult = transferService.transferBatches(request);
+            return R.ok("发送红包成功").put("orderCode", transferBatchesResult.getOutBatchNo());
         } catch (WxPayException e) {
             e.printStackTrace();
             return R.error("发送失败");
         }
     }
 
+    @Override
+    public R sendRedPacketV3(WxSendRedPacketParam param) {
+        return null;
+    }
 
     @Override
     public String transferNotify(String notifyData, HttpServletRequest request) {
@@ -431,65 +509,6 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService
         }
     }
 
-    @Override
-    public R sendRedPacketV3(WxSendRedPacketParam param) {
-        String json = configService.selectConfigByKey("redPacket.config");
-        RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
-
-        //创建微信订单
-        WxPayConfig payConfig = new WxPayConfig();
-        BeanUtils.copyProperties(config,payConfig);
-        WxPayService wxPayService = new WxPayServiceImpl();
-        wxPayService.setConfig(payConfig);
-        TransferService transferService = wxPayService.getTransferService();
-
-        //商家转账请求
-        TransferBillsRequest request = new TransferBillsRequest();
-        request.setAppid(config.getAppId());
-        request.setOpenid(param.getOpenId());
-
-//        String code =  OrderCodeUtils.getH5RedPacketOrderSn();
-//        if(StringUtils.isEmpty(code)){
-//            return R.error("订单生成失败,请重试");
-//        }
-        String code = String.valueOf(IdUtil.getSnowflake(0, 0).nextId());
-        request.setOutBillNo("fsCourse"+code);
-        //转账金额
-        Integer amount = WxPayUnifiedOrderRequest.yuanToFen(param.getAmount()!=null ? param.getAmount().toString() : "0.1");
-        request.setTransferAmount(amount);
-        request.setTransferRemark("活动奖励");
-        //用户感知
-        request.setUserRecvPerception("活动奖励");
-        request.setNotifyUrl(config.getNotifyUrl());
-        request.setTransferSceneId("1000");
-        List<TransferBillsRequest.TransferSceneReportInfo> transferSceneReportInfos = new ArrayList<>();
-        // 添加第一条数据
-        TransferBillsRequest.TransferSceneReportInfo info1 = new TransferBillsRequest.TransferSceneReportInfo();
-        info1.setInfoType("活动名称");
-        info1.setInfoContent("新会员有礼");
-        transferSceneReportInfos.add(info1);
-
-        // 添加第二条数据
-        TransferBillsRequest.TransferSceneReportInfo info2 = new TransferBillsRequest.TransferSceneReportInfo();
-        info2.setInfoType("奖励说明");
-        info2.setInfoContent("注册会员抽奖一等奖");
-        transferSceneReportInfos.add(info2);
-        request.setTransferSceneReportInfos(transferSceneReportInfos);
-
-        //发起商家转账API(新)
-        TransferBillsResult transferBillsResult=null;
-        try {
-            transferBillsResult = transferService.transferBills(request);
-            logger.info("商家转账支付完成:[msg:{}]",transferBillsResult);
-            return R.ok("发送红包成功").put("data",transferBillsResult);
-        } catch (WxPayException e) {
-            e.printStackTrace();
-            logger.info("商家转账支付失败:[msg:{}]",e.getMessage());
-            return R.error("发送失败");
-        }
-    }
-
-
     @Override
     public String v3TransferNotify(String notifyData, HttpServletRequest request) {
         logger.info("zyp \n【收到转账回调】:{}",notifyData);

+ 76 - 3
fs-service-system/src/main/java/com/fs/store/service/impl/FsUserServiceImpl.java

@@ -1,14 +1,19 @@
 package com.fs.store.service.impl;
 
 import java.math.BigDecimal;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.utils.DateUtils;
+import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.company.domain.CompanyUser;
 import com.fs.qw.param.QwFsUserParam;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.qw.vo.newvo.ExternalContactNumVO;
@@ -17,23 +22,29 @@ import com.fs.store.domain.FsStoreOrder;
 import com.fs.store.domain.FsStoreOrderItem;
 import com.fs.store.domain.FsUserBill;
 import com.fs.store.dto.FsStoreCartDTO;
+import com.fs.store.dto.FsUserTransferParamDTO;
 import com.fs.store.enums.BillDetailEnum;
 import com.fs.store.mapper.FsStoreOrderMapper;
 import com.fs.store.mapper.FsStoreProductAttrValueMapper;
 import com.fs.store.param.h5.FsUserPageListParam;
+import com.fs.store.param.SelectCusListPageParam;
 import com.fs.store.service.IFsUserBillService;
 import com.fs.store.vo.FSUserVO;
 import com.fs.store.vo.FsCompanyUserListQueryVO;
 import com.fs.store.vo.FsUserTuiVO;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.http.util.Asserts;
 import com.fs.store.vo.h5.FsUserPageListVO;
 import com.fs.store.vo.h5.UserDetailsVO;
 import com.fs.store.vo.h5.UserListCountVO;
 import com.fs.store.vo.h5.UserListPageVO;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.store.mapper.FsUserMapper;
 import com.fs.store.domain.FsUser;
 import com.fs.store.service.IFsUserService;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import static com.fs.store.enums.BillDetailEnum.CATEGORY_1;
@@ -58,6 +69,9 @@ public class FsUserServiceImpl implements IFsUserService
     private IFsUserBillService billService;
     @Autowired
     private FsStoreOrderMapper storeOrderMapper;
+
+    @Autowired
+    private ICompanyUserCacheService companyUserCacheService;
     /**
      * 查询用户
      *
@@ -159,6 +173,34 @@ public class FsUserServiceImpl implements IFsUserService
         return fsUserMapper.selectFsUserByPhone(phone);
     }
 
+    @Override
+    public TableDataInfo selectCusListPage(SelectCusListPageParam param) {
+        Asserts.check(ObjectUtils.isNotNull(param.getPageNum()), "页数不能为空");
+        Asserts.check(ObjectUtils.isNotNull(param.getPageSize()), "页大小不能为空");
+
+        List<FsUser> fsUsers = fsUserMapper.selectCusListPage(param);
+        for (FsUser fsUser : fsUsers) {
+            if(ObjectUtils.isNotNull(fsUser.getStatus())){
+                if(ObjectUtil.equal(0,fsUser.getStatus())){
+                    fsUser.setStatusText("禁止");
+                } else {
+                    fsUser.setStatusText("正常");
+                }
+            }
+            if(ObjectUtils.isNotNull(fsUser.getCompanyUserId())){
+                CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(fsUser.getCompanyUserId());
+                if(ObjectUtils.isNotNull(companyUser)){
+                    fsUser.setCompanyUserName(String.format("%s_%d",companyUser.getUserName(),companyUser.getUserId()));
+                }
+            }
+        }
+        TableDataInfo tableDataInfo = new TableDataInfo();
+        tableDataInfo.setRows(fsUsers);
+        tableDataInfo.setTotal(fsUserMapper.selectCusListPageCount(param));
+        return tableDataInfo;
+    }
+
+
     @Override
     public List<FsCompanyUserListQueryVO> selectFsCompanyUserListQuery(FsUser fsUser) {
         return fsUserMapper.selectFsCompanyUserListQuery(fsUser);
@@ -380,7 +422,38 @@ public class FsUserServiceImpl implements IFsUserService
 
     @Override
     public UserDetailsVO getUserDetails(Long userId, Long fsUserId, String dateTag) {
-        fsUserMapper.getCountAnswer(userId, fsUserId, dateTag);
-        return null;
+        UserDetailsVO countAnswer = fsUserMapper.getCountAnswer(userId, fsUserId, dateTag);
+        UserDetailsVO countRedPacket = fsUserMapper.getCountRedPacket(userId, fsUserId, dateTag);
+        UserDetailsVO vo = new UserDetailsVO();
+        if (countRedPacket != null) {
+            BeanUtils.copyProperties(countRedPacket, vo);
+        }
+        if (countAnswer != null) {
+            vo.setAnswerTime(countAnswer.getAnswerTime());
+            vo.setAnswerRightTime(countAnswer.getAnswerRightTime());
+        }
+        return vo;
+    }
+
+    @Override
+    public Boolean disabledUser(String[] ids, boolean status) {
+        boolean result;
+        if(status){
+            //启用
+            result = fsUserMapper.batchUpdateFsUserByIds(ids, 1) > 0;
+        } else {
+            //禁用
+            result = fsUserMapper.batchUpdateFsUserByIds(ids, 0) > 0;
+        }
+        return result;
+    }
+    @Override
+    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
+    public void transfer(FsUserTransferParamDTO param) {
+        Asserts.check(ObjectUtils.isNotNull(param.getSourceCompanyUserId()), "来源用户不能为空!");
+        Asserts.check(ObjectUtils.isNotNull(param.getTargetCompanyUserId()), "转移用户不能为空!");
+        Asserts.check(CollectionUtils.isNotEmpty(param.getUserIds()), "要转移的客户列表不能为空!");
+
+        fsUserMapper.transferCompanyUser(param);
     }
 }

+ 19 - 0
fs-service-system/src/main/java/com/fs/store/vo/h5/CompanyUserTagListVO.java

@@ -0,0 +1,19 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户标签 返回对象
+ */
+@Data
+@ApiModel
+public class CompanyUserTagListVO {
+    @ApiModelProperty(value = "标签id")
+    private Long tagId;
+
+    @ApiModelProperty(value = "标签名称")
+    private String tagName;
+
+}

+ 2 - 0
fs-service-system/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java

@@ -71,6 +71,8 @@ public class FsUserPageListVO {
     @ApiModelProperty(value = "标签名称")
     private String tag;
 
+    @ApiModelProperty(value = "销售名称")
+    private String companyUserNickName;
 
 
 }

+ 8 - 0
fs-service-system/src/main/java/com/fs/store/vo/h5/UserDetailsVO.java

@@ -23,4 +23,12 @@ public class UserDetailsVO {
     @ApiModelProperty(value = "答题红包金额")
     private int answerRedPacketAmount;
 
+    @ApiModelProperty(value = "完播次数")
+    private int completeWatchCount;
+
+    @ApiModelProperty(value = "观看次数")
+    private int watchTimes;
+
+
+
 }

+ 66 - 0
fs-service-system/src/main/resources/mapper/company/CompanyTagMapper.xml

@@ -0,0 +1,66 @@
+<?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.company.mapper.CompanyTagMapper">
+    
+    <resultMap type="CompanyTag" id="CompanyTagResult">
+        <result property="tagId"    column="tag_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="tag"    column="tag"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectCompanyTagVo">
+        select tag_id, company_id, tag, create_time from company_tag
+    </sql>
+
+    <select id="selectCompanyTagList" parameterType="CompanyTag" resultMap="CompanyTagResult">
+        <include refid="selectCompanyTagVo"/>
+        <where>  
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="tag != null  and tag != ''"> and tag = #{tag}</if>
+        </where>
+    </select>
+    
+    <select id="selectCompanyTagById" parameterType="Long" resultMap="CompanyTagResult">
+        <include refid="selectCompanyTagVo"/>
+        where tag_id = #{tagId}
+    </select>
+        
+    <insert id="insertCompanyTag" parameterType="CompanyTag" useGeneratedKeys="true" keyProperty="tagId">
+        insert into company_tag
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="tag != null">tag,</if>
+            <if test="createTime != null">create_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="tag != null">#{tag},</if>
+            <if test="createTime != null">#{createTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateCompanyTag" parameterType="CompanyTag">
+        update company_tag
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="tag != null">tag = #{tag},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where tag_id = #{tagId}
+    </update>
+
+    <delete id="deleteCompanyTagById" parameterType="Long">
+        delete from company_tag where tag_id = #{tagId}
+    </delete>
+
+    <delete id="deleteCompanyTagByIds" parameterType="String">
+        delete from company_tag where tag_id in 
+        <foreach item="tagId" collection="array" open="(" separator="," close=")">
+            #{tagId}
+        </foreach>
+    </delete>
+    
+</mapper>

+ 98 - 0
fs-service-system/src/main/resources/mapper/company/CompanyTagUserMapper.xml

@@ -0,0 +1,98 @@
+<?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.company.mapper.CompanyTagUserMapper">
+
+    <resultMap type="CompanyTagUser" id="CompanyTagUserResult">
+        <result property="id"    column="id"    />
+        <result property="tagIds"    column="tag_ids"    />
+        <result property="userId"    column="user_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectCompanyTagUserVo">
+        select id, tag_ids, user_id, company_id, company_user_id, create_time from company_tag_user
+    </sql>
+
+    <select id="selectCompanyTagUserList" parameterType="CompanyTagUser" resultMap="CompanyTagUserResult">
+        <include refid="selectCompanyTagUserVo"/>
+        <where>
+            <if test="tagIds != null  and tagIds != ''"> and tag_ids = #{tagIds}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+        </where>
+    </select>
+
+    <select id="selectCompanyTagUserById" parameterType="Long" resultMap="CompanyTagUserResult">
+        <include refid="selectCompanyTagUserVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertCompanyTagUser" parameterType="CompanyTagUser" useGeneratedKeys="true" keyProperty="id">
+        insert into company_tag_user
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="tagIds != null">tag_ids,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="createTime != null">create_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="tagIds != null">#{tagIds},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="createTime != null">#{createTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateCompanyTagUser" parameterType="CompanyTagUser">
+        update company_tag_user
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="tagIds != null">tag_ids = #{tagIds},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteCompanyTagUserById" parameterType="Long">
+        delete from company_tag_user where id = #{id}
+    </delete>
+
+    <delete id="deleteCompanyTagUserByIds" parameterType="String">
+        delete from company_tag_user where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <select id="getTagList" resultType="CompanyUserTagListVO">
+        SELECT
+        company_tag.tag as tagName,
+        company_tag.tag_id
+        FROM
+        company_tag_user
+        right JOIN company_tag ON FIND_IN_SET( company_tag.tag_id, company_tag_user.tag_ids ) > 0
+        WHERE 1 = 1
+        <if test="userIds != null and userIds.size() > 0 ">
+        AND company_tag_user.company_user_id in
+        <foreach item="item" collection="userIds" open="(" separator="," close=")">
+              #{item}
+        </foreach>
+        </if>
+        <if test="keywords != null and keywords.length > 0 ">
+            and
+            <foreach item="item" collection="keywords" open="(" separator="or" close=")">
+                company_tag.tag like concat('%',#{item},'%')
+            </foreach>
+        </if>
+    </select>
+
+</mapper>

+ 25 - 1
fs-service-system/src/main/resources/mapper/company/CompanyUserMapper.xml

@@ -373,7 +373,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
 
 
-
+    <select id="selectAllCompanyUserByParentId" resultType="CompanyUser">
+        SELECT
+            *
+        FROM
+            company_user
+        WHERE
+            del_flag = 0
+            AND parent_id = #{parentId}
+    </select>
+    <select id="getAllUserListLimit" resultType="com.fs.company.domain.CompanyUser">
+        SELECT * FROM company_user
+        <where>
+            <if test="companyId != null">
+                AND company_id != #{companyId}
+            </if>
+            <if test="keywords != null and keywords != ''">
+                AND (
+                phonenumber LIKE CONCAT(#{keywords}, '%')
+                OR user_name LIKE CONCAT(#{keywords}, '%')
+                OR nick_name LIKE CONCAT(#{keywords}, '%')
+                )
+            </if>
+        </where>
+        limit 10
+    </select>
 
 
 </mapper>

+ 20 - 0
fs-service-system/src/main/resources/mapper/course/FsUserCourseMapper.xml

@@ -229,4 +229,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{courseId}
         </foreach>
     </update>
+
+    <select id="getFsUserCourseList" resultType="FsUserCourseListPVO">
+        SELECT
+            c.*,
+            cc.cate_name,
+            ucc.cate_name AS sub_cate_name
+        FROM
+            fs_user_course c
+                LEFT JOIN fs_user_course_category cc ON c.cate_id = cc.cate_id
+                LEFT JOIN fs_user_course_category ucc ON ucc.cate_id = c.sub_cate_id
+        WHERE
+            c.is_del = 0
+            AND FIND_IN_SET(#{companyId}, c.company_ids)
+        <if test="keyword != null and keyword !='' ">
+            AND c.course_name LIKE concat('%',#{keyword},'%'
+            )
+        </if>
+        ORDER BY
+            c.course_id
+    </select>
 </mapper>

+ 25 - 0
fs-service-system/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml

@@ -163,4 +163,29 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{videoId}
         </foreach>
     </update>
+
+    <select id="selectFsUserCourseVideoPageList" resultType="FsUserCourseVideoPageListVO">
+        SELECT
+            video.video_id,
+            video.title,
+            video.description,
+            video.video_url,
+            video.thumbnail,
+            video.duration,
+            video.create_time,
+            video.course_id,
+            video.STATUS,
+            video.course_sort,
+        course.course_name
+        FROM `fs_user_course_video` video
+        LEFT JOIN fs_user_course course ON video.course_id = course.course_id
+        where 1 = 1
+        <if test="courseId != null and courseId !='' ">
+            AND video.course_id = #{courseId}
+        </if>
+        <if test="keyword != null and keyword !='' ">
+            AND video.title LIKE concat('%',#{keyword},'%')
+        </if>
+        order by video.course_sort
+    </select>
 </mapper>

+ 121 - 0
fs-service-system/src/main/resources/mapper/qw/CustomerTransferApprovalMapper.xml

@@ -0,0 +1,121 @@
+<?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.CustomerTransferApprovalMapper">
+
+    <resultMap type="CustomerTransferApproval" id="CustomerTransferApprovalResult">
+        <result property="id"    column="id"    />
+        <result property="corpId"    column="corp_id"    />
+        <result property="transferType"    column="transfer_type"    />
+        <result property="customerIds"    column="customer_ids"    />
+        <result property="originalUserId"    column="original_user_id"    />
+        <result property="targetUserId"    column="target_user_id"    />
+        <result property="initiatorUserId"    column="initiator_user_id"    />
+        <result property="content"    column="content"    />
+        <result property="approvalStatus"    column="approval_status"    />
+        <result property="approverUserId"    column="approver_user_id"    />
+        <result property="approvalRemark"    column="approval_remark"    />
+        <result property="processedAt"    column="processed_at"    />
+        <result property="createdAt"    column="created_at"    />
+        <result property="updatedAt"    column="updated_at"    />
+        <result property="transferBefore"    column="transfer_before"    />
+    </resultMap>
+
+    <sql id="selectCustomerTransferApprovalVo">
+        select id, corp_id, transfer_type, customer_ids, original_user_id, target_user_id, initiator_user_id, content, approval_status, approver_user_id, approval_remark, processed_at, created_at, updated_at,transfer_before from customer_transfer_approval
+    </sql>
+
+    <select id="selectCustomerTransferApprovalList" parameterType="CustomerTransferApproval" resultMap="CustomerTransferApprovalResult">
+        <include refid="selectCustomerTransferApprovalVo"/>
+        <where>
+            <if test="corpId != null  and corpId != ''"> and corp_id = #{corpId}</if>
+            <if test="transferType != null "> and transfer_type = #{transferType}</if>
+            <if test="customerIds != null  and customerIds != ''"> and customer_ids = #{customerIds}</if>
+            <if test="originalUserId != null "> and original_user_id = #{originalUserId}</if>
+            <if test="targetUserId != null "> and target_user_id = #{targetUserId}</if>
+            <if test="initiatorUserId != null "> and initiator_user_id = #{initiatorUserId}</if>
+            <if test="content != null  and content != ''"> and content = #{content}</if>
+            <if test="approvalStatus != null "> and approval_status = #{approvalStatus}</if>
+            <if test="approverUserId != null "> and approver_user_id = #{approverUserId}</if>
+            <if test="approvalRemark != null  and approvalRemark != ''"> and approval_remark = #{approvalRemark}</if>
+            <if test="processedAt != null "> and processed_at = #{processedAt}</if>
+            <if test="createdAt != null "> and created_at = #{createdAt}</if>
+            <if test="updatedAt != null "> and updated_at = #{updatedAt}</if>
+        </where>
+    </select>
+
+    <select id="selectCustomerTransferApprovalById" parameterType="Long" resultMap="CustomerTransferApprovalResult">
+        <include refid="selectCustomerTransferApprovalVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertCustomerTransferApproval" parameterType="CustomerTransferApproval" useGeneratedKeys="true" keyProperty="id">
+        insert into customer_transfer_approval
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="corpId != null and corpId != ''">corp_id,</if>
+            <if test="transferType != null">transfer_type,</if>
+            <if test="customerIds != null and customerIds != ''">customer_ids,</if>
+            <if test="originalUserId != null">original_user_id,</if>
+            <if test="targetUserId != null">target_user_id,</if>
+            <if test="initiatorUserId != null">initiator_user_id,</if>
+            <if test="content != null">content,</if>
+            <if test="approvalStatus != null">approval_status,</if>
+            <if test="approverUserId != null">approver_user_id,</if>
+            <if test="approvalRemark != null">approval_remark,</if>
+            <if test="processedAt != null">processed_at,</if>
+            <if test="createdAt != null">created_at,</if>
+            <if test="updatedAt != null">updated_at,</if>
+            <if test="transferBefore != null">transfer_before,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="corpId != null and corpId != ''">#{corpId},</if>
+            <if test="transferType != null">#{transferType},</if>
+            <if test="customerIds != null and customerIds != ''">#{customerIds},</if>
+            <if test="originalUserId != null">#{originalUserId},</if>
+            <if test="targetUserId != null">#{targetUserId},</if>
+            <if test="initiatorUserId != null">#{initiatorUserId},</if>
+            <if test="content != null">#{content},</if>
+            <if test="approvalStatus != null">#{approvalStatus},</if>
+            <if test="approverUserId != null">#{approverUserId},</if>
+            <if test="approvalRemark != null">#{approvalRemark},</if>
+            <if test="processedAt != null">#{processedAt},</if>
+            <if test="createdAt != null">#{createdAt},</if>
+            <if test="updatedAt != null">#{updatedAt},</if>
+            <if test="transferBefore != null">#{transferBefore},</if>
+         </trim>
+    </insert>
+
+    <update id="updateCustomerTransferApproval" parameterType="CustomerTransferApproval">
+        update customer_transfer_approval
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="corpId != null and corpId != ''">corp_id = #{corpId},</if>
+            <if test="transferType != null">transfer_type = #{transferType},</if>
+            <if test="customerIds != null and customerIds != ''">customer_ids = #{customerIds},</if>
+            <if test="originalUserId != null">original_user_id = #{originalUserId},</if>
+            <if test="targetUserId != null">target_user_id = #{targetUserId},</if>
+            <if test="initiatorUserId != null">initiator_user_id = #{initiatorUserId},</if>
+            <if test="content != null">content = #{content},</if>
+            <if test="approvalStatus != null">approval_status = #{approvalStatus},</if>
+            <if test="approverUserId != null">approver_user_id = #{approverUserId},</if>
+            <if test="approvalRemark != null">approval_remark = #{approvalRemark},</if>
+            <if test="processedAt != null">processed_at = #{processedAt},</if>
+            <if test="createdAt != null">created_at = #{createdAt},</if>
+            <if test="updatedAt != null">updated_at = #{updatedAt},</if>
+            <if test="transferBefore != null">transfer_before = #{transferBefore},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteCustomerTransferApprovalById" parameterType="Long">
+        delete from customer_transfer_approval where id = #{id}
+    </delete>
+
+    <delete id="deleteCustomerTransferApprovalByIds" parameterType="String">
+        delete from customer_transfer_approval where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+</mapper>

+ 21 - 1
fs-service-system/src/main/resources/mapper/store/FsUserCourseCountMapper.xml

@@ -10,7 +10,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="watchCourseCount"    column="watch_course_count"    />
         <result property="missCourseCount"    column="miss_course_count"    />
         <result property="missCourseStatus"    column="miss_course_status"    />
+        <result property="missCourseDays"    column="miss_course_days"    />
         <result property="courseId"    column="course_id"    />
+        <result property="partCourseCount"    column="part_course_count"    />
         <result property="lastWatchDate"    column="last_watch_date"    />
         <result property="status"    column="status"    />
         <result property="stopWatchDays"    column="stop_watch_days"    />
@@ -19,10 +21,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="createBy"    column="create_by"    />
         <result property="updateBy"    column="update_by"    />
         <result property="completeWatchDate"    column="complete_watch_date"    />
+        <result property="completeWatchCount"    column="complete_watch_count"    />
+        <result property="watchTimes"    column="watch_times"    />
     </resultMap>
 
     <sql id="selectFsUserCourseCountVo">
-        select id, user_id, watch_course_count, miss_course_count, miss_course_status, course_id, last_watch_date, status, stop_watch_days, create_time, update_time, create_by, update_by, complete_watch_date from fs_user_course_count
+        select id, user_id, watch_course_count, miss_course_count, miss_course_status, miss_course_days, course_id, part_course_count, last_watch_date, status, stop_watch_days, create_time, update_time, create_by, update_by, complete_watch_date, complete_watch_count, watch_times from fs_user_course_count
     </sql>
 
     <select id="selectFsUserCourseCountList" parameterType="FsUserCourseCount" resultMap="FsUserCourseCountResult">
@@ -32,11 +36,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="watchCourseCount != null "> and watch_course_count = #{watchCourseCount}</if>
             <if test="missCourseCount != null "> and miss_course_count = #{missCourseCount}</if>
             <if test="missCourseStatus != null "> and miss_course_status = #{missCourseStatus}</if>
+            <if test="missCourseDays != null "> and miss_course_days = #{missCourseDays}</if>
             <if test="courseId != null "> and course_id = #{courseId}</if>
+            <if test="partCourseCount != null  and partCourseCount != ''"> and part_course_count = #{partCourseCount}</if>
             <if test="lastWatchDate != null "> and last_watch_date = #{lastWatchDate}</if>
             <if test="status != null "> and status = #{status}</if>
             <if test="stopWatchDays != null "> and stop_watch_days = #{stopWatchDays}</if>
             <if test="completeWatchDate != null "> and complete_watch_date = #{completeWatchDate}</if>
+            <if test="completeWatchCount != null "> and complete_watch_count = #{completeWatchCount}</if>
+            <if test="watchTimes != null "> and watch_times = #{watchTimes}</if>
         </where>
     </select>
     
@@ -53,7 +61,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="watchCourseCount != null">watch_course_count,</if>
             <if test="missCourseCount != null">miss_course_count,</if>
             <if test="missCourseStatus != null">miss_course_status,</if>
+            <if test="missCourseDays != null">miss_course_days,</if>
             <if test="courseId != null">course_id,</if>
+            <if test="partCourseCount != null">part_course_count,</if>
             <if test="lastWatchDate != null">last_watch_date,</if>
             <if test="status != null">status,</if>
             <if test="stopWatchDays != null">stop_watch_days,</if>
@@ -62,6 +72,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createBy != null">create_by,</if>
             <if test="updateBy != null">update_by,</if>
             <if test="completeWatchDate != null">complete_watch_date,</if>
+            <if test="completeWatchCount != null">complete_watch_count,</if>
+            <if test="watchTimes != null">watch_times,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">#{id},</if>
@@ -69,7 +81,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="watchCourseCount != null">#{watchCourseCount},</if>
             <if test="missCourseCount != null">#{missCourseCount},</if>
             <if test="missCourseStatus != null">#{missCourseStatus},</if>
+            <if test="missCourseDays != null">#{missCourseDays},</if>
             <if test="courseId != null">#{courseId},</if>
+            <if test="partCourseCount != null">#{partCourseCount},</if>
             <if test="lastWatchDate != null">#{lastWatchDate},</if>
             <if test="status != null">#{status},</if>
             <if test="stopWatchDays != null">#{stopWatchDays},</if>
@@ -78,6 +92,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createBy != null">#{createBy},</if>
             <if test="updateBy != null">#{updateBy},</if>
             <if test="completeWatchDate != null">#{completeWatchDate},</if>
+            <if test="completeWatchCount != null">#{completeWatchCount},</if>
+            <if test="watchTimes != null">#{watchTimes},</if>
          </trim>
     </insert>
 
@@ -88,7 +104,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="watchCourseCount != null">watch_course_count = #{watchCourseCount},</if>
             <if test="missCourseCount != null">miss_course_count = #{missCourseCount},</if>
             <if test="missCourseStatus != null">miss_course_status = #{missCourseStatus},</if>
+            <if test="missCourseDays != null">miss_course_days = #{missCourseDays},</if>
             <if test="courseId != null">course_id = #{courseId},</if>
+            <if test="partCourseCount != null">part_course_count = #{partCourseCount},</if>
             <if test="lastWatchDate != null">last_watch_date = #{lastWatchDate},</if>
             <if test="status != null">status = #{status},</if>
             <if test="stopWatchDays != null">stop_watch_days = #{stopWatchDays},</if>
@@ -97,6 +115,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createBy != null">create_by = #{createBy},</if>
             <if test="updateBy != null">update_by = #{updateBy},</if>
             <if test="completeWatchDate != null">complete_watch_date = #{completeWatchDate},</if>
+            <if test="completeWatchCount != null">complete_watch_count = #{completeWatchCount},</if>
+            <if test="watchTimes != null">watch_times = #{watchTimes},</if>
         </trim>
         where id = #{id}
     </update>

+ 268 - 122
fs-service-system/src/main/resources/mapper/store/FsUserMapper.xml

@@ -1,86 +1,126 @@
 <?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">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.store.mapper.FsUserMapper">
     <resultMap type="FsUser" id="FsUserResult">
-        <result property="userId"    column="user_id"    />
-        <result property="username"    column="username"    />
-        <result property="password"    column="password"    />
-        <result property="realName"    column="real_name"    />
-        <result property="birthday"    column="birthday"    />
-        <result property="idCard"    column="id_card"    />
-        <result property="remark"    column="remark"    />
-        <result property="nickname"    column="nickname"    />
-        <result property="avatar"    column="avatar"    />
-        <result property="phone"    column="phone"    />
-        <result property="createTime"    column="create_time"    />
-        <result property="updateTime"    column="update_time"    />
-        <result property="lastIp"    column="last_ip"    />
-        <result property="nowMoney"    column="now_money"    />
-        <result property="brokeragePrice"    column="brokerage_price"    />
-        <result property="integral"    column="integral"    />
-        <result property="signNum"    column="sign_num"    />
-        <result property="status"    column="status"    />
-        <result property="level"    column="level"    />
-        <result property="spreadUserId"    column="spread_user_id"    />
-        <result property="spreadTime"    column="spread_time"    />
-        <result property="userType"    column="user_type"    />
-        <result property="isPromoter"    column="is_promoter"    />
-        <result property="payCount"    column="pay_count"    />
-        <result property="spreadCount"    column="spread_count"    />
-        <result property="addres"    column="addres"    />
-        <result property="maOpenId"    column="ma_open_id"    />
-        <result property="mpOpenId"    column="mp_open_id"    />
-        <result property="unionId"    column="union_id"    />
-        <result property="isDel"    column="is_del"    />
-        <result property="isWeixinAuth"    column="is_weixin_auth"    />
-        <result property="companyId"    column="company_id"    />
-        <result property="companyUserId"    column="company_user_id"    />
-        <result property="registerDate"    column="register_date"    />
-        <result property="registerCode"    column="register_code"    />
-        <result property="source"    column="source"    />
-        <result property="userCode"    column="user_code"    />
-        <result property="isShow"    column="is_show"    />
+        <result property="userId" column="user_id"/>
+        <result property="username" column="username"/>
+        <result property="password" column="password"/>
+        <result property="realName" column="real_name"/>
+        <result property="birthday" column="birthday"/>
+        <result property="idCard" column="id_card"/>
+        <result property="remark" column="remark"/>
+        <result property="nickname" column="nickname"/>
+        <result property="avatar" column="avatar"/>
+        <result property="phone" column="phone"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="lastIp" column="last_ip"/>
+        <result property="nowMoney" column="now_money"/>
+        <result property="brokeragePrice" column="brokerage_price"/>
+        <result property="integral" column="integral"/>
+        <result property="signNum" column="sign_num"/>
+        <result property="status" column="status"/>
+        <result property="level" column="level"/>
+        <result property="spreadUserId" column="spread_user_id"/>
+        <result property="spreadTime" column="spread_time"/>
+        <result property="userType" column="user_type"/>
+        <result property="isPromoter" column="is_promoter"/>
+        <result property="payCount" column="pay_count"/>
+        <result property="spreadCount" column="spread_count"/>
+        <result property="addres" column="addres"/>
+        <result property="maOpenId" column="ma_open_id"/>
+        <result property="mpOpenId" column="mp_open_id"/>
+        <result property="unionId" column="union_id"/>
+        <result property="isDel" column="is_del"/>
+        <result property="isWeixinAuth" column="is_weixin_auth"/>
+        <result property="companyId" column="company_id"/>
+        <result property="companyUserId" column="company_user_id"/>
+        <result property="registerDate" column="register_date"/>
+        <result property="registerCode" column="register_code"/>
+        <result property="source" column="source"/>
+        <result property="userCode" column="user_code"/>
+        <result property="isShow" column="is_show"/>
     </resultMap>
 
     <sql id="selectFsUserVo">
-        select user_id,is_show, username, password, real_name, birthday, id_card, remark, nickname, avatar, phone, create_time, update_time, last_ip, now_money, brokerage_price, integral, sign_num, status, level, spread_user_id, spread_time, user_type, is_promoter, pay_count, spread_count, addres,ma_open_id,mp_open_id,union_id, is_del,is_weixin_auth,company_id,company_user_id,register_date,register_code,source,user_code from fs_user
+        select user_id,
+               is_show,
+               username,
+               password,
+               real_name,
+               birthday,
+               id_card,
+               remark,
+               nickname,
+               avatar,
+               phone,
+               create_time,
+               update_time,
+               last_ip,
+               now_money,
+               brokerage_price,
+               integral,
+               sign_num,
+               status,
+               level,
+               spread_user_id,
+               spread_time,
+               user_type,
+               is_promoter,
+               pay_count,
+               spread_count,
+               addres,
+               ma_open_id,
+               mp_open_id,
+               union_id,
+               is_del,
+               is_weixin_auth,
+               company_id,
+               company_user_id,
+               register_date,
+               register_code,
+               source,
+               user_code
+        from fs_user
     </sql>
 
     <select id="selectFsUserList" parameterType="FsUser" resultMap="FsUserResult">
         <include refid="selectFsUserVo"/>
         <where>
-            <if test="username != null  and username != ''"> and username like concat('%', #{username}, '%')</if>
-            <if test="password != null  and password != ''"> and password = #{password}</if>
-            <if test="realName != null  and realName != ''"> and real_name like concat('%', #{realName}, '%')</if>
-            <if test="birthday != null "> and birthday = #{birthday}</if>
-            <if test="idCard != null  and idCard != ''"> and id_card = #{idCard}</if>
-            <if test="remark != null  and remark != ''"> and remark = #{remark}</if>
-            <if test="nickname != null  and nickname != ''"> and nickname like concat('%', #{nickname}, '%')</if>
-            <if test="avatar != null  and avatar != ''"> and avatar = #{avatar}</if>
-            <if test="phone != null  and phone != ''"> and phone = #{phone}</if>
-            <if test="lastIp != null  and lastIp != ''"> and last_ip = #{lastIp}</if>
-            <if test="nowMoney != null "> and now_money = #{nowMoney}</if>
-            <if test="brokeragePrice != null "> and brokerage_price = #{brokeragePrice}</if>
-            <if test="integral != null "> and integral = #{integral}</if>
-            <if test="signNum != null "> and sign_num = #{signNum}</if>
-            <if test="status != null "> and status = #{status}</if>
-            <if test="level != null "> and level = #{level}</if>
-            <if test="spreadUserId != null "> and spread_user_id = #{spreadUserId}</if>
-            <if test="spreadTime != null "> and spread_time = #{spreadTime}</if>
-            <if test="userType != null  and userType != ''"> and user_type = #{userType}</if>
-            <if test="isPromoter != null "> and is_promoter = #{isPromoter}</if>
-            <if test="payCount != null "> and pay_count = #{payCount}</if>
-            <if test="spreadCount != null "> and spread_count = #{spreadCount}</if>
-            <if test="addres != null  and addres != ''"> and addres = #{addres}</if>
-            <if test="isDel != null "> and is_del = #{isDel}</if>
-            <if test="companyId != null "> and company_id = #{companyId}</if>
-            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
-            <if test="registerDate != null "> and DATE_FORMAT(register_date,'%Y-%m-%d') = DATE_FORMAT(#{registerDate},'%Y-%m-%d')</if>
-            <if test="registerCode != null   and registerCode != '' "> and register_code = #{registerCode}</if>
-            <if test="source != null  and source != '' "> and source = #{source}</if>
-            <if test="isShow != null  "> and is_show = #{isShow}</if>
+            <if test="username != null  and username != ''">and username like concat('%', #{username}, '%')</if>
+            <if test="password != null  and password != ''">and password = #{password}</if>
+            <if test="realName != null  and realName != ''">and real_name like concat('%', #{realName}, '%')</if>
+            <if test="birthday != null ">and birthday = #{birthday}</if>
+            <if test="idCard != null  and idCard != ''">and id_card = #{idCard}</if>
+            <if test="remark != null  and remark != ''">and remark = #{remark}</if>
+            <if test="nickname != null  and nickname != ''">and nickname like concat('%', #{nickname}, '%')</if>
+            <if test="avatar != null  and avatar != ''">and avatar = #{avatar}</if>
+            <if test="phone != null  and phone != ''">and phone = #{phone}</if>
+            <if test="lastIp != null  and lastIp != ''">and last_ip = #{lastIp}</if>
+            <if test="nowMoney != null ">and now_money = #{nowMoney}</if>
+            <if test="brokeragePrice != null ">and brokerage_price = #{brokeragePrice}</if>
+            <if test="integral != null ">and integral = #{integral}</if>
+            <if test="signNum != null ">and sign_num = #{signNum}</if>
+            <if test="status != null ">and status = #{status}</if>
+            <if test="level != null ">and level = #{level}</if>
+            <if test="spreadUserId != null ">and spread_user_id = #{spreadUserId}</if>
+            <if test="spreadTime != null ">and spread_time = #{spreadTime}</if>
+            <if test="userType != null  and userType != ''">and user_type = #{userType}</if>
+            <if test="isPromoter != null ">and is_promoter = #{isPromoter}</if>
+            <if test="payCount != null ">and pay_count = #{payCount}</if>
+            <if test="spreadCount != null ">and spread_count = #{spreadCount}</if>
+            <if test="addres != null  and addres != ''">and addres = #{addres}</if>
+            <if test="isDel != null ">and is_del = #{isDel}</if>
+            <if test="companyId != null ">and company_id = #{companyId}</if>
+            <if test="companyUserId != null ">and company_user_id = #{companyUserId}</if>
+            <if test="registerDate != null ">and DATE_FORMAT(register_date,'%Y-%m-%d') =
+                DATE_FORMAT(#{registerDate},'%Y-%m-%d')
+            </if>
+            <if test="registerCode != null   and registerCode != '' ">and register_code = #{registerCode}</if>
+            <if test="source != null  and source != '' ">and source = #{source}</if>
+            <if test="isShow != null  ">and is_show = #{isShow}</if>
         </where>
         order by user_id desc
     </select>
@@ -92,44 +132,91 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectFsUserListLimit" resultType="com.fs.store.domain.FsUser">
         <include refid="selectFsUserVo"/>
         <where>
-            <if test="password != null  and password != ''"> and password = #{password}</if>
-            <if test="realName != null  and realName != ''"> and real_name like concat('%', #{realName}, '%')</if>
-            <if test="birthday != null "> and birthday = #{birthday}</if>
-            <if test="idCard != null  and idCard != ''"> and id_card = #{idCard}</if>
-            <if test="remark != null  and remark != ''"> and remark = #{remark}</if>
-            <if test="avatar != null  and avatar != ''"> and avatar = #{avatar}</if>
-            <if test="lastIp != null  and lastIp != ''"> and last_ip = #{lastIp}</if>
-            <if test="nowMoney != null "> and now_money = #{nowMoney}</if>
-            <if test="brokeragePrice != null "> and brokerage_price = #{brokeragePrice}</if>
-            <if test="integral != null "> and integral = #{integral}</if>
-            <if test="signNum != null "> and sign_num = #{signNum}</if>
-            <if test="status != null "> and status = #{status}</if>
-            <if test="level != null "> and level = #{level}</if>
-            <if test="spreadUserId != null "> and spread_user_id = #{spreadUserId}</if>
-            <if test="spreadTime != null "> and spread_time = #{spreadTime}</if>
-            <if test="userType != null  and userType != ''"> and user_type = #{userType}</if>
-            <if test="isPromoter != null "> and is_promoter = #{isPromoter}</if>
-            <if test="payCount != null "> and pay_count = #{payCount}</if>
-            <if test="spreadCount != null "> and spread_count = #{spreadCount}</if>
-            <if test="addres != null  and addres != ''"> and addres = #{addres}</if>
-            <if test="isDel != null "> and is_del = #{isDel}</if>
-            <if test="companyId != null "> and company_id = #{companyId}</if>
-            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
-            <if test="registerDate != null "> and DATE_FORMAT(register_date,'%Y-%m-%d') = DATE_FORMAT(#{registerDate},'%Y-%m-%d')</if>
-            <if test="registerCode != null   and registerCode != '' "> and register_code = #{registerCode}</if>
-            <if test="source != null  and source != '' "> and source = #{source}</if>
-            <if test="isShow != null  "> and is_show = #{isShow}</if>
-             <if test="(username != null  and username != '') or (nickname != null  and nickname != '') or (phone != null  and phone != '')">
-                 and (
-                 <if test="username != null  and username != ''"> username like concat('%', #{username}, '%')</if>
-                 <if test="nickname != null  and nickname != ''"> or nickname like concat('%', #{nickname}, '%')</if>
-                 <if test="phone != null  and phone != ''"> or phone like concat('%',#{phone},'%')</if>
-                 )
-             </if>
+            <if test="password != null  and password != ''">and password = #{password}</if>
+            <if test="realName != null  and realName != ''">and real_name like concat('%', #{realName}, '%')</if>
+            <if test="birthday != null ">and birthday = #{birthday}</if>
+            <if test="idCard != null  and idCard != ''">and id_card = #{idCard}</if>
+            <if test="remark != null  and remark != ''">and remark = #{remark}</if>
+            <if test="avatar != null  and avatar != ''">and avatar = #{avatar}</if>
+            <if test="lastIp != null  and lastIp != ''">and last_ip = #{lastIp}</if>
+            <if test="nowMoney != null ">and now_money = #{nowMoney}</if>
+            <if test="brokeragePrice != null ">and brokerage_price = #{brokeragePrice}</if>
+            <if test="integral != null ">and integral = #{integral}</if>
+            <if test="signNum != null ">and sign_num = #{signNum}</if>
+            <if test="status != null ">and status = #{status}</if>
+            <if test="level != null ">and level = #{level}</if>
+            <if test="spreadUserId != null ">and spread_user_id = #{spreadUserId}</if>
+            <if test="spreadTime != null ">and spread_time = #{spreadTime}</if>
+            <if test="userType != null  and userType != ''">and user_type = #{userType}</if>
+            <if test="isPromoter != null ">and is_promoter = #{isPromoter}</if>
+            <if test="payCount != null ">and pay_count = #{payCount}</if>
+            <if test="spreadCount != null ">and spread_count = #{spreadCount}</if>
+            <if test="addres != null  and addres != ''">and addres = #{addres}</if>
+            <if test="isDel != null ">and is_del = #{isDel}</if>
+            <if test="companyId != null ">and company_id = #{companyId}</if>
+            <if test="companyUserId != null ">and company_user_id = #{companyUserId}</if>
+            <if test="registerDate != null ">and DATE_FORMAT(register_date,'%Y-%m-%d') =
+                DATE_FORMAT(#{registerDate},'%Y-%m-%d')
+            </if>
+            <if test="registerCode != null   and registerCode != '' ">and register_code = #{registerCode}</if>
+            <if test="source != null  and source != '' ">and source = #{source}</if>
+            <if test="isShow != null  ">and is_show = #{isShow}</if>
+            <if test="(username != null  and username != '') or (nickname != null  and nickname != '') or (phone != null  and phone != '')">
+                and (
+                <if test="username != null  and username != ''">username like concat('%', #{username}, '%')</if>
+                <if test="nickname != null  and nickname != ''">or nickname like concat('%', #{nickname}, '%')</if>
+                <if test="phone != null  and phone != ''">or phone like concat('%',#{phone},'%')</if>
+                )
+            </if>
         </where>
         order by user_id desc
         limit 10
     </select>
+    <select id="selectCusListPage" resultType="com.fs.store.domain.FsUser">
+        select user.user_id,
+        user.username,
+        user.real_name,
+        user.id_card,
+        user.phone,
+        user.addres,
+        user.nickname,
+        user.status,
+        user.company_id,
+        user.company_user_id,
+        user.create_time
+        from
+        fs_user `user` join (
+        select user_id from fs_user
+        <where>
+            <if test="companyId != null and companyId != ''">
+                AND company_id = #{companyId}
+            </if>
+            <if test="companyUserId != null and companyUserId != ''">
+                AND company_user_id = #{companyUserId}
+            </if>
+            <if test="phone != null and phone != ''">
+                AND phone = #{phone}
+            </if>
+        </where>
+        order by user_id desc
+        limit ${(pageNum-1)*pageSize},${pageSize}
+        ) t on t.user_id = `user`.user_id
+    </select>
+    <select id="selectCusListPageCount" resultType="java.lang.Long">
+        SELECT COUNT(user_id)
+        FROM fs_user
+        <where>
+            <if test="companyId != null and companyId != ''">
+                AND company_id = #{companyId}
+            </if>
+            <if test="companyUserId != null and companyUserId != ''">
+                AND company_user_id = #{companyUserId}
+            </if>
+            <if test="phone != null and phone != ''">
+                AND phone = #{phone}
+            </if>
+        </where>
+    </select>
 
     <insert id="insertFsUser" parameterType="FsUser" useGeneratedKeys="true" keyProperty="userId">
         insert into fs_user
@@ -171,7 +258,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="source != null">source,</if>
             <if test="userCode != null">user_code,</if>
             <if test="isShow != null">is_show,</if>
-         </trim>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="username != null">#{username},</if>
             <if test="password != null">#{password},</if>
@@ -210,7 +297,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="source != null">#{source},</if>
             <if test="userCode != null">#{userCode},</if>
             <if test="isShow != null">#{isShow},</if>
-         </trim>
+        </trim>
     </insert>
 
     <update id="updateFsUser" parameterType="FsUser">
@@ -256,9 +343,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </trim>
         where user_id = #{userId}
     </update>
+    <update id="transferCompanyUser">
+        update fs_user
+        set company_user_id=#{targetCompanyUserId}
+        where
+            user_id in
+        <foreach collection="userIds" open="(" close=")" separator="," item="item">
+            ${item}
+        </foreach>
+    </update>
 
     <delete id="deleteFsUserById" parameterType="Long">
-        delete from fs_user where user_id = #{userId}
+        delete
+        from fs_user
+        where user_id = #{userId}
     </delete>
 
     <delete id="deleteFsUserByIds" parameterType="String">
@@ -279,12 +377,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         fs_user_course_count.course_id,
         fs_user_course_count.part_course_count,
         fs_user_course_count.last_watch_date,
-        fs_user_course_count.STATUS AS course_count,
+        fs_user_course_count.STATUS AS courseCountStatus,
         fs_user_course_count.stop_watch_days,
         fs_user_course_count.create_time,
         fs_user_course_count.complete_watch_date,
         company_tag.tag,
-        company_tag_user.tag_ids
+        company_tag_user.tag_ids,
+        company_user.nick_name as companyUserNickName
         FROM
         fs_user
         left join company_user on fs_user.company_user_id = company_user.user_id
@@ -292,6 +391,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         LEFT JOIN company_tag_user ON fs_user.user_id = company_tag_user.user_id
         LEFT JOIN company_tag ON FIND_IN_SET(company_tag.tag_id, company_tag_user.tag_ids) > 0
         where company_user.parent_id = #{userId}
+        <if test="companyUserId != null and companyUserId !='' ">
+            and company_user.user_id = #{companyUserId}
+        </if>
         <choose>
             <when test = "isBlack">
                 AND fs_user.status = 0
@@ -353,6 +455,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 </when>
             </choose>
         </if>
+        <if test="continueMissCourseSort != null and continueMissCourseSort !='' ">
+            order by
+            <choose>
+                <when test = "continueMissCourseSort == 0">
+                    fs_user_course_count.miss_course_days desc
+                </when>
+                <when test = "continueMissCourseSort == 1">
+                    fs_user_course_count.miss_course_days asc
+                </when>
+                <when test = "continueMissCourseSort == 2">
+                    fs_user.create_time desc
+                </when>
+                <when test = "continueMissCourseSort == 3">
+                    fs_user.nickname asc
+                </when>
+            </choose>
+        </if>
 
     </select>
 
@@ -371,9 +490,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="getCountAnswer" resultType="UserDetailsVO">
         SELECT
-            (
+        (
                 SELECT
-                    count( DISTINCT log_id ) AS answerTime
+                ifnull(count( DISTINCT log_id ), 0) AS answerTime
                 FROM
                     fs_course_answer_logs
                         LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
@@ -400,10 +519,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     fs_user.user_id
                 HAVING
                     fs_user.user_id = #{fsUserId}
-            ),
+            ) AS answerTime,
             (
                 SELECT
-                    count( DISTINCT log_id ) AS answerRightTime
+                ifnull(count( DISTINCT log_id ), 0) AS answerRightTime
                 FROM
                     fs_course_answer_logs
                         LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
@@ -431,24 +550,51 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     fs_user.user_id
                 HAVING
                     fs_user.user_id = #{fsUserId}
-            );
+            ) AS answerRightTime;
     </select>
 
-    <select id="getCountRedPacket" resultType="UserDetailsVO">
+    <select id="getCountRedPacket" resultType="com.fs.store.vo.h5.UserDetailsVO">
         SELECT
-            count( DISTINCT log_id ) AS answerRedPacketTime,
-            sum( amount ) AS answerRedPacketAmount,
-            complete_watch_count,
-            watch_times,
-            fs_user.user_id
+        ifnull( count( DISTINCT log_id ), 0 ) AS answerRedPacketTime,
+        ifnull( sum( amount ), 0 ) AS answerRedPacketAmount,
+        ifnull( complete_watch_count, 0 ) AS completeWatchCount ,
+        ifnull( watch_times, 0 ) AS watchTimes,
+        fs_user.user_id
         FROM
             fs_course_red_packet_log
                 LEFT JOIN fs_user ON fs_user.user_id = fs_course_red_packet_log.user_id
                 LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+                LEFT JOIN fs_user_course_count ON fs_user_course_count.user_id = fs_user.user_id
         WHERE
             company_user.parent_id = #{userId}
+            <if test="dateTag != null and dateTag !='' ">
+                <choose>
+                    <when test = "dateTag == '今天'">
+                        and to_days(fs_course_red_packet_log.create_time) = to_days(now())
+                    </when>
+                    <when test = "dateTag == ' 昨天'">
+                        and to_days(now()) - to_days(fs_course_red_packet_log.create_time) &lt;= 1
+                    </when>
+                    <when test = "dateTag == '前天'">
+                        and to_days(now()) - to_days(fs_course_red_packet_log.create_time) &lt;= 2
+                    </when>
+                    <when test = "dateTag == '近七天'">
+                        and DATE_SUB(CURDATE(), INTERVAL 7 DAY) &lt;= date(fs_course_red_packet_log.create_time)
+                    </when>
+                </choose>
+            </if>
+        GROUP BY
+        fs_user.user_id
+        HAVING
+        fs_user.user_id = #{fsUserId}
     </select>
 
-
+    <update id="batchUpdateFsUserByIds" parameterType="Long">
+        update fs_user
+        set status = #{status} where user_id in
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
 
 </mapper>

+ 8 - 32
fs-user-app/src/main/java/com/fs/app/controller/WxPayController.java

@@ -30,6 +30,7 @@ import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -108,40 +109,15 @@ public class WxPayController {
         }
     }
 
-    @PostMapping(value = "/TransferNotify")
-    public String TransferNotify(String notifyData,HttpServletRequest request, HttpServletResponse response) throws Exception {
-        SignatureHeader signatureHeader = new SignatureHeader();
-        signatureHeader.setTimeStamp(response.getHeader("Wechatpay-Timestamp"));
-        signatureHeader.setNonce(response.getHeader("Wechatpay-Nonce"));
-        signatureHeader.setSerial(response.getHeader("Wechatpay-Serial"));
-        signatureHeader.setSignature(response.getHeader("Wechatpay-Signature"));
-        try {
-            String json = configService.selectConfigByKey("redPacket.config");
-            RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
-            //创建微信订单
-            WxPayConfig payConfig = new WxPayConfig();
-            BeanUtils.copyProperties(config,payConfig);
-            WxPayService wxPayService = new WxPayServiceImpl();
-            wxPayService.setConfig(payConfig);
-            WxPayTransferBatchesNotifyV3Result result = wxPayService.parseTransferBatchesNotifyV3Result(notifyData,signatureHeader);
-            logger.info("到零钱回调:{}",result.getResult());
-            if (result.getResult().getBatchStatus().equals("FINISHED")) {
-                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBatchNo());
-                logger.info("result:{}",r);
-                if (r.get("code").equals(200)){
-                    return WxPayNotifyResponse.success("处理成功");
-                }else {
-                    return WxPayNotifyResponse.fail("");
-                }
-            }else {
-                return WxPayNotifyResponse.fail("");
-            }
-        } catch (Exception e) {
-            logger.error("微信回调结果异常,异常原因{}", e.getMessage());
-            return WxPayNotifyResponse.fail(e.getMessage());
-        }
+    @PostMapping( "/TransferNotify")
+    public String TransferNotify(@RequestBody String notifyData, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        return storePaymentService.transferNotify(notifyData,request);
+    }
 
 
+    @PostMapping( "/v3TransferNotify")
+    public String v3TransferNotify(@RequestBody String notifyData,HttpServletRequest request, HttpServletResponse response) throws Exception {
+        return storePaymentService.v3TransferNotify(notifyData,request);
     }
 
 }