Bladeren bron

黑名单和拦截明细表

yuhongqi 1 dag geleden
bovenliggende
commit
930f891ed3
21 gewijzigde bestanden met toevoegingen van 1933 en 654 verwijderingen
  1. 149 0
      fs-admin-saas/src/main/java/com/fs/company/controller/company/CompanyVoiceBlacklistController.java
  2. 83 0
      fs-admin-saas/src/main/java/com/fs/company/controller/company/CompanyVoiceBlacklistInterceptController.java
  3. 2 44
      fs-admin/src/main/java/com/fs/admin/controller/AdminCompanyBridgeController.java
  4. 198 0
      fs-admin/src/main/java/com/fs/admin/controller/AdminVoiceBlacklistController.java
  5. 136 0
      fs-admin/src/main/java/com/fs/admin/controller/AdminVoiceBlacklistInterceptController.java
  6. 79 26
      fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticCallBlacklistController.java
  7. 4 0
      fs-service/src/main/java/com/fs/comm/service/CommCallSendService.java
  8. 21 1
      fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallBlacklist.java
  9. 64 0
      fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallBlacklistInterceptLog.java
  10. 51 0
      fs-service/src/main/java/com/fs/company/enums/VoiceRoboticCallBlacklistBusinessTypeEnum.java
  11. 17 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCallBlacklistInterceptLogMapper.java
  12. 25 3
      fs-service/src/main/java/com/fs/company/param/CompanyVoiceRoboticCallBlacklistCheckParam.java
  13. 27 0
      fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticCallBlacklistInterceptLogService.java
  14. 34 1
      fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticCallBlacklistService.java
  15. 98 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallBlacklistInterceptLogServiceImpl.java
  16. 230 36
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallBlacklistServiceImpl.java
  17. 34 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallBlacklistExportVO.java
  18. 28 0
      fs-service/src/main/resources/db/tenant-initTable-migration.sql
  19. 84 0
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallBlacklistInterceptLogMapper.xml
  20. 12 6
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallBlacklistMapper.xml
  21. 557 537
      sql/adminUI_views_menu_structure.md

+ 149 - 0
fs-admin-saas/src/main/java/com/fs/company/controller/company/CompanyVoiceBlacklistController.java

