From 6f77dcd80df0081466d49c933fff74afedf867b8 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期四, 31 七月 2025 10:10:21 +0800
Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/QianYunTong

---
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/OrderPrivateCarMapper.java              |    5 
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/vo/TripOrderVo.java                         |  145 ++++++++
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/impl/OrderTaxiServiceImpl.java              |   25 +
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/OrderCrossCityMapper.java                  |    5 
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/mapping/OrderTaxiMapper.xml                     |   46 ++
 UserQYTTravel/guns-admin/src/main/resources/application.yml                                                                |   50 +
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/IOrderPrivateCarService.java         |    4 
 UserQYTTravel/guns-admin/pom.xml                                                                                           |   21 +
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/impl/OrderPrivateCarServiceImpl.java |   24 +
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/IOrderTaxiService.java                      |   12 
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/OrderTaxiMapper.java                            |   12 
 UserQYTTravel/guns-admin/src/main/resources/static/fonts/AlibabaPuHuiTi-3-105-Heavy.ttf                                    |    0 
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/mapping/OrderCrossCityMapper.xml           |   47 ++
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/impl/OrderCrossCityServiceImpl.java     |   24 +
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/IOrderCrossCityService.java             |    3 
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/pdf/TripSheetGenerator.java                       |  335 ++++++++++++++++++
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/EmailUtil.java                               |   52 ++
 UserQYTTravel/guns-admin/src/main/resources/static/img/logo.png                                                            |    0 
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/OrderController.java                                 |  212 +++++++++++
 UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/mapping/OrderPrivateCarMapper.xml       |   48 ++
 20 files changed, 1,053 insertions(+), 17 deletions(-)

diff --git a/UserQYTTravel/guns-admin/pom.xml b/UserQYTTravel/guns-admin/pom.xml
index 14973e1..3db4b12 100644
--- a/UserQYTTravel/guns-admin/pom.xml
+++ b/UserQYTTravel/guns-admin/pom.xml
@@ -232,6 +232,27 @@
             <artifactId>quartz</artifactId>
             <version>2.2.1</version>
         </dependency>
+<!--        生成pdf-->
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>itextpdf</artifactId>
+            <version>5.5.13.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>itext-asian</artifactId>
+            <version>5.2.0</version>
+        </dependency>
+<!--        邮件依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
     </dependencies>
 
 
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/OrderController.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/OrderController.java
index b6fb4c6..a6f588b 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/OrderController.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/OrderController.java
@@ -13,9 +13,12 @@
 import com.stylefeng.guns.modular.smallLogistics.server.IOrderLogisticsService;
 import com.stylefeng.guns.modular.specialTrain.model.OrderPrivateCar;
 import com.stylefeng.guns.modular.specialTrain.server.IOrderPrivateCarService;
+import com.stylefeng.guns.modular.system.dao.CarMapper;
 import com.stylefeng.guns.modular.system.dao.SystemPriceMapper;
 import com.stylefeng.guns.modular.system.model.*;
+import com.stylefeng.guns.modular.system.model.vo.TripOrderVo;
 import com.stylefeng.guns.modular.system.model.vo.UnPayOrderVO;
+import com.stylefeng.guns.modular.system.pdf.TripSheetGenerator;
 import com.stylefeng.guns.modular.system.service.*;
 import com.stylefeng.guns.modular.system.util.*;
 import com.stylefeng.guns.modular.system.util.qianyuntong.model.QYTPaymentCallback;
@@ -39,7 +42,9 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.io.File;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.text.SimpleDateFormat;
 import java.util.*;
 
@@ -129,6 +134,18 @@
     private IUserCouponRecordService userCouponRecordService;
     @Value("${pushMinistryOfTransport}")
     private boolean pushMinistryOfTransport;
+
+
+    @Value("${trip.sheet.filePath}")
+    private  String filePath;
+    @Autowired
+    private EmailUtil emailUtil;
+    @Autowired
+    private  TripSheetGenerator tripSheetGenerator;
+    @Autowired
+    private IServerCarModelService serverCarModelService;
+
+
     
     @Resource
     private SystemPriceMapper systemPriceMapper;
@@ -2172,4 +2189,199 @@
         }
     }
 
