Selaa lähdekoodia

1、迁移润天绑定关系接口

yys 1 viikko sitten
vanhempi
commit
8891f18cf9

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

@@ -18,6 +18,7 @@ import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
 import java.time.LocalDate;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -368,4 +369,7 @@ public interface CompanyUserMapper
     List<CompanyUser> getSalesByCompanyId(@Param("param") AppDownloadParam param);
 
     SalesAppDownloadStatDTO getSalesAppDownloadStats(@Param("param") AppDownloadParam param);
+
+    @Update("update company_user set status=1 where user_type != '00' and login_date < #{thirtyDaysAgo}")
+    void stopLoginOverdue(@Param("thirtyDaysAgo") Date thirtyDaysAgo);
 }

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

@@ -0,0 +1,71 @@
+package com.fs.company.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.company.domain.CompanyCompanyFsuser;
+
+import java.util.List;
+
+/**
+ * 客服绑定用户Service接口
+ *
+ * @author fs
+ * @date 2025-04-09
+ */
+public interface ICompanyCompanyFsuserService extends IService<CompanyCompanyFsuser>{
+    /**
+     * 查询客服绑定用户
+     *
+     * @param id 客服绑定用户主键
+     * @return 客服绑定用户
+     */
+    CompanyCompanyFsuser selectCompanyCompanyUserById(Long id);
+
+    /**
+     * 查询客服绑定用户列表
+     *
+     * @param companyCompanyFsuser 客服绑定用户
+     * @return 客服绑定用户集合
+     */
+    List<CompanyCompanyFsuser> selectCompanyCompanyUserList(CompanyCompanyFsuser companyCompanyFsuser);
+
+    /**
+     * 新增客服绑定用户
+     *
+     * @param companyCompanyFsuser 客服绑定用户
+     * @return 结果
+     */
+    int insertCompanyCompanyUser(CompanyCompanyFsuser companyCompanyFsuser);
+
+    /**
+     * 修改客服绑定用户
+     *
+     * @param companyCompanyFsuser 客服绑定用户
+     * @return 结果
+     */
+    int updateCompanyCompanyUser(CompanyCompanyFsuser companyCompanyFsuser);
+
+    /**
+     * 批量删除客服绑定用户
+     *
+     * @param ids 需要删除的客服绑定用户主键集合
+     * @return 结果
+     */
+    int deleteCompanyCompanyUserByIds(Long[] ids);
+
+    /**
+     * 删除客服绑定用户信息
+     *
+     * @param id 客服绑定用户主键
+     * @return 结果
+     */
+    int deleteCompanyCompanyUserById(Long id);
+
+    R bind(Long companyUserId, String userId);
+
+    R getInfoByUserId(String userId);
+
+    void unbindCompany();
+
+    void stopLoginOverdue();
+}

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

@@ -17,6 +17,7 @@ import com.fs.wxUser.domain.CompanyWxUser;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -284,4 +285,6 @@ public interface ICompanyUserService {
     int unBind(String userId);
 
     CompanyUser getInviteCodeByCompanyUserIdAndUserId(Long invitedBySalesId);
+
+    void stopLoginOverdue(Date thirtyDaysAgo);
 }

+ 199 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyCompanyFsuserServiceImpl.java

