package com.oying.modules.sh.utils; import java.time.LocalTime; import java.util.HashMap; import java.util.Map; public class ShippingFeeCalculator { // 城市等级映射 private static final Map CITY_LEVEL_MAP = new HashMap<>(); // 等级基础运费映射 (普通品类, 特殊品类) private static final Map LEVEL_BASE_FEE_MAP = new HashMap<>(); // 高峰时段及加价规则 private static final Object[][] PEAK_HOURS_RULES = { {LocalTime.of(0, 0), LocalTime.of(6, 0), 4.0}, // 00:00-06:00 加价4元 {LocalTime.of(11, 0), LocalTime.of(13, 0), 2.0}, // 11:00-13:00 加价2元 {LocalTime.of(21, 0), LocalTime.of(23, 59), 3.0} // 21:00-23:59 加价3元 }; // 特殊品类 private static final String[] SPECIAL_CATEGORIES = { "鲜花", "蛋糕", "电商", "高端餐饮" }; static { // 初始化城市等级映射 initializeCityLevelMap(); // 初始化等级基础运费 initializeLevelBaseFee(); } private static void initializeCityLevelMap() { // C等级城市 String[] levelCCities = {"西安", "福州", "上海", "哈尔滨", "杭州", "北京", "长春", "珠海", "重庆", "舟山"}; for (String city : levelCCities) { CITY_LEVEL_MAP.put(city, "C"); } // D等级城市 String[] levelDCities = {"郑州", "大连", "天津", "长沙", "中山", "东莞", "广州", "贵阳", "兰州", "温州", "厦门", "惠州", "深圳"}; for (String city : levelDCities) { CITY_LEVEL_MAP.put(city, "D"); } // E等级城市 String[] levelECities = {"青岛", "邯郸", "宿迁", "湖州", "绍兴", "金华", "衢州", "台州", "丽水", "阜阳", "三明", "南平", "龙岩", "宁德", "淄博", "济宁", "威海", "十堰", "泸州", "绵阳", "德阳", "汉阳", "襄阳", "武汉", "常德", "沈阳"}; for (String city : levelECities) { CITY_LEVEL_MAP.put(city, "E"); } } private static void initializeLevelBaseFee() { // 等级C: 普通品类5.2元,特殊品类6.7元 LEVEL_BASE_FEE_MAP.put("C", new Double[]{5.8, 7.9}); // 等级D: 普通品类4.7元,特殊品类6.7元 LEVEL_BASE_FEE_MAP.put("D", new Double[]{5.2, 7.3}); // 等级E: 普通品类4.5元,特殊品类6.0元 LEVEL_BASE_FEE_MAP.put("E", new Double[]{5.0, 6.6}); } /** * 计算运费 * * @param city 城市名称 * @param category 商品品类 * @param weight 重量(公斤) * @param distance 距离(公里) * @param orderTime 下单时间 * @param isSpecialConditions 是否特殊条件(恶劣天气、运力紧张、特殊日期) * @return 总运费 */ public static double calculateShippingFee(String city, String category, double weight, double distance, LocalTime orderTime, boolean isSpecialConditions) { double totalFee = 0.0; // 1. 基础运费 totalFee += calculateBaseFee(city, category); // 2. 重量加价 totalFee += calculateWeightSurcharge(weight); // 3. 距离加价 totalFee += calculateDistanceSurcharge(distance); // 4. 时段加价 totalFee += calculateTimeSurcharge(orderTime); // 5. 特殊条件加价(需要外部传入具体加价金额,这里返回基础值) if (isSpecialConditions) { totalFee += 1.0; // 默认加价1元,实际应根据具体规则调整 } return totalFee; } /** * 计算基础运费 */ private static double calculateBaseFee(String city, String category) { String cityLevel = CITY_LEVEL_MAP.getOrDefault(city, "E"); // 默认E等级 Double[] fees = LEVEL_BASE_FEE_MAP.get(cityLevel); if (fees == null) { fees = LEVEL_BASE_FEE_MAP.get("E"); // 默认使用E等级 } // 判断是否为特殊品类 boolean isSpecialCategory = false; for (String specialCat : SPECIAL_CATEGORIES) { if (category.contains(specialCat)) { isSpecialCategory = true; break; } } return isSpecialCategory ? fees[1] : fees[0]; } /** * 计算重量加价 */ private static double calculateWeightSurcharge(double weight) { final double BASE_WEIGHT = 5.0; // 起步重量5公斤 final double SURCHARGE_PER_KG = 2.0; // 每公斤加价2元 if (weight <= BASE_WEIGHT) { return 0.0; } double excessWeight = weight - BASE_WEIGHT; return Math.ceil(excessWeight) * SURCHARGE_PER_KG; } /** * 计算距离加价 */ private static double calculateDistanceSurcharge(double distance) { double surcharge = 0.0; // 分段计算加价 if (distance > 7.0) { surcharge += (distance - 7.0) * 4.0; // 超过7km部分 distance = 7.0; } if (distance > 5.0) { surcharge += (distance - 5.0) * 3.0; // 5-7km部分 distance = 5.0; } if (distance > 3.0) { surcharge += (distance - 3.0) * 2.0; // 3-5km部分 distance = 3.0; } if (distance > 1.0) { surcharge += (distance - 1.0); // 1-3km部分 // 0-1km部分不加价 } return surcharge; } /** * 计算时段加价 */ private static double calculateTimeSurcharge(LocalTime orderTime) { for (Object[] rule : PEAK_HOURS_RULES) { LocalTime startTime = (LocalTime) rule[0]; LocalTime endTime = (LocalTime) rule[1]; double surcharge = (Double) rule[2]; if (!orderTime.isBefore(startTime) && !orderTime.isAfter(endTime)) { return surcharge; } } return 0.0; } /** * 使用示例 - 优化版 */ public static void main(String[] args) { System.out.println( "等级C: 普通品类5.8元,特殊品类7.9元\n" + "等级D: 普通品类5.2元,特殊品类7.3元\n" + "等级E: 普通品类5.0元,特殊品类6.6元" ); // 测试用例数组 Object[][] testCases = { // 城市, 品类, 重量(kg), 距离(km), 时间, 特殊条件, 预期运费描述 {"上海", "食品小吃", 7.0, 3.5, LocalTime.of(14, 30), false, "普通商品,超重,中距离,非高峰"}, {"北京", "蛋糕", 10.0, 8.0, LocalTime.of(12, 30), false, "特殊商品,超重,长距离,高峰"}, {"青岛", "饮料", 3.0, 2.0, LocalTime.of(10, 0), false, "普通商品,未超重,中距离,非高峰"}, {"深圳", "高端餐饮", 5.0, 0.5, LocalTime.of(5, 30), true, "特殊商品,临界重量,短距离,高峰+特殊"}, {"武汉", "普通商品", 15.0, 6.0, LocalTime.of(20, 0), false, "普通商品,超重,中距离,高峰"}, {"西安", "电商", 2.0, 10.0, LocalTime.of(15, 0), true, "特殊商品,未超重,长距离,特殊"}, {"广州", "普通商品", 5.0, 1.0, LocalTime.of(12, 0), false, "普通商品,临界重量,临界距离,高峰"}, {"沈阳", "蛋糕", 8.0, 4.0, LocalTime.of(22, 30), true, "特殊商品,超重,中距离,高峰+特殊"}, {"杭州", "鲜花", 4.0, 7.0, LocalTime.of(9, 0), false, "特殊商品,未超重,临界距离,非高峰"}, {"重庆", "普通商品", 6.0, 3.0, LocalTime.of(0, 30), true, "普通商品,超重,临界距离,高峰+特殊"} }; // 打印表头 System.out.println("+--------+------------+--------+--------+----------+--------------+----------+-----------------+"); System.out.println("| 测试ID | 城市 | 品类 | 重量(kg) | 距离(km) | 时间 | 特殊条件 | 运费(元) | 描述"); System.out.println("+--------+------------+--------+--------+----------+--------------+--------------+-----------------+"); for (int i = 0; i < testCases.length; i++) { Object[] testCase = testCases[i]; String city = (String) testCase[0]; String category = (String) testCase[1]; double weight = (double) testCase[2]; double distance = (double) testCase[3]; LocalTime time = (LocalTime) testCase[4]; boolean special = (boolean) testCase[5]; String description = (String) testCase[6]; double fee = calculateShippingFee(city, category, weight, distance, time, special); // 格式化输出 System.out.printf("| %-6d | %-8s | %-6s | %-6.1f | %-8.1f | %-12s | %-8s | %-8.2f | %s%n", i + 1, city + ":" + CITY_LEVEL_MAP.getOrDefault(city, "E"), category, weight, distance, time, special ? "是" : "否", fee, description); } // 打印表尾 System.out.println("+--------+------------+--------+--------+----------+--------------+--------------+-----------------+"); // 边界值测试 System.out.println("\n边界值测试C等级城市:"); System.out.println("1. 重量边界(5kg): " + calculateShippingFee("上海", "普通", 5.0, 3.0, LocalTime.of(10, 0), false)); System.out.println("2. 距离边界(1km): " + calculateShippingFee("上海", "普通", 3.0, 1.0, LocalTime.of(10, 0), false)); System.out.println("3. 时间边界(06:00): " + calculateShippingFee("上海", "普通", 3.0, 3.0, LocalTime.of(6, 0), false)); } }