ApiController.java 80 KB

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