@@ -0,0 +1,199 @@
+package com.fs.company.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyCompanyFsuser;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.domain.CompanyUserUser;
+import com.fs.company.mapper.CompanyCompanyFsuserMapper;
+import com.fs.company.service.ICompanyCompanyFsuserService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.his.config.AppConfig;
+import com.fs.im.service.OpenIMService;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.system.service.ISysConfigService;
+import com.fs.watch.service.WatchDeviceInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 客服绑定用户(一个用户绑定唯一一个客服)Service业务层处理
+ *
+ * @author fs
+ * @date 2025-04-09
+ */
+@Service
+public class CompanyCompanyFsuserServiceImpl extends ServiceImpl<CompanyCompanyFsuserMapper, CompanyCompanyFsuser> implements ICompanyCompanyFsuserService {
+    @Autowired
+    private ICompanyUserService companyUserService;
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+    @Autowired
+    private ISysConfigService configService;
+    @Autowired
+    private OpenIMService openIMService;
+    @Autowired
+    private WatchDeviceInfoService watchDeviceInfoService;
+    /**
+     * 查询客服绑定用户(一个用户绑定唯一一个客服)
+     *
+     * @param id 客服绑定用户(一个用户绑定唯一一个客服)主键
+     * @return 客服绑定用户(一个用户绑定唯一一个客服)
+     */
+    @Override
+    public CompanyCompanyFsuser selectCompanyCompanyUserById(Long id)
+    {
+        return baseMapper.selectCompanyCompanyUserById(id);
+    }
+
+    /**
+     * 查询客服绑定用户(一个用户绑定唯一一个客服)列表
+     *
+     * @param companyCompanyUser 客服绑定用户(一个用户绑定唯一一个客服)
+     * @return 客服绑定用户(一个用户绑定唯一一个客服)
+     */
+    @Override
+    public List<CompanyCompanyFsuser> selectCompanyCompanyUserList(CompanyCompanyFsuser companyCompanyUser)
+    {
+        return baseMapper.selectCompanyCompanyUserList(companyCompanyUser);
+    }
+
+    /**
+     * 新增客服绑定用户(一个用户绑定唯一一个客服)
+     *
+     * @param companyCompanyUser 客服绑定用户(一个用户绑定唯一一个客服)
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyCompanyUser(CompanyCompanyFsuser companyCompanyUser)
+    {
+        companyCompanyUser.setCreateTime(DateUtils.getNowDate());
+        openIMService.checkAndImportFriend(companyCompanyUser.getCompanyUserId(),companyCompanyUser.getUserId().toString());
+        return baseMapper.insertCompanyCompanyUser(companyCompanyUser);
+    }
+
+    /**
+     * 修改客服绑定用户(一个用户绑定唯一一个客服)
+     *
+     * @param companyCompanyUser 客服绑定用户(一个用户绑定唯一一个客服)
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyCompanyUser(CompanyCompanyFsuser companyCompanyUser)
+    {
+        companyCompanyUser.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateCompanyCompanyUser(companyCompanyUser);
+    }
+
+    /**
+     * 批量删除客服绑定用户(一个用户绑定唯一一个客服)
+     *
+     * @param ids 需要删除的客服绑定用户(一个用户绑定唯一一个客服)主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyCompanyUserByIds(Long[] ids)
+    {
+        return baseMapper.deleteCompanyCompanyUserByIds(ids);
+    }
+
+    /**
+     * 删除客服绑定用户(一个用户绑定唯一一个客服)信息
+     *
+     * @param id 客服绑定用户(一个用户绑定唯一一个客服)主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyCompanyUserById(Long id)
+    {
+        return baseMapper.deleteCompanyCompanyUserById(id);
+    }
+
+    @Override
+    @Transactional
+    public R bind(Long companyUserId, String userId) {
+        //查询客服
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(companyUserId);
+        if (companyUser == null){
+            return R.error("该链接不存在");
+        }
+        CompanyCompanyFsuser insertTemp = new CompanyCompanyFsuser();
+        insertTemp.setUserId(Long.valueOf(userId));
+        //查询是否绑定
+        List<CompanyCompanyFsuser> list = selectCompanyCompanyUserList(insertTemp);
+        if (list != null && !list.isEmpty()){
+            return R.error("已存在绑定关系");
+        }
+        insertTemp.setCompanyUserId(companyUserId);
+        insertTemp.setCompanyId(companyUser.getCompanyId());
+        insertTemp.setStatus(1);
+        insertTemp.setBindType(0);
+        //查询企微外部联系人
+        QwExternalContact qw= qwExternalContactService.selectQwExternalContactLastByFsUserAndCompany(
+                companyUserId,userId
+        );
+        if (qw != null){
+            //企业微信关联用户
+            insertTemp.setQwContactId(qw.getId());
+        }
+        //腕表绑定
+        CompanyUserUser companyUserUser = new CompanyUserUser();
+        companyUserUser.setCompanyId(companyUser.getCompanyId());
+        companyUserUser.setCompanyUserId(companyUserId);
+        companyUserUser.setUserId(Long.valueOf(userId));
+        watchDeviceInfoService.bindCompany(companyUserUser);
+        // 同步更新 fs_user.bind_company_user_id
+        companyUserService.batchUpdateBindCompanyUserId(Collections.singletonList(Long.valueOf(userId)), companyUserId);
+        //绑定
+        return insertCompanyCompanyUser(insertTemp)>0?R.ok("绑定成功"):R.error("绑定失败");
+    }
+
+    @Override
+    public R getInfoByUserId(String userId) {
+        CompanyCompanyFsuser user = baseMapper.getInfoByUserId(userId);
+        return R.ok().put("data",user);
+    }
+
+    @Override
+    public void unbindCompany() {
+        //先查询解绑限制天数
+        String json = configService.selectConfigByKey("app.config");
+        if (StringUtils.isNotBlank(json)) {
+            AppConfig config = JSONUtil.toBean(json, AppConfig.class);
+            if(config!=null) {
+                Integer limit = config.getUnbindLimit();
+                if (limit != null && limit > 0) {
+                    //需要解除绑定
+                    List<CompanyCompanyFsuser> list = baseMapper.selectNoHistoryApp(limit);
+                    if (list != null && !list.isEmpty()) {
+                        Long[] ids = list.stream().map(CompanyCompanyFsuser::getId).toArray(Long[]::new);
+                        if (ids.length > 0) {
+                            //删除绑定关系
+                                deleteCompanyCompanyUserByIds(ids);
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    @Override
+    public void stopLoginOverdue() {
+        // 获取当天0点的时间,往前推31天
+        Date thirtyDaysAgo = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtils.getNowDate(), -31));
+
+        companyUserService.stopLoginOverdue(thirtyDaysAgo);
+
+    }
+}

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

@@ -65,7 +65,9 @@ import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
+import java.net.URLDecoder;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -1051,7 +1053,12 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         if (companyUser != null) {
             if (StringUtils.isBlank(companyUser.getBindCode())) {
                 //生成二维码
-                InputStream qrCodeStream = QRutils.getQRCodeImageInputStream(url, 250, 250);
+                InputStream qrCodeStream = null;
+                try {
+                    qrCodeStream = QRutils.getQRCodeImageInputStream(URLDecoder.decode(url, "UTF-8"), 250, 250);
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
                 CloudStorageService storage = OSSFactory.build();
                 if (storage != null) {
                     String link = storage.uploadSuffix(qrCodeStream, ".jpg");
@@ -1166,4 +1173,10 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     public int unBind(String userId) {
         return companyUserMapper.unBind(userId);
     }
+
+    @Override
+    public void stopLoginOverdue(Date thirtyDaysAgo) {
+        companyUserMapper.stopLoginOverdue(thirtyDaysAgo);
+    }
+
 }

+ 48 - 28
fs-service/src/main/java/com/fs/live/service/impl/LiveConsoleOpLogServiceImpl.java

@@ -11,13 +11,11 @@ import com.fs.live.domain.LiveConsoleOpLogUser;
 import com.fs.live.domain.LiveCoupon;
 import com.fs.live.domain.LiveCouponIssue;
 import com.fs.live.domain.LiveCouponIssueRelation;
-import com.fs.live.domain.LiveCouponIssueUser;
 import com.fs.live.domain.LiveCouponUser;
 import com.fs.live.domain.LiveLotteryConf;
 import com.fs.live.domain.LiveRedConf;
 import com.fs.live.mapper.LiveConsoleOpLogMapper;
 import com.fs.live.mapper.LiveConsoleOpLogUserMapper;
-import com.fs.live.mapper.LiveCouponIssueUserMapper;
 import com.fs.live.mapper.LiveCouponMapper;
 import com.fs.live.mapper.LiveMapper;
 import com.fs.live.service.ILiveConsoleOpLogService;
@@ -77,12 +75,11 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
     @Autowired
     private LiveCouponMapper liveCouponMapper;
 
+    /** 中控台发券 live_coupon_user.type 前缀(按直播间隔离:live-{liveId}) */
+    private static final String LIVE_COUPON_USER_TYPE_PREFIX = "live-";
     /** 完课优惠券 live_coupon_user.type 前缀 */
     private static final String COMPLETION_COUPON_USER_TYPE_PREFIX = "4-";
 
-    @Autowired
-    private LiveCouponIssueUserMapper liveCouponIssueUserMapper;
-
     @Autowired
     private ILiveCouponUserService liveCouponUserService;
 
@@ -265,8 +262,10 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
                     .filter(Objects::nonNull)
                     .collect(Collectors.toSet());
         }
