From 5171fcf8ccf77a670632e54d2c88642377bfc2ae Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期二, 10 三月 2026 16:55:21 +0800
Subject: [PATCH] 门票对接

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/TTicketOrderService.java          |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/model/TTicketOrder.java                   |    8 +
 ruoyi-system/src/main/java/com/ruoyi/system/utils/ticketUtil/TicketUtil.java          |  246 ++++++++++++++++++++++++++++++++++++++++-
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java          |   34 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTicketOrderServiceImpl.java |   50 ++++++++
 5 files changed, 330 insertions(+), 10 deletions(-)

diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
index dc38c2c..b349467 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/OrderController.java
@@ -5,6 +5,7 @@
 import com.ruoyi.framework.web.service.TokenService;
 import com.ruoyi.system.dto.CreateOrderDto;
 import com.ruoyi.system.dto.CreateOrderRequest;
+import com.ruoyi.system.model.TTicketOrder;
 import com.ruoyi.system.query.AppletOrderListQuery;
 import com.ruoyi.system.service.TAppUserService;
 import com.ruoyi.system.service.TTicketOrderService;
@@ -16,10 +17,9 @@
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.validation.annotation.Validated;
-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;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
 
 /**
  * 下单接口
@@ -70,6 +70,32 @@
     }
 
 
+    /**
+     * 退单
+     */
+    @ApiOperation(value = "退单")
+    @PostMapping("/refundOrder")
+    public R<Void> refundOrder(@RequestParam Integer orderId) throws Exception {
+        Integer userId = tokenService.getLoginUserApplet().getUserId();
+        TTicketOrder order = tTicketOrderService.getById(orderId);
+        if(order.getAppUserId().equals(userId)){
+            boolean refund = tTicketOrderService.refundOrder(order);
+            if(refund){
+                return R.ok();
+            }
+        }
+        return R.fail("退单失败");
+    }
 
 
+    /**
+     * 验票通知
+     */
+    @ApiOperation(value = "验票通知")
+    @PostMapping("/verifyTicket")
+    public R<Void> verifyTicket(HttpServletRequest request) throws Exception {
+
+        return R.ok();
+    }
+
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/model/TTicketOrder.java b/ruoyi-system/src/main/java/com/ruoyi/system/model/TTicketOrder.java
index 728d88a..36c9b27 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/model/TTicketOrder.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/model/TTicketOrder.java
@@ -44,6 +44,10 @@
     @TableField("order_price")
     private BigDecimal orderPrice;
 
+    @ApiModelProperty(value = "票价")
+    @TableField("ticket_price")
+    private BigDecimal ticketPrice;
+
     @ApiModelProperty(value = "支付时间")
     @TableField("pay_time")
     private LocalDateTime payTime;
@@ -80,6 +84,10 @@
     @TableField("partner_order_id")
     private String partnerOrderId;
 
+    @ApiModelProperty(value = "门票信息")
+    @TableField("visit_persons")
+    private String visitPersons;
+
     @ApiModelProperty(value = "审核意见")
     @TableField("audit_content")
     private String auditContent;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/TTicketOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/TTicketOrderService.java
index d1512d3..7837c5d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/TTicketOrderService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/TTicketOrderService.java
@@ -28,4 +28,6 @@
 
     boolean addOrder(CreateOrderDto request, Integer userId) throws Exception;
 
+    boolean refundOrder(TTicketOrder order) throws Exception;
+
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTicketOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTicketOrderServiceImpl.java
index 5f9092a..6c3c92b 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTicketOrderServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTicketOrderServiceImpl.java
@@ -1,5 +1,7 @@
 package com.ruoyi.system.service.impl;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.utils.OrderNos;
 import com.ruoyi.system.dto.CreateOrderDto;
@@ -20,6 +22,8 @@
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -102,6 +106,10 @@
         order.setPartnerOrderId(createOrderVo.getPartnerOrderId());
         order.setOrderPrice(new BigDecimal(createOrderVo.getOrderAmount()).setScale(2, BigDecimal.ROUND_HALF_UP));
 
+        // 获取票价
+        BigDecimal ticketPrice = order.getOrderPrice().divide(new BigDecimal(dto.getQuantity()), 2, BigDecimal.ROUND_HALF_UP);
+        order.setTicketPrice(ticketPrice);
+
 
         String result = dto.getVisitPersons().stream()
                 .map(String::valueOf)  // Integer 转 String
@@ -112,6 +120,48 @@
 
         order.setTicketInfo(dto.getProductName());
         boolean save = this.save(order);
+
+
         return save;
     }
