Prechádzať zdrojové kódy

Merge remote-tracking branch 'origin/master'

yh 3 mesiacov pred
rodič
commit
ede779225c

+ 98 - 9
fs-company/src/main/java/com/fs/company/controller/qw/QwTagGroupController.java

@@ -1,22 +1,31 @@
 package com.fs.company.controller.qw;
 
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.service.IQwTagGroupService;
 import com.fs.qw.vo.QwTagGroupAddParam;
 import com.fs.qw.vo.QwTagGroupListVO;
+import com.fs.qwApi.config.OpenQwConfig;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.net.SocketTimeoutException;
 import java.util.List;
 
 /**
@@ -25,6 +34,7 @@ import java.util.List;
  * @author fs
  * @date 2024-06-20
  */
+@Slf4j
 @RestController
 @RequestMapping("/qw/tagGroup")
 public class QwTagGroupController extends BaseController
@@ -36,6 +46,10 @@ public class QwTagGroupController extends BaseController
 
     @Autowired
     private RedisTemplate redisTemplate;
+
+    /** HTTP调用超时时间(秒) */
+    @Value("${qw.api.timeout:30}")
+    private int apiTimeout;
     /**
      * 查询企微客户标签组列表
      */
@@ -74,8 +88,26 @@ public class QwTagGroupController extends BaseController
     @PostMapping("/syncTag/{corpId}")
     public R syncTag(@PathVariable("corpId") String corpId)
     {
-
-        return qwTagGroupService.syncQwTagGroup(corpId);
+        // 从当前登录用户获取租户ID
+        Long tenantId = SecurityUtils.getTenantId();
+        String url = OpenQwConfig.api + "/qw/tagGroup/syncTag/" + corpId + "?tenantId=" + tenantId;
+        try {
+            HttpResponse response = HttpRequest.get(url)
+                    .timeout(apiTimeout * 1000)
+                    .execute();
+            if (response.getStatus() == 200) {
+                return JSON.parseObject(response.body(), R.class);
+            } else {
+                log.error("同步标签失败,HTTP状态码: {}", response.getStatus());
+                return R.error("同步标签失败,服务返回状态码: " + response.getStatus());
+            }
+        } catch (Exception e) {
+            log.error("同步标签异常, url={}", url, e);
+            if (e.getCause() instanceof SocketTimeoutException) {
+                return R.error("同步标签超时,请稍后重试");
+            }
+            return R.error("同步标签失败: " + e.getMessage());
+        }
     }
 
     /**
@@ -110,8 +142,27 @@ public class QwTagGroupController extends BaseController
     @PostMapping
     public AjaxResult add(@RequestBody QwTagGroupAddParam qwTagGroup)
     {
-
-        return toAjax(qwTagGroupService.insertQwTagGroupParam(qwTagGroup));
+        // 从当前登录用户获取租户ID
+        Long tenantId = SecurityUtils.getTenantId();
+        String url = OpenQwConfig.api + "/qw/tagGroup?tenantId=" + tenantId;
+        try {
+            HttpResponse response = HttpRequest.post(url)
+                    .body(JSON.toJSONString(qwTagGroup))
+                    .timeout(apiTimeout * 1000)
+                    .execute();
+            if (response.getStatus() == 200) {
+                return JSON.parseObject(response.body(), AjaxResult.class);
+            } else {
+                log.error("新增标签组失败,HTTP状态码: {}", response.getStatus());
+                return AjaxResult.error("新增标签组失败,服务返回状态码: " + response.getStatus());
+            }
+        } catch (Exception e) {
+            log.error("新增标签组异常, url={}", url, e);
+            if (e.getCause() instanceof SocketTimeoutException) {
+                return AjaxResult.error("新增标签组超时,请稍后重试");
+            }
+            return AjaxResult.error("新增标签组失败: " + e.getMessage());
+        }
     }
 
     /**
@@ -122,8 +173,27 @@ public class QwTagGroupController extends BaseController
     @PutMapping
     public AjaxResult edit(@RequestBody QwTagGroupAddParam qwTagGroup)
     {
-
-        return toAjax(qwTagGroupService.updateQwTagGroupParam(qwTagGroup));
+        // 从当前登录用户获取租户ID
+        Long tenantId = SecurityUtils.getTenantId();
+        String url = OpenQwConfig.api + "/qw/tagGroup/update?tenantId=" + tenantId;
+        try {
+            HttpResponse response = HttpRequest.post(url)
+                    .body(JSON.toJSONString(qwTagGroup))
+                    .timeout(apiTimeout * 1000)
+                    .execute();
+            if (response.getStatus() == 200) {
+                return JSON.parseObject(response.body(), AjaxResult.class);
+            } else {
+                log.error("修改标签组失败,HTTP状态码: {}", response.getStatus());
+                return AjaxResult.error("修改标签组失败,服务返回状态码: " + response.getStatus());
+            }
+        } catch (Exception e) {
+            log.error("修改标签组异常, url={}", url, e);
+            if (e.getCause() instanceof SocketTimeoutException) {
+                return AjaxResult.error("修改标签组超时,请稍后重试");
+            }
+            return AjaxResult.error("修改标签组失败: " + e.getMessage());
+        }
     }
 
     /**
@@ -131,10 +201,29 @@ public class QwTagGroupController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('qw:tagGroup:remove')")
     @Log(title = "企微客户标签组", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{ids}")
+    @DeleteMapping("/{ids}")
     public R remove(@PathVariable Long[] ids)
     {
-
-        return qwTagGroupService.deleteQwTagGroupByIds(ids);
+        // 从当前登录用户获取租户ID
+        Long tenantId = SecurityUtils.getTenantId();
+        String url = OpenQwConfig.api + "/qw/tagGroup/delete/" + StringUtils.join(ids, ",") + "?tenantId=" + tenantId;
+        try {
+            HttpResponse response = HttpRequest.post(url)
+                    .body(JSON.toJSONString(ids))
+                    .timeout(apiTimeout * 1000)
+                    .execute();
+            if (response.getStatus() == 200) {
+                return JSON.parseObject(response.body(), R.class);
+            } else {
+                log.error("删除标签组失败,HTTP状态码: {}", response.getStatus());
+                return R.error("删除标签组失败,服务返回状态码: " + response.getStatus());
+            }
+        } catch (Exception e) {
+            log.error("删除标签组异常, url={}", url, e);
+            if (e.getCause() instanceof SocketTimeoutException) {
+                return R.error("删除标签组超时,请稍后重试");
+            }
+            return R.error("删除标签组失败: " + e.getMessage());
+        }
     }
 }

+ 93 - 0
fs-qw-api/src/main/java/com/fs/app/controller/QwTagGroupController.java

@@ -0,0 +1,93 @@
+package com.fs.app.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.framework.datasource.TenantDataSourceUtil;
+import com.fs.framework.service.TokenService;
+import com.fs.qw.domain.QwTagGroup;
+import com.fs.qw.service.IQwTagGroupService;
+import com.fs.qw.vo.QwTagGroupAddParam;
+import com.fs.qw.vo.QwTagGroupListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 企微客户标签组Controller
+ *
+ * @author fs
+ * @date 2024-06-20
+ */
+@RestController
+@RequestMapping("/qw/tagGroup")
+public class QwTagGroupController extends BaseController
+{
+    @Autowired
+    private IQwTagGroupService qwTagGroupService;
+
+    @Resource
+    private TenantDataSourceUtil tenantDataSourceUtil;
+
+    @Log(title = "同步标签", businessType = BusinessType.INSERT)
+    @GetMapping("/syncTag/{corpId}")
+    public R syncTag(@PathVariable("corpId") String corpId,
+                     @RequestParam("tenantId") Long tenantId)
+    {
+        // 切换到指定租户数据源执行操作
+        return tenantDataSourceUtil.executeWithResult(tenantId, () -> {
+            return qwTagGroupService.syncQwTagGroup(corpId);
+        });
+    }
+
+    /**
+     * 新增企微客户标签组
+     */
+    @Log(title = "企微客户标签组", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwTagGroupAddParam qwTagGroup,
+                          @RequestParam("tenantId") Long tenantId)
+    {
+        // 切换到指定租户数据源执行操作
+        int result = tenantDataSourceUtil.executeWithResult(tenantId, () -> {
+            return qwTagGroupService.insertQwTagGroupParam(qwTagGroup);
+        });
+        return toAjax(result);
+    }
+
+    /**
+     * 修改企微客户标签组
+     */
+    @PostMapping("/update")
+    public AjaxResult edit(@RequestBody QwTagGroupAddParam qwTagGroup,
+                           @RequestParam("tenantId") Long tenantId)
+    {
+        // 切换到指定租户数据源执行操作
+        int result = tenantDataSourceUtil.executeWithResult(tenantId, () -> {
+            return qwTagGroupService.updateQwTagGroupParam(qwTagGroup);
+        });
+        return toAjax(result);
+    }
+
+    /**
+     * 删除企微客户标签组
+     */
+    @Log(title = "企微客户标签组", businessType = BusinessType.DELETE)
+	@PostMapping("/delete/{ids}")
+    public R remove(@PathVariable Long[] ids,
+                    @RequestParam("tenantId") Long tenantId)
+    {
+        // 切换到指定租户数据源执行操作
+        return tenantDataSourceUtil.executeWithResult(tenantId, () -> {
+            return qwTagGroupService.deleteQwTagGroupByIds(ids);
+        });
+    }
+}

+ 201 - 0
fs-qw-api/src/main/java/com/fs/framework/datasource/TenantDataSourceUtil.java

@@ -0,0 +1,201 @@
+package com.fs.framework.datasource;
+
+import com.fs.tenant.domain.TenantInfo;
+import com.fs.tenant.service.TenantInfoService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * 租户数据源切换工具类
+ * 用于在指定租户数据源下执行增删改查操作
+ */
+@Slf4j
+@Component
+public class TenantDataSourceUtil {
+
+    @Resource
+    private TenantDataSourceManager tenantDataSourceManager;
+
+    @Resource
+    private TenantInfoService tenantInfoService;
+
+    /**
+     * 在指定租户数据源下执行操作(无返回值)
+     *
+     * @param tenantId 租户ID
+     * @param action   要执行的操作
+     */
+    public void execute(Long tenantId, Runnable action) {
+        TenantInfo tenantInfo = getTenantInfo(tenantId);
+        if (tenantInfo == null) {
+            throw new IllegalArgumentException("租户不存在或已禁用,tenantId=" + tenantId);
+        }
+        execute(tenantInfo, action);
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(无返回值)
+     *
+     * @param tenantInfo 租户信息
+     * @param action     要执行的操作
+     */
+    public void execute(TenantInfo tenantInfo, Runnable action) {
+        try {
+            // 切换到租户数据源
+            tenantDataSourceManager.switchTenant(tenantInfo);
+            log.debug("[TenantDS] 已切换到租户数据源: tenantId={}, tenantCode={}",
+                    tenantInfo.getId(), tenantInfo.getTenantCode());
+
+            // 执行操作
+            action.run();
+
+        } finally {
+            // 清理数据源上下文
+            tenantDataSourceManager.clear();
+            log.debug("[TenantDS] 已清理租户数据源上下文");
+        }
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(带返回值)
+     *
+     * @param tenantId 租户ID
+     * @param action   要执行的操作
+     * @param <T>      返回值类型
+     * @return 操作结果
+     */
+    public <T> T executeWithResult(Long tenantId, Supplier<T> action) {
+        TenantInfo tenantInfo = getTenantInfo(tenantId);
+        if (tenantInfo == null) {
+            throw new IllegalArgumentException("租户不存在或已禁用,tenantId=" + tenantId);
+        }
+        return executeWithResult(tenantInfo, action);
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(带返回值)
+     *
+     * @param tenantInfo 租户信息
+     * @param action     要执行的操作
+     * @param <T>        返回值类型
+     * @return 操作结果
+     */
+    public <T> T executeWithResult(TenantInfo tenantInfo, Supplier<T> action) {
+        try {
+            // 切换到租户数据源
+            tenantDataSourceManager.switchTenant(tenantInfo);
+            log.debug("[TenantDS] 已切换到租户数据源: tenantId={}, tenantCode={}",
+                    tenantInfo.getId(), tenantInfo.getTenantCode());
+
+            // 执行操作并返回结果
+            return action.get();
+
+        } finally {
+            // 清理数据源上下文
+            tenantDataSourceManager.clear();
+            log.debug("[TenantDS] 已清理租户数据源上下文");
+        }
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(消费租户信息,无返回值)
+     *
+     * @param tenantId 租户ID
+     * @param action   要执行的操作,接收租户信息作为参数
+     */
+    public void executeWithTenant(Long tenantId, Consumer<TenantInfo> action) {
+        TenantInfo tenantInfo = getTenantInfo(tenantId);
+        if (tenantInfo == null) {
+            throw new IllegalArgumentException("租户不存在或已禁用,tenantId=" + tenantId);
+        }
+        executeWithTenant(tenantInfo, action);
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(消费租户信息,无返回值)
+     *
+     * @param tenantInfo 租户信息
+     * @param action     要执行的操作,接收租户信息作为参数
+     */
+    public void executeWithTenant(TenantInfo tenantInfo, Consumer<TenantInfo> action) {
+        try {
+            // 切换到租户数据源
+            tenantDataSourceManager.switchTenant(tenantInfo);
+            log.debug("[TenantDS] 已切换到租户数据源: tenantId={}, tenantCode={}",
+                    tenantInfo.getId(), tenantInfo.getTenantCode());
+
+            // 执行操作
+            action.accept(tenantInfo);
+
+        } finally {
+            // 清理数据源上下文
+            tenantDataSourceManager.clear();
+            log.debug("[TenantDS] 已清理租户数据源上下文");
+        }
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(消费租户信息,带返回值)
+     *
+     * @param tenantId 租户ID
+     * @param action   要执行的操作,接收租户信息并返回结果
+     * @param <R>      返回值类型
+     * @return 操作结果
+     */
+    public <R> R executeWithTenantAndResult(Long tenantId, Function<TenantInfo, R> action) {
+        TenantInfo tenantInfo = getTenantInfo(tenantId);
+        if (tenantInfo == null) {
+            throw new IllegalArgumentException("租户不存在或已禁用,tenantId=" + tenantId);
+        }
+        return executeWithTenantAndResult(tenantInfo, action);
+    }
+
+    /**
+     * 在指定租户数据源下执行操作(消费租户信息,带返回值)
+     *
+     * @param tenantInfo 租户信息
+     * @param action     要执行的操作,接收租户信息并返回结果
+     * @param <R>        返回值类型
+     * @return 操作结果
+     */
+    public <R> R executeWithTenantAndResult(TenantInfo tenantInfo, Function<TenantInfo, R> action) {
+        try {
+            // 切换到租户数据源
+            tenantDataSourceManager.switchTenant(tenantInfo);
+            log.debug("[TenantDS] 已切换到租户数据源: tenantId={}, tenantCode={}",
+                    tenantInfo.getId(), tenantInfo.getTenantCode());
+
+            // 执行操作并返回结果
+            return action.apply(tenantInfo);
+
+        } finally {
+            // 清理数据源上下文
+            tenantDataSourceManager.clear();
+            log.debug("[TenantDS] 已清理租户数据源上下文");
+        }
+    }
+
+    /**
+     * 获取租户信息
+     *
+     * @param tenantId 租户ID
+     * @return 租户信息,不存在或已禁用则返回null
+     */
+    private TenantInfo getTenantInfo(Long tenantId) {
+        TenantInfo tenantInfo = tenantInfoService.getById(tenantId);
+        if (tenantInfo == null) {
+            log.warn("[TenantDS] 租户不存在,tenantId={}", tenantId);
+            return null;
+        }
+        if (!Integer.valueOf(1).equals(tenantInfo.getStatus())) {
+            log.warn("[TenantDS] 租户已禁用,tenantId={}", tenantId);
+            return null;
+        }
+        return tenantInfo;
+    }
+}

+ 1 - 0
fs-service/src/main/java/com/fs/qwApi/config/OpenQwConfig.java

@@ -2,4 +2,5 @@ package com.fs.qwApi.config;
 
 public interface OpenQwConfig {
     String baseApi ="http://127.0.0.1:8007/open/qwapi";
+    String api ="http://127.0.0.1:8007";
 }

+ 14 - 1
fs-service/src/main/java/com/fs/qwApi/service/impl/QwApiServiceImpl.java

@@ -1408,12 +1408,25 @@ public class QwApiServiceImpl implements QwApiService {
         }
         return null;
     }
+
+    String getPermanentCode(String corpId){
+        String key =(String)redisCache.getCacheObject("permanentCode:corpId:" + corpId);
+        if (!StringUtil.strIsNullOrEmpty(key)){
+            return key;
+        }
+        QwCompany qwCompany = iQwCompanyService.selectQwCompanyByCorpId(corpId);
+        if (qwCompany!=null&&qwCompany.getPermanentCode()!=null){
+            redisCache.setCacheObject("permanentCode:corpId:" + corpId,qwCompany.getPermanentCode(),1,TimeUnit.HOURS);
+            return qwCompany.getOpenSecret();
+        }
+        return null;
+    }
     public String sendPost(String url, Object param, String corpId,String appSecret) {
         int maxRetries = 3; // 最大重试次数
         int retryCount = 0; // 当前重试次数
         // 1. 获取配置信息(可放在循环外,但要确保每次都能获取到最新的token)
         if (StringUtils.isBlank(appSecret)) {
-            appSecret = getAppSecret(corpId);
+            appSecret = getPermanentCode(corpId);
         }
         while (retryCount < maxRetries) {
             try {