-        Set<Long> claimedCouponIssueIds = loadUserClaimedCouponIssueIds(userId);
+        // 中控台发券以 live_coupon_user(type=live-{liveId}) 为准,避免跨直播间共用 issue 误判已领取
+        Set<Long> claimedLiveCouponIds = loadUserClaimedLiveCouponIds(liveId, userId);
         Set<Long> claimedCompletionCouponIds = loadUserClaimedCompletionCouponIds(liveId, userId);
+        Map<Long, Long> issueCouponIdMap = resolveIssueCouponIdMap(opLogs);
 
         Date now = DateUtils.getNowDate();
         Live live = liveMapper.selectLiveByLiveId(liveId);
@@ -281,7 +280,8 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
                     && opLog.getOpType() == LiveConsoleOpLog.OP_COMPLETION_POINTS) {
                 continue;
             }
-            boolean claimed = isUserClaimedOpLog(opLog, claimedOpLogIds, claimedCouponIssueIds, claimedCompletionCouponIds);
+            boolean claimed = isUserClaimedOpLog(opLog, claimedOpLogIds, claimedLiveCouponIds,
+                    claimedCompletionCouponIds, issueCouponIdMap);
             int status = resolveOpLogStatus(opLog, claimed, now, live);
             LiveConsoleOpLogRecordVo recordVo = LiveConsoleOpLogRecordVo.from(opLog, status);
             fillCouponType(recordVo, opLog, couponTypeMap);
