package com.ruoyi.aicall.controller; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ruoyi.aicall.domain.CcCallPhone; import com.ruoyi.aicall.domain.CcCallTask; import com.ruoyi.aicall.domain.CcLlmAgentAccount; import com.ruoyi.aicall.domain.CcTtsAliyun; import com.ruoyi.aicall.model.*; import com.ruoyi.aicall.service.ICcCallPhoneService; import com.ruoyi.aicall.service.ICcCallTaskService; import com.ruoyi.aicall.service.ICcLlmAgentAccountService; import com.ruoyi.aicall.service.ICcTtsAliyunService; import com.ruoyi.aicall.utils.ClientIpCheck; import com.ruoyi.aicall.utils.DESUtil; import com.ruoyi.cc.domain.*; import com.ruoyi.cc.service.*; import com.ruoyi.cc.utils.DateValidatorUtils; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.uuid.UuidGenerator; import com.ruoyi.framework.shiro.service.SysPasswordService; import com.ruoyi.framework.shiro.util.AuthorizationUtils; import com.ruoyi.system.service.ISysUserService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.stream.Collectors; @Controller @Slf4j @RequestMapping("/aicall/api") public class ApiController extends BaseController { @Autowired private ICcCallTaskService callTaskService; @Autowired private ICcCallPhoneService ccCallPhoneService; @Autowired private ICcInboundCdrService inboundCdrService; @Autowired private ICcOutboundCdrService outboundCdrService; @Autowired private ICcParamsService paramsService; @Autowired private ICcGatewaysService ccGatewaysService; @Autowired private ICcLlmAgentAccountService ccLlmAgentAccountService; @Autowired private ICcBizGroupService ccBizGroupService; @Autowired private ICcCallTaskService ccCallTaskService; @Autowired private ICcTtsAliyunService ccTtsAliyunService; @Autowired private ICcExtNumService ccExtNumService; @Autowired private ICcParamsService ccParamsService; @Autowired private ISysUserService userService; @Autowired private SysPasswordService passwordService; @Autowired private ICcCustCallRecordService ccCustCallRecordService; @Autowired private ICcCustInfoService ccCustInfoService; @Autowired private ISysDivisionDataService sysDivisionDataService; @Autowired private ICcOutboundCdrService ccOutboundCdrService; /** * 获取外呼网关列表接口 * @param req * @return */ @GetMapping("/gateway/list") @ResponseBody public AjaxResult getGatewayList(HttpServletRequest req, @RequestParam(value = "purposes", required = false) String purposes){ // 校验客户端ip是否在白名单内 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", ""); } // 获取外呼网关列表 Map params = new HashMap<>(); if (StringUtils.isBlank(purposes)) { params.put("purposes", Arrays.asList(1,2,3)); } else { params.put("purposes", Arrays.asList(purposes.split(","))); } List list = ccGatewaysService.selectCcGatewaysList(new CcGateways().setParams(params)); List result = new ArrayList<>(); for (CcGateways data: list) { ApiGatewaysModel model = new ApiGatewaysModel(); BeanUtils.copyProperties(data, model); result.add(model); } return AjaxResult.success(result); } /** * 获取大模型列表接口 * @param req * @return */ @GetMapping("/llmacount/list") @ResponseBody public AjaxResult getLlmAcountList(HttpServletRequest req){ // 校验客户端ip是否在白名单内 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", ""); } // 获取大模型列表 List list = ccLlmAgentAccountService.selectCcLlmAgentAccountList(new CcLlmAgentAccount()); return AjaxResult.success(list); } /** * 获取音色列表 * @return */ @GetMapping("/voicecode/list") @ResponseBody public AjaxResult getVoiceCodeList(HttpServletRequest req) { // 校验客户端ip是否在白名单内 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", ""); } // 获取音色列表 List list = ccTtsAliyunService.selectCcTtsAliyunList(new CcTtsAliyun()); JSONArray result = new JSONArray(); for (CcTtsAliyun ttsAliyun: list) { JSONObject obj = new JSONObject(); obj.put("voiceName", ttsAliyun.getVoiceName()); obj.put("voiceCode", ttsAliyun.getVoiceCode()); obj.put("voiceSource", ttsAliyun.getVoiceSource()); result.add(obj); } return AjaxResult.success(result); } /** * 获取技能组列表 * @param req * @return */ @GetMapping("/busigroup/list") @ResponseBody public AjaxResult getBusigroupList(HttpServletRequest req){ // // 校验客户端ip是否在白名单内 // if (!ClientIpCheck.checkIp(req)) { // return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", ""); // } // 获取技能组列表 List list = ccBizGroupService.selectCcBizGroupList(new CcBizGroup()); return AjaxResult.success(list); } /** * 通话记录查询接口(支持按时间、坐席、号码、呼入/呼出类型筛选) * @param req * @param queryParams * @return */ @PostMapping("/calltask/list") @ResponseBody public TableDataInfo getCallTaskList(HttpServletRequest req, @RequestBody ApiCallTaskQueryParams queryParams) { TableDataInfo tableDataInfo; // 校验请求方ip是否合法 if (!ClientIpCheck.checkIp(req)) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value()); tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!"); return tableDataInfo; } // 处理分页 if (null == queryParams.getPageNum()) { queryParams.setPageNum(1); } if (null == queryParams.getPageSize()) { queryParams.setPageSize(20); } // 校验参数 if (StringUtils.isNotEmpty(queryParams.getCreateTimeStart()) && !DateValidatorUtils.isYmdHms(queryParams.getCreateTimeStart())) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("createTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!"); return tableDataInfo; } if (StringUtils.isNotEmpty(queryParams.getCreateTimeEnd()) && !DateValidatorUtils.isYmdHms(queryParams.getCreateTimeEnd())) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.ERROR.value()); tableDataInfo.setMsg("createTimeEnd格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!"); return tableDataInfo; } Map params = new HashMap<>(); params.put("createTimeStart", queryParams.getCreateTimeStart()); params.put("createTimeEnd", queryParams.getCreateTimeEnd()); // 分页请求数据 startPage(queryParams.getPageNum(), queryParams.getPageSize()); CcCallTask ccCallTask = new CcCallTask(); ccCallTask.setBatchId(queryParams.getBatchId()); ccCallTask.setBatchName(queryParams.getBatchName()); ccCallTask.setParams(params); List list = ccCallTaskService.selectCcCallTaskList(ccCallTask); tableDataInfo = getDataTable(list); List records = (List) tableDataInfo.getRows(); for (CcCallTask data: records){ CallTaskStatModel statModel = ccCallPhoneService.statByBatchId(data.getBatchId()); data.setPhoneCount(statModel.getPhoneCount()); data.setCallCount(statModel.getCallCount()); data.setNoCallCount(statModel.getPhoneCount() - statModel.getCallCount()); data.setConnectCount(statModel.getConnectCount()); data.setNoConnectCount(statModel.getCallCount() - statModel.getConnectCount()); if (data.getCallCount() > 0) { data.setRealConnectRate(data.getConnectCount()*1.0/data.getCallCount()); } else { data.setRealConnectRate(0.0); } } tableDataInfo.setRows(records); return tableDataInfo; } /** * 根据uuid查询 * @param req * @param uuid * @param callType * @return */ @GetMapping("/record/uuid") @ResponseBody public AjaxResult getRecordByUuid(HttpServletRequest req, @RequestParam String uuid, @RequestParam String callType) { // 校验客户端ip是否在白名单内 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", ""); } if (StringUtils.isBlank(callType)) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "callType不能为空!", ""); } // 01:呼入, 02:AI外呼, 03:人工外呼 ApiCallRecordQueryParams queryParams = new ApiCallRecordQueryParams().setUuid(uuid).setCallType(callType); TableDataInfo tableDataInfo = new TableDataInfo(); if ("01".equals(callType)) { tableDataInfo = getInboundRecords(queryParams); } else if ("02".equals(callType)) { tableDataInfo = getAiCallRecords(queryParams); } else if ("03".equals(callType)) { tableDataInfo = getOutboundRecords(queryParams); } if (null != tableDataInfo.getRows() && tableDataInfo.getRows().size() > 0) { return AjaxResult.success(tableDataInfo.getRows().get(0)); } else { return AjaxResult.success(); } } /** * 通话记录查询接口(支持按时间、坐席、号码、呼入/呼出类型筛选) * @param req * @param queryParams * @return */ @PostMapping("/records/list") @ResponseBody public TableDataInfo getRecordsList(HttpServletRequest req, @RequestBody ApiCallRecordQueryParams queryParams) { TableDataInfo tableDataInfo; // 校验请求方ip是否合法 if (!ClientIpCheck.checkIp(req)) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value()); tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!"); return tableDataInfo; } // 分页参数处理 if (null == queryParams.getPageNum() && null == queryParams.getPageSize()) { queryParams.setPageNum(1); queryParams.setPageSize(200000); } if (null == queryParams.getPageNum()) { queryParams.setPageNum(1); } if (null == queryParams.getPageSize()) { queryParams.setPageSize(20); } // 类型(01:呼入, 02:AI外呼, 03:人工外呼) String callType = queryParams.getCallType(); if (StringUtils.isBlank(callType)) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("callType不能为空!"); return tableDataInfo; } // 校验参数 if (StringUtils.isNotEmpty(queryParams.getCalloutTimeStart()) && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeStart())) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!"); return tableDataInfo; } if (StringUtils.isNotEmpty(queryParams.getCalloutTimeEnd()) && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeEnd())) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!"); return tableDataInfo; } // 01:呼入, 02:AI外呼, 03:人工外呼 if ("01".equals(callType)) { return getInboundRecords(queryParams); } else if ("02".equals(callType)) { return getAiCallRecords(queryParams); } else if ("03".equals(callType)) { return getOutboundRecords(queryParams); } else { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("callType参数不合法,呼入请输入01,AI外呼请输入02,手工外呼请输入03!"); return tableDataInfo; } } /** * 创建外呼任务接口(含任务名称、优先级、并发数、TTS/音频模板等参数)接口 * @param req * @param apiCallTaskModel * @return */ @PostMapping("/ai/createTask") @ResponseBody public AjaxResult createCallTask(HttpServletRequest req, @RequestBody ApiCallTaskModel apiCallTaskModel) { // 校验ip白名单 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", ""); } CcCallTask ccCallTask = new CcCallTask(); // 校验参数 // 任务名称不能为空 if (StringUtils.isBlank(apiCallTaskModel.getBatchName())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "batchName不能为空!", ""); } // threadNum不能为空 if (null == apiCallTaskModel.getThreadNum()) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "threadNum不能为空!", ""); } // 校验groupId是否存在 if (!checkGroupId(apiCallTaskModel.getGroupId())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "groupId参数不合法,请输入正确的groupId!", ""); } // 校验taskType是否合法 if (null == apiCallTaskModel.getTaskType()) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "taskType不能为空!", ""); } else { if (apiCallTaskModel.getTaskType() != 1 && apiCallTaskModel.getTaskType() != 2) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "taskType参数不合法,AI外呼请输入1,通知提醒请输入2!", ""); } } // 校验gatewayId是否合法 if (!checkGatewayId(apiCallTaskModel.getGatewayId())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "gatewayId参数不合法,请输入正确的gatewayId!", ""); } // AI外呼需要校验llmAccountId是否合法 if (apiCallTaskModel.getTaskType() == 2) { if (!checkLlmAccountId(apiCallTaskModel.getLlmAccountId())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "llmAccountId参数不合法,请输入正确的llmAccountId!", ""); } } // playTimes 如果为空,默认值给1 if (apiCallTaskModel.getTaskType() == 3) { if (null == apiCallTaskModel.getPlayTimes()) { apiCallTaskModel.setPlayTimes(1); } } // 校验voiceCode、voiceSource是否合法 if (!checkVoiceCode(apiCallTaskModel.getVoiceCode(), apiCallTaskModel.getVoiceSource())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "voiceCode或voiceSource参数不合法,请输入正确的voiceCode和voiceSource!", ""); } // 创建任务 BeanUtils.copyProperties(apiCallTaskModel, ccCallTask, "batchId"); if (null != ccCallTask.getConntectRate() && ccCallTask.getConntectRate() > 0) { ccCallTask.setRate(ccCallTask.getConntectRate()/100.0); } ccCallTask.setCreatetime(System.currentTimeMillis()); ccCallTaskService.insertCcCallTask(ccCallTask); apiCallTaskModel.setBatchId(ccCallTask.getBatchId()); return AjaxResult.success("success", apiCallTaskModel); } /** * 启动任务接口 * @param req * @param batchId * @return */ @GetMapping("/ai/startTask") @ResponseBody public AjaxResult startTask(HttpServletRequest req, @RequestParam("batchId") Long batchId) { // 校验ip白名单 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", ""); } // 启动任务 CcCallTask ccCallTask = ccCallTaskService.selectCcCallTaskByBatchId(batchId); if (null == ccCallTask) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", ""); } ccCallTask.setIfcall(1); ccCallTask.setExecuting(0L); ccCallTask.setStopTime(0L); ccCallTaskService.updateCcCallTask(ccCallTask); return AjaxResult.success(); } /** * 停止任务接口 * @param req * @param batchId * @return */ @GetMapping( "/ai/stopTask") @ResponseBody public AjaxResult stopTask(HttpServletRequest req, @RequestParam("batchId") Long batchId) { // 校验ip白名单 if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", ""); } // 停止任务 CcCallTask ccCallTask = ccCallTaskService.selectCcCallTaskByBatchId(batchId); if (null == ccCallTask) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", ""); } ccCallTask.setIfcall(0); ccCallTask.setExecuting(0L); ccCallTask.setStopTime(System.currentTimeMillis()); ccCallTaskService.updateCcCallTask(ccCallTask); return AjaxResult.success(); } /** * 追加名单(不自动启动任务) * @param req * @param aiCallListModel * @return */ @PostMapping("/ai/addCallList") @ResponseBody public AjaxResult addAiCallList(HttpServletRequest req, @RequestBody AiCallListModel aiCallListModel) { if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", ""); } Long batchId = aiCallListModel.getBatchId(); if (null == batchId) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不能为空", ""); } if (CollectionUtils.isEmpty(aiCallListModel.getPhoneList())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数phoneList不能为空", ""); } // 获取任务 CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchId(batchId); if (null == ccCallTask) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", ""); } if (ccCallTask.getTaskType() != 1) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入AI外呼任务(taskType为1)的batchId", ""); } // 追加名单 Integer successCount = 0; List callPhoneList = new ArrayList<>(); for (String phoneNum: aiCallListModel.getPhoneList()) { if (StringUtils.isBlank(phoneNum)) { continue; } JSONObject bizJson = new JSONObject(); CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, bizJson); callPhoneList.add(callPhone); successCount ++; if (callPhoneList.size() >= 200) { ccCallPhoneService.batchInsertCcCallPhone(callPhoneList); callPhoneList = new ArrayList<>(); } } if (callPhoneList.size() > 0) { ccCallPhoneService.batchInsertCcCallPhone(callPhoneList); } log.info("成功追加" + successCount + "个名单"); return AjaxResult.success("成功追加" + successCount + "个名单"); } /** * 追加外呼名单(不自动启动任务) * @param req * @param commonCallListModel * @return */ @PostMapping("/common/addCallList") @ResponseBody public AjaxResult addCommonCallList(HttpServletRequest req, @RequestBody CommonCallListModel commonCallListModel) { if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", ""); } Long batchId = commonCallListModel.getBatchId(); if (null == batchId) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不能为空", ""); } if (CollectionUtils.isEmpty(commonCallListModel.getPhoneList())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数phoneList不能为空", ""); } // 获取任务 CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchId(batchId); if (null == ccCallTask) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", ""); } // 通知类的通知内容必填 if (ccCallTask.getTaskType() == 2) { for (CommonPhoneModel commonPhoneModel : commonCallListModel.getPhoneList()) { if (StringUtils.isBlank(commonPhoneModel.getNoticeContent())) { return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "号码" + commonPhoneModel.getPhoneNum() + "的noticeContent不能为空!", ""); } } } // 追加名单 Integer successCount = 0; List callPhoneList = new ArrayList<>(); for (CommonPhoneModel commonPhoneModel : commonCallListModel.getPhoneList()) { String phoneNum = commonPhoneModel.getPhoneNum(); if (StringUtils.isBlank(phoneNum)) { continue; } CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, commonPhoneModel.getBizJson()); callPhone.setTtsText(commonPhoneModel.getNoticeContent()); callPhoneList.add(callPhone); successCount ++; if (callPhoneList.size() >= 200) { ccCallPhoneService.batchInsertCcCallPhone(callPhoneList); callPhoneList = new ArrayList<>(); } } if (callPhoneList.size() > 0) { ccCallPhoneService.batchInsertCcCallPhone(callPhoneList); } log.info("成功追加" + successCount + "个名单"); return AjaxResult.success("成功追加" + successCount + "个名单",callPhoneList); } /** * yangqiang定制的追加通知的名单 * @param req * @param noticeCallModel * @return */ @PostMapping("/notice/call") @ResponseBody public AjaxResult callNotice(HttpServletRequest req, @RequestBody NoticeCallModel noticeCallModel) { if (!ClientIpCheck.checkIp(req)) { return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", ""); } // 获取任务 String batchName = paramsService.getParamValueByCode("testNoticeCallTaskName", "test"); String phoneNum = paramsService.getParamValueByCode("testNoticeCallPhoneNum", "13908113506"); CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchName(batchName, 2); // 追加名单 JSONObject bizJson = new JSONObject(); CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, bizJson); callPhone.setTtsText(noticeCallModel.getNoticeContent()); ccCallPhoneService.insertCcCallPhone(callPhone); // 启动任务 ccCallTask.setIfcall(1); ccCallTask.setExecuting(0L); ccCallTask.setStopTime(0L); callTaskService.updateCcCallTask(ccCallTask); return AjaxResult.success(); } private CcCallPhone buildCcCallPhone(CcCallTask ccCallTask, String phoneNum, JSONObject bizJson) { CcCallPhone callPhone = new CcCallPhone(); callPhone.setId(UuidGenerator.GetOneUuid()); callPhone.setGroupId("1"); callPhone.setBatchId(ccCallTask.getBatchId()); callPhone.setCreatetime(new Date().getTime()); callPhone.setCallstatus(0); callPhone.setCalloutTime(0L); callPhone.setCallcount(0); callPhone.setCallEndTime(0L); callPhone.setTimeLen(0L); callPhone.setValidTimeLen(0L); callPhone.setUuid(""); callPhone.setConnectedTime(0L); callPhone.setHangupCause(""); callPhone.setAnsweredTime(0L); callPhone.setDialogue(""); callPhone.setWavfile(""); callPhone.setRecordServerUrl(""); callPhone.setDialogueCount(0L); callPhone.setAcdOpnum(""); callPhone.setAcdQueueTime(0L); callPhone.setAcdWaitTime(0); callPhone.setTelephone(phoneNum); if (phoneNum.length() > 4) { bizJson.put("tailNum", phoneNum.substring(phoneNum.length()-4)); } else { bizJson.put("tailNum", phoneNum); } bizJson.put("phoneNum", phoneNum); callPhone.setCustName(bizJson.getString("custName")); if (null == callPhone.getCustName()) { callPhone.setCustName(""); } callPhone.setBizJson(JSONObject.toJSONString(bizJson)); if (ccCallTask.getTaskType() == 1) { callPhone.setIntent(""); } else { callPhone.setIntent("-"); } return callPhone; } private TableDataInfo getOutboundRecords(ApiCallRecordQueryParams queryParams) { Map params = new HashMap<>(); params.put("inboundTimeStart", queryParams.getCalloutTimeStart()); params.put("inboundTimeEnd", queryParams.getCalloutTimeEnd()); if (null != queryParams.getTimeLenStart()) { params.put("timeLenSecondStart", queryParams.getTimeLenStart().toString()); } if (null != queryParams.getTimeLenEnd()) { params.put("timeLenSecondEnd", queryParams.getTimeLenEnd().toString()); } startPage(queryParams.getPageNum(), queryParams.getPageSize()); CcOutboundCdr outboundCdr = new CcOutboundCdr(); outboundCdr.setUuid(queryParams.getUuid()); outboundCdr.setCaller(queryParams.getTelephone()); outboundCdr.setOpnum(queryParams.getExtnum()); outboundCdr.setParams(params); List list = outboundCdrService.selectCcOutboundCdrList(outboundCdr); TableDataInfo tableData = getDataTable(list); List records = (List) tableData.getRows(); List apiRecords = new ArrayList<>(); for (CcOutboundCdr data: records) { ApiCallRecordQueryResult apiData = new ApiCallRecordQueryResult(); if (data.getRecordFilename().startsWith("/")) { data.setRecordFilename(data.getRecordFilename().substring(1)); } data.setWavFileUrl("/recordings/files?filename=" + data.getRecordFilename()); apiData.setUuid(data.getUuid()); apiData.setTelephone(data.getCallee()); apiData.setCalloutTime(DateUtils.format(new Date(data.getStartTime()), "yyyy-MM-dd HH:mm:ss")); if (data.getAnsweredTime() > 0) { apiData.setAnsweredTime(DateUtils.format(new Date(data.getAnsweredTime()), "yyyy-MM-dd HH:mm:ss")); } else { apiData.setAnsweredTime(""); } if (data.getEndTime() > 0) { apiData.setCallEndTime(DateUtils.format(new Date(data.getEndTime()), "yyyy-MM-dd HH:mm:ss")); } else { apiData.setCallEndTime(""); } apiData.setHangupCause(data.getHangupCause()); if (data.getTimeLen() > 0) { apiData.setWavFileUrl(data.getWavFileUrl()); } else { apiData.setWavFileUrl(""); } apiData.setDialogue(new JSONArray()); apiData.setTimeLen(Long.valueOf(data.getTimeLen()/1000).intValue()); apiRecords.add(apiData); } tableData.setRows(records); TableDataInfo tableDataInfo = new TableDataInfo(); tableDataInfo.setCode(tableData.getCode()); tableDataInfo.setRows(apiRecords); tableDataInfo.setTotal(tableData.getTotal()); tableDataInfo.setMsg(tableData.getMsg()); return tableDataInfo; } private TableDataInfo getInboundRecords(ApiCallRecordQueryParams queryParams) { Map params = new HashMap<>(); params.put("inboundTimeStart", queryParams.getCalloutTimeStart()); params.put("inboundTimeEnd", queryParams.getCalloutTimeEnd()); if (null != queryParams.getTimeLenStart()) { params.put("timeLenSecondStart", queryParams.getTimeLenStart().toString()); } if (null != queryParams.getTimeLenEnd()) { params.put("timeLenSecondEnd", queryParams.getTimeLenEnd().toString()); } startPage(queryParams.getPageNum(), queryParams.getPageSize()); CcInboundCdr inboundCdr = new CcInboundCdr(); inboundCdr.setUuid(queryParams.getUuid()); inboundCdr.setCaller(queryParams.getTelephone()); inboundCdr.setOpnum(queryParams.getExtnum()); inboundCdr.setParams(params); List list = inboundCdrService.selectCcInboundCdrList(inboundCdr); TableDataInfo tableData = getDataTable(list); List records = (List) tableData.getRows(); List apiRecords = new ArrayList<>(); for (CcInboundCdr data: records) { ApiCallRecordQueryResult apiData = new ApiCallRecordQueryResult(); if (data.getWavFile().startsWith("/")) { data.setWavFile(data.getWavFile().substring(1)); } data.setWavFileUrl("/recordings/files?filename=" + data.getWavFile()); apiData.setUuid(data.getUuid()); apiData.setTelephone(data.getCaller()); apiData.setCalloutTime(DateUtils.format(new Date(data.getInboundTime()), "yyyy-MM-dd HH:mm:ss")); if (data.getAnsweredTime() > 0) { apiData.setAnsweredTime(DateUtils.format(new Date(data.getAnsweredTime()), "yyyy-MM-dd HH:mm:ss")); } else { apiData.setAnsweredTime(""); } if (data.getHangupTime() > 0) { apiData.setCallEndTime(DateUtils.format(new Date(data.getHangupTime()), "yyyy-MM-dd HH:mm:ss")); } else { apiData.setCallEndTime(""); } apiData.setHangupCause(""); if (data.getTimeLen() > 0) { apiData.setWavFileUrl(data.getWavFileUrl()); } else { apiData.setWavFileUrl(""); } if (StringUtils.isNotEmpty(data.getChatContent())) { JSONArray dialogue = new JSONArray(); JSONArray.parseArray(data.getChatContent()).forEach(obj -> { JSONObject json = (JSONObject) obj; if ("assistant".equals(json.getString("role")) || "user".equals(json.getString("role"))) { JSONObject content = new JSONObject(); content.put("role", json.getString("role")); content.put("content", json.getString("content")); dialogue.add(content); } }); apiData.setDialogue(dialogue); } else { apiData.setDialogue(new JSONArray()); } apiData.setTimeLen(Long.valueOf(data.getTimeLen()/1000).intValue()); apiData.setManualAnsweredTime(data.getManualAnsweredTime()); apiData.setManualAnsweredTimeLen(data.getManualAnsweredTimeLen()); apiRecords.add(apiData); } tableData.setRows(records); TableDataInfo tableDataInfo = new TableDataInfo(); tableDataInfo.setCode(tableData.getCode()); tableDataInfo.setRows(apiRecords); tableDataInfo.setTotal(tableData.getTotal()); tableDataInfo.setMsg(tableData.getMsg()); return tableDataInfo; } private TableDataInfo getAiCallRecords(ApiCallRecordQueryParams queryParams) { Map params = new HashMap<>(); params.put("calloutTimeStart", queryParams.getCalloutTimeStart()); params.put("calloutTimeEnd", queryParams.getCalloutTimeEnd()); if (null != queryParams.getTimeLenStart()) { params.put("timeLenSecondStart", queryParams.getTimeLenStart().toString()); } if (null != queryParams.getTimeLenEnd()) { params.put("timeLenSecondEnd", queryParams.getTimeLenEnd().toString()); } startPage(queryParams.getPageNum(), queryParams.getPageSize()); CcCallPhone ccCallPhone = new CcCallPhone(); if (null != queryParams.getBatchId() && queryParams.getBatchId() > 0) { ccCallPhone.setBatchId(queryParams.getBatchId()); } ccCallPhone.setUuid(queryParams.getUuid()); ccCallPhone.setTelephone(queryParams.getTelephone()); ccCallPhone.setAcdOpnum(queryParams.getExtnum()); ccCallPhone.setCallstatus(queryParams.getCallstatus()); ccCallPhone.setCallerNumber(queryParams.getCallerNumber()); ccCallPhone.setParams(params); List list = ccCallPhoneService.selectCcCallPhoneList(ccCallPhone); TableDataInfo tableData = getDataTable(list); List records = (List) tableData.getRows(); List apiRecords = new ArrayList<>(); for (CcCallPhone data: records) { ApiCallRecordQueryResult apiData = new ApiCallRecordQueryResult(); if (data.getWavfile().startsWith("/")) { data.setWavfile(data.getWavfile().substring(1)); } data.setWavfile("/recordings/files?filename=" + data.getWavfile()); apiData.setUuid(data.getUuid()); apiData.setTelephone(data.getTelephone()); apiData.setCalloutTime(DateUtils.format(new Date(data.getCalloutTime()), "yyyy-MM-dd HH:mm:ss")); if (data.getAnsweredTime() > 0) { apiData.setAnsweredTime(DateUtils.format(new Date(data.getAnsweredTime()), "yyyy-MM-dd HH:mm:ss")); } else { apiData.setAnsweredTime(""); } if (data.getCallEndTime() > 0) { apiData.setCallEndTime(DateUtils.format(new Date(data.getCallEndTime()), "yyyy-MM-dd HH:mm:ss")); } else { apiData.setCallEndTime(""); } apiData.setHangupCause(data.getHangupCause()); if (data.getTimeLen() > 0) { apiData.setWavFileUrl(data.getWavfile()); } else { apiData.setWavFileUrl(""); } if (StringUtils.isNotEmpty(data.getDialogue())) { JSONArray dialogue = new JSONArray(); JSONArray.parseArray(data.getDialogue()).forEach(obj -> { JSONObject json = (JSONObject) obj; if ("assistant".equals(json.getString("role")) || "user".equals(json.getString("role"))) { JSONObject content = new JSONObject(); content.put("role", json.getString("role")); content.put("content", json.getString("content")); dialogue.add(content); } }); apiData.setDialogue(dialogue); } else { apiData.setDialogue(new JSONArray()); } apiData.setTimeLen(Long.valueOf(data.getTimeLen()/1000).intValue()); apiData.setSessionId(data.getId()); apiData.setCallstatus(data.getCallstatus()); apiData.setCallerNumber(data.getCallerNumber()); apiData.setManualAnsweredTime(data.getManualAnsweredTime()); apiData.setManualAnsweredTimeLen(data.getManualAnsweredTimeLen()); apiRecords.add(apiData); } tableData.setRows(records); TableDataInfo tableDataInfo = new TableDataInfo(); tableDataInfo.setCode(tableData.getCode()); tableDataInfo.setRows(apiRecords); tableDataInfo.setTotal(tableData.getTotal()); tableDataInfo.setMsg(tableData.getMsg()); return tableDataInfo; } private boolean checkGroupId(String groupId) { // 可以为空 if (StringUtils.isBlank(groupId)) { return true; } // 如果传值了,必须是存在的值 CcBizGroup ccBizGroup = ccBizGroupService.selectCcBizGroupByGroupId(groupId); if (null == ccBizGroup) { return false; } return true; } private boolean checkGatewayId(Long gatewayId) { // 不可以为空 if (null == gatewayId) { return false; } // 必须是存在的网关,且用途是外呼或者不限制 CcGateways ccGateways = ccGatewaysService.selectCcGatewaysById(gatewayId); if (null == ccGateways) { return false; } // 网关用途 0 dropped; 1 phonebar; 2 outbound tasks; 3. Unlimited if (ccGateways.getPurpose() != 2 && ccGateways.getPurpose() != 3) { return false; } return true; } private boolean checkLlmAccountId(Integer llmAccountId) { // 不能为空 if (null == llmAccountId) { return false; } // 必须存在 CcLlmAgentAccount ccLlmAgentAccount = ccLlmAgentAccountService.selectCcLlmAgentAccountById(llmAccountId); if (null == ccLlmAgentAccount) { return false; } return true; } private boolean checkVoiceCode(String voiceCode, String voiceSource) { // 不能为空 if (StringUtils.isBlank(voiceCode) || StringUtils.isBlank(voiceSource)) { return false; } // voiceSource仅支持aliyun_tts 、 aliyun_tts_flow 和 doubao_vcl_tts if (!"aliyun_tts".equals(voiceSource) && !"aliyun_tts_flow".equals(voiceSource) && !"doubao_vcl_tts".equals(voiceSource)) { return false; } // voiceCode必须是存在的 CcTtsAliyun ccTtsAliyun = ccTtsAliyunService.selectCcTtsAliyunByVoiceCode(voiceCode); if (null == ccTtsAliyun) { return false; } return true; } /** * 行稳数智追加名单【不自动启动任务,需要在任务管理页面手动启动任务】 * @param req * @param localCallModel * @return */ @PostMapping("/local/addCall") @ResponseBody public AjaxResult addLocalCall(HttpServletRequest req, @RequestBody LocalCallModel localCallModel) { // if (!ClientIpCheck.checkIp(req)) { // return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", ""); // } // 获取任务 String batchName = localCallModel.getBatchName(); if (StringUtils.isEmpty(batchName)) { batchName = paramsService.getParamValueByCode("testNoticeCallTaskName", "test"); } CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchName(batchName, 1); log.info("接收到名单localCallModel:{}", JSONObject.toJSONString(localCallModel)); log.info("batchName:{}", batchName); log.info("ccCallTask:{}", JSONObject.toJSONString(ccCallTask)); // 追加名单 String phoneNum = localCallModel.getPhone(); JSONObject bizJson = new JSONObject(); bizJson.put("caller", localCallModel.getCaller()); bizJson.put("welcomeMessage", localCallModel.getWelcomeMessage()); bizJson.put("questionChainId", localCallModel.getQuestionChainId()); CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, bizJson); ccCallPhoneService.insertCcCallPhone(callPhone); // 暂时关闭自动启动逻辑(后续改成自动启停逻辑) // // 如果停止超过5分钟,则自动启动 // if (ccCallTask.getIfcall() == 0 // && (System.currentTimeMillis() - ccCallTask.getStopTime()) >= 5*60*1000L) { // ccCallTask.setIfcall(1); // ccCallTask.setExecuting(0L); // ccCallTask.setStopTime(0L); // callTaskService.updateCcCallTask(ccCallTask); // } JSONObject res = new JSONObject(); res.put("sessionId", callPhone.getId().toString()); log.info("名单处理完成:{}", JSONObject.toJSONString(callPhone)); return AjaxResult.success(res); } /** * 自动绑定并获取分机信息 * @param req * @param loginUser * @return */ @GetMapping("/phoneBar/extnum/bind") @ResponseBody public AjaxResult getExtNumByUserName(HttpServletRequest req, @RequestParam String loginUser) { // 获取分机号 CcExtNum ccExtNum = ccExtNumService.selectCcExtNumByUserCode(loginUser); if (null != ccExtNum) { return AjaxResult.success("success", ccExtNum); } // 如果没有获取到分机,则自动绑定分机 List ccExtNumList = ccExtNumService.selectUnBindCcExtNumList(); if (CollectionUtils.isEmpty(ccExtNumList)) { log.error("没有可用分机,无法分配分机-:{}", loginUser); return AjaxResult.error("没有可用分机,无法分配分机"); } ccExtNum = ccExtNumList.get(RandomUtils.nextInt(0, ccExtNumList.size())); ccExtNum.setUserCode(loginUser); ccExtNumService.updateCcExtNum(ccExtNum); return AjaxResult.success("success", ccExtNum); } /** * 获取电话工具条的网关列表 * @param req * @param extNum * @return */ @GetMapping("/phoneBar/params") @ResponseBody public AjaxResult getPhoneBaseParams(HttpServletRequest req, @RequestParam String extNum) { // 获取分机号 CcExtNum ccExtNum = ccExtNumService.selectCcExtNumByExtNum(Long.valueOf(extNum)); String extnum = ccExtNum.getExtNum().toString(); String opnum = ccExtNum.getUserCode(); String groupId = "1"; String skillLevel = "9"; String projectId = "1"; String loginToken = ccExtNumService.createToken(extnum, opnum, groupId, skillLevel, projectId); // 网关用途 0 dropped; 1 phonebar; 2 outbound tasks; 3. Unlimited Map params = new HashMap<>(); params.put("purposes", Arrays.asList(1,3)); List gatewaysList = ccGatewaysService.selectCcGatewaysList(new CcGateways().setParams(params)); List gatewayList = new ArrayList<>(); for (CcGateways ccGateways: gatewaysList) { JSONObject configGateway = new JSONObject(); configGateway.put("uuid", ccGateways.getId().toString()); configGateway.put("updateTime", ccGateways.getUpdateTime()); configGateway.put("gatewayAddr", ccGateways.getGwAddr()); configGateway.put("callerNumber", ccGateways.getCaller()); configGateway.put("calleePrefix", ccGateways.getCalleePrefix()); configGateway.put("callProfile", ccGateways.getProfileName()); configGateway.put("priority", ccGateways.getPriority()); configGateway.put("concurrency", ccGateways.getMaxConcurrency()); configGateway.put("register", ccGateways.getRegister()); configGateway.put("authUsername", ccGateways.getAuthUsername()); configGateway.put("audioCodec", ccGateways.getCodec()); gatewayList.add(configGateway); } JSONObject callConfig = new JSONObject(); String scriptServer = ccParamsService.getParamValueByCode("call-center-server-ip-addr", ""); String scriptPort = ccParamsService.getParamValueByCode("call-center-websocket-port", ""); callConfig.put("scriptServer", scriptServer); callConfig.put("scriptPort", scriptPort); callConfig.put("loginToken", loginToken); callConfig.put("gatewayList", gatewayList); return AjaxResult.success(callConfig); } @PostMapping("/test/localChat") @ResponseBody public JSONObject localChat(HttpServletRequest request, @RequestBody JSONObject reqParams) { // {"code":200, "data":{"choices":[{"content":"xxxxxxx", "wavFilePath":"/home/Records/251224101457010001/20260113161253001914.wav"}]}} log.info("请求参数:{}", reqParams); Integer rounds = 0; for (int i = 0; i < reqParams.getJSONArray("messages").size(); i++) { if ("assistant".equals(reqParams.getJSONArray("messages").getJSONObject(i).getString("role"))) { rounds ++; } } String[] rspDatas = new String[]{ // "您好,请问您是测试1本人是吗?| /home/Records/23/round-1.wav; ", "这里是中信银行委托方,这个电话号码是测试1在中信银行办理业务时登记的号码,您是测试1吗? | /home/Records/23/round-2-1.wav;/home/Records/23/round-2-2.wav;/home/Records/23/round-2-3.wav", "这里是中信银行委托方,这边主要是通知您一下,您在中信银行卡尾号6388的信用卡已错过到期环款日,当期账单账面欠款总额9097元全国统一核账时间在今天下午5点需要您在此之前处理进来,可以吧?| /home/Records/23/round-3-1.wav;/home/Records/23/round-3-2.wav;", "您的账单现在已经过环款日了,能和我们说一下您是为什么还没处理欠款吗? | /home/Records/23/round-4.wav", "好的,请您在今天下午5点之前至少处理您的最低还款额0元时间和资金都没问题,对吗?|/home/Records/23/round-5.wav", "银行稍后安排工作人员查账,建议您尽快处理欠款,不打扰您了,再见。hangupCall|/home/Records/23/round-6.wav" }; JSONObject result = new JSONObject(); result.put("code", 200); JSONObject data = new JSONObject(); JSONArray choices = new JSONArray(); JSONObject delta = new JSONObject(); String[] rspData = rspDatas[rounds].split("\\|"); delta.put("content", rspData[0].trim()); delta.put("wavFilePath", rspData[1].trim()); JSONObject choices0 = new JSONObject(); choices0.put("delta", delta); choices.add(choices0); data.put("choices", choices); result.put("data", data); return result; } //=======================================================新增接口============================================================ /** * 删除外呼任务 */ @PostMapping( "/removeTask") @ResponseBody @Transactional public AjaxResult removeTask(@RequestBody Map paramMap) { Long[] batchIds= paramMap.get("batchIds"); if(batchIds==null){ return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "batchIds不能为空!", ""); } for (Long batchId : batchIds) { // 备份拨打记录数据 ccCallPhoneService.bakCallPhoneByBatchId(batchId); // 删除拨打记录数据 ccCallPhoneService.delCallPhoneByBatchId(batchId); // 备份任务数据 ccCallTaskService.bakCallTaskByBatchId(batchId); } // 删除任务数据 String batchIdsStr = Arrays.stream(batchIds) .map(String::valueOf) .collect(Collectors.joining(",")); return toAjax(ccCallTaskService.deleteCcCallTaskByBatchIds(batchIdsStr)); } /** * 获取电话工具条的网关列表 */ @PostMapping("/myPhoneBar/params") @ResponseBody public AjaxResult getMyPhoneBaseParams(@RequestBody Map param) { String extNum = param.get("extNum"); String myGateway = param.get("myGateway"); if(extNum == null){ return AjaxResult.error("分机号参数缺失"); } // 获取分机号 CcExtNum ccExtNum = ccExtNumService.selectCcExtNumByExtNum(Long.valueOf(extNum)); String extnum = ccExtNum.getExtNum().toString(); String opnum = ccExtNum.getUserCode(); String password = ccExtNum.getExtPass(); String groupId = "1"; String skillLevel = "9"; String projectId = "1"; //1.创建token String loginToken = ccExtNumService.createToken(extnum, opnum, groupId, skillLevel, projectId); //2.获取加密密码 String encryptStr = DESUtil.encrypt(password + "," + DateUtils.format(DateUtils.addDays(new Date(), 1), "yyyyMMddHHmm")); encryptStr = String.format("var _phoneEncryptPassword='%s';", encryptStr); CcGateways ccGatewaysVo = new CcGateways(); //判断指定网关还是全部网关 if(StringUtils.isNotBlank(myGateway)){ List gatewayIds = Arrays.stream(myGateway.split(",")) .map(Long::parseLong) .collect(Collectors.toList()); ccGatewaysVo.setGatewayIds(gatewayIds); }else{ // 网关用途 0 已废弃; 1 电话条; 2 外呼任务; 3 无限制 Map params = new HashMap<>(); params.put("purposes", Arrays.asList(1,3)); ccGatewaysVo.setParams(params); } //3.获取工具条网关列表 List gatewaysList = ccGatewaysService.selectCcGatewaysList(ccGatewaysVo); List gatewayList = new ArrayList<>(); for (CcGateways ccGateways: gatewaysList) { JSONObject configGateway = new JSONObject(); configGateway.put("uuid", ccGateways.getId().toString()); configGateway.put("updateTime", ccGateways.getUpdateTime()); configGateway.put("gatewayAddr", ccGateways.getGwAddr()); configGateway.put("callerNumber", ccGateways.getCaller()); configGateway.put("calleePrefix", ccGateways.getCalleePrefix()); configGateway.put("callProfile", ccGateways.getProfileName()); configGateway.put("priority", ccGateways.getPriority()); configGateway.put("concurrency", ccGateways.getMaxConcurrency()); configGateway.put("register", ccGateways.getRegister()); configGateway.put("authUsername", ccGateways.getAuthUsername()); configGateway.put("audioCodec", ccGateways.getCodec()); gatewayList.add(configGateway); } JSONObject callConfig = new JSONObject(); String scriptServer = ccParamsService.getParamValueByCode("call-center-server-ip-addr", ""); String scriptPort = ccParamsService.getParamValueByCode("call-center-websocket-port", ""); callConfig.put("scriptServer", scriptServer); callConfig.put("scriptPort", scriptPort); callConfig.put("loginToken", loginToken); callConfig.put("encryptPsw", encryptStr); callConfig.put("gatewayList", gatewayList); //登录账号 callConfig.put("opNum", opnum); //登录用户名称 SysUser sysUser = userService.selectUserByLoginName(opnum); if(sysUser != null){ callConfig.put("userName", sysUser.getUserName()); } return AjaxResult.success(callConfig); } /** * 查询未绑定的分机管理列表 */ @GetMapping("/extnum/selectUnBindCcExtNumList") @ResponseBody public AjaxResult selectUnBindCcExtNumList() { return AjaxResult.success(ccExtNumService.selectUnBindCcExtNumList()); } /** * 新增用户且绑定未使用的分机返回用户 */ @PostMapping("/user/addUserOrBindExtNumReturnUser") @ResponseBody @Transactional public AjaxResult addUserOrBindExtNumReturnUser(@RequestBody SysUser user) { if (!userService.checkLoginNameUnique(user)) { throw new RuntimeException("新增用户'" + user.getLoginName() + "'失败,登录账号已存在"); } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { throw new RuntimeException("新增用户'" + user.getLoginName() + "'失败,手机号码已存在"); } user.setSalt(ShiroUtils.randomSalt()); user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); user.setPwdUpdateDate(DateUtils.getNowDate()); user.setCreateBy("ylrz"); int i = userService.insertUser(user); if(i>0){ //绑定分机 if (StringUtils.isNotEmpty(user.getLoginName())) { CcExtNum extNum = ccExtNumService.selectCcExtNumByExtNum(user.getExtNum()); if (null != extNum) { extNum.setUserCode(user.getLoginName()); int num = ccExtNumService.updateCcExtNum(extNum); if(num>0){ return AjaxResult.success(user); } } } } throw new RuntimeException("新增用户失败"); } /** * 修改用户且绑分机 */ @PostMapping("/user/editUserOrUnBindExtNum") @ResponseBody @Transactional public AjaxResult editUserOrUnBindExtNum(@RequestBody SysUser user) { if (!userService.checkLoginNameUnique(user)) { throw new RuntimeException("修改用户'" + user.getLoginName() + "'失败,登录账号已存在"); } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { throw new RuntimeException("修改用户'" + user.getLoginName() + "'失败,手机号码已存在"); } user.setUpdateBy("ylrz"); AuthorizationUtils.clearAllCachedAuthorizationInfo(); int i = userService.updateUser(user); if(i>0){ //修改绑定分机 CcExtNum extNum = new CcExtNum(); extNum.setExtNum(user.getExtNum()); extNum.setUserCode(user.getLoginName()); //先清除原分机绑定 int cleanNum = ccExtNumService.cleanCcExtNumByUserCode(user.getLoginName()); if(cleanNum>0){ int updateNum = ccExtNumService.updateCcExtNumByUserCode(extNum); if(updateNum>0){ return AjaxResult.success(user); } } } throw new RuntimeException("修改用户失败"); } /** * 获取手动外呼客户沟通信息 * @param phoneNum 手机号 * @param callType 类型 1呼入 2外呼 * @param uuid 通话uuid */ @GetMapping("/getCustCommunicationInfo") @ResponseBody public AjaxResult getCustCommunicationInfo(@RequestParam("phoneNum") String phoneNum, @RequestParam("callType") Integer callType, @RequestParam("uuid") String uuid) { Map mmap = new HashMap<>(); CcCustInfo ccCustInfo = ccCustInfoService.selectCcCustInfoByPhoneNum(phoneNum); if (null == ccCustInfo) { ccCustInfo = new CcCustInfo(); ccCustInfo.setCallRecordList(new ArrayList<>()); } else { ccCustInfo.setCallRecordList(ccCustCallRecordService.selectCcCustCallRecordList(new CcCustCallRecord().setCustId(ccCustInfo.getId()))); } ccCustInfo.setPhoneNum(phoneNum); mmap.put("ccCustInfo", ccCustInfo); mmap.put("callType", callType); mmap.put("uuid", uuid); // 省下拉框 List sysDivisionData = sysDivisionDataService.selectSysDivisionDataList(null); List provinces = sysDivisionData.stream() .filter(d -> d.getDeep() == 0) .collect(Collectors.toList()); mmap.put("provinces", provinces); // 市下拉框 List citys = sysDivisionData.stream() .filter(d -> d.getDeep() == 1) .collect(Collectors.toList()); mmap.put("citys", citys); // 区县下拉框 List countys = sysDivisionData.stream() .filter(d -> d.getDeep() == 2) .collect(Collectors.toList()); mmap.put("countys", countys); return AjaxResult.success(mmap); } /** * 新增保存手动外呼沟通记录 */ @PostMapping("/add/custcallrecord") @ResponseBody public AjaxResult addAustcallrecord(@RequestBody CcCustInfo ccCustInfo) { ccCustInfoService.updateCcCustInfo(ccCustInfo); CcCustInfo custInfoBak = ccCustInfoService.selectCcCustInfoByPhoneNum(ccCustInfo.getPhoneNum()); CcCustCallRecord callRecord = JSONObject.parseObject(ccCustInfo.getCallRecord(), CcCustCallRecord.class); callRecord.setCustId(custInfoBak.getId()); //这里改成查询 callRecord.setUserId(ccCustInfo.getOpNum()); callRecord.setUserRealName(ccCustInfo.getUserName()); callRecord.setCreateTime(new Date()); CcCustCallRecord hisCallRecord = ccCustCallRecordService.selectCcCustCallRecordByUuid(callRecord.getUuid()); if (null == hisCallRecord) { return toAjax(ccCustCallRecordService.insertCcCustCallRecord(callRecord)); } else { callRecord.setId(hisCallRecord.getId()); return toAjax(ccCustCallRecordService.updateCcCustCallRecord(callRecord)); } } /** * 查询手动外呼记录列表 */ @PostMapping("/outboundcdrList") @ResponseBody public TableDataInfo outboundcdrList(@RequestBody CcOutboundCdr ccOutboundCdr) { startPage(); List list = ccOutboundCdrService.selectCcOutboundCdrList(ccOutboundCdr); for (CcOutboundCdr data: list) { data.setWavFileUrl("/recordings/files?filename=" + data.getRecordFilename()); } return getDataTable(list); } /** * 通话记录查询接口(返回完整的数据表格式) */ @PostMapping("/call/phone/records") @ResponseBody public TableDataInfo getcallPhoneRecords(HttpServletRequest req, @RequestBody ApiCallRecordQueryParams queryParams) { TableDataInfo tableDataInfo; // 校验请求方ip是否合法 if (!ClientIpCheck.checkIp(req)) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value()); tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!"); return tableDataInfo; } // 分页参数处理 if (null == queryParams.getPageNum() && null == queryParams.getPageSize()) { queryParams.setPageNum(1); queryParams.setPageSize(200000); } if (null == queryParams.getPageNum()) { queryParams.setPageNum(1); } if (null == queryParams.getPageSize()) { queryParams.setPageSize(20); } // 类型(01:呼入, 02:AI外呼, 03:人工外呼) String callType = queryParams.getCallType(); if (StringUtils.isBlank(callType)) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("callType不能为空!"); return tableDataInfo; } // 校验参数 if (StringUtils.isNotEmpty(queryParams.getCalloutTimeStart()) && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeStart())) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!"); return tableDataInfo; } if (StringUtils.isNotEmpty(queryParams.getCalloutTimeEnd()) && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeEnd())) { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!"); return tableDataInfo; } // 01:呼入, 02:AI外呼, 03:人工外呼 if ("01".equals(callType)) { return getInboundRecords(queryParams); } else if ("02".equals(callType)) { return getAiCallRecordsTable(queryParams); } else if ("03".equals(callType)) { return getOutboundRecordsTable(queryParams); } else { tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value()); tableDataInfo.setMsg("callType参数不合法,呼入请输入01,AI外呼请输入02,手工外呼请输入03!"); return tableDataInfo; } } //ai外呼记录查询 private TableDataInfo getAiCallRecordsTable(ApiCallRecordQueryParams queryParams) { Map params = new HashMap<>(); if (null != queryParams.getTimeLenStart()) { params.put("timeLenStart", queryParams.getTimeLenStart()); } if (null != queryParams.getTimeLenEnd()) { params.put("timeLenEnd", queryParams.getTimeLenEnd()); } if (null != queryParams.getCalloutTimeStart()) { params.put("calloutTimeStart", queryParams.getCalloutTimeStart()); } if (null != queryParams.getCalloutTimeEnd()) { params.put("calloutTimeEnd", queryParams.getCalloutTimeEnd()); } if (null != queryParams.getAnsweredTimeStart()) { params.put("answeredTimeStart", queryParams.getAnsweredTimeStart()); } if (null != queryParams.getAnsweredTimeEnd()) { params.put("answeredTimeEnd", queryParams.getAnsweredTimeEnd()); } if (null != queryParams.getCallEndTimeStart()) { params.put("callEndTimeStart", queryParams.getCallEndTimeStart()); } if (null != queryParams.getCallEndTimeEnd()) { params.put("callEndTimeEnd", queryParams.getCallEndTimeEnd()); } CcCallPhone ccCallPhone = new CcCallPhone(); if (null != queryParams.getBatchId() && queryParams.getBatchId() > 0) { ccCallPhone.setBatchId(queryParams.getBatchId()); } ccCallPhone.setUuid(queryParams.getUuid()); ccCallPhone.setTelephone(queryParams.getTelephone()); ccCallPhone.setAcdOpnum(queryParams.getExtnum()); ccCallPhone.setCallstatus(queryParams.getCallstatus()); ccCallPhone.setCallerNumber(queryParams.getCallerNumber()); ccCallPhone.setParams(params); startPage(queryParams.getPageNum(), queryParams.getPageSize()); List list = ccCallPhoneService.selectCcCallPhoneYlrzList(ccCallPhone); list.forEach(callPhoneRecord -> { if(StringUtils.isNotBlank(callPhoneRecord.getWavfile())){ if (callPhoneRecord.getWavfile().startsWith("/")) { callPhoneRecord.setWavfile("/recordings/files?filename=" + callPhoneRecord.getWavfile().substring(1)); }else{ callPhoneRecord.setWavfile("/recordings/files?filename=" + callPhoneRecord.getWavfile()); } } callPhoneRecord.setCallstatusName( CcCallPhone.getCallStatusName(callPhoneRecord.getCallstatus())); callPhoneRecord.setCalloutTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getCalloutTime()))); callPhoneRecord.setAnsweredTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getAnsweredTime()))); callPhoneRecord.setCallEndTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getCallEndTime()))); callPhoneRecord.setTimeLenSec(DateUtils.formatTimeLength(callPhoneRecord.getTimeLen()/1000)); }); return getDataTable(list); } //人工外呼记录查询 private TableDataInfo getOutboundRecordsTable(ApiCallRecordQueryParams queryParams) { Map params = new HashMap<>(); if (null != queryParams.getTimeLenStart()) { params.put("timeLenStart", queryParams.getTimeLenStart()); } if (null != queryParams.getTimeLenEnd()) { params.put("timeLenEnd", queryParams.getTimeLenEnd()); } if (null != queryParams.getCalloutTimeStart()) { params.put("calloutTimeStart", queryParams.getCalloutTimeStart()); } if (null != queryParams.getCalloutTimeEnd()) { params.put("calloutTimeEnd", queryParams.getCalloutTimeEnd()); } if (null != queryParams.getAnsweredTimeStart()) { params.put("answeredTimeStart", queryParams.getAnsweredTimeStart()); } if (null != queryParams.getAnsweredTimeEnd()) { params.put("answeredTimeEnd", queryParams.getAnsweredTimeEnd()); } if (null != queryParams.getEndTimeStart()) { params.put("endTimeStart", queryParams.getEndTimeStart()); } if (null != queryParams.getEndTimeEnd()) { params.put("endTimeEnd", queryParams.getEndTimeEnd()); } CcCallPhone ccCallPhone = new CcCallPhone(); if (null != queryParams.getBatchId() && queryParams.getBatchId() > 0) { ccCallPhone.setBatchId(queryParams.getBatchId()); } CcOutboundCdr outboundCdr = new CcOutboundCdr(); outboundCdr.setUuid(queryParams.getUuid()); outboundCdr.setCaller(queryParams.getTelephone()); outboundCdr.setOpnum(queryParams.getExtnum()); outboundCdr.setParams(params); startPage(queryParams.getPageNum(), queryParams.getPageSize()); List list = outboundCdrService.selectCcOutboundCdrYlrzList(outboundCdr); list.forEach(callPhoneRecord -> { if(StringUtils.isNotBlank(callPhoneRecord.getRecordFilename())){ if (callPhoneRecord.getRecordFilename().startsWith("/")) { callPhoneRecord.setRecordFilename("/recordings/files?filename=" + callPhoneRecord.getRecordFilename().substring(1)); }else{ callPhoneRecord.setWavFileUrl("/recordings/files?filename=" + callPhoneRecord.getRecordFilename()); } callPhoneRecord.setStartTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getStartTime()))); callPhoneRecord.setAnsweredTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getAnsweredTime()))); callPhoneRecord.setEndTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getEndTime()))); callPhoneRecord.setTimeLenSec(DateUtils.formatTimeLength(callPhoneRecord.getTimeLen()/1000)); callPhoneRecord.setTimeLenValidStr(DateUtils.formatTimeLength(callPhoneRecord.getTimeLenValid()/1000)); } }); return getDataTable(list); } /** * 获取外呼网关列表接口 * purposes 1手动外呼电话条,2AI外呼,3不限制 * @param queryParams 网关参数 * @param req */ @PostMapping("/gateway/myList") @ResponseBody public TableDataInfo getGatewayMyList(@RequestBody CcGateways queryParams, HttpServletRequest req){ // 校验请求方ip是否合法 if (!ClientIpCheck.checkIp(req)) { TableDataInfo tableDataInfo; tableDataInfo = new TableDataInfo(); tableDataInfo.setTotal(0); tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value()); tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!"); return tableDataInfo; } startPage(queryParams.getPageNum(), queryParams.getPageSize()); return getDataTable(ccGatewaysService.selectCcGatewaysList(queryParams)); } /** * 根据通话id集合查询uuid不为空的自动外呼数据 */ @PostMapping( "/getCcCallPhoneByIds") @ResponseBody public AjaxResult getCcCallPhoneByIds(@RequestBody List callPhoneIds) { if(callPhoneIds==null){ return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "callPhoneIds不能为空!", ""); } return AjaxResult.success(ccCallPhoneService.selectCcCallPhoneListByIds(callPhoneIds)); } /** * 修改任务 * @param ccCallTask * @return */ @PostMapping("/editTask") @ResponseBody public AjaxResult editTask(@RequestBody CcCallTask ccCallTask) { if ("acd".equals(ccCallTask.getAiTransferType())) { ccCallTask.setAiTransferData(ccCallTask.getAiTransferGroupId()); } else if ("extension".equals(ccCallTask.getAiTransferType())) { ccCallTask.setAiTransferData(ccCallTask.getAiTransferExtNumber()); } else if ("gateway".equals(ccCallTask.getAiTransferType())) { JSONObject aiTransferData = new JSONObject(); aiTransferData.put("gatewayId", ccCallTask.getAiTransferGatewayId()); aiTransferData.put("destNumber", ccCallTask.getAiTransferGatewayDestNumber()); ccCallTask.setAiTransferData(JSONObject.toJSONString(aiTransferData)); } return toAjax(ccCallTaskService.updateCcCallTask(ccCallTask)); } }