From 0ab919187081583c07a9b7654050f6e8741628dc Mon Sep 17 00:00:00 2001
From: xin <1099200748@qq.com>
Date: Sat, 27 Sep 2025 23:13:16 +0800
Subject: [PATCH] 运费计算器

---
 oying-system/src/main/java/com/oying/modules/sh/utils/ShippingFeeCalculator.java |  208 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 208 insertions(+), 0 deletions(-)

diff --git a/oying-system/src/main/java/com/oying/modules/sh/utils/ShippingFeeCalculator.java b/oying-system/src/main/java/com/oying/modules/sh/utils/ShippingFeeCalculator.java
new file mode 100644
index 0000000..d7ad514
--- /dev/null
+++ b/oying-system/src/main/java/com/oying/modules/sh/utils/ShippingFeeCalculator.java
@@ -0,0 +1,208 @@
+package com.oying.modules.sh.utils;
+
+import com.oying.utils.BigDecimalUtils;
+import com.oying.utils.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author xin
+ * @description 运费计算器
+ * @date 2025/9/27 21:08
+ */
+public class ShippingFeeCalculator {
+
+    // 商品类型枚举
+    public enum ProductType {
+        FOOD,          // 食品小吃、饮料、商超
+        SPECIAL         // 鲜花、蛋糕、电商、高端餐饮
+    }
+
+    // 城市等级枚举
+    public enum CityLevel {
+        C, D, E
+    }
+
+    // 基础运费配置
+    private static class BaseFeeConfig {
+        private final double foodFee;
+        private final double specialFee;
+
+        public BaseFeeConfig(double foodFee, double specialFee) {
+            this.foodFee = foodFee;
+            this.specialFee = specialFee;
+        }
+
+        public double getFee(ProductType type) {
+            return type == ProductType.FOOD ? foodFee : specialFee;
+        }
+    }
+
+    // 各等级对应的基础运费
+    private static final Map<CityLevel, BaseFeeConfig> LEVEL_FEES = new HashMap<>();
+
+    static {
+        LEVEL_FEES.put(CityLevel.C, new BaseFeeConfig(5.2, 7.2));
+        LEVEL_FEES.put(CityLevel.D, new BaseFeeConfig(4.7, 6.7));
+        LEVEL_FEES.put(CityLevel.E, new BaseFeeConfig(4.5, 6.0));
+    }
+
+    // 城市到等级的映射
+    private static final Map<String, CityLevel> CITY_LEVELS = new HashMap<>();
+
+    static {
+        // C等级城市
+        CITY_LEVELS.put("西安市", CityLevel.C);
+        CITY_LEVELS.put("福州市", CityLevel.C);
+        CITY_LEVELS.put("上海市", CityLevel.C);
+        CITY_LEVELS.put("哈尔滨", CityLevel.C);
+        CITY_LEVELS.put("杭州市", CityLevel.C);
+        CITY_LEVELS.put("北京市", CityLevel.C);
+        CITY_LEVELS.put("长春市", CityLevel.C);
+        CITY_LEVELS.put("珠海市", CityLevel.C);
+        CITY_LEVELS.put("重庆市", CityLevel.C);
+        CITY_LEVELS.put("舟山市", CityLevel.C);
+
+        // D等级城市
+        CITY_LEVELS.put("郑州市", CityLevel.D);
+        CITY_LEVELS.put("大连市", CityLevel.D);
+        CITY_LEVELS.put("天津市", CityLevel.D);
+        CITY_LEVELS.put("长沙市", CityLevel.D);
+        CITY_LEVELS.put("中山市", CityLevel.D);
+        CITY_LEVELS.put("东莞市", CityLevel.D);
+        CITY_LEVELS.put("广州市", CityLevel.D);
+        CITY_LEVELS.put("贵阳市", CityLevel.D);
+        CITY_LEVELS.put("兰州市", CityLevel.D);
+        CITY_LEVELS.put("温州市", CityLevel.D);
+        CITY_LEVELS.put("厦门市", CityLevel.D);
+        CITY_LEVELS.put("惠州市", CityLevel.D);
+        CITY_LEVELS.put("深圳市", CityLevel.D);
+        CITY_LEVELS.put("青岛市", CityLevel.D);
+
+        // E等级城市
+        CITY_LEVELS.put("邯郸市", CityLevel.E);
+        CITY_LEVELS.put("宿迁市", CityLevel.E);
+        CITY_LEVELS.put("湖州市", CityLevel.E);
+        CITY_LEVELS.put("绍兴市", CityLevel.E);
+        CITY_LEVELS.put("金华市", CityLevel.E);
+        CITY_LEVELS.put("衢州市", CityLevel.E);
+        CITY_LEVELS.put("台州市", CityLevel.E);
+        CITY_LEVELS.put("丽水市", CityLevel.E);
+        CITY_LEVELS.put("阜阳市", CityLevel.E);
+        CITY_LEVELS.put("三明市", CityLevel.E);
+        CITY_LEVELS.put("南平市", CityLevel.E);
+        CITY_LEVELS.put("龙岩市", CityLevel.E);
+        CITY_LEVELS.put("宁德市", CityLevel.E);
+        CITY_LEVELS.put("淄博市", CityLevel.E);
+        CITY_LEVELS.put("济宁市", CityLevel.E);
+        CITY_LEVELS.put("威海市", CityLevel.E);
+        CITY_LEVELS.put("日照市", CityLevel.E);
+        CITY_LEVELS.put("十堰市", CityLevel.E);
+        CITY_LEVELS.put("衡阳市", CityLevel.E);
+        CITY_LEVELS.put("泸州市", CityLevel.E);
+        CITY_LEVELS.put("绵阳市", CityLevel.E);
+        CITY_LEVELS.put("泰安市", CityLevel.E);
+        CITY_LEVELS.put("廊坊市", CityLevel.E);
+    }
+
+    // 加价规则常量
+    private static final double BASE_DISTANCE = 1.0; // 起步距离1公里
+    private static final double BASE_WEIGHT = 5.0;   // 起步重量5公斤
+    private static final double DISTANCE_RATE = 1.0; // 距离加价:每公里1元
+    private static final double WEIGHT_RATE = 2.0;   // 重量加价:每公斤2元
+
+    /**
+     * 计算订单运费
+     *
+     * @param city        城市名称
+     * @param productType 商品类型
+     * @param distance    配送距离(公里)
+     * @param weight      商品重量(公斤)
+     * @param isPeakHour  是否午高峰时段
+     * @return 总运费
+     */
+    public static double calculateShippingFee(String city, ProductType productType,
+                                              double distance, double weight, boolean isPeakHour) {
+        if (StringUtils.isEmpty(city)) {
+            city = "重庆市";
+        }
+        // 获取城市等级
+        CityLevel level = CITY_LEVELS.get(city);
+
+        // 基础运费
+        double baseFee = LEVEL_FEES.get(level).getFee(productType);
+
+        // 距离加价(超过1公里部分,每公里加1元)
+        double distanceFee = 0;
+        if (distance > BASE_DISTANCE) {
+            double extraDistance = Math.min(distance - BASE_DISTANCE, 2.0); // 1-3公里内加价
+            distanceFee = Math.ceil(extraDistance) * DISTANCE_RATE;
+        }
+
+        // 重量加价(超过5公斤部分,每公斤加2元)
+        double weightFee = 0;
+        if (weight > BASE_WEIGHT) {
+            double extraWeight = weight - BASE_WEIGHT;
+            weightFee = Math.ceil(extraWeight) * WEIGHT_RATE;
+        }
+
+        // 时段加价(午高峰时段,具体加价金额需补充)
+        double peakFee = isPeakHour ? getPeakHourFee() : 0;
+
+        return baseFee + distanceFee + weightFee + peakFee;
+    }
+
+    /**
+     * 获取午高峰时段加价费用(需要根据具体规则补充)
+     */
+    private static double getPeakHourFee() {
+        // 根据实际午高峰加价规则返回具体金额
+        return 0.0; // 暂设为0,需补充具体规则
+    }
+
+    /**
+     * 获取城市运费等级信息
+     */
+    public static String getCityLevelInfo(String city) {
+        if (StringUtils.isEmpty(city)) {
+            city = "重庆市";
+        }
+        CityLevel level = CITY_LEVELS.get(city);
+
+        BaseFeeConfig config = LEVEL_FEES.get(level);
+        return String.format("城市: %s, 等级: %s, 食品类起步费: %.1f元, 特殊类起步费: %.1f元",
+                city, level, config.foodFee, config.specialFee);
+    }
+
+    /**
+     * 重量换算kg
+     *
+     * @param grams 重量 单位:g
+     * @return double
+     */
+    public static double safeConvert(Integer grams) {
+        if (grams == null || grams < 0) {
+            return 0.0; // 返回默认值
+        }
+        return grams / 1000.0;
+    }
+
+    // 测试示例
+    public static void main(String[] args) {
+        // 测试不同城市的运费计算
+        System.out.println("=== 运费计算测试 ===");
+        double distance = 9.00;
+        double width = safeConvert(1500);
+        String[] testCities = {null, "", "淄博市", "天津市"};
+        for (String city : testCities) {
+            System.out.println(getCityLevelInfo(city));
+            // 计算示例订单
+            double fee1 = calculateShippingFee(city, ProductType.FOOD, distance, width, false);
+            double fee2 = calculateShippingFee(city, ProductType.SPECIAL, distance, width, true);
+            System.out.printf("  食品订单(" + distance + "km, " + width + "kg): %.1f元\n", fee1);
+            System.out.printf("  特殊订单(" + distance + "km, " + width + "kg, 高峰): %.1f元\n", fee2);
+            System.out.println();
+        }
+    }
+}

--
Gitblit v1.9.3