@@ -350,30 +350,26 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
         recordVo.setCouponType(couponTypeMap.get(opLog.getBizId()));
     }
 
-    private Set<Long> loadUserClaimedCouponIssueIds(Long userId) {
-        if (userId == null) {
-            return Collections.emptySet();
-        }
-        LiveCouponIssueUser query = new LiveCouponIssueUser();
-        query.setUserId(userId);
-        query.setIsDel(0);
-        List<LiveCouponIssueUser> issueUsers = liveCouponIssueUserMapper.selectLiveCouponIssueUserList(query);
-        if (issueUsers == null || issueUsers.isEmpty()) {
-            return Collections.emptySet();
-        }
-        return issueUsers.stream()
-                .map(LiveCouponIssueUser::getIssueId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
+    /**
+     * 当前直播间中控台发券已领取的优惠券 ID(live_coupon_user.type = live-{liveId})。
+     * 按直播间隔离,避免同一 issue 绑定到多个直播间时跨场误判。
+     */
+    private Set<Long> loadUserClaimedLiveCouponIds(Long liveId, Long userId) {
+        return loadUserClaimedCouponIdsByType(userId, LIVE_COUPON_USER_TYPE_PREFIX + liveId);
     }
 
     private Set<Long> loadUserClaimedCompletionCouponIds(Long liveId, Long userId) {
-        if (liveId == null || userId == null) {
+        return loadUserClaimedCouponIdsByType(userId, COMPLETION_COUPON_USER_TYPE_PREFIX + liveId);
+    }
+
+    private Set<Long> loadUserClaimedCouponIdsByType(Long userId, String type) {
+        if (userId == null || StringUtils.isEmpty(type)) {
             return Collections.emptySet();
         }
         LiveCouponUser query = new LiveCouponUser();
         query.setUserId(userId.intValue());
-        query.setType(COMPLETION_COUPON_USER_TYPE_PREFIX + liveId);
+        query.setType(type);
+        query.setIsDel(0);
         List<LiveCouponUser> couponUsers = liveCouponUserService.selectLiveCouponUserList(query);
         if (couponUsers == null || couponUsers.isEmpty()) {
             return Collections.emptySet();
@@ -384,12 +380,35 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
                 .collect(Collectors.toSet());
     }
 
+    /** 优惠券展示留存 bizId=issueId → couponId,用于对齐 live_coupon_user.coupon_id */
+    private Map<Long, Long> resolveIssueCouponIdMap(List<LiveConsoleOpLog> opLogs) {
+        Map<Long, Long> issueCouponIdMap = new HashMap<>();
+        if (opLogs == null || opLogs.isEmpty()) {
+            return issueCouponIdMap;
+        }
+        List<Long> issueIds = opLogs.stream()
+                .filter(log -> log.getOpType() != null && log.getBizId() != null
+                        && (log.getOpType() == LiveConsoleOpLog.OP_COUPON_SHOW
+                        || log.getOpType() == LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW))
+                .map(LiveConsoleOpLog::getBizId)
+                .distinct()
+                .collect(Collectors.toList());
+        for (Long issueId : issueIds) {
+            LiveCouponIssue issue = liveCouponIssueService.selectLiveCouponIssueById(issueId);
+            if (issue != null && issue.getCouponId() != null) {
+                issueCouponIdMap.put(issueId, issue.getCouponId());
+            }
+        }
+        return issueCouponIdMap;
+    }
+
     /**
      * 判断用户是否已领取/参与该条留存。
-     * 普通优惠券 additionally 以 live_coupon_issue_user 为准,避免领券时未绑定 opLog 被误判为已结束。
+     * 普通优惠券以当前直播间 live_coupon_user 为准,避免领券未绑定 opLog 或跨直播间共用 issue 误判
      */
     private boolean isUserClaimedOpLog(LiveConsoleOpLog opLog, Set<Long> claimedOpLogIds,
-                                       Set<Long> claimedCouponIssueIds, Set<Long> claimedCompletionCouponIds) {
+                                       Set<Long> claimedLiveCouponIds, Set<Long> claimedCompletionCouponIds,
+                                       Map<Long, Long> issueCouponIdMap) {
         if (opLog == null) {
             return false;
         }
@@ -401,10 +420,11 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
         }
         int opType = opLog.getOpType();
         if (opType == LiveConsoleOpLog.OP_COUPON_SHOW || opType == LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW) {
-            return claimedCouponIssueIds.contains(opLog.getBizId());
+            Long couponId = issueCouponIdMap != null ? issueCouponIdMap.get(opLog.getBizId()) : null;
+            return couponId != null && claimedLiveCouponIds != null && claimedLiveCouponIds.contains(couponId);
         }
         if (opType == LiveConsoleOpLog.OP_COMPLETION_COUPON) {
-            return claimedCompletionCouponIds.contains(opLog.getBizId());
+            return claimedCompletionCouponIds != null && claimedCompletionCouponIds.contains(opLog.getBizId());
         }
         return false;
     }

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

@@ -682,4 +682,7 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
 
     @Select("SELECT * FROM qw_external_contact WHERE company_user_id = #{companyUserId} AND qw_user_id = #{qwUserId} AND fs_user_id = #{userId} and status = 0 limit 1")
     QwExternalContact selectQwExternalContactByCompanyUserIdQwUserIdUserId(@Param("companyUserId") String companyUserId, @Param("qwUserId") String qwUserId, @Param("userId") String userId);
+
+    QwExternalContact selectQwExternalContactLastByFsUserAndCompany(@Param("companyUserId") Long companyUserId,
+                                                                    @Param("userId") String userId);
 }

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

@@ -295,4 +295,6 @@ public interface IQwExternalContactService extends IService<QwExternalContact> {
     TableDataInfo getSalesAppDownloadStats(AppDownloadParam param);
 
     List<SalesAppDownloadStatDTO> exportSalesAppDownloadStats(AppDownloadParam param);
+
+    QwExternalContact selectQwExternalContactLastByFsUserAndCompany(Long companyUserId, String userId);
 }

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

@@ -6214,5 +6214,8 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         qwExternalContactMapper.updateById(externalContact);
     }
 
-
+    @Override
+    public QwExternalContact selectQwExternalContactLastByFsUserAndCompany(Long companyUserId, String userId) {
+        return qwExternalContactMapper.selectQwExternalContactLastByFsUserAndCompany(companyUserId,userId);
+    }
 }

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