+    @PostMapping("/api/order/queryMyTripList")
+    @ApiOperation(value = "获取我的行程列表", tags = {"用户端-个人中心"}, notes = "")
+    @ApiImplicitParams({
+            @ApiImplicitParam(value = "订单类型(1=专车,2=出租车,3=跨城出行)", name = "type", required = true, dataType = "int"),
+            @ApiImplicitParam(value = "页码(首页1)", name = "pageNum", required = true, dataType = "int"),
+            @ApiImplicitParam(value = "页条数", name = "size", required = true, dataType = "int"),
+            @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9.....")
+    })
+    public ResultUtil<List<TripOrderVo>> queryMyTripList(Integer type, Integer pageNum, Integer size, HttpServletRequest request){
+        try {
+            Integer uid = userInfoService.getUserIdFormRedis(request);
+            if(null == uid){
+                return ResultUtil.tokenErr();
+            }
+//            List<Map<String, Object>> list = null;
+//            switch (type){
+//                case 1:
+//                    list = orderPrivateCarService.queryMyTripList(uid, pageNum, size);
+//                    break;
+//                case 2:
+//                    list = orderTaxiService.queryMyTripList(uid, pageNum, size);
+//                    break;
+//                case 3:
+//                    list = orderCrossCityService.queryMyTripList(uid, pageNum, size);
+//                    break;
+//
+//            }
+//
+//            // 将经纬度转换为城市并设置到数据中
+//            if (list != null && !list.isEmpty()) {
+//                for (Map<String, Object> orderMap : list) {
+//                    // 获取经纬度(根据实际字段名调整)
+//                    Object lonObj = orderMap.get("boardingLon");
+//                    Object latObj = orderMap.get("boardingLat");
+//                    //获取公司id
+//                    Object companyId = orderMap.get("companyId");
+//
+//                    Object serverCarModelId =null;
+//                    ServerCarModel serverCarModel = null;
+//                    if (type == 1 || type == 3){
+//                        //获取车型id
+//                         serverCarModelId = orderMap.get("serverCarModelId");
+//                         serverCarModel = serverCarModelService.selectById((Serializable) serverCarModelId);
+//                    }
+//
+//                    if (lonObj != null && latObj != null) {
+//                        String lon = lonObj.toString();
+//                        String lat = latObj.toString();
+//                        Company company = companyService.selectById((Serializable) companyId);
+//
+//                        try {
+//                            // 调用逆地理编码接口获取城市信息
+//                            Map<String, String> geoInfo = gdMapGeocodingUtil.geocode(lon, lat);
+//                            // 将城市信息存入map,供后续转换VO使用
+//                            orderMap.put("city", geoInfo.getOrDefault("city", ""));
+//                            orderMap.put("companyName", company.getName());
+//                            if (serverCarModel != null) {
+//                                orderMap.put("serverCarModel", serverCarModel.getName());
+//                            }
+//                        } catch (Exception e) {
+//                            // 记录转换失败日志,不中断流程
+//                            System.err.println("经纬度转城市失败: " + lon + "," + lat + ",错误: " + e.getMessage());
+//                            orderMap.put("city", ""); // 转换失败时设为空
+//                        }
+//                    } else {
+//                        orderMap.put("city", ""); // 经纬度为空时设为空
+//                    }
+//                }
+//            }
+            List<Map<String,Object>> raw = fetchTrips(uid, type, pageNum, size);
+            return ResultUtil.success(TripOrderVo.getTripOrderVo(raw));
+//            return ResultUtil.success(TripOrderVo.getTripOrderVo(list));
+        }catch (Exception e){
+            e.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+    /**
+     * 私有:拉取指定 type 的行程列表。
+     * type=0 → 全部类型;1/2/3 → 对应三种服务;pageNum/size 负责分页。
+     * 对于 type==1 或 3,内部额外加载 serverCarModel 信息。
+     */
+    private List<Map<String,Object>> fetchTrips(
+            Integer uid, Integer type, Integer pageNum, Integer size) throws Exception {
+
+        List<Map<String, Object>> list = new ArrayList<>();
+        if (type == null || type == 0) {
+            list.addAll(orderPrivateCarService.queryMyTripListAll(uid));
+            list.addAll(orderTaxiService.queryMyTripListAll(uid));
+            list.addAll(orderCrossCityService.queryMyTripListAll(uid));
+        } else {
+            switch (type) {
+                case 1:
+                    list = orderPrivateCarService.queryMyTripList(uid, pageNum, size);
+                    break;
+                case 2:
+                    list = orderTaxiService.queryMyTripList(uid, pageNum, size);
+                    break;
+                case 3:
+                    list = orderCrossCityService.queryMyTripList(uid, pageNum, size);
+                    break;
+                default:
+                    throw new IllegalArgumentException("无效的订单类型:" + type);
+            }
+        }
+        // 排序
+        list.sort((a, b) -> {
+            Date da = (Date) a.get("boardingTime");
+            Date db = (Date) b.get("boardingTime");
+            if (da == null && db == null) return 0;
+            if (da == null) return 1;   // a 在后面
+            if (db == null) return -1;  // b 在后面
+            return db.compareTo(da);    // 都不为空,再按时间倒序
+        });
+        // 将经纬度转换为城市并设置到数据中
+        if (list != null && !list.isEmpty()) {
+            for (Map<String, Object> orderMap : list) {
+                // 获取经纬度(根据实际字段名调整)
+                Object lonObj = orderMap.get("boardingLon");
+                Object latObj = orderMap.get("boardingLat");
+                //获取公司id
+                Object companyId = orderMap.get("companyId");
+
+                Object serverCarModelId =null;
+                ServerCarModel serverCarModel = null;
+                if (orderMap.get("serverCarModelId") != null ){
+                    //获取车型id
+                    serverCarModelId = orderMap.get("serverCarModelId");
+                    serverCarModel = serverCarModelService.selectById((Serializable) serverCarModelId);
+                }
+
+                if (lonObj != null && latObj != null) {
+                    String lon = lonObj.toString();
+                    String lat = latObj.toString();
+                    Company company = companyService.selectById((Serializable) companyId);
+
+                    try {
+                        // 调用逆地理编码接口获取城市信息
+                        Map<String, String> geoInfo = gdMapGeocodingUtil.geocode(lon, lat);
+                        // 将城市信息存入map,供后续转换VO使用
+                        orderMap.put("city", geoInfo.getOrDefault("city", ""));
+                        orderMap.put("companyName", company.getName());
+                        if (serverCarModel != null) {
+                            orderMap.put("serverCarModel", serverCarModel.getName());
+                        }
+                    } catch (Exception e) {
+                        // 记录转换失败日志,不中断流程
+                        System.err.println("经纬度转城市失败: " + lon + "," + lat + ",错误: " + e.getMessage());
+                        orderMap.put("city", ""); // 转换失败时设为空
+                    }
+                } else {
+                    orderMap.put("city", ""); // 经纬度为空时设为空
+                }
+            }
+        }
+        return list;
+    }
+    @PostMapping("/api/user/sendTripSheetEmail")
+    @ApiOperation(value = "发送行程单邮件", tags = {"用户端-个人中心"}, notes = "")
+    @ApiImplicitParams({
+            @ApiImplicitParam(value = "订单列表", name = "orders", required = false, dataType = "List<OrderWarpper>"),
+            @ApiImplicitParam(value = "收件人邮箱", name = "recipientEmail", required = false, dataType = "String"),
+            @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9.....")
+    })
+    public ResultUtil sendTripSheetEmail( @RequestParam boolean allOrders,
+                                          @RequestBody(required = false) List<TripOrderVo> orders,
+                                          @RequestParam String recipientEmail,
+                                          HttpServletRequest  request) {
+        try {
+            // 从Redis中获取当前用户ID
+            Integer uid = userInfoService.getUserIdFormRedis(request);
+            if (null == uid) {
+                return ResultUtil.tokenErr();
+            }
+            if (allOrders) {
+                // 这里复用 queryMyTripList 逻辑,不分页,type=0 表示全部
+                List<Map<String, Object>> rawList = fetchTrips(uid, 0, null, null);
+                orders = TripOrderVo.getTripOrderVo(rawList);
+            } else {
+                // allOrders=false,需要前端传 orders
+                if (orders == null || orders.isEmpty()) {
+                    return ResultUtil.error("请传入 orders 或者选择全部订单");
+                }
+            }
+            String filePath = tripSheetGenerator.generatePdf(orders);
+            File attachment = new File(filePath);
+            emailUtil.sendEmailWithAttachment(recipientEmail, "行程单", "请查收您的行程单", attachment);
+            attachment.delete(); // 发送成功后删除临时文件
+            return ResultUtil.success("邮件发送成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResultUtil.error("邮件发送失败");
+        }
+    }
+
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/OrderCrossCityMapper.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/OrderCrossCityMapper.java
index 9dbc933..02d3c8c 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/OrderCrossCityMapper.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/OrderCrossCityMapper.java
@@ -91,4 +91,9 @@
      * @return
      */
     List<Map<String, Object>> queryRedEnvelope(@Param("uid") Integer uid);
+
+    List<Map<String, Object>> queryMyTripList(@Param("uid") Integer uid, @Param("pageNum") Integer pageNum,
+                                               @Param("size") Integer size);
+
+    List<Map<String, Object>> queryMyTripListAll(@Param("uid") Integer uid);
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/mapping/OrderCrossCityMapper.xml b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/mapping/OrderCrossCityMapper.xml
index 85bc470..e3a9e73 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/mapping/OrderCrossCityMapper.xml
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/dao/mapping/OrderCrossCityMapper.xml
@@ -612,4 +612,51 @@
             and DATE_FORMAT(a.travelTime, '%Y-%m-%d') = #{day}
         </if>
     </select>
+
+
+    <select id="queryMyTripList" resultType="map">
+        select
+            id as orderId,
+            DATE_FORMAT(insertTime, '%Y-%m-%d %H:%i') as orderTime,
+            DATE_FORMAT(travelTime, '%m月?d日?%H:%i') as time,
+        startAddress as startAddress,
+        endAddress as endAddress,
+        driverId as driverId,
+        (3) as orderType,
+        state as state,
+        oldState as oldState,
+        thankYouFee,
+        passengersPhone,
+        payMoney,
+        endServiceTime,
+        companyId,
+        arriveTime,
+        boardingTime,
+        boardingLon,
+        boardingLat
+        from t_order_cross_city where userId = #{uid} order by insertTime desc limit #{pageNum}, #{size}
+    </select>
+
+    <select id="queryMyTripListAll" resultType="map">
+        select
+            id as orderId,
+            DATE_FORMAT(insertTime, '%Y-%m-%d %H:%i') as orderTime,
+            DATE_FORMAT(travelTime, '%m月?d日?%H:%i') as time,
+        startAddress as startAddress,
+        endAddress as endAddress,
+        driverId as driverId,
+        (3) as orderType,
+        state as state,
+        oldState as oldState,
+        thankYouFee,
+        passengersPhone,
+        payMoney,
+        endServiceTime,
+        companyId,
+        arriveTime,
+        boardingTime,
+        boardingLon,
+        boardingLat
+        from t_order_cross_city where userId = #{uid} order by insertTime desc
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/IOrderCrossCityService.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/IOrderCrossCityService.java
index 2f6c4d5..d1f2130 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/IOrderCrossCityService.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/IOrderCrossCityService.java
@@ -329,5 +329,6 @@
 
     void promotion(Integer orderId);
 
-
+    List<Map<String, Object>> queryMyTripList(Integer uid, Integer pageNum, Integer size) throws Exception;
+    List<Map<String, Object>> queryMyTripListAll(Integer uid) throws Exception;
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/impl/OrderCrossCityServiceImpl.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/impl/OrderCrossCityServiceImpl.java
index 2629341..9605ec5 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/impl/OrderCrossCityServiceImpl.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/crossCity/server/impl/OrderCrossCityServiceImpl.java
@@ -2737,4 +2737,28 @@
 			}
 		}
 	}
