ApiController.java 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631
  1. package com.ruoyi.aicall.controller;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.ruoyi.aicall.domain.CcCallPhone;
  5. import com.ruoyi.aicall.domain.CcCallTask;
  6. import com.ruoyi.aicall.domain.CcLlmAgentAccount;
  7. import com.ruoyi.aicall.domain.CcTtsAliyun;
  8. import com.ruoyi.aicall.model.*;
  9. import com.ruoyi.aicall.service.ICcCallPhoneService;
  10. import com.ruoyi.aicall.service.ICcCallTaskService;
  11. import com.ruoyi.aicall.service.ICcLlmAgentAccountService;
  12. import com.ruoyi.aicall.service.ICcTtsAliyunService;
  13. import com.ruoyi.aicall.utils.ClientIpCheck;
  14. import com.ruoyi.aicall.utils.DESUtil;
  15. import com.ruoyi.cc.domain.*;
  16. import com.ruoyi.cc.service.*;
  17. import com.ruoyi.cc.utils.DateValidatorUtils;
  18. import com.ruoyi.common.core.controller.BaseController;
  19. import com.ruoyi.common.core.domain.AjaxResult;
  20. import com.ruoyi.common.core.domain.entity.SysUser;
  21. import com.ruoyi.common.core.page.TableDataInfo;
  22. import com.ruoyi.common.utils.DateUtils;
  23. import com.ruoyi.common.utils.ShiroUtils;
  24. import com.ruoyi.common.utils.StringUtils;
  25. import com.ruoyi.common.utils.bean.BeanUtils;
  26. import com.ruoyi.common.utils.uuid.UuidGenerator;
  27. import com.ruoyi.framework.shiro.service.SysPasswordService;
  28. import com.ruoyi.framework.shiro.util.AuthorizationUtils;
  29. import com.ruoyi.system.service.ISysUserService;
  30. import lombok.extern.slf4j.Slf4j;
  31. import org.apache.commons.lang3.RandomUtils;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.stereotype.Controller;
  34. import org.springframework.transaction.annotation.Transactional;
  35. import org.springframework.util.CollectionUtils;
  36. import org.springframework.web.bind.annotation.*;
  37. import javax.servlet.http.HttpServletRequest;
  38. import java.util.*;
  39. import java.util.stream.Collectors;
  40. @Controller
  41. @Slf4j
  42. @RequestMapping("/aicall/api")
  43. public class ApiController extends BaseController {
  44. @Autowired
  45. private ICcCallTaskService callTaskService;
  46. @Autowired
  47. private ICcCallPhoneService ccCallPhoneService;
  48. @Autowired
  49. private ICcInboundCdrService inboundCdrService;
  50. @Autowired
  51. private ICcOutboundCdrService outboundCdrService;
  52. @Autowired
  53. private ICcParamsService paramsService;
  54. @Autowired
  55. private ICcGatewaysService ccGatewaysService;
  56. @Autowired
  57. private ICcLlmAgentAccountService ccLlmAgentAccountService;
  58. @Autowired
  59. private ICcBizGroupService ccBizGroupService;
  60. @Autowired
  61. private ICcCallTaskService ccCallTaskService;
  62. @Autowired
  63. private ICcTtsAliyunService ccTtsAliyunService;
  64. @Autowired
  65. private ICcExtNumService ccExtNumService;
  66. @Autowired
  67. private ICcParamsService ccParamsService;
  68. @Autowired
  69. private ISysUserService userService;
  70. @Autowired
  71. private SysPasswordService passwordService;
  72. @Autowired
  73. private ICcCustCallRecordService ccCustCallRecordService;
  74. @Autowired
  75. private ICcCustInfoService ccCustInfoService;
  76. @Autowired
  77. private ISysDivisionDataService sysDivisionDataService;
  78. @Autowired
  79. private ICcOutboundCdrService ccOutboundCdrService;
  80. /**
  81. * 获取外呼网关列表接口
  82. * @param req
  83. * @return
  84. */
  85. @GetMapping("/gateway/list")
  86. @ResponseBody
  87. public AjaxResult getGatewayList(HttpServletRequest req, @RequestParam(value = "purposes", required = false) String purposes){
  88. // 校验客户端ip是否在白名单内
  89. if (!ClientIpCheck.checkIp(req)) {
  90. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", "");
  91. }
  92. // 获取外呼网关列表
  93. Map<String, Object> params = new HashMap<>();
  94. if (StringUtils.isBlank(purposes)) {
  95. params.put("purposes", Arrays.asList(1,2,3));
  96. } else {
  97. params.put("purposes", Arrays.asList(purposes.split(",")));
  98. }
  99. List<CcGateways> list = ccGatewaysService.selectCcGatewaysList(new CcGateways().setParams(params));
  100. List<ApiGatewaysModel> result = new ArrayList<>();
  101. for (CcGateways data: list) {
  102. ApiGatewaysModel model = new ApiGatewaysModel();
  103. BeanUtils.copyProperties(data, model);
  104. result.add(model);
  105. }
  106. return AjaxResult.success(result);
  107. }
  108. /**
  109. * 获取大模型列表接口
  110. * @param req
  111. * @return
  112. */
  113. @GetMapping("/llmacount/list")
  114. @ResponseBody
  115. public AjaxResult getLlmAcountList(HttpServletRequest req){
  116. // 校验客户端ip是否在白名单内
  117. if (!ClientIpCheck.checkIp(req)) {
  118. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", "");
  119. }
  120. // 获取大模型列表
  121. List<CcLlmAgentAccount> list = ccLlmAgentAccountService.selectCcLlmAgentAccountList(new CcLlmAgentAccount());
  122. return AjaxResult.success(list);
  123. }
  124. /**
  125. * 获取音色列表
  126. * @return
  127. */
  128. @GetMapping("/voicecode/list")
  129. @ResponseBody
  130. public AjaxResult getVoiceCodeList(HttpServletRequest req)
  131. {
  132. // 校验客户端ip是否在白名单内
  133. if (!ClientIpCheck.checkIp(req)) {
  134. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", "");
  135. }
  136. // 获取音色列表
  137. List<CcTtsAliyun> list = ccTtsAliyunService.selectCcTtsAliyunList(new CcTtsAliyun());
  138. JSONArray result = new JSONArray();
  139. for (CcTtsAliyun ttsAliyun: list) {
  140. JSONObject obj = new JSONObject();
  141. obj.put("voiceName", ttsAliyun.getVoiceName());
  142. obj.put("voiceCode", ttsAliyun.getVoiceCode());
  143. obj.put("voiceSource", ttsAliyun.getVoiceSource());
  144. result.add(obj);
  145. }
  146. return AjaxResult.success(result);
  147. }
  148. /**
  149. * 获取技能组列表
  150. * @param req
  151. * @return
  152. */
  153. @GetMapping("/busigroup/list")
  154. @ResponseBody
  155. public AjaxResult getBusigroupList(HttpServletRequest req){
  156. // // 校验客户端ip是否在白名单内
  157. // if (!ClientIpCheck.checkIp(req)) {
  158. // return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", "");
  159. // }
  160. // 获取技能组列表
  161. List<CcBizGroup> list = ccBizGroupService.selectCcBizGroupList(new CcBizGroup());
  162. return AjaxResult.success(list);
  163. }
  164. /**
  165. * 通话记录查询接口(支持按时间、坐席、号码、呼入/呼出类型筛选)
  166. * @param req
  167. * @param queryParams
  168. * @return
  169. */
  170. @PostMapping("/calltask/list")
  171. @ResponseBody
  172. public TableDataInfo getCallTaskList(HttpServletRequest req, @RequestBody ApiCallTaskQueryParams queryParams)
  173. {
  174. TableDataInfo tableDataInfo;
  175. // 校验请求方ip是否合法
  176. if (!ClientIpCheck.checkIp(req)) {
  177. tableDataInfo = new TableDataInfo();
  178. tableDataInfo.setTotal(0);
  179. tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value());
  180. tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!");
  181. return tableDataInfo;
  182. }
  183. // 处理分页
  184. if (null == queryParams.getPageNum()) {
  185. queryParams.setPageNum(1);
  186. }
  187. if (null == queryParams.getPageSize()) {
  188. queryParams.setPageSize(20);
  189. }
  190. // 校验参数
  191. if (StringUtils.isNotEmpty(queryParams.getCreateTimeStart())
  192. && !DateValidatorUtils.isYmdHms(queryParams.getCreateTimeStart())) {
  193. tableDataInfo = new TableDataInfo();
  194. tableDataInfo.setTotal(0);
  195. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  196. tableDataInfo.setMsg("createTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!");
  197. return tableDataInfo;
  198. }
  199. if (StringUtils.isNotEmpty(queryParams.getCreateTimeEnd())
  200. && !DateValidatorUtils.isYmdHms(queryParams.getCreateTimeEnd())) {
  201. tableDataInfo = new TableDataInfo();
  202. tableDataInfo.setTotal(0);
  203. tableDataInfo.setCode(AjaxResult.Type.ERROR.value());
  204. tableDataInfo.setMsg("createTimeEnd格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!");
  205. return tableDataInfo;
  206. }
  207. Map<String, Object> params = new HashMap<>();
  208. params.put("createTimeStart", queryParams.getCreateTimeStart());
  209. params.put("createTimeEnd", queryParams.getCreateTimeEnd());
  210. // 分页请求数据
  211. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  212. CcCallTask ccCallTask = new CcCallTask();
  213. ccCallTask.setBatchId(queryParams.getBatchId());
  214. ccCallTask.setBatchName(queryParams.getBatchName());
  215. ccCallTask.setParams(params);
  216. List<CcCallTask> list = ccCallTaskService.selectCcCallTaskList(ccCallTask);
  217. tableDataInfo = getDataTable(list);
  218. List<CcCallTask> records = (List<CcCallTask>) tableDataInfo.getRows();
  219. for (CcCallTask data: records){
  220. CallTaskStatModel statModel = ccCallPhoneService.statByBatchId(data.getBatchId());
  221. data.setPhoneCount(statModel.getPhoneCount());
  222. data.setCallCount(statModel.getCallCount());
  223. data.setNoCallCount(statModel.getPhoneCount() - statModel.getCallCount());
  224. data.setConnectCount(statModel.getConnectCount());
  225. data.setNoConnectCount(statModel.getCallCount() - statModel.getConnectCount());
  226. if (data.getCallCount() > 0) {
  227. data.setRealConnectRate(data.getConnectCount()*1.0/data.getCallCount());
  228. } else {
  229. data.setRealConnectRate(0.0);
  230. }
  231. }
  232. tableDataInfo.setRows(records);
  233. return tableDataInfo;
  234. }
  235. /**
  236. * 根据uuid查询
  237. * @param req
  238. * @param uuid
  239. * @param callType
  240. * @return
  241. */
  242. @GetMapping("/record/uuid")
  243. @ResponseBody
  244. public AjaxResult getRecordByUuid(HttpServletRequest req, @RequestParam String uuid, @RequestParam String callType)
  245. {
  246. // 校验客户端ip是否在白名单内
  247. if (!ClientIpCheck.checkIp(req)) {
  248. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", "");
  249. }
  250. if (StringUtils.isBlank(callType)) {
  251. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "callType不能为空!", "");
  252. }
  253. // 01:呼入, 02:AI外呼, 03:人工外呼
  254. ApiCallRecordQueryParams queryParams = new ApiCallRecordQueryParams().setUuid(uuid).setCallType(callType);
  255. TableDataInfo tableDataInfo = new TableDataInfo();
  256. if ("01".equals(callType)) {
  257. tableDataInfo = getInboundRecords(queryParams);
  258. } else if ("02".equals(callType)) {
  259. tableDataInfo = getAiCallRecords(queryParams);
  260. } else if ("03".equals(callType)) {
  261. tableDataInfo = getOutboundRecords(queryParams);
  262. }
  263. if (null != tableDataInfo.getRows() && tableDataInfo.getRows().size() > 0) {
  264. return AjaxResult.success(tableDataInfo.getRows().get(0));
  265. } else {
  266. return AjaxResult.success();
  267. }
  268. }
  269. /**
  270. * 通话记录查询接口(支持按时间、坐席、号码、呼入/呼出类型筛选)
  271. * @param req
  272. * @param queryParams
  273. * @return
  274. */
  275. @PostMapping("/records/list")
  276. @ResponseBody
  277. public TableDataInfo getRecordsList(HttpServletRequest req, @RequestBody ApiCallRecordQueryParams queryParams)
  278. {
  279. TableDataInfo tableDataInfo;
  280. // 校验请求方ip是否合法
  281. if (!ClientIpCheck.checkIp(req)) {
  282. tableDataInfo = new TableDataInfo();
  283. tableDataInfo.setTotal(0);
  284. tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value());
  285. tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!");
  286. return tableDataInfo;
  287. }
  288. // 分页参数处理
  289. if (null == queryParams.getPageNum()
  290. && null == queryParams.getPageSize()) {
  291. queryParams.setPageNum(1);
  292. queryParams.setPageSize(200000);
  293. }
  294. if (null == queryParams.getPageNum()) {
  295. queryParams.setPageNum(1);
  296. }
  297. if (null == queryParams.getPageSize()) {
  298. queryParams.setPageSize(20);
  299. }
  300. // 类型(01:呼入, 02:AI外呼, 03:人工外呼)
  301. String callType = queryParams.getCallType();
  302. if (StringUtils.isBlank(callType)) {
  303. tableDataInfo = new TableDataInfo();
  304. tableDataInfo.setTotal(0);
  305. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  306. tableDataInfo.setMsg("callType不能为空!");
  307. return tableDataInfo;
  308. }
  309. // 校验参数
  310. if (StringUtils.isNotEmpty(queryParams.getCalloutTimeStart())
  311. && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeStart())) {
  312. tableDataInfo = new TableDataInfo();
  313. tableDataInfo.setTotal(0);
  314. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  315. tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!");
  316. return tableDataInfo;
  317. }
  318. if (StringUtils.isNotEmpty(queryParams.getCalloutTimeEnd())
  319. && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeEnd())) {
  320. tableDataInfo = new TableDataInfo();
  321. tableDataInfo.setTotal(0);
  322. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  323. tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!");
  324. return tableDataInfo;
  325. }
  326. // 01:呼入, 02:AI外呼, 03:人工外呼
  327. if ("01".equals(callType)) {
  328. return getInboundRecords(queryParams);
  329. } else if ("02".equals(callType)) {
  330. return getAiCallRecords(queryParams);
  331. } else if ("03".equals(callType)) {
  332. return getOutboundRecords(queryParams);
  333. } else {
  334. tableDataInfo = new TableDataInfo();
  335. tableDataInfo.setTotal(0);
  336. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  337. tableDataInfo.setMsg("callType参数不合法,呼入请输入01,AI外呼请输入02,手工外呼请输入03!");
  338. return tableDataInfo;
  339. }
  340. }
  341. /**
  342. * 创建外呼任务接口(含任务名称、优先级、并发数、TTS/音频模板等参数)接口
  343. * @param req
  344. * @param apiCallTaskModel
  345. * @return
  346. */
  347. @PostMapping("/ai/createTask")
  348. @ResponseBody
  349. public AjaxResult createCallTask(HttpServletRequest req, @RequestBody ApiCallTaskModel apiCallTaskModel) {
  350. // 校验ip白名单
  351. if (!ClientIpCheck.checkIp(req)) {
  352. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单!", "");
  353. }
  354. CcCallTask ccCallTask = new CcCallTask();
  355. // 校验参数
  356. // 任务名称不能为空
  357. if (StringUtils.isBlank(apiCallTaskModel.getBatchName())) {
  358. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "batchName不能为空!", "");
  359. }
  360. // threadNum不能为空
  361. if (null == apiCallTaskModel.getThreadNum()) {
  362. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "threadNum不能为空!", "");
  363. }
  364. // 校验groupId是否存在
  365. if (!checkGroupId(apiCallTaskModel.getGroupId())) {
  366. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "groupId参数不合法,请输入正确的groupId!", "");
  367. }
  368. // 校验taskType是否合法
  369. if (null == apiCallTaskModel.getTaskType()) {
  370. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "taskType不能为空!", "");
  371. } else {
  372. if (apiCallTaskModel.getTaskType() != 1
  373. && apiCallTaskModel.getTaskType() != 2) {
  374. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "taskType参数不合法,AI外呼请输入1,通知提醒请输入2!", "");
  375. }
  376. }
  377. // 校验gatewayId是否合法
  378. if (!checkGatewayId(apiCallTaskModel.getGatewayId())) {
  379. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "gatewayId参数不合法,请输入正确的gatewayId!", "");
  380. }
  381. // AI外呼需要校验llmAccountId是否合法
  382. if (apiCallTaskModel.getTaskType() == 2) {
  383. if (!checkLlmAccountId(apiCallTaskModel.getLlmAccountId())) {
  384. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "llmAccountId参数不合法,请输入正确的llmAccountId!", "");
  385. }
  386. }
  387. // playTimes 如果为空,默认值给1
  388. if (apiCallTaskModel.getTaskType() == 3) {
  389. if (null == apiCallTaskModel.getPlayTimes()) {
  390. apiCallTaskModel.setPlayTimes(1);
  391. }
  392. }
  393. // 校验voiceCode、voiceSource是否合法
  394. if (!checkVoiceCode(apiCallTaskModel.getVoiceCode(), apiCallTaskModel.getVoiceSource())) {
  395. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "voiceCode或voiceSource参数不合法,请输入正确的voiceCode和voiceSource!", "");
  396. }
  397. // 创建任务
  398. BeanUtils.copyProperties(apiCallTaskModel, ccCallTask, "batchId");
  399. if (null != ccCallTask.getConntectRate() && ccCallTask.getConntectRate() > 0) {
  400. ccCallTask.setRate(ccCallTask.getConntectRate()/100.0);
  401. }
  402. ccCallTask.setCreatetime(System.currentTimeMillis());
  403. ccCallTaskService.insertCcCallTask(ccCallTask);
  404. apiCallTaskModel.setBatchId(ccCallTask.getBatchId());
  405. return AjaxResult.success("success", apiCallTaskModel);
  406. }
  407. /**
  408. * 启动任务接口
  409. * @param req
  410. * @param batchId
  411. * @return
  412. */
  413. @GetMapping("/ai/startTask")
  414. @ResponseBody
  415. public AjaxResult startTask(HttpServletRequest req, @RequestParam("batchId") Long batchId) {
  416. // 校验ip白名单
  417. if (!ClientIpCheck.checkIp(req)) {
  418. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", "");
  419. }
  420. // 启动任务
  421. CcCallTask ccCallTask = ccCallTaskService.selectCcCallTaskByBatchId(batchId);
  422. if (null == ccCallTask) {
  423. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", "");
  424. }
  425. ccCallTask.setIfcall(1);
  426. ccCallTask.setExecuting(0L);
  427. ccCallTask.setStopTime(0L);
  428. ccCallTaskService.updateCcCallTask(ccCallTask);
  429. return AjaxResult.success();
  430. }
  431. /**
  432. * 停止任务接口
  433. * @param req
  434. * @param batchId
  435. * @return
  436. */
  437. @GetMapping( "/ai/stopTask")
  438. @ResponseBody
  439. public AjaxResult stopTask(HttpServletRequest req, @RequestParam("batchId") Long batchId)
  440. {
  441. // 校验ip白名单
  442. if (!ClientIpCheck.checkIp(req)) {
  443. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", "");
  444. }
  445. // 停止任务
  446. CcCallTask ccCallTask = ccCallTaskService.selectCcCallTaskByBatchId(batchId);
  447. if (null == ccCallTask) {
  448. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", "");
  449. }
  450. ccCallTask.setIfcall(0);
  451. ccCallTask.setExecuting(0L);
  452. ccCallTask.setStopTime(System.currentTimeMillis());
  453. ccCallTaskService.updateCcCallTask(ccCallTask);
  454. return AjaxResult.success();
  455. }
  456. /**
  457. * 追加名单(不自动启动任务)
  458. * @param req
  459. * @param aiCallListModel
  460. * @return
  461. */
  462. @PostMapping("/ai/addCallList")
  463. @ResponseBody
  464. public AjaxResult addAiCallList(HttpServletRequest req, @RequestBody AiCallListModel aiCallListModel) {
  465. if (!ClientIpCheck.checkIp(req)) {
  466. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", "");
  467. }
  468. Long batchId = aiCallListModel.getBatchId();
  469. if (null == batchId) {
  470. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不能为空", "");
  471. }
  472. if (CollectionUtils.isEmpty(aiCallListModel.getPhoneList())) {
  473. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数phoneList不能为空", "");
  474. }
  475. // 获取任务
  476. CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchId(batchId);
  477. if (null == ccCallTask) {
  478. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", "");
  479. }
  480. if (ccCallTask.getTaskType() != 1) {
  481. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入AI外呼任务(taskType为1)的batchId", "");
  482. }
  483. // 追加名单
  484. Integer successCount = 0;
  485. List<CcCallPhone> callPhoneList = new ArrayList<>();
  486. for (String phoneNum: aiCallListModel.getPhoneList()) {
  487. if (StringUtils.isBlank(phoneNum)) {
  488. continue;
  489. }
  490. JSONObject bizJson = new JSONObject();
  491. CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, bizJson);
  492. callPhoneList.add(callPhone);
  493. successCount ++;
  494. if (callPhoneList.size() >= 200) {
  495. ccCallPhoneService.batchInsertCcCallPhone(callPhoneList);
  496. callPhoneList = new ArrayList<>();
  497. }
  498. }
  499. if (callPhoneList.size() > 0) {
  500. ccCallPhoneService.batchInsertCcCallPhone(callPhoneList);
  501. }
  502. log.info("成功追加" + successCount + "个名单");
  503. return AjaxResult.success("成功追加" + successCount + "个名单");
  504. }
  505. /**
  506. * 追加外呼名单(不自动启动任务)
  507. * @param req
  508. * @param commonCallListModel
  509. * @return
  510. */
  511. @PostMapping("/common/addCallList")
  512. @ResponseBody
  513. public AjaxResult addCommonCallList(HttpServletRequest req, @RequestBody CommonCallListModel commonCallListModel) {
  514. if (!ClientIpCheck.checkIp(req)) {
  515. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", "");
  516. }
  517. Long batchId = commonCallListModel.getBatchId();
  518. if (null == batchId) {
  519. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不能为空", "");
  520. }
  521. if (CollectionUtils.isEmpty(commonCallListModel.getPhoneList())) {
  522. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数phoneList不能为空", "");
  523. }
  524. // 获取任务
  525. CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchId(batchId);
  526. if (null == ccCallTask) {
  527. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "参数batchId不合法,请输入正确的batchId", "");
  528. }
  529. // 通知类的通知内容必填
  530. if (ccCallTask.getTaskType() == 2) {
  531. for (CommonPhoneModel commonPhoneModel : commonCallListModel.getPhoneList()) {
  532. if (StringUtils.isBlank(commonPhoneModel.getNoticeContent())) {
  533. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "号码" + commonPhoneModel.getPhoneNum() + "的noticeContent不能为空!", "");
  534. }
  535. }
  536. }
  537. // 追加名单
  538. Integer successCount = 0;
  539. List<CcCallPhone> callPhoneList = new ArrayList<>();
  540. for (CommonPhoneModel commonPhoneModel : commonCallListModel.getPhoneList()) {
  541. String phoneNum = commonPhoneModel.getPhoneNum();
  542. if (StringUtils.isBlank(phoneNum)) {
  543. continue;
  544. }
  545. CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, commonPhoneModel.getBizJson());
  546. callPhone.setTtsText(commonPhoneModel.getNoticeContent());
  547. callPhoneList.add(callPhone);
  548. successCount ++;
  549. if (callPhoneList.size() >= 200) {
  550. ccCallPhoneService.batchInsertCcCallPhone(callPhoneList);
  551. callPhoneList = new ArrayList<>();
  552. }
  553. }
  554. if (callPhoneList.size() > 0) {
  555. ccCallPhoneService.batchInsertCcCallPhone(callPhoneList);
  556. }
  557. log.info("成功追加" + successCount + "个名单");
  558. return AjaxResult.success("成功追加" + successCount + "个名单",callPhoneList);
  559. }
  560. /**
  561. * yangqiang定制的追加通知的名单
  562. * @param req
  563. * @param noticeCallModel
  564. * @return
  565. */
  566. @PostMapping("/notice/call")
  567. @ResponseBody
  568. public AjaxResult callNotice(HttpServletRequest req, @RequestBody NoticeCallModel noticeCallModel) {
  569. if (!ClientIpCheck.checkIp(req)) {
  570. return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", "");
  571. }
  572. // 获取任务
  573. String batchName = paramsService.getParamValueByCode("testNoticeCallTaskName", "test");
  574. String phoneNum = paramsService.getParamValueByCode("testNoticeCallPhoneNum", "13908113506");
  575. CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchName(batchName, 2);
  576. // 追加名单
  577. JSONObject bizJson = new JSONObject();
  578. CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, bizJson);
  579. callPhone.setTtsText(noticeCallModel.getNoticeContent());
  580. ccCallPhoneService.insertCcCallPhone(callPhone);
  581. // 启动任务
  582. ccCallTask.setIfcall(1);
  583. ccCallTask.setExecuting(0L);
  584. ccCallTask.setStopTime(0L);
  585. callTaskService.updateCcCallTask(ccCallTask);
  586. return AjaxResult.success();
  587. }
  588. private CcCallPhone buildCcCallPhone(CcCallTask ccCallTask, String phoneNum, JSONObject bizJson) {
  589. CcCallPhone callPhone = new CcCallPhone();
  590. callPhone.setId(UuidGenerator.GetOneUuid());
  591. callPhone.setGroupId("1");
  592. callPhone.setBatchId(ccCallTask.getBatchId());
  593. callPhone.setCreatetime(new Date().getTime());
  594. callPhone.setCallstatus(0);
  595. callPhone.setCalloutTime(0L);
  596. callPhone.setCallcount(0);
  597. callPhone.setCallEndTime(0L);
  598. callPhone.setTimeLen(0L);
  599. callPhone.setValidTimeLen(0L);
  600. callPhone.setUuid("");
  601. callPhone.setConnectedTime(0L);
  602. callPhone.setHangupCause("");
  603. callPhone.setAnsweredTime(0L);
  604. callPhone.setDialogue("");
  605. callPhone.setWavfile("");
  606. callPhone.setRecordServerUrl("");
  607. callPhone.setDialogueCount(0L);
  608. callPhone.setAcdOpnum("");
  609. callPhone.setAcdQueueTime(0L);
  610. callPhone.setAcdWaitTime(0);
  611. callPhone.setTelephone(phoneNum);
  612. if (phoneNum.length() > 4) {
  613. bizJson.put("tailNum", phoneNum.substring(phoneNum.length()-4));
  614. } else {
  615. bizJson.put("tailNum", phoneNum);
  616. }
  617. bizJson.put("phoneNum", phoneNum);
  618. callPhone.setCustName(bizJson.getString("custName"));
  619. if (null == callPhone.getCustName()) {
  620. callPhone.setCustName("");
  621. }
  622. callPhone.setBizJson(JSONObject.toJSONString(bizJson));
  623. if (ccCallTask.getTaskType() == 1) {
  624. callPhone.setIntent("");
  625. } else {
  626. callPhone.setIntent("-");
  627. }
  628. return callPhone;
  629. }
  630. private TableDataInfo getOutboundRecords(ApiCallRecordQueryParams queryParams) {
  631. Map<String, Object> params = new HashMap<>();
  632. params.put("inboundTimeStart", queryParams.getCalloutTimeStart());
  633. params.put("inboundTimeEnd", queryParams.getCalloutTimeEnd());
  634. if (null != queryParams.getTimeLenStart()) {
  635. params.put("timeLenSecondStart", queryParams.getTimeLenStart().toString());
  636. }
  637. if (null != queryParams.getTimeLenEnd()) {
  638. params.put("timeLenSecondEnd", queryParams.getTimeLenEnd().toString());
  639. }
  640. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  641. CcOutboundCdr outboundCdr = new CcOutboundCdr();
  642. outboundCdr.setUuid(queryParams.getUuid());
  643. outboundCdr.setCaller(queryParams.getTelephone());
  644. outboundCdr.setOpnum(queryParams.getExtnum());
  645. outboundCdr.setParams(params);
  646. List<CcOutboundCdr> list = outboundCdrService.selectCcOutboundCdrList(outboundCdr);
  647. TableDataInfo tableData = getDataTable(list);
  648. List<CcOutboundCdr> records = (List<CcOutboundCdr>) tableData.getRows();
  649. List<ApiCallRecordQueryResult> apiRecords = new ArrayList<>();
  650. for (CcOutboundCdr data: records) {
  651. ApiCallRecordQueryResult apiData = new ApiCallRecordQueryResult();
  652. if (data.getRecordFilename().startsWith("/")) {
  653. data.setRecordFilename(data.getRecordFilename().substring(1));
  654. }
  655. data.setWavFileUrl("/recordings/files?filename=" + data.getRecordFilename());
  656. apiData.setUuid(data.getUuid());
  657. apiData.setTelephone(data.getCallee());
  658. apiData.setCalloutTime(DateUtils.format(new Date(data.getStartTime()), "yyyy-MM-dd HH:mm:ss"));
  659. if (data.getAnsweredTime() > 0) {
  660. apiData.setAnsweredTime(DateUtils.format(new Date(data.getAnsweredTime()), "yyyy-MM-dd HH:mm:ss"));
  661. } else {
  662. apiData.setAnsweredTime("");
  663. }
  664. if (data.getEndTime() > 0) {
  665. apiData.setCallEndTime(DateUtils.format(new Date(data.getEndTime()), "yyyy-MM-dd HH:mm:ss"));
  666. } else {
  667. apiData.setCallEndTime("");
  668. }
  669. apiData.setHangupCause(data.getHangupCause());
  670. if (data.getTimeLen() > 0) {
  671. apiData.setWavFileUrl(data.getWavFileUrl());
  672. } else {
  673. apiData.setWavFileUrl("");
  674. }
  675. apiData.setDialogue(new JSONArray());
  676. apiData.setTimeLen(Long.valueOf(data.getTimeLen()/1000).intValue());
  677. apiRecords.add(apiData);
  678. }
  679. tableData.setRows(records);
  680. TableDataInfo tableDataInfo = new TableDataInfo();
  681. tableDataInfo.setCode(tableData.getCode());
  682. tableDataInfo.setRows(apiRecords);
  683. tableDataInfo.setTotal(tableData.getTotal());
  684. tableDataInfo.setMsg(tableData.getMsg());
  685. return tableDataInfo;
  686. }
  687. private TableDataInfo getInboundRecords(ApiCallRecordQueryParams queryParams) {
  688. Map<String, Object> params = new HashMap<>();
  689. params.put("inboundTimeStart", queryParams.getCalloutTimeStart());
  690. params.put("inboundTimeEnd", queryParams.getCalloutTimeEnd());
  691. if (null != queryParams.getTimeLenStart()) {
  692. params.put("timeLenSecondStart", queryParams.getTimeLenStart().toString());
  693. }
  694. if (null != queryParams.getTimeLenEnd()) {
  695. params.put("timeLenSecondEnd", queryParams.getTimeLenEnd().toString());
  696. }
  697. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  698. CcInboundCdr inboundCdr = new CcInboundCdr();
  699. inboundCdr.setUuid(queryParams.getUuid());
  700. inboundCdr.setCaller(queryParams.getTelephone());
  701. inboundCdr.setOpnum(queryParams.getExtnum());
  702. inboundCdr.setParams(params);
  703. List<CcInboundCdr> list = inboundCdrService.selectCcInboundCdrList(inboundCdr);
  704. TableDataInfo tableData = getDataTable(list);
  705. List<CcInboundCdr> records = (List<CcInboundCdr>) tableData.getRows();
  706. List<ApiCallRecordQueryResult> apiRecords = new ArrayList<>();
  707. for (CcInboundCdr data: records) {
  708. ApiCallRecordQueryResult apiData = new ApiCallRecordQueryResult();
  709. if (data.getWavFile().startsWith("/")) {
  710. data.setWavFile(data.getWavFile().substring(1));
  711. }
  712. data.setWavFileUrl("/recordings/files?filename=" + data.getWavFile());
  713. apiData.setUuid(data.getUuid());
  714. apiData.setTelephone(data.getCaller());
  715. apiData.setCalloutTime(DateUtils.format(new Date(data.getInboundTime()), "yyyy-MM-dd HH:mm:ss"));
  716. if (data.getAnsweredTime() > 0) {
  717. apiData.setAnsweredTime(DateUtils.format(new Date(data.getAnsweredTime()), "yyyy-MM-dd HH:mm:ss"));
  718. } else {
  719. apiData.setAnsweredTime("");
  720. }
  721. if (data.getHangupTime() > 0) {
  722. apiData.setCallEndTime(DateUtils.format(new Date(data.getHangupTime()), "yyyy-MM-dd HH:mm:ss"));
  723. } else {
  724. apiData.setCallEndTime("");
  725. }
  726. apiData.setHangupCause("");
  727. if (data.getTimeLen() > 0) {
  728. apiData.setWavFileUrl(data.getWavFileUrl());
  729. } else {
  730. apiData.setWavFileUrl("");
  731. }
  732. if (StringUtils.isNotEmpty(data.getChatContent())) {
  733. JSONArray dialogue = new JSONArray();
  734. JSONArray.parseArray(data.getChatContent()).forEach(obj -> {
  735. JSONObject json = (JSONObject) obj;
  736. if ("assistant".equals(json.getString("role"))
  737. || "user".equals(json.getString("role"))) {
  738. JSONObject content = new JSONObject();
  739. content.put("role", json.getString("role"));
  740. content.put("content", json.getString("content"));
  741. dialogue.add(content);
  742. }
  743. });
  744. apiData.setDialogue(dialogue);
  745. } else {
  746. apiData.setDialogue(new JSONArray());
  747. }
  748. apiData.setTimeLen(Long.valueOf(data.getTimeLen()/1000).intValue());
  749. apiData.setManualAnsweredTime(data.getManualAnsweredTime());
  750. apiData.setManualAnsweredTimeLen(data.getManualAnsweredTimeLen());
  751. apiRecords.add(apiData);
  752. }
  753. tableData.setRows(records);
  754. TableDataInfo tableDataInfo = new TableDataInfo();
  755. tableDataInfo.setCode(tableData.getCode());
  756. tableDataInfo.setRows(apiRecords);
  757. tableDataInfo.setTotal(tableData.getTotal());
  758. tableDataInfo.setMsg(tableData.getMsg());
  759. return tableDataInfo;
  760. }
  761. private TableDataInfo getAiCallRecords(ApiCallRecordQueryParams queryParams) {
  762. Map<String, Object> params = new HashMap<>();
  763. params.put("calloutTimeStart", queryParams.getCalloutTimeStart());
  764. params.put("calloutTimeEnd", queryParams.getCalloutTimeEnd());
  765. if (null != queryParams.getTimeLenStart()) {
  766. params.put("timeLenSecondStart", queryParams.getTimeLenStart().toString());
  767. }
  768. if (null != queryParams.getTimeLenEnd()) {
  769. params.put("timeLenSecondEnd", queryParams.getTimeLenEnd().toString());
  770. }
  771. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  772. CcCallPhone ccCallPhone = new CcCallPhone();
  773. if (null != queryParams.getBatchId() && queryParams.getBatchId() > 0) {
  774. ccCallPhone.setBatchId(queryParams.getBatchId());
  775. }
  776. ccCallPhone.setUuid(queryParams.getUuid());
  777. ccCallPhone.setTelephone(queryParams.getTelephone());
  778. ccCallPhone.setAcdOpnum(queryParams.getExtnum());
  779. ccCallPhone.setCallstatus(queryParams.getCallstatus());
  780. ccCallPhone.setCallerNumber(queryParams.getCallerNumber());
  781. ccCallPhone.setParams(params);
  782. List<CcCallPhone> list = ccCallPhoneService.selectCcCallPhoneList(ccCallPhone);
  783. TableDataInfo tableData = getDataTable(list);
  784. List<CcCallPhone> records = (List<CcCallPhone>) tableData.getRows();
  785. List<ApiCallRecordQueryResult> apiRecords = new ArrayList<>();
  786. for (CcCallPhone data: records) {
  787. ApiCallRecordQueryResult apiData = new ApiCallRecordQueryResult();
  788. if (data.getWavfile().startsWith("/")) {
  789. data.setWavfile(data.getWavfile().substring(1));
  790. }
  791. data.setWavfile("/recordings/files?filename=" + data.getWavfile());
  792. apiData.setUuid(data.getUuid());
  793. apiData.setTelephone(data.getTelephone());
  794. apiData.setCalloutTime(DateUtils.format(new Date(data.getCalloutTime()), "yyyy-MM-dd HH:mm:ss"));
  795. if (data.getAnsweredTime() > 0) {
  796. apiData.setAnsweredTime(DateUtils.format(new Date(data.getAnsweredTime()), "yyyy-MM-dd HH:mm:ss"));
  797. } else {
  798. apiData.setAnsweredTime("");
  799. }
  800. if (data.getCallEndTime() > 0) {
  801. apiData.setCallEndTime(DateUtils.format(new Date(data.getCallEndTime()), "yyyy-MM-dd HH:mm:ss"));
  802. } else {
  803. apiData.setCallEndTime("");
  804. }
  805. apiData.setHangupCause(data.getHangupCause());
  806. if (data.getTimeLen() > 0) {
  807. apiData.setWavFileUrl(data.getWavfile());
  808. } else {
  809. apiData.setWavFileUrl("");
  810. }
  811. if (StringUtils.isNotEmpty(data.getDialogue())) {
  812. JSONArray dialogue = new JSONArray();
  813. JSONArray.parseArray(data.getDialogue()).forEach(obj -> {
  814. JSONObject json = (JSONObject) obj;
  815. if ("assistant".equals(json.getString("role"))
  816. || "user".equals(json.getString("role"))) {
  817. JSONObject content = new JSONObject();
  818. content.put("role", json.getString("role"));
  819. content.put("content", json.getString("content"));
  820. dialogue.add(content);
  821. }
  822. });
  823. apiData.setDialogue(dialogue);
  824. } else {
  825. apiData.setDialogue(new JSONArray());
  826. }
  827. apiData.setTimeLen(Long.valueOf(data.getTimeLen()/1000).intValue());
  828. apiData.setSessionId(data.getId());
  829. apiData.setCallstatus(data.getCallstatus());
  830. apiData.setCallerNumber(data.getCallerNumber());
  831. apiData.setManualAnsweredTime(data.getManualAnsweredTime());
  832. apiData.setManualAnsweredTimeLen(data.getManualAnsweredTimeLen());
  833. apiRecords.add(apiData);
  834. }
  835. tableData.setRows(records);
  836. TableDataInfo tableDataInfo = new TableDataInfo();
  837. tableDataInfo.setCode(tableData.getCode());
  838. tableDataInfo.setRows(apiRecords);
  839. tableDataInfo.setTotal(tableData.getTotal());
  840. tableDataInfo.setMsg(tableData.getMsg());
  841. return tableDataInfo;
  842. }
  843. private boolean checkGroupId(String groupId) {
  844. // 可以为空
  845. if (StringUtils.isBlank(groupId)) {
  846. return true;
  847. }
  848. // 如果传值了,必须是存在的值
  849. CcBizGroup ccBizGroup = ccBizGroupService.selectCcBizGroupByGroupId(groupId);
  850. if (null == ccBizGroup) {
  851. return false;
  852. }
  853. return true;
  854. }
  855. private boolean checkGatewayId(Long gatewayId) {
  856. // 不可以为空
  857. if (null == gatewayId) {
  858. return false;
  859. }
  860. // 必须是存在的网关,且用途是外呼或者不限制
  861. CcGateways ccGateways = ccGatewaysService.selectCcGatewaysById(gatewayId);
  862. if (null == ccGateways) {
  863. return false;
  864. }
  865. // 网关用途 0 dropped; 1 phonebar; 2 outbound tasks; 3. Unlimited
  866. if (ccGateways.getPurpose() != 2
  867. && ccGateways.getPurpose() != 3) {
  868. return false;
  869. }
  870. return true;
  871. }
  872. private boolean checkLlmAccountId(Integer llmAccountId) {
  873. // 不能为空
  874. if (null == llmAccountId) {
  875. return false;
  876. }
  877. // 必须存在
  878. CcLlmAgentAccount ccLlmAgentAccount = ccLlmAgentAccountService.selectCcLlmAgentAccountById(llmAccountId);
  879. if (null == ccLlmAgentAccount) {
  880. return false;
  881. }
  882. return true;
  883. }
  884. private boolean checkVoiceCode(String voiceCode, String voiceSource) {
  885. // 不能为空
  886. if (StringUtils.isBlank(voiceCode) || StringUtils.isBlank(voiceSource)) {
  887. return false;
  888. }
  889. // voiceSource仅支持aliyun_tts 、 aliyun_tts_flow 和 doubao_vcl_tts
  890. if (!"aliyun_tts".equals(voiceSource)
  891. && !"aliyun_tts_flow".equals(voiceSource)
  892. && !"doubao_vcl_tts".equals(voiceSource)) {
  893. return false;
  894. }
  895. // voiceCode必须是存在的
  896. CcTtsAliyun ccTtsAliyun = ccTtsAliyunService.selectCcTtsAliyunByVoiceCode(voiceCode);
  897. if (null == ccTtsAliyun) {
  898. return false;
  899. }
  900. return true;
  901. }
  902. /**
  903. * 行稳数智追加名单【不自动启动任务,需要在任务管理页面手动启动任务】
  904. * @param req
  905. * @param localCallModel
  906. * @return
  907. */
  908. @PostMapping("/local/addCall")
  909. @ResponseBody
  910. public AjaxResult addLocalCall(HttpServletRequest req, @RequestBody LocalCallModel localCallModel) {
  911. // if (!ClientIpCheck.checkIp(req)) {
  912. // return AjaxResult.error(AjaxResult.Type.NO_AUTH, "未授权,请联系系统管理员添加ip白名单", "");
  913. // }
  914. // 获取任务
  915. String batchName = localCallModel.getBatchName();
  916. if (StringUtils.isEmpty(batchName)) {
  917. batchName = paramsService.getParamValueByCode("testNoticeCallTaskName", "test");
  918. }
  919. CcCallTask ccCallTask = callTaskService.selectCcCallTaskByBatchName(batchName, 1);
  920. log.info("接收到名单localCallModel:{}", JSONObject.toJSONString(localCallModel));
  921. log.info("batchName:{}", batchName);
  922. log.info("ccCallTask:{}", JSONObject.toJSONString(ccCallTask));
  923. // 追加名单
  924. String phoneNum = localCallModel.getPhone();
  925. JSONObject bizJson = new JSONObject();
  926. bizJson.put("caller", localCallModel.getCaller());
  927. bizJson.put("welcomeMessage", localCallModel.getWelcomeMessage());
  928. bizJson.put("questionChainId", localCallModel.getQuestionChainId());
  929. CcCallPhone callPhone = buildCcCallPhone(ccCallTask, phoneNum, bizJson);
  930. ccCallPhoneService.insertCcCallPhone(callPhone);
  931. // 暂时关闭自动启动逻辑(后续改成自动启停逻辑)
  932. // // 如果停止超过5分钟,则自动启动
  933. // if (ccCallTask.getIfcall() == 0
  934. // && (System.currentTimeMillis() - ccCallTask.getStopTime()) >= 5*60*1000L) {
  935. // ccCallTask.setIfcall(1);
  936. // ccCallTask.setExecuting(0L);
  937. // ccCallTask.setStopTime(0L);
  938. // callTaskService.updateCcCallTask(ccCallTask);
  939. // }
  940. JSONObject res = new JSONObject();
  941. res.put("sessionId", callPhone.getId().toString());
  942. log.info("名单处理完成:{}", JSONObject.toJSONString(callPhone));
  943. return AjaxResult.success(res);
  944. }
  945. /**
  946. * 自动绑定并获取分机信息
  947. * @param req
  948. * @param loginUser
  949. * @return
  950. */
  951. @GetMapping("/phoneBar/extnum/bind")
  952. @ResponseBody
  953. public AjaxResult getExtNumByUserName(HttpServletRequest req, @RequestParam String loginUser) {
  954. // 获取分机号
  955. CcExtNum ccExtNum = ccExtNumService.selectCcExtNumByUserCode(loginUser);
  956. if (null != ccExtNum) {
  957. return AjaxResult.success("success", ccExtNum);
  958. }
  959. // 如果没有获取到分机,则自动绑定分机
  960. List<CcExtNum> ccExtNumList = ccExtNumService.selectUnBindCcExtNumList();
  961. if (CollectionUtils.isEmpty(ccExtNumList)) {
  962. log.error("没有可用分机,无法分配分机-:{}", loginUser);
  963. return AjaxResult.error("没有可用分机,无法分配分机");
  964. }
  965. ccExtNum = ccExtNumList.get(RandomUtils.nextInt(0, ccExtNumList.size()));
  966. ccExtNum.setUserCode(loginUser);
  967. ccExtNumService.updateCcExtNum(ccExtNum);
  968. return AjaxResult.success("success", ccExtNum);
  969. }
  970. /**
  971. * 获取电话工具条的网关列表
  972. * @param req
  973. * @param extNum
  974. * @return
  975. */
  976. @GetMapping("/phoneBar/params")
  977. @ResponseBody
  978. public AjaxResult getPhoneBaseParams(HttpServletRequest req, @RequestParam String extNum) {
  979. // 获取分机号
  980. CcExtNum ccExtNum = ccExtNumService.selectCcExtNumByExtNum(Long.valueOf(extNum));
  981. String extnum = ccExtNum.getExtNum().toString();
  982. String opnum = ccExtNum.getUserCode();
  983. String groupId = "1";
  984. String skillLevel = "9";
  985. String projectId = "1";
  986. String loginToken = ccExtNumService.createToken(extnum, opnum, groupId, skillLevel, projectId);
  987. // 网关用途 0 dropped; 1 phonebar; 2 outbound tasks; 3. Unlimited
  988. Map<String, Object> params = new HashMap<>();
  989. params.put("purposes", Arrays.asList(1,3));
  990. List<CcGateways> gatewaysList = ccGatewaysService.selectCcGatewaysList(new CcGateways().setParams(params));
  991. List<JSONObject> gatewayList = new ArrayList<>();
  992. for (CcGateways ccGateways: gatewaysList) {
  993. JSONObject configGateway = new JSONObject();
  994. configGateway.put("uuid", ccGateways.getId().toString());
  995. configGateway.put("updateTime", ccGateways.getUpdateTime());
  996. configGateway.put("gatewayAddr", ccGateways.getGwAddr());
  997. configGateway.put("callerNumber", ccGateways.getCaller());
  998. configGateway.put("calleePrefix", ccGateways.getCalleePrefix());
  999. configGateway.put("callProfile", ccGateways.getProfileName());
  1000. configGateway.put("priority", ccGateways.getPriority());
  1001. configGateway.put("concurrency", ccGateways.getMaxConcurrency());
  1002. configGateway.put("register", ccGateways.getRegister());
  1003. configGateway.put("authUsername", ccGateways.getAuthUsername());
  1004. configGateway.put("audioCodec", ccGateways.getCodec());
  1005. gatewayList.add(configGateway);
  1006. }
  1007. JSONObject callConfig = new JSONObject();
  1008. String scriptServer = ccParamsService.getParamValueByCode("call-center-server-ip-addr", "");
  1009. String scriptPort = ccParamsService.getParamValueByCode("call-center-websocket-port", "");
  1010. callConfig.put("scriptServer", scriptServer);
  1011. callConfig.put("scriptPort", scriptPort);
  1012. callConfig.put("loginToken", loginToken);
  1013. callConfig.put("gatewayList", gatewayList);
  1014. return AjaxResult.success(callConfig);
  1015. }
  1016. @PostMapping("/test/localChat")
  1017. @ResponseBody
  1018. public JSONObject localChat(HttpServletRequest request, @RequestBody JSONObject reqParams) {
  1019. // {"code":200, "data":{"choices":[{"content":"xxxxxxx", "wavFilePath":"/home/Records/251224101457010001/20260113161253001914.wav"}]}}
  1020. log.info("请求参数:{}", reqParams);
  1021. Integer rounds = 0;
  1022. for (int i = 0; i < reqParams.getJSONArray("messages").size(); i++) {
  1023. if ("assistant".equals(reqParams.getJSONArray("messages").getJSONObject(i).getString("role"))) {
  1024. rounds ++;
  1025. }
  1026. }
  1027. String[] rspDatas = new String[]{
  1028. // "您好,请问您是测试1本人是吗?| /home/Records/23/round-1.wav; ",
  1029. "这里是中信银行委托方,这个电话号码是测试1在中信银行办理业务时登记的号码,您是测试1吗? | /home/Records/23/round-2-1.wav;/home/Records/23/round-2-2.wav;/home/Records/23/round-2-3.wav",
  1030. "这里是中信银行委托方,这边主要是通知您一下,您在中信银行卡尾号6388的信用卡已错过到期环款日,当期账单账面欠款总额9097元全国统一核账时间在今天下午5点需要您在此之前处理进来,可以吧?| /home/Records/23/round-3-1.wav;/home/Records/23/round-3-2.wav;",
  1031. "您的账单现在已经过环款日了,能和我们说一下您是为什么还没处理欠款吗? | /home/Records/23/round-4.wav",
  1032. "好的,请您在今天下午5点之前至少处理您的最低还款额0元时间和资金都没问题,对吗?|/home/Records/23/round-5.wav",
  1033. "银行稍后安排工作人员查账,建议您尽快处理欠款,不打扰您了,再见。hangupCall|/home/Records/23/round-6.wav"
  1034. };
  1035. JSONObject result = new JSONObject();
  1036. result.put("code", 200);
  1037. JSONObject data = new JSONObject();
  1038. JSONArray choices = new JSONArray();
  1039. JSONObject delta = new JSONObject();
  1040. String[] rspData = rspDatas[rounds].split("\\|");
  1041. delta.put("content", rspData[0].trim());
  1042. delta.put("wavFilePath", rspData[1].trim());
  1043. JSONObject choices0 = new JSONObject();
  1044. choices0.put("delta", delta);
  1045. choices.add(choices0);
  1046. data.put("choices", choices);
  1047. result.put("data", data);
  1048. return result;
  1049. }
  1050. //=======================================================新增接口============================================================
  1051. /**
  1052. * 删除外呼任务
  1053. */
  1054. @PostMapping( "/removeTask")
  1055. @ResponseBody
  1056. @Transactional
  1057. public AjaxResult removeTask(@RequestBody Map<String, Long[]> paramMap)
  1058. {
  1059. Long[] batchIds= paramMap.get("batchIds");
  1060. if(batchIds==null){
  1061. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "batchIds不能为空!", "");
  1062. }
  1063. for (Long batchId : batchIds) {
  1064. // 备份拨打记录数据
  1065. ccCallPhoneService.bakCallPhoneByBatchId(batchId);
  1066. // 删除拨打记录数据
  1067. ccCallPhoneService.delCallPhoneByBatchId(batchId);
  1068. // 备份任务数据
  1069. ccCallTaskService.bakCallTaskByBatchId(batchId);
  1070. }
  1071. // 删除任务数据
  1072. String batchIdsStr = Arrays.stream(batchIds)
  1073. .map(String::valueOf)
  1074. .collect(Collectors.joining(","));
  1075. return toAjax(ccCallTaskService.deleteCcCallTaskByBatchIds(batchIdsStr));
  1076. }
  1077. /**
  1078. * 获取电话工具条的网关列表
  1079. */
  1080. @PostMapping("/myPhoneBar/params")
  1081. @ResponseBody
  1082. public AjaxResult getMyPhoneBaseParams(@RequestBody Map<String,String> param) {
  1083. String extNum = param.get("extNum");
  1084. String myGateway = param.get("myGateway");
  1085. if(extNum == null){
  1086. return AjaxResult.error("分机号参数缺失");
  1087. }
  1088. // 获取分机号
  1089. CcExtNum ccExtNum = ccExtNumService.selectCcExtNumByExtNum(Long.valueOf(extNum));
  1090. String extnum = ccExtNum.getExtNum().toString();
  1091. String opnum = ccExtNum.getUserCode();
  1092. String password = ccExtNum.getExtPass();
  1093. String groupId = "1";
  1094. String skillLevel = "9";
  1095. String projectId = "1";
  1096. //1.创建token
  1097. String loginToken = ccExtNumService.createToken(extnum, opnum, groupId, skillLevel, projectId);
  1098. //2.获取加密密码
  1099. String encryptStr = DESUtil.encrypt(password + "," + DateUtils.format(DateUtils.addDays(new Date(), 1), "yyyyMMddHHmm"));
  1100. encryptStr = String.format("var _phoneEncryptPassword='%s';", encryptStr);
  1101. CcGateways ccGatewaysVo = new CcGateways();
  1102. //判断指定网关还是全部网关
  1103. if(StringUtils.isNotBlank(myGateway)){
  1104. List<Long> gatewayIds = Arrays.stream(myGateway.split(","))
  1105. .map(Long::parseLong)
  1106. .collect(Collectors.toList());
  1107. ccGatewaysVo.setGatewayIds(gatewayIds);
  1108. }else{
  1109. // 网关用途 0 已废弃; 1 电话条; 2 外呼任务; 3 无限制
  1110. Map<String, Object> params = new HashMap<>();
  1111. params.put("purposes", Arrays.asList(1,3));
  1112. ccGatewaysVo.setParams(params);
  1113. }
  1114. //3.获取工具条网关列表
  1115. List<CcGateways> gatewaysList = ccGatewaysService.selectCcGatewaysList(ccGatewaysVo);
  1116. List<JSONObject> gatewayList = new ArrayList<>();
  1117. for (CcGateways ccGateways: gatewaysList) {
  1118. JSONObject configGateway = new JSONObject();
  1119. configGateway.put("uuid", ccGateways.getId().toString());
  1120. configGateway.put("updateTime", ccGateways.getUpdateTime());
  1121. configGateway.put("gatewayAddr", ccGateways.getGwAddr());
  1122. configGateway.put("callerNumber", ccGateways.getCaller());
  1123. configGateway.put("calleePrefix", ccGateways.getCalleePrefix());
  1124. configGateway.put("callProfile", ccGateways.getProfileName());
  1125. configGateway.put("priority", ccGateways.getPriority());
  1126. configGateway.put("concurrency", ccGateways.getMaxConcurrency());
  1127. configGateway.put("register", ccGateways.getRegister());
  1128. configGateway.put("authUsername", ccGateways.getAuthUsername());
  1129. configGateway.put("audioCodec", ccGateways.getCodec());
  1130. gatewayList.add(configGateway);
  1131. }
  1132. JSONObject callConfig = new JSONObject();
  1133. String scriptServer = ccParamsService.getParamValueByCode("call-center-server-ip-addr", "");
  1134. String scriptPort = ccParamsService.getParamValueByCode("call-center-websocket-port", "");
  1135. callConfig.put("scriptServer", scriptServer);
  1136. callConfig.put("scriptPort", scriptPort);
  1137. callConfig.put("loginToken", loginToken);
  1138. callConfig.put("encryptPsw", encryptStr);
  1139. callConfig.put("gatewayList", gatewayList);
  1140. //登录账号
  1141. callConfig.put("opNum", opnum);
  1142. //登录用户名称
  1143. SysUser sysUser = userService.selectUserByLoginName(opnum);
  1144. if(sysUser != null){
  1145. callConfig.put("userName", sysUser.getUserName());
  1146. }
  1147. return AjaxResult.success(callConfig);
  1148. }
  1149. /**
  1150. * 查询未绑定的分机管理列表
  1151. */
  1152. @GetMapping("/extnum/selectUnBindCcExtNumList")
  1153. @ResponseBody
  1154. public AjaxResult selectUnBindCcExtNumList()
  1155. {
  1156. return AjaxResult.success(ccExtNumService.selectUnBindCcExtNumList());
  1157. }
  1158. /**
  1159. * 新增用户且绑定未使用的分机返回用户
  1160. */
  1161. @PostMapping("/user/addUserOrBindExtNumReturnUser")
  1162. @ResponseBody
  1163. @Transactional
  1164. public AjaxResult addUserOrBindExtNumReturnUser(@RequestBody SysUser user)
  1165. {
  1166. if (!userService.checkLoginNameUnique(user))
  1167. {
  1168. throw new RuntimeException("新增用户'" + user.getLoginName() + "'失败,登录账号已存在");
  1169. }
  1170. else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
  1171. {
  1172. throw new RuntimeException("新增用户'" + user.getLoginName() + "'失败,手机号码已存在");
  1173. }
  1174. user.setSalt(ShiroUtils.randomSalt());
  1175. user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt()));
  1176. user.setPwdUpdateDate(DateUtils.getNowDate());
  1177. user.setCreateBy("ylrz");
  1178. int i = userService.insertUser(user);
  1179. if(i>0){
  1180. //绑定分机
  1181. if (StringUtils.isNotEmpty(user.getLoginName())) {
  1182. CcExtNum extNum = ccExtNumService.selectCcExtNumByExtNum(user.getExtNum());
  1183. if (null != extNum) {
  1184. extNum.setUserCode(user.getLoginName());
  1185. int num = ccExtNumService.updateCcExtNum(extNum);
  1186. if(num>0){
  1187. return AjaxResult.success(user);
  1188. }
  1189. }
  1190. }
  1191. }
  1192. throw new RuntimeException("新增用户失败");
  1193. }
  1194. /**
  1195. * 修改用户且绑分机
  1196. */
  1197. @PostMapping("/user/editUserOrUnBindExtNum")
  1198. @ResponseBody
  1199. @Transactional
  1200. public AjaxResult editUserOrUnBindExtNum(@RequestBody SysUser user)
  1201. {
  1202. if (!userService.checkLoginNameUnique(user))
  1203. {
  1204. throw new RuntimeException("修改用户'" + user.getLoginName() + "'失败,登录账号已存在");
  1205. }
  1206. else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
  1207. {
  1208. throw new RuntimeException("修改用户'" + user.getLoginName() + "'失败,手机号码已存在");
  1209. }
  1210. user.setUpdateBy("ylrz");
  1211. AuthorizationUtils.clearAllCachedAuthorizationInfo();
  1212. int i = userService.updateUser(user);
  1213. if(i>0){
  1214. //修改绑定分机
  1215. CcExtNum extNum = new CcExtNum();
  1216. extNum.setExtNum(user.getExtNum());
  1217. extNum.setUserCode(user.getLoginName());
  1218. //先清除原分机绑定
  1219. int cleanNum = ccExtNumService.cleanCcExtNumByUserCode(user.getLoginName());
  1220. if(cleanNum>0){
  1221. int updateNum = ccExtNumService.updateCcExtNumByUserCode(extNum);
  1222. if(updateNum>0){
  1223. return AjaxResult.success(user);
  1224. }
  1225. }
  1226. }
  1227. throw new RuntimeException("修改用户失败");
  1228. }
  1229. /**
  1230. * 获取手动外呼客户沟通信息
  1231. * @param phoneNum 手机号
  1232. * @param callType 类型 1呼入 2外呼
  1233. * @param uuid 通话uuid
  1234. */
  1235. @GetMapping("/getCustCommunicationInfo")
  1236. @ResponseBody
  1237. public AjaxResult getCustCommunicationInfo(@RequestParam("phoneNum") String phoneNum, @RequestParam("callType") Integer callType, @RequestParam("uuid") String uuid)
  1238. {
  1239. Map<String,Object> mmap = new HashMap<>();
  1240. CcCustInfo ccCustInfo = ccCustInfoService.selectCcCustInfoByPhoneNum(phoneNum);
  1241. if (null == ccCustInfo) {
  1242. ccCustInfo = new CcCustInfo();
  1243. ccCustInfo.setCallRecordList(new ArrayList<>());
  1244. } else {
  1245. ccCustInfo.setCallRecordList(ccCustCallRecordService.selectCcCustCallRecordList(new CcCustCallRecord().setCustId(ccCustInfo.getId())));
  1246. }
  1247. ccCustInfo.setPhoneNum(phoneNum);
  1248. mmap.put("ccCustInfo", ccCustInfo);
  1249. mmap.put("callType", callType);
  1250. mmap.put("uuid", uuid);
  1251. // 省下拉框
  1252. List<SysDivisionData> sysDivisionData = sysDivisionDataService.selectSysDivisionDataList(null);
  1253. List<SysDivisionData> provinces = sysDivisionData.stream()
  1254. .filter(d -> d.getDeep() == 0)
  1255. .collect(Collectors.toList());
  1256. mmap.put("provinces", provinces);
  1257. // 市下拉框
  1258. List<SysDivisionData> citys = sysDivisionData.stream()
  1259. .filter(d -> d.getDeep() == 1)
  1260. .collect(Collectors.toList());
  1261. mmap.put("citys", citys);
  1262. // 区县下拉框
  1263. List<SysDivisionData> countys = sysDivisionData.stream()
  1264. .filter(d -> d.getDeep() == 2)
  1265. .collect(Collectors.toList());
  1266. mmap.put("countys", countys);
  1267. return AjaxResult.success(mmap);
  1268. }
  1269. /**
  1270. * 新增保存手动外呼沟通记录
  1271. */
  1272. @PostMapping("/add/custcallrecord")
  1273. @ResponseBody
  1274. public AjaxResult addAustcallrecord(@RequestBody CcCustInfo ccCustInfo)
  1275. {
  1276. ccCustInfoService.updateCcCustInfo(ccCustInfo);
  1277. CcCustInfo custInfoBak = ccCustInfoService.selectCcCustInfoByPhoneNum(ccCustInfo.getPhoneNum());
  1278. CcCustCallRecord callRecord = JSONObject.parseObject(ccCustInfo.getCallRecord(), CcCustCallRecord.class);
  1279. callRecord.setCustId(custInfoBak.getId());
  1280. //这里改成查询
  1281. callRecord.setUserId(ccCustInfo.getOpNum());
  1282. callRecord.setUserRealName(ccCustInfo.getUserName());
  1283. callRecord.setCreateTime(new Date());
  1284. CcCustCallRecord hisCallRecord = ccCustCallRecordService.selectCcCustCallRecordByUuid(callRecord.getUuid());
  1285. if (null == hisCallRecord) {
  1286. return toAjax(ccCustCallRecordService.insertCcCustCallRecord(callRecord));
  1287. } else {
  1288. callRecord.setId(hisCallRecord.getId());
  1289. return toAjax(ccCustCallRecordService.updateCcCustCallRecord(callRecord));
  1290. }
  1291. }
  1292. /**
  1293. * 查询手动外呼记录列表
  1294. */
  1295. @PostMapping("/outboundcdrList")
  1296. @ResponseBody
  1297. public TableDataInfo outboundcdrList(@RequestBody CcOutboundCdr ccOutboundCdr)
  1298. {
  1299. startPage();
  1300. List<CcOutboundCdr> list = ccOutboundCdrService.selectCcOutboundCdrList(ccOutboundCdr);
  1301. for (CcOutboundCdr data: list) {
  1302. data.setWavFileUrl("/recordings/files?filename=" + data.getRecordFilename());
  1303. }
  1304. return getDataTable(list);
  1305. }
  1306. /**
  1307. * 通话记录查询接口(返回完整的数据表格式)
  1308. */
  1309. @PostMapping("/call/phone/records")
  1310. @ResponseBody
  1311. public TableDataInfo getcallPhoneRecords(HttpServletRequest req, @RequestBody ApiCallRecordQueryParams queryParams)
  1312. {
  1313. TableDataInfo tableDataInfo;
  1314. // 校验请求方ip是否合法
  1315. if (!ClientIpCheck.checkIp(req)) {
  1316. tableDataInfo = new TableDataInfo();
  1317. tableDataInfo.setTotal(0);
  1318. tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value());
  1319. tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!");
  1320. return tableDataInfo;
  1321. }
  1322. // 分页参数处理
  1323. if (null == queryParams.getPageNum()
  1324. && null == queryParams.getPageSize()) {
  1325. queryParams.setPageNum(1);
  1326. queryParams.setPageSize(200000);
  1327. }
  1328. if (null == queryParams.getPageNum()) {
  1329. queryParams.setPageNum(1);
  1330. }
  1331. if (null == queryParams.getPageSize()) {
  1332. queryParams.setPageSize(20);
  1333. }
  1334. // 类型(01:呼入, 02:AI外呼, 03:人工外呼)
  1335. String callType = queryParams.getCallType();
  1336. if (StringUtils.isBlank(callType)) {
  1337. tableDataInfo = new TableDataInfo();
  1338. tableDataInfo.setTotal(0);
  1339. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  1340. tableDataInfo.setMsg("callType不能为空!");
  1341. return tableDataInfo;
  1342. }
  1343. // 校验参数
  1344. if (StringUtils.isNotEmpty(queryParams.getCalloutTimeStart())
  1345. && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeStart())) {
  1346. tableDataInfo = new TableDataInfo();
  1347. tableDataInfo.setTotal(0);
  1348. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  1349. tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!");
  1350. return tableDataInfo;
  1351. }
  1352. if (StringUtils.isNotEmpty(queryParams.getCalloutTimeEnd())
  1353. && !DateValidatorUtils.isYmdHms(queryParams.getCalloutTimeEnd())) {
  1354. tableDataInfo = new TableDataInfo();
  1355. tableDataInfo.setTotal(0);
  1356. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  1357. tableDataInfo.setMsg("calloutTimeStart格式不正确,请使用'yyyy-MM-dd HH:mm:ss'格式!");
  1358. return tableDataInfo;
  1359. }
  1360. // 01:呼入, 02:AI外呼, 03:人工外呼
  1361. if ("01".equals(callType)) {
  1362. return getInboundRecords(queryParams);
  1363. } else if ("02".equals(callType)) {
  1364. return getAiCallRecordsTable(queryParams);
  1365. } else if ("03".equals(callType)) {
  1366. return getOutboundRecordsTable(queryParams);
  1367. } else {
  1368. tableDataInfo = new TableDataInfo();
  1369. tableDataInfo.setTotal(0);
  1370. tableDataInfo.setCode(AjaxResult.Type.INVALID_PARAM.value());
  1371. tableDataInfo.setMsg("callType参数不合法,呼入请输入01,AI外呼请输入02,手工外呼请输入03!");
  1372. return tableDataInfo;
  1373. }
  1374. }
  1375. //ai外呼记录查询
  1376. private TableDataInfo getAiCallRecordsTable(ApiCallRecordQueryParams queryParams) {
  1377. Map<String, Object> params = new HashMap<>();
  1378. if (null != queryParams.getTimeLenStart()) {
  1379. params.put("timeLenStart", queryParams.getTimeLenStart());
  1380. }
  1381. if (null != queryParams.getTimeLenEnd()) {
  1382. params.put("timeLenEnd", queryParams.getTimeLenEnd());
  1383. }
  1384. if (null != queryParams.getCalloutTimeStart()) {
  1385. params.put("calloutTimeStart", queryParams.getCalloutTimeStart());
  1386. }
  1387. if (null != queryParams.getCalloutTimeEnd()) {
  1388. params.put("calloutTimeEnd", queryParams.getCalloutTimeEnd());
  1389. }
  1390. if (null != queryParams.getAnsweredTimeStart()) {
  1391. params.put("answeredTimeStart", queryParams.getAnsweredTimeStart());
  1392. }
  1393. if (null != queryParams.getAnsweredTimeEnd()) {
  1394. params.put("answeredTimeEnd", queryParams.getAnsweredTimeEnd());
  1395. }
  1396. if (null != queryParams.getCallEndTimeStart()) {
  1397. params.put("callEndTimeStart", queryParams.getCallEndTimeStart());
  1398. }
  1399. if (null != queryParams.getCallEndTimeEnd()) {
  1400. params.put("callEndTimeEnd", queryParams.getCallEndTimeEnd());
  1401. }
  1402. CcCallPhone ccCallPhone = new CcCallPhone();
  1403. if (null != queryParams.getBatchId() && queryParams.getBatchId() > 0) {
  1404. ccCallPhone.setBatchId(queryParams.getBatchId());
  1405. }
  1406. ccCallPhone.setUuid(queryParams.getUuid());
  1407. ccCallPhone.setTelephone(queryParams.getTelephone());
  1408. ccCallPhone.setAcdOpnum(queryParams.getExtnum());
  1409. ccCallPhone.setCallstatus(queryParams.getCallstatus());
  1410. ccCallPhone.setCallerNumber(queryParams.getCallerNumber());
  1411. ccCallPhone.setParams(params);
  1412. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  1413. List<CcCallPhone> list = ccCallPhoneService.selectCcCallPhoneYlrzList(ccCallPhone);
  1414. list.forEach(callPhoneRecord -> {
  1415. if(StringUtils.isNotBlank(callPhoneRecord.getWavfile())){
  1416. if (callPhoneRecord.getWavfile().startsWith("/")) {
  1417. callPhoneRecord.setWavfile("/recordings/files?filename=" + callPhoneRecord.getWavfile().substring(1));
  1418. }else{
  1419. callPhoneRecord.setWavfile("/recordings/files?filename=" + callPhoneRecord.getWavfile());
  1420. }
  1421. }
  1422. callPhoneRecord.setCallstatusName( CcCallPhone.getCallStatusName(callPhoneRecord.getCallstatus()));
  1423. callPhoneRecord.setCalloutTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getCalloutTime())));
  1424. callPhoneRecord.setAnsweredTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getAnsweredTime())));
  1425. callPhoneRecord.setCallEndTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getCallEndTime())));
  1426. callPhoneRecord.setTimeLenSec(DateUtils.formatTimeLength(callPhoneRecord.getTimeLen()/1000));
  1427. });
  1428. return getDataTable(list);
  1429. }
  1430. //人工外呼记录查询
  1431. private TableDataInfo getOutboundRecordsTable(ApiCallRecordQueryParams queryParams) {
  1432. Map<String, Object> params = new HashMap<>();
  1433. if (null != queryParams.getTimeLenStart()) {
  1434. params.put("timeLenStart", queryParams.getTimeLenStart());
  1435. }
  1436. if (null != queryParams.getTimeLenEnd()) {
  1437. params.put("timeLenEnd", queryParams.getTimeLenEnd());
  1438. }
  1439. if (null != queryParams.getCalloutTimeStart()) {
  1440. params.put("calloutTimeStart", queryParams.getCalloutTimeStart());
  1441. }
  1442. if (null != queryParams.getCalloutTimeEnd()) {
  1443. params.put("calloutTimeEnd", queryParams.getCalloutTimeEnd());
  1444. }
  1445. if (null != queryParams.getAnsweredTimeStart()) {
  1446. params.put("answeredTimeStart", queryParams.getAnsweredTimeStart());
  1447. }
  1448. if (null != queryParams.getAnsweredTimeEnd()) {
  1449. params.put("answeredTimeEnd", queryParams.getAnsweredTimeEnd());
  1450. }
  1451. if (null != queryParams.getEndTimeStart()) {
  1452. params.put("endTimeStart", queryParams.getEndTimeStart());
  1453. }
  1454. if (null != queryParams.getEndTimeEnd()) {
  1455. params.put("endTimeEnd", queryParams.getEndTimeEnd());
  1456. }
  1457. CcCallPhone ccCallPhone = new CcCallPhone();
  1458. if (null != queryParams.getBatchId() && queryParams.getBatchId() > 0) {
  1459. ccCallPhone.setBatchId(queryParams.getBatchId());
  1460. }
  1461. CcOutboundCdr outboundCdr = new CcOutboundCdr();
  1462. outboundCdr.setUuid(queryParams.getUuid());
  1463. outboundCdr.setCaller(queryParams.getTelephone());
  1464. outboundCdr.setOpnum(queryParams.getExtnum());
  1465. outboundCdr.setParams(params);
  1466. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  1467. List<CcOutboundCdr> list = outboundCdrService.selectCcOutboundCdrYlrzList(outboundCdr);
  1468. list.forEach(callPhoneRecord -> {
  1469. if(StringUtils.isNotBlank(callPhoneRecord.getRecordFilename())){
  1470. if (callPhoneRecord.getRecordFilename().startsWith("/")) {
  1471. callPhoneRecord.setRecordFilename("/recordings/files?filename=" + callPhoneRecord.getRecordFilename().substring(1));
  1472. }else{
  1473. callPhoneRecord.setWavFileUrl("/recordings/files?filename=" + callPhoneRecord.getRecordFilename());
  1474. }
  1475. callPhoneRecord.setStartTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getStartTime())));
  1476. callPhoneRecord.setAnsweredTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getAnsweredTime())));
  1477. callPhoneRecord.setEndTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", new Date(callPhoneRecord.getEndTime())));
  1478. callPhoneRecord.setTimeLenSec(DateUtils.formatTimeLength(callPhoneRecord.getTimeLen()/1000));
  1479. callPhoneRecord.setTimeLenValidStr(DateUtils.formatTimeLength(callPhoneRecord.getTimeLenValid()/1000));
  1480. }
  1481. });
  1482. return getDataTable(list);
  1483. }
  1484. /**
  1485. * 获取外呼网关列表接口
  1486. * purposes 1手动外呼电话条,2AI外呼,3不限制
  1487. * @param queryParams 网关参数
  1488. * @param req
  1489. */
  1490. @PostMapping("/gateway/myList")
  1491. @ResponseBody
  1492. public TableDataInfo getGatewayMyList(@RequestBody CcGateways queryParams, HttpServletRequest req){
  1493. // 校验请求方ip是否合法
  1494. if (!ClientIpCheck.checkIp(req)) {
  1495. TableDataInfo tableDataInfo;
  1496. tableDataInfo = new TableDataInfo();
  1497. tableDataInfo.setTotal(0);
  1498. tableDataInfo.setCode(AjaxResult.Type.NO_AUTH.value());
  1499. tableDataInfo.setMsg("未授权,请联系系统管理员添加ip白名单!");
  1500. return tableDataInfo;
  1501. }
  1502. startPage(queryParams.getPageNum(), queryParams.getPageSize());
  1503. return getDataTable(ccGatewaysService.selectCcGatewaysList(queryParams));
  1504. }
  1505. /**
  1506. * 根据通话id集合查询uuid不为空的自动外呼数据
  1507. */
  1508. @PostMapping( "/getCcCallPhoneByIds")
  1509. @ResponseBody
  1510. public AjaxResult getCcCallPhoneByIds(@RequestBody List<String> callPhoneIds)
  1511. {
  1512. if(callPhoneIds==null){
  1513. return AjaxResult.error(AjaxResult.Type.INVALID_PARAM, "callPhoneIds不能为空!", "");
  1514. }
  1515. return AjaxResult.success(ccCallPhoneService.selectCcCallPhoneListByIds(callPhoneIds));
  1516. }
  1517. /**
  1518. * 修改任务
  1519. * @param ccCallTask
  1520. * @return
  1521. */
  1522. @PostMapping("/editTask")
  1523. @ResponseBody
  1524. public AjaxResult editTask(@RequestBody CcCallTask ccCallTask)
  1525. {
  1526. if ("acd".equals(ccCallTask.getAiTransferType())) {
  1527. ccCallTask.setAiTransferData(ccCallTask.getAiTransferGroupId());
  1528. } else if ("extension".equals(ccCallTask.getAiTransferType())) {
  1529. ccCallTask.setAiTransferData(ccCallTask.getAiTransferExtNumber());
  1530. } else if ("gateway".equals(ccCallTask.getAiTransferType())) {
  1531. JSONObject aiTransferData = new JSONObject();
  1532. aiTransferData.put("gatewayId", ccCallTask.getAiTransferGatewayId());
  1533. aiTransferData.put("destNumber", ccCallTask.getAiTransferGatewayDestNumber());
  1534. ccCallTask.setAiTransferData(JSONObject.toJSONString(aiTransferData));
  1535. }
  1536. return toAjax(ccCallTaskService.updateCcCallTask(ccCallTask));
  1537. }
  1538. }