@@ -290,6 +290,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="SET" suffixOverrides=",">
             <if test="companyId != null">company_id = #{companyId},</if>
             <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="bindCode != null">bind_code = #{bindCode},</if>
             <if test="userName != null and userName != ''">user_name = #{userName},</if>
             <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
             <if test="userType != null">user_type = #{userType},</if>
@@ -331,6 +332,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="companyId != null">company_id = #{companyId},</if>
             <if test="deptId != null">dept_id = #{deptId},</if>
             <if test="userName != null and userName != ''">user_name = #{userName},</if>
+            <if test="bindCode != null">bind_code = #{bindCode},</if>
             <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
             <if test="email != null">email = #{email},</if>
             <if test="phonenumber != null">phonenumber = #{phonenumber},</if>

+ 8 - 0
fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

@@ -849,4 +849,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             and t1.corp_id = #{corpId}
             and t1.status = 0
      </select>
+
+
+    <select id="selectQwExternalContactLastByFsUserAndCompany" resultType="com.fs.qw.domain.QwExternalContact">
+        select * from qw_external_contact
+        where
+            company_user_id = #{companyUserId} and fs_user_id = #{userId}
+        order by create_time desc limit 1
+    </select>
 </mapper>

+ 71 - 0
fs-user-app/src/main/java/com/fs/app/controller/CompanyCompanyFsuserController.java

