package test_data import ( "bufio" "encoding/json" "errors" "github.com/shopspring/decimal" "log" "math" "os" "sort" "strconv" "strings" "testData/global" "testData/model" "testData/request" ) // QuerySelection 查询可选择的参数 func QuerySelection(req *request.QuerySelection) map[string][]string { return LotInMultipleFilesSelection(req.Product, req.Lot, req.PBI) } // Histogram 直方图 func Histogram(req *request.Histogram) ([]*model.Histogram, error) { var fTHistogram []*model.Histogram var x, groups []string var xMax, xMin string //var datas [][]string //fieldMap := make(map[string]int) if len(req.SubBatch) == 0 && len(req.WaferID) == 0 { //datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI, req.Step) groups = append(groups, "") } else if len(req.SubBatch) != 0 { groups = req.SubBatch } else if len(req.WaferID) != 0 { groups = req.WaferID } for _, group := range groups { var datas [][]string fieldMap := make(map[string]int) if group == "" { datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI) } else if len(req.SubBatch) != 0 { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "") } else if len(req.WaferID) != 0 { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group) } left := req.Average - req.Offset*req.StandardDeviation right := req.Average + req.Offset*req.StandardDeviation for _, selection := range req.Selections { if _, ok := fieldMap[selection]; !ok { continue } if len(req.Site) == 0 { var n float64 var sumSelection float64 = 0 // 计算最大值、最小值、标准差、均值、数量 //var standardDeviation float64 var max, min string for _, data := range datas { selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]]) if req.XMax != "" && req.XMin != "" { xMaxDecimal, _ := decimal.NewFromString(req.XMax) xMinDecimal, _ := decimal.NewFromString(req.XMin) if !(selectionDecimal.LessThanOrEqual(xMaxDecimal) && xMinDecimal.LessThanOrEqual(selectionDecimal)) { continue } } if req.Offset != 0 { leftDecimal := decimal.NewFromFloat(left) rightDecimal := decimal.NewFromFloat(right) if selectionDecimal.LessThan(leftDecimal) || rightDecimal.LessThan(selectionDecimal) { continue } } // 筛选SBin var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if binInclude { if data[fieldMap[selection]] != "" { selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64) sumSelection += selectionData n++ //difference := sumSelection/n - selectionData //standardDeviation += math.Pow(difference, 2) if max == "" { max = data[fieldMap[selection]] } else { maxDecimal, _ := strconv.ParseFloat(max, 64) if maxDecimal < selectionData { max = data[fieldMap[selection]] } } if min == "" { min = data[fieldMap[selection]] } else { minDecimal, _ := strconv.ParseFloat(min, 64) if selectionData < minDecimal { min = data[fieldMap[selection]] } } if xMax == "" { xMax = data[fieldMap[selection]] } else { maxDecimal, _ := strconv.ParseFloat(xMax, 64) if maxDecimal < selectionData { xMax = data[fieldMap[selection]] } } if xMin == "" { xMin = data[fieldMap[selection]] } else { minDecimal, _ := strconv.ParseFloat(xMin, 64) if selectionData < minDecimal { xMin = data[fieldMap[selection]] } } } } } averageFloat64 := sumSelection / n //standardDeviation = math.Sqrt(standardDeviation / n) var filed string if group == "" { filed = selection } else { filed = selection + "-" + group } fTHistogram = append(fTHistogram, &model.Histogram{ Field: filed, Average: averageFloat64, //StandardDeviation: standardDeviation, Max: max, Min: min, N: n, }) } else { for _, site := range req.Site { var n float64 var sumSelection float64 = 0 // 计算最大值、最小值、标准差、均值、数量 //var standardDeviation float64 var max, min string for _, data := range datas { selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]]) if req.XMax != "" && req.XMin != "" { xMaxDecimal, _ := decimal.NewFromString(req.XMax) xMinDecimal, _ := decimal.NewFromString(req.XMin) if !(selectionDecimal.LessThanOrEqual(xMaxDecimal) && xMinDecimal.LessThanOrEqual(selectionDecimal)) { continue } } if req.Offset != 0 { leftDecimal := decimal.NewFromFloat(left) rightDecimal := decimal.NewFromFloat(right) if selectionDecimal.LessThan(leftDecimal) || rightDecimal.LessThan(rightDecimal) { continue } } // 筛选Site var siteInclude bool if data[fieldMap["SITE_NUM"]] == site { siteInclude = true } // 筛选SBin var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if siteInclude && binInclude { if data[fieldMap[selection]] != "" { selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64) sumSelection += selectionData n++ //difference := sumSelection/n - selectionData //standardDeviation += math.Pow(difference, 2) if max == "" { max = data[fieldMap[selection]] } else { maxDecimal, _ := strconv.ParseFloat(max, 64) if maxDecimal < selectionData { max = data[fieldMap[selection]] } } if min == "" { min = data[fieldMap[selection]] } else { minDecimal, _ := strconv.ParseFloat(min, 64) if selectionData < minDecimal { min = data[fieldMap[selection]] } } if xMax == "" { xMax = data[fieldMap[selection]] } else { maxDecimal, _ := strconv.ParseFloat(xMax, 64) if maxDecimal < selectionData { xMax = data[fieldMap[selection]] } } if xMin == "" { xMin = data[fieldMap[selection]] } else { minDecimal, _ := strconv.ParseFloat(xMin, 64) if selectionData < minDecimal { xMin = data[fieldMap[selection]] } } } } } averageFloat64 := sumSelection / n //standardDeviation = math.Sqrt(standardDeviation / n) var filed string if group == "" { filed = selection + "-Site" + site } else { filed = selection + "-" + group + "-Site" + site } fTHistogram = append(fTHistogram, &model.Histogram{ Field: filed, Average: averageFloat64, //StandardDeviation: standardDeviation, Max: max, Min: min, N: n, }) } } } } // 生成X坐标 if req.XMax != "" { xMax = req.XMax } if req.XMin != "" { xMin = req.XMin } //minDecimal, _ := strconv.ParseFloat(xMin, 64) //maxDecimal, _ := strconv.ParseFloat(xMax, 64) //interval := (maxDecimal - minDecimal) / 50 //for i := 0; i < 51; i++ { // xPoint := strconv.FormatFloat(minDecimal+interval*float64(i), 'f', 6, 64) // x = append(x, xPoint) //} minDecimal, _ := decimal.NewFromString(xMin) if minDecimal.LessThan(decimal.NewFromInt(0)) { minDecimal = minDecimal.RoundUp(0) } else { minDecimal = minDecimal.RoundDown(0) } maxDecimal, _ := decimal.NewFromString(xMax) if maxDecimal.LessThan(decimal.NewFromInt(0)) { maxDecimal = maxDecimal.RoundDown(0) } else { maxDecimal = maxDecimal.RoundUp(0) } interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(50)) for i := 0; i < 51; i++ { xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String() x = append(x, xPoint) } for _, group := range groups { var datas [][]string fieldMap := make(map[string]int) if group == "" { datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI) } else if len(req.SubBatch) != 0 { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "") } else if len(req.WaferID) != 0 { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group) } for _, selection := range req.Selections { if _, ok := fieldMap[selection]; !ok { continue } if len(req.Site) == 0 { var filed string if group == "" { filed = selection } else { filed = selection + "-" + group } var standardDeviation, average float64 var index int for k, v := range fTHistogram { if v.Field == filed { average = v.Average index = k break } } var y []string counter := make(map[float64]int) // 计算最大值、最小值、标准差、均值、数量 for _, data := range datas { // 筛选SBin var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if binInclude { if data[fieldMap[selection]] != "" { selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64) standardDeviation += math.Pow(average-selectionData, 2) counter[selectionData]++ } } } fTHistogram[index].StandardDeviation = math.Sqrt(standardDeviation / fTHistogram[index].N) for i := 0; i < len(x); i++ { if i == len(x)-1 { xFloat, _ := strconv.ParseFloat(x[i], 64) if yValue, ok := counter[xFloat]; ok { y = append(y, strconv.Itoa(yValue)) } else { y = append(y, "0") } break } xPointMin, _ := decimal.NewFromString(x[i]) xPointMax, _ := decimal.NewFromString(x[i+1]) var yCounter float64 = 0 for k, v := range counter { if xPointMin.LessThanOrEqual(decimal.NewFromFloat(k)) && decimal.NewFromFloat(k).LessThan(xPointMax) { yCounter += float64(v) } } yPoint := strconv.FormatFloat(yCounter, 'f', 0, 64) y = append(y, yPoint) } fTHistogram[index].X = x fTHistogram[index].Y = y } else { for _, site := range req.Site { var filed string if group == "" { filed = selection + "-Site" + site } else { filed = selection + "-" + group + "-Site" + site } var standardDeviation, average float64 var index int for k, v := range fTHistogram { if v.Field == filed { average = v.Average index = k break } } var y []string counter := make(map[float64]int) for _, data := range datas { // 筛选Site var siteInclude bool if data[fieldMap["SITE_NUM"]] == site { siteInclude = true } // 筛选SBin var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if siteInclude && binInclude { if data[fieldMap[selection]] != "" { selectionData, _ := strconv.ParseFloat(data[fieldMap[selection]], 64) standardDeviation += math.Pow(average-selectionData, 2) counter[selectionData]++ } } } fTHistogram[index].StandardDeviation = math.Sqrt(standardDeviation / fTHistogram[index].N) for i := 0; i < len(x); i++ { if i == len(x)-1 { xFloat, _ := strconv.ParseFloat(x[i], 64) if yValue, ok := counter[xFloat]; ok { y = append(y, strconv.Itoa(yValue)) } else { y = append(y, "0") } break } xPointMin, _ := strconv.ParseFloat(x[i], 64) xPointMax, _ := strconv.ParseFloat(x[i+1], 64) var yCounter float64 = 0 for k, v := range counter { if xPointMin <= k && k < xPointMax { yCounter += float64(v) } } yPoint := strconv.FormatFloat(yCounter, 'f', 0, 64) y = append(y, yPoint) } fTHistogram[index].X = x fTHistogram[index].Y = y } } } } return fTHistogram, nil } // Scatter 散点图 func Scatter(req *request.Scatter) ([]*model.Scatter, model.ScatterLimit, model.ScatterLimit, error) { var groups []string if len(req.SubBatch) == 0 && len(req.WaferID) == 0 { groups = append(groups, "") } else if len(req.SubBatch) != 0 { groups = req.SubBatch } else if len(req.WaferID) != 0 { groups = req.WaferID } // 判断子批次还是大批次查询数据 var datas [][]string fieldMap := make(map[string]int) if len(req.SubBatch) == 0 { datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI) } else { for _, group := range groups { if len(req.SubBatch) != 0 { groupDatas, groupFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, group, "") datas = append(datas, groupDatas...) fieldMap = groupFieldMap } else { groupDatas, groupFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, "", group) datas = append(datas, groupDatas...) fieldMap = groupFieldMap } } } var scatters []*model.Scatter var xScatterLimit, yScatterLimit model.ScatterLimit if len(req.Site) == 0 { scatterFieldMap := make(map[string]int) counter := make(map[string]map[string]int) for _, data := range datas { // 筛选SBin var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if binInclude { for _, xySelection := range req.XYSelection { if data[fieldMap[xySelection.X]] == "" || data[fieldMap[xySelection.Y]] == "" { continue } if _, ok := counter[xySelection.X+","+xySelection.Y]; !ok { counter[xySelection.X+","+xySelection.Y] = map[string]int{} } // 过滤重复点 needAppend := true coordinate := data[fieldMap[xySelection.X]] + "," + data[fieldMap[xySelection.Y]] if _, ok := counter[xySelection.X+","+xySelection.Y][coordinate]; ok { needAppend = false } if needAppend { counter[xySelection.X+","+xySelection.Y][coordinate]++ if _, ok := scatterFieldMap[xySelection.X+","+xySelection.Y]; !ok { scatter := &model.Scatter{ Field: xySelection.X + "," + xySelection.Y + " All Site", Datas: [][]string{}} scatterFieldMap[xySelection.X+","+xySelection.Y] = len(scatters) scatters = append(scatters, scatter) } scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas = append( scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas, []string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]}) if xScatterLimit.Min == "" { xScatterLimit.Min = data[fieldMap[xySelection.X]] } else { xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Min, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8) if xScatterLimitFloat > dataFloat { xScatterLimit.Min = data[fieldMap[xySelection.X]] } } if xScatterLimit.Max == "" { xScatterLimit.Max = data[fieldMap[xySelection.X]] } else { xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Max, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8) if xScatterLimitFloat < dataFloat { xScatterLimit.Max = data[fieldMap[xySelection.X]] } } if yScatterLimit.Min == "" { yScatterLimit.Min = data[fieldMap[xySelection.Y]] } else { yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Min, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8) if yScatterLimitFloat > dataFloat { yScatterLimit.Min = data[fieldMap[xySelection.Y]] } } if yScatterLimit.Max == "" { yScatterLimit.Max = data[fieldMap[xySelection.Y]] } else { yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Max, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8) if yScatterLimitFloat < dataFloat { yScatterLimit.Max = data[fieldMap[xySelection.Y]] } } } } } } } else { scatterFieldMap := make(map[string]int) for _, site := range req.Site { counter := make(map[string]map[string]int) for _, data := range datas { // 筛选Site if data[fieldMap["SITE_NUM"]] != site { continue } // 筛选SBin var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if binInclude { for _, xySelection := range req.XYSelection { if data[fieldMap[xySelection.X]] == "" || data[fieldMap[xySelection.Y]] == "" { continue } if _, ok := counter[xySelection.X+","+xySelection.Y]; !ok { counter[xySelection.X+","+xySelection.Y] = map[string]int{} } // 过滤重复点 needAppend := true coordinate := data[fieldMap[xySelection.X]] + "," + data[fieldMap[xySelection.Y]] if _, ok := counter[xySelection.X+","+xySelection.Y][coordinate]; ok { needAppend = false } if needAppend { counter[xySelection.X+","+xySelection.Y][coordinate]++ if _, ok := scatterFieldMap[xySelection.X+","+xySelection.Y]; !ok { scatter := &model.Scatter{ Field: xySelection.X + "," + xySelection.Y + "-Site" + site, Datas: [][]string{}} scatterFieldMap[xySelection.X+","+xySelection.Y] = len(scatters) scatters = append(scatters, scatter) } scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas = append( scatters[scatterFieldMap[xySelection.X+","+xySelection.Y]].Datas, []string{data[fieldMap[xySelection.X]], data[fieldMap[xySelection.Y]]}) if xScatterLimit.Min == "" { xScatterLimit.Min = data[fieldMap[xySelection.X]] } else { xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Min, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8) if xScatterLimitFloat > dataFloat { xScatterLimit.Min = data[fieldMap[xySelection.X]] } } if xScatterLimit.Max == "" { xScatterLimit.Max = data[fieldMap[xySelection.X]] } else { xScatterLimitFloat, _ := strconv.ParseFloat(xScatterLimit.Max, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.X]], 8) if xScatterLimitFloat < dataFloat { xScatterLimit.Max = data[fieldMap[xySelection.X]] } } if yScatterLimit.Min == "" { yScatterLimit.Min = data[fieldMap[xySelection.Y]] } else { yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Min, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8) if yScatterLimitFloat > dataFloat { yScatterLimit.Min = data[fieldMap[xySelection.Y]] } } if yScatterLimit.Max == "" { yScatterLimit.Max = data[fieldMap[xySelection.Y]] } else { yScatterLimitFloat, _ := strconv.ParseFloat(yScatterLimit.Max, 8) dataFloat, _ := strconv.ParseFloat(data[fieldMap[xySelection.Y]], 8) if yScatterLimitFloat < dataFloat { yScatterLimit.Max = data[fieldMap[xySelection.Y]] } } } } } } } } return scatters, xScatterLimit, yScatterLimit, nil } func Pie(req *request.Pie) ([]*model.Pie, error) { var pie []*model.Pie var datas [][]string fieldMap := make(map[string]int) if req.SubBatch == "" { datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI) } else { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step) } if _, ok := fieldMap[req.Selection]; !ok { return nil, errors.New("不存在该参数") } m := make(map[string]int) if req.Min == "" { req.Min = "0" } if req.Max == "" { req.Max = "0" } minDecimal, _ := decimal.NewFromString(req.Min) maxDecimal, _ := decimal.NewFromString(req.Max) for _, data := range datas { var siteInclude bool if len(req.Site) == 0 { siteInclude = true } else { for _, site := range req.Site { if data[fieldMap["SITE_NUM"]] == site { siteInclude = true break } } } var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if siteInclude && binInclude { if data[fieldMap[req.Selection]] == "" { data[fieldMap[req.Selection]] = "0" } selectionDecimal, _ := decimal.NewFromString(data[fieldMap[req.Selection]]) if minDecimal.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThanOrEqual(maxDecimal) { var isValid bool for _, interval := range req.PieInterval { if interval.Min == "" { interval.Min = "0" } if interval.Max == "" { interval.Max = "0" } minIntervalDecimal, _ := decimal.NewFromString(interval.Min) maxIntervalDecimal, _ := decimal.NewFromString(interval.Max) if minIntervalDecimal.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(maxIntervalDecimal) { m[interval.Name]++ isValid = true break } } if !isValid { m["else"]++ } } } } for k, v := range m { pie = append(pie, &model.Pie{ Name: k, Value: v, }) } return pie, nil } func Line(req *request.Line) (*model.Line, error) { var datas [][]string fieldMap := make(map[string]int) if req.SubBatch == "" { datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI) } else { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step) } var x, y []string for index, data := range datas { var siteInclude bool if len(req.Site) == 0 { siteInclude = true } else { for _, site := range req.Site { if data[fieldMap["SITE_NUM"]] == site { siteInclude = true break } } } var binInclude bool if len(req.Bin) == 0 { binInclude = true } else { for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { binInclude = true break } } } if siteInclude && binInclude { x = append(x, strconv.Itoa(index)) y = append(y, data[fieldMap[req.Selection]]) } } lineChart := &model.Line{ X: x, Y: y, } return lineChart, nil } // CPMap CP晶圆图 func CPMap(req *request.CPMap) (map[string]interface{}, error) { // 需要显示的参数 selections := []string{"SITE_NUM", "SOFT_BIN", "HARD_BIN"} if len(req.Selection) > 0 { selections = append(selections, req.Selection[0]) } // CP测试没有子批次 var fileHandle *model.FileHandled global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ? AND wafer_id = ?", req.PBI, req.Product, req.Lot, req.WaferID). Find(&fileHandle) f, err := os.Open(fileHandle.Path) if err != nil { log.Println(err) return nil, err } defer f.Close() scanner := bufio.NewScanner(f) datas := make([][]string, 0) fieldMap := make(map[string]int) for scanner.Scan() { line := scanner.Text() s := strings.Split(line, ",") datas = append(datas, s[:len(s)-1]) if len(datas) == 1 { for index, cell := range s { if index == len(s)-1 { continue } fieldMap[cell] = index } } } if len(datas) >= 1 { datas = datas[1:] } sbinHbinMap := make(map[string]map[string]string) res := make(map[string]interface{}) resDatas := make([]map[string]interface{}, 0) selectDatas := make(map[string]interface{}) // 颜色、标题、数据数组初始化 color := []string{"#4FFF00", "#FF0000", "#1B81FF", "#FF0000", "#E12AE8"} datasTitle := []string{"第一次测试Pass", "第一次测试Fail", "复测Pass", "复测Fail", "复测Fail变动"} selectDatas["第一次测试Pass"] = [][]string{} selectDatas["第一次测试Fail"] = [][]string{} selectDatas["复测Pass"] = [][]string{} selectDatas["复测Fail"] = [][]string{} selectDatas["复测Fail变动"] = [][]string{} for _, sBinColor := range req.SBinColor { color = append(color, sBinColor.Color) datasTitle = append(datasTitle, sBinColor.Name) selectDatas[sBinColor.Name] = [][]string{} } for _, hBinColor := range req.HBinColor { color = append(color, hBinColor.Color) datasTitle = append(datasTitle, hBinColor.Name) selectDatas[hBinColor.Name] = [][]string{} } for _, selectionColor := range req.SelectionColor { color = append(color, selectionColor.Color) datasTitle = append(datasTitle, selectionColor.Name+":"+selectionColor.Min+"~"+selectionColor.Max) selectDatas[selectionColor.Name+":"+selectionColor.Min+"~"+selectionColor.Max] = [][]string{} } sbinHbinByte := []byte(fileHandle.SbinHbin) _ = json.Unmarshal(sbinHbinByte, &sbinHbinMap) passArray := selectDatas["复测Pass"].([][]string) failArray := selectDatas["复测Fail"].([][]string) failChangeArray := selectDatas["复测Fail变动"].([][]string) lastPassArray := selectDatas["第一次测试Pass"].([][]string) lastFailArray := selectDatas["第一次测试Fail"].([][]string) var total, pass float64 binMap := make(map[string]int) sbinColorMap := make(map[string]int) hbinColorMap := make(map[string]int) selectionColorMap := make(map[string]int) for _, data := range datas { binInfoMap := sbinHbinMap[data[fieldMap["SOFT_BIN"]]] // 筛选Site var siteInclude bool if len(req.Site) == 0 { siteInclude = true } else { for _, site := range req.Site { if data[fieldMap["SITE_NUM"]] == site { siteInclude = true break } } } if !siteInclude { continue } // 筛选Soft Bin var sBinInclude bool if len(req.SBin) == 0 { sBinInclude = true } else { for _, bin := range req.SBin { if data[fieldMap["SOFT_BIN"]] == bin { sBinInclude = true break } } } if !sBinInclude { continue } // 筛选Hard Bin var hBinInclude bool if len(req.HBin) == 0 { hBinInclude = true } else { for _, bin := range req.HBin { if binInfoMap["HBin"] == bin { hBinInclude = true break } } } if !hBinInclude { continue } // 将HBin写入单行信息内 //data = append(data, binInfoMap["HBin"]) x := data[fieldMap["X_COORD"]] y := data[fieldMap["Y_COORD"]] data[fieldMap["PASSFG"]] = strings.ToLower(data[fieldMap["PASSFG"]]) // 判断测试点是否通过测试 var isPass bool if data[fieldMap["PASSFG"]] == "true" { isPass = true } // 需要显示的参数 var field []string for _, selection := range selections { var dataValue string if selection == "HARD_BIN" { dataValue = binInfoMap["HBin"] field = append(field, []string{selection, dataValue}...) continue } if _, ok := fieldMap[selection]; !ok { dataValue = "0" } else { dataValue = data[fieldMap[selection]] } field = append(field, []string{selection, dataValue}...) } // 区分通过、不通过、第一次测试数据 var isSamePoint bool var isFinal bool for _, lastPoint := range lastFailArray { if lastPoint[0] == x && lastPoint[1] == y { if isPass { passArray = append(passArray, append([]string{x, y}, field...)) } else { var isChangeFail bool for lastPointFieldIndex := 2; lastPointFieldIndex < len(lastPoint); lastPointFieldIndex++ { if lastPoint[lastPointFieldIndex] == "SOFT_BIN" { for pointFieldIndex := 2; pointFieldIndex < len(field); pointFieldIndex++ { if field[pointFieldIndex] == "SOFT_BIN" && lastPoint[lastPointFieldIndex+1] != field[pointFieldIndex+1] { isChangeFail = true } } } } if isChangeFail { failArray = append(failArray, append([]string{x, y}, field...)) failChangeArray = append(failChangeArray, append([]string{x, y}, field...)) } else { failArray = append(failArray, append([]string{x, y}, field...)) } } isFinal = true isSamePoint = true break } } if !isSamePoint { if isPass { lastPassArray = append(lastPassArray, append([]string{x, y}, field...)) isFinal = true } else { lastFailArray = append(lastFailArray, append([]string{x, y}, field...)) } } if isFinal { total++ if isPass { pass++ } binMap[data[fieldMap["SOFT_BIN"]]]++ sbinColorMap[data[fieldMap["SOFT_BIN"]]]++ hbinColorMap[binInfoMap["HBin"]]++ // 根据SOFT_BIN区分颜色 for _, sBinColor := range req.SBinColor { array := selectDatas[sBinColor.Name].([][]string) var isReplace bool for _, point := range array { if point[0] == x && point[1] == y { point = append([]string{x, y}, field...) isReplace = true break } } if !isReplace && data[fieldMap["SOFT_BIN"]] == sBinColor.Name { array = append(array, append([]string{x, y}, field...)) selectDatas[sBinColor.Name] = array break } } // 根据HARD_BIN区分颜色 for _, hBinColor := range req.HBinColor { array := selectDatas[hBinColor.Name].([][]string) var isReplace bool for _, point := range array { if point[0] == x && point[1] == y { point = append([]string{x, y}, field...) isReplace = true break } } if !isReplace && binInfoMap["HBin"] == hBinColor.Name { array = append(array, append([]string{x, y}, field...)) selectDatas[hBinColor.Name] = array break } } // 根据参数范围区分颜色 for _, selectionColor := range req.SelectionColor { if data[fieldMap[selectionColor.Name]] == "" { break } selection, _ := decimal.NewFromString(data[fieldMap[selectionColor.Name]]) max, _ := decimal.NewFromString(selectionColor.Max) min, _ := decimal.NewFromString(selectionColor.Min) if selection.LessThanOrEqual(max) && min.LessThanOrEqual(selection) { s := selectionColor.Name + ":" + selectionColor.Min + "~" + selectionColor.Max selectionColorMap[s]++ array := selectDatas[s].([][]string) var isReplace bool for _, point := range array { if point[0] == x && point[1] == y { point = append([]string{x, y}, field...) isReplace = true selectDatas[s] = array break } } if !isReplace { array = append(array, append([]string{x, y}, field...)) selectDatas[s] = array break } } //selection, _ := strconv.ParseFloat(data[fieldMap[selectionColor.Name]], 8) //max, _ := strconv.ParseFloat(selectionColor.Max, 8) //min, _ := strconv.ParseFloat(selectionColor.Min, 8) //if selection <= max && min <= selection { // selectionColorMap[selectionColor.Name]++ // s := selectionColor.Name + ":" + selectionColor.Min + "~" + selectionColor.Max // array := selectDatas[s].([][]string) // var isReplace bool // for _, point := range array { // if point[0] == x && point[1] == y { // point = append([]string{x, y}, field...) // isReplace = true // selectDatas[s] = array // break // } // } // if !isReplace { // array = append(array, append([]string{x, y}, field...)) // selectDatas[s] = array // break // } //} } } } selectDatas["复测Pass"] = passArray selectDatas["复测Fail"] = failArray selectDatas["复测Fail变动"] = failChangeArray selectDatas["第一次测试Pass"] = lastPassArray selectDatas["第一次测试Fail"] = lastFailArray // 将根据标题顺序存入数组 for _, v := range datasTitle { resDatas = append(resDatas, map[string]interface{}{ "name": v, "data": selectDatas[v], }) } res["color"] = color res["datas_title"] = datasTitle res["datas"] = resDatas totalDecimal := decimal.NewFromFloat(total) passDecimal := decimal.NewFromFloat(pass) res["Total"] = totalDecimal.String() if !totalDecimal.IsZero() { res["PassProbability"] = passDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%" } var binArray []string for bin := range binMap { binArray = append(binArray, bin) } sort.Slice(binArray, func(i, j int) bool { return binMap[binArray[i]] > binMap[binArray[j]] }) var binProbability [][]string for _, bin := range binArray { binDecimal := decimal.NewFromInt(int64(binMap[bin])) probability := "0%" if !totalDecimal.IsZero() { probability = binDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%" } binProbability = append(binProbability, []string{"BIN " + bin, probability, strconv.Itoa(binMap[bin])}) } res["Bin情况"] = binProbability res["Sbin数量"] = sbinColorMap res["Hbin数量"] = hbinColorMap res["参数数量"] = selectionColorMap return res, nil } func LogSiteChart(req *request.LogSiteChart) *model.Histogram { //var fileHandle *model.FileHandled //global.PostGreSQL.Where("product = ? AND sub_batch = ?", req.Product, req.SubBatch).Find(&fileHandle) var datas [][]string fieldMap := make(map[string]int) if req.SubBatch == "" { datas, fieldMap = LotInMultipleFiles(req.Product, req.Lot, req.PBI) } else { datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, req.SubBatch, req.Step) } var x []string for _, v := range req.Site { x = append(x, "Site"+v) } var y []string if req.ContentType == "数量" { counter := make(map[string]int) for _, data := range datas { counter[data[fieldMap["SITE_NUM"]]]++ } for _, v := range req.Site { y = append(y, strconv.Itoa(counter[v])) } //y = append(y, strconv.Itoa(counter["Site1"]), strconv.Itoa(counter["Site2"]), strconv.Itoa(counter["Site3"]), strconv.Itoa(counter["Site4"])) } else if req.ContentType == "良率" { counter := make(map[string]int) passCounter := make(map[string]int) for _, data := range datas { counter[data[fieldMap["SITE_NUM"]]]++ if data[fieldMap["PASSFG"]] == "True" { passCounter[data[fieldMap["SITE_NUM"]]]++ } } for _, v := range x { counterDecimal := decimal.NewFromInt(int64(counter[v])) passCounterDecimal := decimal.NewFromInt(int64(passCounter[v])) s := passCounterDecimal.Div(counterDecimal).Round(4).Mul(decimal.NewFromInt(10000)).String() if s == "0" { y = append(y, "0%") continue } s = s[:2] + "." + s[2:] + "%" y = append(y, s) } } else if req.ContentType == "参数均值" { counter := make(map[string]int) sum := make(map[string]string) for _, data := range datas { if len(req.Bin) != 0 { var isContain bool for _, bin := range req.Bin { if data[fieldMap["SOFT_BIN"]] == bin { isContain = true break } } if !isContain { continue } } counter[data[fieldMap["SITE_NUM"]]]++ if data[fieldMap[req.Selection]] == "" { data[fieldMap[req.Selection]] = "0" } if sum[data[fieldMap["SITE_NUM"]]] == "" { sum[data[fieldMap["SITE_NUM"]]] = "0" } selectionDecimal, _ := decimal.NewFromString(data[fieldMap[req.Selection]]) sumDecimal, _ := decimal.NewFromString(sum[data[fieldMap["SITE_NUM"]]]) sum[data[fieldMap["SITE_NUM"]]] = sumDecimal.Add(selectionDecimal).String() } for _, v := range req.Site { counterDecimal := decimal.NewFromInt(int64(counter[v])) passCounterDecimal, _ := decimal.NewFromString(sum[v]) s := passCounterDecimal.Div(counterDecimal).Round(4).String() y = append(y, s) } } return &model.Histogram{ X: x, Y: y, } }