liu
16 小时以前 3e144b2eb8fc9447d2d092edb71db533d12abc52
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
package com.ruoyi.production.enums;
 
import lombok.Getter;
 
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 生产报工产品大类。
 *
 * <p>报工只区分乐器大类(小提琴/中提琴/大提琴/贝斯),不再区分零件。
 * 大类同时是「折合小提琴当量」折算的匹配键,因此这里的规范值必须与
 * 前端下拉选项、{@code production_product_main.major_category} 落库值保持一致。</p>
 *
 * <p>本枚举是大类判定的<b>唯一事实源</b>:报工写入时按产品名称归类;
 * 工资核算与生产核算直接读取已落库的大类字段,不再各自做字符串比较。</p>
 *
 * @since 2026/09/24
 */
@Getter
public enum MajorCategoryEnum {
 
    VIOLIN("小提琴", "小提琴"),
    VIOLA("中提琴", "中提琴"),
    CELLO("大提琴", "大提琴"),
    BASS("贝斯", "贝斯", "贝司");
 
    /**
     * 配件排除词:琴盒/琴套/弓盒等配件名称里可能出现「贝司」「大提套」等字样
     * (如“SA贝司套”“SA大提套”),先排除,避免被误归入乐器大类。
     */
    private static final List<String> ACCESSORY_EXCLUDES = List.of("琴盒", "琴套", "弓盒");
 
    /**
     * 大类规范值 -> 该大类的产品名称匹配别名。
     * 现场数据把「贝斯」写作「贝司」,故 BASS 配了两个别名。
     */
    private static final Map<String, List<String>> CATEGORY_ALIASES = new LinkedHashMap<>();
 
    static {
        for (MajorCategoryEnum item : values()) {
            CATEGORY_ALIASES.put(item.category, List.of(item.aliases));
        }
    }
 
    /** 大类规范值,落库到 production_product_main.major_category */
    private final String category;
 
    /** 用于匹配产品名称的别名,第一个与规范值相同 */
    private final String[] aliases;
 
    MajorCategoryEnum(String category, String... aliases) {
        this.category = category;
        this.aliases = aliases;
    }
 
    /**
     * 按产品名称归入乐器大类。自底向上遍历产品树时逐层调用,命中即返回。
     *
     * @param productName 产品名称,可为 null
     * @return 大类规范值;配件、非乐器产品、空值一律返回 null
     */
    public static String match(String productName) {
        if (productName == null || productName.isEmpty()) {
            return null;
        }
        if (ACCESSORY_EXCLUDES.stream().anyMatch(productName::contains)) {
            return null;
        }
        for (Map.Entry<String, List<String>> entry : CATEGORY_ALIASES.entrySet()) {
            for (String alias : entry.getValue()) {
                if (productName.contains(alias)) {
                    return entry.getKey();
                }
            }
        }
        return null;
    }
 
    /**
     * 按大类规范值取枚举。
     *
     * @param category 大类规范值,可为 null
     * @return 对应枚举;null 或未知取值返回 null
     */
    public static MajorCategoryEnum of(String category) {
        if (category == null || category.isEmpty()) {
            return null;
        }
        for (MajorCategoryEnum item : values()) {
            if (item.category.equals(category)) {
                return item;
            }
        }
        return null;
    }
 
    /**
     * 判断是否是乐器大类。报工未归类(大类为 null)时返回 false,
     * 由调用方走「非乐器产品」分支处理。
     */
    public static boolean isInstrument(String category) {
        return of(category) != null;
    }
 
    /**
     * 全部大类规范值,按枚举声明顺序。
     */
    public static List<String> allCategories() {
        List<String> categories = new ArrayList<>(values().length);
        for (MajorCategoryEnum item : values()) {
            categories.add(item.category);
        }
        return categories;
    }
}