@@ -0,0 +1,149 @@
+package com.fs.company.controller.company;
+
+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.model.LoginUser;
+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.company.domain.CompanyVoiceRoboticCallBlacklist;
+import com.fs.company.enums.VoiceRoboticCallBlacklistBusinessTypeEnum;
+import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistService;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 租户总后台外呼黑名单(查询当前租户库:租户级 12 + 线路级 13)
+ */
+@RestController
+@RequestMapping("/company/companyVoiceBlacklist")
+public class CompanyVoiceBlacklistController extends BaseController {
+
+    private static final List<String> TENANT_SCOPE_TYPES = Arrays.asList(
+            VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode(),
+            VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode()
+    );
+
+    @Autowired
+    private ICompanyVoiceRoboticCallBlacklistService companyVoiceRoboticCallBlacklistService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyVoiceRoboticCallBlacklist query) {
+        startPage();
+        query = applyTenantScope(query);
+        List<CompanyVoiceRoboticCallBlacklist> list =
+                companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(query);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:export')")
+    @Log(title = "租户外呼黑名单", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody CompanyVoiceRoboticCallBlacklist query) {
+        query = applyTenantScope(query);
+        List<CompanyVoiceRoboticCallBlacklist> list =
+                companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(query);
+        ExcelUtil<CompanyVoiceRoboticCallBlacklist> util = new ExcelUtil<>(CompanyVoiceRoboticCallBlacklist.class);
+        return util.exportExcel(list, "租户外呼黑名单");
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:query')")
+    @GetMapping("/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:add')")
+    @Log(title = "租户外呼黑名单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
+        data = applyTenantScope(data);
+        data.setCreateBy(getUsername());
+        data.setUpdateBy(getUsername());
+        if (data.getTargetType() == null) {
+            data.setTargetType(1);
+        }
+        if (data.getSource() == null) {
+            data.setSource(1);
+        }
+        if (data.getStatus() == null) {
+            data.setStatus(1);
+        }
+        if (VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode().equals(data.getBusinessType())) {
+            return toAjax(companyVoiceRoboticCallBlacklistService.insertLineBlacklist(data));
+        }
+        return toAjax(companyVoiceRoboticCallBlacklistService.insertTenantBlacklist(data));
+    }
+
+    @PreAuthorize("@ss.hasAnyPermi('company:companyVoiceBlacklist:update,company:companyVoiceBlacklist:edit')")
+    @Log(title = "租户外呼黑名单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
+        data.setUpdateBy(getUsername());
+        return toAjax(companyVoiceRoboticCallBlacklistService.updateCompanyVoiceRoboticCallBlacklist(data));
+    }
+
+    @PreAuthorize("@ss.hasAnyPermi('company:companyVoiceBlacklist:update,company:companyVoiceBlacklist:edit')")
+    @Log(title = "租户外呼黑名单状态", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
+        data.setUpdateBy(getUsername());
+        return toAjax(companyVoiceRoboticCallBlacklistService.changeStatus(data));
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:remove')")
+    @Log(title = "租户外呼黑名单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(companyVoiceRoboticCallBlacklistService.deleteCompanyVoiceRoboticCallBlacklistByIds(ids));
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:queryPhone')")
+    @Log(title = "查看租户外呼黑名单手机号", businessType = BusinessType.GRANT)
+    @GetMapping("/queryPhone/{id}")
+    public AjaxResult queryPhone(@PathVariable Long id) {
+        String mobile = companyVoiceRoboticCallBlacklistService.getDecryptPhoneById(id);
+        if (!StringUtils.hasText(mobile)) {
+            return AjaxResult.error("记录不存在或手机号为空");
+        }
+        AjaxResult success = AjaxResult.success();
+        success.put("mobile", mobile);
+        return success;
+    }
+
+    /**
+     * 限定当前租户库:默认查租户级(12)+线路级(13)
+     */
+    private CompanyVoiceRoboticCallBlacklist applyTenantScope(CompanyVoiceRoboticCallBlacklist query) {
+        if (query == null) {
+            query = new CompanyVoiceRoboticCallBlacklist();
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (query.getCompanyId() == null && loginUser != null && loginUser.getUser() != null
+                && loginUser.getUser().getCompanyId() != null) {
+            query.setCompanyId(loginUser.getUser().getCompanyId());
+        }
+        if (query.getTargetType() == null && StringUtils.hasText(query.getTargetValue())) {
+            query.setTargetType(1);
+        }
+        if (!StringUtils.hasText(query.getBusinessType())) {
+            query.setBusinessType(null);
+            query.setBusinessTypeList(TENANT_SCOPE_TYPES);
+        } else {
+            query.setBusinessTypeList(null);
+        }
+        return query;
+    }
+}

+ 83 - 0
fs-admin-saas/src/main/java/com/fs/company/controller/company/CompanyVoiceBlacklistInterceptController.java

@@ -0,0 +1,83 @@
+package com.fs.company.controller.company;
+
+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.model.LoginUser;
+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.company.domain.CompanyVoiceRoboticCallBlacklistInterceptLog;
+import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistInterceptLogService;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 外呼黑名单拦截明细
+ */
+@RestController
+@RequestMapping("/company/companyVoiceBlacklistIntercept")
+public class CompanyVoiceBlacklistInterceptController extends BaseController {
+
+    @Autowired
+    private ICompanyVoiceRoboticCallBlacklistInterceptLogService interceptLogService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        startPage();
+        query = applyCompanyScope(query);
+        List<CompanyVoiceRoboticCallBlacklistInterceptLog> list = interceptLogService.selectList(query);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:queryPhone')")
+    @GetMapping("/queryPhone/{id}")
+    public AjaxResult queryPhone(@PathVariable Long id) {
+        String mobile = interceptLogService.getDecryptTargetValueById(id);
+        if (!StringUtils.hasText(mobile)) {
+            return AjaxResult.error("记录不存在或对象值为空");
+        }
+        AjaxResult success = AjaxResult.success();
+        success.put("mobile", mobile);
+        return success;
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:query')")
+    @GetMapping("/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        return AjaxResult.success(interceptLogService.selectById(id));
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:export')")
+    @Log(title = "黑名单拦截明细", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        query = applyCompanyScope(query);
+        List<CompanyVoiceRoboticCallBlacklistInterceptLog> list = interceptLogService.selectList(query);
+        ExcelUtil<CompanyVoiceRoboticCallBlacklistInterceptLog> util =
+                new ExcelUtil<>(CompanyVoiceRoboticCallBlacklistInterceptLog.class);
+        return util.exportExcel(list, "黑名单拦截明细");
+    }
+
+    private CompanyVoiceRoboticCallBlacklistInterceptLog applyCompanyScope(CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        if (query == null) {
+            query = new CompanyVoiceRoboticCallBlacklistInterceptLog();
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (query.getCompanyId() == null && loginUser != null && loginUser.getUser() != null
+                && loginUser.getUser().getCompanyId() != null) {
+            query.setCompanyId(loginUser.getUser().getCompanyId());
+        }
+        return query;
+    }
+}

+ 2 - 44
fs-admin/src/main/java/com/fs/admin/controller/AdminCompanyBridgeController.java

@@ -18,6 +18,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
 import java.util.*;
 import java.util.*;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 公司管理桥接Controller - adminui端(fs-admin 8004)
  * 公司管理桥接Controller - adminui端(fs-admin 8004)
@@ -66,9 +67,6 @@ public class AdminCompanyBridgeController extends BaseController {
     @Autowired(required = false)
     @Autowired(required = false)
     private ICompanyOperLogService companyOperLogService;
     private ICompanyOperLogService companyOperLogService;
 
 
-    @Autowired(required = false)
-    private ICompanyVoiceRoboticCallBlacklistService companyVoiceRoboticCallBlacklistService;
-
     @Autowired(required = false)
     @Autowired(required = false)
     private com.fs.company.service.ICompanyVoiceMobileService companyVoiceMobileService;
     private com.fs.company.service.ICompanyVoiceMobileService companyVoiceMobileService;
     @Autowired(required = false)
     @Autowired(required = false)
@@ -331,8 +329,7 @@ public class AdminCompanyBridgeController extends BaseController {
 
 
     // ========== 号码管理/通话套餐/黑名单/频率/通话包 ==========
     // ========== 号码管理/通话套餐/黑名单/频率/通话包 ==========
     @GetMapping({"/company/companyVoiceMobile/list", "/company/companyVoicePackage/list",
     @GetMapping({"/company/companyVoiceMobile/list", "/company/companyVoicePackage/list",
-                 "/company/companyVoiceBlacklist/list", "/company/companyVoiceConfig/list",
-                 "/company/companyVoice/list"})
+                 "/company/companyVoiceConfig/list", "/company/companyVoice/list"})
     public TableDataInfo companyVoiceMiscList() {
     public TableDataInfo companyVoiceMiscList() {
         return getDataTable(new ArrayList<>());
         return getDataTable(new ArrayList<>());
     }
     }
@@ -366,45 +363,6 @@ public class AdminCompanyBridgeController extends BaseController {
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
-    // ========== [Admin] 外呼黑名单 /admin/voice-blacklist ==========
-    @GetMapping("/admin/voice-blacklist/list")
-    public TableDataInfo adminVoiceBlacklistList(CompanyVoiceRoboticCallBlacklist param) {
-        startPage();
-        List<CompanyVoiceRoboticCallBlacklist> list = companyVoiceRoboticCallBlacklistService != null ?
-            companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(param) : new ArrayList<>();
-        return getDataTable(list);
-    }
-
-    @GetMapping("/admin/voice-blacklist/{blacklistId}")
-    public AjaxResult adminVoiceBlacklistGet(@PathVariable Long blacklistId) {
-        if (companyVoiceRoboticCallBlacklistService == null) return AjaxResult.error("服务不可用");
-        return AjaxResult.success(companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistById(blacklistId));
-    }
-
-    @PostMapping("/admin/voice-blacklist")
-    public AjaxResult adminVoiceBlacklistAdd(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
-        if (companyVoiceRoboticCallBlacklistService == null) return AjaxResult.error("服务不可用");
-        return toAjax(companyVoiceRoboticCallBlacklistService.insertCompanyVoiceRoboticCallBlacklist(data));
-    }
-
-    @PutMapping("/admin/voice-blacklist")
-    public AjaxResult adminVoiceBlacklistUpdate(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
-        if (companyVoiceRoboticCallBlacklistService == null) return AjaxResult.error("服务不可用");
-        return toAjax(companyVoiceRoboticCallBlacklistService.updateCompanyVoiceRoboticCallBlacklist(data));
-    }
-
-    @DeleteMapping("/admin/voice-blacklist/{blacklistIds}")
-    public AjaxResult adminVoiceBlacklistDelete(@PathVariable Long[] blacklistIds) {
-        if (companyVoiceRoboticCallBlacklistService == null) return AjaxResult.error("服务不可用");
-        return toAjax(companyVoiceRoboticCallBlacklistService.deleteCompanyVoiceRoboticCallBlacklistByIds(blacklistIds));
-    }
-
-    @PutMapping("/admin/voice-blacklist/changeStatus")
-    public AjaxResult adminVoiceBlacklistChangeStatus(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
-        if (companyVoiceRoboticCallBlacklistService == null) return AjaxResult.error("服务不可用");
-        return toAjax(companyVoiceRoboticCallBlacklistService.updateCompanyVoiceRoboticCallBlacklist(data));
-    }
-
     // ========== 公司短信包 /company/companySms ==========
     // ========== 公司短信包 /company/companySms ==========
     @PreAuthorize("@ss.hasPermi('company:companySms:list')")
     @PreAuthorize("@ss.hasPermi('company:companySms:list')")
     @GetMapping("/company/companySms/list")
     @GetMapping("/company/companySms/list")

+ 198 - 0
fs-admin/src/main/java/com/fs/admin/controller/AdminVoiceBlacklistController.java

@@ -0,0 +1,198 @@
+package com.fs.admin.controller;
+
+import com.fs.admin.annotation.TenantDS;
+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.enums.DataSourceType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyVoiceRoboticCallBlacklist;
+import com.fs.company.enums.VoiceRoboticCallBlacklistBusinessTypeEnum;
+import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistService;
+import com.fs.company.vo.CompanyVoiceRoboticCallBlacklistExportVO;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 平台总后台 - 外呼黑名单(主库平台级 / 选租户切库查租户库)
+ */
+@TenantDS
+@RestController
+@RequestMapping("/admin/voice-blacklist")
+public class AdminVoiceBlacklistController extends BaseController {
+
+    private static final String HEADER_TENANT_ID = "tenant-id";
+
+    private static final List<String> TENANT_SCOPE_TYPES = Arrays.asList(
+            VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode(),
+            VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode()
+    );
+
+    @Autowired(required = false)
+    private ICompanyVoiceRoboticCallBlacklistService companyVoiceRoboticCallBlacklistService;
+
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyVoiceRoboticCallBlacklist param) {
+        startPage();
+        applyListScope(param);
+        List<CompanyVoiceRoboticCallBlacklist> list = companyVoiceRoboticCallBlacklistService != null
+                ? companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(param)
+                : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    @GetMapping("/{blacklistId}")
+    public AjaxResult getInfo(@PathVariable Long blacklistId) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        return AjaxResult.success(companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistById(blacklistId));
+    }
+
+    @Log(title = "外呼黑名单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        data.setCreateBy(getUsername());
+        data.setUpdateBy(getUsername());
+        if (data.getTargetType() == null) {
+            data.setTargetType(1);
+        }
+        if (data.getSource() == null) {
+            data.setSource(1);
+        }
+        if (data.getStatus() == null) {
+            data.setStatus(1);
+        }
+        if (hasTenantScope()) {
+            if (VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode().equals(data.getBusinessType())) {
+                return toAjax(companyVoiceRoboticCallBlacklistService.insertLineBlacklist(data));
+            }
+            if (VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode().equals(data.getBusinessType())) {
+                return toAjax(companyVoiceRoboticCallBlacklistService.insertTenantBlacklist(data));
+            }
+            return AjaxResult.error("租户库仅支持租户级(12)或线路级(13)黑名单");
+        }
+        return toAjax(companyVoiceRoboticCallBlacklistService.insertPlatformBlacklist(data));
+    }
+
+    @Log(title = "外呼黑名单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        data.setUpdateBy(getUsername());
+        if (!hasTenantScope()
+                && !VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode().equals(data.getBusinessType())) {
+            data.setBusinessType(VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode());
+            data.setCompanyId(null);
+        }
+        return toAjax(companyVoiceRoboticCallBlacklistService.updateCompanyVoiceRoboticCallBlacklist(data));
+    }
+
+    @Log(title = "外呼黑名单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{blacklistIds}")
+    public AjaxResult remove(@PathVariable Long[] blacklistIds) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        return toAjax(companyVoiceRoboticCallBlacklistService.deleteCompanyVoiceRoboticCallBlacklistByIds(blacklistIds));
+    }
+
+    @PutMapping("/changeStatus")
+    @Log(title = "外呼黑名单状态", businessType = BusinessType.UPDATE)
+    public AjaxResult changeStatus(@RequestBody CompanyVoiceRoboticCallBlacklist data) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        data.setUpdateBy(getUsername());
+        return toAjax(companyVoiceRoboticCallBlacklistService.changeStatus(data));
+    }
+
+    @Log(title = "外呼黑名单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyVoiceRoboticCallBlacklist param) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        applyListScope(param);
+        List<CompanyVoiceRoboticCallBlacklist> list =
+                companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(param);
+        List<CompanyVoiceRoboticCallBlacklistExportVO> exportList = list.stream().map(item -> {
+            CompanyVoiceRoboticCallBlacklistExportVO vo = new CompanyVoiceRoboticCallBlacklistExportVO();
+            BeanUtils.copyProperties(item, vo);
+            return vo;
+        }).collect(Collectors.toList());
+        ExcelUtil<CompanyVoiceRoboticCallBlacklistExportVO> util =
+                new ExcelUtil<>(CompanyVoiceRoboticCallBlacklistExportVO.class);
+        return util.exportExcel(exportList, "外呼黑名单");
+    }
+
+    @Log(title = "查看外呼黑名单手机号", businessType = BusinessType.GRANT)
+    @GetMapping("/queryPhone/{blacklistId}")
+    public AjaxResult queryPhone(@PathVariable Long blacklistId) {
+        if (companyVoiceRoboticCallBlacklistService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        String mobile = companyVoiceRoboticCallBlacklistService.getDecryptPhoneById(blacklistId);
+        if (mobile == null) {
+            return AjaxResult.error("记录不存在或手机号为空");
+        }
+        AjaxResult success = AjaxResult.success();
+        success.put("mobile", mobile);
+        return success;
+    }
+
+    private void applyListScope(CompanyVoiceRoboticCallBlacklist param) {
+        if (param == null) {
+            param = new CompanyVoiceRoboticCallBlacklist();
+        }
+        if (hasTenantScope()) {
+            param.setOnlyGlobal(false);
+            if (!StringUtils.hasText(param.getBusinessType())) {
+                param.setBusinessType(null);
+                param.setBusinessTypeList(TENANT_SCOPE_TYPES);
+            } else {
+                param.setBusinessTypeList(null);
+            }
+            return;
+        }
+        DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+        param.setBusinessTypeList(null);
+        if (!StringUtils.hasText(param.getBusinessType())) {
+            param.setBusinessType(VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode());
+            param.setOnlyGlobal(true);
+        } else if (VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode().equals(param.getBusinessType())) {
+            param.setOnlyGlobal(true);
+        } else {
+            param.setOnlyGlobal(false);
+        }
+    }
+
+    private boolean hasTenantScope() {
+        HttpServletRequest request = ServletUtils.getRequest();
+        if (request == null) {
+            return false;
+        }
+        String tenantId = request.getParameter("tenantId");
+        if (!StringUtils.hasText(tenantId)) {
+            tenantId = request.getHeader(HEADER_TENANT_ID);
+        }
+        return StringUtils.hasText(tenantId);
+    }
+}

+ 136 - 0
fs-admin/src/main/java/com/fs/admin/controller/AdminVoiceBlacklistInterceptController.java

@@ -0,0 +1,136 @@
+package com.fs.admin.controller;
+
+import com.fs.admin.annotation.TenantDS;
+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.enums.DataSourceType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyVoiceRoboticCallBlacklistInterceptLog;
+import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistInterceptLogService;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.StringUtils;
+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 javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 平台总后台 - 外呼黑名单拦截明细
+ * <p>
+ * 未选择租户时查询主库;请求头 tenant-id 或参数 tenantId 存在时切换租户库查询。
+ * </p>
+ */
+@TenantDS
+@RestController
+@RequestMapping("/admin/voice-blacklist-intercept")
+public class AdminVoiceBlacklistInterceptController extends BaseController {
+
+    private static final String HEADER_TENANT_ID = "tenant-id";
+
+    @Autowired(required = false)
+    private ICompanyVoiceRoboticCallBlacklistInterceptLogService interceptLogService;
+
+    /**
+     * 分页查询拦截明细列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        startPage();
+        ensureDataSource();
+        List<CompanyVoiceRoboticCallBlacklistInterceptLog> list = interceptLogService != null
+                ? interceptLogService.selectList(normalizeQuery(query))
+                : new ArrayList<>();
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询拦截明细详情
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:query')")
+    @GetMapping("/{id}")
+    public AjaxResult getInfo(@PathVariable Long id) {
+        if (interceptLogService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        ensureDataSource();
+        return AjaxResult.success(interceptLogService.selectById(id));
+    }
+
+    /**
+     * 查看拦截明细中的手机号明文(仅对象类型为手机号时有效)
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:queryPhone')")
+    @Log(title = "查看黑名单拦截明细手机号", businessType = BusinessType.GRANT)
+    @GetMapping("/queryPhone/{id}")
+    public AjaxResult queryPhone(@PathVariable Long id) {
+        if (interceptLogService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        ensureDataSource();
+        String mobile = interceptLogService.getDecryptTargetValueById(id);
+        if (!StringUtils.hasText(mobile)) {
+            return AjaxResult.error("记录不存在或对象值为空");
+        }
+        AjaxResult success = AjaxResult.success();
+        success.put("mobile", mobile);
+        return success;
+    }
+
+    /**
+     * 导出当前筛选条件下的拦截明细
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklistIntercept:export')")
+    @Log(title = "黑名单拦截明细", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        if (interceptLogService == null) {
+            return AjaxResult.error("服务不可用");
+        }
+        ensureDataSource();
+        List<CompanyVoiceRoboticCallBlacklistInterceptLog> list =
+                interceptLogService.selectList(normalizeQuery(query));
+        ExcelUtil<CompanyVoiceRoboticCallBlacklistInterceptLog> util =
+                new ExcelUtil<>(CompanyVoiceRoboticCallBlacklistInterceptLog.class);
+        return util.exportExcel(list, "黑名单拦截明细");
+    }
+
+    /**
+     * 未选租户时强制使用主数据源
+     */
+    private void ensureDataSource() {
+        if (!hasTenantScope()) {
+            DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+        }
+    }
+
+    private CompanyVoiceRoboticCallBlacklistInterceptLog normalizeQuery(
+            CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        return query != null ? query : new CompanyVoiceRoboticCallBlacklistInterceptLog();
+    }
+
+    /**
+     * 判断是否已选择租户(通过 query 参数或请求头)
+     */
+    private boolean hasTenantScope() {
+        HttpServletRequest request = ServletUtils.getRequest();
+        if (request == null) {
+            return false;
+        }
+        String tenantId = request.getParameter("tenantId");
+        if (!StringUtils.hasText(tenantId)) {
+            tenantId = request.getHeader(HEADER_TENANT_ID);
+        }
+        return StringUtils.hasText(tenantId);
+    }
+}

+ 79 - 26
fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticCallBlacklistController.java

@@ -8,20 +8,19 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.CompanyVoiceRoboticCallBlacklist;
 import com.fs.company.domain.CompanyVoiceRoboticCallBlacklist;
+import com.fs.company.enums.VoiceRoboticCallBlacklistBusinessTypeEnum;
 import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistService;
 import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.framework.service.TokenService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
- * 黑名单Controller
- *
- * @author fs
- * @date 2023-02-23
+ * 外呼黑名单 Controller
  */
  */
 @RestController
 @RestController
 @RequestMapping("/company/companyVoiceRoboticCallBlacklist")
 @RequestMapping("/company/companyVoiceRoboticCallBlacklist")
@@ -35,13 +34,12 @@ public class CompanyVoiceRoboticCallBlacklistController extends BaseController
     /**
     /**
      * 查询黑名单列表
      * 查询黑名单列表
      */
      */
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:list')")
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:list')")
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     public TableDataInfo list(CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     {
     {
         startPage();
         startPage();
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (companyVoiceRoboticCallBlacklist.getCompanyId() == null && loginUser.getCompany() != null) { companyVoiceRoboticCallBlacklist.setCompanyId(loginUser.getCompany().getCompanyId()); };
+        companyVoiceRoboticCallBlacklist = applyLineScope(companyVoiceRoboticCallBlacklist);
         List<CompanyVoiceRoboticCallBlacklist> list = companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(companyVoiceRoboticCallBlacklist);
         List<CompanyVoiceRoboticCallBlacklist> list = companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(companyVoiceRoboticCallBlacklist);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
@@ -49,20 +47,21 @@ public class CompanyVoiceRoboticCallBlacklistController extends BaseController
     /**
     /**
      * 导出黑名单列表
      * 导出黑名单列表
      */
      */
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:export')")
-    @Log(title = "黑名单", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:export')")
+    @Log(title = "外呼黑名单", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
     public AjaxResult export(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     public AjaxResult export(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     {
     {
+        companyVoiceRoboticCallBlacklist = applyLineScope(companyVoiceRoboticCallBlacklist);
         List<CompanyVoiceRoboticCallBlacklist> list = companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(companyVoiceRoboticCallBlacklist);
         List<CompanyVoiceRoboticCallBlacklist> list = companyVoiceRoboticCallBlacklistService.selectCompanyVoiceRoboticCallBlacklistList(companyVoiceRoboticCallBlacklist);
-        ExcelUtil<CompanyVoiceRoboticCallBlacklist> util = new ExcelUtil<CompanyVoiceRoboticCallBlacklist>(CompanyVoiceRoboticCallBlacklist.class);
-        return util.exportExcel(list, "companyVoiceBlacklist");
+        ExcelUtil<CompanyVoiceRoboticCallBlacklist> util = new ExcelUtil<>(CompanyVoiceRoboticCallBlacklist.class);
+        return util.exportExcel(list, "外呼黑名单");
     }
     }
 
 
     /**
     /**
      * 获取黑名单详细信息
      * 获取黑名单详细信息
      */
      */
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:query')")
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:query')")
     @GetMapping(value = "/{blacklistId}")
     @GetMapping(value = "/{blacklistId}")
     public AjaxResult getInfo(@PathVariable("blacklistId") Long blacklistId)
     public AjaxResult getInfo(@PathVariable("blacklistId") Long blacklistId)
     {
     {
@@ -72,44 +71,98 @@ public class CompanyVoiceRoboticCallBlacklistController extends BaseController
     /**
     /**
      * 新增黑名单
      * 新增黑名单
      */
      */
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:add')")
-    @Log(title = "黑名单", businessType = BusinessType.INSERT)
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:add')")
+    @Log(title = "外呼黑名单", businessType = BusinessType.INSERT)
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     public AjaxResult add(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     {
     {
+        companyVoiceRoboticCallBlacklist = applyLineScope(companyVoiceRoboticCallBlacklist);
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (companyVoiceRoboticCallBlacklist.getCompanyId() == null && loginUser.getCompany() != null) { companyVoiceRoboticCallBlacklist.setCompanyId(loginUser.getCompany().getCompanyId()); }
-        return toAjax(companyVoiceRoboticCallBlacklistService.insertCompanyVoiceRoboticCallBlacklist(companyVoiceRoboticCallBlacklist));
+        String operator = resolveOperatorName(loginUser);
+        companyVoiceRoboticCallBlacklist.setCreateBy(operator);
+        companyVoiceRoboticCallBlacklist.setUpdateBy(operator);
+        if (companyVoiceRoboticCallBlacklist.getTargetType() == null) {
+            companyVoiceRoboticCallBlacklist.setTargetType(1);
+        }
+        return toAjax(companyVoiceRoboticCallBlacklistService.insertLineBlacklist(companyVoiceRoboticCallBlacklist));
     }
     }
 
 
     /**
     /**
-     * 修改黑名单nessType = BusinessType.UPDATE)
-     * */
+     * 修改黑名单
+     */
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:edit')")
+    @Log(title = "外呼黑名单", businessType = BusinessType.UPDATE)
     @PutMapping
     @PutMapping
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:update')")
-    @Log(title = "修改黑名单信息", businessType = BusinessType.INSERT)
     public AjaxResult edit(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     public AjaxResult edit(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyVoiceRoboticCallBlacklist.setUpdateBy(resolveOperatorName(loginUser));
         return toAjax(companyVoiceRoboticCallBlacklistService.updateCompanyVoiceRoboticCallBlacklist(companyVoiceRoboticCallBlacklist));
         return toAjax(companyVoiceRoboticCallBlacklistService.updateCompanyVoiceRoboticCallBlacklist(companyVoiceRoboticCallBlacklist));
     }
     }
 
 
     /**
     /**
      * 删除黑名单
      * 删除黑名单
      */
      */
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:remove')")
-    @Log(title = "黑名单", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{blacklistIds}")
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:remove')")
+    @Log(title = "外呼黑名单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{blacklistIds}")
     public AjaxResult remove(@PathVariable Long[] blacklistIds)
     public AjaxResult remove(@PathVariable Long[] blacklistIds)
     {
     {
         return toAjax(companyVoiceRoboticCallBlacklistService.deleteCompanyVoiceRoboticCallBlacklistByIds(blacklistIds));
         return toAjax(companyVoiceRoboticCallBlacklistService.deleteCompanyVoiceRoboticCallBlacklistByIds(blacklistIds));
     }
     }
 
 
-    @Log(title = "修改黑名单状态", businessType = BusinessType.UPDATE)
-    @PreAuthorize("@ss.hasPermi('company:companyVoiceBlacklist:update')")
+    /**
+     * 修改黑名单状态
+     */
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:edit')")
+    @Log(title = "外呼黑名单状态", businessType = BusinessType.UPDATE)
     @PutMapping("/changeStatus")
     @PutMapping("/changeStatus")
     public AjaxResult changeStatus(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist) {
     public AjaxResult changeStatus(@RequestBody CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyVoiceRoboticCallBlacklist.setUpdateBy(resolveOperatorName(loginUser));
         return toAjax(companyVoiceRoboticCallBlacklistService.changeStatus(companyVoiceRoboticCallBlacklist));
         return toAjax(companyVoiceRoboticCallBlacklistService.changeStatus(companyVoiceRoboticCallBlacklist));
     }
     }
 
 
+    /**
+     * 查看解密手机号
+     */
+    @PreAuthorize("@ss.hasPermi('company:voiceRoboticCallBlacklist:queryPhone')")
+    @Log(title = "查看外呼黑名单手机号", businessType = BusinessType.GRANT)
+    @GetMapping("/queryPhone/{blacklistId}")
+    public AjaxResult queryPhone(@PathVariable Long blacklistId) {
+        String mobile = companyVoiceRoboticCallBlacklistService.getDecryptPhoneById(blacklistId);
+        if (!StringUtils.hasText(mobile)) {
+            return AjaxResult.error("记录不存在或手机号为空");
+        }
+        AjaxResult success = AjaxResult.success();
+        success.put("mobile", mobile);
+        return success;
+    }
 
 
+    /**
+     * 租户端默认线路级黑名单(businessType=13)
+     */
+    private CompanyVoiceRoboticCallBlacklist applyLineScope(CompanyVoiceRoboticCallBlacklist query) {
+        if (query == null) {
+            query = new CompanyVoiceRoboticCallBlacklist();
+        }
+        if (!StringUtils.hasText(query.getBusinessType())) {
+            query.setBusinessType(VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode());
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (query.getCompanyId() == null && loginUser != null && loginUser.getCompany() != null) {
+            query.setCompanyId(loginUser.getCompany().getCompanyId());
+        }
+        return query;
+    }
+
+    private String resolveOperatorName(LoginUser loginUser) {
+        if (loginUser != null && loginUser.getUser() != null && StringUtils.hasText(loginUser.getUser().getNickName())) {
+            return loginUser.getUser().getNickName();
+        }
+        if (loginUser != null && StringUtils.hasText(loginUser.getUsername())) {
+            return loginUser.getUsername();
+        }
+        return getUsername();
+    }
 }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/comm/service/CommCallSendService.java

@@ -100,7 +100,11 @@ public class CommCallSendService {
         CompanyVoiceRoboticCallBlacklistCheckParam blacklistParam = new CompanyVoiceRoboticCallBlacklistCheckParam();
         CompanyVoiceRoboticCallBlacklistCheckParam blacklistParam = new CompanyVoiceRoboticCallBlacklistCheckParam();
         blacklistParam.setCompanyId(crmCustomer.getCompanyId());
         blacklistParam.setCompanyId(crmCustomer.getCompanyId());
         blacklistParam.setBusinessType(BusinessTypeEnum.CALL.getCode());
         blacklistParam.setBusinessType(BusinessTypeEnum.CALL.getCode());
+        blacklistParam.setTargetType(1);
         blacklistParam.setTargetValue(callees.getPhone());
         blacklistParam.setTargetValue(callees.getPhone());
+        blacklistParam.setCustomerId(crmCustomer.getCustomerId());
+        blacklistParam.setCalleeId(param.getCalleeId());
+        blacklistParam.setRoboticId(robotic.getId());
         CompanyVoiceRoboticCallBlacklistCheckVO blacklistVo = companyVoiceRoboticCallBlacklistService.checkBlacklist(blacklistParam);
         CompanyVoiceRoboticCallBlacklistCheckVO blacklistVo = companyVoiceRoboticCallBlacklistService.checkBlacklist(blacklistParam);
         if (!blacklistVo.getPass()) {
         if (!blacklistVo.getPass()) {
             throw new ServiceException("被叫人命中外呼黑名单");
             throw new ServiceException("被叫人命中外呼黑名单");

+ 21 - 1
fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallBlacklist.java

@@ -2,39 +2,46 @@ package com.fs.company.domain;
 
 
 
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.NoArgsConstructor;
 
 
 import java.util.Date;
 import java.util.Date;
+import java.util.List;
 
 
 /**
 /**
  * 黑名单对象 company_voice_blacklist
  * 黑名单对象 company_voice_blacklist
  * @author ZhuanZ(无密码)
  * @author ZhuanZ(无密码)
  */
  */
 @Data
 @Data
+@EqualsAndHashCode(callSuper = true)
 @AllArgsConstructor
 @AllArgsConstructor
 @NoArgsConstructor
 @NoArgsConstructor
 public class CompanyVoiceRoboticCallBlacklist extends BaseEntity
 public class CompanyVoiceRoboticCallBlacklist extends BaseEntity
 {
 {
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
+    @Excel(name = "ID")
     private Long id;
     private Long id;
 
 
     /**
     /**
-     * 业务类型
+     * 黑名单级别:1-10 预留;11 平台封禁;12 租户级;13 线路(手机号)级
      */
      */
     private String businessType;
     private String businessType;
 
 
     /**
     /**
      * 1手机号 2客户ID 3企微客户ID
      * 1手机号 2客户ID 3企微客户ID
      */
      */
+    @Excel(name = "对象类型", readConverterExp = "1=手机号,2=客户ID,3=企微客户ID")
     private Integer targetType;
     private Integer targetType;
 
 
     /**
     /**
      * 对象值
      * 对象值
      */
      */
+    @Excel(name = "对象值")
     private String targetValue;
     private String targetValue;
 
 
     /**
     /**
@@ -45,31 +52,39 @@ public class CompanyVoiceRoboticCallBlacklist extends BaseEntity
     /**
     /**
      * 拉黑原因
      * 拉黑原因
      */
      */
+    @Excel(name = "拉黑原因")
     private String reason;
     private String reason;
 
 
     /**
     /**
      * 来源:1手工添加 2系统
      * 来源:1手工添加 2系统
      */
      */
+    @Excel(name = "来源", readConverterExp = "1=手动添加,2=系统同步")
     private Integer source;
     private Integer source;
 
 
     /**
     /**
      * 状态:1生效 0禁用
      * 状态:1生效 0禁用
      */
      */
+    @Excel(name = "状态", readConverterExp = "0=失效,1=生效")
     private Integer status;
     private Integer status;
 
 
     /**
     /**
      * 备注
      * 备注
      */
      */
+    @Excel(name = "备注")
     private String remark;
     private String remark;
 
 
+    @Excel(name = "创建人")
     private String createBy;
     private String createBy;
 
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
     private Date createTime;
 
 
+    @Excel(name = "更新人")
     private String updateBy;
     private String updateBy;
 
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
     private Date updateTime;
 
 
     /**
     /**
@@ -82,4 +97,9 @@ public class CompanyVoiceRoboticCallBlacklist extends BaseEntity
      */
      */
     private Boolean onlyGlobal;
     private Boolean onlyGlobal;
 
 
+    /**
+     * 查询用:多黑名单级别(如 12 租户级 + 13 线路级)
+     */
+    private List<String> businessTypeList;
+
 }
 }

+ 64 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyVoiceRoboticCallBlacklistInterceptLog.java

@@ -0,0 +1,64 @@
+package com.fs.company.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 外呼黑名单拦截明细 company_voice_robotic_call_blacklist_intercept_log
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyVoiceRoboticCallBlacklistInterceptLog extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @Excel(name = "ID")
+    private Long id;
+
+    private Long companyId;
+
+    @Excel(name = "业务场景", readConverterExp = "CALL=外呼,SMS=短信,ADD_WX=加微")
+    private String sceneCode;
+
+    private Long blacklistId;
+
+    @Excel(name = "对象类型", readConverterExp = "1=手机号,2=客户ID,3=企微客户ID")
+    private Integer targetType;
+
+    @Excel(name = "对象值")
+    private String targetValue;
+
+    @Excel(name = "拉黑原因")
+    private String blacklistReason;
+
+    @Excel(name = "拦截说明")
+    private String interceptReason;
+
+    @Excel(name = "客户ID")
+    private Long customerId;
+
+    @Excel(name = "被叫人ID")
+    private Long calleeId;
+
+    @Excel(name = "外呼任务ID")
+    private Long roboticId;
+
+    @Excel(name = "操作人ID")
+    private Long companyUserId;
+
+    @Excel(name = "业务ID")
+    private String bizId;
+
+    private String bizTraceId;
+
+    private String requestIp;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "拦截时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+}

+ 51 - 0
fs-service/src/main/java/com/fs/company/enums/VoiceRoboticCallBlacklistBusinessTypeEnum.java

@@ -0,0 +1,51 @@
+package com.fs.company.enums;
+
+/**
+ * 外呼黑名单级别(business_type 字段)
+ * 1-10 预留;11 平台封禁;12 租户级;13 线路(手机号)级
+ *
+ * @author ZhuanZ
+ */
+public enum VoiceRoboticCallBlacklistBusinessTypeEnum {
+
+    /** 平台级黑名单 */
+    PLATFORM("11", "平台封禁"),
+
+    /** 租户级黑名单 */
+    TENANT("12", "租户级黑名单"),
+
+    /** 线路(手机号)级黑名单 */
+    LINE("13", "线路(手机号)级黑名单");
+
+    private final String code;
+    private final String desc;
+
+    VoiceRoboticCallBlacklistBusinessTypeEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public static VoiceRoboticCallBlacklistBusinessTypeEnum fromCode(String code) {
+        if (code == null) {
+            return null;
+        }
+        for (VoiceRoboticCallBlacklistBusinessTypeEnum item : values()) {
+            if (item.code.equals(code)) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public static boolean isValid(String code) {
+        return fromCode(code) != null;
+    }
+}

+ 17 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCallBlacklistInterceptLogMapper.java

@@ -0,0 +1,17 @@
+package com.fs.company.mapper;
+
+import com.fs.company.domain.CompanyVoiceRoboticCallBlacklistInterceptLog;
+
+import java.util.List;
+
+/**
+ * 外呼黑名单拦截明细 Mapper
+ */
+public interface CompanyVoiceRoboticCallBlacklistInterceptLogMapper {
+
+    CompanyVoiceRoboticCallBlacklistInterceptLog selectById(Long id);
+
+    List<CompanyVoiceRoboticCallBlacklistInterceptLog> selectList(CompanyVoiceRoboticCallBlacklistInterceptLog query);
+
+    int insert(CompanyVoiceRoboticCallBlacklistInterceptLog log);
+}

+ 25 - 3
fs-service/src/main/java/com/fs/company/param/CompanyVoiceRoboticCallBlacklistCheckParam.java

@@ -10,17 +10,26 @@ import java.io.Serializable;
 @Data
 @Data
 public class CompanyVoiceRoboticCallBlacklistCheckParam implements Serializable {
 public class CompanyVoiceRoboticCallBlacklistCheckParam implements Serializable {
     /**
     /**
-     * 公司ID
+     * 租户ID(数据源标识)。
+     * <p>
+     * 传入时:先切租户库查 12 租户级、13 线路级黑名单;未命中再切主库查 11 平台级。
+     * 未传时:仅切主库查 11 平台级黑名单。
+     * </p>
+     */
+    private Long tenantId;
+
+    /**
+     * 公司ID(租户库内查 12/13 级黑名单时必填)
      */
      */
     private Long companyId;
     private Long companyId;
 
 
     /**
     /**
-     * 业务类型
+     * 业务场景(外呼 CALL / 短信 SMS / 加微 ADD_WX),写入拦截明细 scene_code
      */
      */
     private String businessType;
     private String businessType;
 
 
     /**
     /**
-     * 手机号
+     * 对象值(手机号/客户ID等)
      */
      */
     private String targetValue;
     private String targetValue;
 
 
@@ -29,6 +38,19 @@ public class CompanyVoiceRoboticCallBlacklistCheckParam implements Serializable
      */
      */
     private Integer targetType;
     private Integer targetType;
 
 
+    private Long customerId;
+
+    private Long calleeId;
+
+    private Long roboticId;
+
+    private Long companyUserId;
+
+    private String bizId;
+
+    private String bizTraceId;
+
+    private String requestIp;
 
 
 }
 }
 
 

+ 27 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticCallBlacklistInterceptLogService.java

@@ -0,0 +1,27 @@
+package com.fs.company.service;
+
+import com.fs.company.domain.CompanyVoiceRoboticCallBlacklistInterceptLog;
+import com.fs.company.param.CompanyVoiceRoboticCallBlacklistCheckParam;
+import com.fs.company.vo.CompanyVoiceRoboticCallBlacklistCheckVO;
+
+import java.util.List;
+
+/**
+ * 外呼黑名单拦截明细 Service
+ */
+public interface ICompanyVoiceRoboticCallBlacklistInterceptLogService {
+
+    CompanyVoiceRoboticCallBlacklistInterceptLog selectById(Long id);
+
+    List<CompanyVoiceRoboticCallBlacklistInterceptLog> selectList(CompanyVoiceRoboticCallBlacklistInterceptLog query);
+
+    /**
+     * 命中黑名单被拦截时写入明细
+     */
+    void saveOnBlacklistReject(CompanyVoiceRoboticCallBlacklistCheckParam param, CompanyVoiceRoboticCallBlacklistCheckVO vo);
+
+    /**
+     * 解密对象值(手机号)
+     */
+    String getDecryptTargetValueById(Long id);
+}

+ 34 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticCallBlacklistService.java

@@ -67,7 +67,40 @@ public interface ICompanyVoiceRoboticCallBlacklistService
     int changeStatus(CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist);
     int changeStatus(CompanyVoiceRoboticCallBlacklist companyVoiceRoboticCallBlacklist);
 
 
     /**
     /**
-     * 外呼前检查是否命中黑名单
+     * 外呼前检查是否命中黑名单(依赖当前线程数据源,不主动切库)
      */
      */
     CompanyVoiceRoboticCallBlacklistCheckVO checkBlacklist(CompanyVoiceRoboticCallBlacklistCheckParam companyVoiceRoboticCallBlacklistCheckParam);
     CompanyVoiceRoboticCallBlacklistCheckVO checkBlacklist(CompanyVoiceRoboticCallBlacklistCheckParam companyVoiceRoboticCallBlacklistCheckParam);
+
+    /**
+     * 按数据源进行黑名单校验,命中时拦截并写入拦截明细。
+     * <p>
+     * 调用方通过 {@link CompanyVoiceRoboticCallBlacklistCheckParam#getTenantId()} 告知数据源:
+     * <ul>
+     *   <li>传入 tenantId:切租户库,先查 12 租户级、13 线路级;未命中再切主库查 11 平台级</li>
+     *   <li>未传 tenantId:仅切主库查 11 平台级</li>
+     * </ul>
+     * 拦截明细落库规则:租户/线路命中 → 写入租户库;平台命中 → 写入主库。
+     * </p>
+     */
+    CompanyVoiceRoboticCallBlacklistCheckVO checkBlacklistWithDataSource(CompanyVoiceRoboticCallBlacklistCheckParam param);
+
+    /**
+     * 新增平台级黑名单(businessType=11,companyId 为空)
+     */
+    int insertPlatformBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist);
+
+    /**
+     * 新增租户级黑名单(businessType=12)
+     */
+    int insertTenantBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist);
+
+    /**
+     * 新增线路级黑名单(businessType=13)
+     */
+    int insertLineBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist);
+
+    /**
+     * 查看解密手机号
+     */
+    String getDecryptPhoneById(Long blacklistId);
 }
 }

+ 98 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallBlacklistInterceptLogServiceImpl.java

@@ -0,0 +1,98 @@
+package com.fs.company.service.impl;
+
+import com.fs.company.domain.CompanyVoiceRoboticCallBlacklist;
+import com.fs.company.domain.CompanyVoiceRoboticCallBlacklistInterceptLog;
+import com.fs.company.mapper.CompanyVoiceRoboticCallBlacklistInterceptLogMapper;
+import com.fs.company.mapper.CompanyVoiceRoboticCallBlacklistMapper;
+import com.fs.company.param.CompanyVoiceRoboticCallBlacklistCheckParam;
+import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistInterceptLogService;
+import com.fs.company.vo.CompanyVoiceRoboticCallBlacklistCheckVO;
+import com.fs.his.utils.PhoneUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+/**
+ * 外呼黑名单拦截明细 Service 实现
+ */
+@Service
+public class CompanyVoiceRoboticCallBlacklistInterceptLogServiceImpl implements ICompanyVoiceRoboticCallBlacklistInterceptLogService {
+
+    private static final Logger log = LoggerFactory.getLogger(CompanyVoiceRoboticCallBlacklistInterceptLogServiceImpl.class);
+
+    @Autowired
+    private CompanyVoiceRoboticCallBlacklistInterceptLogMapper interceptLogMapper;
+
+    @Autowired
+    private CompanyVoiceRoboticCallBlacklistMapper blacklistMapper;
+
+    @Override
+    public CompanyVoiceRoboticCallBlacklistInterceptLog selectById(Long id) {
+        return interceptLogMapper.selectById(id);
+    }
+
+    @Override
+    public List<CompanyVoiceRoboticCallBlacklistInterceptLog> selectList(CompanyVoiceRoboticCallBlacklistInterceptLog query) {
+        prepareQueryTargetValue(query);
+        return interceptLogMapper.selectList(query);
+    }
+
+    @Override
+    public void saveOnBlacklistReject(CompanyVoiceRoboticCallBlacklistCheckParam param, CompanyVoiceRoboticCallBlacklistCheckVO vo) {
+        if (param == null || vo == null || Boolean.TRUE.equals(vo.getPass()) || !Boolean.TRUE.equals(vo.getHitBlacklist())) {
+            return;
+        }
+        try {
+            CompanyVoiceRoboticCallBlacklistInterceptLog entity = new CompanyVoiceRoboticCallBlacklistInterceptLog();
+            entity.setCompanyId(param.getCompanyId());
+            entity.setSceneCode(StringUtils.hasText(param.getBusinessType()) ? param.getBusinessType() : null);
+            entity.setBlacklistId(vo.getBlacklistId());
+            entity.setTargetType(vo.getTargetType() != null ? vo.getTargetType() : param.getTargetType());
+            entity.setTargetValue(vo.getTargetValue());
+            entity.setInterceptReason(vo.getReason());
+            entity.setCustomerId(param.getCustomerId());
+            entity.setCalleeId(param.getCalleeId());
+            entity.setRoboticId(param.getRoboticId());
+            entity.setCompanyUserId(param.getCompanyUserId());
+            entity.setBizId(param.getBizId());
+            entity.setBizTraceId(param.getBizTraceId());
+            entity.setRequestIp(param.getRequestIp());
+            if (vo.getBlacklistId() != null) {
+                CompanyVoiceRoboticCallBlacklist blacklist = blacklistMapper.selectCompanyVoiceBlacklistById(vo.getBlacklistId());
+                if (blacklist != null) {
+                    entity.setBlacklistReason(blacklist.getReason());
+                }
+            }
+            interceptLogMapper.insert(entity);
+        } catch (Exception e) {
+            log.warn("写入黑名单拦截明细失败: {}", e.getMessage());
+        }
+    }
+
+    @Override
+    public String getDecryptTargetValueById(Long id) {
+        CompanyVoiceRoboticCallBlacklistInterceptLog db = interceptLogMapper.selectById(id);
+        if (db == null || !StringUtils.hasText(db.getTargetValue())) {
+            return null;
+        }
+        if (Integer.valueOf(1).equals(db.getTargetType())) {
+            return PhoneUtil.decryptAutoPhone(db.getTargetValue());
+        }
+        return db.getTargetValue();
+    }
+
+    private void prepareQueryTargetValue(CompanyVoiceRoboticCallBlacklistInterceptLog entity) {
+        if (entity == null || !StringUtils.hasText(entity.getTargetValue())) {
+            return;
+        }
+        Integer targetType = entity.getTargetType() != null ? entity.getTargetType() : 1;
+        String value = entity.getTargetValue().trim();
+        if (Integer.valueOf(1).equals(targetType) && value.length() <= 11) {
+            entity.setTargetValue(PhoneUtil.encryptPhone(value));
+        }
+    }
+}

+ 230 - 36
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallBlacklistServiceImpl.java

@@ -1,11 +1,17 @@
 package com.fs.company.service.impl;
 package com.fs.company.service.impl;
 
 
+import com.fs.common.enums.DataSourceType;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.company.domain.CompanyVoiceRoboticCallBlacklist;
 import com.fs.company.domain.CompanyVoiceRoboticCallBlacklist;
+import com.fs.company.enums.VoiceRoboticCallBlacklistBusinessTypeEnum;
 import com.fs.company.mapper.CompanyVoiceRoboticCallBlacklistMapper;
 import com.fs.company.mapper.CompanyVoiceRoboticCallBlacklistMapper;
 import com.fs.company.param.CompanyVoiceRoboticCallBlacklistCheckParam;
 import com.fs.company.param.CompanyVoiceRoboticCallBlacklistCheckParam;
+import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistInterceptLogService;
 import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistService;
 import com.fs.company.service.ICompanyVoiceRoboticCallBlacklistService;
 import com.fs.company.vo.CompanyVoiceRoboticCallBlacklistCheckVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallBlacklistCheckVO;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
+import com.fs.framework.datasource.TenantDataSourceManager;
+import com.fs.his.utils.PhoneUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
@@ -15,7 +21,7 @@ import java.util.List;
 
 
 /**
 /**
  * 黑名单Service业务层处理
  * 黑名单Service业务层处理
- * 
+ *
  * @author fs
  * @author fs
  * @date 2023-02-23
  * @date 2023-02-23
  */
  */
@@ -25,9 +31,15 @@ public class CompanyVoiceRoboticCallBlacklistServiceImpl implements ICompanyVoic
     @Autowired
     @Autowired
     private CompanyVoiceRoboticCallBlacklistMapper companyVoiceRoboticCallBlacklistMapper;
     private CompanyVoiceRoboticCallBlacklistMapper companyVoiceRoboticCallBlacklistMapper;
 
 
+    @Autowired
+    private ICompanyVoiceRoboticCallBlacklistInterceptLogService interceptLogService;
+
+    @Autowired
+    private TenantDataSourceManager tenantDataSourceManager;
+
     /**
     /**
      * 查询黑名单
      * 查询黑名单
-     * 
+     *
      * @param blacklistId 黑名单ID
      * @param blacklistId 黑名单ID
      * @return 黑名单
      * @return 黑名单
      */
      */
@@ -39,45 +51,109 @@ public class CompanyVoiceRoboticCallBlacklistServiceImpl implements ICompanyVoic
 
 
     /**
     /**
      * 查询黑名单列表
      * 查询黑名单列表
-     * 
+     *
      * @param companyCallBlacklist 黑名单
      * @param companyCallBlacklist 黑名单
      * @return 黑名单
      * @return 黑名单
      */
      */
     @Override
     @Override
     public List<CompanyVoiceRoboticCallBlacklist> selectCompanyVoiceRoboticCallBlacklistList(CompanyVoiceRoboticCallBlacklist companyCallBlacklist)
     public List<CompanyVoiceRoboticCallBlacklist> selectCompanyVoiceRoboticCallBlacklistList(CompanyVoiceRoboticCallBlacklist companyCallBlacklist)
     {
     {
+        prepareQueryTargetValue(companyCallBlacklist);
         return companyVoiceRoboticCallBlacklistMapper.selectCompanyVoiceBlacklistList(companyCallBlacklist);
         return companyVoiceRoboticCallBlacklistMapper.selectCompanyVoiceBlacklistList(companyCallBlacklist);
     }
     }
 
 
     /**
     /**
      * 新增黑名单
      * 新增黑名单
-     * 
+     *
      * @param companyCallBlacklist 黑名单
      * @param companyCallBlacklist 黑名单
      * @return 结果
      * @return 结果
      */
      */
     @Override
     @Override
     public int insertCompanyVoiceRoboticCallBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist)
     public int insertCompanyVoiceRoboticCallBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist)
     {
     {
+        prepareTargetValue(companyCallBlacklist);
+        companyCallBlacklist.setCreateTime(DateUtils.getNowDate());
+        return companyVoiceRoboticCallBlacklistMapper.insertCompanyVoiceBlacklist(companyCallBlacklist);
+    }
+
+    @Override
+    public int insertPlatformBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist) {
+        companyCallBlacklist.setBusinessType(VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode());
+        companyCallBlacklist.setCompanyId(null);
+        if (companyCallBlacklist.getTargetType() == null) {
+            companyCallBlacklist.setTargetType(1);
+        }
+        if (companyCallBlacklist.getSource() == null) {
+            companyCallBlacklist.setSource(1);
+        }
+        if (companyCallBlacklist.getStatus() == null) {
+            companyCallBlacklist.setStatus(1);
+        }
+        if (!StringUtils.hasText(companyCallBlacklist.getTargetValue())) {
+            throw new RuntimeException("手机号不能为空");
+        }
+        prepareTargetValue(companyCallBlacklist);
+        companyCallBlacklist.setCreateTime(DateUtils.getNowDate());
+        return companyVoiceRoboticCallBlacklistMapper.insertCompanyVoiceBlacklist(companyCallBlacklist);
+    }
+
+    @Override
+    public int insertTenantBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist) {
+        companyCallBlacklist.setBusinessType(VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode());
+        if (companyCallBlacklist.getTargetType() == null) {
+            companyCallBlacklist.setTargetType(1);
+        }
+        if (companyCallBlacklist.getSource() == null) {
+            companyCallBlacklist.setSource(1);
+        }
+        if (companyCallBlacklist.getStatus() == null) {
+            companyCallBlacklist.setStatus(1);
+        }
+        if (!StringUtils.hasText(companyCallBlacklist.getTargetValue())) {
+            throw new RuntimeException("对象值不能为空");
+        }
+        prepareTargetValue(companyCallBlacklist);
+        companyCallBlacklist.setCreateTime(DateUtils.getNowDate());
+        return companyVoiceRoboticCallBlacklistMapper.insertCompanyVoiceBlacklist(companyCallBlacklist);
+    }
+
+    @Override
+    public int insertLineBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist) {
+        companyCallBlacklist.setBusinessType(VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode());
+        if (companyCallBlacklist.getTargetType() == null) {
+            companyCallBlacklist.setTargetType(1);
+        }
+        if (companyCallBlacklist.getSource() == null) {
+            companyCallBlacklist.setSource(1);
+        }
+        if (companyCallBlacklist.getStatus() == null) {
+            companyCallBlacklist.setStatus(1);
+        }
+        if (!StringUtils.hasText(companyCallBlacklist.getTargetValue())) {
+            throw new RuntimeException("对象值不能为空");
+        }
+        prepareTargetValue(companyCallBlacklist);
         companyCallBlacklist.setCreateTime(DateUtils.getNowDate());
         companyCallBlacklist.setCreateTime(DateUtils.getNowDate());
         return companyVoiceRoboticCallBlacklistMapper.insertCompanyVoiceBlacklist(companyCallBlacklist);
         return companyVoiceRoboticCallBlacklistMapper.insertCompanyVoiceBlacklist(companyCallBlacklist);
     }
     }
 
 
     /**
     /**
      * 修改黑名单
      * 修改黑名单
-     * 
+     *
      * @param companyCallBlacklist 黑名单
      * @param companyCallBlacklist 黑名单
      * @return 结果
      * @return 结果
      */
      */
     @Override
     @Override
     public int updateCompanyVoiceRoboticCallBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist)
     public int updateCompanyVoiceRoboticCallBlacklist(CompanyVoiceRoboticCallBlacklist companyCallBlacklist)
     {
     {
+        prepareTargetValue(companyCallBlacklist);
         companyCallBlacklist.setUpdateTime(DateUtils.getNowDate());
         companyCallBlacklist.setUpdateTime(DateUtils.getNowDate());
         return companyVoiceRoboticCallBlacklistMapper.updateCompanyVoiceBlacklist(companyCallBlacklist);
         return companyVoiceRoboticCallBlacklistMapper.updateCompanyVoiceBlacklist(companyCallBlacklist);
     }
     }
 
 
     /**
     /**
      * 批量删除黑名单
      * 批量删除黑名单
-     * 
+     *
      * @param blacklistIds 需要删除的黑名单ID
      * @param blacklistIds 需要删除的黑名单ID
      * @return 结果
      * @return 结果
      */
      */
@@ -89,7 +165,7 @@ public class CompanyVoiceRoboticCallBlacklistServiceImpl implements ICompanyVoic
 
 
     /**
     /**
      * 删除黑名单信息
      * 删除黑名单信息
-     * 
+     *
      * @param blacklistId 黑名单ID
      * @param blacklistId 黑名单ID
      * @return 结果
      * @return 结果
      */
      */
@@ -115,6 +191,7 @@ public class CompanyVoiceRoboticCallBlacklistServiceImpl implements ICompanyVoic
         CompanyVoiceRoboticCallBlacklist entity = new CompanyVoiceRoboticCallBlacklist();
         CompanyVoiceRoboticCallBlacklist entity = new CompanyVoiceRoboticCallBlacklist();
         entity.setId(companyVoiceRoboticCallBlacklist.getId());
         entity.setId(companyVoiceRoboticCallBlacklist.getId());
         entity.setStatus(companyVoiceRoboticCallBlacklist.getStatus());
         entity.setStatus(companyVoiceRoboticCallBlacklist.getStatus());
+        entity.setUpdateBy(companyVoiceRoboticCallBlacklist.getUpdateBy());
         return companyVoiceRoboticCallBlacklistMapper.updateStatusById(entity);
         return companyVoiceRoboticCallBlacklistMapper.updateStatusById(entity);
     }
     }
 
 
@@ -123,65 +200,182 @@ public class CompanyVoiceRoboticCallBlacklistServiceImpl implements ICompanyVoic
      */
      */
     @Override
     @Override
     public CompanyVoiceRoboticCallBlacklistCheckVO checkBlacklist(CompanyVoiceRoboticCallBlacklistCheckParam param) {
     public CompanyVoiceRoboticCallBlacklistCheckVO checkBlacklist(CompanyVoiceRoboticCallBlacklistCheckParam param) {
-        if (param == null || param.getCompanyId() == null
-                || !StringUtils.hasText(param.getBusinessType())
-                || !StringUtils.hasText(param.getTargetValue())) {
+        if (param == null || !StringUtils.hasText(param.getTargetValue())) {
             return CompanyVoiceRoboticCallBlacklistCheckVO.paramNull("校验参数不能为空");
             return CompanyVoiceRoboticCallBlacklistCheckVO.paramNull("校验参数不能为空");
         }
         }
 
 
         String targetValue = normalizeTargetValue(param.getTargetType(), param.getTargetValue());
         String targetValue = normalizeTargetValue(param.getTargetType(), param.getTargetValue());
+        targetValue = encryptPhoneIfNeeded(param.getTargetType(), targetValue);
 
 
-        // 1. 有 companyId,先查公司级黑名单
+        // 1. 有 companyId,先查租户级黑名单(businessType=12)
         if (param.getCompanyId() != null) {
         if (param.getCompanyId() != null) {
             CompanyVoiceRoboticCallBlacklist companyHit =
             CompanyVoiceRoboticCallBlacklist companyHit =
                     companyVoiceRoboticCallBlacklistMapper.selectActiveByTarget(
                     companyVoiceRoboticCallBlacklistMapper.selectActiveByTarget(
                             param.getCompanyId(),
                             param.getCompanyId(),
-                            param.getBusinessType(),
+                            VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode(),
                             targetValue
                             targetValue
                     );
                     );
 
 
             if (companyHit != null) {
             if (companyHit != null) {
-                return CompanyVoiceRoboticCallBlacklistCheckVO.reject(
+                CompanyVoiceRoboticCallBlacklistCheckVO rejectVo = CompanyVoiceRoboticCallBlacklistCheckVO.reject(
                         companyHit.getId(),
                         companyHit.getId(),
                         companyHit.getBusinessType(),
                         companyHit.getBusinessType(),
                         companyHit.getTargetType(),
                         companyHit.getTargetType(),
                         companyHit.getTargetValue(),
                         companyHit.getTargetValue(),
-                        buildReason(companyHit, "公司级黑名单")
+                        buildReason(companyHit, "租户级黑名单")
                 );
                 );
+                interceptLogService.saveOnBlacklistReject(param, rejectVo);
+                return rejectVo;
             }
             }
         }
         }
 
 
-//        CompanyVoiceRoboticCallBlacklist hit = companyVoiceRoboticCallBlacklistMapper.selectActiveByTarget(
-//                param.getCompanyId(),
-//                param.getBusinessType(),
-//                targetValue
-//        );
-
-//        if (hit == null) {
-//            return CompanyVoiceRoboticCallBlacklistCheckVO.pass(param.getBusinessType());
-//        }
-//
-//        return CompanyVoiceRoboticCallBlacklistCheckVO.reject(
-//                hit.getId(),
-//                hit.getBusinessType(),
-//                hit.getTargetType(),
-//                hit.getTargetValue(),
-//                buildReason(hit)
-//        );
-        // 2. 查全局黑名单
-        CompanyVoiceRoboticCallBlacklist globalHit = companyVoiceRoboticCallBlacklistMapper.selectGlobalActiveByTarget(param.getBusinessType(),targetValue);
+        // 2. 查平台级黑名单(businessType=11,company_id 为空)
+        CompanyVoiceRoboticCallBlacklist globalHit = companyVoiceRoboticCallBlacklistMapper.selectGlobalActiveByTarget(
+                VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode(),
+                targetValue
+        );
 
 
         if (globalHit != null) {
         if (globalHit != null) {
-            return CompanyVoiceRoboticCallBlacklistCheckVO.reject(
+            CompanyVoiceRoboticCallBlacklistCheckVO rejectVo = CompanyVoiceRoboticCallBlacklistCheckVO.reject(
                     globalHit.getId(),
                     globalHit.getId(),
                     globalHit.getBusinessType(),
                     globalHit.getBusinessType(),
                     globalHit.getTargetType(),
                     globalHit.getTargetType(),
                     globalHit.getTargetValue(),
                     globalHit.getTargetValue(),
-                    buildReason(globalHit, "全局黑名单")
+                    buildReason(globalHit, "平台级黑名单")
+            );
+            interceptLogService.saveOnBlacklistReject(param, rejectVo);
+            return rejectVo;
+        }
+        return CompanyVoiceRoboticCallBlacklistCheckVO.pass(
+                VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode()
+        );
+
+    }
+
+    /**
+     * 按数据源校验黑名单:租户库先查 12/13,未命中再查主库 11;未传租户仅查主库 11。
+     * 命中时在当前数据源写入拦截明细(平台命中写主库,租户/线路命中写租户库)。
+     */
+    @Override
+    public CompanyVoiceRoboticCallBlacklistCheckVO checkBlacklistWithDataSource(CompanyVoiceRoboticCallBlacklistCheckParam param) {
+        if (param == null || !StringUtils.hasText(param.getTargetValue())) {
+            return CompanyVoiceRoboticCallBlacklistCheckVO.paramNull("校验参数不能为空");
+        }
+
+        String previousDs = DynamicDataSourceContextHolder.getDataSourceType();
+        try {
+            Integer targetType = param.getTargetType() != null ? param.getTargetType() : 1;
+            String targetValue = normalizeTargetValue(targetType, param.getTargetValue());
+            targetValue = encryptPhoneIfNeeded(targetType, targetValue);
+
+            Long tenantId = param.getTenantId();
+            if (tenantId != null) {
+                tenantDataSourceManager.ensureSwitchByTenantId(tenantId);
+
+                if (param.getCompanyId() != null) {
+                    CompanyVoiceRoboticCallBlacklist tenantHit = companyVoiceRoboticCallBlacklistMapper.selectActiveByTarget(
+                            param.getCompanyId(),
+                            VoiceRoboticCallBlacklistBusinessTypeEnum.TENANT.getCode(),
+                            targetValue
+                    );
+                    if (tenantHit != null) {
+                        return rejectAndSaveInterceptLog(param, tenantHit, "租户级黑名单");
+                    }
+
+                    CompanyVoiceRoboticCallBlacklist lineHit = companyVoiceRoboticCallBlacklistMapper.selectActiveByTarget(
+                            param.getCompanyId(),
+                            VoiceRoboticCallBlacklistBusinessTypeEnum.LINE.getCode(),
+                            targetValue
+                    );
+                    if (lineHit != null) {
+                        return rejectAndSaveInterceptLog(param, lineHit, "线路级黑名单");
+                    }
+                }
+
+                DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+            } else {
+                DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+            }
+
+            CompanyVoiceRoboticCallBlacklist platformHit = companyVoiceRoboticCallBlacklistMapper.selectGlobalActiveByTarget(
+                    VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode(),
+                    targetValue
             );
             );
+            if (platformHit != null) {
+                return rejectAndSaveInterceptLog(param, platformHit, "平台级黑名单");
+            }
+
+            return CompanyVoiceRoboticCallBlacklistCheckVO.pass(
+                    VoiceRoboticCallBlacklistBusinessTypeEnum.PLATFORM.getCode()
+            );
+        } finally {
+            restoreDataSource(previousDs);
         }
         }
-        return CompanyVoiceRoboticCallBlacklistCheckVO.pass(param.getBusinessType());
+    }
 
 
+    private CompanyVoiceRoboticCallBlacklistCheckVO rejectAndSaveInterceptLog(
+            CompanyVoiceRoboticCallBlacklistCheckParam param,
+            CompanyVoiceRoboticCallBlacklist hit,
+            String scopeDesc) {
+        CompanyVoiceRoboticCallBlacklistCheckVO rejectVo = CompanyVoiceRoboticCallBlacklistCheckVO.reject(
+                hit.getId(),
+                hit.getBusinessType(),
+                hit.getTargetType(),
+                hit.getTargetValue(),
+                buildReason(hit, scopeDesc)
+        );
+        interceptLogService.saveOnBlacklistReject(param, rejectVo);
+        return rejectVo;
+    }
+
+    private void restoreDataSource(String previousDs) {
+        if (StringUtils.hasText(previousDs)) {
+            DynamicDataSourceContextHolder.setDataSourceType(previousDs);
+        } else {
+            DynamicDataSourceContextHolder.clearDataSourceType();
+        }
+    }
+
+    @Override
+    public String getDecryptPhoneById(Long blacklistId) {
+        CompanyVoiceRoboticCallBlacklist db = companyVoiceRoboticCallBlacklistMapper.selectCompanyVoiceBlacklistById(blacklistId);
+        if (db == null || !StringUtils.hasText(db.getTargetValue())) {
+            return null;
+        }
+        if (Integer.valueOf(1).equals(db.getTargetType())) {
+            return PhoneUtil.decryptAutoPhone(db.getTargetValue());
+        }
+        return db.getTargetValue();
+    }
+
+    private void prepareTargetValue(CompanyVoiceRoboticCallBlacklist entity) {
+        if (entity == null || !StringUtils.hasText(entity.getTargetValue())) {
+            return;
+        }
+        String value = normalizeTargetValue(entity.getTargetType(), entity.getTargetValue());
+        value = encryptPhoneIfNeeded(entity.getTargetType(), value);
+        entity.setTargetValue(value);
+    }
+
+    private void prepareQueryTargetValue(CompanyVoiceRoboticCallBlacklist entity) {
+        if (entity == null || !StringUtils.hasText(entity.getTargetValue())) {
+            return;
+        }
+        Integer targetType = entity.getTargetType() != null ? entity.getTargetType() : 1;
+        String value = normalizeTargetValue(targetType, entity.getTargetValue());
+        value = encryptPhoneIfNeeded(targetType, value);
+        entity.setTargetValue(value);
+    }
+
+    private String encryptPhoneIfNeeded(Integer targetType, String value) {
+        if (!StringUtils.hasText(value)) {
+            return value;
+        }
+        Integer phoneType = targetType != null ? targetType : 1;
+        if (Integer.valueOf(1).equals(phoneType) && value.length() <= 11) {
+            return PhoneUtil.encryptPhone(value);
+        }
+        return value;
     }
     }
 
 
     /**
     /**

+ 34 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyVoiceRoboticCallBlacklistExportVO.java

@@ -0,0 +1,34 @@
+package com.fs.company.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 外呼黑名单导出
+ */
+@Data
+public class CompanyVoiceRoboticCallBlacklistExportVO {
+
+    @Excel(name = "ID")
+    private Long id;
+
+    @Excel(name = "黑名单级别", readConverterExp = "11=平台封禁,12=租户级,13=线路级")
+    private String businessType;
+
+    @Excel(name = "手机号")
+    private String targetValue;
+
+    @Excel(name = "状态", readConverterExp = "0=禁用,1=启用")
+    private Integer status;
+
+    @Excel(name = "备注")
+    private String remark;
+
+    @Excel(name = "创建人")
+    private String createBy;
+
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+}

+ 28 - 0
fs-service/src/main/resources/db/tenant-initTable-migration.sql

@@ -382,6 +382,34 @@ CREATE TABLE IF NOT EXISTS `company_voice_robotic_call_blacklist` (
   KEY `idx_company_id` (`company_id`)
   KEY `idx_company_id` (`company_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
 
 
+-- Table: company_voice_robotic_call_blacklist_intercept_log
+CREATE TABLE IF NOT EXISTS `company_voice_robotic_call_blacklist_intercept_log` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `company_id` bigint DEFAULT NULL COMMENT '租户/公司ID',
+  `scene_code` varchar(32) NOT NULL COMMENT '业务场景:CALL外呼 SMS短信 ADD_WX加微',
+  `blacklist_id` bigint DEFAULT NULL COMMENT '命中的黑名单记录ID',
+  `target_type` tinyint NOT NULL COMMENT '对象类型:1手机号 2客户ID 3企微客户ID',
+  `target_value` varchar(128) NOT NULL COMMENT '拦截时对象值(手机号加密)',
+  `blacklist_reason` varchar(255) DEFAULT NULL COMMENT '黑名单拉黑原因快照',
+  `intercept_reason` varchar(500) NOT NULL COMMENT '拦截说明',
+  `customer_id` bigint DEFAULT NULL COMMENT 'CRM客户ID',
+  `callee_id` bigint DEFAULT NULL COMMENT '外呼被叫人ID',
+  `robotic_id` bigint DEFAULT NULL COMMENT '外呼任务ID',
+  `company_user_id` bigint DEFAULT NULL COMMENT '操作人ID',
+  `biz_id` varchar(64) DEFAULT NULL COMMENT '业务ID',
+  `biz_trace_id` varchar(64) DEFAULT NULL COMMENT '链路追踪ID',
+  `request_ip` varchar(64) DEFAULT NULL COMMENT '请求IP',
+  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '拦截时间',
+  PRIMARY KEY (`id`),
+  KEY `idx_company_time` (`company_id`, `create_time`),
+  KEY `idx_blacklist_id` (`blacklist_id`),
+  KEY `idx_scene_time` (`scene_code`, `create_time`),
+  KEY `idx_target_value` (`target_type`, `target_value`(32)),
+  KEY `idx_customer_id` (`customer_id`),
+  KEY `idx_robotic_callee` (`robotic_id`, `callee_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='外呼黑名单拦截明细';
+
 -- Table: crm_customer_analyze
 -- Table: crm_customer_analyze
 CREATE TABLE IF NOT EXISTS `crm_customer_analyze` (
 CREATE TABLE IF NOT EXISTS `crm_customer_analyze` (
   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',

+ 84 - 0
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallBlacklistInterceptLogMapper.xml

@@ -0,0 +1,84 @@
+<?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.CompanyVoiceRoboticCallBlacklistInterceptLogMapper">
+
+    <resultMap type="CompanyVoiceRoboticCallBlacklistInterceptLog" id="InterceptLogResult">
+        <id property="id" column="id"/>
+        <result property="companyId" column="company_id"/>
+        <result property="sceneCode" column="scene_code"/>
+        <result property="blacklistId" column="blacklist_id"/>
+        <result property="targetType" column="target_type"/>
+        <result property="targetValue" column="target_value"/>
+        <result property="blacklistReason" column="blacklist_reason"/>
+        <result property="interceptReason" column="intercept_reason"/>
+        <result property="customerId" column="customer_id"/>
+        <result property="calleeId" column="callee_id"/>
+        <result property="roboticId" column="robotic_id"/>
+        <result property="companyUserId" column="company_user_id"/>
+        <result property="bizId" column="biz_id"/>
+        <result property="bizTraceId" column="biz_trace_id"/>
+        <result property="requestIp" column="request_ip"/>
+        <result property="remark" column="remark"/>
+        <result property="createTime" column="create_time"/>
+    </resultMap>
+
+    <sql id="selectVo">
+        select id, company_id, scene_code, blacklist_id, target_type, target_value,
+               blacklist_reason, intercept_reason, customer_id, callee_id, robotic_id,
+               company_user_id, biz_id, biz_trace_id, request_ip, remark, create_time
+        from company_voice_robotic_call_blacklist_intercept_log
+    </sql>
+
+    <select id="selectById" resultMap="InterceptLogResult">
+        <include refid="selectVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectList" resultMap="InterceptLogResult">
+        <include refid="selectVo"/>
+        <where>
+            <if test="companyId != null">
+                and company_id = #{companyId}
+            </if>
+            <if test="sceneCode != null and sceneCode != ''">
+                and scene_code = #{sceneCode}
+            </if>
+            <if test="targetType != null">
+                and target_type = #{targetType}
+            </if>
+            <if test="targetValue != null and targetValue != ''">
+                and target_value like concat('%', #{targetValue}, '%')
+            </if>
+            <if test="blacklistId != null">
+                and blacklist_id = #{blacklistId}
+            </if>
+            <if test="customerId != null">
+                and customer_id = #{customerId}
+            </if>
+            <if test="roboticId != null">
+                and robotic_id = #{roboticId}
+            </if>
+            <if test="beginTime != null">
+                and create_time &gt;= #{beginTime}
+            </if>
+            <if test="endTime != null">
+                and create_time &lt;= #{endTime}
+            </if>
+        </where>
+        order by id desc
+    </select>
+
+    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
+        insert into company_voice_robotic_call_blacklist_intercept_log (
+            company_id, scene_code, blacklist_id, target_type, target_value,
+            blacklist_reason, intercept_reason, customer_id, callee_id, robotic_id,
+            company_user_id, biz_id, biz_trace_id, request_ip, remark, create_time
+        ) values (
+            #{companyId}, #{sceneCode}, #{blacklistId}, #{targetType}, #{targetValue},
+            #{blacklistReason}, #{interceptReason}, #{customerId}, #{calleeId}, #{roboticId},
+            #{companyUserId}, #{bizId}, #{bizTraceId}, #{requestIp}, #{remark}, now()
+        )
+    </insert>
+</mapper>

+ 12 - 6
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallBlacklistMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.company.mapper.CompanyVoiceRoboticCallBlacklistMapper">
 <mapper namespace="com.fs.company.mapper.CompanyVoiceRoboticCallBlacklistMapper">
-    
+
     <resultMap type="CompanyVoiceRoboticCallBlacklist" id="CompanyVoiceBlacklistResult">
     <resultMap type="CompanyVoiceRoboticCallBlacklist" id="CompanyVoiceBlacklistResult">
         <id property="id" column="id"/>
         <id property="id" column="id"/>
         <result property="businessType" column="business_type"/>
         <result property="businessType" column="business_type"/>
@@ -47,6 +47,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="businessType != null and businessType != ''">
             <if test="businessType != null and businessType != ''">
                 and business_type = #{businessType}
                 and business_type = #{businessType}
             </if>
             </if>
+            <if test="businessTypeList != null and businessTypeList.size() > 0">
+                and business_type in
+                <foreach collection="businessTypeList" item="bt" open="(" separator="," close=")">
+                    #{bt}
+                </foreach>
+            </if>
             <if test="targetType != null">
             <if test="targetType != null">
                 and target_type = #{targetType}
                 and target_type = #{targetType}
             </if>
             </if>
@@ -71,7 +77,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
         </where>
         order by id desc
         order by id desc
     </select>
     </select>
-    
+
     <select id="selectCompanyVoiceBlacklistById" resultMap="CompanyVoiceBlacklistResult">
     <select id="selectCompanyVoiceBlacklistById" resultMap="CompanyVoiceBlacklistResult">
         <include refid="selectCompanyVoiceBlacklistVo"/>
         <include refid="selectCompanyVoiceBlacklistVo"/>
         where id = #{blacklistId}
         where id = #{blacklistId}
@@ -119,6 +125,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="status != null">status = #{status},</if>
             <if test="status != null">status = #{status},</if>
             <if test="remark != null">remark = #{remark},</if>
             <if test="remark != null">remark = #{remark},</if>
             <if test="reason != null">reason = #{reason},</if>
             <if test="reason != null">reason = #{reason},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
         </trim>
         </trim>
         where id = #{id}
         where id = #{id}
@@ -127,6 +134,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update company_voice_robotic_call_blacklist
         update company_voice_robotic_call_blacklist
         set
         set
             status = #{status},
             status = #{status},
+            <if test="updateBy != null">update_by = #{updateBy},</if>
             update_time = now()
             update_time = now()
         where id = #{id}
         where id = #{id}
           and deleted = 0
           and deleted = 0
@@ -193,13 +201,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where deleted = 0
         where deleted = 0
         and status = 1
         and status = 1
         and company_id is null
         and company_id is null
-<!--        <if test="targetType != null and targetType != ''">-->
-<!--        and target_type = #{targetType}-->
-<!--        </if>-->
+        and target_value = #{targetValue}
         <if test="businessType != null and businessType != ''">
         <if test="businessType != null and businessType != ''">
             and business_type = #{businessType}
             and business_type = #{businessType}
         </if>
         </if>
         limit 1
         limit 1
     </select>
     </select>
 
 
-</mapper>
+</mapper>

File diff suppressed because it is too large
+ 557 - 537
sql/adminUI_views_menu_structure.md


Some files were not shown because too many files changed in this diff