zhangqian
2024-03-12 1a2e7a46273fdb6eb53348f4e06100aa7854c3cf
新增或保存纤度登记表后进行纤度检查并保存结果到纤度检查表
3个文件已添加
6个文件已修改
408 ■■■■■ 已修改文件
constvar/const.go 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/fineness.go 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
extend/code/code.go 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/fineness_check.go 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/fineness_check_item.go 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/fineness_item.go 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/fineness.go 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/silk_rank.go 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/mathx.go 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constvar/const.go
@@ -34,3 +34,11 @@
    CheckItemPurity                            //洁净分
    CheckItemMaxDeviation                      //最大偏差
)
type BadFinenessGrade string
const (
    BadFinenessGradeA = "badA"
    BadFinenessGradeB = "badB"
    BadFinenessGradeC = "badC"
)
controllers/fineness.go
@@ -8,7 +8,9 @@
    "silkserver/extend/util"
    "silkserver/models"
    "silkserver/pkg/convertx"
    "silkserver/pkg/logx"
    "silkserver/pkg/structx"
    "silkserver/service"
)
type FinenessController struct{}
@@ -52,6 +54,12 @@
        util.ResponseFormat(c, code.RequestParamError, "保存失败")
    }
    err = service.FinenessCheck(&params)
    if err != nil {
        logx.Errorf("service.FinenessCheck err:%v, finenessRegister:%+v", err, params)
        util.ResponseFormat(c, code.RequestParamError, "生成检验表失败")
    }
    util.ResponseFormat(c, code.Success, "保存成功")
}
extend/code/code.go
@@ -8,22 +8,21 @@
    Message string `json:"msg"`    // 描述信息
}
// 实现 error 接口的 Error 方法
func (c *Code) Error() string {
    return c.Message
}
var (
    Success       = &Code{http.StatusOK, "请求处理成功"}
    UpdateSuccess = &Code{http.StatusOK, "更新成功"}
    DeleteSuccess = &Code{http.StatusOK, "删除成功"}
    SaveFail                     = &Code{3001, "新增失败"}
    RequestParamError            = &Code{3002, "请求参数有误"}
    DeleteUsingError             = &Code{3003, "删除失败"}
    NameExistedError             = &Code{3004, "名称已存在"}
    OrderSchedulingError         = &Code{3005, "订单正在排程中"}
    InventoryNotEnoughError      = &Code{3006, "物料库存不足"}
    UseAmountNotEnoughError      = &Code{3007, "使用数量不足"}
    OrderProductNoProcedureError = &Code{3008, "订单产品无工序"}
    SetStatusError               = &Code{3009, "设置状态失败"}
    NoTemplateError              = &Code{3010, "未配置订单模板"}
    InternalError                = &Code{3011, "内部错误"}
    NoProductionRequiredError    = &Code{3012, "当前库存满足毛需求量,暂时无需进行生产"}
    SelectError                  = &Code{3013, "查询失败"}
    SaveFail          = &Code{3001, "新增失败"}
    RequestParamError = &Code{3002, "请求参数有误"}
    DeleteUsingError  = &Code{3003, "删除失败"}
    NameExistedError  = &Code{3004, "名称已存在"}
    SelectError       = &Code{3013, "查询失败"}
    SilkRankStandardNotSetError = &Code{4101, "生丝标注未设定"}
)
models/fineness_check.go
@@ -18,9 +18,9 @@
        Deviation                decimal.Decimal  `gorm:"type:decimal(12,2);not null;comment:偏差" json:"deviation"`                    //偏差
        TotalDeviation           decimal.Decimal  `gorm:"type:decimal(12,2);not null;comment:总差" json:"totalDeviation"`               //总差
        FinenessGrade            string           `gorm:"type:varchar(255);not null;comment:纤度等级" json:"finenessGrade"`               //纤度等级
        Cleanliness              string           `gorm:"type:varchar(255);not null;comment:清洁度" json:"cleanliness"`                  //清洁度
        Purity                   string           `gorm:"type:varchar(255);not null;comment:洁净度" json:"purity"`                       //洁净度
        TwiceChange              string           `gorm:"type:varchar(255);not null;comment:二度变化" json:"twiceChange"`                 //二度变化
        Cleanliness              decimal.Decimal  `gorm:"type:varchar(255);not null;comment:清洁度" json:"cleanliness"`                  //清洁度
        Purity                   decimal.Decimal  `gorm:"type:varchar(255);not null;comment:洁净度" json:"purity"`                       //洁净度
        TwiceChange              decimal.Decimal  `gorm:"type:varchar(255);not null;comment:二度变化" json:"twiceChange"`                 //二度变化
        MarketProcessOrderNumber string           `gorm:"type:varchar(255);not null;comment:庄口工艺单编号" json:"marketProcessOrderNumber"` //庄口工艺单编号
        Inspector                string           `gorm:"type:varchar(255);not null;comment:检验员" json:"inspector"`                    //检验员
    }
