| 
					
				 | 
			
			
				@@ -0,0 +1,184 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package com.qmrb.parking.fee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.time.Duration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.time.LocalDateTime; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.time.LocalTime; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.ArrayList; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.List; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class ParkingFeeCalculator { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计费规则类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static class FeeRule { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int freeDurationMinutes; // 免费时长(分钟) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public double firstCycleFee; // 首周期费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int firstCycleDurationMinutes; // 首周期时长(分钟) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int cycleDurationMinutes; // 计费周期时长(分钟) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public double cycleFee; // 每个计费周期的费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public double dailyCapFee; // 24 小时封顶费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int gracePeriodMinutes; // 离场时长宽容度(分钟) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 停车记录类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static class ParkingRecord { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public LocalDateTime entryTime; // 入场时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public LocalDateTime exitTime; // 离场时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public LocalDateTime monthlyCardExpiryTime; // 月卡到期时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public double paidAmount; // 已支付金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public List<PaymentRecord> paymentRecords = new ArrayList<>(); // 支付记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 支付记录类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static class PaymentRecord { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public LocalDateTime paymentTime; // 支付时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public double amount; // 支付金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算停车费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static double calculateParkingFee(ParkingRecord parkingRecord, FeeRule feeRule, boolean isMonthlyCardMode) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 1. 确定计费开始时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        LocalDateTime billingStartTime = parkingRecord.entryTime; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (parkingRecord.monthlyCardExpiryTime != null && parkingRecord.monthlyCardExpiryTime.isAfter(parkingRecord.entryTime)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            billingStartTime = parkingRecord.monthlyCardExpiryTime; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 2. 确定计费结束时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        LocalDateTime billingEndTime = isMonthlyCardMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ? LocalDateTime.of(parkingRecord.exitTime.toLocalDate(), LocalTime.MIN) // 办卡清费模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                : parkingRecord.exitTime; // 临停收费模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 3. 计算计费时长 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Duration billingDuration = Duration.between(billingStartTime, billingEndTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 4. 检查离场时长宽容度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (feeRule.gracePeriodMinutes > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (PaymentRecord payment : parkingRecord.paymentRecords) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (payment.paymentTime.isAfter(billingEndTime.minusMinutes(feeRule.gracePeriodMinutes))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    billingDuration = billingDuration.minusMinutes(feeRule.gracePeriodMinutes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 5. 判断是否在免费时长内 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (billingDuration.toMinutes() <= feeRule.freeDurationMinutes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 6. 计算费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double totalFee = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 6.1 超过 24 小时的部分 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (billingDuration.toHours() >= 24) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int fullDays = (int) (billingDuration.toHours() / 24); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalFee += fullDays * feeRule.dailyCapFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 剩余不足 24 小时的部分 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Duration remainingDuration = billingDuration.minusHours(fullDays * 24); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            double remainingFee = calculateRemainingFeeDue(remainingDuration, feeRule); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalFee += Math.min(remainingFee, feeRule.dailyCapFee); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 6.2 不超过 24 小时的部分 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalFee = calculateRemainingFee(billingDuration, feeRule); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalFee = Math.min(totalFee, feeRule.dailyCapFee); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 7. 扣除已支付金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        totalFee = Math.max(0, totalFee - parkingRecord.paidAmount); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return totalFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算不足 24 小时的费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static double calculateRemainingFee(Duration duration, FeeRule feeRule) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double totalFee = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 扣除首周期时长 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Duration remainingDuration = duration.minusMinutes(feeRule.firstCycleDurationMinutes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        totalFee += feeRule.firstCycleFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 计算剩余周期的费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (remainingDuration.toMinutes() > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int cycles = (int) Math.ceil((double) remainingDuration.toMinutes() / feeRule.cycleDurationMinutes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalFee += cycles * feeRule.cycleFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return totalFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 超过24小时的剩余不足24小时部分 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param duration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param feeRule 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static double calculateRemainingFeeDue(Duration duration, FeeRule feeRule) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double totalFee = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 计算剩余周期的费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (duration.toMinutes() > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int cycles = (int) Math.ceil((double) duration.toMinutes() / feeRule.cycleDurationMinutes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            totalFee += cycles * feeRule.cycleFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return totalFee; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* * 场景2:设【免费时长】=10分钟;【24小时收费金额】=50元;【首周期计费时长】=120分钟;【首周期计费金额】=20元;【计费周期】=30分钟;【每周期计费金额】=5元 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static void e2(){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 示例计费规则 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        FeeRule feeRule = new FeeRule(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.freeDurationMinutes = 10; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.firstCycleFee = 20.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.firstCycleDurationMinutes = 120;//首周期计费时长 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.cycleDurationMinutes = 30;//计费周期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.cycleFee = 5.0;//每周期计费金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.dailyCapFee = 50.0;//24小时封顶费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.gracePeriodMinutes = 15; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 示例停车记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ParkingRecord parkingRecord = new ParkingRecord(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.entryTime = LocalDateTime.of(2025, 3, 4, 0, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.exitTime = LocalDateTime.of(2025, 3, 5, 0, 16); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.monthlyCardExpiryTime = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.paidAmount = 0.0;//已支付金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 计算费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double fee = calculateParkingFee(parkingRecord, feeRule, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        System.out.println("停车费用: " + fee + " 元"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 设【免费时长】=0;【24小时收费金额】=30元;【首周期计费时长】=60分钟;【首周期计费金额】=20元;【计费周期】=30分钟;【每周期计费金额】=2元 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static void e1(){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 示例计费规则 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        FeeRule feeRule = new FeeRule(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.freeDurationMinutes = 0;//免费时长 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.firstCycleFee = 20.0;//首周期计费金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.firstCycleDurationMinutes = 60;//首周期计费时长 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.cycleDurationMinutes = 30;//计费周期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.cycleFee = 2.0;//每周期计费金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.dailyCapFee = 30.0;//24小时封顶费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        feeRule.gracePeriodMinutes = 15; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 示例停车记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ParkingRecord parkingRecord = new ParkingRecord(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.entryTime = LocalDateTime.of(2025, 3, 3, 0, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.exitTime = LocalDateTime.of(2025, 3, 8, 10, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.monthlyCardExpiryTime = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        parkingRecord.paidAmount = 0.0;//已支付金额 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 计算费用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double fee = calculateParkingFee(parkingRecord, feeRule, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        System.out.println("停车费用: " + fee + " 元"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param args 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static void main(String[] args) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        e1(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//        e2(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |