Просмотр исходного кода

Merge remote-tracking branch 'origin/saas-api' into saas-api

xgb 1 месяц назад
Родитель
Сommit
23905fde98
24 измененных файлов с 596 добавлено и 228 удалено
  1. 37 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticCallLogCallphoneController.java
  2. 5 4
      fs-company/src/main/resources/application-dev.yml
  3. 1 0
      fs-framework/src/main/java/com/fs/framework/config/SecurityConfig.java
  4. 25 0
      fs-qw-api/src/main/java/com/fs/app/controller/OpenQwApiController.java
  5. 1 0
      fs-qw-api/src/main/java/com/fs/app/service/impl/OpenQwApiServiceImpl.java
  6. 7 0
      fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallLogCallphone.java
  7. 5 1
      fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCallLogCallphoneMapper.java
  8. 10 1
      fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticCallLogCallphoneService.java
  9. 122 8
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java
  10. 88 53
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java
  11. 23 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO.java
  12. 19 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO.java
  13. 3 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallLogCallPhoneVO.java
  14. 4 0
      fs-service/src/main/java/com/fs/qw/domain/QwUser.java
  15. 1 1
      fs-service/src/main/java/com/fs/qw/service/IQwUserService.java
  16. 1 1
      fs-service/src/main/java/com/fs/qw/service/IQwUserServiceAsyncHelper.java
  17. 27 27
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceAsyncHelperImpl.java
  18. 57 15
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java
  19. 2 1
      fs-service/src/main/java/com/fs/qwApi/config/OpenQwConfig.java
  20. 112 112
      fs-service/src/main/resources/db/tenant-initTable.sql
  21. 43 0
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogCallphoneMapper.xml
  22. 1 1
      fs-task/src/main/java/com/fs/task/controller/TaskManualController.java
  23. 1 1
      fs-task/src/main/java/com/fs/task/jobs/QwUserAsyncTask.java
  24. 1 1
      fs-task/src/main/resources/application-dev.yml

+ 37 - 1
fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticCallLogCallphoneController.java

@@ -10,6 +10,7 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
 import com.fs.company.service.ICompanyVoiceRoboticCallLogCallphoneService;
+import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO;
 import com.fs.crm.domain.CrmCustomer;
 import com.fs.crm.service.ICrmCustomerService;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneVO;
@@ -85,6 +86,10 @@ public class CompanyVoiceRoboticCallLogCallphoneController extends BaseControlle
     public TableDataInfo groupList(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone)
     {
         startPage();
+        if(null == companyVoiceRoboticCallLogCallphone.getCompanyId()){
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+            companyVoiceRoboticCallLogCallphone.setCompanyId(loginUser.getUser().getCompanyId());
+        }
         List<CompanyVoiceRoboticCallLogCallphone> list = companyVoiceRoboticCallLogCallphoneService.selectCompanyVoiceRoboticCallPhoneLogGroupList(companyVoiceRoboticCallLogCallphone);
         return getDataTable(list);
     }
@@ -96,7 +101,9 @@ public class CompanyVoiceRoboticCallLogCallphoneController extends BaseControlle
     @GetMapping("/count")
     public AjaxResult selectCompanyVoiceRoboticCallPhoneLogCount()
     {
-        CompanyVoiceRoboticCallLogCount companyVoiceRoboticCallLogCount = companyVoiceRoboticCallLogCallphoneService.selectCompanyVoiceRoboticCallPhoneLogCount();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getUser().getCompanyId();
+        CompanyVoiceRoboticCallLogCount companyVoiceRoboticCallLogCount = companyVoiceRoboticCallLogCallphoneService.selectCompanyVoiceRoboticCallPhoneLogCount(companyId);
         return AjaxResult.success(companyVoiceRoboticCallLogCount);
     }
 
@@ -166,6 +173,35 @@ public class CompanyVoiceRoboticCallLogCallphoneController extends BaseControlle
         return util.exportExcel(list, "调用日志_ai打电话数据");
     }
 
+
+    /**
+     * 导出详情外呼记录(任务名称、客户名称、解密手机号)
+     */
+    @PreAuthorize("@ss.hasPermi('company:callphonelog:exportPhone')")
+    @Log(title = "外呼记录详情手机号导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportDetailPhone")
+    public AjaxResult exportDetailPhone(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone)
+    {
+        List<CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO> list =
+                companyVoiceRoboticCallLogCallphoneService.listDecryptPhoneExport(companyVoiceRoboticCallLogCallphone);
+        ExcelUtil<CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO> util =
+                new ExcelUtil<>(CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO.class);
+        return util.exportExcel(list, "外呼记录详情手机号");
+    }
+
+    /**
+     * 查看外呼记录解密手机号(无CRM客户时按记录解密)
+     */
+    @PreAuthorize("@ss.hasPermi('crm:customer:queryPhone')")
+    @Log(title = "查看外呼记录手机号", businessType = BusinessType.GRANT)
+    @GetMapping("/queryPhone/{logId}")
+    public AjaxResult queryCallLogPhone(@PathVariable("logId") Long logId)
+    {
+        String mobile = companyVoiceRoboticCallLogCallphoneService.getDecryptPhoneByLogId(logId);
+        AjaxResult success = AjaxResult.success();
+        success.put("mobile", mobile);
+        return success;
+    }
 //    /**
 //     * 导出调用日志_ai打电话列表
 //     */

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

@@ -1,10 +1,11 @@
 # 数据源配置
 spring:
-    # redis 配置
+#    devtools:
+#        restart:
+#            enabled: false
     redis:
-        # 地址
-        host: localhost
-        # 端口,默认为6379
+#        host: localhost
+        host: 172.27.0.7
         port: 6379
         # 数据库索引
         database: 0