+
+	@Override
+	public List<Map<String, Object>> queryMyTripList(Integer uid, Integer pageNum, Integer size) throws Exception {
+		pageNum = (pageNum - 1) * size;
+		List<Map<String, Object>> maps = orderCrossCityMapper.queryMyTripList(uid, pageNum, size);
+		for (Map<String, Object> map : maps) {
+			if (Integer.valueOf(String.valueOf(map.get("state"))) == 11) {
+				map.put("state", map.get("oldState"));
+			}
+		}
+		return maps;
+	}
+
+	@Override
+	public List<Map<String, Object>> queryMyTripListAll(Integer uid) throws Exception {
+
+		List<Map<String, Object>> maps = orderCrossCityMapper.queryMyTripListAll(uid);
+		for (Map<String, Object> map : maps) {
+			if (Integer.valueOf(String.valueOf(map.get("state"))) == 11) {
+				map.put("state", map.get("oldState"));
+			}
+		}
+		return maps;
+	}
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/OrderPrivateCarMapper.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/OrderPrivateCarMapper.java
index 28e3d56..f2a49a8 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/OrderPrivateCarMapper.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/OrderPrivateCarMapper.java
@@ -98,4 +98,9 @@
                                              @Param("state") Integer state,
                                              @Param("lon") String lon,
                                              @Param("lat") String lat);
+
+    List<Map<String, Object>> queryMyTripList(@Param("uid") Integer uid, @Param("pageNum") Integer pageNum,
+                                               @Param("size") Integer size);
+
+    List<Map<String, Object>> queryMyTripListAll(@Param("uid") Integer uid);
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/mapping/OrderPrivateCarMapper.xml b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/mapping/OrderPrivateCarMapper.xml
index 6bd4523..0644455 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/mapping/OrderPrivateCarMapper.xml
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/dao/mapping/OrderPrivateCarMapper.xml
@@ -581,4 +581,52 @@
         </if>
 
     </select>
+
+
+    <select id="queryMyTripList" resultType="map">
+        select
+            id as orderId,
+            rideType as rideType,
+            DATE_FORMAT(insertTime, '%Y-%m-%d %H:%i') as orderTime,
+            DATE_FORMAT(travelTime, '%m月?d日?%H:%i') as time,
+        startAddress as startAddress,
+        endAddress as endAddress,
+        driverId as driverId,
+        (1) as orderType,
+        state as state,
+        oldState as oldState,
+        thankYouFee,
+        passengersPhone,
+        payMoney,
+        endServiceTime,
+        companyId,
+        arriveTime,
+        boardingTime,
+        boardingLon,
+        boardingLat
+        from t_order_private_car where userId = #{uid} order by insertTime desc limit #{pageNum}, #{size}
+    </select>
+    <select id="queryMyTripListAll" resultType="map">
+        select
+            id as orderId,
+            rideType as rideType,
+            DATE_FORMAT(insertTime, '%Y-%m-%d %H:%i') as orderTime,
+            DATE_FORMAT(travelTime, '%m月?d日?%H:%i') as time,
+        startAddress as startAddress,
+        endAddress as endAddress,
+        driverId as driverId,
+        (1) as orderType,
+        state as state,
+        oldState as oldState,
+        thankYouFee,
+        passengersPhone,
+        payMoney,
+        endServiceTime,
+        companyId,
+        arriveTime,
+        boardingTime,
+        boardingLon,
+        boardingLat
+        from t_order_private_car where userId = #{uid} order by insertTime desc
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/IOrderPrivateCarService.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/IOrderPrivateCarService.java
index 3a6bb39..19033bb 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/IOrderPrivateCarService.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/IOrderPrivateCarService.java
@@ -332,4 +332,8 @@
 
     void promotion(Integer orderId);
 
+    List<Map<String, Object>> queryMyTripList(Integer uid, Integer pageNum, Integer size) throws Exception;
+
+    List<Map<String, Object>> queryMyTripListAll(Integer uid) throws Exception;
+
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/impl/OrderPrivateCarServiceImpl.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/impl/OrderPrivateCarServiceImpl.java
index 4e068a8..6fcdab1 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/impl/OrderPrivateCarServiceImpl.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/specialTrain/server/impl/OrderPrivateCarServiceImpl.java
@@ -2775,4 +2775,28 @@
 			}
 		}
 	}
