|
|
@@ -1,13 +1,10 @@
|
|
|
package com.fs.kdzl.service.impl;
|
|
|
|
|
|
-import com.alibaba.fastjson.JSONArray;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
import com.fs.common.utils.http.HttpUtils;
|
|
|
-import com.fs.kdzl.dto.Custm;
|
|
|
-import com.fs.kdzl.dto.CustomerResponse;
|
|
|
-import com.fs.kdzl.dto.HighSeaCustomerResponse;
|
|
|
-import com.fs.kdzl.dto.KdzlCustomerDTO;
|
|
|
+import com.fs.kdzl.dto.*;
|
|
|
import com.fs.kdzl.service.KdzlService;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
@@ -15,7 +12,11 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
+import java.time.Instant;
|
|
|
+import java.time.ZoneOffset;
|
|
|
+import java.time.ZonedDateTime;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
import java.util.List;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
@@ -34,6 +35,7 @@ public class KdzlServiceImpl implements KdzlService {
|
|
|
private static final int CACHE_ADVANCE_EXPIRE_SECONDS = 600;
|
|
|
private static final String CUSTOMER_NEXT_CACHE_KEY = "kdzl:customer_next";
|
|
|
private static final int MAX_COUNT = 2000;
|
|
|
+ private static final String CALL_RECORD_LAST_CACHE_KEY = "kdzl:call_record_last";
|
|
|
|
|
|
@Autowired
|
|
|
private RedisCache redisCache;
|
|
|
@@ -197,4 +199,197 @@ public class KdzlServiceImpl implements KdzlService {
|
|
|
return customerList;
|
|
|
}
|
|
|
|
|
|
+// @Override
|
|
|
+// public List<CallRecord> exportCallRecords() {
|
|
|
+// List<CallRecord> callRecordList = new ArrayList<>();
|
|
|
+// try {
|
|
|
+// String accessToken = getAccessToken();
|
|
|
+// if (accessToken.isEmpty()) {
|
|
|
+// log.error("获取access_token失败,无法导出通话记录");
|
|
|
+// return callRecordList;
|
|
|
+// }
|
|
|
+// //构建查询参数
|
|
|
+// CallFilter callFilter = new CallFilter();
|
|
|
+// //分页
|
|
|
+// CallLast last = null;
|
|
|
+// callFilter.setCallLast(last);
|
|
|
+// //查询日期
|
|
|
+// long eTime = Instant.now().toEpochMilli();
|
|
|
+// ZonedDateTime zonedDateTime = ZonedDateTime.of(2026, 6, 19, 0, 0, 0, 0, ZoneOffset.ofHours(8));
|
|
|
+// long sTime = zonedDateTime.toInstant().toEpochMilli();
|
|
|
+// CallFilter.TimeRange timeRange = new CallFilter.TimeRange();
|
|
|
+// timeRange.setStime(sTime);
|
|
|
+// timeRange.setEtime(eTime);
|
|
|
+//
|
|
|
+// CallFilter.Filter filter = new CallFilter.Filter();
|
|
|
+// filter.setTimeRange(timeRange);
|
|
|
+// callFilter.setFilter(filter);
|
|
|
+// //查询条数
|
|
|
+// callFilter.setLimit(2000L);
|
|
|
+//
|
|
|
+// boolean hasMore = true;
|
|
|
+// while (hasMore) {
|
|
|
+// String url = URL1 + "/open/api/phonesale/getCallRecordList?access_token=" + accessToken;
|
|
|
+// String response = HttpUtils.doPost(url, JSONUtil.toJsonStr(callFilter));
|
|
|
+// if (response.isEmpty()) {
|
|
|
+// log.error("导出通话记录失败,响应为空");
|
|
|
+// return callRecordList;
|
|
|
+// }
|
|
|
+// JSONObject jsonObject = JSONObject.parseObject(response);
|
|
|
+// CallRecordDataResponse callRecordData = jsonObject.toJavaObject(CallRecordDataResponse.class);
|
|
|
+// Integer result = callRecordData.getResult();
|
|
|
+// if (result != null && result == 0) {
|
|
|
+// CallRecordData data = callRecordData.getData();
|
|
|
+// if (data != null && !CollectionUtils.isEmpty(data.getRecords())) {
|
|
|
+// callRecordList.addAll(callRecordData.getData().getRecords());
|
|
|
+// log.info("成功导出通话记录数量: {}, 当前分页: {}", callRecordList.size(), callFilter.getCallLast());
|
|
|
+// CallLast nextLast = data.getLast();
|
|
|
+// if (nextLast != null) {
|
|
|
+// callFilter.setLast(nextLast);
|
|
|
+// } else {
|
|
|
+// hasMore = false; // 没有下一页了
|
|
|
+// }
|
|
|
+// }
|
|
|
+// } else {
|
|
|
+// String errMsg = jsonObject.getString("errmsg");
|
|
|
+// log.error("导出通话记录失败,错误码: {}, 错误信息: {}", result, errMsg);
|
|
|
+// }
|
|
|
+// }
|
|
|
+//// String url = URL1 + "/open/api/phonesale/getCallRecordList?access_token=" + accessToken;
|
|
|
+//// String response = HttpUtils.doPost(url, JSONUtil.toJsonStr(callFilter));
|
|
|
+////
|
|
|
+//// if (response.isEmpty()) {
|
|
|
+//// log.error("导出通话记录失败,响应为空");
|
|
|
+//// return callRecordList;
|
|
|
+//// }
|
|
|
+////
|
|
|
+//// JSONObject jsonObject = JSONObject.parseObject(response);
|
|
|
+//// CallRecordDataResponse callRecordData = jsonObject.toJavaObject(CallRecordDataResponse.class);
|
|
|
+//// Integer result = callRecordData.getResult();
|
|
|
+////
|
|
|
+//// if (result != null && result == 0) {
|
|
|
+//// if (callRecordData.getData() != null && !CollectionUtils.isEmpty(callRecordData.getData().getRecords())) {
|
|
|
+//// callRecordList = callRecordData.getData().getRecords();
|
|
|
+//// log.info("成功导出通话记录数量: {}, 当前分页: {}", callRecordList.size(), callFilter.getCallLast());
|
|
|
+//// last = callRecordData.getData().getLast();
|
|
|
+//// }
|
|
|
+//// } else {
|
|
|
+//// String errMsg = jsonObject.getString("errmsg");
|
|
|
+//// log.error("导出通话记录失败,错误码: {}, 错误信息: {}", result, errMsg);
|
|
|
+//// }
|
|
|
+// } catch (Exception e) {
|
|
|
+// log.error("导出通话记录异常", e);
|
|
|
+// }
|
|
|
+// return callRecordList;
|
|
|
+// }
|
|
|
+@Override
|
|
|
+public List<CallRecord> exportCallRecords() {
|
|
|
+ List<CallRecord> callRecordList = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ String accessToken = getAccessToken();
|
|
|
+ if (accessToken.isEmpty()) {
|
|
|
+ log.error("获取access_token失败,无法导出通话记录");
|
|
|
+ return callRecordList;
|
|
|
+ }
|
|
|
+
|
|
|
+ CallFilter callFilter = new CallFilter();
|
|
|
+ long eTime = Instant.now().toEpochMilli();
|
|
|
+ ZonedDateTime zonedDateTime = ZonedDateTime.of(2026, 6, 19, 0, 0, 0, 0, ZoneOffset.ofHours(8));
|
|
|
+ long sTime = zonedDateTime.toInstant().toEpochMilli();
|
|
|
+
|
|
|
+ CallFilter.TimeRange timeRange = new CallFilter.TimeRange();
|
|
|
+ timeRange.setStime(sTime);
|
|
|
+ timeRange.setEtime(eTime);
|
|
|
+
|
|
|
+ CallFilter.Filter filter = new CallFilter.Filter();
|
|
|
+ filter.setTimeRange(timeRange);
|
|
|
+ callFilter.setFilter(filter);
|
|
|
+ callFilter.setLimit(2000L);
|
|
|
+
|
|
|
+ int emptyCount = 0; // 连续空数据计数器
|
|
|
+ final int MAX_EMPTY_RETRY = 3; // 最大空数据重试次数
|
|
|
+ final int MAX_TOTAL_RECORDS = 100000; // 安全上限,防止无限循环
|
|
|
+
|
|
|
+ boolean hasMore = true;
|
|
|
+ while (hasMore) {
|
|
|
+ String url = URL1 + "/open/api/phonesale/getCallRecordList?access_token=" + accessToken;
|
|
|
+ String jsonStr = JSONUtil.toJsonStr(callFilter);
|
|
|
+ String response = HttpUtils.doPost(url, jsonStr);
|
|
|
+
|
|
|
+ if (response.isEmpty()) {
|
|
|
+ log.error("导出通话记录失败,响应为空");
|
|
|
+ break; // 改为 break 而不是 return,保留已获取的数据
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(response);
|
|
|
+ CallRecordDataResponse callRecordData = jsonObject.toJavaObject(CallRecordDataResponse.class);
|
|
|
+ Integer result = callRecordData.getResult();
|
|
|
+
|
|
|
+ if (result != null && result == 0) {
|
|
|
+ CallRecordData data = callRecordData.getData();
|
|
|
+
|
|
|
+ if (data != null && !CollectionUtils.isEmpty(data.getRecords())) {
|
|
|
+ int beforeSize = callRecordList.size();
|
|
|
+ callRecordList.addAll(data.getRecords());
|
|
|
+ int addedCount = callRecordList.size() - beforeSize;
|
|
|
+
|
|
|
+ log.info("成功导出通话记录,本次新增: {}, 累计总数: {}, 当前分页参数: {}",
|
|
|
+ addedCount, callRecordList.size(), callFilter.getLast());
|
|
|
+
|
|
|
+ // 安全检查1:总数量上限
|
|
|
+ if (callRecordList.size() >= MAX_TOTAL_RECORDS) {
|
|
|
+ log.warn("通话记录数量达到安全上限 {},停止导出", MAX_TOTAL_RECORDS);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 安全检查2:数据是否真的增加了(防止重复数据)
|
|
|
+ if (addedCount == 0) {
|
|
|
+ emptyCount++;
|
|
|
+ log.warn("本次未新增数据,连续空次数: {}/{}", emptyCount, MAX_EMPTY_RETRY);
|
|
|
+ if (emptyCount >= MAX_EMPTY_RETRY) {
|
|
|
+ log.error("连续 {} 次未获取到新数据,可能存在死循环,强制退出", MAX_EMPTY_RETRY);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ emptyCount = 0; // 重置计数器
|
|
|
+ }
|
|
|
+
|
|
|
+ CallLast nextLast = data.getLast();
|
|
|
+
|
|
|
+ // 安全检查3:last 对象是否与本次请求相同(死循环检测)
|
|
|
+ if (nextLast != null && nextLast.equals(callFilter.getLast())) {
|
|
|
+ log.error("检测到重复的分页参数,last 对象未变化,强制退出循环。last: {}", nextLast);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nextLast != null) {
|
|
|
+ callFilter.setLast(nextLast);
|
|
|
+ } else {
|
|
|
+ log.info("没有下一页了,分页结束");
|
|
|
+ hasMore = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("未查询到通话记录数据,分页结束");
|
|
|
+ hasMore = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ String errMsg = jsonObject.getString("errmsg");
|
|
|
+ log.error("导出通话记录失败,错误码: {}, 错误信息: {}", result, errMsg);
|
|
|
+ break; // 错误时退出,保留已获取数据
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("导出通话记录异常", e);
|
|
|
+ }
|
|
|
+ return callRecordList;
|
|
|
+}
|
|
|
+ public static void main(String[] args) {
|
|
|
+ long epochMilli = Instant.now().toEpochMilli();
|
|
|
+ System.out.println(epochMilli);
|
|
|
+
|
|
|
+ ZonedDateTime zonedDateTime = ZonedDateTime.of(2026, 6, 19, 0, 0, 0, 0, ZoneOffset.ofHours(8));
|
|
|
+ long epochMilli1 = zonedDateTime.toInstant().toEpochMilli();
|
|
|
+ System.out.println(epochMilli1);
|
|
|
+ }
|
|
|
+
|
|
|
}
|