+
+    @Override
+    public boolean refundOrder(TTicketOrder order) throws Exception {
+        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        // 查询未使用的票
+        String visitPersons = order.getVisitPersons();
+        JSONArray jsonArray = JSONArray.parseArray(visitPersons);
+        List<String> ticketIds = new ArrayList<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject jsonObject = jsonArray.getJSONObject(i);
+            Integer status = jsonObject.getInteger("status");
+            if(status==null || status==0){
+                String ticketId = jsonObject.getString("ticketId");
+                ticketIds.add(ticketId);
+            }
+        }
+        if(ticketIds.isEmpty()){
+            throw new RuntimeException("无未使用的票");
+        }
+        boolean refund = ticketUtil.cannelTicket(order.getOrderNo(), order.getPartnerOrderId(), ticketIds);
+        if(refund){
+            for (int i = 0; i < jsonArray.size(); i++) {
+                JSONObject jsonObject = jsonArray.getJSONObject(i);
+                Integer status = jsonObject.getInteger("status");
+                if(status==null || status==0){
+                    jsonObject.put("status",2);
+                    jsonObject.put("refundTime",System.currentTimeMillis());
+                }
+            }
+
+            // jsonArray 转换为字符串
+            String result = jsonArray.toJSONString();
+            order.setVisitPersons(result);
+            order.setStatus(4);
+            order.setRefundMoney(order.getTicketPrice().multiply(new BigDecimal(ticketIds.size())));
+            boolean update = this.updateById(order);
+            return update;
+        }
+        return false;
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/utils/ticketUtil/TicketUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/utils/ticketUtil/TicketUtil.java
index 53bbf7c..9285498 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/utils/ticketUtil/TicketUtil.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/utils/ticketUtil/TicketUtil.java
@@ -8,19 +8,24 @@
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.ruoyi.system.dto.CreateOrderRequest;
+import com.ruoyi.system.dto.VisitPerson;
 import com.ruoyi.system.vo.CreateOrderVo;
 import com.ruoyi.system.vo.TicketListVo;
 
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.HashMap;
-import java.util.List;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 
 /**
  * 门票接口
  */
 public class TicketUtil {
 
+    /**
+     * 获取门票列表
+     * @return
+     * @throws Exception
+     */
     public List<TicketListVo> getTicketList() throws Exception {
         ArrayList<TicketListVo> ticketListVos = new ArrayList<>();
         String userId = "1d9a42e0-9de3-451b-9964-4e9f8e62b101";
@@ -123,6 +128,12 @@
     }
 
 
+    /**
+     * 创建订单
+     * @param request
+     * @return
+     * @throws Exception
+     */
     public  CreateOrderVo saveOrder(CreateOrderRequest request) throws Exception {
         String userId = "1d9a42e0-9de3-451b-9964-4e9f8e62b101";
         String method = "createOrder";
@@ -193,7 +204,7 @@
                 byte[] decodedBytes = Base64.getDecoder().decode(responseBody);
                 String decodedResponse = new String(decodedBytes, "UTF-8");
                 System.out.println("Base64解码后的响应: " + decodedResponse);
-                String res_code = JSONObject.parseObject(decodedResponse).get("res_code").toString();
+                String res_code = JSONObject.parseObject(decodedResponse).getJSONObject("responseHead").getString("res_code");
                 if("1000".equals(res_code)){
                     String responseBody1 = JSONObject.parseObject(decodedResponse).get("responseBody").toString();
                     String decryptedResponseBody = DesUtil.decrypt(responseBody1, desKey);
@@ -207,7 +218,7 @@
                     return createOrderVo;
                 }else {
 
-                    String res_msg = JSONObject.parseObject(decodedResponse).get("res_msg").toString();
+                    String res_msg = JSONObject.parseObject(decodedResponse).getJSONObject("responseHead").getString("res_msg");
                     System.out.println("错误信息: " + res_msg);
                     throw new RuntimeException(res_msg);
                 }
@@ -219,8 +230,231 @@
         return null;
     }
 
+
+
+
+    /**
+     * 支付订单
+     * @param
+     * @return
+     * @throws Exception
+     */
+    public  String payOrder(String orderId,String partnerOrderId) throws Exception {
+        String userId = "1d9a42e0-9de3-451b-9964-4e9f8e62b101";
+        String method = "payOrder";
+        String timestamp = System.currentTimeMillis() + "";
+        String desKey = "TFD9BEOK";  // DES密钥必须是8字节
+        String userKey = "TFD9BEOK";  // 用于签名的用户密钥
+
+        // 1. 构建请求体数据
+        HashMap<String, Object> bodyData = new HashMap<>();
+        bodyData.put("orderId", orderId);
+        bodyData.put("partnerOrderId", partnerOrderId);
+
+        String requestBody = JSON.toJSONString(bodyData);
+        System.out.println("原始请求体: " + requestBody);
+
+        // 2. 使用DES加密请求体
+        String encryptedBody = DesUtil.encrypt(requestBody, desKey);
+        System.out.println("DES加密后的请求体: " + encryptedBody);
+
+        // 3. 生成签名
+        String params = userId + method + timestamp + encryptedBody + userKey;
+        String md5 = SecureUtil.md5(params);
+        System.out.println("MD5签名: " + md5);
+
+        // 4. 构建请求头
+        HashMap<String, Object> headMap = new HashMap<>();
+        headMap.put("user_id", userId);
+        headMap.put("method", method);
+        headMap.put("timestamp", timestamp);
+        headMap.put("sign", md5);
+
+        // 5. 构建完整的请求消息
+        HashMap<String, Object> fullRequestMap = new HashMap<>();
+        fullRequestMap.put("requestHead", headMap);
+        fullRequestMap.put("requestBody", encryptedBody);
+
+        // 6. 将完整消息转换为JSON字符串
+        String fullRequestJson = JSON.toJSONString(fullRequestMap);
+        System.out.println("完整请求JSON: " + fullRequestJson);
+
+        // 7. 对整个JSON字符串进行Base64编码
+        String base64EncodedRequest = Base64.getEncoder().encodeToString(fullRequestJson.getBytes("UTF-8"));
+        System.out.println("Base64编码后的请求: " + base64EncodedRequest);
+
+        // 8. 发送HTTP请求
+        HttpRequest post = HttpUtil.createPost("http://ota.huilvyun.com.cn:8086/scenic-ota/ota/v2/zshl/rent034/payOrder");
+
+        // 设置请求头
+        post.header("Content-Type", "text/plain;charset=UTF-8");  // 根据要求,可能是纯文本
+        // 或者如果是application/json,则使用:
+        // post.header("Content-Type", "application/json;charset=UTF-8");
+
+        // 直接将Base64编码后的字符串作为body发送
+        post.body(base64EncodedRequest);
+
+        System.out.println("发送请求...");
+        HttpResponse execute = post.execute();
+
+        // 9. 处理响应
+        System.out.println("响应状态码: " + execute.getStatus());
+        String responseBody = execute.body();
+        System.out.println("原始响应Body: " + responseBody);
+        // 10. 解析响应(假设响应也是Base64编码的)
+        if (responseBody != null && !responseBody.isEmpty()) {
+            try {
+                // 先Base64解码
+                byte[] decodedBytes = Base64.getDecoder().decode(responseBody);
+                String decodedResponse = new String(decodedBytes, "UTF-8");
+                System.out.println("Base64解码后的响应: " + decodedResponse);
+                String res_code = JSONObject.parseObject(decodedResponse).getJSONObject("responseHead").getString("res_code");
+                if("1000".equals(res_code)){
+                    String responseBody1 = JSONObject.parseObject(decodedResponse).get("responseBody").toString();
+                    String decryptedResponseBody = DesUtil.decrypt(responseBody1, desKey);
+                    System.out.println("解密后的响应: " + decryptedResponseBody);
+                    JSONObject jsonObject = JSONObject.parseObject(decryptedResponseBody);
+                    String visitPersons = jsonObject.getJSONArray("visitPersons").toString();
+                    return visitPersons;
+                }else {
+                    String res_msg = JSONObject.parseObject(decodedResponse).getJSONObject("responseHead").getString("res_msg");
+                    System.out.println("错误信息: " + res_msg);
+                    throw new RuntimeException(res_msg);
+                }
+            } catch (IllegalArgumentException e) {
+                System.out.println("响应不是有效的Base64格式: " + e.getMessage());
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     *  取消订单
+     * @param
+     * @return
+     * @throws Exception
+     */
+    public  Boolean cannelTicket(String orderId,String partnerOrderId,List<String> refundDetailIds) throws Exception {
+        String userId = "1d9a42e0-9de3-451b-9964-4e9f8e62b101";
+        String method = "cannelTicket";
+        String timestamp = System.currentTimeMillis() + "";
+        String desKey = "TFD9BEOK";  // DES密钥必须是8字节
+        String userKey = "TFD9BEOK";  // 用于签名的用户密钥
+
+        // 1. 构建请求体数据
+        HashMap<String, Object> bodyData = new HashMap<>();
+        bodyData.put("orderId", orderId);
+        bodyData.put("partnerOrderId", partnerOrderId);
+        bodyData.put("refundDetailIds", refundDetailIds);
+
+        String requestBody = JSON.toJSONString(bodyData);
+        System.out.println("原始请求体: " + requestBody);
+
+        // 2. 使用DES加密请求体
+        String encryptedBody = DesUtil.encrypt(requestBody, desKey);
+        System.out.println("DES加密后的请求体: " + encryptedBody);
+
+        // 3. 生成签名
+        String params = userId + method + timestamp + encryptedBody + userKey;
+        String md5 = SecureUtil.md5(params);
+        System.out.println("MD5签名: " + md5);
+
+        // 4. 构建请求头
+        HashMap<String, Object> headMap = new HashMap<>();
+        headMap.put("user_id", userId);
+        headMap.put("method", method);
+        headMap.put("timestamp", timestamp);
+        headMap.put("sign", md5);
+
+        // 5. 构建完整的请求消息
+        HashMap<String, Object> fullRequestMap = new HashMap<>();
+        fullRequestMap.put("requestHead", headMap);
+        fullRequestMap.put("requestBody", encryptedBody);
+
+        // 6. 将完整消息转换为JSON字符串
+        String fullRequestJson = JSON.toJSONString(fullRequestMap);
+        System.out.println("完整请求JSON: " + fullRequestJson);
+
+        // 7. 对整个JSON字符串进行Base64编码
+        String base64EncodedRequest = Base64.getEncoder().encodeToString(fullRequestJson.getBytes("UTF-8"));
+        System.out.println("Base64编码后的请求: " + base64EncodedRequest);
+
+        // 8. 发送HTTP请求
+        HttpRequest post = HttpUtil.createPost("http://ota.huilvyun.com.cn:8086/scenic-ota/ota/v2/zshl/rent034/cannelTicket");
+
+        // 设置请求头
+        post.header("Content-Type", "text/plain;charset=UTF-8");  // 根据要求,可能是纯文本
+        // 或者如果是application/json,则使用:
+        // post.header("Content-Type", "application/json;charset=UTF-8");
+
+        // 直接将Base64编码后的字符串作为body发送
+        post.body(base64EncodedRequest);
+
+        System.out.println("发送请求...");
+        HttpResponse execute = post.execute();
+
+        // 9. 处理响应
+        System.out.println("响应状态码: " + execute.getStatus());
+        String responseBody = execute.body();
+        System.out.println("原始响应Body: " + responseBody);
+        // 10. 解析响应(假设响应也是Base64编码的)
+        if (responseBody != null && !responseBody.isEmpty()) {
+            try {
+                // 先Base64解码
+                byte[] decodedBytes = Base64.getDecoder().decode(responseBody);
+                String decodedResponse = new String(decodedBytes, "UTF-8");
+                System.out.println("Base64解码后的响应: " + decodedResponse);
+                String res_code = JSONObject.parseObject(decodedResponse).getJSONObject("responseHead").getString("res_code");
+                if("1000".equals(res_code)){
+                    return true;
+                }else {
+                    String res_msg = JSONObject.parseObject(decodedResponse).getJSONObject("responseHead").getString("res_msg");
+                    System.out.println("错误信息: " + res_msg);
+                    throw new RuntimeException(res_msg);
+                }
+            } catch (IllegalArgumentException e) {
+                System.out.println("响应不是有效的Base64格式: " + e.getMessage());
+            }
+        }
+
+        return null;
+    }
+
+
+
+
     public static void main(String[] args) {
         try {
+            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+//            CreateOrderRequest createOrderRequest = new CreateOrderRequest();
+//            createOrderRequest.setOrderId("20231025110000000000000000000001");
+//            createOrderRequest.setTravelDate("2026-03-11");
+//            createOrderRequest.setQuantity(1);
+//            createOrderRequest.setProductId("HXY19051010090001");
+//            List<VisitPerson> visitPersons = new ArrayList<>();
+//            VisitPerson visitPerson = new VisitPerson();
+//            visitPerson.setIdCard("511028200002150815");
+//            visitPersons.add(visitPerson);
+//            createOrderRequest.setVisitPersons(visitPersons);
+//            TicketUtil ticketUtil = new TicketUtil();
+//            CreateOrderVo createOrderVo = ticketUtil.saveOrder(createOrderRequest);
+//            System.out.println(createOrderVo);
+//
+//
+//            String payOrder = ticketUtil.payOrder(createOrderVo.getOrderId(), createOrderVo.getPartnerOrderId());
+//            System.out.println(payOrder);
+//            List<String> list =new ArrayList<>();
+//                    JSONArray jsonArray = JSONArray.parseArray(payOrder);
+//            for (int i = 0; i < jsonArray.size(); i++) {
+//                JSONObject jsonObject = jsonArray.getJSONObject(i);
+//                String ticketId = jsonObject.getString("ticketId");
+//                list.add(ticketId);
+//            }
+//
+//            Boolean b = ticketUtil.cannelTicket(createOrderVo.getOrderId(), createOrderVo.getPartnerOrderId(), list);
+//            System.out.println(b);
+
         } catch (Exception e) {
             throw new RuntimeException(e);
         }

--
Gitblit v1.7.1