+
+	@Override
+	public List<Map<String, Object>> queryMyTripList(Integer uid, Integer pageNum, Integer size) throws Exception {
+		pageNum = (pageNum - 1) * size;
+		List<Map<String, Object>> maps = orderPrivateCarMapper.queryMyTripList(uid, pageNum, size);
+		for (Map<String, Object> map : maps) {
+			if (Integer.valueOf(String.valueOf(map.get("state"))) == 11) {
+				map.put("state", map.get("oldState"));
+			}
+		}
+		return maps;
+	}
+
+	@Override
+	public List<Map<String, Object>> queryMyTripListAll(Integer uid) throws Exception {
+
+		List<Map<String, Object>> maps = orderPrivateCarMapper.queryMyTripListAll(uid);
+		for (Map<String, Object> map : maps) {
+			if (Integer.valueOf(String.valueOf(map.get("state"))) == 11) {
+				map.put("state", map.get("oldState"));
+			}
+		}
+		return maps;
+	}
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/vo/TripOrderVo.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/vo/TripOrderVo.java
new file mode 100644
index 0000000..ace2687
--- /dev/null
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/vo/TripOrderVo.java
@@ -0,0 +1,145 @@
+package com.stylefeng.guns.modular.system.model.vo;
+
+import com.stylefeng.guns.modular.system.warpper.OrderWarpper;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TripOrderVo  implements Comparable{
+
+    @ApiModelProperty("订单id")
+    private Integer orderId;
+    @ApiModelProperty("订单日期")
+    private String orderTime;
+    @ApiModelProperty("出行时间/(小件物流的取货时间)")
+    private String time;
+    @ApiModelProperty("起点名称")
+    private String startAddress;
+    @ApiModelProperty("终点名称")
+    private String endAddress;
+    @ApiModelProperty("公司id(服务商)")
+    private Integer companyId;
+    @ApiModelProperty("司机id")
+    private Integer driverId;
+    @ApiModelProperty("车辆id")
+    private Integer carId;
+    @ApiModelProperty("行程人电话")
+    private String passengersPhone;
+    @ApiModelProperty("订单状态(1=待接单,2=待出发,3=待到达预约地点,4=待乘客上车,5=服务中,6=完成服务,7=待支付,8=待评价,9=已完成,10=已取消,11=改派中,12=取消待支付)<br/>" +
+            "小件物流订单状态(1=待接单,2=待出发,3=待到达预约地点,4=待取货,5=送货中,6=已送达,7=待支付,8=需补差价,9=已取货,10=已取消,11=已支付差价")
+    private Integer state;
+    @ApiModelProperty("用车时长")
+    private Integer carTime;
+    @ApiModelProperty("车型id")
+    private Integer serverCarModelId;
+    @ApiModelProperty("车型")
+    private String serverCarModel;
+//    @ApiModelProperty("订单金额")
+//    private Double orderMoney;
+    @ApiModelProperty("支付金额")
+    private Double payMoney;
+//    @ApiModelProperty("差价金额")
+//    private Double differenceMoney;
+    @ApiModelProperty("感谢费")
+    private Double thankYouFee;
+//    @ApiModelProperty("开票状态(1=未开票,2=已开票)")
+//    private Integer invoice;
+    @ApiModelProperty("订单名称")
+    private String orderName;
+    @ApiModelProperty("订单类型(1=专车,2=出租车,3=跨城出行,4=小件物流,5=包车)")
+    private Integer orderType;
+    @ApiModelProperty("下单时间")
+    private Long insertTime;
+    @ApiModelProperty("服务结束事件")
+    private String endServiceTime;
+    @ApiModelProperty("乘车类型(1=独享,2=一口价,3=拼车)")
+    private Integer rideType;
+    @ApiModelProperty("上车经度")
+    private Double boardingLon;
+    @ApiModelProperty("上车纬度")
+    private Double boardingLat;
+    @ApiModelProperty("上车时间")
+    private LocalDateTime boardingTime;
+    @ApiModelProperty("到达时间")
+    private LocalDateTime arriveTime;
+    @ApiModelProperty("城市")
+    private String city;
+    @ApiModelProperty("服务商")
+    private String companyName;
+
+    public static List<TripOrderVo> getTripOrderVo(List<Map<String, Object>> maps) {
+        List<TripOrderVo> list = new ArrayList<>();
+        if (null != maps) {
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
+            for (Map<String, Object> map : maps) {
+                TripOrderVo tripOrderVo = new TripOrderVo();
+
+                tripOrderVo.setRideType(null != map.get("rideType") ? Integer.valueOf(String.valueOf(map.get("rideType"))) : 1);
+                tripOrderVo.setOrderId(null != map.get("orderId") ? Integer.valueOf(String.valueOf(map.get("orderId"))) : 0);
+                tripOrderVo.setOrderTime(null != map.get("orderTime") ? String.valueOf(map.get("orderTime")) : "");
+                tripOrderVo.setTime(null != map.get("time") ? String.valueOf(map.get("time")) : "");
+                tripOrderVo.setStartAddress(null != map.get("startAddress") ? String.valueOf(map.get("startAddress")) : "");
+                tripOrderVo.setEndAddress(null != map.get("endAddress") ? String.valueOf(map.get("endAddress")) : "");
+                tripOrderVo.setState(null != map.get("state") ? Integer.valueOf(String.valueOf(map.get("state"))) : 0);
+//                tripOrderVo.setOrderMoney(null != map.get("orderMoney") ? Double.valueOf(String.valueOf(map.get("orderMoney"))) : 0);
+                tripOrderVo.setPayMoney(null != map.get("payMoney") ? Double.valueOf(String.valueOf(map.get("payMoney"))) : 0);
+//                tripOrderVo.setInvoice(null != map.get("invoice") ? Integer.valueOf(String.valueOf(map.get("invoice"))) : 0);
+                tripOrderVo.setOrderName(null != map.get("orderName") ? String.valueOf(map.get("orderName")) : "");
+                tripOrderVo.setInsertTime(null != map.get("insertTime") ? Long.valueOf(String.valueOf(map.get("insertTime"))) : 0);
+                tripOrderVo.setOrderType(null != map.get("orderType") ? Integer.valueOf(String.valueOf(map.get("orderType"))) : 0);
+                tripOrderVo.setDriverId(null != map.get("driverId") ? Integer.valueOf(String.valueOf(map.get("driverId"))) : 0);
+                tripOrderVo.setCarTime(null != map.get("carTime") ? Integer.valueOf(String.valueOf(map.get("carTime"))) : 0);
+                tripOrderVo.setServerCarModel(null != map.get("serverCarModel") ? String.valueOf(map.get("serverCarModel")) : "");
+//                tripOrderVo.setDifferenceMoney(null != map.get("differenceMoney") ? Double.valueOf(map.get("differenceMoney").toString()) : 0D);
+                tripOrderVo.setThankYouFee(null != map.get("thankYouFee") ? Double.valueOf(map.get("thankYouFee").toString()) : 0D);
+                tripOrderVo.setEndServiceTime(null != map.get("endServiceTime") ? String.valueOf(map.get("endServiceTime")) : "");
+                tripOrderVo.setCompanyId(null != map.get("companyId") ? Integer.valueOf(String.valueOf(map.get("companyId"))) : 0);
+                tripOrderVo.setPassengersPhone(null != map.get("passengersPhone") ? String.valueOf(map.get("passengersPhone")) : "");
+                tripOrderVo.setBoardingLon(null != map.get("boardingLon") ? Double.valueOf(String.valueOf(map.get("boardingLon"))) : 0D);
+                tripOrderVo.setBoardingLat(null != map.get("boardingLat") ? Double.valueOf(String.valueOf(map.get("boardingLat"))) : 0D);
+                tripOrderVo.setCity(null != map.get("city") ? String.valueOf(map.get("city")) : "");
+                tripOrderVo.setBoardingTime(null != map.get("boardingTime") ?
+                        LocalDateTime.parse(String.valueOf(map.get("boardingTime")), formatter) : null);
+                tripOrderVo.setArriveTime(null != map.get("arriveTime") ?
+                        LocalDateTime.parse(String.valueOf(map.get("arriveTime")), formatter) : null);
+                tripOrderVo.setCompanyName(null != map.get("companyName") ? String.valueOf(map.get("companyName")) : "");
+                tripOrderVo.setCarId(null != map.get("carId") ? Integer.valueOf(String.valueOf(map.get("carId"))) : 0);
+                tripOrderVo.setServerCarModelId(null != map.get("serverCarModelId") ? Integer.valueOf(String.valueOf(map.get("serverCarModelId"))) : 0);
+                list.add(tripOrderVo);
+            }
+
+        }
+        Collections.sort(list);
+        return list;
+    }
+
+    @Override
+    public int compareTo(Object o) {
+        if (o instanceof OrderWarpper) {
+            OrderWarpper s = (OrderWarpper) o;
+            if(this.insertTime == null || s.getInsertTime() == null){
+                return -1;
+            }
+            if (this.insertTime > s.getInsertTime()) {
+                return -1;
+            } else if (this.insertTime == s.getInsertTime()) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+        return 0;
+    }
+}
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/pdf/TripSheetGenerator.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/pdf/TripSheetGenerator.java
new file mode 100644
index 0000000..eb4a023
--- /dev/null
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/pdf/TripSheetGenerator.java
@@ -0,0 +1,335 @@
+package com.stylefeng.guns.modular.system.pdf;
+
+import com.itextpdf.text.*;
+import com.itextpdf.text.pdf.BaseFont;
+import com.itextpdf.text.pdf.PdfPCell;
+import com.itextpdf.text.pdf.PdfPTable;
+import com.itextpdf.text.pdf.PdfWriter;
+import com.stylefeng.guns.modular.system.model.vo.TripOrderVo;
+import com.stylefeng.guns.modular.system.warpper.OrderWarpper;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.ServletContextAware;
+
+import java.io.*;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.UUID;
+
+@Component
+public class TripSheetGenerator {
+
+    @Value("${trip.sheet.filePath}")
+    private String pdfDir;
+
+    // 内置中文备用字体
+    private static final String FALLBACK_FONT = "STSong-Light";
+    private static final String FALLBACK_ENCODING = "UniGB-UCS2-H";
+
+    // 完整日期时间格式
+    private static final DateTimeFormatter DATE_TIME_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    public String generatePdf(List<TripOrderVo> orders) throws DocumentException, IOException {
+        if (orders == null || orders.isEmpty()) {
+            throw new IllegalArgumentException("订单列表不能为空");
+        }
+
+        String fileName = "行程单_" + UUID.randomUUID() + ".pdf";
+        String filePath = pdfDir + fileName;
+        File file = new File(filePath);
+        FileUtils.forceMkdirParent(file);
+
+        Document document = new Document(PageSize.A4);
+        PdfWriter.getInstance(document, new FileOutputStream(file));
+        document.open();
+
+        // 新布局:Logo+标题 → 主标题 → 信息行 → 表格
+        addLogoAndTitle(document);
+        addMainTitle(document);
+        addTripInfo(document, orders);
+        addOrderTable(document, orders);
+
+        document.close();
+        return filePath;
+    }
+
+    private void addLogoAndTitle(Document document) throws DocumentException {
+        try {
+            document.setMargins(10, 50, 50, 50); // 左=0,右=50,上=50,下=50(单位:pt)
+            Resource logoResource = new ClassPathResource("static/img/logo.png");
+            if (logoResource.exists()) {
+                Image logo = Image.getInstance(logoResource.getURL());
+                logo.scaleToFit(80, 40); // 保持logo原有尺寸(宽100pt,高40pt)
+
+                // 1. 调整表格列宽:左列刚好容纳logo,右列仅够放下文字(缩小间距)
+                // 列宽比例:左列100pt(logo宽度),右列80pt(文字宽度,足够放下“贵人家园”)
+                PdfPTable layoutTable = new PdfPTable(new float[]{81f, 100f}); // 左列(Logo),右列100f(文字)
+                layoutTable.setWidthPercentage(35);
+                layoutTable.setSpacingAfter(15f); // 与下方主标题的间距不变
+                layoutTable.setHorizontalAlignment(Element.ALIGN_LEFT); // 整体左对齐,避免居中导致的空隙
+
+                // 2. 左单元格(logo):消除内边距,紧贴右侧
+                PdfPCell logoCell = new PdfPCell(logo);
+                logoCell.setBorder(Rectangle.NO_BORDER); // 无边框
+                logoCell.setPadding(0); // 去除内边距(关键:默认padding会导致空隙)
+                logoCell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中对齐
+                logoCell.setHorizontalAlignment(Element.ALIGN_RIGHT); //logo居中
+                layoutTable.addCell(logoCell);
+
+                // 3. 右单元格(文字):消除内边距,紧贴左侧
+                Font titleFont = getChineseFont(18, Font.BOLD);
+                Paragraph titlePara = new Paragraph("贵人家园", titleFont);
+                titlePara.setAlignment(Element.ALIGN_LEFT); // 文字左对齐,贴近logo
+                titlePara.setSpacingBefore(0);
+                titlePara.setSpacingAfter(0);
+
+                PdfPCell titleCell = new PdfPCell(titlePara);
+                titleCell.setBorder(Rectangle.NO_BORDER); // 无边框
+                titleCell.setPadding(0); // 去除内边距(关键)
+                titleCell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中对齐
+                titleCell.setHorizontalAlignment(Element.ALIGN_LEFT); // 文字靠左,贴近logo
+                layoutTable.addCell(titleCell);
+
+                document.add(layoutTable);
+                // 关键3:恢复页面默认边距(避免影响后续内容)
+                document.setMargins(50, 50, 50, 50);
+            } else {
+                // 降级处理(无logo时)
+                Font titleFont = getChineseFont(18, Font.BOLD);
+                Paragraph fallbackTitle = new Paragraph("贵人家园", titleFont);
+                fallbackTitle.setAlignment(Element.ALIGN_LEFT);
+                fallbackTitle.setSpacingAfter(15f);
+                document.add(fallbackTitle);
+            }
+        } catch (Exception e) {
+            System.err.println("Logo加载失败: " + e.getMessage());
+            // 降级处理
+            Font titleFont = getChineseFont(18, Font.BOLD);
+            Paragraph fallbackTitle = new Paragraph("贵人家园", titleFont);
+            fallbackTitle.setAlignment(Element.ALIGN_LEFT);
+            fallbackTitle.setSpacingAfter(15f);
+            document.add(fallbackTitle);
+        }
+    }
+
+    // 新增主标题方法(原 addTitle 逻辑调整)
+    private void addMainTitle(Document document) throws DocumentException {
+        Font titleFont = getChineseFont(18, Font.BOLD);
+        Paragraph mainTitle = new Paragraph("贵人家园—打车—行程单", titleFont);
+        mainTitle.setAlignment(Element.ALIGN_CENTER);
+        mainTitle.setSpacingBefore(5f);
+        mainTitle.setSpacingAfter(15f);
+        document.add(mainTitle);
+    }
+
+
+
+    // 修改信息行构建逻辑(以第一行为例)
+    private void addTripInfo(Document document, List<TripOrderVo> orders) throws DocumentException {
+        if (orders.isEmpty()) return;
+        TripOrderVo first = orders.get(0);
+        TripOrderVo last = orders.size() > 1 ? orders.get(orders.size() - 1) : first;
+
+        Font infoFont = getChineseFont(10, Font.NORMAL);
+        // 申请时间现在的时间
+        String applyTime = DATE_TIME_FORMATTER.format(LocalDateTime.now());
+
+        // 行程时间格式化
+        String tripTimeStart = first.getBoardingTime() != null
+                ? DATE_TIME_FORMATTER.format(first.getBoardingTime()) : "N/A";
+        String tripTimeEnd = last.getBoardingTime() != null
+                ? DATE_TIME_FORMATTER.format(last.getBoardingTime()) : "N/A";
+        String tripTime = tripTimeStart + " 至 " + tripTimeEnd;
+
+        // 总金额计算(修复:先定义 totalText 并拼接内容)
+        double totalAmount = orders.stream()
+                .mapToDouble(o -> o.getPayMoney() != null ? o.getPayMoney() : 0)
+                .sum();
+        String totalPrefix = "共计" + orders.size() + "单行程,合计";
+        String totalMoney = String.format("%.2f元", totalAmount);
+        String totalText = totalPrefix + totalMoney; // 正确定义 totalText
+
+
+        // ========== 第一行:申请时间 + 行程时间(均带分隔条) ==========
+        // 关键:通过表格列宽控制分隔条宽度(8pt)
+        PdfPTable line1Table = new PdfPTable(4);
+        line1Table.setWidthPercentage(100);
+        line1Table.setSpacingAfter(5f);
+        // 列宽比例:分隔条列固定为8pt,内容列按比例分配
+        line1Table.setWidths(new float[]{4, 200, 4, 374});
+
+        // 列1:申请时间前的蓝色分隔条(宽度由表格列宽控制)
+        line1Table.addCell(createBlueSeparatorCell());
+
+        // 列2:申请时间内容
+        Paragraph applyPara = new Paragraph();
+        applyPara.add(new Chunk("申请时间:", infoFont));
+        applyPara.add(new Chunk(applyTime, infoFont));
+        line1Table.addCell(createContentCell(applyPara));
+
+        // 列3:行程时间前的蓝色分隔条(与列1宽度一致)
+        line1Table.addCell(createBlueSeparatorCell());
+
+        // 列4:行程时间内容
+        Paragraph tripPara = new Paragraph();
+        tripPara.add(new Chunk("行程时间:", infoFont));
+        tripPara.add(new Chunk(tripTime, infoFont));
+        line1Table.addCell(createContentCell(tripPara));
+
+        document.add(line1Table);
+
+
+        // ========== 第二行:手机号 + 共计订单(均带分隔条) ==========
+        PdfPTable line2Table = new PdfPTable(4);
+        line2Table.setWidthPercentage(100);
+        line2Table.setSpacingAfter(15f);
+        // 与第一行保持完全相同的列宽比例(确保分隔条对齐)
+        line2Table.setWidths(new float[]{4, 200, 4, 374});
+
+        // 列1:手机号前的蓝色分隔条
+        line2Table.addCell(createBlueSeparatorCell());
+
+        // 列2:手机号内容
+        Paragraph phonePara = new Paragraph();
+        phonePara.add(new Chunk("行程人手机号:", infoFont));
+        phonePara.add(new Chunk(first.getPassengersPhone() != null ? first.getPassengersPhone() : "N/A", infoFont));
+        line2Table.addCell(createContentCell(phonePara));
+
+        // 列3:共计订单前的蓝色分隔条
+        line2Table.addCell(createBlueSeparatorCell());
+
+        // 列4:共计订单内容
+        Paragraph totalPara = new Paragraph();
+        totalPara.add(new Chunk(totalPrefix, infoFont));
+        Font totalFont = getChineseFont(10, Font.BOLD);
+        totalFont.setColor(BaseColor.RED);
+        totalPara.add(new Chunk(totalMoney, totalFont));
+        line2Table.addCell(createContentCell(totalPara));
+
+        document.add(line2Table);
+    }
+
+    /**
+     * 蓝色分隔条单元格(宽度由所在表格的列宽控制,无需单独设置)
+     */
+    private PdfPCell createBlueSeparatorCell() {
+        PdfPCell separatorCell = new PdfPCell();
+        // 关键:不设置宽度,完全由表格的 setWidths() 控制
+        separatorCell.setBackgroundColor(BaseColor.BLUE); // 蓝色背景
+        separatorCell.setBorder(Rectangle.NO_BORDER); // 无边框
+        separatorCell.setMinimumHeight(8); // 匹配文字行高
+        separatorCell.setPadding(0); // 去除内边距,确保分隔条紧凑
+        return separatorCell;
+    }
+
+    /**
+     * 内容单元格样式
+     */
+    private PdfPCell createContentCell(Paragraph content) {
+        PdfPCell cell = new PdfPCell(content);
+        cell.setBorder(Rectangle.NO_BORDER);
+        cell.setPaddingLeft(5); // 内容与分隔条的间距
+        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
+        return cell;
+    }
+    private void addOrderTable(Document document, List<TripOrderVo> orders) throws DocumentException {
+        // 调整列宽:第1列(序号)加宽至1.5f
+        float[] columnWidths = {1.5f, 2f, 2f, 3f, 2f, 3f, 3f, 2f};
+        PdfPTable table = new PdfPTable(columnWidths);
+        table.setWidthPercentage(100);
+        table.setSpacingBefore(10f); // 与上方信息行的间距
+
+        // 表头样式(蓝色背景,白色文字,居中)
+        Font headerFont = getChineseFont(10, Font.BOLD);
+        headerFont.setColor(BaseColor.WHITE);
+        BaseColor headerBg = new BaseColor(59, 130, 246);
+        String[] headers = {"序号","服务商","车型","上车时间","城市","起点","终点","金额"};
+
+        for (String header : headers) {
+            PdfPCell cell = new PdfPCell(new Paragraph(header, headerFont));
+            cell.setBackgroundColor(headerBg);
+            cell.setPadding(5);
+            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+            table.addCell(cell);
+        }
+
+        // 单元格样式(居中对齐,统一处理)
+        Font cellFont = getChineseFont(9, Font.NORMAL);
+        for (int i = 0; i < orders.size(); i++) {
+            TripOrderVo order = orders.get(i);
+            // 序号列:强制居中,内容为 i+1
+            addCenteredCell(table, String.valueOf(i + 1), cellFont);
+            addCenteredCell(table, order.getCompanyName(), cellFont);
+            addCenteredCell(table, order.getServerCarModel(), cellFont);
+            addCenteredCell(table,
+                    order.getBoardingTime() != null
+                            ? DATE_TIME_FORMATTER.format(order.getBoardingTime())
+                            : "N/A",
+                    cellFont);
+            addCenteredCell(table, order.getCity(), cellFont);
+            addCenteredCell(table, order.getStartAddress(), cellFont);
+            addCenteredCell(table, order.getEndAddress(), cellFont);
+
+            // 金额列:右对齐
+            PdfPCell moneyCell = new PdfPCell(
+                    new Paragraph(String.format("%.2f元",
+                            order.getPayMoney() != null ? order.getPayMoney() : 0),
+                            cellFont)
+            );
+            moneyCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
+            moneyCell.setPadding(5);
+            table.addCell(moneyCell);
+        }
+
+        document.add(table);
+    }
+
+    // 辅助方法:创建居中对齐的单元格
+    private void addCenteredCell(PdfPTable table, String text, Font font) {
+        PdfPCell cell = new PdfPCell(new Paragraph(text != null ? text : "", font));
+        cell.setPadding(5);
+        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+        table.addCell(cell);
+    }
+
+    private void addTableCell(PdfPTable table, String text, Font font) {
+        PdfPCell cell = new PdfPCell(new Paragraph(text != null ? text : "", font));
+        cell.setPadding(5);
+        table.addCell(cell);
+    }
+
+    /**
+     * 获取中文字体,优先自定义字体,fallback到 CJK 内置
+     */
+    private Font getChineseFont(float size, int style) {
+        // 自定义字体
+        try {
+            Resource res = new ClassPathResource("static/fonts/AlibabaPuHuiTi-3-105-Heavy.ttf");
+            if (res.exists()) {
+                BaseFont bf = BaseFont.createFont(
+                        res.getURL().toString(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
+                return new Font(bf, size, style);
+            }
+        } catch (Exception e) {
+            System.err.println("加载自定义字体失败: " + e.getMessage());
+        }
+        // 内置 CJK 字体
+        try {
+            BaseFont bf = BaseFont.createFont(
+                    FALLBACK_FONT, FALLBACK_ENCODING, BaseFont.EMBEDDED);
+            return new Font(bf, size, style);
+        } catch (Exception e) {
+            System.err.println("加载备用字体失败: " + e.getMessage());
+            return new Font(Font.FontFamily.HELVETICA, size, style);
+        }
+    }
+}
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/EmailUtil.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/EmailUtil.java
new file mode 100644
index 0000000..e09f2dd
--- /dev/null
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/EmailUtil.java
@@ -0,0 +1,52 @@
+package com.stylefeng.guns.modular.system.util;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import java.io.File;
+
+@Component
+public class EmailUtil {
+    private final JavaMailSender javaMailSender;
+
+    // 从配置文件读取发件人邮箱(必须与spring.mail.username一致)
+    @Value("${spring.mail.username}")
+    private String fromEmail;
+
+    @Autowired
+    public EmailUtil(JavaMailSender javaMailSender) {
+        this.javaMailSender = javaMailSender;
+    }
+
+    public void sendEmailWithAttachment(String to, String subject, String text, File attachment) throws MessagingException {
+        MimeMessage message = javaMailSender.createMimeMessage();
+        MimeMessageHelper helper = new MimeMessageHelper(message, true);
+
+        // 设置发件人(必须与配置的spring.mail.username一致)
+        helper.setFrom(fromEmail);
+        // 设置收件人
+        helper.setTo(to);
+        // 设置邮件主题和内容
+        helper.setSubject(subject);
+        helper.setText(text);
+        // 添加附件
+        helper.addAttachment(attachment.getName(), attachment);
+
+        // 发送邮件
+        javaMailSender.send(message);
+    }
+
+    public void sendSimpleEmail(String to, String subject, String text) {
+        SimpleMailMessage message = new SimpleMailMessage();
+        message.setTo(to);
+        message.setSubject(subject);
+        message.setText(text);
+        javaMailSender.send(message);
+    }
+}
\ No newline at end of file
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/OrderTaxiMapper.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/OrderTaxiMapper.java
index 6f8920e..dce3cc5 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/OrderTaxiMapper.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/OrderTaxiMapper.java
@@ -89,4 +89,16 @@
      */
     List<OrderTaxi> queryByState_(@Param("uid") Integer uid, @Param("orderType") Integer orderType,
                                   @Param("type") Integer type, @Param("state") Integer...state);
+
+    /**
+     * 获取用户的行程列表
+     * @param uid
+     * @param pageNum
+     * @param size
+     * @return
+     */
+    List<Map<String, Object>> queryMyTripList(@Param("uid") Integer uid, @Param("pageNum") Integer pageNum,
+                                               @Param("size") Integer size);
+
+    List<Map<String, Object>> queryMyTripListAll(@Param("uid") Integer uid);
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/mapping/OrderTaxiMapper.xml b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/mapping/OrderTaxiMapper.xml
index da859a5..60883ea 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/mapping/OrderTaxiMapper.xml
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/dao/mapping/OrderTaxiMapper.xml
@@ -414,4 +414,50 @@
             and `type` = #{type}
         </if>
     </select>
+
+    <select id="queryMyTripList" resultType="map">
+        select
+            id as orderId,
+            DATE_FORMAT(insertTime, '%Y-%m-%d %H:%i') as orderTime,
+            DATE_FORMAT(travelTime, '%m月%d日 %H:%i') as time,
+        startAddress as startAddress,
+        endAddress as endAddress,
+        driverId as driverId,
+        (2) as orderType,
+        state as state,
+        oldState as oldState,
+        thankYouFee,
+        passengersPhone,
+        payMoney,
+        endServiceTime,
+        companyId,
+        arriveTime,
+        boardingTime,
+        boardingLon,
+        boardingLat
+        from t_order_taxi where userId = #{uid} order by insertTime desc limit #{pageNum}, #{size}
+    </select>
+
+    <select id="queryMyTripListAll" resultType="map">
+        select
+            id as orderId,
+            DATE_FORMAT(insertTime, '%Y-%m-%d %H:%i') as orderTime,
+            DATE_FORMAT(travelTime, '%m月%d日 %H:%i') as time,
+        startAddress as startAddress,
+        endAddress as endAddress,
+        driverId as driverId,
+        (2) as orderType,
+        state as state,
+        oldState as oldState,
+        thankYouFee,
+        passengersPhone,
+        payMoney,
+        endServiceTime,
+        companyId,
+        arriveTime,
+        boardingTime,
+        boardingLon,
+        boardingLat
+        from t_order_taxi where userId = #{uid} order by insertTime desc
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/IOrderTaxiService.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/IOrderTaxiService.java
index be2011e..caf8829 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/IOrderTaxiService.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/IOrderTaxiService.java
@@ -313,4 +313,16 @@
 
     void promotion(Integer orderId);
 
+    /**
+     * 获取我的行程列表
+     * @param uid
+     * @param pageNum
+     * @param size
+     * @return
+     * @throws Exception
+     */
+    List<Map<String, Object>> queryMyTripList(Integer uid, Integer pageNum, Integer size) throws Exception;
+
+    List<Map<String, Object>> queryMyTripListAll(Integer uid) throws Exception;
+
 }
diff --git a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/impl/OrderTaxiServiceImpl.java b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/impl/OrderTaxiServiceImpl.java
index 3b5bc2a..839b316 100644
--- a/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/impl/OrderTaxiServiceImpl.java
+++ b/UserQYTTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/taxi/service/impl/OrderTaxiServiceImpl.java
@@ -2332,4 +2332,29 @@
 			}
 		}
 	}