models/fineness_check_item.go
@@ -13,22 +13,20 @@
        gorm.Model
        FinenessRegisterID   uint `gorm:"not null;comment:纤度登记表ID" json:"finenessRegisterID"` //纤度登记表ID
        FinenessCheckID      uint `gorm:"not null;comment:纤度检验表ID" json:"finenessCheckID"`    //纤度检验表ID
        Position             int8 `json:"position"`                                           //车号
        FinenessRoundingItem FinenessRoundingItem
        AverageFineness      decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:平均纤度" json:"averageFineness"` //平均纤度
        MeasureFineness      decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:公量纤度" json:"measureFineness"` //公量纤度
        Deviation            decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:偏差" json:"deviation"`         //偏差
        TotalDeviation       decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:总差" json:"totalDeviation"`    //总差
        FinenessGrade        string          `gorm:"type:varchar(255);not null;comment:纤度等级" json:"finenessGrade"`    //纤度等级
        Cleanliness          string          `gorm:"type:varchar(255);not null;comment:清洁度" json:"cleanliness"`       //清洁度
        Purity               string          `gorm:"type:varchar(255);not null;comment:洁净度" json:"purity"`            //洁净度
        TwiceChange          string          `gorm:"type:varchar(255);not null;comment:二度变化" json:"twiceChange"`      //二度变化
        Remark               string          `gorm:"type:varchar(255);not null;comment:备注" json:"remark"`             //备注
        Position             int  `json:"position"`                                           //车号
        FinenessRoundingItem []*FinenessRoundingItem
        Deviation            decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:偏差" json:"deviation"`      //偏差
        TotalDeviation       decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:总差" json:"totalDeviation"` //总差
        FinenessGrade        string          `gorm:"type:varchar(255);not null;comment:纤度等级" json:"finenessGrade"` //纤度等级
        Cleanliness          decimal.Decimal `gorm:"type:varchar(255);not null;comment:清洁度" json:"cleanliness"`    //清洁度
        Purity               decimal.Decimal `gorm:"type:varchar(255);not null;comment:洁净度" json:"purity"`         //洁净度
        TwiceChange          decimal.Decimal `gorm:"type:varchar(255);not null;comment:二度变化" json:"twiceChange"`   //二度变化
        Remark               string          `gorm:"type:varchar(255);not null;comment:备注" json:"remark"`          //备注
    }
    FinenessRoundingItem struct {
        Fineness decimal.Decimal `json:"fineness"` //纤度
        Quantity decimal.Decimal `json:"quantity"` //数量
        Quantity int             `json:"quantity"` //数量
    }
    FinenessCheckItemSearch struct {
        FinenessCheckItem
models/fineness_item.go
@@ -12,8 +12,8 @@
    FinenessItem struct {
        gorm.Model
        FinenessRegisterID uint            `json:"finenessRegisterID"`
        Position           int8            `json:"position"` //车号
        Fineness           decimal.Decimal `json:"fineness"` //纤度
        Position           int             `json:"position"` //车号
        Fineness           float32         `json:"fineness"` //纤度
        Quantity           decimal.Decimal `json:"quantity"` //数量
        Sum                decimal.Decimal `json:"sum"`      //纤度合计
    }
service/fineness.go
New file
@@ -0,0 +1,193 @@
package service
import (
    "github.com/shopspring/decimal"
    "gorm.io/gorm"
    "math"
    "silkserver/constvar"
    "silkserver/models"
    "silkserver/utils"
    "sort"
)
func FinenessCheck(finenessRegister *models.FinenessRegister) (err error) {
    standardMap, err := GetSilkRankStandard()
    if err != nil {
        return err
    }
    //整理成检验表的数据结构
    finenessRoundingItemMap := make(map[int]map[float32]*models.FinenessRoundingItem)
    for _, item := range finenessRegister.FinenessList {
        if finenessRoundingItemMap[item.Position] == nil {
            finenessRoundingItemMap[item.Position] = make(map[float32]*models.FinenessRoundingItem, 0)
        }
        roundedHalfFineness := ToRoundedHalfFineness(item.Fineness)
        if finenessRoundingItemMap[item.Position][roundedHalfFineness] == nil {
            finenessRoundingItemMap[item.Position][roundedHalfFineness] = &models.FinenessRoundingItem{
                Fineness: decimal.NewFromFloat32(roundedHalfFineness),
                Quantity: 1,
            }
        } else {
            finenessRoundingItemMap[item.Position][roundedHalfFineness].Quantity++
        }
    }
    finenessCheckItems := make([]*models.FinenessCheckItem, 0)
    var allFinenessList []decimal.Decimal
    var personEndFlag bool //走到了某个人最后的车号
    var finenessList []decimal.Decimal
    var step = 3 //临时按一个人三个车号算。
    for pos, roundingItemMap := range finenessRoundingItemMap {
        roundingItems := make([]*models.FinenessRoundingItem, 0, len(roundingItemMap))
        for _, v := range roundingItemMap {
            roundingItems = append(roundingItems, v)
            finenessList = append(finenessList, v.Fineness)
            allFinenessList = append(allFinenessList, v.Fineness)
        }
        item := &models.FinenessCheckItem{
            FinenessRegisterID:   finenessRegister.ID,
            Position:             pos,
            FinenessRoundingItem: roundingItems,
            Remark:               "",
        }
        if pos%step == 0 {
            personEndFlag = true
        } else {
            personEndFlag = false
        }
        if personEndFlag {
            item.Deviation = utils.Deviation(finenessList)
            item.FinenessGrade = CalcFinenessGrade(item.Deviation, item.TotalDeviation, item.Cleanliness, item.Purity, item.TwiceChange, standardMap)
            finenessList = finenessList[:0]
        }
        finenessCheckItems = append(finenessCheckItems, item)
    }
    finenessCheck := models.FinenessCheck{
        FinenessRegisterID:       finenessRegister.ID,
        AverageFineness:          utils.Average(allFinenessList),
        Deviation:                utils.Deviation(allFinenessList),
        TotalDeviation:           decimal.Decimal{},
        Cleanliness:              decimal.Decimal{},
        Purity:                   decimal.Decimal{},
        TwiceChange:              decimal.Decimal{},
        MarketProcessOrderNumber: "",
        Inspector:                "",
    }
    finenessCheck.FinenessGrade = CalcFinenessGrade(finenessCheck.Deviation, finenessCheck.TotalDeviation, finenessCheck.Cleanliness, finenessCheck.Purity, finenessCheck.TwiceChange, standardMap)
    err = models.WithTransaction(func(db *gorm.DB) error {
        err := models.NewFinenessCheckSearch().SetOrm(db).Create(&finenessCheck)
        if err != nil {
            return err
        }
        return models.NewFinenessCheckItemSearch().SetOrm(db).CreateBatch(finenessCheckItems)
    })
    return err
}
type gradeRank struct {
    gradeName string
    gradeRank int
}
func CalcFinenessGrade(deviation, totalDeviation, cleanliness, purity, twiceChange decimal.Decimal, standardMap map[string]*Standard) (gradeName string) {
    checkItemGradeMap := make(map[constvar.CheckItem]string, 5)
    gradeRanks := make([]gradeRank, 0)
    for _, st := range standardMap {
        if st.StartFineness.GreaterThan(deviation) || st.EndFineness.LessThan(deviation) {
            continue
        }
        grade := ""
        for _, pair := range st.ValueList {
            switch st.CheckItem {
            case constvar.CheckItemDeviation:
                if st.SortType == SortTypeAsc {
                    if deviation.LessThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                } else {
                    if deviation.GreaterThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                }
            case constvar.CheckItemMaxDeviation:
                if st.SortType == SortTypeAsc {
                    if totalDeviation.LessThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                } else {
                    if totalDeviation.GreaterThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                }
            case constvar.CheckItemTwiceChange:
                if st.SortType == SortTypeAsc {
                    if twiceChange.LessThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                } else {
                    if twiceChange.GreaterThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                }
            case constvar.CheckItemCleanliness:
                if st.SortType == SortTypeAsc {
                    if cleanliness.LessThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                } else {
                    if cleanliness.GreaterThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                }
            case constvar.CheckItemPurity:
                if st.SortType == SortTypeAsc {
                    if purity.LessThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                } else {
                    if purity.GreaterThanOrEqual(pair.RankValue) {
                        grade = pair.RankName
                    }
                }
            }
            if grade != "" {
                break
            }
        }
        if grade != "" {
            checkItemGradeMap[st.CheckItem] = grade
            gradeRanks = append(gradeRanks, gradeRank{
                gradeName: grade,
                gradeRank: st.GradeRank[grade],
            })
        }
    }
    if len(gradeRanks) == 0 {
        return ""
    }
    sort.Slice(gradeRanks, func(i, j int) bool {
        return gradeRanks[i].gradeRank < gradeRanks[j].gradeRank
    })
    return gradeRanks[0].gradeName
}
func ToRoundedHalfFineness(fineness float32) float32 {
    intPart := int(fineness)
    diff := fineness - float32(intPart)
    var result float32
    if diff < 0.25 {
        result = float32(intPart)
    } else if diff < 0.75 {
        result = float32(intPart) + 0.5
    } else {
        result = float32(intPart + 1)
    }
    // 保留一位小数,并在整数情况下在小数点后加一个零
    result = float32(math.Round(float64(result)*10) / 10)
    return result
}
service/silk_rank.go
New file
@@ -0,0 +1,112 @@
package service
import (
    "github.com/shopspring/decimal"
    "silkserver/constvar"
    "silkserver/extend/code"
    "silkserver/models"
    "sort"
)
type Standard struct {
    CheckItem     constvar.CheckItem
    StartFineness decimal.Decimal
    EndFineness   decimal.Decimal
    GradeMap      map[string]struct{}
    ValueList     []*Pair
    SortType      SortType
    GradeRank     map[string]int
}
type Pair struct {
    RankName  string
    RankValue decimal.Decimal
}
type SortType int
const (
    SortTypeAsc  SortType = 0
    SortTypeDesc SortType = 1
)
var sortTypeMap = map[constvar.CheckItem]SortType{
    constvar.CheckItemDeviation:    SortTypeAsc,
    constvar.CheckItemTwiceChange:  SortTypeAsc,
    constvar.CheckItemCleanliness:  SortTypeDesc,
    constvar.CheckItemPurity:       SortTypeDesc,
    constvar.CheckItemMaxDeviation: SortTypeAsc,
}
func GetSilkRankStandard() (map[string]*Standard, error) {
    rankStandards, err := models.NewRawSilkRankStandardSearch().FindNotTotal()
    if err != nil {
        return nil, err
    }
    if len(rankStandards) == 0 {
        return nil, code.SilkRankStandardNotSetError
    }
    standardMap := make(map[string]*Standard)
    for _, v := range rankStandards {
        if standardMap[v.LineId] == nil {
            standardMap[v.LineId] = &Standard{
                CheckItem:     v.CheckItem,
                StartFineness: v.StartFineness,
                EndFineness:   v.EndFineness,
                GradeMap:      make(map[string]struct{}),
                ValueList:     make([]*Pair, 0),
            }
        }
        if _, ok := standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeA]; !ok {
            standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
                RankName:  constvar.BadFinenessGradeA,
                RankValue: v.RankA,
            })
            standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeA] = struct{}{}
        }
        if _, ok := standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeB]; !ok {
            standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
                RankName:  constvar.BadFinenessGradeB,
                RankValue: v.RankB,
            })
            standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeB] = struct{}{}
        }
        if _, ok := standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeC]; !ok {
            standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
                RankName:  constvar.BadFinenessGradeC,
                RankValue: v.RankC,
            })
            standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeC] = struct{}{}
        }
        if _, ok := standardMap[v.LineId].GradeMap[v.RankName]; !ok {
            standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
                RankName:  v.RankName,
                RankValue: v.RankValue,
            })
            standardMap[v.LineId].GradeMap[v.RankName] = struct{}{}
        }
    }
    //value排序
    for k := range standardMap {
        sort.Slice(standardMap[k].ValueList, func(i, j int) bool {
            sortType := sortTypeMap[standardMap[k].CheckItem]
            standardMap[k].SortType = sortType
            if sortType == SortTypeAsc {
                return standardMap[k].ValueList[i].RankValue.LessThan(standardMap[k].ValueList[j].RankValue)
            } else {
                return standardMap[k].ValueList[i].RankValue.GreaterThan(standardMap[k].ValueList[j].RankValue)
            }
        })
    }
    //等级排名
    for lineId, standard := range standardMap {
        for k, pair := range standard.ValueList {
            if standard.SortType == SortTypeAsc {
                standardMap[lineId].GradeRank[pair.RankName] = k + 1
            } else {
                standardMap[lineId].GradeRank[pair.RankName] = len(standard.ValueList) - k
            }
        }
    }
    return standardMap, nil
}
utils/mathx.go
New file
@@ -0,0 +1,30 @@
package utils
import "github.com/shopspring/decimal"
func Average(numbers []decimal.Decimal) decimal.Decimal {
    if len(numbers) == 0 {
        return decimal.Decimal{}
    }
    if len(numbers) == 1 {
        return numbers[0]
    }
    var sum decimal.Decimal
    for _, d := range numbers {
        sum = sum.Add(d)
    }
    return sum.Div(decimal.NewFromInt(int64(len(numbers))))
}
func Deviation(numbers []decimal.Decimal) decimal.Decimal {
    if len(numbers) == 0 || len(numbers) == 1 {
        return decimal.Decimal{}
    }
    avgNum := Average(numbers)
    var diffSquaredSum decimal.Decimal
    for _, n := range numbers {
        diff := n.Sub(avgNum)
        diffSquaredSum = diffSquaredSum.Add(diff.Mul(diff))
    }
    return diffSquaredSum.Div(decimal.NewFromInt(int64(len(numbers))))
}