新增或保存纤度登记表后进行纤度检查并保存结果到纤度检查表
| | |
| | | CheckItemPurity //洁净分 |
| | | CheckItemMaxDeviation //最大偏差 |
| | | ) |
| | | |
| | | type BadFinenessGrade string |
| | | |
| | | const ( |
| | | BadFinenessGradeA = "badA" |
| | | BadFinenessGradeB = "badB" |
| | | BadFinenessGradeC = "badC" |
| | | ) |
| | |
| | | "silkserver/extend/util" |
| | | "silkserver/models" |
| | | "silkserver/pkg/convertx" |
| | | "silkserver/pkg/logx" |
| | | "silkserver/pkg/structx" |
| | | "silkserver/service" |
| | | ) |
| | | |
| | | type FinenessController struct{} |
| | |
| | | util.ResponseFormat(c, code.RequestParamError, "保存失败") |
| | | } |
| | | |
| | | err = service.FinenessCheck(¶ms) |
| | | if err != nil { |
| | | logx.Errorf("service.FinenessCheck err:%v, finenessRegister:%+v", err, params) |
| | | util.ResponseFormat(c, code.RequestParamError, "生成检验表失败") |
| | | } |
| | | |
| | | util.ResponseFormat(c, code.Success, "保存成功") |
| | | } |
| | | |
| | |
| | | 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, "生丝标注未设定"} |
| | | ) |
| | |
| | | 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"` //检验员 |
| | | } |
| | |
| | | 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 |
| | |
| | | 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"` //纤度合计 |
| | | } |
New file |
| | |
| | | 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 |
| | | } |
New file |
| | |
| | | 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 |
| | | } |
New file |
| | |
| | | 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)))) |
| | | } |