Jelajahi Sumber

增加一个定时任务同步口袋助理的通话状态,增加对接超好麦平台的获取订单接口与更新订单接口

cgp 1 hari lalu
induk
melakukan
282f29f3d2
24 mengubah file dengan 781 tambahan dan 6 penghapusan
  1. 23 0
      fs-admin/src/main/java/com/fs/his/task/KdzlTask.java
  2. 1 1
      fs-admin/src/main/java/com/fs/his/task/Task.java
  3. 7 0
      fs-company/src/main/java/com/fs/company/controller/qw/FsCompanyCustomerController.java
  4. 6 0
      fs-service/src/main/java/com/fs/his/mapper/FsKdzlCallRecordMapper.java
  5. 12 0
      fs-service/src/main/java/com/fs/his/vo/UserPhoneAndCallStatusVO.java
  6. 1 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  7. 1 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  8. 140 0
      fs-service/src/main/java/com/fs/jhmApi/client/JHMThirdApiClient.java
  9. 23 0
      fs-service/src/main/java/com/fs/jhmApi/config/JHMThirdApiConfig.java
  10. 92 0
      fs-service/src/main/java/com/fs/jhmApi/model/push/JHMOrderPushData.java
  11. 37 0
      fs-service/src/main/java/com/fs/jhmApi/model/request/JHMOrderInfoRequest.java
  12. 40 0
      fs-service/src/main/java/com/fs/jhmApi/model/request/JHMOrderUpdateRequest.java
  13. 19 0
      fs-service/src/main/java/com/fs/jhmApi/model/response/JHMBaseResponse.java
  14. 188 0
      fs-service/src/main/java/com/fs/jhmApi/model/response/JHMOrderDetail.java
  15. 15 0
      fs-service/src/main/java/com/fs/jhmApi/model/response/JHMOrderInfoData.java
  16. 26 0
      fs-service/src/main/java/com/fs/jhmApi/model/response/JHMOrderUpdateResponse.java
  17. 27 0
      fs-service/src/main/java/com/fs/jhmApi/service/IJHMThirdOrderService.java
  18. 67 0
      fs-service/src/main/java/com/fs/jhmApi/service/impl/JHMThirdOrderServiceImpl.java
  19. 4 0
      fs-service/src/main/java/com/fs/qw/dto/ImportCustomerDTO.java
  20. 6 0
      fs-service/src/main/java/com/fs/qw/mapper/FsCompanyCustomerMapper.java
  21. 15 2
      fs-service/src/main/java/com/fs/qw/service/impl/FsCompanyCustomerServiceImpl.java
  22. 18 0
      fs-service/src/main/resources/mapper/his/FsKdzlCallRecordMapper.xml
  23. 12 0
      fs-service/src/main/resources/mapper/qw/FsCompanyCustomerMapper.xml
  24. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/store/CommonScrmController.java

+ 23 - 0
fs-admin/src/main/java/com/fs/his/task/KdzlTask.java

@@ -6,10 +6,12 @@ import com.fs.his.domain.FsImportMember;
 import com.fs.his.domain.FsKdzlCallRecord;
 import com.fs.his.mapper.FsImportMemberMapper;
 import com.fs.his.mapper.FsKdzlCallRecordMapper;
+import com.fs.his.vo.UserPhoneAndCallStatusVO;
 import com.fs.kdzl.dto.CallRecord;
 import com.fs.kdzl.dto.Custm;
 import com.fs.kdzl.dto.Property;
 import com.fs.kdzl.service.KdzlService;
