package com.smartor.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.service.IConfigService; import com.ruoyi.common.dx.MessageSend; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.*; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.mapper.SysConfigMapper; import com.ruoyi.system.service.ISysConfigService; import com.smartor.common.FtpService; import com.smartor.common.MtSubmitSmUtil; import com.smartor.common.ScheduleSubtaskBuilder; import com.smartor.config.PhoneUtils; import com.smartor.domain.DTO.ServiceSubtaskDetailDTO; import com.smartor.domain.*; import com.smartor.domain.VO.HeLibraryCountVO; import com.smartor.domain.VO.ServiceSubtaskCotinueCountVO; import com.smartor.domain.VO.TransferDeptVO; import com.smartor.domain.entity.ServiceSubtaskEntity; import com.smartor.mapper.*; import com.smartor.service.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestBody; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * 单一任务(随访)Service业务层处理 * * @author ruoyi * @date 2024-02-02 */ @Slf4j @Service public class ServicPhoneServiceImpl implements IServicePhoneService { @Value("${shurl}") private String shurl; @Value("${shversion}") private String shversion; /** * 新增外呼实例配置 * * @param request 外呼实例配置请求对象 * @return 外呼实例配置结果 * @throws BaseException 接口调用失败或数据解析异常时抛出 */ @Override public OutboundInstanceResVO addOutboundInstance(OutboundConfigAddReqVO request) { // 1. 参数校验 validateRequest(request); // 2. 发送 HTTP 请求 String responseJson = sendHttpPostRequest(shurl + shversion + "/config/addOutboundInstance", request); // 3. 解析响应并返回结果 return parseResponse(responseJson); } /** * 参数校验 */ private void validateRequest(OutboundConfigAddReqVO request) { if (request == null) { throw new BaseException("请求参数不能为空"); } // 必传参数校验 assertNotBlank(request.getName(), "项目名称不能为空"); assertNotBlank(request.getAgent(), "坐席号不能为空"); assertNotBlank(request.getTenantId(), "资源组号不能为空"); assertNotBlank(request.getCallType(), "呼叫类型不能为空"); assertNotBlank(request.getActionID(), "actionID 不能为空"); // 条件必填校验:isVgc=0 时,queueId 和 ratio 为必填 if ("0".equals(request.getIsVgc())) { assertNotBlank(request.getQueueId(), "isVgc=0 时,执行坐席组 ID 不能为空"); assertNotBlank(request.getRatio(), "isVgc=0 时,外呼速率不能为空"); } // 条件必填校验:isVgc=1 时,ivrId 为必填 else if ("1".equals(request.getIsVgc())) { assertNotBlank(request.getIvrId(), "isVgc=1 时,IVR 流程 ID 不能为空"); } } /** * 发送 POST HTTP 请求 * * @param url API 地址 * @param request 请求对象 * @return 服务器响应 JSON 字符串 */ private String sendHttpPostRequest(String url, Object request) { log.info("开始调用外呼实例配置接口,URL: {}", url); Map headers = buildHeaders(); String requestBody = new Gson().toJson(request); String response = HttpUtils.sendPostByHeader(url, requestBody, headers); if (StringUtils.isEmpty(response)) { log.error("外呼实例配置接口调用失败,未返回有效数据,URL: {}", url); throw new BaseException("接口调用失败,未返回有效数据"); } log.info("外呼实例配置接口调用成功,响应:{}", response); return response; } /** * 构建 HTTP 请求头 */ private Map buildHeaders() { Map headers = new HashMap<>(1); headers.put("Content-Type", "application/json; charset=UTF-8"); return headers; } /** * 解析 HTTP 响应并转换为 OutboundInstanceResVO * * @param responseJson 响应 JSON 字符串 * @return 外呼实例配置响应对象 * @throws BaseException 当响应码不为 200 或响应数据解析失败时抛出 */ private OutboundInstanceResVO parseResponse(String responseJson) { try { JSONObject response = JSON.parseObject(responseJson); // 检查响应码 Integer code = response.getInteger("code"); if (!"200".equals(code.toString())) { String message = response.getString("message"); log.error("外呼实例配置接口返回失败,code: {}, message: {}", code, message); throw new BaseException("新增外呼实例配置失败:" + message); } // 解析 data 字段 JSONObject data = response.getJSONObject("data"); if (data == null || data.isEmpty()) { throw new BaseException("接口返回数据为空"); } return data.toJavaObject(OutboundInstanceResVO.class); } catch (BaseException e) { throw e; } catch (Exception e) { log.error("解析外呼实例配置响应异常,response: {}", responseJson, e); throw new BaseException("解析响应数据异常:" + e.getMessage()); } } /** * 断言字符串非空工具方法 * * @param value 待检查的值 * @param message 断言失败时的错误消息 * @throws BaseException 当值为空时抛出 */ private void assertNotBlank(String value, String message) { if (StringUtils.isBlank(value)) { throw new BaseException(message); } } }