+
+	@Override
+	public List<Map<String, Object>> queryMyTripList(Integer uid, Integer pageNum, Integer size) throws Exception {
+		pageNum = (pageNum - 1) * size;
+		List<Map<String, Object>> maps = orderTaxiMapper.queryMyTripList(uid, pageNum, size);
+		for (Map<String, Object> map : maps) {
+			if (Integer.valueOf(String.valueOf(map.get("state"))) == 11) {
+				map.put("state", map.get("oldState"));
+			}
+		}
+		return maps;
+	}
+
+	@Override
+	public List<Map<String, Object>> queryMyTripListAll(Integer uid) throws Exception {
+
+		List<Map<String, Object>> maps = orderTaxiMapper.queryMyTripListAll(uid);
+		for (Map<String, Object> map : maps) {
+			if (Integer.valueOf(String.valueOf(map.get("state"))) == 11) {
+				map.put("state", map.get("oldState"));
+			}
+		}
+		return maps;
+	}
+
 }
diff --git a/UserQYTTravel/guns-admin/src/main/resources/application.yml b/UserQYTTravel/guns-admin/src/main/resources/application.yml
index 3d56997..8a3a7ca 100644
--- a/UserQYTTravel/guns-admin/src/main/resources/application.yml
+++ b/UserQYTTravel/guns-admin/src/main/resources/application.yml
@@ -33,14 +33,14 @@
     host: 192.168.110.80
     port: 6379
     password: 123456