+import com.fs.qw.mapper.FsCompanyCustomerMapper;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,6 +31,9 @@ public class KdzlTask {
     @Autowired
     private FsKdzlCallRecordMapper kdzlCallRecordMapper;
 
+    @Autowired
+    private FsCompanyCustomerMapper companyCustomerMapper;
+
     org.slf4j.Logger logger= LoggerFactory.getLogger(getClass());
 
     public void syncKdzlMember(){
@@ -350,6 +355,24 @@ public class KdzlTask {
             }
     }
 
+    /**
+     * 根据电话号码同步客户信息表的通话状态
+     *
+     */
+    public void  syncCallStatusByPhone() {
+        List<UserPhoneAndCallStatusVO> phoneAndCallStatusVOList =kdzlCallRecordMapper.selectUserPhoneAndCallStatus();
+        if (CollectionUtils.isEmpty(phoneAndCallStatusVOList)){
+            return;
+        }
+        for (UserPhoneAndCallStatusVO item : phoneAndCallStatusVOList) {
+            if ("".equals(item.getCallStatus())||item.getCallStatus()==null){
+                item.setCallStatus("2");//未接通
+            }
+        }
+        //根据电话号码更新客户信息表的通话状态
+        int update=companyCustomerMapper.updateBatchFsCompanyCustomerCallStatusByPhoneList(phoneAndCallStatusVOList);
+    }
+
     /**
      * 构建组合键(从FsKdzlCallRecord)
      */

+ 1 - 1
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -2541,7 +2541,7 @@ public class Task {
     }
 
     /**
-     * 定时批量添加待销售认领客户信息
+     * 定时批量更新或添加客户信息表数据
      * */
     public void batchAddCompanyCustomer(){
         int i = fsImportMemberService.batchAddCompanyCustomer();

+ 7 - 0
fs-company/src/main/java/com/fs/company/controller/qw/FsCompanyCustomerController.java

@@ -237,6 +237,12 @@ public class FsCompanyCustomerController extends BaseController {
             String name = formatter.formatCellValue(row.getCell(1));  // B列
             String phone = formatter.formatCellValue(row.getCell(2)); // C列
             String address = formatter.formatCellValue(row.getCell(3)); // D列
+            Integer buyCount; // E列
+            if ("".equals(formatter.formatCellValue(row.getCell(4)))||formatter.formatCellValue(row.getCell(4))==null){
+                buyCount = 0;
+            }else {
+                buyCount = Integer.valueOf(formatter.formatCellValue(row.getCell(4)));
+            }
 
             if (StringUtils.isEmpty(name) || StringUtils.isEmpty(phone) || StringUtils.isEmpty(address)) {
                 continue; // 跳过空行
@@ -246,6 +252,7 @@ public class FsCompanyCustomerController extends BaseController {
             dto.setCustomerName(name);
             dto.setPhone(phone);
             dto.setAddress(address);
+            dto.setBuyCount(buyCount);
             list.add(dto);
         }
         workbook.close();

+ 6 - 0
fs-service/src/main/java/com/fs/his/mapper/FsKdzlCallRecordMapper.java

@@ -3,6 +3,7 @@ package com.fs.his.mapper;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.his.domain.FsKdzlCallRecord;
+import com.fs.his.vo.UserPhoneAndCallStatusVO;
 import com.fs.kdzl.dto.CallRecord;
 import org.apache.ibatis.annotations.Param;
 
@@ -64,4 +65,9 @@ public interface FsKdzlCallRecordMapper extends BaseMapper<FsKdzlCallRecord>{
     List<FsKdzlCallRecord> selectExistingFsKdzlCallRecordList(@Param("list") List<CallRecord> list);
 
     int batchInsertFsKdzlCallRecord(@Param("list") List<FsKdzlCallRecord> list);
+
+    /**
+     * 查询用户手机号和通话状态(手机号去重,优先保留接通的那条数据)
+     * */
+    List<UserPhoneAndCallStatusVO> selectUserPhoneAndCallStatus();
 }

+ 12 - 0
fs-service/src/main/java/com/fs/his/vo/UserPhoneAndCallStatusVO.java

@@ -0,0 +1,12 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+@Data
+public class UserPhoneAndCallStatusVO {
+    /** 客户电话*/
+    private String phone;
+
+    /** 接听状态 (1= 接通,2= 未接通)*/
+    private String callStatus;
+}

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java

@@ -502,7 +502,7 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
 //        request.setTid(order.getOrderCode());
 //        request.setOid(order.getOrderCode());
 //        request.setRefund_state(0);
-//        BaseResponse response= erpOrderService.refundUpdate(request);
+//        JHMBaseResponse response= erpOrderService.refundUpdate(request);
 //        if(response.getSuccess()){
 //            return R.ok();
 //        }

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -2608,7 +2608,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             request.setTid(order.getOrderCode());
             request.setOid(order.getOrderCode());
             request.setRefund_state(1);
-            //BaseResponse response=erpOrderService.refundUpdate(request);
+            //JHMBaseResponse response=erpOrderService.refundUpdate(request);
 //            if(response.getSuccess()){
 //            }
 //            else{

+ 140 - 0
fs-service/src/main/java/com/fs/jhmApi/client/JHMThirdApiClient.java

@@ -0,0 +1,140 @@
+package com.fs.jhmApi.client;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.jhmApi.config.JHMThirdApiConfig;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+
+/**
+ * 第三方开放平台 HTTP 客户端
+ * 功能:自动添加系统参数(app_key/nonce/timestamp/sign)并执行 POST 请求
+ * 注意:所有接口均为 POST,系统参数在 Query,业务参数在 Body(JSON)
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class JHMThirdApiClient {
+
+    private final JHMThirdApiConfig config;
+    private final ObjectMapper objectMapper;
+
+    private static final RestTemplate restTemplate;
+
+    static {
+        restTemplate = new RestTemplate();
+    }
+
+    /**
+     * 通用 POST 请求,返回泛型响应
+     *
+     * @param path         接口路径(如 "/open-api/order/info")
+     * @param body         业务请求体对象(自动序列化为 JSON)
+     * @param responseType 响应类型引用(用于保留泛型,如 new ParameterizedTypeReference<BaseResponse<OrderInfoData>>() {})
+     * @param <T>          响应类型
+     * @return 解析后的响应对象
+     */
+    public <T> T doPost(String path, Object body, ParameterizedTypeReference<T> responseType) {
+        try {
+            // 1. 序列化 Body 为 JSON
+            String rawBodyJson = objectMapper.writeValueAsString(body);
+            // 去除所有空白字符(签名和发送均使用压缩后的 JSON)
+            String compactBody = rawBodyJson.replaceAll("\\s+", "");
+
+            // 2. 生成系统参数
+            String nonce = UUID.randomUUID().toString().replace("-", "").substring(0, 12);
+            long timestamp = System.currentTimeMillis() / 1000; // 10位秒级时间戳
+
+            // 使用 TreeMap 自动按键字典序排序
+            Map<String, String> queryParams = new TreeMap<>();
+            queryParams.put("app_key", config.getAppKey());
+            queryParams.put("nonce", nonce);
+            queryParams.put("timestamp", String.valueOf(timestamp));
+
+            // 3. 生成签名
+            String sign = buildSign(config.getAppSecret(), compactBody, queryParams);
+            queryParams.put("sign", sign);
+
+            // 4. 构建 URL(使用 UriComponentsBuilder 逐个添加 Query 参数,避免泛型警告)
+            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(config.getBaseUrl() + path);
+            for (Map.Entry<String, String> entry : queryParams.entrySet()) {
+                builder.queryParam(entry.getKey(), entry.getValue());
+            }
+            String url = builder.build().toUriString();
+
+            // 5. 设置 Headers
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            headers.set(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
+
+            HttpEntity<String> httpEntity = new HttpEntity<>(compactBody, headers);
+
+            log.debug("请求 URL: {}, Body: {}", url, compactBody);
+            ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);
+            return responseEntity.getBody();
+
+        } catch (Exception e) {
+            log.error("调用聚好麦第三方接口异常, path: {}", path, e);
+            throw new RuntimeException("聚好麦第三方接口调用失败: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 签名算法(严格按文档实现)
+     *
+     * @param appSecret    应用密钥
+     * @param compactBody  去除空白后的 Body JSON
+     * @param systemParams 系统参数(已包含 app_key, nonce, timestamp)
+     * @return 大写 MD5 签名
+     */
+    private String buildSign(String appSecret, String compactBody, Map<String, String> systemParams) {
+        // 1. 将系统参数和 body 放入 TreeMap 进行字典序排序
+        TreeMap<String, String> sortedMap = new TreeMap<>();
+        sortedMap.put("app_key", systemParams.get("app_key"));
+        sortedMap.put("nonce", systemParams.get("nonce"));
+        sortedMap.put("timestamp", systemParams.get("timestamp"));
+        sortedMap.put("body", compactBody);
+
+        // 2. 拼接:appSecret + key1value1key2value2... + appSecret
+        StringBuilder sb = new StringBuilder(appSecret);
+        for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
+            sb.append(entry.getKey()).append(entry.getValue());
+        }
+        sb.append(appSecret);
+
+        String strToSign = sb.toString();
+        log.debug("待签名字符串: {}", strToSign);
+
+        // 3. MD5 加密并转大写
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] digest = md.digest(strToSign.getBytes(StandardCharsets.UTF_8));
+            return bytesToHex(digest).toUpperCase();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("MD5 算法不存在", e);
+        }
+    }
+
+    /** 字节数组转十六进制字符串 */
+    private String bytesToHex(byte[] bytes) {
+        char[] hexArray = "0123456789ABCDEF".toCharArray();
+        char[] hexChars = new char[bytes.length * 2];
+        for (int i = 0; i < bytes.length; i++) {
+            int v = bytes[i] & 0xFF;
+            hexChars[i * 2] = hexArray[v >>> 4];
+            hexChars[i * 2 + 1] = hexArray[v & 0x0F];
+        }
+        return new String(hexChars);
+    }
+}

+ 23 - 0
fs-service/src/main/java/com/fs/jhmApi/config/JHMThirdApiConfig.java

@@ -0,0 +1,23 @@
+package com.fs.jhmApi.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+/**
+ * HTTP客户端 + 签名工具
+ * */
+@Data
+@Component
+//@ConfigurationProperties(prefix = "third-api")
+public class JHMThirdApiConfig {
+    /** 应用 AppKey(测试:KHAUN24Y8ANJ76QE7VY1MWTQ) */
+    private String appKey;
+    /** 应用 AppSecret(测试:8UI5HIO308X2AKYSX841BABPRBNYSI2N) */
+    private String appSecret;
+    /** 接口基础地址(生产:https://api.yixikeji.cn) */
+    private String baseUrl;
+    /** 连接超时(毫秒) */
+    private int connectTimeout = 5000;
+    /** 读取超时(毫秒) */
+    private int readTimeout = 10000;
+}

+ 92 - 0
fs-service/src/main/java/com/fs/jhmApi/model/push/JHMOrderPushData.java

@@ -0,0 +1,92 @@
+package com.fs.jhmApi.model.push;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fs.jhmApi.model.response.JHMOrderDetail;
+import lombok.Data;
+import java.util.List;
+
+/**
+ * 第三方主动推送的订单数据(与 OrderDetail 结构基本相同,但多出 app_key 和 action)
+ * 推送路径:您的回调地址 + /callback/order
+ */
+@Data
+public class JHMOrderPushData {
+
+    @JsonProperty("app_key")
+    private String appKey;
+
+    /** 操作类型:0创建/1支付成功/2取消/3修改/4售后 */
+    private Integer action;
+
+    @JsonProperty("union_id")
+    private String unionId;
+
+    @JsonProperty("order_num")
+    private String orderNum;
+
+    /** 订单主状态 */
+    private Integer status;
+
+    /** 售后状态 */
+    @JsonProperty("after_status")
+    private Integer afterStatus;
+
+    @JsonProperty("after_status_remark")
+    private String afterStatusRemark;
+
+    @JsonProperty("cancel_type")
+    private Integer cancelType;
+
+    @JsonProperty("total_money")
+    private Integer totalMoney;
+
+    private Integer money;
+    private Integer discount;
+
+    @JsonProperty("freight_money")
+    private Integer freightMoney;
+
+    @JsonProperty("pay_mode")
+    private Integer payMode;
+
+    @JsonProperty("pay_sn")
+    private String paySn;
+
+    @JsonProperty("pay_time")
+    private Long payTime;
+
+    @JsonProperty("pay_money")
+    private Integer payMoney;
+
+    @JsonProperty("pay_state_desc")
+    private String payStateDesc;
+
+    @JsonProperty("transaction_id")
+    private String transactionId;
+
+    @JsonProperty("complete_time")
+    private Long completeTime;
+
+    @JsonProperty("receipt_time")
+    private Long receiptTime;
+
+    @JsonProperty("deliver_time")
+    private Long deliverTime;
+
+    @JsonProperty("shop_remark")
+    private String shopRemark;
+
+    @JsonProperty("user_remark")
+    private String userRemark;
+
+    @JsonProperty("updated_at")
+    private Long updatedAt;
+
+    @JsonProperty("created_at")
+    private Long createdAt;
+
+    private JHMOrderDetail.Goods goods;
+    private JHMOrderDetail.Buyer buyer;
+    @JsonProperty("after_sales")
+    private List<JHMOrderDetail.AfterSale> afterSales;
+}

+ 37 - 0
fs-service/src/main/java/com/fs/jhmApi/model/request/JHMOrderInfoRequest.java

@@ -0,0 +1,37 @@
+package com.fs.jhmApi.model.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 获取订单信息请求体(Body 参数)
+ * 对应接口:POST /open-api/order/info
+ */
+@Data
+public class JHMOrderInfoRequest {
+
+    /** 订单号列表(可选),若传则只返回这些订单 */
+    @JsonProperty("order_num")
+    private List<Long> orderNum;
+
+    /** 查询时间类型:1=创建时间,不传默认按更新时间 */
+    @JsonProperty("filter_type")
+    private Integer filterType;
+
+    /** 开始时间(10位时间戳),必需 */
+    @JsonProperty("start_time")
+    private Long startTime;
+
+    /** 结束时间(10位时间戳),必需 */
+    @JsonProperty("end_time")
+    private Long endTime;
+
+    /** 页码,必需 */
+    private Integer page;
+
+    /** 每页条数,必需 */
+    @JsonProperty("page_size")
+    private Integer pageSize;
+}

+ 40 - 0
fs-service/src/main/java/com/fs/jhmApi/model/request/JHMOrderUpdateRequest.java

@@ -0,0 +1,40 @@
+package com.fs.jhmApi.model.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 更新订单信息请求体(Body 参数)
+ * 对应接口:POST /open-api/order/update
+ */
+@Data
+public class JHMOrderUpdateRequest {
+
+    /** 订单更新列表,必需 */
+    private List<OrderUpdateItem> list;
+
+    @Data
+    public static class OrderUpdateItem {
+        /** 订单号,必需 */
+        @JsonProperty("order_num")
+        private String orderNum;
+
+        /** 快递公司 ID,必需 */
+        @JsonProperty("express_code")
+        private String expressCode;
+
+        /** 快递公司名称,必需 */
+        @JsonProperty("express_name")
+        private String expressName;
+
+        /** 快递单号,必需 */
+        @JsonProperty("express_number")
+        private String expressNumber;
+
+        /** 快递单号修改时间(10位时间戳),必需 */
+        @JsonProperty("express_update_time")
+        private Long expressUpdateTime;
+    }
+}

+ 19 - 0
fs-service/src/main/java/com/fs/jhmApi/model/response/JHMBaseResponse.java

@@ -0,0 +1,19 @@
+package com.fs.jhmApi.model.response;
+
+import lombok.Data;
+
+/**
+ * 第三方接口统一响应包装
+ * @param <T> 实际数据泛型
+ */
+@Data
+public class JHMBaseResponse<T> {
+    /** 业务状态码,10000 表示成功 */
+    private Integer code;
+    /** 业务数据 */
+    private T data;
+    /** 是否成功(框架层标识) */
+    private Boolean success;
+    /** 链路追踪ID(用于排查问题) */
+    private String traceId;
+}

+ 188 - 0
fs-service/src/main/java/com/fs/jhmApi/model/response/JHMOrderDetail.java

@@ -0,0 +1,188 @@
+package com.fs.jhmApi.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.util.List;
+
+/**
+ * 订单详情(对应推送示例中的订单对象)
+ * 字段与推送数据中的订单主体一致,但无 app_key 和 action
+ */
+@Data
+public class JHMOrderDetail {
+
+    @JsonProperty("union_id")
+    private String unionId;
+
+    @JsonProperty("order_num")
+    private String orderNum;
+
+    /** 订单主状态:-1取消,1待支付,2待发货,3待收货,4已完成 */
+    private Integer status;
+
+    /** 售后状态:1待处理,2待退货,3待收货,6退款完成,7关闭,8退款中,9极速退款,12失败,13用户取消 */
+    @JsonProperty("after_status")
+    private Integer afterStatus;
+
+    @JsonProperty("after_status_remark")
+    private String afterStatusRemark;
+
+    @JsonProperty("cancel_type")
+    private Integer cancelType;
+
+    @JsonProperty("total_money")
+    private Integer totalMoney;
+
+    private Integer money;
+    private Integer discount;
+
+    @JsonProperty("freight_money")
+    private Integer freightMoney;
+
+    @JsonProperty("order_source")
+    private Integer orderSource;
+
+    @JsonProperty("pay_mode")
+    private Integer payMode;
+
+    @JsonProperty("pay_sn")
+    private String paySn;
+
+    @JsonProperty("pay_time")
+    private Long payTime;
+
+    @JsonProperty("pay_money")
+    private Integer payMoney;
+
+    @JsonProperty("pay_state_desc")
+    private String payStateDesc;
+
+    @JsonProperty("transaction_id")
+    private String transactionId;
+
+    @JsonProperty("complete_time")
+    private Long completeTime;
+
+    @JsonProperty("receipt_time")
+    private Long receiptTime;
+
+    @JsonProperty("deliver_time")
+    private Long deliverTime;
+
+    @JsonProperty("ad_account_id")
+    private Long adAccountId;
+
+    @JsonProperty("shop_remark")
+    private String shopRemark;
+
+    @JsonProperty("user_remark")
+    private String userRemark;
+
+    @JsonProperty("updated_at")
+    private Long updatedAt;
+
+    @JsonProperty("created_at")
+    private Long createdAt;
+
+    /** 商品信息 */
+    private Goods goods;
+
+    /** 买家/收货信息 */
+    private Buyer buyer;
+
+    /** 售后单列表(可能有多个) */
+    @JsonProperty("after_sales")
+    private List<AfterSale> afterSales;
+
+    // ---------- 内部类 ----------
+    @Data
+    public static class Goods {
+        @JsonProperty("product_id")
+        private String productId;
+        @JsonProperty("product_code")
+        private String productCode; // 商家商品编码
+        @JsonProperty("sku_id")
+        private Integer skuId;      // 0表示无规格
+        @JsonProperty("sku_code")
+        private String skuCode;     // SKU编码
+        private Integer price;
+        private Integer num;
+        private String image;
+        private String name;
+        @JsonProperty("sku_name")
+        private String skuName;
+        @JsonProperty("created_at")
+        private Long createdAt;
+        @JsonProperty("updated_at")
+        private Long updatedAt;
+        @JsonProperty("after_num")
+        private Integer afterNum;
+    }
+
+    @Data
+    public static class Buyer {
+        private String express;
+        @JsonProperty("express_number")
+        private String expressNumber;
+        private String consignee;
+        @JsonProperty("receive_phone")
+        private String receivePhone;
+        private String address;
+        private String province;
+        private String city;
+        private String area;
+        @JsonProperty("address_detail")
+        private String addressDetail;
+        @JsonProperty("area_id")
+        private Integer areaId;
+        @JsonProperty("area_ids")
+        private String areaIds;
+        @JsonProperty("edit_address_code")
+        private Integer editAddressCode;
+        @JsonProperty("is_update")
+        private Integer isUpdate;
+        @JsonProperty("express_update_time")
+        private Long expressUpdateTime;
+        @JsonProperty("created_at")
+        private Long createdAt;
+        @JsonProperty("updated_at")
+        private Long updatedAt;
+    }
+
+    @Data
+    public static class AfterSale {
+        @JsonProperty("refund_sn")
+        private String refundSn;
+        @JsonProperty("after_sale_status")
+        private Integer afterSaleStatus;
+        @JsonProperty("after_sale_type")
+        private Integer afterSaleType;
+        private String reason;
+        private Integer number;
+        private Integer price;
+        @JsonProperty("refund_money")
+        private Integer refundMoney;
+        @JsonProperty("refuse_reason")
+        private String refuseReason;
+        @JsonProperty("refuse_fail")
+        private String refuseFail;
+        @JsonProperty("apply_at")
+        private Long applyAt;
+        @JsonProperty("confirm_at")
+        private Long confirmAt;
+        @JsonProperty("audit_at")
+        private Long auditAt;
+        @JsonProperty("cancel_at")
+        private Long cancelAt;
+        @JsonProperty("updated_at")
+        private Long updatedAt;
+        @JsonProperty("success_at")
+        private Long successAt;
+        @JsonProperty("refuse_at")
+        private Long refuseAt;
+        @JsonProperty("after_sale")
+        private Integer afterSale;
+        @JsonProperty("after_status_remark")
+        private String afterStatusRemark;
+    }
+}

+ 15 - 0
fs-service/src/main/java/com/fs/jhmApi/model/response/JHMOrderInfoData.java

@@ -0,0 +1,15 @@
+package com.fs.jhmApi.model.response;
+
+import lombok.Data;
+import java.util.List;
+
+/**
+ * 获取订单信息响应中的 data 结构
+ */
+@Data
+public class JHMOrderInfoData {
+    /** 订单列表 */
+    private List<JHMOrderDetail> list;
+    /** 总记录数 */
+    private Integer total;
+}

+ 26 - 0
fs-service/src/main/java/com/fs/jhmApi/model/response/JHMOrderUpdateResponse.java

@@ -0,0 +1,26 @@
+package com.fs.jhmApi.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.util.List;
+
+/**
+ * 更新订单响应中的 data 结构
+ */
+@Data
+public class JHMOrderUpdateResponse {
+    /** 更新成功的订单号列表(包含状态异常但物流更新成功的) */
+    private List<String> success;
+    /** 完全失败的订单号列表(订单号错误或物流信息错误等) */
+    private List<String> error;
+    /** 订单号错误的列表 */
+    private List<String> order;
+    /** 物流信息错误的列表 */
+    private List<String> express;
+    /** 订单更新失败的列表(如状态不允许) */
+    @JsonProperty("order_update")
+    private List<String> orderUpdate;
+    /** 物流更新失败的列表 */
+    @JsonProperty("express_update")
+    private List<String> expressUpdate;
+}

+ 27 - 0
fs-service/src/main/java/com/fs/jhmApi/service/IJHMThirdOrderService.java

@@ -0,0 +1,27 @@
+package com.fs.jhmApi.service;
+
+
+import com.fs.jhmApi.model.request.JHMOrderInfoRequest;
+import com.fs.jhmApi.model.request.JHMOrderUpdateRequest;
+import com.fs.jhmApi.model.response.JHMOrderInfoData;
+import com.fs.jhmApi.model.response.JHMOrderUpdateResponse;
+
+/**
+ * 第三方订单服务接口
+ */
+public interface IJHMThirdOrderService {
+
+    /**
+     * 获取订单信息
+     * @param request 请求参数
+     * @return 订单列表数据
+     */
+    JHMOrderInfoData getOrderInfo(JHMOrderInfoRequest request);
+
+    /**
+     * 更新订单信息(发货)
+     * @param request 请求参数
+     * @return 更新结果明细
+     */
+    JHMOrderUpdateResponse updateOrder(JHMOrderUpdateRequest request);
+}

+ 67 - 0
fs-service/src/main/java/com/fs/jhmApi/service/impl/JHMThirdOrderServiceImpl.java

@@ -0,0 +1,67 @@
+package com.fs.jhmApi.service.impl;
+
+
+import com.fs.jhmApi.client.JHMThirdApiClient;
+import com.fs.jhmApi.model.request.JHMOrderInfoRequest;
+import com.fs.jhmApi.model.request.JHMOrderUpdateRequest;
+import com.fs.jhmApi.model.response.JHMBaseResponse;
+import com.fs.jhmApi.model.response.JHMOrderInfoData;
+import com.fs.jhmApi.model.response.JHMOrderUpdateResponse;
+import com.fs.jhmApi.service.IJHMThirdOrderService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.stereotype.Service;
+
+/**
+ * 第三方订单服务实现
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class JHMThirdOrderServiceImpl implements IJHMThirdOrderService {
+
+    private final JHMThirdApiClient apiClient;
+
+    /** 接口路径常量 */
+    private static final String PATH_ORDER_INFO = "/open-api/order/info";
+    private static final String PATH_ORDER_UPDATE = "/open-api/order/update";
+
+    @Override
+    public JHMOrderInfoData getOrderInfo(JHMOrderInfoRequest request) {
+        ParameterizedTypeReference<JHMBaseResponse<JHMOrderInfoData>> responseType =
+                new ParameterizedTypeReference<JHMBaseResponse<JHMOrderInfoData>>() {};
+        JHMBaseResponse<JHMOrderInfoData> response = apiClient.doPost(PATH_ORDER_INFO, request, responseType);
+        return handleResponse(response, PATH_ORDER_INFO);
+    }
+
+    @Override
+    public JHMOrderUpdateResponse updateOrder(JHMOrderUpdateRequest request) {
+        ParameterizedTypeReference<JHMBaseResponse<JHMOrderUpdateResponse>> responseType =
+                new ParameterizedTypeReference<JHMBaseResponse<JHMOrderUpdateResponse>>() {};
+        JHMBaseResponse<JHMOrderUpdateResponse> response = apiClient.doPost(PATH_ORDER_UPDATE, request, responseType);
+        return handleResponse(response, PATH_ORDER_UPDATE);
+    }
+
+    /**
+     * 统一响应处理:校验 code 和 success,失败抛出异常
+     */
+    private <T> T handleResponse(JHMBaseResponse<T> response, String path) {
+        if (response == null) {
+            throw new RuntimeException("聚好麦第三方接口返回空响应,path: " + path);
+        }
+        if (!Boolean.TRUE.equals(response.getSuccess())) {
+            log.error("聚好麦第三方接口 success=false, code: {}, traceId: {}, path: {}",
+                    response.getCode(), response.getTraceId(), path);
+            throw new RuntimeException(String.format("聚好麦第三方接口失败,code=%s, traceId=%s",
+                    response.getCode(), response.getTraceId()));
+        }
+        if (response.getCode() == null || !response.getCode().equals(10000)) {
+            log.error("第三方业务错误, code: {}, traceId: {}, path: {}",
+                    response.getCode(), response.getTraceId(), path);
+            throw new RuntimeException(String.format("第三方业务错误,code=%s, traceId=%s",
+                    response.getCode(), response.getTraceId()));
+        }
+        return response.getData();
+    }
+}

+ 4 - 0
fs-service/src/main/java/com/fs/qw/dto/ImportCustomerDTO.java

@@ -19,4 +19,8 @@ public class ImportCustomerDTO {
      * 地址
      * */
     private String address;
+    /**
+     * 下单次数
+     * */
+    private Integer buyCount;
 }

+ 6 - 0
fs-service/src/main/java/com/fs/qw/mapper/FsCompanyCustomerMapper.java

@@ -1,5 +1,6 @@
 package com.fs.qw.mapper;
 
+import com.fs.his.vo.UserPhoneAndCallStatusVO;
 import com.fs.hisStore.vo.FsStoreOrderScrmPhoneAndOrderNumVO;
 import com.fs.qw.domain.FsCompanyCustomer;
 import com.fs.qw.param.TransferCustomerParam;
@@ -97,4 +98,9 @@ public interface FsCompanyCustomerMapper {
      * 根据手机号更新客户信息表购买次数
      * */
     int updateCompanyUserBuyCountByUserPhone(@Param("phoneList") List<FsStoreOrderScrmPhoneAndOrderNumVO> phoneList);
+
+    /**
+     * 根据手机号批量更新客户信息表通话状态
+     * */
+    int updateBatchFsCompanyCustomerCallStatusByPhoneList(@Param("phoneAndCallStatusVOList") List<UserPhoneAndCallStatusVO> phoneAndCallStatusVOList);
 }

+ 15 - 2
fs-service/src/main/java/com/fs/qw/service/impl/FsCompanyCustomerServiceImpl.java

@@ -418,14 +418,16 @@ public class FsCompanyCustomerServiceImpl implements IFsCompanyCustomerService {
 
                 if (existingId != null) {
                     // 存在 → 购买次数 +1
-                    self().addBuyTimes(existingId);
+                    //self().addBuyTimes(existingId);
+                    //存在就更新购买次数
+                    updateBuyCount(existingId, dto.getBuyCount());
                 } else {
                     // 不存在 → 新增客户
                     FsCompanyCustomer customer = new FsCompanyCustomer();
                     customer.setCustomerName(dto.getCustomerName());
                     customer.setPhone(dto.getPhone());
                     customer.setAddress(dto.getAddress());
-                    customer.setBuyCount(1L);               // 首次购买次数 = 1
+                    customer.setBuyCount(Long.valueOf(dto.getBuyCount()));// 使用导入的购买次数
                     customer.setCreateTime(new Date());     // 创建时间
                     customer.setClaimStatus(0);  //未认领状态
                     fsCompanyCustomerMapper.insertFsCompanyCustomer(customer);
@@ -640,4 +642,15 @@ public class FsCompanyCustomerServiceImpl implements IFsCompanyCustomerService {
         setCompleteStatus(customer);
         fsCompanyCustomerMapper.updateFsCompanyCustomer(customer);
     }
+    /**
+     * 更新购买次数
+     * */
+    private int updateBuyCount(Long id, Integer buyCount) {
+        FsCompanyCustomer fsCompanyCustomer = fsCompanyCustomerMapper.selectFsCompanyCustomerById(id);
+        if (fsCompanyCustomer!=null&&fsCompanyCustomer.getBuyCount()!=null){
+            fsCompanyCustomer.setBuyCount(fsCompanyCustomer.getBuyCount()+buyCount);
+            return fsCompanyCustomerMapper.updateFsCompanyCustomer(fsCompanyCustomer);
+        }
+        return 0;
+    }
 }

+ 18 - 0
fs-service/src/main/resources/mapper/his/FsKdzlCallRecordMapper.xml

@@ -116,6 +116,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
     </select>
 
+    <select id="selectUserPhoneAndCallStatus" resultType="com.fs.his.vo.UserPhoneAndCallStatusVO">
+        SELECT called, status
+        FROM (
+                 SELECT
+                     called,
+                     status,
+                     ROW_NUMBER() OVER (
+                         PARTITION BY called
+                         ORDER BY
+                             CASE WHEN status = 1 THEN 0 ELSE 1 END,  -- status=1 优先(0在前)
+                             call_time DESC,                           -- 时间最新优先
+                             id DESC                                   -- 时间相同时ID最大优先
+                         ) AS rn
+                 FROM fs_kdzl_call_record
+             ) t
+        WHERE rn = 1;
+    </select>
+
     <!-- 只插入不存在的记录 -->
     <insert id="batchInsertFsKdzlCallRecord">
         INSERT IGNORE INTO fs_kdzl_call_record (uid, call_time, talk_len, status,  customer_id, customer_name,  caller, called, type, create_time)

+ 12 - 0
fs-service/src/main/resources/mapper/qw/FsCompanyCustomerMapper.xml

@@ -446,4 +446,16 @@
         </foreach>
     </update>
 
+    <update id="updateBatchFsCompanyCustomerCallStatusByPhoneList">
+        UPDATE fs_company_customer
+        SET kdzl_call_status =
+        <foreach collection="phoneAndCallStatusVOList" item="item" separator=" " open="CASE phone" close="END">
+            WHEN #{item.phone} THEN #{item.callStatus}
+        </foreach>
+        WHERE phone IN
+        <foreach collection="phoneAndCallStatusVOList" item="item" open="(" close=")" separator=",">
+            #{item.phone}
+        </foreach>
+    </update>
+
 </mapper>

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/controller/store/CommonScrmController.java

@@ -293,7 +293,7 @@ public class CommonScrmController extends AppBaseController {
 //        // address.setName(user.getName());
 //        // receive_infos.add(address);
 //        user.setReceive_infos(receive_infos);
-//        BaseResponse response = userService.addUser(user);
+//        JHMBaseResponse response = userService.addUser(user);
 //        return R.ok();
 //    }