1
This commit is contained in:
@@ -21,30 +21,30 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 腾讯文档控制器
|
* 腾讯文档控制器
|
||||||
*
|
*
|
||||||
* @author system
|
* @author system
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/jarvis/tendoc")
|
@RequestMapping("/jarvis/tendoc")
|
||||||
public class TencentDocController extends BaseController {
|
public class TencentDocController extends BaseController {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(TencentDocController.class);
|
private static final Logger log = LoggerFactory.getLogger(TencentDocController.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ITencentDocService tencentDocService;
|
private ITencentDocService tencentDocService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IJDOrderService jdOrderService;
|
private IJDOrderService jdOrderService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private com.ruoyi.jarvis.service.ITencentDocTokenService tencentDocTokenService;
|
private com.ruoyi.jarvis.service.ITencentDocTokenService tencentDocTokenService;
|
||||||
|
|
||||||
/** Redis key前缀,用于存储上次处理的最大行数 */
|
/** Redis key前缀,用于存储上次处理的最大行数 */
|
||||||
private static final String LAST_PROCESSED_ROW_KEY_PREFIX = "tendoc:last_row:";
|
private static final String LAST_PROCESSED_ROW_KEY_PREFIX = "tendoc:last_row:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试回调接口是否可访问(用于调试)
|
* 测试回调接口是否可访问(用于调试)
|
||||||
*/
|
*/
|
||||||
@@ -53,7 +53,7 @@ public class TencentDocController extends BaseController {
|
|||||||
public AjaxResult testCallback() {
|
public AjaxResult testCallback() {
|
||||||
return AjaxResult.success("回调接口测试成功,路由配置正确");
|
return AjaxResult.success("回调接口测试成功,路由配置正确");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取授权URL(用于手动授权,获取token后通过setToken接口保存)
|
* 获取授权URL(用于手动授权,获取token后通过setToken接口保存)
|
||||||
*/
|
*/
|
||||||
@@ -67,7 +67,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("获取授权URL失败: " + e.getMessage());
|
return AjaxResult.error("获取授权URL失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动设置访问令牌(用于首次授权后保存token)
|
* 手动设置访问令牌(用于首次授权后保存token)
|
||||||
*/
|
*/
|
||||||
@@ -76,13 +76,13 @@ public class TencentDocController extends BaseController {
|
|||||||
try {
|
try {
|
||||||
String accessToken = (String) params.get("accessToken");
|
String accessToken = (String) params.get("accessToken");
|
||||||
String refreshToken = (String) params.get("refreshToken");
|
String refreshToken = (String) params.get("refreshToken");
|
||||||
Integer expiresIn = params.get("expiresIn") != null ?
|
Integer expiresIn = params.get("expiresIn") != null ?
|
||||||
Integer.valueOf(params.get("expiresIn").toString()) : 7200;
|
Integer.valueOf(params.get("expiresIn").toString()) : 7200;
|
||||||
|
|
||||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||||
return AjaxResult.error("accessToken不能为空");
|
return AjaxResult.error("accessToken不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过反射调用setToken方法
|
// 通过反射调用setToken方法
|
||||||
if (tencentDocTokenService instanceof com.ruoyi.jarvis.service.impl.TencentDocTokenServiceImpl) {
|
if (tencentDocTokenService instanceof com.ruoyi.jarvis.service.impl.TencentDocTokenServiceImpl) {
|
||||||
((com.ruoyi.jarvis.service.impl.TencentDocTokenServiceImpl) tencentDocTokenService)
|
((com.ruoyi.jarvis.service.impl.TencentDocTokenServiceImpl) tencentDocTokenService)
|
||||||
@@ -96,7 +96,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("设置访问令牌失败: " + e.getMessage());
|
return AjaxResult.error("设置访问令牌失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试获取用户信息接口
|
* 测试获取用户信息接口
|
||||||
*/
|
*/
|
||||||
@@ -112,7 +112,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("测试失败: " + e.getMessage());
|
return AjaxResult.error("测试失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前token状态
|
* 获取当前token状态
|
||||||
*/
|
*/
|
||||||
@@ -133,7 +133,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("获取token状态失败: " + e.getMessage());
|
return AjaxResult.error("获取token状态失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OAuth回调 - 通过授权码获取访问令牌
|
* OAuth回调 - 通过授权码获取访问令牌
|
||||||
* 根据腾讯文档官方文档:https://docs.qq.com/open/document/app/oauth2/authorize.html
|
* 根据腾讯文档官方文档:https://docs.qq.com/open/document/app/oauth2/authorize.html
|
||||||
@@ -142,7 +142,7 @@ public class TencentDocController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@Anonymous
|
@Anonymous
|
||||||
@GetMapping(value = "/oauth/callback", produces = MediaType.TEXT_HTML_VALUE)
|
@GetMapping(value = "/oauth/callback", produces = MediaType.TEXT_HTML_VALUE)
|
||||||
public String oauthCallback(@RequestParam(value = "code", required = false) String code,
|
public String oauthCallback(@RequestParam(value = "code", required = false) String code,
|
||||||
@RequestParam(value = "state", required = false) String state,
|
@RequestParam(value = "state", required = false) String state,
|
||||||
@RequestParam(value = "error", required = false) String error,
|
@RequestParam(value = "error", required = false) String error,
|
||||||
@RequestParam(value = "error_description", required = false) String errorDescription) {
|
@RequestParam(value = "error_description", required = false) String errorDescription) {
|
||||||
@@ -153,30 +153,30 @@ public class TencentDocController extends BaseController {
|
|||||||
String errorMsg = errorDescription != null ? errorDescription : error;
|
String errorMsg = errorDescription != null ? errorDescription : error;
|
||||||
return generateCallbackHtml(false, "授权失败: " + errorMsg, null);
|
return generateCallbackHtml(false, "授权失败: " + errorMsg, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证授权码
|
// 验证授权码
|
||||||
if (code == null || code.trim().isEmpty()) {
|
if (code == null || code.trim().isEmpty()) {
|
||||||
log.error("授权码为空");
|
log.error("授权码为空");
|
||||||
return generateCallbackHtml(false, "授权码不能为空", null);
|
return generateCallbackHtml(false, "授权码不能为空", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("收到腾讯文档授权回调 - code: {}, state: {}", code, state);
|
log.info("收到腾讯文档授权回调 - code: {}, state: {}", code, state);
|
||||||
|
|
||||||
// 使用授权码换取access_token
|
// 使用授权码换取access_token
|
||||||
JSONObject tokenInfo = tencentDocService.getAccessTokenByCode(code);
|
JSONObject tokenInfo = tencentDocService.getAccessTokenByCode(code);
|
||||||
|
|
||||||
// 验证返回的token信息
|
// 验证返回的token信息
|
||||||
if (tokenInfo == null || !tokenInfo.containsKey("access_token")) {
|
if (tokenInfo == null || !tokenInfo.containsKey("access_token")) {
|
||||||
log.error("获取访问令牌失败 - 响应数据: {}", tokenInfo);
|
log.error("获取访问令牌失败 - 响应数据: {}", tokenInfo);
|
||||||
return generateCallbackHtml(false, "获取访问令牌失败,响应数据格式不正确", null);
|
return generateCallbackHtml(false, "获取访问令牌失败,响应数据格式不正确", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
String accessToken = tokenInfo.getString("access_token");
|
String accessToken = tokenInfo.getString("access_token");
|
||||||
String refreshToken = tokenInfo.getString("refresh_token");
|
String refreshToken = tokenInfo.getString("refresh_token");
|
||||||
Integer expiresIn = tokenInfo.getIntValue("expires_in");
|
Integer expiresIn = tokenInfo.getIntValue("expires_in");
|
||||||
|
|
||||||
log.info("成功获取访问令牌 - access_token: {}", accessToken);
|
log.info("成功获取访问令牌 - access_token: {}", accessToken);
|
||||||
|
|
||||||
// 自动保存token到后端
|
// 自动保存token到后端
|
||||||
try {
|
try {
|
||||||
if (tencentDocTokenService instanceof com.ruoyi.jarvis.service.impl.TencentDocTokenServiceImpl) {
|
if (tencentDocTokenService instanceof com.ruoyi.jarvis.service.impl.TencentDocTokenServiceImpl) {
|
||||||
@@ -188,14 +188,14 @@ public class TencentDocController extends BaseController {
|
|||||||
log.error("保存访问令牌失败", e);
|
log.error("保存访问令牌失败", e);
|
||||||
return generateCallbackHtml(false, "保存访问令牌失败: " + e.getMessage(), null);
|
return generateCallbackHtml(false, "保存访问令牌失败: " + e.getMessage(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateCallbackHtml(true, "授权成功,访问令牌已自动保存", null);
|
return generateCallbackHtml(true, "授权成功,访问令牌已自动保存", null);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("OAuth回调处理失败", e);
|
log.error("OAuth回调处理失败", e);
|
||||||
return generateCallbackHtml(false, "授权失败: " + e.getMessage(), null);
|
return generateCallbackHtml(false, "授权失败: " + e.getMessage(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成回调HTML页面
|
* 生成回调HTML页面
|
||||||
*/
|
*/
|
||||||
@@ -252,7 +252,7 @@ public class TencentDocController extends BaseController {
|
|||||||
html.append("</html>");
|
html.append("</html>");
|
||||||
return html.toString();
|
return html.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新访问令牌
|
* 刷新访问令牌
|
||||||
*/
|
*/
|
||||||
@@ -263,7 +263,7 @@ public class TencentDocController extends BaseController {
|
|||||||
if (refreshToken == null || refreshToken.isEmpty()) {
|
if (refreshToken == null || refreshToken.isEmpty()) {
|
||||||
return AjaxResult.error("refreshToken不能为空");
|
return AjaxResult.error("refreshToken不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject tokenInfo = tencentDocService.refreshAccessToken(refreshToken);
|
JSONObject tokenInfo = tencentDocService.refreshAccessToken(refreshToken);
|
||||||
return AjaxResult.success("刷新令牌成功", tokenInfo);
|
return AjaxResult.success("刷新令牌成功", tokenInfo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -271,7 +271,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("刷新令牌失败: " + e.getMessage());
|
return AjaxResult.error("刷新令牌失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将订单物流信息上传到腾讯文档表格
|
* 将订单物流信息上传到腾讯文档表格
|
||||||
*/
|
*/
|
||||||
@@ -281,19 +281,19 @@ public class TencentDocController extends BaseController {
|
|||||||
String accessToken = (String) params.get("accessToken");
|
String accessToken = (String) params.get("accessToken");
|
||||||
String fileId = (String) params.get("fileId");
|
String fileId = (String) params.get("fileId");
|
||||||
String sheetId = (String) params.get("sheetId");
|
String sheetId = (String) params.get("sheetId");
|
||||||
|
|
||||||
if (accessToken == null || fileId == null || sheetId == null) {
|
if (accessToken == null || fileId == null || sheetId == null) {
|
||||||
return AjaxResult.error("accessToken、fileId和sheetId不能为空");
|
return AjaxResult.error("accessToken、fileId和sheetId不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取订单ID列表
|
// 获取订单ID列表
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Long> orderIds = (List<Long>) params.get("orderIds");
|
List<Long> orderIds = (List<Long>) params.get("orderIds");
|
||||||
|
|
||||||
if (orderIds == null || orderIds.isEmpty()) {
|
if (orderIds == null || orderIds.isEmpty()) {
|
||||||
return AjaxResult.error("订单ID列表不能为空");
|
return AjaxResult.error("订单ID列表不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询订单信息
|
// 查询订单信息
|
||||||
List<JDOrder> orders = new java.util.ArrayList<>();
|
List<JDOrder> orders = new java.util.ArrayList<>();
|
||||||
for (Long orderId : orderIds) {
|
for (Long orderId : orderIds) {
|
||||||
@@ -302,11 +302,11 @@ public class TencentDocController extends BaseController {
|
|||||||
orders.add(order);
|
orders.add(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (orders.isEmpty()) {
|
if (orders.isEmpty()) {
|
||||||
return AjaxResult.error("未找到有效的订单信息");
|
return AjaxResult.error("未找到有效的订单信息");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject result = tencentDocService.uploadLogisticsToSheet(accessToken, fileId, sheetId, orders);
|
JSONObject result = tencentDocService.uploadLogisticsToSheet(accessToken, fileId, sheetId, orders);
|
||||||
return AjaxResult.success("上传物流信息成功", result);
|
return AjaxResult.success("上传物流信息成功", result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -314,7 +314,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("上传物流信息失败: " + e.getMessage());
|
return AjaxResult.error("上传物流信息失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将单个订单的物流信息追加到表格
|
* 将单个订单的物流信息追加到表格
|
||||||
*/
|
*/
|
||||||
@@ -325,17 +325,17 @@ public class TencentDocController extends BaseController {
|
|||||||
String fileId = (String) params.get("fileId");
|
String fileId = (String) params.get("fileId");
|
||||||
String sheetId = (String) params.get("sheetId");
|
String sheetId = (String) params.get("sheetId");
|
||||||
Long orderId = params.get("orderId") != null ? Long.valueOf(params.get("orderId").toString()) : null;
|
Long orderId = params.get("orderId") != null ? Long.valueOf(params.get("orderId").toString()) : null;
|
||||||
|
|
||||||
if (accessToken == null || fileId == null || sheetId == null || orderId == null) {
|
if (accessToken == null || fileId == null || sheetId == null || orderId == null) {
|
||||||
return AjaxResult.error("accessToken、fileId、sheetId和orderId不能为空");
|
return AjaxResult.error("accessToken、fileId、sheetId和orderId不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询订单信息
|
// 查询订单信息
|
||||||
JDOrder order = jdOrderService.selectJDOrderById(orderId);
|
JDOrder order = jdOrderService.selectJDOrderById(orderId);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
return AjaxResult.error("未找到订单信息");
|
return AjaxResult.error("未找到订单信息");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject result = tencentDocService.appendLogisticsToSheet(accessToken, fileId, sheetId, order);
|
JSONObject result = tencentDocService.appendLogisticsToSheet(accessToken, fileId, sheetId, order);
|
||||||
return AjaxResult.success("追加物流信息成功", result);
|
return AjaxResult.success("追加物流信息成功", result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -343,7 +343,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("追加物流信息失败: " + e.getMessage());
|
return AjaxResult.error("追加物流信息失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取表格数据
|
* 读取表格数据
|
||||||
*/
|
*/
|
||||||
@@ -360,7 +360,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("读取表格数据失败: " + e.getMessage());
|
return AjaxResult.error("读取表格数据失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文件信息
|
* 获取文件信息
|
||||||
*/
|
*/
|
||||||
@@ -375,7 +375,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("获取文件信息失败: " + e.getMessage());
|
return AjaxResult.error("获取文件信息失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取工作表列表
|
* 获取工作表列表
|
||||||
*/
|
*/
|
||||||
@@ -390,7 +390,7 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("获取工作表列表失败: " + e.getMessage());
|
return AjaxResult.error("获取工作表列表失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自动发货 - 将指定订单的物流信息上传到腾讯文档并标记为已发货
|
* 自动发货 - 将指定订单的物流信息上传到腾讯文档并标记为已发货
|
||||||
*/
|
*/
|
||||||
@@ -401,41 +401,41 @@ public class TencentDocController extends BaseController {
|
|||||||
String fileId = (String) params.get("fileId");
|
String fileId = (String) params.get("fileId");
|
||||||
String sheetId = (String) params.get("sheetId");
|
String sheetId = (String) params.get("sheetId");
|
||||||
Long orderId = params.get("orderId") != null ? Long.valueOf(params.get("orderId").toString()) : null;
|
Long orderId = params.get("orderId") != null ? Long.valueOf(params.get("orderId").toString()) : null;
|
||||||
|
|
||||||
if (accessToken == null || fileId == null || sheetId == null || orderId == null) {
|
if (accessToken == null || fileId == null || sheetId == null || orderId == null) {
|
||||||
return AjaxResult.error("accessToken、fileId、sheetId和orderId不能为空");
|
return AjaxResult.error("accessToken、fileId、sheetId和orderId不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询订单信息
|
// 查询订单信息
|
||||||
JDOrder order = jdOrderService.selectJDOrderById(orderId);
|
JDOrder order = jdOrderService.selectJDOrderById(orderId);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
return AjaxResult.error("未找到订单信息");
|
return AjaxResult.error("未找到订单信息");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有物流链接
|
// 检查是否有物流链接
|
||||||
if (order.getLogisticsLink() == null || order.getLogisticsLink().trim().isEmpty()) {
|
if (order.getLogisticsLink() == null || order.getLogisticsLink().trim().isEmpty()) {
|
||||||
return AjaxResult.error("订单缺少物流链接,无法自动发货");
|
return AjaxResult.error("订单缺少物流链接,无法自动发货");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传物流信息到腾讯文档
|
// 上传物流信息到腾讯文档
|
||||||
JSONObject uploadResult = tencentDocService.appendLogisticsToSheet(accessToken, fileId, sheetId, order);
|
JSONObject uploadResult = tencentDocService.appendLogisticsToSheet(accessToken, fileId, sheetId, order);
|
||||||
|
|
||||||
// 更新订单状态为已发货(可选)
|
// 更新订单状态为已发货(可选)
|
||||||
// order.setStatus("已发货");
|
// order.setStatus("已发货");
|
||||||
// jdOrderService.updateJDOrder(order);
|
// jdOrderService.updateJDOrder(order);
|
||||||
|
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
result.put("uploadResult", uploadResult);
|
result.put("uploadResult", uploadResult);
|
||||||
result.put("orderId", orderId);
|
result.put("orderId", orderId);
|
||||||
result.put("message", "物流信息已上传到腾讯文档,自动发货成功");
|
result.put("message", "物流信息已上传到腾讯文档,自动发货成功");
|
||||||
|
|
||||||
return AjaxResult.success("自动发货成功", result);
|
return AjaxResult.success("自动发货成功", result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("自动发货失败", e);
|
log.error("自动发货失败", e);
|
||||||
return AjaxResult.error("自动发货失败: " + e.getMessage());
|
return AjaxResult.error("自动发货失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据单号填充物流链接 - 读取表格数据,根据单号查询订单系统中的物流链接,并填充到表格
|
* 根据单号填充物流链接 - 读取表格数据,根据单号查询订单系统中的物流链接,并填充到表格
|
||||||
* 优化:记录上次处理的最大行数,每次从最大行数-100开始读取,避免重复处理历史数据
|
* 优化:记录上次处理的最大行数,每次从最大行数-100开始读取,避免重复处理历史数据
|
||||||
@@ -458,27 +458,27 @@ public class TencentDocController extends BaseController {
|
|||||||
return AjaxResult.error("访问令牌无效,请先完成授权。获取授权URL: GET /jarvis/tendoc/authUrl");
|
return AjaxResult.error("访问令牌无效,请先完成授权。获取授权URL: GET /jarvis/tendoc/authUrl");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String fileId = (String) params.get("fileId");
|
String fileId = (String) params.get("fileId");
|
||||||
String sheetId = (String) params.get("sheetId");
|
String sheetId = (String) params.get("sheetId");
|
||||||
|
|
||||||
// 可选参数:表头行号
|
// 可选参数:表头行号
|
||||||
Integer headerRow = params.get("headerRow") != null ?
|
Integer headerRow = params.get("headerRow") != null ?
|
||||||
Integer.valueOf(params.get("headerRow").toString()) : 1; // 表头所在行(默认第1行,从1开始)
|
Integer.valueOf(params.get("headerRow").toString()) : 1; // 表头所在行(默认第1行,从1开始)
|
||||||
|
|
||||||
// 可选参数:是否强制从指定行开始(如果为true,则忽略Redis记录的最大行数)
|
// 可选参数:是否强制从指定行开始(如果为true,则忽略Redis记录的最大行数)
|
||||||
Boolean forceStart = params.get("forceStart") != null ?
|
Boolean forceStart = params.get("forceStart") != null ?
|
||||||
Boolean.valueOf(params.get("forceStart").toString()) : false;
|
Boolean.valueOf(params.get("forceStart").toString()) : false;
|
||||||
Integer forceStartRow = params.get("forceStartRow") != null ?
|
Integer forceStartRow = params.get("forceStartRow") != null ?
|
||||||
Integer.valueOf(params.get("forceStartRow").toString()) : null;
|
Integer.valueOf(params.get("forceStartRow").toString()) : null;
|
||||||
|
|
||||||
if (accessToken == null || fileId == null || sheetId == null) {
|
if (accessToken == null || fileId == null || sheetId == null) {
|
||||||
return AjaxResult.error("accessToken、fileId和sheetId不能为空");
|
return AjaxResult.error("accessToken、fileId和sheetId不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成Redis key,用于存储该文件的工作表的上次处理最大行数
|
// 生成Redis key,用于存储该文件的工作表的上次处理最大行数
|
||||||
String redisKey = LAST_PROCESSED_ROW_KEY_PREFIX + fileId + ":" + sheetId;
|
String redisKey = LAST_PROCESSED_ROW_KEY_PREFIX + fileId + ":" + sheetId;
|
||||||
|
|
||||||
// 获取上次处理的最大行数
|
// 获取上次处理的最大行数
|
||||||
Integer lastMaxRow = null;
|
Integer lastMaxRow = null;
|
||||||
if (!forceStart && redisCache.hasKey(redisKey)) {
|
if (!forceStart && redisCache.hasKey(redisKey)) {
|
||||||
@@ -487,7 +487,7 @@ public class TencentDocController extends BaseController {
|
|||||||
lastMaxRow = Integer.valueOf(cacheObj.toString());
|
lastMaxRow = Integer.valueOf(cacheObj.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算起始行:从上次最大行数-100开始,或者从强制指定的行开始,或者从表头下一行开始
|
// 计算起始行:从上次最大行数-100开始,或者从强制指定的行开始,或者从表头下一行开始
|
||||||
int startRow;
|
int startRow;
|
||||||
if (forceStartRow != null) {
|
if (forceStartRow != null) {
|
||||||
@@ -497,21 +497,21 @@ public class TencentDocController extends BaseController {
|
|||||||
} else {
|
} else {
|
||||||
startRow = headerRow + 1; // 默认从表头下一行开始
|
startRow = headerRow + 1; // 默认从表头下一行开始
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算读取范围:从起始行开始,读取足够多的行
|
// 计算读取范围:从起始行开始,读取足够多的行
|
||||||
// 根据官方文档限制:查询范围行数≤1000,列数≤200,总单元格≤10000
|
// 根据官方文档限制:查询范围行数≤1000,列数≤200,总单元格≤10000
|
||||||
// 为了避免超出表格实际范围(A1表示法的range不能超出实际数据区域),每次只读取50行
|
// 为了避免超出表格实际范围(A1表示法的range不能超出实际数据区域),每次只读取50行
|
||||||
int endRow = startRow + 49; // 每次最多读取50行(包含起始行)
|
int endRow = startRow + 49; // 每次最多读取50行(包含起始行)
|
||||||
|
|
||||||
log.info("开始填充物流链接 - 文件ID: {}, 工作表ID: {}, 起始行: {}, 结束行: {}, 上次最大行: {}",
|
log.info("开始填充物流链接 - 文件ID: {}, 工作表ID: {}, 起始行: {}, 结束行: {}, 上次最大行: {}",
|
||||||
fileId, sheetId, startRow, endRow, lastMaxRow);
|
fileId, sheetId, startRow, endRow, lastMaxRow);
|
||||||
|
|
||||||
// 读取表格数据(先读取表头行用于识别列位置)
|
// 读取表格数据(先读取表头行用于识别列位置)
|
||||||
// 根据官方文档,使用 A1 表示法(Excel格式)
|
// 根据官方文档,使用 A1 表示法(Excel格式)
|
||||||
// 参考:https://docs.qq.com/open/document/app/openapi/v3/sheet/get/get_range.html
|
// 参考:https://docs.qq.com/open/document/app/openapi/v3/sheet/get/get_range.html
|
||||||
String headerRange = String.format("A%d:Z%d", headerRow, headerRow); // 例如:A2:Z2
|
String headerRange = String.format("A%d:Z%d", headerRow, headerRow); // 例如:A2:Z2
|
||||||
log.info("读取表头 - 行号: {}, range: {}", headerRow, headerRange);
|
log.info("读取表头 - 行号: {}, range: {}", headerRow, headerRange);
|
||||||
|
|
||||||
JSONObject headerData = null;
|
JSONObject headerData = null;
|
||||||
try {
|
try {
|
||||||
headerData = tencentDocService.readSheetData(accessToken, fileId, sheetId, headerRange);
|
headerData = tencentDocService.readSheetData(accessToken, fileId, sheetId, headerRange);
|
||||||
@@ -520,53 +520,53 @@ public class TencentDocController extends BaseController {
|
|||||||
log.error("读取表头失败", e);
|
log.error("读取表头失败", e);
|
||||||
return AjaxResult.error("读取表头失败: " + e.getMessage());
|
return AjaxResult.error("读取表头失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headerData == null) {
|
if (headerData == null) {
|
||||||
return AjaxResult.error("读取表头返回null,请检查Access Token是否有效或文档权限");
|
return AjaxResult.error("读取表头返回null,请检查Access Token是否有效或文档权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONArray headerValues = headerData.getJSONArray("values");
|
JSONArray headerValues = headerData.getJSONArray("values");
|
||||||
|
|
||||||
if (headerValues == null || headerValues.isEmpty()) {
|
if (headerValues == null || headerValues.isEmpty()) {
|
||||||
log.error("表头数据中values数组为空,完整响应: {}", headerData.toJSONString());
|
log.error("表头数据中values数组为空,完整响应: {}", headerData.toJSONString());
|
||||||
return AjaxResult.error("无法读取表头,请检查headerRow参数。API响应: " + headerData.toJSONString());
|
return AjaxResult.error("无法读取表头,请检查headerRow参数。API响应: " + headerData.toJSONString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动识别列位置(从表头中识别)
|
// 自动识别列位置(从表头中识别)
|
||||||
Integer orderNoColumn = null; // "单号"列
|
Integer orderNoColumn = null; // "单号"列
|
||||||
Integer logisticsLinkColumn = null; // "物流单号"列
|
Integer logisticsLinkColumn = null; // "物流单号"列
|
||||||
Integer arrangedColumn = null; // "是否安排"列
|
Integer arrangedColumn = null; // "是否安排"列
|
||||||
Integer markColumn = null; // "标记"列
|
Integer markColumn = null; // "标记"列
|
||||||
|
|
||||||
JSONArray headerRowData = headerValues.getJSONArray(0);
|
JSONArray headerRowData = headerValues.getJSONArray(0);
|
||||||
if (headerRowData == null || headerRowData.isEmpty()) {
|
if (headerRowData == null || headerRowData.isEmpty()) {
|
||||||
return AjaxResult.error("无法识别表头,表头数据为空");
|
return AjaxResult.error("无法识别表头,表头数据为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找所有相关列
|
// 查找所有相关列
|
||||||
for (int i = 0; i < headerRowData.size(); i++) {
|
for (int i = 0; i < headerRowData.size(); i++) {
|
||||||
String cellValue = headerRowData.getString(i);
|
String cellValue = headerRowData.getString(i);
|
||||||
if (cellValue != null) {
|
if (cellValue != null) {
|
||||||
String cellValueTrim = cellValue.trim();
|
String cellValueTrim = cellValue.trim();
|
||||||
|
|
||||||
// 识别"单号"列
|
// 识别"单号"列
|
||||||
if (orderNoColumn == null && cellValueTrim.contains("单号")) {
|
if (orderNoColumn == null && cellValueTrim.contains("单号")) {
|
||||||
orderNoColumn = i;
|
orderNoColumn = i;
|
||||||
log.info("✓ 识别到 '单号' 列:第 {} 列(索引{})", i + 1, i);
|
log.info("✓ 识别到 '单号' 列:第 {} 列(索引{})", i + 1, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 识别"物流单号"或"物流链接"列
|
// 识别"物流单号"或"物流链接"列
|
||||||
if (logisticsLinkColumn == null && (cellValueTrim.contains("物流单号") || cellValueTrim.contains("物流链接"))) {
|
if (logisticsLinkColumn == null && (cellValueTrim.contains("物流单号") || cellValueTrim.contains("物流链接"))) {
|
||||||
logisticsLinkColumn = i;
|
logisticsLinkColumn = i;
|
||||||
log.info("✓ 识别到 '物流单号' 列:第 {} 列(索引{})", i + 1, i);
|
log.info("✓ 识别到 '物流单号' 列:第 {} 列(索引{})", i + 1, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 识别"是否安排"列(可选)
|
// 识别"是否安排"列(可选)
|
||||||
if (arrangedColumn == null && cellValueTrim.contains("是否安排")) {
|
//if (arrangedColumn == null && cellValueTrim.contains("是否安排")) {
|
||||||
arrangedColumn = i;
|
// arrangedColumn = i;
|
||||||
log.info("✓ 识别到 '是否安排' 列:第 {} 列(索引{})", i + 1, i);
|
// log.info("✓ 识别到 '是否安排' 列:第 {} 列(索引{})", i + 1, i);
|
||||||
}
|
//}
|
||||||
|
|
||||||
// 识别"标记"列(可选)
|
// 识别"标记"列(可选)
|
||||||
if (markColumn == null && cellValueTrim.contains("标记")) {
|
if (markColumn == null && cellValueTrim.contains("标记")) {
|
||||||
markColumn = i;
|
markColumn = i;
|
||||||
@@ -574,7 +574,7 @@ public class TencentDocController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查必需的列是否都已识别
|
// 检查必需的列是否都已识别
|
||||||
if (orderNoColumn == null) {
|
if (orderNoColumn == null) {
|
||||||
return AjaxResult.error("无法找到'单号'列,请检查表头是否包含'单号'字段");
|
return AjaxResult.error("无法找到'单号'列,请检查表头是否包含'单号'字段");
|
||||||
@@ -582,7 +582,7 @@ public class TencentDocController extends BaseController {
|
|||||||
if (logisticsLinkColumn == null) {
|
if (logisticsLinkColumn == null) {
|
||||||
return AjaxResult.error("无法找到'物流单号'或'物流链接'列,请检查表头");
|
return AjaxResult.error("无法找到'物流单号'或'物流链接'列,请检查表头");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提示可选列的识别情况
|
// 提示可选列的识别情况
|
||||||
if (arrangedColumn == null) {
|
if (arrangedColumn == null) {
|
||||||
log.warn("未找到'是否安排'列,将跳过该字段的更新");
|
log.warn("未找到'是否安排'列,将跳过该字段的更新");
|
||||||
@@ -590,15 +590,15 @@ public class TencentDocController extends BaseController {
|
|||||||
if (markColumn == null) {
|
if (markColumn == null) {
|
||||||
log.warn("未找到'标记'列,将跳过该字段的更新");
|
log.warn("未找到'标记'列,将跳过该字段的更新");
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("列位置识别完成 - 单号: {}, 物流单号: {}, 是否安排: {}, 标记: {}",
|
log.info("列位置识别完成 - 单号: {}, 物流单号: {}, 是否安排: {}, 标记: {}",
|
||||||
orderNoColumn, logisticsLinkColumn, arrangedColumn, markColumn);
|
orderNoColumn, logisticsLinkColumn, arrangedColumn, markColumn);
|
||||||
|
|
||||||
// 读取数据行
|
// 读取数据行
|
||||||
// 使用 A1 表示法(Excel格式)
|
// 使用 A1 表示法(Excel格式)
|
||||||
String range = String.format("A%d:Z%d", startRow, endRow); // 例如:A3:Z203
|
String range = String.format("A%d:Z%d", startRow, endRow); // 例如:A3:Z203
|
||||||
log.info("开始读取数据行 - 行号: {} ~ {}, range: {}", startRow, endRow, range);
|
log.info("开始读取数据行 - 行号: {} ~ {}, range: {}", startRow, endRow, range);
|
||||||
|
|
||||||
JSONObject sheetData = null;
|
JSONObject sheetData = null;
|
||||||
try {
|
try {
|
||||||
sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range);
|
sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range);
|
||||||
@@ -607,23 +607,23 @@ public class TencentDocController extends BaseController {
|
|||||||
log.error("读取数据行失败", e);
|
log.error("读取数据行失败", e);
|
||||||
return AjaxResult.error("读取数据行失败: " + e.getMessage());
|
return AjaxResult.error("读取数据行失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sheetData == null) {
|
if (sheetData == null) {
|
||||||
return AjaxResult.error("读取数据行返回null");
|
return AjaxResult.error("读取数据行返回null");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONArray values = sheetData.getJSONArray("values");
|
JSONArray values = sheetData.getJSONArray("values");
|
||||||
log.info("解析后的数据行数: {}", values != null ? values.size() : "null");
|
log.info("解析后的数据行数: {}", values != null ? values.size() : "null");
|
||||||
|
|
||||||
if (values == null || values.isEmpty()) {
|
if (values == null || values.isEmpty()) {
|
||||||
log.warn("指定范围内没有数据,可能已处理完毕。range={}, sheetData keys={}",
|
log.warn("指定范围内没有数据,可能已处理完毕。range={}, sheetData keys={}",
|
||||||
range, sheetData.keySet());
|
range, sheetData.keySet());
|
||||||
|
|
||||||
// 打印前10个键值对用于调试
|
// 打印前10个键值对用于调试
|
||||||
if (sheetData != null && !sheetData.isEmpty()) {
|
if (sheetData != null && !sheetData.isEmpty()) {
|
||||||
log.warn("sheetData内容预览: {}", sheetData.toJSONString().substring(0, Math.min(500, sheetData.toJSONString().length())));
|
log.warn("sheetData内容预览: {}", sheetData.toJSONString().substring(0, Math.min(500, sheetData.toJSONString().length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
result.put("startRow", startRow);
|
result.put("startRow", startRow);
|
||||||
result.put("endRow", endRow);
|
result.put("endRow", endRow);
|
||||||
@@ -637,50 +637,50 @@ public class TencentDocController extends BaseController {
|
|||||||
result.put("sheetDataKeys", sheetData != null ? sheetData.keySet() : null);
|
result.put("sheetDataKeys", sheetData != null ? sheetData.keySet() : null);
|
||||||
return AjaxResult.success("没有需要处理的数据", result);
|
return AjaxResult.success("没有需要处理的数据", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("成功读取 {} 行数据,开始处理...", values.size());
|
log.info("成功读取 {} 行数据,开始处理...", values.size());
|
||||||
|
|
||||||
// 处理数据行
|
// 处理数据行
|
||||||
int filledCount = 0;
|
int filledCount = 0;
|
||||||
int skippedCount = 0;
|
int skippedCount = 0;
|
||||||
int errorCount = 0;
|
int errorCount = 0;
|
||||||
int currentMaxRow = startRow - 1; // 记录当前处理的最大行号(Excel行号,从1开始)
|
int currentMaxRow = startRow - 1; // 记录当前处理的最大行号(Excel行号,从1开始)
|
||||||
|
|
||||||
JSONArray updates = new JSONArray(); // 存储需要更新的行和值
|
JSONArray updates = new JSONArray(); // 存储需要更新的行和值
|
||||||
|
|
||||||
for (int i = 0; i < values.size(); i++) {
|
for (int i = 0; i < values.size(); i++) {
|
||||||
JSONArray row = values.getJSONArray(i);
|
JSONArray row = values.getJSONArray(i);
|
||||||
if (row == null || row.size() <= Math.max(orderNoColumn, logisticsLinkColumn)) {
|
if (row == null || row.size() <= Math.max(orderNoColumn, logisticsLinkColumn)) {
|
||||||
continue; // 跳过空行或列数不足的行
|
continue; // 跳过空行或列数不足的行
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算实际的行号(Excel行号,从1开始)
|
// 计算实际的行号(Excel行号,从1开始)
|
||||||
int excelRow = startRow + i;
|
int excelRow = startRow + i;
|
||||||
currentMaxRow = Math.max(currentMaxRow, excelRow);
|
currentMaxRow = Math.max(currentMaxRow, excelRow);
|
||||||
|
|
||||||
// 获取单号
|
// 获取单号
|
||||||
String orderNo = row.getString(orderNoColumn);
|
String orderNo = row.getString(orderNoColumn);
|
||||||
if (orderNo == null || orderNo.trim().isEmpty()) {
|
if (orderNo == null || orderNo.trim().isEmpty()) {
|
||||||
skippedCount++;
|
skippedCount++;
|
||||||
continue; // 跳过空单号的行
|
continue; // 跳过空单号的行
|
||||||
}
|
}
|
||||||
|
|
||||||
orderNo = orderNo.trim();
|
orderNo = orderNo.trim();
|
||||||
|
|
||||||
// 检查物流链接列是否已有值
|
// 检查物流链接列是否已有值
|
||||||
String existingLogisticsLink = row.getString(logisticsLinkColumn);
|
String existingLogisticsLink = row.getString(logisticsLinkColumn);
|
||||||
if (existingLogisticsLink != null && !existingLogisticsLink.trim().isEmpty()) {
|
if (existingLogisticsLink != null && !existingLogisticsLink.trim().isEmpty()) {
|
||||||
skippedCount++; // 已有物流链接,跳过
|
skippedCount++; // 已有物流链接,跳过
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 根据第三方单号查询订单
|
// 根据第三方单号查询订单
|
||||||
JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo);
|
JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo);
|
||||||
|
|
||||||
if (order != null && order.getLogisticsLink() != null && !order.getLogisticsLink().trim().isEmpty()) {
|
if (order != null && order.getLogisticsLink() != null && !order.getLogisticsLink().trim().isEmpty()) {
|
||||||
String logisticsLink = order.getLogisticsLink().trim();
|
String logisticsLink = order.getLogisticsLink().trim();
|
||||||
|
|
||||||
// 构建更新请求
|
// 构建更新请求
|
||||||
JSONObject update = new JSONObject();
|
JSONObject update = new JSONObject();
|
||||||
update.put("row", excelRow);
|
update.put("row", excelRow);
|
||||||
@@ -688,7 +688,7 @@ public class TencentDocController extends BaseController {
|
|||||||
update.put("orderNo", orderNo);
|
update.put("orderNo", orderNo);
|
||||||
update.put("logisticsLink", logisticsLink);
|
update.put("logisticsLink", logisticsLink);
|
||||||
updates.add(update);
|
updates.add(update);
|
||||||
|
|
||||||
filledCount++;
|
filledCount++;
|
||||||
log.info("找到订单物流链接 - 单号: {}, 物流链接: {}, 行号: {}", orderNo, logisticsLink, excelRow);
|
log.info("找到订单物流链接 - 单号: {}, 物流链接: {}, 行号: {}", orderNo, logisticsLink, excelRow);
|
||||||
} else {
|
} else {
|
||||||
@@ -700,12 +700,12 @@ public class TencentDocController extends BaseController {
|
|||||||
log.error("处理订单失败 - 单号: {}, 行号: {}", orderNo, excelRow, e);
|
log.error("处理订单失败 - 单号: {}, 行号: {}", orderNo, excelRow, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量更新表格
|
// 批量更新表格
|
||||||
if (!updates.isEmpty()) {
|
if (!updates.isEmpty()) {
|
||||||
// 获取今天的日期,格式:yyMMdd(如:251105)
|
// 获取今天的日期,格式:yyMMdd(如:251105)
|
||||||
String today = new java.text.SimpleDateFormat("yyMMdd").format(new java.util.Date());
|
String today = new java.text.SimpleDateFormat("yyMMdd").format(new java.util.Date());
|
||||||
|
|
||||||
// 将更新按行分组,批量写入
|
// 将更新按行分组,批量写入
|
||||||
Map<Integer, JSONObject> rowUpdates = new java.util.HashMap<>();
|
Map<Integer, JSONObject> rowUpdates = new java.util.HashMap<>();
|
||||||
for (int i = 0; i < updates.size(); i++) {
|
for (int i = 0; i < updates.size(); i++) {
|
||||||
@@ -713,7 +713,7 @@ public class TencentDocController extends BaseController {
|
|||||||
int row = update.getIntValue("row");
|
int row = update.getIntValue("row");
|
||||||
rowUpdates.put(row, update);
|
rowUpdates.put(row, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量写入(每行单独写入,同时更新多个字段)
|
// 批量写入(每行单独写入,同时更新多个字段)
|
||||||
int successUpdates = 0;
|
int successUpdates = 0;
|
||||||
for (Map.Entry<Integer, JSONObject> entry : rowUpdates.entrySet()) {
|
for (Map.Entry<Integer, JSONObject> entry : rowUpdates.entrySet()) {
|
||||||
@@ -722,38 +722,38 @@ public class TencentDocController extends BaseController {
|
|||||||
JSONObject update = entry.getValue();
|
JSONObject update = entry.getValue();
|
||||||
String logisticsLink = update.getString("logisticsLink");
|
String logisticsLink = update.getString("logisticsLink");
|
||||||
String orderNo = update.getString("orderNo");
|
String orderNo = update.getString("orderNo");
|
||||||
|
|
||||||
// 使用 batchUpdate 一次性更新多个字段
|
// 使用 batchUpdate 一次性更新多个字段
|
||||||
JSONArray requests = new JSONArray();
|
JSONArray requests = new JSONArray();
|
||||||
|
|
||||||
// 1. 更新物流单号
|
// 1. 更新物流单号
|
||||||
requests.add(buildUpdateCellRequest(sheetId, row - 1, logisticsLinkColumn, logisticsLink));
|
requests.add(buildUpdateCellRequest(sheetId, row - 1, logisticsLinkColumn, logisticsLink));
|
||||||
|
|
||||||
// 2. 更新"是否安排"列(如果存在)
|
// 2. 更新"是否安排"列(如果存在)
|
||||||
if (arrangedColumn != null) {
|
if (arrangedColumn != null) {
|
||||||
requests.add(buildUpdateCellRequest(sheetId, row - 1, arrangedColumn, "2"));
|
requests.add(buildUpdateCellRequest(sheetId, row - 1, arrangedColumn, "2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 更新"标记"列(如果存在)
|
// 3. 更新"标记"列(如果存在)
|
||||||
if (markColumn != null) {
|
if (markColumn != null) {
|
||||||
requests.add(buildUpdateCellRequest(sheetId, row - 1, markColumn, today));
|
requests.add(buildUpdateCellRequest(sheetId, row - 1, markColumn, today));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建完整的 batchUpdate 请求体
|
// 构建完整的 batchUpdate 请求体
|
||||||
JSONObject batchUpdateBody = new JSONObject();
|
JSONObject batchUpdateBody = new JSONObject();
|
||||||
batchUpdateBody.put("requests", requests);
|
batchUpdateBody.put("requests", requests);
|
||||||
|
|
||||||
// 调用 batchUpdate API
|
// 调用 batchUpdate API
|
||||||
tencentDocService.batchUpdate(accessToken, fileId, batchUpdateBody);
|
tencentDocService.batchUpdate(accessToken, fileId, batchUpdateBody);
|
||||||
successUpdates++;
|
successUpdates++;
|
||||||
|
|
||||||
log.info("成功写入数据 - 行: {}, 单号: {}, 物流链接: {}, 是否安排: 2, 标记: {}",
|
log.info("成功写入数据 - 行: {}, 单号: {}, 物流链接: {}, 是否安排: 2, 标记: {}",
|
||||||
row, orderNo, logisticsLink, today);
|
row, orderNo, logisticsLink, today);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("写入数据失败 - 行: {}", entry.getKey(), e);
|
log.error("写入数据失败 - 行: {}", entry.getKey(), e);
|
||||||
errorCount++;
|
errorCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加延迟,避免API调用频率过高
|
// 添加延迟,避免API调用频率过高
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100); // 100ms延迟
|
Thread.sleep(100); // 100ms延迟
|
||||||
@@ -761,16 +761,16 @@ public class TencentDocController extends BaseController {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("批量填充物流链接完成 - 成功: {}, 跳过: {}, 错误: {}", successUpdates, skippedCount, errorCount);
|
log.info("批量填充物流链接完成 - 成功: {}, 跳过: {}, 错误: {}", successUpdates, skippedCount, errorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新Redis中记录的最大行数(如果本次处理了数据)
|
// 更新Redis中记录的最大行数(如果本次处理了数据)
|
||||||
if (currentMaxRow >= startRow) {
|
if (currentMaxRow >= startRow) {
|
||||||
redisCache.setCacheObject(redisKey, currentMaxRow, 30, TimeUnit.DAYS);
|
redisCache.setCacheObject(redisKey, currentMaxRow, 30, TimeUnit.DAYS);
|
||||||
log.info("更新上次处理的最大行数 - 文件ID: {}, 工作表ID: {}, 最大行: {}", fileId, sheetId, currentMaxRow);
|
log.info("更新上次处理的最大行数 - 文件ID: {}, 工作表ID: {}, 最大行: {}", fileId, sheetId, currentMaxRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject result = new JSONObject();
|
JSONObject result = new JSONObject();
|
||||||
result.put("startRow", startRow);
|
result.put("startRow", startRow);
|
||||||
result.put("endRow", endRow);
|
result.put("endRow", endRow);
|
||||||
@@ -781,19 +781,19 @@ public class TencentDocController extends BaseController {
|
|||||||
result.put("errorCount", errorCount);
|
result.put("errorCount", errorCount);
|
||||||
result.put("orderNoColumn", orderNoColumn);
|
result.put("orderNoColumn", orderNoColumn);
|
||||||
result.put("logisticsLinkColumn", logisticsLinkColumn);
|
result.put("logisticsLinkColumn", logisticsLinkColumn);
|
||||||
result.put("message", String.format("处理完成:成功填充 %d 条,跳过 %d 条,错误 %d 条,最大行号: %d",
|
result.put("message", String.format("处理完成:成功填充 %d 条,跳过 %d 条,错误 %d 条,最大行号: %d",
|
||||||
filledCount, skippedCount, errorCount, currentMaxRow));
|
filledCount, skippedCount, errorCount, currentMaxRow));
|
||||||
|
|
||||||
return AjaxResult.success("填充物流链接完成", result);
|
return AjaxResult.success("填充物流链接完成", result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("填充物流链接失败", e);
|
log.error("填充物流链接失败", e);
|
||||||
return AjaxResult.error("填充物流链接失败: " + e.getMessage());
|
return AjaxResult.error("填充物流链接失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建单个单元格的更新请求(用于 batchUpdate)
|
* 构建单个单元格的更新请求(用于 batchUpdate)
|
||||||
*
|
*
|
||||||
* @param sheetId 工作表ID
|
* @param sheetId 工作表ID
|
||||||
* @param rowIndex 行索引(从0开始)
|
* @param rowIndex 行索引(从0开始)
|
||||||
* @param columnIndex 列索引(从0开始)
|
* @param columnIndex 列索引(从0开始)
|
||||||
@@ -804,37 +804,37 @@ public class TencentDocController extends BaseController {
|
|||||||
// 构建 updateRangeRequest
|
// 构建 updateRangeRequest
|
||||||
JSONObject updateRangeRequest = new JSONObject();
|
JSONObject updateRangeRequest = new JSONObject();
|
||||||
updateRangeRequest.put("sheetId", sheetId);
|
updateRangeRequest.put("sheetId", sheetId);
|
||||||
|
|
||||||
// 构建 gridData
|
// 构建 gridData
|
||||||
JSONObject gridData = new JSONObject();
|
JSONObject gridData = new JSONObject();
|
||||||
gridData.put("startRow", rowIndex);
|
gridData.put("startRow", rowIndex);
|
||||||
gridData.put("startColumn", columnIndex);
|
gridData.put("startColumn", columnIndex);
|
||||||
|
|
||||||
// 构建 rows 数组
|
// 构建 rows 数组
|
||||||
JSONArray rows = new JSONArray();
|
JSONArray rows = new JSONArray();
|
||||||
JSONObject rowData = new JSONObject();
|
JSONObject rowData = new JSONObject();
|
||||||
JSONArray cellValues = new JSONArray();
|
JSONArray cellValues = new JSONArray();
|
||||||
|
|
||||||
// 构建单元格数据
|
// 构建单元格数据
|
||||||
JSONObject cellData = new JSONObject();
|
JSONObject cellData = new JSONObject();
|
||||||
JSONObject cellValue = new JSONObject();
|
JSONObject cellValue = new JSONObject();
|
||||||
cellValue.put("text", value);
|
cellValue.put("text", value);
|
||||||
cellData.put("cellValue", cellValue);
|
cellData.put("cellValue", cellValue);
|
||||||
cellValues.add(cellData);
|
cellValues.add(cellData);
|
||||||
|
|
||||||
rowData.put("values", cellValues);
|
rowData.put("values", cellValues);
|
||||||
rows.add(rowData);
|
rows.add(rowData);
|
||||||
gridData.put("rows", rows);
|
gridData.put("rows", rows);
|
||||||
|
|
||||||
updateRangeRequest.put("gridData", gridData);
|
updateRangeRequest.put("gridData", gridData);
|
||||||
|
|
||||||
// 包装为 request 对象
|
// 包装为 request 对象
|
||||||
JSONObject request = new JSONObject();
|
JSONObject request = new JSONObject();
|
||||||
request.put("updateRangeRequest", updateRangeRequest);
|
request.put("updateRangeRequest", updateRangeRequest);
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将列索引转换为Excel列字母(0->A, 1->B, ..., 25->Z, 26->AA, ...)
|
* 将列索引转换为Excel列字母(0->A, 1->B, ..., 25->Z, 26->AA, ...)
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user