feat:旷世接口定义

This commit is contained in:
dzc committed 2025-04-09 17:30:26 +08:00
1 parent 281c05e2c4
commit 7fedecc3bd
44 files changed
+1013 -25

No files matched your search

+1
View File
@@ -44,6 +44,7 @@ CREATE TABLE hard_door_manager
id bigint NOT NULL COMMENT '编号',
hard_id bigint NOT NULL COMMENT '设备编号',
imei varchar(32) NOT NULL COMMENT '设备 IMEI 号(15 位)',
device_code int DEFAULT NULL COMMENT '设备编号',
cabinet_num int DEFAULT NULL COMMENT '货柜数量',
cabinet_camera_num int DEFAULT NULL COMMENT '每个货柜中摄像头数量',
cabinet_weight_unit_num int DEFAULT NULL COMMENT '每个货柜中称重单元数量',
@@ -38,6 +38,12 @@ public class HardDoorManagerEntity extends Model<HardDoorManagerEntity> {
@Schema(description = "设备编号")
private Long hardId;
/**
* 内置设备编号
*/
@Schema(description = "内置设备编号")
private String deviceCode;
/**
* 设备 IMEI 号(15 位)
*/
@@ -42,6 +42,7 @@ public class HardDoorManagerController {
@PreAuthorize("@pms.hasPermission('hard_hardDoorManager_add')")
public R bind(@RequestBody HardDoorManagerEntity dto) {
if (ObjectUtil.isEmpty(dto.getImei())) throw new RuntimeException("设备IMEI卡号不能为空");
if (ObjectUtil.isEmpty(dto.getDeviceCode())) throw new RuntimeException("设备内置设备编号不能为空");
hardDoorManagerService.bind(dto);
return R.ok();
}
@@ -1,5 +1,6 @@
package com.bsd.pjcloud.hard.service.impl.manager;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.common.data.datascope.DataScope;
@@ -8,14 +9,27 @@ import com.bsd.pjcloud.hard.api.entity.manager.HardDoorManagerEntity;
import com.bsd.pjcloud.hard.api.vo.manager.HardDoorManagerVo;
import com.bsd.pjcloud.hard.mapper.manager.HardDoorManagerMapper;
import com.bsd.pjcloud.hard.service.HardDoorManagerService;
import com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdDoorApiService;
import com.bsd.pjcloud.thirdparty.dto.door.DoorBindDto;
import com.bsd.pjcloud.thirdparty.dto.door.DoorRegisterDto;
import com.bsd.pjcloud.thirdparty.vo.door.DoorBindVo;
import com.bsd.pjcloud.thirdparty.vo.door.DoorRegisterVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* 智能柜设置
*/
@Validated
@Slf4j
@RequiredArgsConstructor
@Service
public class HardDoorManagerServiceImpl extends ServiceImpl<HardDoorManagerMapper, HardDoorManagerEntity> implements HardDoorManagerService {
private final RemoterThirdDoorApiService thirdDoorApiService;
@Override
public Page<HardDoorManagerVo> scopePageJoin(Page page, HardDoorManagerDto dto, DataScope dataScope) {
return baseMapper.scopePageJoin(page, dto, dataScope);
@@ -34,10 +48,38 @@ public class HardDoorManagerServiceImpl extends ServiceImpl<HardDoorManagerMappe
*/
@Override
public void bind(HardDoorManagerEntity dto) {
HardDoorManagerEntity saveOrUpdate = new HardDoorManagerEntity();
saveOrUpdate.setId(dto.getId());
saveOrUpdate.setHardId(dto.getHardId());
saveOrUpdate.setImei(dto.getImei());
baseMapper.insertOrUpdate(saveOrUpdate);
// 查询设备
HardDoorManagerVo hardDoorDetail = getByHardId(dto.getHardId());
if (ObjectUtil.isEmpty(hardDoorDetail)) {
HardDoorManagerEntity saveOrUpdate = new HardDoorManagerEntity();
saveOrUpdate.setHardId(dto.getHardId());
saveOrUpdate.setImei(dto.getImei());
saveOrUpdate.setDeviceCode(dto.getDeviceCode());
baseMapper.insert(saveOrUpdate);
} else {
HardDoorManagerEntity saveOrUpdate = new HardDoorManagerEntity();
saveOrUpdate.setId(hardDoorDetail.getId());
saveOrUpdate.setHardId(dto.getHardId());
saveOrUpdate.setImei(dto.getImei());
saveOrUpdate.setDeviceCode(dto.getDeviceCode());
baseMapper.updateById(saveOrUpdate);
}
// 设备绑定
DoorBindDto bindDto = new DoorBindDto();
bindDto.setImei(dto.getImei());
bindDto.setDeviceCode(dto.getDeviceCode());
bindDto.setOutDeviceCode(String.valueOf(dto.getHardId()));
DoorBindVo bindVo = thirdDoorApiService.bind(bindDto).getData();
if (!bindVo.isSuccess()) {
throw new RuntimeException(bindVo.getMessage());
}
// 设备注册
DoorRegisterDto registerDto = new DoorRegisterDto();
registerDto.setImei(dto.getImei());
registerDto.setOutDeviceCode(String.valueOf(dto.getHardId()));
DoorRegisterVo registerVo = thirdDoorApiService.register(registerDto).getData();
if (!registerVo.isSuccess()) {
throw new RuntimeException(registerVo.getMessage());
}
}
}
@@ -6,6 +6,7 @@
<id property="id" column="id"/>
<result property="hardId" column="hard_id"/>
<result property="imei" column="imei"/>
<result property="deviceCode" column="device_code"/>
<result property="cabinetNum" column="cabinet_num"/>
<result property="cabinetCameraNum" column="cabinet_camera_num"/>
<result property="cabinetWeightUnitNum" column="cabinet_weight_unit_num"/>
@@ -29,6 +30,7 @@
select a.id,
a.hard_id,
a.imei,
a.device_code,
a.cabinet_num,
a.cabinet_camera_num,
a.cabinet_weight_unit_num,
@@ -56,6 +58,9 @@
<if test="dto.imei != null and dto.imei != '' ">
and a.imei like concat('%', #{dto.imei}, '%')
</if>
<if test="dto.deviceCode != null and dto.deviceCode != '' ">
and a.device_code like concat('%', #{dto.deviceCode}, '%')
</if>
<if test="dto.powerStatus != null">
and a.power_status = #{dto.powerStatus}
</if>
@@ -251,7 +251,7 @@
<where>
<include refid="whereA"/>
</where>
group by DATE_FORMAT(a.create_time, '%Y-%d-%m')
group by DATE_FORMAT(a.create_time, '%Y-%m-%d')
</select>
<select id="listOrerPayType" resultType="com.bsd.pjcloud.hard.api.vo.order.HardOrderPayTypeVo">
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsBarcodeByIdsDto {
/**
* ${ks_sku_id}该字段为超级收银员平台的sku_id,是请求地址中的一部分
*/
private String ks_sku_id;
}
@@ -0,0 +1,33 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsBarcodeLikeDto {
/**
* 模糊查询条件,可根据商品名称、69码模糊查询
*/
private String search;
/**
* 是否只查询标准库(默认false)
*/
private Boolean only_standard;
/**
* 是否只查询非集合SKU(默认false)
*/
private Boolean only_single;
/**
* 当前页码,正整数,默认1
*/
private Integer page_num;
/**
* 分页大小,正整数,默认10,最大50
*/
private Integer page_size;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsBarcodeSkuDto {
/**
* 根据69码查询标准库和私有库商品信息
*/
private String barcode;
}
@@ -0,0 +1,70 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
import java.util.StringTokenizer;
@Data
public class KsRecognitionDto {
/**
* 做为双方系统交互的凭证ID,电商体系可以是订单ID等,由第三方系统保证ID唯一,最大长度32位
*/
private String recog_id;
/**
* 该字段为扩展参数,扩展参数有助于提高识别速度和识别精准度,建议传该字段值
* <p>
* origin_time(必选):
* 该时间的原始发生时间,比如识别请求发生在下单行为后,该字段可以为下单时间,即该事件发生的原始时间
* <p>
* sku_scope(必选):
* 该字段标明了当前识别请求所包含的SKU范围,如识别请求来源于货柜,则当前货柜的所有SKU可作为当前识别范围,sku_id为超级收银员平台的sku_id
* <p>
* floor_num(非必选):
* SKU所在的货架层数
*/
private String extra_params;
/**
* 货柜ID
*/
private String container_id;
/**
* 资源类型 :
* 1 资源URL,2资源ID
*/
private String resource_type;
/**
* 视频资源地址列表,如资源为使用方所属,请确保外部可以访问。视频格式暂时只支持MP4、AVI、webm格式,且编码格式为H.264
* <p>
* 需将主摄像头,即设备左上角或右上角的摄像头(开门那侧的最优),的url作为第一个链接
*/
private String resource_urls;
/**
* 资源信息列表,与resource_urls二选一。
* <p>
* resource_type=2时resource_id需设置值。
* <p>
* camera_id建议的命名方式:
* "层数"+
* "摄像头位于该层顶部(Top)还是底部(Bottom)"+
* "摄像头位于左侧(Left)中间(Middle)还是右侧(Right)"
* 如摄像头位于第一层顶部中间,建议camera_id命名为“01TM”
*/
private String resource_infos;
/**
* 回调地址
*/
private String notify_url;
/**
* 子商户号
*/
private String sub_mch_id;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsRecognitionResultDto {
/**
* 识别任务唯一ID,提交SKU识别时系统返回字段,作为资源ID传递,是请求地址中的一部分
*/
private String ks_recog_id;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsSkuDeleteDto {
/**
* 该字段为超级收银员平台的sku_id,提交SKU审核后由系统返回,作为资源ID传递,是请求地址中的一部分
*/
private String ks_sku_id;
}
@@ -0,0 +1,37 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsSkuEditDto {
/**
* 该字段为超级收银员平台的sku_id,提交SKU审核后由系统返回,作为资源ID传递,是请求地址中的一部分,不需要提交到form表单
*/
private String ks_sku_id;
/**
* 该字段为使用方系统sku_name,建议使用品牌名+商品名,如统一冰红茶
*/
private String sku_name;
/**
* 该字段为SKU所对应的69码,当商品为标品时该字段必填,非标品可不填
*/
private String barcode;
/**
* SKU图片仅在SKU因图片原因审核不通过的情况下支持修改,一旦SKU被审核通过,SKU图片将不再允许修改,如有相关需求,请重新申请SKU
*/
private String img_urls;
/**
* 审核结果回调地址
*/
private String notify_url;
/**
* 该字段为SKU所对应的规格,包含口味、容量、重量,taste表示口味,capacity表示容量,单位:ml,weight表示重量,单位:g
*/
private String specs;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsSkuResultDto {
/**
* 该字段为超级收银员平台的sku_id,提交SKU审核后由系统返回,作为资源ID传递,是请求地址中的一部分
*/
private String ks_sku_id;
}
@@ -0,0 +1,43 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsSkuSubmitCollectionDto {
/**
* 该字段为使用方系统sku_id
*/
private String sku_id;
/**
* 该字段为使用方系统sku_name,建议使用品牌名+商品名,如统一冰红茶
*/
private String sku_name;
/**
* 一张正面合拍图
*/
private String img_url;
/**
* 审核结果回调地址
*/
private String notify_url;
/**
* 一串要集合的SKU的ks_sku_id。
* <p>
* 可混合标准库及私有库的ks_sku_id。
* <p>
* 上限为10。
* <p>
* 这里的SKU在被集合时,审核状态可以是:
* 0:待审核
* 1:审核中
* 2:审核通过。
* <p>
* 但是,这里的SKU最终未被审核通过,集合SKU(母SKU)也不会被审核通过。
*/
private String ks_sku_id;
}
@@ -0,0 +1,37 @@
package com.bsd.pjcloud.thirdparty.dto.ks;
import lombok.Data;
@Data
public class KsSkuSubmitDto {
/**
* 该字段为使用方系统sku_id
*/
private String sku_id;
/**
* 该字段为使用方系统sku_name,建议使用品牌名+商品名,如统一冰红茶
*/
private String sku_name;
/**
* 该字段为SKU所对应的69码,当商品为标品时该字段必填,非标品可不填
*/
private String barcode;
/**
* 该字段为SKU不同方位视图,所需拍摄的图片数量及角度请参考商品建模文档,参数具体值为图片资源地址,如资源为使用方所属,请确保外部可以访问,请注意图片尺寸及质量,综合质量不佳可能会导致审核不通过。图片尺寸不小于1920*1080,压缩质量不低于70%,长宽比介于16:9同1:1之间。
*/
private String img_urls;
/**
* 审核结果回调地址
*/
private String notify_url;
/**
* 该字段为SKU所对应的规格,包含口味、容量、重量,taste表示口味,capacity表示容量,单位:ml,weight表示重量,单位:g
*/
private String specs;
}
@@ -0,0 +1,15 @@
package com.bsd.pjcloud.thirdparty.vo.door;
import cn.hutool.core.util.ObjectUtil;
import lombok.Data;
@Data
public class DoorBaseInnerVo {
private String message;
public boolean isSuccess() {
return ObjectUtil.isEmpty(message);
}
}
@@ -3,7 +3,7 @@ package com.bsd.pjcloud.thirdparty.vo.door;
import lombok.Data;
@Data
public class DoorBindVo {
public class DoorBindVo extends DoorBaseInnerVo {
/**
* 设备编号
@@ -3,7 +3,7 @@ package com.bsd.pjcloud.thirdparty.vo.door;
import lombok.Data;
@Data
public class DoorOpenVo {
public class DoorOpenVo extends DoorBaseInnerVo {
/**
* 开门事件号
@@ -3,7 +3,7 @@ package com.bsd.pjcloud.thirdparty.vo.door;
import lombok.Data;
@Data
public class DoorRegisterVo {
public class DoorRegisterVo extends DoorBaseInnerVo {
/**
* 设备编号
*/
@@ -3,6 +3,6 @@ package com.bsd.pjcloud.thirdparty.vo.door;
import lombok.Data;
@Data
public class DoorRestartVo {
public class DoorRestartVo extends DoorBaseInnerVo {
}
@@ -7,7 +7,7 @@ import java.util.List;
@Data
public class DoorStatusVo {
public class DoorStatusVo extends DoorBaseInnerVo {
/**
@@ -4,5 +4,5 @@ import lombok.Data;
@Data
public class DoorVideoVo {
public class DoorVideoVo extends DoorBaseInnerVo {
}
@@ -3,5 +3,5 @@ package com.bsd.pjcloud.thirdparty.vo.door;
import lombok.Data;
@Data
public class DoorVolumeVo {
public class DoorVolumeVo extends DoorBaseInnerVo {
}
@@ -0,0 +1,61 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsBarcodeByIdsVo {
/**
* 该字段为超级收银员平台的商品ID
*/
private String ks_sku_id;
/**
* 商品69码,集合SKU无返回
*/
private String barcode;
/**
* 商品名称
*/
private String sku_name;
/**
* 业务方sku_id
*/
private String sku_id;
/**
* 商品包装图片列表,用于供无人零售柜运营方确认商品包装是否同拟售卖商品一致。因69码并非包装的唯一ID,同一69码会出现包装不一致的情况。所以该确认过程非常重要。
*/
private String img_urls;
/**
* 商品封图300*300
*/
private String cover;
/**
* SKU类型:
* 0:标准库
* 1:私有库
*/
private String sku_type;
/**
* 该字段为SKU所对应的规格,包含口味、容量、重量,taste表示口味,capacity表示容量,单位:ml,weight表示重量,单位:g
*/
private String specs;
/**
* 是否集合SKU
*/
private String has_sub_sku;
/**
* 集合SKU的子SKU信息,
* 子SKU更多详情可以通过4.1.8接口根据ks_sku_id查询。
*/
private String sub_sku;
}
@@ -0,0 +1,7 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsBarcodeLikeVo {
}
@@ -0,0 +1,61 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsBarcodeSkuVo {
/**
* 该字段为超级收银员平台的商品ID
*/
private String ks_sku_id;
/**
* 商品69码,集合SKU无返回
*/
private String barcode;
/**
* 商品名称
*/
private String sku_name;
/**
* 业务方sku_id
*/
private String sku_id;
/**
* 商品包装图片列表,用于供无人零售柜运营方确认商品包装是否同拟售卖商品一致。因69码并非包装的唯一ID,同一69码会出现包装不一致的情况。所以该确认过程非常重要。
*/
private String img_urls;
/**
* 商品封图300*300
*/
private String cover;
/**
* SKU类型:
* 0:标准库
* 1:私有库
*/
private String sku_type;
/**
* 该字段为SKU所对应的规格,包含口味、容量、重量,taste表示口味,capacity表示容量,单位:ml,weight表示重量,单位:g
*/
private String specs;
/**
* 是否集合SKU
*/
private String has_sub_sku;
/**
* 集合SKU的子SKU信息,
* 子SKU更多详情可以通过4.1.8接口根据ks_sku_id查询。
*/
private String sub_sku;
}
@@ -0,0 +1,60 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsRecognitionResultVo {
/**
* 该字段用于表示识别任务进行到了哪个阶段,返回结果为字典值,不同code代表不同结果
* <p>
* 1:识别进行中
* <p>
* 2:识别完成(已生成识别结果,但未经过人工二次复核,如业务方对此识别结果不认同,还可通过售后识别接口发起一次售后识别)
* <p>
* 3:二次验证中(业务方对识别结果不认同,通过售后识别接口发起售后识别,人工二次验证中)
* <p>
* 4:自动二次验证中(已生成识别结果,但由于识别结果为失败或告警,为谨慎返回失败或告警的结果,人工二次验证中)
* <p>
* 5:识别完成(已生成识别结果,且已经过人工二次复核,此时的结果为最终结果,不可再通过售后识别接口发起售后识别)
* <p>
* 注意:2和5的区别为,当结果为2时,可通过售后识别接口发起售后识别,当结果为5时,不可再通过售后识别接口发起售后识别
*/
private String state;
/**
* 该字段为识别结果
* <p>
* status:
* <p>
* 1:识别中
* <p>
* 2:成功
* <p>
* 3:成功:未拿商品
* <p>
* 4:失败:无法识别
* <p>
* 6:告警:故意遮挡
* <p>
* 7:告警:柜中无此SKU
* <p>
* 8:告警:其他告警
* <p>
* 9:告警:异物拿放
* <p>
* 10:告警:疑似设备故障
* <p>
* result
* :只有status:code值为2是该字段才返回
* <p>
* ks_sku_id:识别到的sku_id(超级收银员平台的sku_id)
* <p>
* sku_num:识别到的sku数量
* <p>
* comments
* :标注备注信息
*/
private String result;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsRecognitionVo {
/**
* 识别任务唯一ID,用于结果获取、重新发起售后识别
*/
private String ks_recog_id;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsSkuDeleteVo {
/**
* 该sku_id为使用方sku_id
*/
private String sku_id;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsSkuEditVo {
/**
* 该sku_id为使用方sku_id
*/
private String sku_id;
}
@@ -0,0 +1,26 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsSkuResultVo {
/**
* 该字段返回结果为字典值,不同code代表不同结果
* <p>
* 0:待审核
* <p>
* 1:审核中
* <p>
* 2:审核通过
* <p>
* 3:审核不通过
*/
private String result;
/**
* 审核不通过时该字段才有值
*/
private String comments;
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsSkuSubmitCollectionVo {
/**
* 集合SKU的ks_sku_id,该字段为超级收银员平台的sku_id,后续SKU管理域所有请求都需要以该字段作为参数
*/
private String ks_sku_id;
}
@@ -0,0 +1,10 @@
package com.bsd.pjcloud.thirdparty.vo.ks;
import lombok.Data;
@Data
public class KsSkuSubmitVo {
private String ks_sku_id;
}
@@ -13,5 +13,7 @@ public class DoorConfig {
private String appId;
private String appKey;
private String selfBaseUrl;
}
@@ -0,0 +1,16 @@
package com.bsd.pjcloud.thirdparty.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "ks-discern")
@Data
public class KsDiscernConfig {
private String baseUrl;
private String appId;
}
@@ -90,14 +90,14 @@ public class ThirdDoorApiController {
@Inner(value = false)
@Operation(summary = "视频地址通知回调")
@PostMapping("/callback/open")
@PostMapping("/callback/video")
public R<DoorVideoCallbackVo> callbackVideo(@RequestBody DoorVideoCallbackDto dto) {
return R.ok(thirdDoorApiService.callbackVideo(dto));
}
@Inner(value = false)
@Operation(summary = "设备状态通知回调")
@PostMapping("/callback/open")
@PostMapping("/callback/status")
public R<DoorStatusVo> callbackStatus(@RequestBody DoorStatusDto dto) {
return R.ok(thirdDoorApiService.callbackStatus(dto));
}
@@ -0,0 +1,38 @@
package com.bsd.pjcloud.thirdparty.controller.ks;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.security.annotation.Inner;
import com.bsd.pjcloud.thirdparty.dto.door.DoorRegisterDto;
import com.bsd.pjcloud.thirdparty.service.ThirdKsApiService;
import com.bsd.pjcloud.thirdparty.vo.door.DoorRegisterVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@RequestMapping("/third-door")
@Tag(description = "third-door", name = "智能柜")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class ThirdKsApiController {
private final ThirdKsApiService thirdKsApiService;
/* ************************************* start 远程调用 start ************************************* */
@Inner
@Operation(summary = "常规SKU提交审核")
@PostMapping("/sku-submit")
public R<DoorRegisterVo> skuSubmit(@RequestBody DoorRegisterDto dto) {
return R.ok(thirdKsApiService.skuSubmit(dto));
}
/* ************************************* end 远程调用 end ************************************* */
}
@@ -0,0 +1,5 @@
package com.bsd.pjcloud.thirdparty.service;
public interface ThirdKsApiService {
}
@@ -1,7 +1,9 @@
package com.bsd.pjcloud.thirdparty.service.impl.door;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.bsd.pjcloud.thirdparty.config.DoorConfig;
import com.bsd.pjcloud.thirdparty.dto.door.*;
import com.bsd.pjcloud.thirdparty.entity.door.ThirdDoorLogEntity;
import com.bsd.pjcloud.thirdparty.service.ThirdDoorApiService;
@@ -10,10 +12,12 @@ import com.bsd.pjcloud.thirdparty.utils.door.api.DoorApi;
import com.bsd.pjcloud.thirdparty.vo.door.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Arrays;
import java.time.Instant;
import java.util.*;
@Service
@Validated
@@ -23,6 +27,8 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
private final String TAG = "智能柜api";
private final DoorConfig doorConfig;
private final ThirdDoorLogService doorLogService;
/**
@@ -31,17 +37,21 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
@Override
public DoorRegisterVo register(DoorRegisterDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.REGISTER;
DoorApi.Api registerApi = DoorApi.REGISTER.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().body(body).execute().body();
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
throw new RuntimeException(String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body));
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorRegisterVo errorVo = new DoorRegisterVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorRegisterVo.class);
} catch (Exception e) {
@@ -61,17 +71,21 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
@Override
public DoorBindVo bind(DoorBindDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.REGISTER;
DoorApi.Api registerApi = DoorApi.BIND.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().body(body).execute().body();
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
throw new RuntimeException(String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body));
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorBindVo errorVo = new DoorBindVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorBindVo.class);
} catch (Exception e) {
@@ -90,6 +104,32 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
*/
@Override
public DoorStatusVo status(DoorStatusDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.STATUS.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorStatusVo errorVo = new DoorStatusVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorStatusVo.class);
} catch (Exception e) {
String error = String.format("|%s||status|意外的错误error|%s|stack|%s|", TAG, e.getMessage(), Arrays.toString(e.getStackTrace()));
log.error(error);
logEntity.setError(error);
} finally {
logEntity.setTimeConsuming(Long.toString(System.currentTimeMillis() - startTime));
doorLogService.save(logEntity);
}
return null;
}
@@ -98,6 +138,32 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
*/
@Override
public DoorRestartVo restart(DoorRestartDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.RESTART.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorRestartVo errorVo = new DoorRestartVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorRestartVo.class);
} catch (Exception e) {
String error = String.format("|%s||restart|意外的错误error|%s|stack|%s|", TAG, e.getMessage(), Arrays.toString(e.getStackTrace()));
log.error(error);
logEntity.setError(error);
} finally {
logEntity.setTimeConsuming(Long.toString(System.currentTimeMillis() - startTime));
doorLogService.save(logEntity);
}
return null;
}
@@ -106,6 +172,32 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
*/
@Override
public DoorVolumeVo volume(DoorVolumeDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.VOLUME.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorVolumeVo errorVo = new DoorVolumeVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorVolumeVo.class);
} catch (Exception e) {
String error = String.format("|%s||volume|意外的错误error|%s|stack|%s|", TAG, e.getMessage(), Arrays.toString(e.getStackTrace()));
log.error(error);
logEntity.setError(error);
} finally {
logEntity.setTimeConsuming(Long.toString(System.currentTimeMillis() - startTime));
doorLogService.save(logEntity);
}
return null;
}
@@ -114,6 +206,32 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
*/
@Override
public DoorOpenVo open(DoorOpenDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.OPEN.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorOpenVo errorVo = new DoorOpenVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorOpenVo.class);
} catch (Exception e) {
String error = String.format("|%s||volume|意外的错误error|%s|stack|%s|", TAG, e.getMessage(), Arrays.toString(e.getStackTrace()));
log.error(error);
logEntity.setError(error);
} finally {
logEntity.setTimeConsuming(Long.toString(System.currentTimeMillis() - startTime));
doorLogService.save(logEntity);
}
return null;
}
@@ -122,6 +240,32 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
*/
@Override
public DoorVideoVo video(DoorVideoDto dto) {
long startTime = System.currentTimeMillis();
DoorApi.Api registerApi = DoorApi.VIDEO.setBaseUrl(doorConfig.getBaseUrl());
ThirdDoorLogEntity logEntity = registerApi.getInitLogEntity();
logEntity.setReq(JSONUtil.toJsonStr(dto));
try {
String body = JSONUtil.toJsonStr(dto);
String res = registerApi.getHttpRequest().header(apiCountersign(body)).body(body).execute().body();
if (ObjectUtil.isEmpty(res)) throw new RuntimeException("response响应为空");
logEntity.setRes(res);
DoorBaseVo doorBaseVo = JSONUtil.toBean(res, DoorBaseVo.class);
if (!doorBaseVo.isSuccess()) {
String errorLog = String.format("请求错误res|%s|url|%s|body|%s|", res, registerApi, body);
log.error(errorLog);
DoorVideoVo errorVo = new DoorVideoVo();
errorVo.setMessage(doorBaseVo.getMessage());
return errorVo;
}
return JSONUtil.toBean(res, DoorVideoVo.class);
} catch (Exception e) {
String error = String.format("|%s||volume|意外的错误error|%s|stack|%s|", TAG, e.getMessage(), Arrays.toString(e.getStackTrace()));
log.error(error);
logEntity.setError(error);
} finally {
logEntity.setTimeConsuming(Long.toString(System.currentTimeMillis() - startTime));
doorLogService.save(logEntity);
}
return null;
}
@@ -146,6 +290,31 @@ public class ThirdDoorApiServiceImpl implements ThirdDoorApiService {
*/
@Override
public DoorStatusVo callbackStatus(DoorStatusDto dto) {
return null;
}
/**
* 接口加签
*/
private Map<String, List<String>> apiCountersign(String body) {
Map<String, String> map = new HashMap<>();
map.put("appid", doorConfig.getAppId());
map.put("noncestr", RandomUtil.randomString(32));
map.put("timestamp", String.valueOf(Instant.now().getEpochSecond()));
String sign = "";
sign += doorConfig.getAppId() + "&";
sign += doorConfig.getAppKey() + "&";
sign += map.get("noncestr") + "&";
sign += map.get("timestamp") + "&";
sign += body;
String signMd5 = DigestUtils.md5Hex(sign);
map.put("sign", signMd5);
Map<String, List<String>> header = new LinkedHashMap<>();
header.put("appid", List.of(map.get("appid")));
header.put("noncestr", List.of(map.get("noncestr")));
header.put("timestamp", List.of(map.get("timestamp")));
header.put("sign", List.of(map.get("sign")));
return header;
}
}
@@ -0,0 +1,15 @@
package com.bsd.pjcloud.thirdparty.service.impl.ks;
import com.bsd.pjcloud.thirdparty.service.ThirdKsApiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@Service
@Validated
@Slf4j
@RequiredArgsConstructor
public class ThirdKsApiServiceImpl implements ThirdKsApiService {
}
@@ -52,6 +52,8 @@ public class DoorApi {
@NoArgsConstructor
public static class Api {
private String baseUrl = "";
private String url;
private String method;
@@ -62,17 +64,23 @@ public class DoorApi {
private ThordDoorApiTypeEnum bizType;
public Api setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
return this;
}
public HttpRequest getHttpRequest() {
if (ObjectUtil.equals(method, "post")) {
return HttpRequest.post(url).contentType(contentType);
return HttpRequest.post(baseUrl + url).contentType(contentType);
} else if (ObjectUtil.equals(method, "get")) {
return HttpRequest.get(url).contentType(contentType);
return HttpRequest.get(baseUrl + url).contentType(contentType);
} else {
return null;
}
}
public ThirdDoorLogEntity getInitLogEntity() {
if (ObjectUtil.isEmpty(this.apiType)) this.setApiType(ThirdDoorApiTypeEnum.DOOR_API);
ThirdDoorLogEntity entity = new ThirdDoorLogEntity();
entity.setBizId(null);
entity.setBizType(bizType.getType());
@@ -0,0 +1,95 @@
package com.bsd.pjcloud.thirdparty.utils.ks.api;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import com.bsd.pjcloud.thirdparty.constant.door.ThirdDoorApiTypeEnum;
import com.bsd.pjcloud.thirdparty.constant.door.ThordDoorApiTypeEnum;
import com.bsd.pjcloud.thirdparty.entity.door.ThirdDoorLogEntity;
import com.bsd.pjcloud.thirdparty.utils.door.api.DoorApi;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
public class KsApi {
// 常规SKU提交审核
public static final DoorApi.Api SKU_SUBMIT = DoorApi.Api.builder().url("/openapi/sc/v1/sku").bizType(ThordDoorApiTypeEnum.REGISTER).method("post").contentType("application/json").build();
// 集合SKU提交审核(未公开)
public static final DoorApi.Api SKU_SUBMIT_COLLECTION = DoorApi.Api.builder().url("/openapi/sc/v1/sku/collection").bizType(ThordDoorApiTypeEnum.REGISTER).method("post").contentType("application/json").build();
// SKU审核结果主动获取
public static final DoorApi.Api SKU_RESULT = DoorApi.Api.builder().url("/openapi/sc/v1/sku/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("post").contentType("application/json").build();
// 常规SKU修改
public static final DoorApi.Api SKU_EDIT = DoorApi.Api.builder().url("/openapi/sc/v1/sku/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("patch").contentType("application/json").build();
// 常规SKU修改
public static final DoorApi.Api SKU_DELETE = DoorApi.Api.builder().url("/openapi/sc/v1/sku/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("delete").contentType("application/json").build();
// 根据69码查询标准库和私有库商品信息
public static final DoorApi.Api BARCODE_SKU = DoorApi.Api.builder().url("/openapi/sc/v1/sku/all_sku/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("get").contentType("application/json").build();
// 根据ks_sku_id查询标准库和私有库商品信息
public static final DoorApi.Api BARCODE_SKU_BY_IDS = DoorApi.Api.builder().url("/openapi/sc/v1/sku/skus/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("get").contentType("application/json").build();
// 模糊查询标准库和私有库商品信息
public static final DoorApi.Api BARCODE_SKU_LIKE = DoorApi.Api.builder().url("/openapi/sc/v1/sku/sku_list/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("get").contentType("application/json").build();
// SKU提交识别
public static final DoorApi.Api RECOGNITION = DoorApi.Api.builder().url("/openapi/sc/v1/recognition/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("post").contentType("application/json").build();
// SKU识别结果主动获取
public static final DoorApi.Api RECOGNITION_RESULT = DoorApi.Api.builder().url("/openapi/sc/v1/recognition/%s").bizType(ThordDoorApiTypeEnum.REGISTER).method("post").contentType("application/json").build();
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Api {
private String baseUrl = "";
private String url;
private String method;
private String contentType;
private ThirdDoorApiTypeEnum apiType = ThirdDoorApiTypeEnum.DISCERN_API;
private ThordDoorApiTypeEnum bizType;
public KsApi.Api setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
return this;
}
public HttpRequest getHttpRequest() {
if (ObjectUtil.equals(method, "post")) {
return HttpRequest.post(baseUrl + url).contentType(contentType);
} else if (ObjectUtil.equals(method, "get")) {
return HttpRequest.get(baseUrl + url).contentType(contentType);
} else if (ObjectUtil.equals(method, "patch")) {
return HttpRequest.patch(baseUrl + url).contentType(contentType);
} else if (ObjectUtil.equals(method, "delete")) {
return HttpRequest.delete(baseUrl + url).contentType(contentType);
} else {
return null;
}
}
public ThirdDoorLogEntity getInitLogEntity() {
if (ObjectUtil.isEmpty(this.apiType)) this.setApiType(ThirdDoorApiTypeEnum.DISCERN_API);
ThirdDoorLogEntity entity = new ThirdDoorLogEntity();
entity.setBizId(null);
entity.setBizType(bizType.getType());
entity.setApiType(apiType.getType());
entity.setApiUrl(url);
return entity;
}
}
}
@@ -73,8 +73,16 @@ zy:
# 智能柜
door:
base-url: https://www.365e-life.net:8443/bkopenapi
app-id:
app-id: 2025040991646569
app-key: 2800650617d44e0d8b31ad5287431179
self-base-url:
# 旷世识别
ks-discern:
base-url: https://gwycport.zj.gov.cn
app-id:
app