feat(device): 实现设备与账号绑定管理机制

- 引入 ClientAccountDevice 表管理设备与账号绑定关系
- 重构设备注册逻辑,支持多账号绑定同一设备
- 新增设备配额检查,基于账号维度限制设备数量
-优化设备移除逻辑,仅解除绑定而非物理删除- 改进设备列表查询,通过账号ID关联获取设备信息
- 更新心跳任务,支持向设备绑定的所有账号发送心跳
- 调整设备API参数,增加username字段用于权限校验
-修复HTTP请求编码问题,统一使用UTF-8字符集
- 增强错误处理,携带错误码信息便于前端识别
- 移除设备表中的username字段,解耦设备与用户名关联
This commit is contained in:
2025-10-22 09:51:55 +08:00
parent 901d67d2dc
commit 17b6a7b9f9
29 changed files with 589 additions and 277 deletions

View File

@@ -10,7 +10,7 @@
</parent>
<groupId>com.tashow.erp</groupId>
<artifactId>erp_client_sb</artifactId>
<version>2.4.7</version>
<version>2.4.8</version>
<name>erp_client_sb</name>
<description>erp客户端</description>
<properties>

View File

@@ -92,12 +92,7 @@ public class Alibaba1688ServiceImpl implements Alibaba1688Service {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("data", jsonData);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
Iterator<JsonNode> offerIterator = null;
for (int retry = 0; retry < 3 && (offerIterator == null || !offerIterator.hasNext()); retry++) {
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
JsonNode root = objectMapper.readTree(response.getBody());
offerIterator = root.path("data").path("offerList").path("offers").elements();
}
Iterator<JsonNode> offerIterator = getOfferIterator(url, requestEntity);
//运费 - 收集所有运费数据
Set<Double> freight = new HashSet<>();
while (offerIterator.hasNext()) {
@@ -111,12 +106,7 @@ public class Alibaba1688ServiceImpl implements Alibaba1688Service {
.filter(fee -> fee > 0)
.ifPresent(freight::add);
}
offerIterator = null;
for (int retry = 0; retry < 3 && (offerIterator == null || !offerIterator.hasNext()); retry++) {
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
JsonNode root = objectMapper.readTree(response.getBody());
offerIterator = root.path("data").path("offerList").path("offers").elements();
}
offerIterator = getOfferIterator(url, requestEntity);
for (int i = 0; i < 10 && offerIterator.hasNext(); i++) {
JsonNode offer = offerIterator.next();
String offerId = offer.path("id").asText();
@@ -162,6 +152,15 @@ public class Alibaba1688ServiceImpl implements Alibaba1688Service {
}
}
private Iterator<JsonNode> getOfferIterator(String url, HttpEntity<MultiValueMap<String, String>> requestEntity) throws IOException {
for (int retry = 0; retry < 3; retry++) {
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
JsonNode root = objectMapper.readTree(response.getBody());
Iterator<JsonNode> iterator = root.path("data").path("offerList").path("offers").elements();
if (iterator.hasNext()) return iterator;
}
return Collections.emptyIterator();
}
/**
* 获取sku价格
@@ -252,7 +251,16 @@ public class Alibaba1688ServiceImpl implements Alibaba1688Service {
public String uploadImageBase64(String imageUrl) {
String token = Alibaba1688CookieUtil.getToken();
long timestamp = System.currentTimeMillis();
byte[] imageBytes = noSslRestTemplate.getForObject(imageUrl, byte[].class);
byte[] imageBytes = null;
for (int i = 0; i < 3; i++) {
try {
imageBytes = noSslRestTemplate.getForObject(imageUrl, byte[].class);
break;
} catch (Exception e) {
if (i == 2) throw e;
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
}
}
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
String jsonData = "{\"appId\":32517,\"params\":\"{\\\"searchScene\\\":\\\"imageEx\\\",\\\"interfaceName\\\":\\\"imageBase64ToImageId\\\",\\\"serviceParam.extendParam[imageBase64]\\\":\\\"" + base64Image + "\\\",\\\"subChannel\\\":\\\"pc_image_search_image_id\\\"}\"}";
String sign = Alibaba1688CookieUtil.generateSign(token, String.valueOf(timestamp), jsonData);