xin
17 hours ago d3563f0bdb487124d79cdd20d0f8bfc79db31f24
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
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<String, String> CITY_LEVEL_MAP = new HashMap<>();
 
    // 等级基础运费映射 (普通品类, 特殊品类)
    private static final Map<String, Double[]> 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));
    }
}