ApiController.java 78 KB

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