-#  redis:
-#    host: 172.21.35.151
-#    port: 6512
-#    password: SC_cache@20#25
-#    database: 0
-#    timeout: 1000
-#    cluster:
-#      nodes: 172.21.35.151:6512,172.21.35.152:6512,172.21.35.153:6512,172.21.35.151:6513,172.21.35.152:6513,172.21.35.153:6513
+  #  redis:
+  #    host: 172.21.35.151
+  #    port: 6512
+  #    password: SC_cache@20#25
+  #    database: 0
+  #    timeout: 1000
+  #    cluster:
+  #      nodes: 172.21.35.151:6512,172.21.35.152:6512,172.21.35.153:6512,172.21.35.151:6513,172.21.35.152:6513,172.21.35.153:6513
 
 mybatis-plus:
   typeAliasesPackage: com.stylefeng.guns.modular
@@ -72,13 +72,13 @@
     filters: wall,mergeStat
 
 
-#spring:
-#  datasource:
-#    url: jdbc:mysql://172.21.35.140:8066/traffic_scdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=Asia/Shanghai
-#    username: traffic_scusr
-#    password: QYT_sc@20#25
-#    db-name: traffic_scdb #用来搜集数据库的所有表
-#    filters: wall,mergeStat
+  #spring:
+  #  datasource:
+  #    url: jdbc:mysql://172.21.35.140:8066/traffic_scdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=Asia/Shanghai
+  #    username: traffic_scusr
+  #    password: QYT_sc@20#25
+  #    db-name: traffic_scdb #用来搜集数据库的所有表
+  #    filters: wall,mergeStat
 
 
 ---
