xin
2025-09-27 db091e95d9e4c83241fb25f14bd9f36b40e0de1e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package com.oying.modules.sh.utils;
 
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();
        }
    }
}