diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/ApiFrom.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/ApiFrom.java index f9bb682c3f..e8696d8838 100644 --- a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/ApiFrom.java +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/ApiFrom.java @@ -10,7 +10,8 @@ public enum ApiFrom { LianTong(1L, "联通Api", ApiFrom.LianTongApiDealStrategy), GuangZhouDX(2L, "广州电信Api", ApiFrom.GuangZhouDXApiDealStrategy), HaiNanDX(3L, "海南电信Api", ApiFrom.HaiNanDXApiDealStrategy), - HuNanDX(4L, "湖南电信Api", ApiFrom.HuNanDXApiDealStrategy); + HuNanDX(4L, "湖南电信Api", ApiFrom.HuNanDXApiDealStrategy), + LiangHao(5L,"靓号Api",ApiFrom.LiangHaoApiDealStrategy); private final Long id; private final String name; private final String apiDealStrategy; @@ -21,6 +22,7 @@ public enum ApiFrom { public static final String GuangZhouDXApiDealStrategy = "GuangZhouDXApiDealStrategy"; public static final String HaiNanDXApiDealStrategy = "HaiNanDXApiDealStrategy"; public static final String HuNanDXApiDealStrategy = "HuNanDXApiDealStrategy"; + public static final String LiangHaoApiDealStrategy = "LiangHaoApiDealStrategy"; public static ApiFrom fromId(Long id) { ApiFrom[] values = values(); diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/LiangHaoApiClientService.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/LiangHaoApiClientService.java new file mode 100644 index 0000000000..209090f73c --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/LiangHaoApiClientService.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.haoka.api; + +import cn.iocoder.yudao.module.haoka.api.lianghaoapi.LiangHaoApiClient; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +public class LiangHaoApiClientService extends ApiConfigService { + + // 原有联通方法保持不变... + + // ================== 靓号API集成 ================== + + /** + * 获取靓号API客户端配置 + */ + private LiangHaoApiClient.Config getLiangHaoConfig(Long haokaSuperiorApiId) { + Map devConfig = this.getDevConfig(haokaSuperiorApiId); + LiangHaoApiClient.Config config = new LiangHaoApiClient.Config(); + // 从devConfig中映射配置项,假设配置键与联通类似需要调整 + config.setSecretKey(devConfig.get("secretKey")); + config.setSelectUrl(devConfig.get("selectUrl")); + config.setSubmitUrl(devConfig.get("submitUrl")); + config.setQueryUrl(devConfig.get("queryUrl")); + config.setAgentMark(devConfig.get("agentMark")); + return config; + } + + /** + * 靓号选号接口 + */ + public LiangHaoApiClient.SelectNumberResponse liangHaoSelectNumber( + Long haokaSuperiorApiId, + LiangHaoApiClient.SelectNumberRequest request) throws Exception { + LiangHaoApiClient.Config config = getLiangHaoConfig(haokaSuperiorApiId); + return LiangHaoApiClient.selectNumber(config, request); + } + + /** + * 靓号下单接口 + */ + public LiangHaoApiClient.SubmitOrderResponse liangHaoSubmitOrder( + Long haokaSuperiorApiId, + LiangHaoApiClient.SubmitOrderRequest request) throws Exception { + LiangHaoApiClient.Config config = getLiangHaoConfig(haokaSuperiorApiId); + return LiangHaoApiClient.submitOrder(config, request); + } + + /** + * 靓号订单查询接口 + */ + public LiangHaoApiClient.QueryOrderResponse liangHaoQueryOrder( + Long haokaSuperiorApiId, + LiangHaoApiClient.QueryOrderRequest request) throws Exception { + LiangHaoApiClient.Config config = getLiangHaoConfig(haokaSuperiorApiId); + return LiangHaoApiClient.queryOrder(config, request); + } +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/lianghaoapi/LiangHaoApiClient.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/lianghaoapi/LiangHaoApiClient.java new file mode 100644 index 0000000000..8eb54e88b1 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/api/lianghaoapi/LiangHaoApiClient.java @@ -0,0 +1,262 @@ +package cn.iocoder.yudao.module.haoka.api.lianghaoapi; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 接口调用工具类 + */ +public class LiangHaoApiClient { + + + +// // +// 生产环境接口地址 http://ddkb.hfswcz.com/api/openapi/ +// +// 平台名称 美美靓号 +// 代理商标识 meimeilianghao +// 秘钥 0fb47e1ab69a7fc236456ee32c53b773 + + /** + * 配置类(需根据实际信息填充) + */ + @Data + public static class Config { + private String secretKey = "0fb47e1ab69a7fc236456ee32c53b773"; // 需联系管理员获取 + private String selectUrl = "https://ddkb.hfswcz.com/api/openapi/select"; + private String submitUrl = "https://ddkb.hfswcz.com/api/openapi/submit"; + private String queryUrl = "https://ddkb.hfswcz.com/api/openapi/query"; + private String agentMark = "meimeilianghao"; + private String platformName = "美美靓号"; + } + + /** + * 请求参数基类(包含公共字段) + */ + @Data + public static abstract class BaseRequest { + protected String sign; + protected String timeStamp; + } + + /** + * 选号接口请求参数 + */ + @Data + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class SelectNumberRequest extends BaseRequest { + private String agentMark; + private String productCode; + private String searchKey; + } + + /** + * 选号接口响应数据 + */ + @Data + public static class SelectNumberResponse { + private Integer code; + private String msg; + private List data; + + @Data + public static class PhoneNumberData { + private String serialNumber; + private Integer monthFee; + private Integer protocolTime; + private String location; + } + } + + /** + * 下单接口请求参数 + */ + @Data + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class SubmitOrderRequest extends BaseRequest { + private String contactNumber; + private String userName; + private String idNumber; + private String agentMark; + private String productCode; + private String serialNumber; + private String province; + private String city; + private String area; + private String address; + private String apiNumber; + } + + /** + * 下单接口响应数据 + */ + @Data + public static class SubmitOrderResponse { + private Integer code; + private String msg; + private String sysOrderNo; + } + + /** + * 查询订单接口请求参数 + */ + @Data + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class QueryOrderRequest extends BaseRequest { + private String sysOrderNo; + private String agentMark; + private String apiNumber; + } + + /** + * 查询订单接口响应数据 + */ + @Data + public static class QueryOrderResponse { + private Integer code; + private String msg; + private Integer orderStatus; + private String reason; + private String sysOrderNo; + private String serialNumber; + private String apiNumber; + private String creatTime; + } + + /** + * 签名工具类 + */ + private static class SignUtil { + /** + * 生成签名 + */ + public static String generateSign(Object req, String secretKey) throws Exception { + JSONObject params = JSON.parseObject(JSON.toJSONString(req)); + // 按字段名排序 + List sortedKeys = new ArrayList<>(params.keySet()); + sortedKeys.sort(String::compareTo); + + // 拼接值 + StringBuilder sb = new StringBuilder(); + for (String key : sortedKeys) sb.append(params.get(key)); + sb.append(secretKey); + + // MD5加密 + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(sb.toString().getBytes(StandardCharsets.UTF_8)); + StringBuilder hexString = new StringBuilder(); + for (byte b : digest) { + hexString.append(String.format("%02X", b)); + } + return hexString.toString(); + } + + /** + * 生成时间戳 + */ + public static String generateTimestamp() { + return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + } + } + + /** + * HTTP工具类 + */ + private static class HttpClientUtil { + private static final ObjectMapper mapper = new ObjectMapper(); + + public static T post(String url, Object request, Class responseType) throws IOException { + HttpClient client = HttpClients.createDefault(); + HttpPost post = new HttpPost(url); + post.setHeader("Content-Type", "application/json;charset=utf-8"); + String json = mapper.writeValueAsString(request); + post.setEntity(new StringEntity(json, StandardCharsets.UTF_8)); + + HttpResponse response = client.execute(post); + String result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + return mapper.readValue(result, responseType); + } + } + + // -------------------- 接口调用方法 -------------------- + + /** + * 选号接口 + */ + public static SelectNumberResponse selectNumber(LiangHaoApiClient.Config config, SelectNumberRequest request) throws Exception { + request.setTimeStamp(SignUtil.generateTimestamp()); + request.setSign(SignUtil.generateSign(JSON.parseObject(JSON.toJSONString(request)), config.getSecretKey())); + request.setAgentMark(config.getAgentMark()); + return HttpClientUtil.post(config.getSelectUrl(), request, SelectNumberResponse.class); + } + + /** + * 下单接口 + */ + public static SubmitOrderResponse submitOrder(LiangHaoApiClient.Config config,SubmitOrderRequest request) throws Exception { + request.setTimeStamp(SignUtil.generateTimestamp()); + request.setSign(SignUtil.generateSign(request, config.getSecretKey())); + request.setAgentMark(config.getAgentMark()); + return HttpClientUtil.post(config.getSubmitUrl(), request, SubmitOrderResponse.class); + } + + /** + * 查询订单接口 + */ + public static QueryOrderResponse queryOrder(LiangHaoApiClient.Config config,QueryOrderRequest request) throws Exception { + request.setTimeStamp(SignUtil.generateTimestamp()); + request.setSign(SignUtil.generateSign(request, config.getSecretKey())); + request.setAgentMark(config.getAgentMark()); + return HttpClientUtil.post(config.getQueryUrl(), request, QueryOrderResponse.class); + } + + // -------------------- 示例调用 -------------------- + public static void main(String[] args) throws Exception { + LiangHaoApiClient.Config config = new LiangHaoApiClient.Config(); + // 示例:选号接口调用 + SelectNumberRequest selectReq = new SelectNumberRequest(); + selectReq.setAgentMark("meimeilianghao"); + selectReq.setProductCode("8C9909E8F1CE3D95"); + selectReq.setSearchKey("1221"); + SelectNumberResponse selectRes = selectNumber(config,selectReq); + System.out.println("选号结果:" + selectRes); + + // 示例:下单接口调用 + SubmitOrderRequest submitReq = new SubmitOrderRequest(); + submitReq.setContactNumber("12345678910"); + submitReq.setUserName("周海彬"); + submitReq.setIdNumber("450821xxxxxxxxxxxx"); + submitReq.setAgentMark("meimeilianghao"); + submitReq.setProductCode("838D90200D0B0"); + submitReq.setSerialNumber("13026537852"); + submitReq.setProvince("广东"); + submitReq.setCity("广州市"); + submitReq.setArea("天河区"); + submitReq.setAddress("天河路228号"); + submitReq.setApiNumber("sd11221221"); + SubmitOrderResponse submitRes = submitOrder(config,submitReq); + System.out.println("下单结果:" + submitRes); + + // 示例:查询订单接口调用 + QueryOrderRequest queryReq = new QueryOrderRequest(); + queryReq.setSysOrderNo("D202111021402373923341"); + queryReq.setAgentMark("meimeilianghao"); + QueryOrderResponse queryRes = queryOrder(config,queryReq); + System.out.println("查询结果:" + queryRes); + } +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/api/strategy/LiangHaoApiDealStrategy.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/api/strategy/LiangHaoApiDealStrategy.java new file mode 100644 index 0000000000..2a4de2e158 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/api/strategy/LiangHaoApiDealStrategy.java @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.haoka.service.api.strategy; + +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.haoka.api.ApiFrom; +import cn.iocoder.yudao.module.haoka.api.LiangHaoApiClientService; +import cn.iocoder.yudao.module.haoka.api.lianghaoapi.LiangHaoApiClient; +import cn.iocoder.yudao.module.haoka.controller.admin.address.vo.AddressVo; +import cn.iocoder.yudao.module.haoka.controller.admin.onsaleproduct.vo.OnSaleProductPreOrderRespVO; +import cn.iocoder.yudao.module.haoka.controller.admin.superiorapilog.vo.SuperiorApiLogSaveReqVO; +import cn.iocoder.yudao.module.haoka.controller.admin.superiorproductconfig.vo.SuperiorProductConfigRespVO; +import cn.iocoder.yudao.module.haoka.dal.dataobject.superiorapi.SuperiorApiDO; +import cn.iocoder.yudao.module.haoka.dal.dataobject.superiorproductconfig.SuperiorProductConfigDO; +import cn.iocoder.yudao.module.haoka.service.address.HaoKaAddressService; +import cn.iocoder.yudao.module.haoka.service.api.*; +import cn.iocoder.yudao.module.haoka.service.api.models.*; +import cn.iocoder.yudao.module.haoka.service.onsaleproduct.OnSaleProductService; +import cn.iocoder.yudao.module.haoka.service.superiorapi.SuperiorApiService; +import cn.iocoder.yudao.module.haoka.service.superiorproductconfig.SuperiorProductConfigService; +import com.alibaba.fastjson.JSON; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component(ApiFrom.LiangHaoApiDealStrategy) +public class LiangHaoApiDealStrategy implements ApiDealStrategy { + + @Resource + private LiangHaoApiClientService liangHaoApiClientService; + + @Resource + private OnSaleProductService onSaleProductService; + + @Resource + private SuperiorApiService superiorApiService; + + @Resource + private SuperiorProductConfigService superiorProductConfigService; + + @Resource + private HaoKaAddressService haoKaAddressService; + + @Override + public ApiDealResp createOrder(SuperiorApiLogSaveReqVO logVO, OrderApiCreateParam param) { + try { + // 1. 校验商品及配置 + OnSaleProductPreOrderRespVO preProduct = onSaleProductService.getOnSaleProductPreOrder(param.getOnSaleProductId()); + if (preProduct == null) { + return ApiDealResp.failed("商品下架或不存在"); + } + SuperiorApiDO superiorApi = superiorApiService.getSuperiorApi(param.getSuperiorApiId()); + SuperiorProductConfigDO skuConfig = superiorProductConfigService.getById(param.getSuperiorProductConfigId()); + if (skuConfig == null) { + return ApiDealResp.failed("商品上游配置不存在"); + } + + // 2. 构建靓号API请求参数 + LiangHaoApiClient.SubmitOrderRequest submitReq = new LiangHaoApiClient.SubmitOrderRequest(); + submitReq.setContactNumber(param.getAddressMobile()); + submitReq.setUserName(param.getIdCardName()); + submitReq.setIdNumber(param.getIdCardNum()); + // submitReq.setAgentMark(superiorApi.getAgentMark()); // 从配置获取代理标识 + submitReq.setProductCode(skuConfig.getSuperiorCode()); // 上游商品编码 + submitReq.setSerialNumber(param.getPlanMobile()); // 预占号码 + submitReq.setApiNumber(param.getId().toString()); // 使用订单ID作为API流水号 + + AddressVo addressDistrict = haoKaAddressService.getAddress(param.getAddressDistrictCode()); + submitReq.setArea(addressDistrict.getName()); + + AddressVo addressProvince = haoKaAddressService.getAddress(addressDistrict.getProvinceCode()); + submitReq.setProvince(addressProvince.getName()); + + AddressVo addressCity = haoKaAddressService.getAddress(addressDistrict.getCityCode()); + submitReq.setCity(addressCity.getName()); + + submitReq.setAddress(param.getAddress()); + + // 3. 调用下单接口 + logVO.setParam(JSON.toJSONString(submitReq)); + LiangHaoApiClient.SubmitOrderResponse response = liangHaoApiClientService.liangHaoSubmitOrder( + superiorApi.getId(), submitReq); + logVO.setResponse(JSON.toJSONString(response)); + + // 4. 处理响应 + OrderApiCreateResp resp = new OrderApiCreateResp(); + if (response.getCode() != 0) { // 假设0为成功状态码 + resp.setOrderStatusCode("0"); + resp.setSupplierOrderStatusDesc(response.getMsg()); + return ApiDealResp.ok(resp); + } + + resp.setSupplierOrderId(response.getSysOrderNo()); + resp.setOrderStatusCode("470"); // 订单创建成功状态码 + resp.setPlanMobileProduced(param.getPlanMobile()); + return ApiDealResp.ok(resp); + + } catch (Exception e) { + log.error("靓号API创建订单异常: {}", e.getMessage()); + return ApiDealResp.failed("系统异常: " + e.getMessage()); + } + } + + @Override + public ApiDealResp queryOrder(SuperiorApiLogSaveReqVO logVO, OrderApiQueryParam param) { + try { + // 1. 校验必要参数 + if (param.getSupplierOrderId() == null) { + return ApiDealResp.failed("订单号不能为空"); + } + + // 2. 构建查询请求 + LiangHaoApiClient.QueryOrderRequest queryReq = new LiangHaoApiClient.QueryOrderRequest(); + queryReq.setSysOrderNo(param.getSupplierOrderId()); + // queryReq.setAgentMark(param.getAgentMark()); // 从参数或配置获取 + + // 3. 调用查询接口 + logVO.setParam(JSON.toJSONString(queryReq)); + LiangHaoApiClient.QueryOrderResponse response = liangHaoApiClientService.liangHaoQueryOrder( + param.getSuperiorApiId(), queryReq); + logVO.setResponse(JSON.toJSONString(response)); + + // 4. 处理响应 + OrderApiQueryResp resp = new OrderApiQueryResp(); + if (response.getCode() != 0) { + resp.setSupplierOrderStatusDesc(response.getMsg()); + return ApiDealResp.ok(resp); + } + + // resp.setSupplierOrderStatus(response.getOrderStatus().toString()); + resp.setSupplierOrderStatusDesc(response.getReason()); + resp.setTrackingNumber(response.getSerialNumber()); // 物流单号映射 + return ApiDealResp.ok(resp); + + } catch (Exception e) { + log.error("靓号API查询订单异常: {}", e.getMessage()); + return ApiDealResp.failed("查询失败: " + e.getMessage()); + } + } +}