@@ -86,7 +86,7 @@
   data:
     mongodb:
       uri: mongodb://192.168.110.80:27017/traveling_track
-#      uri: mongodb://qyt_jtcx:qyt_jtcx2025@172.21.35.195:27017,172.21.35.196:27017/traveling_track
+  #      uri: mongodb://qyt_jtcx:qyt_jtcx2025@172.21.35.195:27017,172.21.35.196:27017/traveling_track
 
 
 ---
@@ -127,3 +127,21 @@
 
 #交通部推送数据功能开关
 pushMinistryOfTransport: false
+
+#邮件配置
+spring:
+  mail:
+    host: smtp.qq.com
+    port: 465
+    username: 1721849008@qq.com
+    password: nhnbmjfdywilcbdj  # 这里是授权码,不是邮箱登录密码
+    properties:
+      mail:
+        smtp:
+          ssl:
+            enable: true  # 启用 SSL 加密(根据端口是否为 465 决定,通常需要开启)
+          auth: true      # 启用身份验证(必须为 true)
+# pdf生成位置
+trip:
+  sheet:
+    filePath: D:/qytPdf/
\ No newline at end of file
diff --git a/UserQYTTravel/guns-admin/src/main/resources/static/fonts/AlibabaPuHuiTi-3-105-Heavy.ttf b/UserQYTTravel/guns-admin/src/main/resources/static/fonts/AlibabaPuHuiTi-3-105-Heavy.ttf
new file mode 100644
index 0000000..3d865c2
--- /dev/null
+++ b/UserQYTTravel/guns-admin/src/main/resources/static/fonts/AlibabaPuHuiTi-3-105-Heavy.ttf
Binary files differ
diff --git a/UserQYTTravel/guns-admin/src/main/resources/static/img/logo.png b/UserQYTTravel/guns-admin/src/main/resources/static/img/logo.png
new file mode 100644
index 0000000..0576707
--- /dev/null
+++ b/UserQYTTravel/guns-admin/src/main/resources/static/img/logo.png
Binary files differ

--
Gitblit v1.7.1