@@ -0,0 +1,71 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.company.domain.CompanyCompanyFsuser;
+import com.fs.company.service.ICompanyCompanyFsuserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 销售绑定用户(一个用户绑定唯一一个销售)Controller
+ *
+ * @author fs
+ * @date 2025-04-09
+ */
+@RestController
+@RequestMapping("/app/companyCompanyFsUser")
+public class CompanyCompanyFsuserController extends AppBaseController
+{
+    @Autowired
+    private ICompanyCompanyFsuserService companyCompanyFsuserService;
+
+    /**
+     * 查询销售绑定用户列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyCompanyFsuser companyCompanyFsuser)
+    {
+        startPage();
+        List<CompanyCompanyFsuser> list = companyCompanyFsuserService.selectCompanyCompanyUserList(companyCompanyFsuser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取销售绑定用户
+     */
+    @Login
+    @GetMapping(value = "/getInfoByUserId")
+    public R getInfoByUserId()
+    {
+        String userId = getUserId();
+        if (userId == null){
+            return R.error("请先登录");
+        }
+        return companyCompanyFsuserService.getInfoByUserId(userId);
+    }
+
+
+    /**
+     * 新增销售绑定用户
+     */
+    @Login
+    @GetMapping("/bind/{companyUserId}")
+    public R bind(@PathVariable("companyUserId") Long companyUserId)
+    {
+        String userId = getUserId();
+        if (userId == null){
+            return R.error("请先登录!");
+        }
+        return companyCompanyFsuserService.bind(companyUserId,userId);
+    }
+
+
+
+}