222
This commit is contained in:
parent
90ecbd90cd
commit
1388d39376
@ -209,6 +209,7 @@ public class BanmaOrderController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private String getTrackingInfo(String trackingNumber) {
|
private String getTrackingInfo(String trackingNumber) {
|
||||||
|
try {
|
||||||
R<Map<String, Object>> sagawaResult = sagawaExpressController.getTrackingInfo(trackingNumber);
|
R<Map<String, Object>> sagawaResult = sagawaExpressController.getTrackingInfo(trackingNumber);
|
||||||
if (sagawaResult != null && sagawaResult.getCode() == 200) {
|
if (sagawaResult != null && sagawaResult.getCode() == 200) {
|
||||||
Map<String, Object> sagawaData = sagawaResult.getData();
|
Map<String, Object> sagawaData = sagawaResult.getData();
|
||||||
@ -223,23 +224,31 @@ public class BanmaOrderController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
String url = String.format(TRACKING_URL, trackingNumber);
|
// 如果从佐川获取失败,尝试从斑马API获取
|
||||||
ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
|
try {
|
||||||
Map<String, Object> responseBody = response.getBody();
|
String url = String.format(TRACKING_URL, trackingNumber);
|
||||||
if (responseBody != null && Integer.valueOf(0).equals(responseBody.get("code"))) {
|
ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
|
||||||
return Optional.ofNullable(responseBody.get("data"))
|
Map<String, Object> responseBody = response.getBody();
|
||||||
.map(data -> (List<Map<String, Object>>) data)
|
if (responseBody != null && Integer.valueOf(0).equals(responseBody.get("code"))) {
|
||||||
.filter(list -> !list.isEmpty())
|
return Optional.ofNullable(responseBody.get("data"))
|
||||||
.map(list -> list.get(0))
|
.map(data -> (List<Map<String, Object>>) data)
|
||||||
.map(track -> (String) track.get("track"))
|
.filter(list -> !list.isEmpty())
|
||||||
.orElse(null);
|
.map(list -> list.get(0))
|
||||||
|
.map(track -> (String) track.get("track"))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("从斑马API获取物流信息失败: {}", e.getMessage());
|
||||||
|
// 继续处理,不中断流程
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("获取物流信息失败: {}", e.getMessage());
|
logger.error("获取物流信息失败: {}", e.getMessage());
|
||||||
|
// 继续处理,不中断流程
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
// 如果所有尝试都失败,返回默认值
|
||||||
|
return "暂无物流信息";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -298,7 +307,8 @@ public class BanmaOrderController extends BaseController {
|
|||||||
|
|
||||||
// 计算分页信息
|
// 计算分页信息
|
||||||
int totalPages = (int) Math.ceil((double) totalCount / DEFAULT_PAGE_SIZE);
|
int totalPages = (int) Math.ceil((double) totalCount / DEFAULT_PAGE_SIZE);
|
||||||
boolean hasMore = orders.size() == DEFAULT_PAGE_SIZE;
|
// 修改hasMore判断逻辑,根据当前页数和总页数判断
|
||||||
|
boolean hasMore = totalCount > 0 && 1 < totalPages;
|
||||||
|
|
||||||
// 构建结果
|
// 构建结果
|
||||||
Map<String, Object> resultMap = new HashMap<>();
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
@ -340,12 +350,26 @@ public class BanmaOrderController extends BaseController {
|
|||||||
@ApiParam("开始日期(yyyy-MM-dd)") @RequestParam(required = false) String startDate,
|
@ApiParam("开始日期(yyyy-MM-dd)") @RequestParam(required = false) String startDate,
|
||||||
@ApiParam("结束日期(yyyy-MM-dd)") @RequestParam(required = false) String endDate) {
|
@ApiParam("结束日期(yyyy-MM-dd)") @RequestParam(required = false) String endDate) {
|
||||||
|
|
||||||
DeferredResult<R<Map<String, Object>>> deferredResult = new DeferredResult<>(120000L);
|
DeferredResult<R<Map<String, Object>>> deferredResult = new DeferredResult<>(999999999L);
|
||||||
|
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
if (deferredResult.isSetOrExpired()) return;
|
if (deferredResult.isSetOrExpired()) return;
|
||||||
|
|
||||||
|
// 获取总页数信息
|
||||||
|
HttpEntity<String> entity = createHttpEntity();
|
||||||
|
String url = buildApiUrl(1, DEFAULT_PAGE_SIZE, startDate, endDate);
|
||||||
|
ResponseEntity<Map> countResponse = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
|
||||||
|
Map<String, Object> countResponseBody = countResponse.getBody();
|
||||||
|
int totalPages = 1;
|
||||||
|
|
||||||
|
if (countResponseBody != null && countResponseBody.containsKey("data")) {
|
||||||
|
Map<String, Object> dataMap = (Map<String, Object>) countResponseBody.get("data");
|
||||||
|
int totalCount = ((Number) dataMap.getOrDefault("total", 0)).intValue();
|
||||||
|
totalPages = (int) Math.ceil((double) totalCount / DEFAULT_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前页数据
|
||||||
R<List<Map<String, Object>>> pageResult = fetchOrdersFromApi(page, DEFAULT_PAGE_SIZE, startDate, endDate);
|
R<List<Map<String, Object>>> pageResult = fetchOrdersFromApi(page, DEFAULT_PAGE_SIZE, startDate, endDate);
|
||||||
|
|
||||||
if (pageResult.getCode() != 200) {
|
if (pageResult.getCode() != 200) {
|
||||||
@ -355,10 +379,14 @@ public class BanmaOrderController extends BaseController {
|
|||||||
|
|
||||||
List<Map<String, Object>> pageData = pageResult.getData();
|
List<Map<String, Object>> pageData = pageResult.getData();
|
||||||
|
|
||||||
|
// 修改hasMore判断逻辑,根据当前页数和总页数判断
|
||||||
|
boolean hasMore = page < totalPages;
|
||||||
|
|
||||||
Map<String, Object> resultMap = new HashMap<>();
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
resultMap.put("orders", pageData);
|
resultMap.put("orders", pageData);
|
||||||
resultMap.put("hasMore", pageData != null && pageData.size() == DEFAULT_PAGE_SIZE);
|
resultMap.put("hasMore", hasMore);
|
||||||
resultMap.put("nextPage", page + 1);
|
resultMap.put("nextPage", page + 1);
|
||||||
|
resultMap.put("totalPages", totalPages);
|
||||||
|
|
||||||
setDeferredResult(deferredResult, R.ok(resultMap));
|
setDeferredResult(deferredResult, R.ok(resultMap));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -369,7 +397,6 @@ public class BanmaOrderController extends BaseController {
|
|||||||
|
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
return deferredResult;
|
return deferredResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
package com.ruoyi.web.controller.tool;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
|
import com.ruoyi.common.core.domain.R;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
|
||||||
|
import us.codecraft.webmagic.Page;
|
||||||
|
import us.codecraft.webmagic.Site;
|
||||||
|
import us.codecraft.webmagic.Spider;
|
||||||
|
import us.codecraft.webmagic.processor.PageProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 佐川急便物流查询控制器
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Api("佐川急便物流查询接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tool/sagawa")
|
||||||
|
@Anonymous
|
||||||
|
public class SagawaExpressController extends BaseController implements PageProcessor {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(SagawaExpressController.class);
|
||||||
|
|
||||||
|
// 站点配置
|
||||||
|
private final Site site = Site.me()
|
||||||
|
.setRetryTimes(3)
|
||||||
|
.setSleepTime(1000)
|
||||||
|
.setTimeOut(99999999)
|
||||||
|
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
|
||||||
|
|
||||||
|
// 查询结果
|
||||||
|
private Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
@Override
|
||||||
|
public void process(Page page) {
|
||||||
|
try {
|
||||||
|
String pageContent = page.getHtml().toString();
|
||||||
|
|
||||||
|
// 检查是否有包裹数据未登记的信息
|
||||||
|
boolean hasNoData = pageContent.contains("お荷物データが登録されておりません");
|
||||||
|
|
||||||
|
if (hasNoData) {
|
||||||
|
resultMap.put("status", "notFound");
|
||||||
|
resultMap.put("message", "没有找到对应的包裹信息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String trackingTableRegex = "<table[^>]*class=\"table_basic table_okurijo_detail2\"[^>]*>\\s*<tbody>\\s*(?:<tr>.*?<th[^>]*>荷物状況</th>.*?</tr>.*?<tr>.*?</tr>.*?)+\\s*</tbody>\\s*</table>";
|
||||||
|
Pattern pattern = Pattern.compile(trackingTableRegex, Pattern.DOTALL);
|
||||||
|
Matcher matcher = pattern.matcher(pageContent);
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
String trackingTable = matcher.group(0);
|
||||||
|
|
||||||
|
// 提取表格中的最后一行
|
||||||
|
String rowRegex = "<tr>\\s*<td>\\s*([^<]*?)\\s*</td>\\s*<td>\\s*([^<]*?)\\s*</td>\\s*<td>\\s*([^<]*?)\\s*</td>\\s*</tr>";
|
||||||
|
Pattern rowPattern = Pattern.compile(rowRegex, Pattern.DOTALL);
|
||||||
|
Matcher rowMatcher = rowPattern.matcher(trackingTable);
|
||||||
|
|
||||||
|
String status = "";
|
||||||
|
String dateTime = "";
|
||||||
|
String office = "";
|
||||||
|
|
||||||
|
// 找到所有匹配项,保留最后一个
|
||||||
|
while (rowMatcher.find()) {
|
||||||
|
status = rowMatcher.group(1).trim();
|
||||||
|
dateTime = rowMatcher.group(2).trim();
|
||||||
|
office = rowMatcher.group(3).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!status.isEmpty()) {
|
||||||
|
Map<String, String> trackInfo = new HashMap<>();
|
||||||
|
trackInfo.put("status", status);
|
||||||
|
trackInfo.put("dateTime", dateTime);
|
||||||
|
trackInfo.put("office", office);
|
||||||
|
|
||||||
|
resultMap.put("status", "success");
|
||||||
|
resultMap.put("trackInfo", trackInfo);
|
||||||
|
} else {
|
||||||
|
resultMap.put("status", "noRecords");
|
||||||
|
resultMap.put("message", "没有物流记录");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultMap.put("status", "noTable");
|
||||||
|
resultMap.put("message", "未找到物流跟踪表格");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("解析页面失败", e);
|
||||||
|
resultMap.put("status", "error");
|
||||||
|
resultMap.put("message", "解析页面失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Site getSite() {
|
||||||
|
return site;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建佐川急便查询URL
|
||||||
|
*/
|
||||||
|
private String buildSagawaUrl(String trackingNumber) {
|
||||||
|
return "https://k2k.sagawa-exp.co.jp/p/web/okurijosearch.do?okurijoNo=" + trackingNumber.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询佐川急便物流信息
|
||||||
|
*/
|
||||||
|
@ApiOperation("查询佐川急便物流信息")
|
||||||
|
@GetMapping("/tracking/{trackingNumber}")
|
||||||
|
public R<Map<String, Object>> getTrackingInfo(@PathVariable("trackingNumber") String trackingNumber) {
|
||||||
|
try {
|
||||||
|
if (trackingNumber == null || trackingNumber.trim().isEmpty()) {
|
||||||
|
return R.fail("运单号不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
resultMap = new HashMap<>();
|
||||||
|
String url = buildSagawaUrl(trackingNumber);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Spider spider = Spider.create(this)
|
||||||
|
.addUrl(url)
|
||||||
|
.thread(1);
|
||||||
|
spider.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("爬取物流信息失败,运单号:" + trackingNumber, e);
|
||||||
|
Map<String, String> defaultTrackInfo = new HashMap<>();
|
||||||
|
defaultTrackInfo.put("status", "处理中");
|
||||||
|
defaultTrackInfo.put("dateTime", "");
|
||||||
|
defaultTrackInfo.put("office", "");
|
||||||
|
|
||||||
|
resultMap.put("status", "success");
|
||||||
|
resultMap.put("trackInfo", defaultTrackInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return R.ok(resultMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("查询物流信息失败", e);
|
||||||
|
Map<String, Object> errorResult = new HashMap<>();
|
||||||
|
errorResult.put("status", "error");
|
||||||
|
errorResult.put("message", "查询物流信息失败: " + e.getMessage());
|
||||||
|
return R.ok(errorResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,11 +17,13 @@ const service = axios.create({
|
|||||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||||
baseURL: process.env.VUE_APP_BASE_API,
|
baseURL: process.env.VUE_APP_BASE_API,
|
||||||
// 超时
|
// 超时
|
||||||
timeout: 10000
|
timeout: 99999999
|
||||||
})
|
})
|
||||||
|
|
||||||
// request拦截器
|
// request拦截器
|
||||||
service.interceptors.request.use(config => {
|
service.interceptors.request.use(config => {
|
||||||
|
config.timeout = 99999999;
|
||||||
|
|
||||||
// 是否需要设置 token
|
// 是否需要设置 token
|
||||||
const isToken = (config.headers || {}).isToken === false
|
const isToken = (config.headers || {}).isToken === false
|
||||||
// 是否需要防止数据重复提交
|
// 是否需要防止数据重复提交
|
||||||
|
@ -84,8 +84,6 @@
|
|||||||
<div class="progress-container">
|
<div class="progress-container">
|
||||||
<el-progress
|
<el-progress
|
||||||
:percentage="loadProgress.percentage"
|
:percentage="loadProgress.percentage"
|
||||||
:format="progressFormat"
|
|
||||||
status="primary"
|
|
||||||
:stroke-width="12"
|
:stroke-width="12"
|
||||||
class="load-progress">
|
class="load-progress">
|
||||||
</el-progress>
|
</el-progress>
|
||||||
@ -343,15 +341,23 @@ export default {
|
|||||||
timeout: 99999999
|
timeout: 99999999
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
this.orderData = [...this.orderData, ...response.data.orders];
|
// 添加当前页数据
|
||||||
|
this.orderData = [...this.orderData, ...(response.data.orders || [])];
|
||||||
this.hasMore = response.data.hasMore;
|
this.hasMore = response.data.hasMore;
|
||||||
this.nextPage = response.data.nextPage;
|
this.nextPage = response.data.nextPage;
|
||||||
this.currentPage++;
|
this.currentPage++;
|
||||||
|
this.totalPages = response.data.totalPages || this.totalPages;
|
||||||
|
|
||||||
this.updateProgress();
|
this.updateProgress();
|
||||||
this.saveToCache();
|
this.saveToCache();
|
||||||
|
|
||||||
if (this.hasMore) {
|
console.log(`已加载第${this.currentPage}页,共${this.totalPages}页,hasMore=${this.hasMore}`);
|
||||||
|
|
||||||
|
// 如果hasMore为false,但当前页小于总页数,强制继续加载
|
||||||
|
if (!this.hasMore && this.currentPage < this.totalPages) {
|
||||||
|
this.hasMore = true;
|
||||||
|
this.autoLoadNextPage();
|
||||||
|
} else if (this.hasMore) {
|
||||||
this.autoLoadNextPage();
|
this.autoLoadNextPage();
|
||||||
} else {
|
} else {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@ -362,8 +368,22 @@ export default {
|
|||||||
this.$message.error(response.msg || "获取更多订单失败");
|
this.$message.error(response.msg || "获取更多订单失败");
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.loading = false;
|
|
||||||
this.$message.error("获取更多订单失败: " + (error.message || error));
|
this.nextPage++;
|
||||||
|
this.currentPage++;
|
||||||
|
|
||||||
|
// 更新进度条,即使加载失败也显示进度
|
||||||
|
this.updateProgress();
|
||||||
|
this.saveToCache();
|
||||||
|
|
||||||
|
// 如果还有更多页,继续尝试加载
|
||||||
|
if (this.currentPage < this.totalPages) {
|
||||||
|
this.$message.warning(`加载第${this.currentPage}页失败,尝试继续加载后续页面`);
|
||||||
|
this.autoLoadNextPage();
|
||||||
|
} else {
|
||||||
|
this.loading = false;
|
||||||
|
this.$message.error("获取更多订单失败: " + (error.message || error));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
},
|
},
|
||||||
@ -373,8 +393,10 @@ export default {
|
|||||||
let percentage;
|
let percentage;
|
||||||
if (this.totalRecords > 0) {
|
if (this.totalRecords > 0) {
|
||||||
percentage = Math.min(Math.round((this.orderData.length / this.totalRecords) * 100), 99);
|
percentage = Math.min(Math.round((this.orderData.length / this.totalRecords) * 100), 99);
|
||||||
} else {
|
} else if (this.totalPages > 1) {
|
||||||
percentage = Math.min(Math.round((this.currentPage / this.totalPages) * 100), 99);
|
percentage = Math.min(Math.round((this.currentPage / this.totalPages) * 100), 99);
|
||||||
|
} else {
|
||||||
|
percentage = this.currentPage > 0 ? 50 : 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadProgress = {
|
this.loadProgress = {
|
||||||
@ -384,10 +406,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 进度条格式化 */
|
|
||||||
progressFormat(percentage) {
|
|
||||||
return `已加载 ${this.currentPage}/${this.totalPages} 页,${this.orderData.length}/${this.totalRecords} 条数据`;
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 导出Excel */
|
/** 导出Excel */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
@ -670,7 +689,7 @@ export default {
|
|||||||
request({
|
request({
|
||||||
url: '/tool/banma/refresh-token',
|
url: '/tool/banma/refresh-token',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
timeout: 60000
|
timeout: 99999999
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
this.$message.success("Token刷新成功");
|
this.$message.success("Token刷新成功");
|
||||||
|
@ -671,7 +671,7 @@ export default {
|
|||||||
url: '/tool/webmagic/batch',
|
url: '/tool/webmagic/batch',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: currentBatch,
|
data: currentBatch,
|
||||||
timeout: 9000000
|
timeout: 99999999
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
this.productData = [...this.productData, ...response.data];
|
this.productData = [...this.productData, ...response.data];
|
||||||
@ -735,7 +735,7 @@ export default {
|
|||||||
url: '/tool/webmagic/batch',
|
url: '/tool/webmagic/batch',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: failedAsins,
|
data: failedAsins,
|
||||||
timeout: 99999000
|
timeout: 99999999
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
if (response.code === 200 && response.data) {
|
if (response.code === 200 && response.data) {
|
||||||
// 更新失败的ASIN数据
|
// 更新失败的ASIN数据
|
||||||
|
Loading…
x
Reference in New Issue
Block a user