+ 1 - 0
fs-framework/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -149,6 +149,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/course/userVideo/videoTranscode").anonymous()
                 .antMatchers("/system/config/getConfigByKey/his.adminUi.config").permitAll()
                 .antMatchers("/erp/call/**").anonymous()
+                .antMatchers("/app/common/**").anonymous()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()

+ 25 - 0
fs-qw-api/src/main/java/com/fs/app/controller/OpenQwApiController.java

@@ -10,6 +10,7 @@ import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.param.QwExternalContactAddTagParam;
 import com.fs.qw.param.QwExternalContactUpdateNoteParam;
 import com.fs.qwApi.param.QwUploadImageByCourseParam;
+import com.fs.qwApi.service.QwApiService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -27,6 +28,9 @@ public class OpenQwApiController extends BaseController {
 
     @Autowired
     private TenantDataSourceUtil tenantDataSourceUtil;
+
+    @Autowired
+    private QwApiService qwApiService;
     /**
      * 同步企微员工
      * @param tenantId
@@ -169,6 +173,27 @@ public class OpenQwApiController extends BaseController {
         }
     }
 
+
+    /**
+     * 加密qwUser的userId
+     */
+    @PostMapping("/getOpenUserid")
+    public R getOpenUserid(@RequestParam("userId") String  userId,
+                                   @RequestParam("corpId") String  corpId,
+                                   @RequestParam("permanentCode") String  permanentCode,
+                                   @RequestParam(value = "tenantId", required = true) Long tenantId){
+        try {
+            return R.ok().put("userId",tenantDataSourceUtil.executeWithResult(tenantId,
+                    () ->  qwApiService.getOpenUserid(qwApiService.getToken(corpId,permanentCode),userId,corpId)));
+        } catch (IllegalArgumentException e) {
+            log.error("加密ExternalUserid,租户不存在或已禁用,tenantId={}", tenantId, e);
+            return R.error("租户不存在或已禁用");
+        } catch (Exception e) {
+            log.error("加密ExternalUserid,tenantId={}", tenantId, e);
+            return R.error("加密ExternalUserid失败: " + e.getMessage());
+        }
+    }
+
     /**
      * 上传图片
      */

+ 1 - 0
fs-qw-api/src/main/java/com/fs/app/service/impl/OpenQwApiServiceImpl.java

@@ -274,6 +274,7 @@ public class OpenQwApiServiceImpl implements OpenQwApiService {
         qwUser.setIsDel(0);
         qwUser.setOpenid(openid);
         qwUser.setQwOpenUserId(apiUser.getUserid());
+        qwUser.setQwUserId(apiUser.getUserid());
 
         // 设置部门(取第一个部门)
         List<Integer> depts = apiUser.getDepartment();

+ 7 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallLogCallphone.java

@@ -173,6 +173,13 @@ public class CompanyVoiceRoboticCallLogCallphone extends BaseEntity{
 
     @TableField(exist = false)
     private Integer runningCount;
+    /** 详情筛选-手机号(明文) */
+    @TableField(exist = false)
+    private String phone;
+
+    /** 详情筛选-加密手机号(匹配 callees.phone) */
+    @TableField(exist = false)
+    private String encryptedPhone;
 
     public static CompanyVoiceRoboticCallLogCallphone initCallLog( String runParam, Long keyId, Long taskId,Long companyId) {
         CompanyVoiceRoboticCallLogCallphone log = new CompanyVoiceRoboticCallLogCallphone();

+ 5 - 1
fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCallLogCallphoneMapper.java

@@ -3,6 +3,7 @@ package com.fs.company.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
 import com.fs.company.domain.CompanyVoiceRoboticCallees;
+import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCount;
 import com.fs.crm.vo.CustomerCallStatVO;
@@ -83,7 +84,7 @@ public interface CompanyVoiceRoboticCallLogCallphoneMapper extends BaseMapper<Co
 
     List<CompanyVoiceRoboticCallLogCallphone> selectCompanyVoiceRoboticCallPhoneLogGroupList(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
 
-    CompanyVoiceRoboticCallLogCount selectCompanyVoiceRoboticCallPhoneLogCount();
+    CompanyVoiceRoboticCallLogCount selectCompanyVoiceRoboticCallPhoneLogCount(@Param("companyId") Long companyId);
 
 
     List<CompanyVoiceRoboticCallLogCallPhoneVO> listByRoboticId(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
@@ -106,4 +107,7 @@ public interface CompanyVoiceRoboticCallLogCallphoneMapper extends BaseMapper<Co
      * 按 customer_id(= callees.user_id)批量统计累计 AI 外呼总数与接通数
      */
     List<CustomerCallStatVO> selectAiCallStatTotal(@Param("customerIds") List<Long> customerIds);
+
+    List<CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO> listDecryptPhoneExport(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
+
 }

+ 10 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticCallLogCallphoneService.java

@@ -2,6 +2,7 @@ package com.fs.company.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
+import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCount;
 
@@ -79,7 +80,7 @@ public interface ICompanyVoiceRoboticCallLogCallphoneService extends IService<Co
 
     List<CompanyVoiceRoboticCallLogCallphone> selectCompanyVoiceRoboticCallPhoneLogGroupList(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
 
-    CompanyVoiceRoboticCallLogCount selectCompanyVoiceRoboticCallPhoneLogCount();
+    CompanyVoiceRoboticCallLogCount selectCompanyVoiceRoboticCallPhoneLogCount(Long companyId);
 
     List<CompanyVoiceRoboticCallLogCallPhoneVO> listByRoboticId(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
 
@@ -92,4 +93,12 @@ public interface ICompanyVoiceRoboticCallLogCallphoneService extends IService<Co
      * @return 影响行数
      */
     int markHandleFlag(Long logId);
+
+    List<CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO> listDecryptPhoneExport(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
+
+
+    /**
+     * 根据外呼记录ID获取解密后的手机号
+     */
+    String getDecryptPhoneByLogId(Long logId);
 }

+ 122 - 8
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java

@@ -23,9 +23,7 @@ import com.fs.company.mapper.CompanyWxAccountMapper;
 import com.fs.company.service.CompanyWorkflowEngine;
 import com.fs.company.service.ICompanyVoiceRoboticCallLogCallphoneService;
 import com.fs.company.service.ICompanyVoiceRoboticService;
-import com.fs.company.vo.CidConfigVO;
-import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneVO;
-import com.fs.company.vo.CompanyVoiceRoboticCallLogCount;
+import com.fs.company.vo.*;
 import com.fs.company.vo.easycall.EasyCallCallPhoneVO;
 import com.fs.core.config.TenantConfigContext;
 import com.fs.crm.service.ICrmCustomerPropertyService;
@@ -365,17 +363,67 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
                     companyVoiceRoboticCallLog.setCallCreateTime(createTime);
                     Long answerTime = result.getCallEndTime();
                     companyVoiceRoboticCallLog.setCallAnswerTime(answerTime);
-                    String intention = result.getIntent();
+                    // 【当前启用】读取 cc_call_phone.intent,再转换为系统字典 intention 数值
+                    String intentRaw = StringUtils.isNotBlank(result.getIntent()) ? result.getIntent().trim() : null;
                     String intentf = null;
+                    final String intentionLabel = intentRaw;
                     List<SysDictData> customerIntentionLevel = sysDictTypeService.selectDictDataByType("customer_intention_level");
-                    if (!isPositiveInteger(intention)) {
-                        Optional<SysDictData> firstDict = customerIntentionLevel.stream().filter(e -> e.getDictLabel().equals(intention)).findFirst();
+                    if (!isPositiveInteger(intentionLabel)) {
+                        Optional<SysDictData> firstDict = customerIntentionLevel.stream().filter(e -> e.getDictLabel().equals(intentionLabel)).findFirst();
                         if (firstDict.isPresent()) {
                             SysDictData sysDictData = firstDict.get();
                             intentf = sysDictData.getDictValue();
                         }
+                    } else {
+                        intentf = intentionLabel;
+                    }
+                    if (StringUtils.isBlank(intentf)) {
+                        intentf = "0";
                     }
                     companyVoiceRoboticCallLog.setIntention(intentf);
+
+                    // ========== 【历史保留】回滚时可注释上方 EasyCall 逻辑并取消下方对应注释 ==========
+                    // 方案A:仅使用 EasyCall intent 字段(改动前的本文件写法)
+//                    String intention = result.getIntent();
+//                    String intentf = null;
+//                    List<SysDictData> customerIntentionLevel = sysDictTypeService.selectDictDataByType("customer_intention_level");
+//                    if (!isPositiveInteger(intention)) {
+//                        Optional<SysDictData> firstDict = customerIntentionLevel.stream().filter(e -> e.getDictLabel().equals(intention)).findFirst();
+//                        if (firstDict.isPresent()) {
+//                            SysDictData sysDictData = firstDict.get();
+//                            intentf = sysDictData.getDictValue();
+//                        }
+//                    }
+//                    companyVoiceRoboticCallLog.setIntention(intentf);
+
+                    // 方案B:自家 AI 根据 dialogue 计算意向度
+//                    String intention = null;
+//                    if (StringUtils.isNotBlank(result.getDialogue())) {
+//                        try {
+//                            intention = crmCustomerAnalyzeService.aiIntentionDegree(
+//                                    result.getDialogue(),
+//                                    java.time.LocalTime.now().getLong(java.time.temporal.ChronoField.MILLI_OF_SECOND)
+//                            );
+//                        } catch (Exception e) {
+//                            log.error("easyCall回调日志意向度AI解析失败,uuid={}", result.getUuid(), e);
+//                        }
+//                    }
+//                    String intentf = null;
+//                    final String intentionLabel = intention;
+//                    List<SysDictData> customerIntentionLevel = sysDictTypeService.selectDictDataByType("customer_intention_level");
+//                    if (!isPositiveInteger(intentionLabel)) {
+//                        Optional<SysDictData> firstDict = customerIntentionLevel.stream().filter(e -> e.getDictLabel().equals(intentionLabel)).findFirst();
+//                        if (firstDict.isPresent()) {
+//                            SysDictData sysDictData = firstDict.get();
+//                            intentf = sysDictData.getDictValue();
+//                        }
+//                    } else {
+//                        intentf = intentionLabel;
+//                    }
+//                    if (StringUtils.isBlank(intentf)) {
+//                        intentf = "0";
+//                    }
+//                    companyVoiceRoboticCallLog.setIntention(intentf);
                     if(null != result.getValidTimeLen() && Integer.valueOf(0).compareTo(result.getValidTimeLen()) < 0){
                         BigDecimal divide = new BigDecimal(result.getValidTimeLen()).divide(new BigDecimal(1000), 0, RoundingMode.CEILING);
                         companyVoiceRoboticCallLog.setCallTime(divide.longValue());
@@ -521,8 +569,8 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
     }
 
     @Override
-    public CompanyVoiceRoboticCallLogCount selectCompanyVoiceRoboticCallPhoneLogCount() {
-        return baseMapper.selectCompanyVoiceRoboticCallPhoneLogCount();
+    public CompanyVoiceRoboticCallLogCount selectCompanyVoiceRoboticCallPhoneLogCount(Long companyId) {
+        return baseMapper.selectCompanyVoiceRoboticCallPhoneLogCount(companyId);
     }
 
     @Override
@@ -551,4 +599,70 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
         updateObj.setHandleFlag(1);
         return baseMapper.updateCompanyVoiceRoboticCallLogCallphone(updateObj);
     }
+
+    @Override
+    public String getDecryptPhoneByLogId(Long logId) {
+        CompanyVoiceRoboticCallLogCallphone log = selectCompanyVoiceRoboticCallLogCallphoneByLogId(logId);
+        if (log == null) {
+            return null;
+        }
+        if (log.getCallerId() != null) {
+            CompanyVoiceRoboticCallees callees = companyVoiceRoboticCalleesMapper.selectCompanyVoiceRoboticCalleesById(log.getCallerId());
+            if (callees != null && StringUtils.isNotEmpty(callees.getPhone())) {
+                return PhoneUtil.decryptPhone(callees.getPhone());
+            }
+        }
+        if (StringUtils.isNotEmpty(log.getCallerNum())) {
+            return PhoneUtil.decryptPhone(log.getCallerNum());
+        }
+        return null;
+    }
+
+    @Override
+    public List<CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO> listDecryptPhoneExport(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone) {
+        prepareDetailPhoneQuery(companyVoiceRoboticCallLogCallphone);
+        List<CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO> rows = baseMapper.listDecryptPhoneExport(companyVoiceRoboticCallLogCallphone);
+        List<CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO> exportList = new ArrayList<>();
+        if (rows == null || rows.isEmpty()) {
+            return exportList;
+        }
+        Map<String, String> intentionLabelMap = buildIntentionLabelMap();
+        for (CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO row : rows) {
+            CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO vo = new CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO();
+            vo.setRoboticName(row.getRoboticName());
+            vo.setUserName(row.getUserName());
+            vo.setIntention(resolveIntentionLabel(row.getIntention(), intentionLabelMap));
+            vo.setPhone(PhoneUtil.decryptPhone(row.getPhone()));
+            exportList.add(vo);
+        }
+        return exportList;
+    }
+
+    private Map<String, String> buildIntentionLabelMap() {
+        Map<String, String> map = new HashMap<>();
+        List<SysDictData> dictList = sysDictTypeService.selectDictDataByType("customer_intention_level");
+        if (dictList != null) {
+            for (SysDictData dict : dictList) {
+                map.put(dict.getDictValue(), dict.getDictLabel());
+            }
+        }
+        return map;
+    }
+
+    private String resolveIntentionLabel(String intention, Map<String, String> intentionLabelMap) {
+        if (StringUtils.isEmpty(intention)) {
+            return "";
+        }
+        String label = intentionLabelMap.get(intention);
+        if (StringUtils.isNotEmpty(label)) {
+            return label;
+        }
+        return intention;
+    }
+
+    private void prepareDetailPhoneQuery(CompanyVoiceRoboticCallLogCallphone query) {
+        if (StringUtils.isNotEmpty(query.getPhone())) {
+            query.setEncryptedPhone(PhoneUtil.encryptPhone(query.getPhone()));
+        }
+    }
 }

+ 88 - 53
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java

@@ -797,54 +797,51 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
                     );
                     // 切换 Redis 租户上下文
                     RedisTenantContext.setTenantId(TenantHelper.getTenantId());
-                    isSwitched = true;
                 } catch (Exception e) {
                     log.error("callerResult4EasyCall 切换租户数据源失败: tenantId={}", TenantHelper.getTenantId(), e);
                 }
-//                // intent(意向度)由对方异步评估写入,回调时可能尚未赋值,进入延迟重试队列等待
-//                if (StringUtils.isBlank(callPhoneRes.getIntent())) {
-//                    String retryKey = EASYCALL_INTENT_RETRY_KEY + result.getUuid();
-//                    Integer retryCount = redisCache2.getCacheObject(retryKey);
-//                    if (retryCount == null) {
-//                        retryCount = 0;
-//                    }
-//                    if (retryCount < EASYCALL_INTENT_MAX_RETRY) {
-//                        redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
-//                        log.info("easyCall外呼回调intent意向度暂未评估完成,uuid={},第{}次放入延迟重试队列", result.getUuid(), retryCount + 1);
-//                        doRetryCallerResult4EasyCall(result, retryCount + 1);
-//                    } else {
-//                        // 超过最大重试次数,以 intent 为空(意向未知)兜底继续处理
-//                        log.warn("easyCall外呼回调intent意向度在{}次重试后仍为空,uuid={},以意向未知兜底处理", EASYCALL_INTENT_MAX_RETRY, result.getUuid());
-//                        redisCache2.deleteObject(retryKey);
-//                        doHandleEasyCallResult(callPhoneRes);
-//                    }
-//                    return;
-//                }
-//                // intent 已有值,直接正常处理
-//                redisCache2.deleteObject(EASYCALL_INTENT_RETRY_KEY + result.getUuid());
-//                doHandleEasyCallResult(callPhoneRes);
-                // dialogue(对话内容)由对方异步写入,回调时可能尚未赋值,进入延迟重试队列等待
-                if (isDialogueEmpty(callPhoneRes.getDialogue()) && !"未接通".equals(callPhoneRes.getIntent())) {
-                    String retryKey = EASYCALL_DIALOGUE_RETRY_KEY + result.getUuid();
+                // 【当前启用】cc_call_phone.intent 由 EasyCall 异步评估写入,回调时可能尚未赋值,进入延迟重试队列等待
+                if (StringUtils.isBlank(resolveCcCallPhoneIntent(callPhoneRes))) {
+                    String retryKey = EASYCALL_INTENT_RETRY_KEY + result.getUuid();
                     Integer retryCount = redisCache2.getCacheObject(retryKey);
                     if (retryCount == null) {
                         retryCount = 0;
                     }
-                    if (retryCount < EASYCALL_DIALOGUE_MAX_RETRY) {
+                    if (retryCount < EASYCALL_INTENT_MAX_RETRY) {
                         redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
-                        log.info("easyCall外呼回调dialogue对话内容暂未写入,uuid={},第{}次放入延迟重试队列", result.getUuid(), retryCount + 1);
-                        doRetryDialogue4EasyCall(result, retryCount + 1);
+                        log.info("easyCall外呼回调intent意向度暂未评估完成,uuid={},第{}次放入延迟重试队列", result.getUuid(), retryCount + 1);
+                        doRetryCallerResult4EasyCall(result, retryCount + 1);
                     } else {
-                        // 超过最大重试次数,以 dialogue 为空兜底继续处理
-                        log.warn("easyCall外呼回调dialogue对话内容在{}次重试后仍为空,uuid={},以对话为空兜底处理", EASYCALL_DIALOGUE_MAX_RETRY, result.getUuid());
+                        log.warn("easyCall外呼回调intent意向度在{}次重试后仍为空,uuid={},以意向未知兜底处理", EASYCALL_INTENT_MAX_RETRY, result.getUuid());
                         redisCache2.deleteObject(retryKey);
                         doHandleEasyCallResult(callPhoneRes);
                     }
                     return;
                 }
-                // dialogue 已有值,直接正常处理
-                redisCache2.deleteObject(EASYCALL_DIALOGUE_RETRY_KEY + result.getUuid());
+                redisCache2.deleteObject(EASYCALL_INTENT_RETRY_KEY + result.getUuid());
                 doHandleEasyCallResult(callPhoneRes);
+
+                // ========== 【历史保留-自家AI】根据 dialogue 等待后走 AI 意向度,回滚时注释上方 intent 重试并取消下方注释 ==========
+//                // 当前:根据对话内容同步调用自家 AI 计算意向度,不依赖第三方 intent
+//                if (isDialogueEmpty(callPhoneRes.getDialogue()) && !"未接通".equals(callPhoneRes.getIntent())) {
+//                    String retryKey = EASYCALL_DIALOGUE_RETRY_KEY + result.getUuid();
+//                    Integer retryCount = redisCache2.getCacheObject(retryKey);
+//                    if (retryCount == null) {
+//                        retryCount = 0;
+//                    }
+//                    if (retryCount < EASYCALL_DIALOGUE_MAX_RETRY) {
+//                        redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
+//                        log.info("easyCall外呼回调dialogue对话内容暂未写入,uuid={},第{}次放入延迟重试队列", result.getUuid(), retryCount + 1);
+//                        doRetryDialogue4EasyCall(result, retryCount + 1);
+//                    } else {
+//                        log.warn("easyCall外呼回调dialogue对话内容在{}次重试后仍为空,uuid={},以对话为空兜底处理", EASYCALL_DIALOGUE_MAX_RETRY, result.getUuid());
+//                        redisCache2.deleteObject(retryKey);
+//                        doHandleEasyCallResult(callPhoneRes);
+//                    }
+//                    return;
+//                }
+//                redisCache2.deleteObject(EASYCALL_DIALOGUE_RETRY_KEY + result.getUuid());
+//                doHandleEasyCallResult(callPhoneRes);
             } catch (Exception e) {
                 throw new RuntimeException(e);
             } finally {
@@ -1054,27 +1051,37 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
 //                    log.error("pushDialogContent4EasyCall 切换租户数据源失败: tenantId={}", TenantHelper.getTenantId(), e);
 //                }
 //            }
-            String intention = null;
-            String intentionDegree = null;
-            if (StringUtils.isNotBlank(callPhoneRes.getDialogue())) {
-                log.info("【验证】意向度来源=自家AI, uuid={}, dialogueLength={}", callPhoneRes.getUuid(),
-                        StringUtils.isBlank(callPhoneRes.getDialogue()) ? 0 : callPhoneRes.getDialogue().length());
-                try {
-                    intentionDegree = crmCustomerAnalyzeService.aiIntentionDegree(
-                            callPhoneRes.getDialogue(),
-                            now().getLong(ChronoField.MILLI_OF_SECOND)
-                    );
-                    log.info("【验证】意向度结果={}, uuid={}", intentionDegree, callPhoneRes.getUuid());
-                    intention = getIntention(intentionDegree);
-                } catch (Exception e) {
-                    log.error("easyCall意向度AI解析失败,uuid={},将使用意向未知兜底", callPhoneRes.getUuid(), e);
-                }
-            }
-            // 2) 最终兜底:意向未知
-//            String intention = getIntention(callPhoneRes.getIntent());
+            // 【当前启用】读取 cc_call_phone.intent,再转换为系统字典 intention 数值
+            String intentRaw = resolveCcCallPhoneIntent(callPhoneRes);
+            String intention = convertEasyCallIntent(intentRaw);
+            log.info("easyCall意向度来源=EasyCall平台, uuid={}, intent(raw)={}, intention(converted)={}",
+                    callPhoneRes.getUuid(), intentRaw, intention);
             if (StringUtils.isEmpty(intention)) {
                 intention = "0";
             }
+
+            // ========== 【历史保留-自家AI】回滚时注释上方 EasyCall 逻辑并取消下方注释 ==========
+//            String intention = null;
+//            String intentionDegree = null;
+//            if (StringUtils.isNotBlank(callPhoneRes.getDialogue())) {
+//                log.info("【验证】意向度来源=自家AI, uuid={}, dialogueLength={}", callPhoneRes.getUuid(),
+//                        StringUtils.isBlank(callPhoneRes.getDialogue()) ? 0 : callPhoneRes.getDialogue().length());
+//                try {
+//                    intentionDegree = crmCustomerAnalyzeService.aiIntentionDegree(
+//                            callPhoneRes.getDialogue(),
+//                            java.time.LocalTime.now().getLong(java.time.temporal.ChronoField.MILLI_OF_SECOND)
+//                    );
+//                    log.info("【验证】意向度结果={}, uuid={}", intentionDegree, callPhoneRes.getUuid());
+//                    intention = getIntention(intentionDegree);
+//                } catch (Exception e) {
+//                    log.error("easyCall意向度AI解析失败,uuid={},将使用意向未知兜底", callPhoneRes.getUuid(), e);
+//                }
+//            }
+//            if (StringUtils.isEmpty(intention)) {
+//                intention = "0";
+//            }
+//            // 历史第三方值(仅 intent 字段,未走 AI 时的写法)
+//            // String intention = getIntention(callPhoneRes.getIntent());
             CompanyVoiceRoboticCallees callee = companyVoiceRoboticCalleesMapper.selectCompanyVoiceRoboticCalleesById(cacheInfo.getLong("calleeId"));
             callee.setUuid(callPhoneRes.getUuid());
             callee.setIntention(intention);
@@ -1272,10 +1279,13 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
         if (robotic.getCompanyAiWorkflowId() == null) {
             throw new RuntimeException("任务未配置工作流: " + id);
         }
+        if(robotic.getDelFlag() == 1){
+            throw new RuntimeException("启动失败,当前任务已删除: " + id);
+        }
         robotic.setTaskStatus(1);
         updateById(robotic);
-        // 根据任务加微方式决定是否直接分配微信 平均时 直接分配用户 场景任务不做分配
-        if (Integer.valueOf(0).equals(robotic.getAddType()) && robotic.getTaskType().equals(TaskTypeEnum.ORDINARY.getValue())) {
+        boolean hasAddWxNode = workflowHasAddWxNode(robotic.getCompanyAiWorkflowId());
+        if (hasAddWxNode && Integer.valueOf(0).equals(robotic.getAddType()) && robotic.getTaskType().equals(TaskTypeEnum.ORDINARY.getValue())) {
             allocateWx(robotic);
         }
         // 新增启动写入任务业务表数据
@@ -2325,4 +2335,29 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
                 new LambdaQueryWrapper<CompanyVoiceRobotic>().eq(CompanyVoiceRobotic::getTaskId, Long.valueOf(taskId)));
         return robotic != null ? robotic.getCompanyId() : null;
     }
+
+    /**
+     * 读取 EasyCall cc_call_phone 表原始字段 intent(非本系统 intention 字典值)
+     */
+    private String resolveCcCallPhoneIntent(EasyCallCallPhoneVO callPhoneRes) {
+        if (callPhoneRes == null || StringUtils.isBlank(callPhoneRes.getIntent())) {
+            return null;
+        }
+        return callPhoneRes.getIntent().trim();
+    }
+
+    /**
+     * 将 cc_call_phone.intent 原始值转为系统字典数值 intention(customer_intention_level.dict_value)
+     */
+    private String convertEasyCallIntent(String intentRaw) {
+        if (StringUtils.isBlank(intentRaw)) {
+            return null;
+        }
+        String t = intentRaw.trim();
+        if (t.matches("^\\d+$")) {
+            return t;
+        }
+        return getIntention(t);
+    }
+
 }

+ 23 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO.java

@@ -0,0 +1,23 @@
+package com.fs.company.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+/**
+ * 外呼记录详情导出(解密手机号)
+ */
+@Data
+public class CompanyVoiceRoboticCallLogCallPhoneDecryptExportVO {
+
+    @Excel(name = "任务名称")
+    private String roboticName;
+
+    @Excel(name = "客户名称")
+    private String userName;
+
+    @Excel(name = "客户类型")
+    private String intention;
+
+    @Excel(name = "手机号")
+    private String phone;
+}

+ 19 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO.java

@@ -0,0 +1,19 @@
+package com.fs.company.vo;
+
+import lombok.Data;
+
+/**
+ * 外呼记录详情导出查询中间对象
+ */
+@Data
+public class CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO {
+
+    private String roboticName;
+
+    private String userName;
+
+    /** 客户类型字典值(存库为数字) */
+    private String intention;
+
+    private String phone;
+}

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

@@ -24,6 +24,9 @@ public class CompanyVoiceRoboticCallLogCallPhoneVO {
     @Excel(name = "caller_id")
     private Long callerId;
 
+    /** 客户ID(callees.user_id) */
+    private Long customerId;
+
     /** 记录调用时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Excel(name = "记录调用时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")

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

@@ -1,7 +1,9 @@
 package com.fs.qw.domain;
 
 
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
@@ -18,6 +20,8 @@ public class QwUser extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** id */
+    /** id(数据库自增;勿依赖应用侧雪花填充) */
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /** 企微用户id */

+ 1 - 1
fs-service/src/main/java/com/fs/qw/service/IQwUserService.java

@@ -97,7 +97,7 @@ public interface IQwUserService
     */
     List<QwUserVO> selectQwUserListBindVO(QwUserParam qwUser);
 
-    R syncQwUser(String corpId);
+    R syncQwUser(String corpId,Long tenantId);
 
     R unlockQwUserLoginCodeUrlTask();
 

+ 1 - 1
fs-service/src/main/java/com/fs/qw/service/IQwUserServiceAsyncHelper.java

@@ -17,7 +17,7 @@ public interface IQwUserServiceAsyncHelper {
      * @param corpId
      * @param company
      */
-    void syncQwUserAsync(String corpId, Company company);
+//    void syncQwUserAsync(String corpId, Company company);
 
     /**
      * 同步企微用户名称

+ 27 - 27
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceAsyncHelperImpl.java

@@ -104,33 +104,33 @@ public class QwUserServiceAsyncHelperImpl implements IQwUserServiceAsyncHelper {
 
     org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
 
-    /**
-     * 同步企微用户
-     *
-     * @param corpId
-     * @param company
-     */
-    @Async
-    @Override
-    public void syncQwUserAsync(String corpId, Company company) {
-        try {
-            log.info("同步企微用户Async");
-            List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByCompanyId(company.getCompanyId());
-            log.info("strings:{}", strings);
-            log.info("corpId:{}", corpId);
-            for (String string : strings) {
-                if (string.equals(corpId)) {
-                    log.info("瞒住条件");
-                    qwUserService.syncQwUser(string);
-                    qwDeptService.insertOrUpdateQwDept(string);
-                }
-            }
-            log.info("同步完成");
-        } catch (Exception e) {
-            log.error("异步任务执行异常", e);
-            log.info("同步企微员工和部门,同步失败");
-        }
-    }
+//    /**
+//     * 同步企微用户
+//     *
+//     * @param corpId
+//     * @param company
+//     */
+//    @Async
+//    @Override
+//    public void syncQwUserAsync(String corpId, Company company) {
+//        try {
+//            log.info("同步企微用户Async");
+//            List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByCompanyId(company.getCompanyId());
+//            log.info("strings:{}", strings);
+//            log.info("corpId:{}", corpId);
+//            for (String string : strings) {
+//                if (string.equals(corpId)) {
+//                    log.info("瞒住条件");
+//                    qwUserService.syncQwUser(string);
+//                    qwDeptService.insertOrUpdateQwDept(string);
+//                }
+//            }
+//            log.info("同步完成");
+//        } catch (Exception e) {
+//            log.error("异步任务执行异常", e);
+//            log.info("同步企微员工和部门,同步失败");
+//        }
+//    }
 
     /**
      * 同步企微用户名称

+ 57 - 15
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java

@@ -3,6 +3,7 @@ package com.fs.qw.service.impl;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -44,6 +45,7 @@ import com.fs.qw.utils.RSAUtils;
 import com.fs.qw.vo.*;
 import com.fs.qwApi.Result.QwOpenidResult;
 import com.fs.qwApi.Result.QwUploadImgResult;
+import com.fs.qwApi.config.OpenQwConfig;
 import com.fs.qwApi.domain.QwUserIdResult;
 import com.fs.qwApi.domain.inner.DeptUser;
 import com.fs.qwApi.param.QwOpenidByUserParams;
@@ -65,6 +67,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.*;
+import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.security.KeyFactory;
 import java.security.PrivateKey;
@@ -935,30 +938,69 @@ public class QwUserServiceImpl implements IQwUserService
     }
 
     @Override
-    public R syncQwUser(String corpId) {
+    public R syncQwUser(String corpId,Long tenantId) {
         QwUserIdResult userList = qwApiService.getUserList(corpId);
         List<DeptUser> deptUser = userList.getDept_user();
         log.info("返回数据:{}", JSON.toJSONString(userList));
         log.info("同步用户数量:{}", deptUser.size());
         QwCompany qwCompany = iQwCompanyService.selectQwCompanyByCorpId(corpId);
         for (DeptUser user : deptUser) {
-            QwUser qw=qwUserMapper.selectQwUserByCorpIdAndUserId(corpId,qwApiService.getOpenUserid(qwApiService.getToken(corpId,qwCompany.getPermanentCode()),user.getUserid(),corpId));
+            String userid = user.getUserid();
+            String openUserIdRedisKey = "corpId:" + userid;
+            String  redisResult= redisCache.getCacheObject(openUserIdRedisKey);
+            String openUserId = "";
+            if (StringUtils.isNotBlank(redisResult)){
+                openUserId = redisResult;
+            } else {
+                if (userid != null && tenantId != null && qwCompany.getPermanentCode() != null) {
+                    // 远程调用 fs-qw-api 同步企微用户
+                    String url = OpenQwConfig.baseApi + "/getOpenUserid?userId=" + userid + "&corpId=" + corpId + "&permanentCode=" + qwCompany.getPermanentCode() + "&tenantId=" + tenantId;
+                    try {
+                        String result = HttpUtil.createPost(url)
+                                .execute()
+                                .body();
+                        if (StringUtils.isNotBlank(result)) {
+                            R r = JSON.parseObject(result, R.class);
+                            if (!"200".equals(r.get("code").toString())) {
+                                log.error("企微用户获取加密userId,HTTP状态码: {}", r.get("code").toString());
+                                return R.error("企微用户获取加密userId,服务返回状态码: " + r.get("code").toString());
+                            } else {
+                                openUserId = r.get("userId").toString();
+                            }
+                        }
+
+                    } catch (Exception e) {
+                        log.error("企微用户获取加密userId异常, url={}", url, e);
+                        if (e.getCause() instanceof SocketTimeoutException) {
+                            return R.error("企微用户获取加密userId超时,请稍后重试");
+                        }
+                        return R.error("企微用户获取加密userId失败: " + e.getMessage());
+                    }
+                }
+            }
+
+            if (StringUtils.isNotBlank(openUserId)) {
+                QwUser qw=qwUserMapper.selectQwUserByCorpIdAndUserId(corpId, openUserId);
 //            String serverQwUserName = qwApiService.getServerQwUserName(corpId, qwCompany.getOpenSecret(), user.getUserid(),qwCompany.getPermanentCode());
 //            log.info("同步用户名称:{}", serverQwUserName);
-            QwUser qwUser = new QwUser();
-            qwUser.setQwUserId(user.getUserid());
-            qwUser.setDepartment(user.getDepartment().toString());
+                QwUser qwUser = new QwUser();
+                qwUser.setQwUserId(userid);
+                qwUser.setDepartment(user.getDepartment().toString());
 //            qwUser.setQwUserName(serverQwUserName);
-            qwUser.setCorpId(corpId);
-            QwOpenidByUserParams param=new QwOpenidByUserParams();
-            param.setUserid(user.getUserid());
-            QwOpenidResult qwOpenidResult = qwApiService.useridToOpenid(param, corpId);
-            qwUser.setOpenid(qwOpenidResult.getOpenid());
-             if (qw!=null){
-                 qwUser.setId(qw.getId());
-                 qwUser.setIsDel(0);
-                 qwUserMapper.updateQwUser(qwUser);
-             }
+                qwUser.setCorpId(corpId);
+//            QwOpenidByUserParams param=new QwOpenidByUserParams();
+//            param.setUserid(user.getUserid());
+//            QwOpenidResult qwOpenidResult = qwApiService.useridToOpenid(param, corpId);
+//            qwUser.setOpenid(qwOpenidResult.getOpenid());
+                if (qw!=null){
+                    qwUser.setId(qw.getId());
+                    qwUser.setIsDel(0);
+                    qwUserMapper.updateQwUser(qwUser);
+                }
+            } else {
+                log.error("企微用户获取加密userId为空, userid={}", userid);
+            }
+
         }
         return R.ok();
     }

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

@@ -6,5 +6,6 @@ public interface OpenQwConfig {
     String api ="http://newsaasqwapi.ylrzcloud.com";
 //    String api ="http://127.0.0.1:8007";
 //    String taskApi ="192.168.0.64:7006";
-    String taskApi ="127.0.0.1:7006";
+    String taskApi ="http://172.27.0.7:7006";
+//    String taskApi ="http://129.28.41.190:7006";
 }

Разница между файлами не показана из-за своего большого размера
+ 112 - 112
fs-service/src/main/resources/db/tenant-initTable.sql


+ 43 - 0
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogCallphoneMapper.xml

@@ -234,6 +234,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         inner join company_voice_robotic cvr on cvr.id = t1.robotic_id
         <where>
             <if test="roboticId != null">and robotic_id = #{roboticId}</if>
+            <if test="companyId != null"> and cvr.company_id = #{companyId}</if>
         </where>
         group by robotic_id
         order by t1.run_time desc
@@ -246,6 +247,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             sum(case when status = 2 and run_time &gt;= CURDATE() and run_time &lt; DATE_ADD(CURDATE(), INTERVAL 1 DAY) then 1 else 0 end) as todaySuccessCount
         from company_voice_robotic_call_log_callphone cp
             inner join company_voice_robotic cvr on cvr.id = cp.robotic_id
+        where cvr.company_id = #{companyId}
     </select>
 
 
@@ -343,5 +345,46 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY ce.user_id
     </select>
 
+    <select id="listDecryptPhoneExport" resultType="com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneDecryptQueryVO" parameterType="com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone">
+        SELECT
+        cvr.name as robotic_name,
+        ce.user_name as user_name,
+        t1.intention as intention,
+        ce.phone as phone
+        FROM company_voice_robotic_call_log_callphone t1
+        left join company_voice_robotic_callees ce on ce.id = t1.caller_id
+        left join company_voice_robotic cvr on cvr.id = t1.robotic_id
+        where 1=1
+        <if test="roboticId != null">and t1.robotic_id = #{roboticId}</if>
+        <if test="callerId != null">and t1.caller_id = #{callerId}</if>
+        <if test="callerIds != null and callerIds.size() > 0">
+            AND t1.caller_id IN
+            <foreach collection='callerIds' item='item' open='(' separator=',' close=')'>
+                #{item}
+            </foreach>
+        </if>
+        <if test="callerNum != null and callerNum != ''">
+            and t1.caller_num like concat('%', #{callerNum}, '%')
+        </if>
+        <if test="encryptedPhone != null and encryptedPhone != ''">
+            and ce.phone = #{encryptedPhone}
+        </if>
+        <if test="intention != null and intention != ''">
+            and t1.intention = #{intention}
+        </if>
+        <if test="isConnected != null and isConnected == 1">
+            and t1.call_time &gt; 0
+        </if>
+        <if test="isConnected != null and isConnected == 0">
+            and (t1.call_time is null or t1.call_time = 0)
+        </if>
+        <if test="minCallTime != null">
+            and t1.call_time &gt;= #{minCallTime}
+        </if>
+        <if test="maxCallTime != null">
+            and t1.call_time &lt;= #{maxCallTime}
+        </if>
+        order by t1.run_time desc
+    </select>
 
 </mapper>

+ 1 - 1
fs-task/src/main/java/com/fs/task/controller/TaskManualController.java

@@ -191,7 +191,7 @@ public class TaskManualController {
             log.info("开始同步企微用户,租户={}, corpId={}", tenantInfo.getId(), qwCompany.getCorpId());
 
             // 执行同步操作
-            qwUserService.syncQwUser(qwCompany.getCorpId());
+            qwUserService.syncQwUser(qwCompany.getCorpId(),tenantInfo.getId());
 
             log.info("同步完成,租户={}", tenantInfo.getId());
 

+ 1 - 1
fs-task/src/main/java/com/fs/task/jobs/QwUserAsyncTask.java

@@ -62,7 +62,7 @@ public class QwUserAsyncTask {
                 log.info("开始同步企微用户,租户={}, corpId={}", tenantInfo.getId(), qwCompany.getCorpId());
 
                 // 执行同步操作
-                qwUserService.syncQwUser(qwCompany.getCorpId());
+                qwUserService.syncQwUser(qwCompany.getCorpId(),tenantInfo.getId());
 //                qwDeptService.insertOrUpdateQwDept(qwCompany.getCorpId());
 
                 log.info("同步完成,租户={}", tenantInfo.getId());

+ 1 - 1
fs-task/src/main/resources/application-dev.yml

@@ -2,7 +2,7 @@
 spring:
     # redis 配置
     redis:
-        #host: localhost
+#        host: localhost
         host: 172.27.0.7
         port: 6379
         database: 0

Некоторые файлы не были показаны из-за большого количества измененных файлов