test_data/repository/test.data/export.go
2024-09-14 18:12:13 +08:00

2344 lines
86 KiB
Go

package test_data
import (
"bufio"
"encoding/json"
"fmt"
"github.com/shopspring/decimal"
"github.com/spf13/viper"
"github.com/xuri/excelize/v2"
"log"
"math"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"testData/global"
"testData/model"
"testData/request"
"testData/utils"
"time"
)
func ExportCPMap(req *request.CPMap) string {
// CP测试没有子批次
var fileHandles []*model.FileHandled
global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ?", req.PBI, req.Product, req.Lot).
Order("wafer_id").Find(&fileHandles)
cpFile := excelize.NewFile()
passStyle := CPMapPassStyle(cpFile)
failStyle := CPMapFailStyle(cpFile)
_ = cpFile.SetSheetName("Sheet1", "Summary")
allBinMap := make(map[string]int)
for _, fileHandle := range fileHandles {
_, err := strconv.Atoi(fileHandle.WaferID)
if err != nil {
continue
}
f, err := os.Open(fileHandle.Path)
if err != nil {
log.Println(err)
}
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:]
}
for _, data := range datas {
allBinMap[data[fieldMap["SOFT_BIN"]]] = 1
}
f.Close()
}
var binStrs []string
for k := range allBinMap {
binStrs = append(binStrs, "BIN "+k)
}
sort.Slice(binStrs, func(i, j int) bool {
iInt, _ := strconv.Atoi(binStrs[i][4:])
jInt, _ := strconv.Atoi(binStrs[j][4:])
return iInt < jInt
})
var title []string
title = append(title, []string{"产品", "工序", "PBI", "批号", "片号", "Total", "Pass", "Fail", "Yield"}...)
rowIndex := 1
title = append(title, binStrs...)
indexMap := make(map[string]int)
for index, field := range title {
indexMap[field] = index + 1
}
_ = cpFile.SetSheetRow("Summary", "A1", &title)
maxProbability, minProbability, maxRowIndex, minRowIndex := "-1", "-1", -1, -1
for _, fileHandle := range fileHandles {
_, err := strconv.Atoi(fileHandle.WaferID)
if err != nil {
continue
}
rowIndex++
f, err := os.Open(fileHandle.Path)
if err != nil {
log.Println(err)
}
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)
sbinHbinByte := []byte(fileHandle.SbinHbin)
_ = json.Unmarshal(sbinHbinByte, &sbinHbinMap)
var rowData []interface{}
var latestDatas [][]string
endRow, endCol := 0, 0
binMap := make(map[string]int)
sheetIndex, _ := cpFile.NewSheet(fileHandle.WaferID)
sheetName := cpFile.GetSheetName(sheetIndex)
for _, data := range datas {
binInfoMap := sbinHbinMap[data[fieldMap["SOFT_BIN"]]]
x := data[fieldMap["X_COORD"]]
y := data[fieldMap["Y_COORD"]]
xInt, _ := strconv.Atoi(x)
yInt, _ := strconv.Atoi(y)
if endRow < xInt {
endRow = xInt
}
if endCol < yInt {
endCol = yInt
}
//xDecimal, _ := decimal.NewFromString(x)
//yDecimal, _ := decimal.NewFromString(y)
//endRowDecimal, _ := decimal.NewFromString(endRow)
//endColDecimal, _ := decimal.NewFromString(endCol)
//if endRowDecimal.LessThan(xDecimal) {
// endRow = x
//}
//if endColDecimal.LessThan(yDecimal) {
// endCol = y
//}
isAppendData := true
for _, mainData := range latestDatas {
if mainData[0] == x && mainData[1] == y {
mainData = []string{x, y, data[fieldMap["SOFT_BIN"]], binInfoMap["HBin"]}
isAppendData = false
break
}
}
if isAppendData {
latestDatas = append(latestDatas, []string{x, y,
data[fieldMap["SOFT_BIN"]], binInfoMap["HBin"]}) //field[5]
}
}
for _, mainData := range latestDatas {
binMap[mainData[2]]++
x := utils.NumToRow(mainData[0])
y := mainData[1]
if mainData[2] == "1" {
_ = cpFile.SetCellValue(sheetName, x+y, 1)
_ = cpFile.SetCellStyle(sheetName, x+y, x+y, passStyle)
} else {
_ = cpFile.SetCellValue(sheetName, x+y, mainData[2]+":"+mainData[3])
_ = cpFile.SetCellStyle(sheetName, x+y, x+y, failStyle)
}
}
_ = cpFile.SetColWidth(sheetName, utils.NumToRow("1"), utils.NumToRow(strconv.Itoa(endRow)), 2)
//endColIndex, _ := strconv.Atoi(endCol)
//for i := 0; i < endColIndex; i++ {
// _ = cpFile.SetRowHeight(sheetName, i, 10)
//}
for i := 0; i < endCol; i++ {
_ = cpFile.SetRowHeight(sheetName, i, 10)
}
totalDecimal := decimal.NewFromFloat(float64(len(latestDatas)))
passDecimal := decimal.NewFromFloat(float64(binMap["1"]))
maxProbabilityDecimal, _ := decimal.NewFromString(maxProbability)
minProbabilityDecimal, _ := decimal.NewFromString(minProbability)
var passProbability string
if totalDecimal.IsZero() {
passProbability = "0"
minProbability = passProbability
minRowIndex = rowIndex
if maxProbability == "-1" {
maxProbability = passProbability
maxRowIndex = rowIndex
}
} else {
passProbability = passDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).String()
if maxProbability == "-1" {
maxProbability = passProbability
maxRowIndex = rowIndex
} else {
if maxProbabilityDecimal.LessThan(passDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100))) {
maxProbability = passProbability
maxRowIndex = rowIndex
}
}
if minProbability == "-1" {
minProbability = passProbability
minRowIndex = rowIndex
} else {
if passDecimal.Div(totalDecimal).Round(4).Mul(decimal.NewFromInt(100)).LessThan(minProbabilityDecimal) {
minProbability = passProbability
minRowIndex = rowIndex
}
}
}
total, _ := strconv.Atoi(totalDecimal.String())
pass, _ := strconv.Atoi(passDecimal.String())
fail, _ := strconv.Atoi(totalDecimal.Sub(passDecimal).String())
rowData = []interface{}{fileHandle.Product, fileHandle.Step, fileHandle.PBI, fileHandle.Lot, fileHandle.WaferID,
total, pass, fail,
passProbability + "%"}
for _, bin := range binStrs {
if quantity, ok := binMap[bin[4:]]; !ok {
rowData = append(rowData, "")
} else {
rowData = append(rowData, quantity)
}
}
_ = cpFile.SetSheetRow("Summary", "A"+strconv.Itoa(rowIndex), &rowData)
f.Close()
}
// Total
_ = cpFile.SetSheetCol("Summary", "D"+strconv.Itoa(rowIndex+1), &[]interface{}{"Total", "Max Yield", "Min Yield", "Average Yield"})
_ = cpFile.SetCellValue("Summary", "E"+strconv.Itoa(rowIndex+1), rowIndex-1)
_ = cpFile.SetCellFormula("Summary", "F"+strconv.Itoa(rowIndex+1), "=SUM(F2:F"+strconv.Itoa(rowIndex)+")")
_ = cpFile.SetCellFormula("Summary", "G"+strconv.Itoa(rowIndex+1), "=SUM(G2:G"+strconv.Itoa(rowIndex)+")")
_ = cpFile.SetCellFormula("Summary", "H"+strconv.Itoa(rowIndex+1), "=SUM(H2:H"+strconv.Itoa(rowIndex)+")")
// Max Yield
_ = cpFile.SetCellFormula("Summary", "E"+strconv.Itoa(rowIndex+2), "=E"+strconv.Itoa(maxRowIndex))
_ = cpFile.SetCellFormula("Summary", "F"+strconv.Itoa(rowIndex+2), "=F"+strconv.Itoa(maxRowIndex))
_ = cpFile.SetCellFormula("Summary", "G"+strconv.Itoa(rowIndex+2), "=G"+strconv.Itoa(maxRowIndex))
_ = cpFile.SetCellFormula("Summary", "H"+strconv.Itoa(rowIndex+2), "=H"+strconv.Itoa(maxRowIndex))
_ = cpFile.SetCellFormula("Summary", "I"+strconv.Itoa(rowIndex+2), "=I"+strconv.Itoa(maxRowIndex))
// Min Yield
_ = cpFile.SetCellFormula("Summary", "E"+strconv.Itoa(rowIndex+3), "=E"+strconv.Itoa(minRowIndex))
_ = cpFile.SetCellFormula("Summary", "F"+strconv.Itoa(rowIndex+3), "=F"+strconv.Itoa(minRowIndex))
_ = cpFile.SetCellFormula("Summary", "G"+strconv.Itoa(rowIndex+3), "=G"+strconv.Itoa(minRowIndex))
_ = cpFile.SetCellFormula("Summary", "H"+strconv.Itoa(rowIndex+3), "=H"+strconv.Itoa(minRowIndex))
_ = cpFile.SetCellFormula("Summary", "I"+strconv.Itoa(rowIndex+3), "=I"+strconv.Itoa(minRowIndex))
// Average Yield
percentStyle, _ := cpFile.NewStyle(&excelize.Style{
NumFmt: 10,
})
_ = cpFile.SetCellFormula("Summary", "I"+strconv.Itoa(rowIndex+4), "=G"+strconv.Itoa(rowIndex+1)+"/F"+strconv.Itoa(rowIndex+1))
_ = cpFile.SetCellStyle("Summary", "F"+strconv.Itoa(rowIndex+4), "F"+strconv.Itoa(rowIndex+4), percentStyle)
for binIndex, bin := range binStrs {
colName := utils.NumToRow(strconv.Itoa(indexMap[bin]))
// Total
_ = cpFile.SetCellFormula("Summary", colName+strconv.Itoa(rowIndex+1), "=SUM("+colName+"2:"+colName+strconv.Itoa(rowIndex)+")")
// Max Yield
_ = cpFile.SetCellFormula("Summary", colName+strconv.Itoa(rowIndex+2), "="+colName+strconv.Itoa(maxRowIndex))
// Min Yield
_ = cpFile.SetCellFormula("Summary", colName+strconv.Itoa(rowIndex+3), "="+colName+strconv.Itoa(minRowIndex))
// Average Yield
_ = cpFile.SetCellFormula("Summary", colName+strconv.Itoa(rowIndex+4), "="+colName+strconv.Itoa(rowIndex+1)+"/F"+strconv.Itoa(rowIndex+1))
if binIndex == len(binStrs)-1 {
_ = cpFile.SetCellStyle("Summary", "I"+strconv.Itoa(rowIndex+4), colName+strconv.Itoa(rowIndex+4), percentStyle)
}
}
_ = cpFile.SetColWidth("Summary", "A", "A", 15)
_ = cpFile.SetColWidth("Summary", "C", "C", 30)
_ = cpFile.SetColWidth("Summary", "D", "D", 20)
filePath := time.Now().Format("_CpMap_2006-01-02_150405.xlsx")
filePath = req.Product + "_" + req.Lot + filePath
filePath = filepath.Join(utils.MakeSavePath("CP"), filePath)
_ = cpFile.SaveAs(filePath)
defer cpFile.Close()
return strings.ReplaceAll(viper.GetString("domain"), "\\", "/") + filePath
}
type SelectionInfo struct {
Field string
Min float64
Max float64
Average float64
StandardDeviation float64
Num float64
}
func ExportHistogram(req *request.Histogram) string {
var fileHandle *model.FileHandled
global.PostGreSQL.Where("product = ? AND lot = ? AND pbi = ?",
req.Product, req.Lot, req.PBI).Find(&fileHandle)
histogramFile := excelize.NewFile()
row := 1
m := make(map[string]map[string]string)
_ = json.Unmarshal([]byte(fileHandle.TitleInfo), &m)
sheetName := histogramFile.GetSheetName(0)
_ = histogramFile.SetSheetName(sheetName, "汇总表")
sheetName = "汇总表"
if ((len(req.SubBatch) == 0 && len(req.WaferID) == 0) || len(req.SubBatch) != 0 || len(req.WaferID) != 0) &&
!req.SpliteSubBatch {
start := row
selectionInfo := make(map[string][]float64)
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)
} else {
if len(req.SubBatch) != 0 {
for _, subBatch := range req.SubBatch {
subBatchDatas, subBatchFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, subBatch, "", req.Step)
datas = append(datas, subBatchDatas...)
fieldMap = subBatchFieldMap
}
} else if len(req.WaferID) != 0 {
for _, waferID := range req.WaferID {
waferIDDatas, waferIDFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, "", waferID, req.Step)
datas = append(datas, waferIDDatas...)
fieldMap = waferIDFieldMap
}
}
}
for _, data := range datas {
if req.OnlyPass && !(data[fieldMap["SOFT_BIN"]] == "1") {
continue
}
for _, selection := range req.Selections {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]])
selectionFloat, _ := selectionDecimal.Float64()
var filed string
if req.SpliteSite {
filed = selection + "_Site" + data[fieldMap["SITE_NUM"]]
} else {
filed = selection
}
if _, ok := selectionInfo[filed]; !ok {
selectionInfo[filed] = []float64{math.MaxInt, math.MinInt, 0, 0}
}
if selectionInfo[filed][0] > selectionFloat {
selectionInfo[filed][0] = selectionFloat
}
if selectionInfo[filed][1] < selectionFloat {
selectionInfo[filed][1] = selectionFloat
}
selectionInfo[filed][2] += selectionFloat
selectionInfo[filed][3]++
}
}
selectionHistogramX := make(map[string][]string)
selectionHistogramY := make(map[string][]int)
for k, v := range selectionInfo {
selectionInfo[k] = []float64{v[0], v[1], v[2], v[3], v[2] / v[3], 0, 0}
selectionHistogramX[k] = []string{}
minDecimal := decimal.NewFromFloat(v[0])
if minDecimal.Abs().LessThan(decimal.NewFromInt(1)) {
if minDecimal.LessThan(decimal.NewFromInt(0)) {
minDecimal = minDecimal.RoundUp(0)
} else {
minDecimal = minDecimal.RoundDown(0)
}
} else {
if minDecimal.LessThan(decimal.NewFromInt(0)) {
minDecimal = minDecimal.RoundDown(1)
} else {
minDecimal = minDecimal.RoundUp(1)
}
}
maxDecimal := decimal.NewFromFloat(v[1])
if maxDecimal.Abs().LessThan(decimal.NewFromInt(1)) {
if maxDecimal.LessThan(decimal.NewFromInt(0)) {
maxDecimal = maxDecimal.RoundDown(0)
} else {
maxDecimal = maxDecimal.RoundUp(0)
}
} else {
if maxDecimal.LessThan(decimal.NewFromInt(0)) {
maxDecimal = maxDecimal.RoundDown(1)
} else {
maxDecimal = maxDecimal.RoundUp(1)
}
}
interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(20))
for i := 0; i < 21; i++ {
xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String()
selectionHistogramX[k] = append(selectionHistogramX[k], xPoint)
}
}
for _, data := range datas {
if req.OnlyPass && !(data[fieldMap["SOFT_BIN"]] == "1") {
continue
}
for k, v := range selectionInfo {
var field, site string
if req.SpliteSite {
field = strings.Split(k, "_Site")[0]
site = strings.Split(k, "_Site")[1]
if !(site == data[fieldMap["SITE_NUM"]]) {
continue
}
} else {
field = k
}
if data[fieldMap[field]] != "" {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[field]])
averageDecimal := decimal.NewFromFloat(v[4])
d, _ := averageDecimal.Sub(selectionDecimal).Pow(decimal.NewFromInt(2)).
Float64()
for i := 0; i < len(selectionHistogramX[k]); i++ {
if i == len(selectionHistogramX[k])-1 {
xPointDecimal, _ := decimal.NewFromString(selectionHistogramX[k][i])
if xPointDecimal.Equals(selectionDecimal) {
selectionHistogramY[k][i]++
}
break
}
xPointMin, _ := decimal.NewFromString(selectionHistogramX[k][i])
xPointMax, _ := decimal.NewFromString(selectionHistogramX[k][i+1])
if _, ok := selectionHistogramY[k]; !ok {
selectionHistogramY[k] = make([]int, len(selectionHistogramX[k]))
}
if xPointMin.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(xPointMax) {
selectionHistogramY[k][i]++
}
}
v[5] += d
v[6]++
}
}
}
rowIndex := 2
histogramFile.NewSheet("All")
selectionValueMap := make(map[string][]int)
for k, v := range selectionHistogramX {
sheetX := []interface{}{k}
for _, x := range v {
sheetX = append(sheetX, x)
}
sheetY := []interface{}{"数量"}
for _, y := range selectionHistogramY[k] {
sheetY = append(sheetY, y)
}
for idx, rows := range [][]interface{}{
sheetX,
sheetY,
} {
cell, err := excelize.CoordinatesToCellName(1, rowIndex+idx)
if err != nil {
fmt.Println(err)
}
if err = histogramFile.SetSheetRow("All", cell, &rows); err != nil {
fmt.Println(err)
}
}
selectionValueMap[k] = []int{rowIndex, len(selectionHistogramY[k]) + 1}
rowIndex += 2
}
a := 1
for _, selection := range req.Selections {
b := 1
for k, v := range selectionValueMap {
if strings.Contains(k, selection) {
if err := histogramFile.AddChart("All", utils.NumToRow(strconv.Itoa(b))+strconv.Itoa(a), &excelize.Chart{
Type: excelize.Col,
Series: []excelize.ChartSeries{
{
Name: "All" + "!$A$1",
Categories: "All" + "!$B$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: "All" + "!$B$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "none", Size: 10,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "left",
},
Title: []excelize.RichTextRun{
{
Text: k,
},
},
PlotArea: excelize.ChartPlotArea{
ShowCatName: false,
ShowLeaderLines: false,
ShowVal: true,
},
ShowBlanksAs: "zero",
}, &excelize.Chart{
Type: excelize.Line,
Series: []excelize.ChartSeries{
{
Name: "All" + "!$A$1",
Categories: "All" + "!$B$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: "All" + "!$B$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "none", Size: 10,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "right",
},
PlotArea: excelize.ChartPlotArea{
ShowCatName: false,
ShowLeaderLines: false,
},
}); err != nil {
fmt.Println(err)
}
b += 9
}
}
a += 20
}
//ftFile.NewSheet("ALL")
//for k, v := range selectionHistogramX {
// sheetX := []interface{}{""}
// for _, x := range v {
// sheetX = append(sheetX, x)
// }
// sheetY := []interface{}{"数量"}
// for _, y := range selectionHistogramY[k] {
// sheetY = append(sheetY, y)
// }
// for idx, rows := range [][]interface{}{
// sheetX,
// sheetY,
// } {
// cell, err := excelize.CoordinatesToCellName(1, idx+1)
// if err != nil {
// fmt.Println(err)
// }
// if err = ftFile.SetSheetRow(k, cell, &rows); err != nil {
// fmt.Println(err)
// }
// }
// if err := ftFile.AddChart(k, "A4", &excelize.Chart{
// Type: excelize.Col,
// Series: []excelize.ChartSeries{
// {
// Name: k + "!$A$1",
// Categories: k + "!$B$1:$" + utils.NumToRow(strconv.Itoa(len(selectionHistogramY[k])+1)) + "$1",
// Values: k + "!$B$2:$" + utils.NumToRow(strconv.Itoa(len(selectionHistogramY[k])+1)) + "$2",
// },
// },
// Format: excelize.GraphicOptions{
// ScaleX: 1,
// ScaleY: 1,
// OffsetX: 15,
// OffsetY: 10,
// },
// Legend: excelize.ChartLegend{
// Position: "left",
// },
// Title: []excelize.RichTextRun{
// {
// Text: k,
// },
// },
// PlotArea: excelize.ChartPlotArea{
// ShowCatName: false,
// ShowLeaderLines: false,
// ShowVal: true,
// },
// ShowBlanksAs: "zero",
// }, &excelize.Chart{
// Type: excelize.Line,
// Series: []excelize.ChartSeries{
// {
// Name: k + "!$A$1",
// Categories: k + "!$B$1:$" + utils.NumToRow(strconv.Itoa(len(selectionHistogramY[k])+1)) + "$1",
// Values: k + "!$B$2:$" + utils.NumToRow(strconv.Itoa(len(selectionHistogramY[k])+1)) + "$2",
// Marker: excelize.ChartMarker{
// Symbol: "none", Size: 10,
// },
// },
// },
// Format: excelize.GraphicOptions{
// ScaleX: 1,
// ScaleY: 1,
// OffsetX: 15,
// OffsetY: 10,
// },
// Legend: excelize.ChartLegend{
// Position: "right",
// },
// PlotArea: excelize.ChartPlotArea{
// ShowCatName: false,
// ShowLeaderLines: false,
// },
// }); err != nil {
// fmt.Println(err)
// }
//}
col := 1
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"", "最小值", "最大值", "平均值", "δ", "数量", "Limit L", "Limit H", "UNIT"})
col++
siteDiff := make(map[string][]float64)
selectionUnit := make(map[string]string)
var selectionInfoArray []SelectionInfo
for _, selection := range req.Selections {
var oneSelectionInfo []SelectionInfo
for k, v := range selectionInfo {
if !strings.Contains(k, selection) {
continue
}
oneSelectionInfo = append(oneSelectionInfo, SelectionInfo{
Field: k,
Min: v[0],
Max: v[1],
Average: v[4],
StandardDeviation: math.Sqrt(v[5] / v[6]),
Num: v[3],
})
}
sort.Slice(oneSelectionInfo, func(i, j int) bool {
return oneSelectionInfo[i].Field < oneSelectionInfo[j].Field
})
selectionInfoArray = append(selectionInfoArray, oneSelectionInfo...)
}
for _, v := range selectionInfoArray {
field := strings.Split(v.Field, "_Site")[0]
limitLDecimal, _ := decimal.NewFromString(m[field]["LimitL"])
limitLFloat, _ := limitLDecimal.Float64()
limitUDecimal, _ := decimal.NewFromString(m[field]["LimitU"])
limitUFloat, _ := limitUDecimal.Float64()
if req.SpliteSite {
if _, ok := siteDiff[field]; !ok {
siteDiff[field] = []float64{v.Average, v.Average, v.StandardDeviation, v.StandardDeviation}
selectionUnit[field] = m[field]["Unit"]
} else {
if v.Average > siteDiff[field][0] {
siteDiff[field][0] = v.Average
}
if v.Average < siteDiff[field][1] {
siteDiff[field][1] = v.Average
}
if v.StandardDeviation > siteDiff[field][2] {
siteDiff[field][2] = v.StandardDeviation
}
if v.StandardDeviation < siteDiff[field][3] {
siteDiff[field][3] = v.StandardDeviation
}
}
}
_ = histogramFile.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start), &[]interface{}{
v.Field, v.Min, v.Max, v.Average, v.StandardDeviation, v.Num, limitLFloat, limitUFloat, m[field]["Unit"]})
col++
}
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
TitleStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+5),
ActualLimitStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+6), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+8),
LimitStyle(histogramFile))
_ = histogramFile.SetColWidth(sheetName, "A", utils.NumToRow(strconv.Itoa(col-1)),
20)
if req.SpliteSite {
start += 10
col = 2
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"SITE差异"})
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start+1), &[]interface{}{
"", "平均值", "δ", "UNIT"})
for k, v := range siteDiff {
_ = histogramFile.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start+1), &[]interface{}{
k, v[0] - v[1], v[2] - v[3], selectionUnit[k]})
col++
}
_ = histogramFile.MergeCell(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
NormalSheetStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+1),
TitleStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+2), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+3),
ActualLimitStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+4), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+4),
LimitStyle(histogramFile))
}
} else {
start := row
selectionUnit := make(map[string]string)
subBatchDiff := make(map[string][]float64)
var groups []string
var isFT bool
if len(req.SubBatch) != 0 {
groups = req.SubBatch
isFT = true
} else if len(req.WaferID) != 0 {
groups = req.WaferID
} else if len(req.SubBatch) == 0 && len(req.WaferID) == 0 {
global.PostGreSQL.Model(&model.FileHandled{}).Where("product = ? AND lot = ? AND pbi = ?",
req.Product, req.Lot, req.PBI).Group("wafer_id").Select("wafer_id").Find(&groups)
if len(groups) == 0 || groups[0] == "" {
global.PostGreSQL.Model(&model.FileHandled{}).Where("product = ? AND lot = ? AND pbi = ?",
req.Product, req.Lot, req.PBI).Group("sub_batch").Select("sub_batch").Find(&groups)
isFT = true
}
}
for _, group := range groups {
siteSelectionInfo := make(map[string][]float64)
selectionInfo := make(map[string][]float64)
var datas [][]string
fieldMap := make(map[string]int)
if isFT {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "", req.Step)
} else {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group, req.Step)
}
group = strings.ReplaceAll(group, "-", "_")
for _, data := range datas {
if req.OnlyPass && !(data[fieldMap["SOFT_BIN"]] == "1") {
continue
}
for _, selection := range req.Selections {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[selection]])
selectionFloat, _ := selectionDecimal.Float64()
var filed string
if req.SpliteSite {
filed = selection + "_Site" + data[fieldMap["SITE_NUM"]]
} else {
filed = selection
}
if _, ok := siteSelectionInfo[filed]; !ok {
siteSelectionInfo[filed] = []float64{math.MaxInt, math.MinInt, 0, 0}
}
if siteSelectionInfo[filed][0] > selectionFloat {
siteSelectionInfo[filed][0] = selectionFloat
}
if siteSelectionInfo[filed][1] < selectionFloat {
siteSelectionInfo[filed][1] = selectionFloat
}
siteSelectionInfo[filed][2] += selectionFloat
siteSelectionInfo[filed][3]++
if _, ok := selectionInfo[selection]; !ok {
selectionInfo[selection] = []float64{math.MaxInt, math.MinInt, 0, 0}
}
if selectionInfo[selection][0] > selectionFloat {
selectionInfo[selection][0] = selectionFloat
}
if selectionInfo[selection][1] < selectionFloat {
selectionInfo[selection][1] = selectionFloat
}
selectionInfo[selection][2] += selectionFloat
selectionInfo[selection][3]++
}
}
selectionHistogramX := make(map[string][]string)
selectionHistogramY := make(map[string][]int)
for k, v := range siteSelectionInfo {
siteSelectionInfo[k] = []float64{v[0], v[1], v[2], v[3], v[2] / v[3], 0, 0}
if req.SpliteSite {
selectionHistogramX[group+"_"+k] = []string{}
minDecimal := decimal.NewFromFloat(v[0])
if minDecimal.LessThan(decimal.NewFromInt(0)) {
minDecimal = minDecimal.RoundUp(0)
} else {
minDecimal = minDecimal.RoundDown(0)
}
maxDecimal := decimal.NewFromFloat(v[1])
if maxDecimal.LessThan(decimal.NewFromInt(0)) {
maxDecimal = maxDecimal.RoundDown(0)
} else {
maxDecimal = maxDecimal.RoundUp(0)
}
interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(20))
for i := 0; i < 21; i++ {
xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String()
selectionHistogramX[group+"_"+k] = append(selectionHistogramX[group+"_"+k], xPoint)
}
}
}
for k, v := range selectionInfo {
selectionInfo[k] = []float64{v[0], v[1], v[2], v[3], v[2] / v[3], 0, 0}
if !req.SpliteSite {
selectionHistogramX[group+"_"+k] = []string{}
minDecimal := decimal.NewFromFloat(v[0])
if minDecimal.LessThan(decimal.NewFromInt(0)) {
minDecimal = minDecimal.RoundUp(0)
} else {
minDecimal = minDecimal.RoundDown(0)
}
maxDecimal := decimal.NewFromFloat(v[1])
if maxDecimal.LessThan(decimal.NewFromInt(0)) {
maxDecimal = maxDecimal.RoundDown(0)
} else {
maxDecimal = maxDecimal.RoundUp(0)
}
interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(20))
for i := 0; i < 21; i++ {
xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String()
selectionHistogramX[group+"_"+k] = append(selectionHistogramX[group+"_"+k], xPoint)
}
}
}
for _, data := range datas {
if req.OnlyPass && !(data[fieldMap["SOFT_BIN"]] == "1") {
continue
}
for k, v := range siteSelectionInfo {
var field, site string
if req.SpliteSite {
field = strings.Split(k, "_Site")[0]
site = strings.Split(k, "_Site")[1]
if !(site == data[fieldMap["SITE_NUM"]]) {
continue
}
} else {
field = k
}
if data[fieldMap[field]] != "" {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[field]])
averageDecimal := decimal.NewFromFloat(v[4])
d, _ := averageDecimal.Sub(selectionDecimal).Pow(decimal.NewFromInt(2)).
Float64()
if req.SpliteSite {
a := group + "_" + k
for i := 0; i < len(selectionHistogramX[a]); i++ {
if i == len(selectionHistogramX[a])-1 {
xPointDecimal, _ := decimal.NewFromString(selectionHistogramX[a][i])
if xPointDecimal.Equals(selectionDecimal) {
selectionHistogramY[a][i]++
}
break
}
xPointMin, _ := decimal.NewFromString(selectionHistogramX[a][i])
xPointMax, _ := decimal.NewFromString(selectionHistogramX[a][i+1])
if _, ok := selectionHistogramY[a]; !ok {
selectionHistogramY[a] = make([]int, len(selectionHistogramX[a]))
}
if xPointMin.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(xPointMax) {
selectionHistogramY[a][i]++
}
}
}
v[5] += d
v[6]++
}
}
for k, v := range selectionInfo {
if data[fieldMap[k]] != "" {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[k]])
averageDecimal := decimal.NewFromFloat(v[4])
d, _ := averageDecimal.Sub(selectionDecimal).Pow(decimal.NewFromInt(2)).
Float64()
if !req.SpliteSite {
field := group + "_" + k
for i := 0; i < len(selectionHistogramX[field]); i++ {
if i == len(selectionHistogramX[field])-1 {
xPointDecimal, _ := decimal.NewFromString(selectionHistogramX[field][i])
if xPointDecimal.Equals(selectionDecimal) {
selectionHistogramY[field][i]++
}
break
}
xPointMin, _ := decimal.NewFromString(selectionHistogramX[field][i])
xPointMax, _ := decimal.NewFromString(selectionHistogramX[field][i+1])
if _, ok := selectionHistogramY[field]; !ok {
selectionHistogramY[field] = make([]int, len(selectionHistogramX[field]))
}
if xPointMin.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(xPointMax) {
selectionHistogramY[field][i]++
}
}
}
v[5] += d
v[6]++
}
}
}
rowIndex, colIndex := 2, 1
histogramFile.NewSheet(group)
selectionValueMap := make(map[string][]int)
for k, v := range selectionHistogramX {
sheetX := []interface{}{k}
for _, x := range v {
sheetX = append(sheetX, x)
}
sheetY := []interface{}{"数量"}
for _, y := range selectionHistogramY[k] {
sheetY = append(sheetY, y)
}
for idx, rows := range [][]interface{}{
sheetX,
sheetY,
} {
cell, err := excelize.CoordinatesToCellName(colIndex, rowIndex+idx)
if err != nil {
fmt.Println(err)
}
if err = histogramFile.SetSheetRow(group, cell, &rows); err != nil {
fmt.Println(err)
}
}
selectionValueMap[k] = []int{rowIndex, len(selectionHistogramY[k]) + 1}
rowIndex += 2
}
a := 1
for _, selection := range req.Selections {
b := 1
for k, v := range selectionValueMap {
if strings.Contains(k, selection) {
if err := histogramFile.AddChart(group, utils.NumToRow(strconv.Itoa(b))+strconv.Itoa(a), &excelize.Chart{
Type: excelize.Col,
Series: []excelize.ChartSeries{
{
Name: group + "!$A$1",
Categories: group + "!$B$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: group + "!$B$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "none", Size: 10,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "left",
},
Title: []excelize.RichTextRun{
{
Text: k,
},
},
PlotArea: excelize.ChartPlotArea{
ShowCatName: false,
ShowLeaderLines: false,
ShowVal: true,
},
ShowBlanksAs: "zero",
}, &excelize.Chart{
Type: excelize.Line,
Series: []excelize.ChartSeries{
{
Name: group + "!$A$1",
Categories: group + "!$B$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: group + "!$B$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "none", Size: 10,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "right",
},
PlotArea: excelize.ChartPlotArea{
ShowCatName: false,
ShowLeaderLines: false,
},
}); err != nil {
fmt.Println(err)
}
b += 9
}
}
a += 20
}
col := 1
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"子批:" + group})
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start+1), &[]interface{}{
"", "最小值", "最大值", "平均值", "δ", "数量", "Limit L", "Limit H", "UNIT"})
col++
siteDiff := make(map[string][]float64)
var selectionInfoArray []SelectionInfo
for _, selection := range req.Selections {
var oneSelectionInfo []SelectionInfo
for k, v := range siteSelectionInfo {
if !strings.Contains(k, selection) {
continue
}
oneSelectionInfo = append(oneSelectionInfo, SelectionInfo{
Field: k,
Min: v[0],
Max: v[1],
Average: v[4],
StandardDeviation: math.Sqrt(v[5] / v[6]),
Num: v[3],
})
}
sort.Slice(oneSelectionInfo, func(i, j int) bool {
return oneSelectionInfo[i].Field < oneSelectionInfo[j].Field
})
selectionInfoArray = append(selectionInfoArray, oneSelectionInfo...)
}
for _, v := range selectionInfoArray {
field := strings.Split(v.Field, "_Site")[0]
limitLDecimal, _ := decimal.NewFromString(m[field]["LimitL"])
limitLFloat, _ := limitLDecimal.Float64()
limitUDecimal, _ := decimal.NewFromString(m[field]["LimitU"])
limitUFloat, _ := limitUDecimal.Float64()
selectionUnit[field] = m[field]["Unit"]
if req.SpliteSite {
if _, ok := siteDiff[field]; !ok {
siteDiff[field] = []float64{v.Average, v.Average, v.StandardDeviation, v.StandardDeviation}
} else {
if v.Average > siteDiff[field][0] {
siteDiff[field][0] = v.Average
}
if v.Average < siteDiff[field][1] {
siteDiff[field][1] = v.Average
}
if v.StandardDeviation > siteDiff[field][2] {
siteDiff[field][2] = v.StandardDeviation
}
if v.StandardDeviation < siteDiff[field][3] {
siteDiff[field][3] = v.StandardDeviation
}
}
}
_ = histogramFile.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start+1), &[]interface{}{
v.Field, v.Min, v.Max, v.Average, v.StandardDeviation, v.Num, limitLFloat, limitUFloat, m[field]["Unit"]})
col++
}
for k, v := range selectionInfo {
if _, ok := subBatchDiff[k]; !ok {
subBatchDiff[k] = []float64{v[4], v[4], v[5] / v[6], v[5] / v[6]}
selectionUnit[k] = m[k]["Unit"]
} else {
if v[4] > subBatchDiff[k][0] {
subBatchDiff[k][0] = v[4]
}
if v[4] < subBatchDiff[k][1] {
subBatchDiff[k][1] = v[4]
}
if v[5]/v[6] > subBatchDiff[k][2] {
subBatchDiff[k][2] = v[5] / v[6]
}
if v[5]/v[6] < subBatchDiff[k][3] {
subBatchDiff[k][3] = v[5] / v[6]
}
}
}
_ = histogramFile.MergeCell(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
NormalSheetStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+1),
TitleStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+2), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+6),
ActualLimitStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+7), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+9),
LimitStyle(histogramFile))
_ = histogramFile.SetColWidth(sheetName, "A", utils.NumToRow(strconv.Itoa(col-1)),
20)
start += 10
if req.SpliteSite {
start += 1
col = 2
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"SITE差异-" + group})
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start+1), &[]interface{}{
"", "平均值", "δ", "UNIT"})
for k, v := range siteDiff {
_ = histogramFile.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start+1), &[]interface{}{
k, v[0] - v[1], v[2] - v[3], selectionUnit[k]})
col++
}
_ = histogramFile.MergeCell(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
NormalSheetStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+1),
TitleStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+2), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+3),
ActualLimitStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+4), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+4),
LimitStyle(histogramFile))
start += 5
}
start += 1
}
start += 1
col := 2
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"批次差异汇总"})
_ = histogramFile.SetSheetCol(sheetName, "A"+strconv.Itoa(start+1), &[]interface{}{
"", "平均值", "δ", "UNIT"})
for _, selection := range req.Selections {
_ = histogramFile.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start+1), &[]interface{}{
selection, subBatchDiff[selection][0] - subBatchDiff[selection][1],
subBatchDiff[selection][2] - subBatchDiff[selection][3], selectionUnit[selection]})
col++
}
_ = histogramFile.MergeCell(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
NormalSheetStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+1),
TitleStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+2), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+3),
ActualLimitStyle(histogramFile))
_ = histogramFile.SetCellStyle(sheetName, "A"+strconv.Itoa(start+4), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+4),
LimitStyle(histogramFile))
}
filePath := time.Now().Format("_直方图_2006-01-02_150405.xlsx")
filePath = req.Product + "_" + req.Lot + filePath
filePath = filepath.Join(utils.MakeSavePath("直方图"), filePath)
_ = histogramFile.SaveAs(filePath)
defer histogramFile.Close()
return strings.ReplaceAll(viper.GetString("domain"), "\\", "/") + filePath
}
func ExportScatter(req *request.Scatter) string {
scatterFile := excelize.NewFile()
//((len(req.SubBatch) == 0 && len(req.WaferID) == 0) || len(req.SubBatch) != 0 || len(req.WaferID) != 0) &&
if !req.SpliteSubBatch {
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)
} else {
if len(req.SubBatch) != 0 {
for _, subBatch := range req.SubBatch {
subBatchDatas, subBatchFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, subBatch, "", req.Step)
datas = append(datas, subBatchDatas...)
fieldMap = subBatchFieldMap
}
} else if len(req.WaferID) != 0 {
for _, waferID := range req.WaferID {
waferIDDatas, waferIDFieldMap := LotInAFile(req.Product, req.Lot, req.PBI, "", waferID, req.Step)
datas = append(datas, waferIDDatas...)
fieldMap = waferIDFieldMap
}
}
}
selectionPointsMap := make(map[string]map[string]int)
for _, data := range datas {
if req.OnlyPass {
if data[fieldMap["SOFT_BIN"]] != "1" {
continue
}
}
for _, selection := range req.XYSelection {
var field string
if req.SpliteSite {
field = selection.X + "," + selection.Y + "_SITE" + data[fieldMap["SITE_NUM"]]
} else {
field = selection.X + "," + selection.Y
}
if _, ok := selectionPointsMap[field]; !ok {
selectionPointsMap[field] = map[string]int{}
}
selectionPointsMap[field][data[fieldMap[selection.X]]+","+data[fieldMap[selection.Y]]]++
}
}
scatterFile.SetSheetName("Sheet1", "All")
sheetName := scatterFile.GetSheetName(0)
selectionValueMap := make(map[string][]int)
rowIndex := 1
for _, selection := range req.XYSelection {
for k := range selectionPointsMap {
if strings.Contains(k, selection.X+","+selection.Y) {
sheetX := []interface{}{k, selection.X}
sheetY := []interface{}{"", selection.Y}
for point := range selectionPointsMap[k] {
pointXY := strings.Split(point, ",")
xDecimal, _ := decimal.NewFromString(pointXY[0])
x, _ := xDecimal.Float64()
yDecimal, _ := decimal.NewFromString(pointXY[1])
y, _ := yDecimal.Float64()
sheetX = append(sheetX, x)
sheetY = append(sheetY, y)
}
for idx, row := range [][]interface{}{
sheetX,
sheetY,
} {
cell, err := excelize.CoordinatesToCellName(1, rowIndex+idx)
if err != nil {
fmt.Println(err)
}
if err = scatterFile.SetSheetRow(sheetName, cell, &row); err != nil {
fmt.Println(err)
}
}
selectionValueMap[k] = []int{rowIndex, len(sheetY) + 1}
rowIndex += 2
}
}
}
a := 1
for _, selection := range req.XYSelection {
b := 1
for k, v := range selectionValueMap {
if strings.Contains(k, selection.X+","+selection.Y) {
if err := scatterFile.AddChart("All", utils.NumToRow(strconv.Itoa(b))+strconv.Itoa(a), &excelize.Chart{
Type: excelize.Scatter,
Series: []excelize.ChartSeries{
{
Name: "All" + "!$A$1",
Categories: "All" + "!$C$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: "All" + "!$C$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "circle", Size: 1,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "bottom",
},
Title: []excelize.RichTextRun{
{
Text: k,
},
},
//PlotArea: excelize.ChartPlotArea{
// ShowCatName: false,
// ShowLeaderLines: false,
//},
ShowBlanksAs: "zero",
}); err != nil {
fmt.Println(err)
}
b += 9
}
}
a += 20
}
} else {
var groups []string
var isFT bool
if len(req.SubBatch) != 0 {
groups = req.SubBatch
isFT = true
} else if len(req.WaferID) != 0 {
groups = req.WaferID
} else if len(req.SubBatch) == 0 && len(req.WaferID) == 0 {
global.PostGreSQL.Model(&model.FileHandled{}).Where("product = ? AND lot = ? AND pbi = ?",
req.Product, req.Lot, req.PBI).Group("wafer_id").Select("wafer_id").Find(&groups)
if len(groups) == 0 || groups[0] == "" {
global.PostGreSQL.Model(&model.FileHandled{}).Where("product = ? AND lot = ? AND pbi = ?",
req.Product, req.Lot, req.PBI).Group("sub_batch").Select("sub_batch").Find(&groups)
isFT = true
}
}
for _, group := range groups {
var datas [][]string
fieldMap := make(map[string]int)
if isFT {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, group, "", req.Step)
} else {
datas, fieldMap = LotInAFile(req.Product, req.Lot, req.PBI, "", group, req.Step)
}
group = strings.ReplaceAll(group, "-", "_")
selectionPointsMap := make(map[string]map[string]int)
for _, data := range datas {
if req.OnlyPass {
if data[fieldMap["SOFT_BIN"]] != "1" {
continue
}
}
for _, selection := range req.XYSelection {
var field string
if req.SpliteSite {
field = selection.X + "," + selection.Y + "_SITE" + data[fieldMap["SITE_NUM"]]
} else {
field = selection.X + "," + selection.Y
}
if _, ok := selectionPointsMap[field]; !ok {
selectionPointsMap[field] = map[string]int{}
}
selectionPointsMap[field][data[fieldMap[selection.X]]+","+data[fieldMap[selection.Y]]]++
}
}
scatterFile.NewSheet(group)
selectionValueMap := make(map[string][]int)
rowIndex := 1
for _, selection := range req.XYSelection {
for k := range selectionPointsMap {
if strings.Contains(k, selection.X+","+selection.Y) {
sheetX := []interface{}{k, selection.X}
sheetY := []interface{}{"", selection.Y}
for point := range selectionPointsMap[k] {
pointXY := strings.Split(point, ",")
xDecimal, _ := decimal.NewFromString(pointXY[0])
x, _ := xDecimal.Float64()
yDecimal, _ := decimal.NewFromString(pointXY[1])
y, _ := yDecimal.Float64()
sheetX = append(sheetX, x)
sheetY = append(sheetY, y)
}
for idx, row := range [][]interface{}{
sheetX,
sheetY,
} {
cell, err := excelize.CoordinatesToCellName(1, rowIndex+idx)
if err != nil {
fmt.Println(err)
}
if err = scatterFile.SetSheetRow(group, cell, &row); err != nil {
fmt.Println(err)
}
}
selectionValueMap[k] = []int{rowIndex, len(sheetY) + 1}
rowIndex += 2
}
}
}
a := 1
for _, selection := range req.XYSelection {
b := 1
for k, v := range selectionValueMap {
if strings.Contains(k, selection.X+","+selection.Y) {
if err := scatterFile.AddChart(group, utils.NumToRow(strconv.Itoa(b))+strconv.Itoa(a), &excelize.Chart{
Type: excelize.Scatter,
Series: []excelize.ChartSeries{
{
Name: group + "!$A$1",
Categories: group + "!$C$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: group + "!$C$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "circle", Size: 1,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "bottom",
},
Title: []excelize.RichTextRun{
{
Text: k,
},
},
//PlotArea: excelize.ChartPlotArea{
// ShowCatName: false,
// ShowLeaderLines: false,
//},
ShowBlanksAs: "zero",
}); err != nil {
fmt.Println(err)
}
b += 9
}
}
a += 20
}
}
}
scatterFile.DeleteSheet("Sheet1")
filePath := time.Now().Format("_散点图_2006-01-02_150405.xlsx")
filePath = req.Product + "_" + req.Lot + filePath
filePath = filepath.Join(utils.MakeSavePath("散点图"), filePath)
_ = scatterFile.SaveAs(filePath)
defer scatterFile.Close()
return strings.ReplaceAll(viper.GetString("domain"), "\\", "/") + filePath
}
func ExportFT() string {
//start := carbon.Now().SubWeek().Format("Y-m-d")
//end := carbon.Now().Format("Y-m-d")
//var fileHandles []*model.FileHandled
//global.PostGreSQL.Where("ending_time != ? AND DATE(ending_time) BETWEEN ? AND ?", "", start, end).
// Find(&fileHandles)
file := excelize.NewFile()
var ftLists []*model.FTList
//global.PostGreSQL.Where("order_date BETWEEN ? AND ?", start, end).Find(&ftLists)
//global.PostGreSQL.Find(&ftLists)
var a []string
global.PostGreSQL.Model(&model.Report{}).Where("pbi != ?", "").Group("pbi").Select("pbi").Find(&a)
global.PostGreSQL.Where("pbi IN ?", a).Find(&ftLists)
//global.PostGreSQL.Where("product = ? AND lot = ? AND pbi = ?", "MP5016-5EC0", "S3S592", "M589-2306200001").Find(&ftLists)
//var exportFTs []*model.ExportFT
sheetName := "FT记录总表"
_, _ = file.NewSheet(sheetName)
_ = file.SetSheetRow(sheetName, "A1", &[]interface{}{"成品型号", "晶圆批次", "PBI", "测试厂", "测试程序", "下单日期",
"丝印", "结批测试数量", "结批良品数量", "结批良率", "初测良品数量", "初测良率", "测试数量", "良品数量", "测试良率",
"回收率", "测试数量差异", "良品数量差异", "硬件bin", "SITE差异", "叠料风险",
})
ftRecordIndex := 2
for _, ftList := range ftLists {
var warning *model.Warning
global.PostGreSQL.Where("step LIKE ? AND product = ?", "%FT%", ftList.Product).
Preload("ProductionControl").Preload("PassProbabilityDiff").Preload("BinControl").
Preload("SelectionDiffControl").Preload("StackingMaterialsWarning").Preload("HistogramSelection").
Preload("ScatterSelection").Find(&warning)
var testQuantity, firstPassQuantity, firstPassProbability, passQuantity, passProbability string
var finalTestQuantity, finalPassQuantity, finalPassProbability, returnProbability string
var reports []*model.Report
global.PostGreSQL.Where("step LIKE ? AND product = ? AND lot = ? AND pbi = ?",
"%FT%", ftList.Product, ftList.Lot, ftList.PBI).Find(&reports)
for _, report := range reports {
reportTestQuantityDecimal, _ := decimal.NewFromString(report.TestQuantity)
testQuantityDecimal, _ := decimal.NewFromString(testQuantity)
testQuantity = testQuantityDecimal.Add(reportTestQuantityDecimal).String()
reportFirstPassQuantityDecimal, _ := decimal.NewFromString(report.FirstPassQuantity)
firstPassQuantityDecimal, _ := decimal.NewFromString(firstPassQuantity)
firstPassQuantity = firstPassQuantityDecimal.Add(reportFirstPassQuantityDecimal).String()
reportPassQuantityDecimal, _ := decimal.NewFromString(report.PassQuantity)
passQuantityDecimal, _ := decimal.NewFromString(passQuantity)
passQuantity = passQuantityDecimal.Add(reportPassQuantityDecimal).String()
}
testQuantityDecimal, _ := decimal.NewFromString(testQuantity)
firstPassQuantityDecimal, _ := decimal.NewFromString(firstPassQuantity)
passQuantityDecimal, _ := decimal.NewFromString(passQuantity)
if !testQuantityDecimal.IsZero() {
firstPassProbability = firstPassQuantityDecimal.Div(testQuantityDecimal).Round(4).
Mul(decimal.NewFromInt(100)).String() + "%"
passProbability = passQuantityDecimal.Div(testQuantityDecimal).Round(4).
Mul(decimal.NewFromInt(100)).String() + "%"
returnProbability = passQuantityDecimal.Sub(firstPassQuantityDecimal).Div(testQuantityDecimal).Round(4).
Mul(decimal.NewFromInt(100)).String() + "%"
}
var finalReports []*model.FinalReport
hardBinCounter := make(map[string]float64)
global.PostGreSQL.Where("step LIKE ? AND product = ? AND lot = ? AND pbi = ?",
"%FT%", ftList.Product, ftList.Lot, ftList.PBI).Find(&finalReports)
for _, finalReport := range finalReports {
reportTestQuantityDecimal, _ := decimal.NewFromString(finalReport.ReportTestQuantity)
finalTestQuantityDecimal, _ := decimal.NewFromString(finalTestQuantity)
finalTestQuantity = finalTestQuantityDecimal.Add(reportTestQuantityDecimal).String()
reportPassQuantityDecimal, _ := decimal.NewFromString(finalReport.ReportPassQuantity)
finalPassQuantityDecimal, _ := decimal.NewFromString(finalPassQuantity)
finalPassQuantity = finalPassQuantityDecimal.Add(reportPassQuantityDecimal).String()
bin1Decimal, _ := decimal.NewFromString(finalReport.Bin1)
bin2Decimal, _ := decimal.NewFromString(finalReport.Bin2)
bin2, _ := bin2Decimal.Float64()
hardBinCounter["BIN2"] += bin2
bin3Decimal, _ := decimal.NewFromString(finalReport.Bin3)
bin3, _ := bin3Decimal.Float64()
hardBinCounter["BIN3"] += bin3
bin4Decimal, _ := decimal.NewFromString(finalReport.Bin4)
bin4, _ := bin4Decimal.Float64()
hardBinCounter["BIN4"] += bin4
bin5Decimal, _ := decimal.NewFromString(finalReport.Bin5)
bin5, _ := bin5Decimal.Float64()
hardBinCounter["BIN5"] += bin5
bin6Decimal, _ := decimal.NewFromString(finalReport.Bin6)
bin6, _ := bin6Decimal.Float64()
hardBinCounter["BIN6"] += bin6
bin7Decimal, _ := decimal.NewFromString(finalReport.Bin7)
bin7, _ := bin7Decimal.Float64()
hardBinCounter["BIN7"] += bin7
bin8Decimal, _ := decimal.NewFromString(finalReport.Bin8)
bin8, _ := bin8Decimal.Float64()
hardBinCounter["BIN8"] += bin8
bin9Decimal, _ := decimal.NewFromString(finalReport.Bin9)
bin9, _ := bin9Decimal.Float64()
hardBinCounter["BIN9"] += bin9
bin10Decimal, _ := decimal.NewFromString(finalReport.Bin10)
bin10, _ := bin10Decimal.Float64()
hardBinCounter["BIN10"] += bin10
outlookFailDecimal, _ := decimal.NewFromString(finalReport.OutlookFail)
otherDecimal, _ := decimal.NewFromString(finalReport.Other)
bentStitchDecimal, _ := decimal.NewFromString(finalReport.BentStitch)
scrappedDecimal, _ := decimal.NewFromString(finalReport.Scrapped)
if !reportTestQuantityDecimal.IsZero() {
finalReport.Bin1 = bin1Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin2 = bin2Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin3 = bin3Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin4 = bin4Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin5 = bin5Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin6 = bin6Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin7 = bin7Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin8 = bin8Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin9 = bin9Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Bin10 = bin10Decimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.OutlookFail = outlookFailDecimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Other = otherDecimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.BentStitch = bentStitchDecimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
finalReport.Scrapped = scrappedDecimal.Div(reportTestQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).
String() + "%"
}
}
finalTestQuantityDecimal, _ := decimal.NewFromString(finalTestQuantity)
finalPassQuantityDecimal, _ := decimal.NewFromString(finalPassQuantity)
if !finalTestQuantityDecimal.IsZero() {
finalPassProbability = finalPassQuantityDecimal.Div(finalTestQuantityDecimal).Round(4).
Mul(decimal.NewFromInt(100)).String() + "%"
}
var testQuantityDiff, passQuantityDiff string
hardBinState := "正常"
if !testQuantityDecimal.IsZero() {
testQuantityDiff = testQuantityDecimal.Sub(finalTestQuantityDecimal).Div(testQuantityDecimal).Round(4).
Mul(decimal.NewFromInt(100)).String() + "%"
passQuantityDiff = passQuantityDecimal.Sub(finalPassQuantityDecimal).Div(passQuantityDecimal).Round(4).
Mul(decimal.NewFromInt(100)).String() + "%"
for _, binControl := range warning.BinControl {
binDecimal := decimal.NewFromFloat(hardBinCounter[binControl.Bin])
limitDecimal, _ := decimal.NewFromString(strings.ReplaceAll(binControl.BinFailLimitH, "%", ""))
if !binDecimal.Div(testQuantityDecimal).Mul(decimal.NewFromInt(100)).LessThanOrEqual(limitDecimal) {
hardBinState = "异常"
}
}
}
var fileHandles []*model.FileHandled
global.PostGreSQL.Where("step = ? AND pbi = ? AND product = ? AND lot = ?", "FT", ftList.PBI,
ftList.Product, ftList.Lot).Find(&fileHandles)
siteDiffState := "正常"
stackingMaterials := "否"
for _, fileHandle := range fileHandles {
f, err := os.Open(fileHandle.Path)
if err != nil {
log.Println(err)
}
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:]
}
siteCounter := make(map[string]int64)
sitePassCounter := make(map[string]int64)
selectionCounter := make(map[string]map[string]string)
stackingMaterialsArray := make(map[string]map[string][]float64)
for _, data := range datas {
siteCounter[data[fieldMap["SITE_NUM"]]]++
if _, ok := stackingMaterialsArray[data[fieldMap["SITE_NUM"]]]; !ok {
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]] = make(map[string][]float64)
}
if data[fieldMap["SOFT_BIN"]] == "1" {
sitePassCounter[data[fieldMap["SITE_NUM"]]]++
for _, stackingMaterialsWarning := range warning.StackingMaterialsWarning {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[stackingMaterialsWarning.Selection]])
selectionFloat64, _ := selectionDecimal.Float64()
if _, ok := stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection]; !ok {
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection] = []float64{selectionFloat64}
} else {
//quantity, _ := strconv.Atoi(stackingMaterialsWarning.Quantity)
if len(stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection]) >
stackingMaterialsWarning.Quantity { //quantity
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection] =
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection][1:]
}
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection] = append(
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection], selectionFloat64)
}
if len(stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection]) ==
stackingMaterialsWarning.Quantity {
diff, _ := strconv.ParseFloat(stackingMaterialsWarning.Diff, 64)
midArray := stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection]
sort.Slice(midArray,
func(i, j int) bool {
return midArray[i] >
midArray[j]
})
if midArray[0]-midArray[len(midArray)-1] >
diff {
stackingMaterials = "是"
}
}
}
} else {
for _, stackingMaterialsWarning := range warning.StackingMaterialsWarning {
stackingMaterialsArray[data[fieldMap["SITE_NUM"]]][stackingMaterialsWarning.Selection] = []float64{}
}
}
for _, selectionDiffControl := range warning.SelectionDiffControl {
if _, ok := selectionCounter[data[fieldMap["SITE_NUM"]]]; !ok {
selectionCounter[data[fieldMap["SITE_NUM"]]] = make(map[string]string)
}
sumDecimal, _ := decimal.NewFromString(selectionCounter[data[fieldMap["SITE_NUM"]]][selectionDiffControl.Selection])
aDecimal, _ := decimal.NewFromString(data[fieldMap[selectionDiffControl.Selection]])
selectionCounter[data[fieldMap["SITE_NUM"]]][selectionDiffControl.Selection] = sumDecimal.Add(aDecimal).String()
}
}
for _, selectionDiffControl := range warning.SelectionDiffControl {
maxAverage, minAverage := math.SmallestNonzeroFloat64, math.MaxFloat64
for _, v := range selectionCounter {
sumDecimal, _ := decimal.NewFromString(v[selectionDiffControl.Selection])
average, _ := sumDecimal.Div(decimal.NewFromInt(siteCounter[selectionDiffControl.Selection])).Float64()
if average > maxAverage {
maxAverage = average
}
if average < minAverage {
minAverage = average
}
}
siteDiffDecimal, _ := decimal.NewFromString(selectionDiffControl.SiteDiff)
averageDiffDecimal := decimal.NewFromFloat(maxAverage - minAverage)
if !siteDiffDecimal.LessThanOrEqual(averageDiffDecimal) {
siteDiffState = "异常"
break
}
}
if siteDiffState == "正常" {
for site := range siteCounter {
sumDecimal := decimal.NewFromInt(siteCounter[site])
sumPassDecimal := decimal.NewFromInt(sitePassCounter[site])
sitePassProbabilityDecimal, _ := decimal.NewFromString(strings.ReplaceAll(warning.FirstPassProbabilityLimitL, "%", ""))
if !sumPassDecimal.Div(sumDecimal).Mul(decimal.NewFromInt(100)).LessThanOrEqual(sitePassProbabilityDecimal) {
siteDiffState = "异常"
break
}
}
}
f.Close()
}
//exportFTs = append(exportFTs, &model.ExportFT{
// Product: ftList.Product,
// Lot: ftList.Lot,
// PBI: ftList.PBI,
// Factory: ftList.Factory,
// TestProgram: ftList.TestProgram,
// OrderDate: ftList.OrderDate,
// Seal: ftList.Seal,
// FinalTestQuantity: finalTestQuantity,
// FinalPassQuantity: finalPassQuantity,
// FinalPassProbability: finalPassProbability,
// FirstPassQuantity: firstPassQuantity,
// FirstPassProbability: firstPassProbability,
// TestQuantity: testQuantity,
// PassQuantity: passQuantity,
// PassProbability: passProbability,
// ReturnProbability: returnProbability,
// TestQuantityDiff: testQuantityDiff,
// PassQuantityDiff: passQuantityDiff,
// HardBinState: hardBinState,
// SiteDiffState: siteDiffState,
// StackingMaterials: stackingMaterials,
//})
_ = file.SetCellStyle(sheetName, "A1", "U1", ExportFTSheetTitleStyle(file))
_ = file.SetSheetRow(sheetName, "A"+strconv.Itoa(ftRecordIndex), &[]interface{}{ftList.Product, ftList.Lot,
ftList.PBI, ftList.Factory, ftList.TestProgram, ftList.OrderDate, ftList.Seal, finalTestQuantity,
finalPassQuantity, finalPassProbability, firstPassQuantity, firstPassProbability,
testQuantity, passQuantity, passProbability, returnProbability,
testQuantityDiff, passQuantityDiff, hardBinState, siteDiffState,
stackingMaterials})
if warning.FirstPassProbabilityLimitL != "" {
s := strings.ReplaceAll(firstPassProbability, "%", "")
sDecimal, _ := decimal.NewFromString(s)
firstPassProbabilityLimitLDecimal, _ := decimal.NewFromString(strings.ReplaceAll(warning.FirstPassProbabilityLimitL, "%", ""))
if sDecimal.LessThan(firstPassProbabilityLimitLDecimal) {
_ = file.SetCellStyle(sheetName, "L"+strconv.Itoa(ftRecordIndex), "L"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
}
if warning.PassProbabilityLimitL != "" {
s := strings.ReplaceAll(passProbability, "%", "")
sDecimal, _ := decimal.NewFromString(s)
passProbabilityLimitLDecimal, _ := decimal.NewFromString(strings.ReplaceAll(warning.PassProbabilityLimitL, "%", ""))
if sDecimal.LessThan(passProbabilityLimitLDecimal) {
_ = file.SetCellStyle(sheetName, "O"+strconv.Itoa(ftRecordIndex), "O"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
}
if warning.ReturnProbabilityLimitH != "" {
s := strings.ReplaceAll(returnProbability, "%", "")
sDecimal, _ := decimal.NewFromString(s)
returnProbabilityLimitHDecimal, _ := decimal.NewFromString(strings.ReplaceAll(warning.ReturnProbabilityLimitH, "%", ""))
if returnProbabilityLimitHDecimal.LessThan(sDecimal) {
_ = file.SetCellStyle(sheetName, "P"+strconv.Itoa(ftRecordIndex), "P"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
}
for _, productionControl := range warning.ProductionControl {
if productionControl.Factory == ftList.Factory {
testQuantityDiffStr := strings.ReplaceAll(testQuantityDiff, "%", "")
sDecimal, _ := decimal.NewFromString(testQuantityDiffStr)
testQuantityDiffHDecimal, _ := decimal.NewFromString(strings.ReplaceAll(productionControl.TestQuantityDiffH, "%", ""))
testQuantityDiffLDecimal, _ := decimal.NewFromString(strings.ReplaceAll(productionControl.TestQuantityDiffL, "%", ""))
if sDecimal.LessThan(testQuantityDiffLDecimal) || testQuantityDiffHDecimal.LessThan(sDecimal) {
_ = file.SetCellStyle(sheetName, "Q"+strconv.Itoa(ftRecordIndex), "Q"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
passQuantityDiffStr := strings.ReplaceAll(passQuantityDiff, "%", "")
saDecimal, _ := decimal.NewFromString(passQuantityDiffStr)
passQuantityDiffHDecimal, _ := decimal.NewFromString(strings.ReplaceAll(productionControl.PassQuantityDiffH, "%", ""))
passQuantityDiffLDecimal, _ := decimal.NewFromString(strings.ReplaceAll(productionControl.PassQuantityDiffL, "%", ""))
if saDecimal.LessThan(passQuantityDiffLDecimal) || passQuantityDiffHDecimal.LessThan(saDecimal) {
_ = file.SetCellStyle(sheetName, "R"+strconv.Itoa(ftRecordIndex), "R"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
break
}
}
if hardBinState == "异常" {
_ = file.SetCellStyle(sheetName, "S"+strconv.Itoa(ftRecordIndex), "S"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
if siteDiffState == "异常" {
_ = file.SetCellStyle(sheetName, "T"+strconv.Itoa(ftRecordIndex), "T"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
if stackingMaterials == "是" {
_ = file.SetCellStyle(sheetName, "U"+strconv.Itoa(ftRecordIndex), "U"+strconv.Itoa(ftRecordIndex), ExportWarningStyle(file))
}
if len(finalReports) > 0 {
ExportFTDetailsSheet(finalReports, file, warning.BinControl)
}
if warning != nil {
ExportFTHistogramSheet(warning, ftList, file)
ExportFTScatterSheet(warning, ftList, file)
}
ftRecordIndex++
}
_ = file.SetRowStyle(sheetName, 2, ftRecordIndex, NormalSheetStyle(file))
_ = file.SetColWidth(sheetName, "A", "U", 20)
//ExportFTSumSheet(exportFTs, file)
file.DeleteSheet("Sheet1")
filePath := time.Now().Format("FT自动导出_2006-01-02_150405.xlsx")
filePath = filepath.Join(utils.MakeSavePath("自动导出"), filePath)
file.SaveAs(filePath)
defer file.Close()
return strings.ReplaceAll(viper.GetString("domain"), "\\", "/") + filePath
}
func ExportFTSumSheet(exportFTs []*model.ExportFT, f *excelize.File) {
sheetName := "FT记录总表"
_, _ = f.NewSheet(sheetName)
_ = f.SetSheetRow(sheetName, "A1", &[]interface{}{"成品型号", "晶圆批次", "PBI", "测试厂", "测试程序", "下单日期",
"丝印", "结批测试数量", "结批良品数量", "结批良率", "初测良品数量", "初测良率", "测试数量", "良品数量", "测试良率",
"回收率", "测试数量差异", "良品数量差异", "硬件bin", "SITE差异", "叠料风险",
})
_ = f.SetCellStyle(sheetName, "A1", "U1", ExportFTSheetTitleStyle(f))
for index, exportFT := range exportFTs {
_ = f.SetSheetRow(sheetName, "A"+strconv.Itoa(index+2), &[]interface{}{exportFT.Product, exportFT.Lot,
exportFT.PBI, exportFT.Factory, exportFT.TestProgram, exportFT.OrderDate, exportFT.Seal, exportFT.FinalTestQuantity,
exportFT.FinalPassQuantity, exportFT.FinalPassProbability, exportFT.FirstPassQuantity, exportFT.FirstPassProbability,
exportFT.TestQuantity, exportFT.PassQuantity, exportFT.PassProbability, exportFT.ReturnProbability,
exportFT.TestQuantityDiff, exportFT.PassQuantityDiff, exportFT.HardBinState, exportFT.SiteDiffState,
exportFT.StackingMaterials})
}
_ = f.SetRowStyle(sheetName, 2, len(exportFTs)+1, NormalSheetStyle(f))
_ = f.SetColWidth(sheetName, "A", "U", 20)
}
func ExportFTDetailsSheet(finalReports []*model.FinalReport, f *excelize.File, binControls []model.BinControl) {
sheetName := "FT记录BIN表"
_, _ = f.NewSheet(sheetName)
_ = f.SetSheetRow(sheetName, "A1", &[]interface{}{"成品型号", "晶圆批次", "PBI", "测试厂", "测试程序", "下单日期", "丝印",
"子批", "结批测试数量", "结批良品数量", "结批良率", "BIN1", "BIN2", "BIN3", "BIN4", "BIN5", "BIN6", "BIN7", "BIN8", "BIN9",
"BIN10", "外观不良", "少数", "弯脚", "报废",
})
_ = f.SetCellStyle(sheetName, "A1", "Y1", ExportFTSheetTitleStyle(f))
for index, finalReport := range finalReports {
for _, binControl := range binControls {
var bin string
binControl.Bin = strings.ToUpper(binControl.Bin)
if binControl.Bin == "BIN1" {
bin = finalReport.Bin1
} else if binControl.Bin == "BIN2" {
bin = finalReport.Bin2
} else if binControl.Bin == "BIN3" {
bin = finalReport.Bin3
} else if binControl.Bin == "BIN4" {
bin = finalReport.Bin4
} else if binControl.Bin == "BIN5" {
bin = finalReport.Bin5
} else if binControl.Bin == "BIN6" {
bin = finalReport.Bin6
} else if binControl.Bin == "BIN7" {
bin = finalReport.Bin7
} else if binControl.Bin == "BIN8" {
bin = finalReport.Bin8
} else if binControl.Bin == "BIN9" {
bin = finalReport.Bin9
} else if binControl.Bin == "BIN10" {
bin = finalReport.Bin10
}
if binControl.BinFailLimitH != "" {
s := strings.ReplaceAll(bin, "%", "")
sDecimal, _ := decimal.NewFromString(s)
binFailLimitHDecimal, _ := decimal.NewFromString(strings.ReplaceAll(binControl.BinFailLimitH, "%", ""))
if binFailLimitHDecimal.LessThan(sDecimal) {
_ = f.SetCellStyle(sheetName, "L"+strconv.Itoa(index+2), "L"+strconv.Itoa(index+2), ExportWarningStyle(f))
}
}
}
_ = f.SetSheetRow(sheetName, "A"+strconv.Itoa(index+2), &[]interface{}{finalReport.Product, finalReport.Lot,
finalReport.PBI, finalReport.Factory, finalReport.TestProgram, finalReport.OrderDate, finalReport.Seal,
finalReport.SubBatch, finalReport.ReportTestQuantity, finalReport.ReportPassQuantity, finalReport.ReportPassProbability,
finalReport.Bin1, finalReport.Bin2, finalReport.Bin3, finalReport.Bin4, finalReport.Bin5, finalReport.Bin6,
finalReport.Bin7, finalReport.Bin8, finalReport.Bin9, finalReport.Bin10, finalReport.OutlookFail,
finalReport.Other, finalReport.BentStitch, finalReport.Scrapped})
}
_ = f.SetRowStyle(sheetName, 2, len(finalReports)+1, NormalSheetStyle(f))
_ = f.SetColWidth(sheetName, "A", "Y", 20)
}
func ExportFTHistogramSheet(warning *model.Warning, ftList *model.FTList, f *excelize.File) {
row := 1
start := row
selectionUnit := make(map[string]string)
subBatchDiff := make(map[string][]float64)
sheetName := ftList.Lot + "汇总表"
f.NewSheet(sheetName)
var groups []string
global.PostGreSQL.Model(&model.FileHandled{}).Where("product = ? AND lot = ? AND pbi = ?",
ftList.Product, ftList.Lot, ftList.PBI).Group("sub_batch").Select("sub_batch").Find(&groups)
for _, group := range groups {
var fileHandle *model.FileHandled
global.PostGreSQL.Where("product = ? AND lot = ? AND pbi = ? AND sub_batch = ?",
ftList.Product, ftList.Lot, ftList.PBI, group).Find(&fileHandle)
m := make(map[string]map[string]string)
_ = json.Unmarshal([]byte(fileHandle.TitleInfo), &m)
siteSelectionInfo := make(map[string][]float64)
selectionInfo := make(map[string][]float64)
var datas [][]string
fieldMap := make(map[string]int)
datas, fieldMap = LotInAFile(ftList.Product, ftList.Lot, ftList.PBI, group, "", "FT")
group = strings.ReplaceAll(group, "-", "_")
if len(datas) == 0 {
continue
}
for _, data := range datas {
for _, histogramSelection := range warning.HistogramSelection {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[histogramSelection.Selection]])
selectionFloat, _ := selectionDecimal.Float64()
var filed string
filed = histogramSelection.Selection
if _, ok := siteSelectionInfo[filed]; !ok {
siteSelectionInfo[filed] = []float64{math.MaxInt, math.MinInt, 0, 0}
}
if siteSelectionInfo[filed][0] > selectionFloat {
siteSelectionInfo[filed][0] = selectionFloat
}
if siteSelectionInfo[filed][1] < selectionFloat {
siteSelectionInfo[filed][1] = selectionFloat
}
siteSelectionInfo[filed][2] += selectionFloat
siteSelectionInfo[filed][3]++
if _, ok := selectionInfo[histogramSelection.Selection]; !ok {
selectionInfo[histogramSelection.Selection] = []float64{math.MaxInt, math.MinInt, 0, 0}
}
if selectionInfo[histogramSelection.Selection][0] > selectionFloat {
selectionInfo[histogramSelection.Selection][0] = selectionFloat
}
if selectionInfo[histogramSelection.Selection][1] < selectionFloat {
selectionInfo[histogramSelection.Selection][1] = selectionFloat
}
selectionInfo[histogramSelection.Selection][2] += selectionFloat
selectionInfo[histogramSelection.Selection][3]++
}
}
selectionHistogramX := make(map[string][]string)
selectionHistogramY := make(map[string][]int)
for k, v := range siteSelectionInfo {
siteSelectionInfo[k] = []float64{v[0], v[1], v[2], v[3], v[2] / v[3], 0, 0}
}
for k, v := range selectionInfo {
selectionInfo[k] = []float64{v[0], v[1], v[2], v[3], v[2] / v[3], 0, 0}
selectionHistogramX[group+"_"+k] = []string{}
minDecimal := decimal.NewFromFloat(v[0])
if minDecimal.LessThan(decimal.NewFromInt(0)) {
minDecimal = minDecimal.RoundUp(0)
} else {
minDecimal = minDecimal.RoundDown(0)
}
maxDecimal := decimal.NewFromFloat(v[1])
if maxDecimal.LessThan(decimal.NewFromInt(0)) {
maxDecimal = maxDecimal.RoundDown(0)
} else {
maxDecimal = maxDecimal.RoundUp(0)
}
interval := maxDecimal.Sub(minDecimal).Div(decimal.NewFromInt(20))
for i := 0; i < 21; i++ {
xPoint := minDecimal.Add(interval.Mul(decimal.NewFromInt(int64(i)))).String()
selectionHistogramX[group+"_"+k] = append(selectionHistogramX[group+"_"+k], xPoint)
}
}
for _, data := range datas {
for k, v := range siteSelectionInfo {
var field string
field = k
if data[fieldMap[field]] != "" {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[field]])
averageDecimal := decimal.NewFromFloat(v[4])
d, _ := averageDecimal.Sub(selectionDecimal).Pow(decimal.NewFromInt(2)).
Float64()
v[5] += d
v[6]++
}
}
for k, v := range selectionInfo {
if data[fieldMap[k]] != "" {
selectionDecimal, _ := decimal.NewFromString(data[fieldMap[k]])
averageDecimal := decimal.NewFromFloat(v[4])
d, _ := averageDecimal.Sub(selectionDecimal).Pow(decimal.NewFromInt(2)).
Float64()
field := group + "_" + k
for i := 0; i < len(selectionHistogramX[field]); i++ {
if i == len(selectionHistogramX[field])-1 {
xPointDecimal, _ := decimal.NewFromString(selectionHistogramX[field][i])
if xPointDecimal.Equals(selectionDecimal) {
selectionHistogramY[field][i]++
}
break
}
xPointMin, _ := decimal.NewFromString(selectionHistogramX[field][i])
xPointMax, _ := decimal.NewFromString(selectionHistogramX[field][i+1])
if _, ok := selectionHistogramY[field]; !ok {
selectionHistogramY[field] = make([]int, len(selectionHistogramX[field]))
}
if xPointMin.LessThanOrEqual(selectionDecimal) && selectionDecimal.LessThan(xPointMax) {
selectionHistogramY[field][i]++
}
}
v[5] += d
v[6]++
}
}
}
rowIndex, colIndex := 2, 1
histogramSheetName := ftList.Lot + "_" + group + "直方图"
f.NewSheet(histogramSheetName)
selectionValueMap := make(map[string][]int)
for k, v := range selectionHistogramX {
sheetX := []interface{}{k}
for _, x := range v {
sheetX = append(sheetX, x)
}
sheetY := []interface{}{"数量"}
for _, y := range selectionHistogramY[k] {
sheetY = append(sheetY, y)
}
for idx, rows := range [][]interface{}{
sheetX,
sheetY,
} {
cell, err := excelize.CoordinatesToCellName(colIndex, rowIndex+idx)
if err != nil {
fmt.Println(err)
}
if err = f.SetSheetRow(histogramSheetName, cell, &rows); err != nil {
fmt.Println(err)
}
}
selectionValueMap[k] = []int{rowIndex, len(selectionHistogramY[k]) + 1}
rowIndex += 2
}
a := 1
for _, histogramSelection := range warning.HistogramSelection {
b := 1
for k, v := range selectionValueMap {
if strings.Contains(k, histogramSelection.Selection) {
if err := f.AddChart(histogramSheetName, utils.NumToRow(strconv.Itoa(b))+strconv.Itoa(a), &excelize.Chart{
Type: excelize.Col,
Series: []excelize.ChartSeries{
{
Name: histogramSheetName + "!$A$1",
Categories: histogramSheetName + "!$B$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: histogramSheetName + "!$B$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "none", Size: 10,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "left",
},
Title: []excelize.RichTextRun{
{
Text: k,
},
},
PlotArea: excelize.ChartPlotArea{
ShowCatName: false,
ShowLeaderLines: false,
ShowVal: true,
},
ShowBlanksAs: "zero",
}, &excelize.Chart{
Type: excelize.Line,
Series: []excelize.ChartSeries{
{
Name: group + "!$A$1",
Categories: group + "!$B$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: group + "!$B$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "none", Size: 10,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "right",
},
PlotArea: excelize.ChartPlotArea{
ShowCatName: false,
ShowLeaderLines: false,
},
}); err != nil {
fmt.Println(err)
}
b += 9
}
}
a += 20
}
col := 1
_ = f.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"子批:" + group})
_ = f.SetSheetCol(sheetName, "A"+strconv.Itoa(start+1), &[]interface{}{
"", "最小值", "最大值", "平均值", "δ", "数量", "Limit L", "Limit H", "UNIT"})
col++
var selectionInfoArray []SelectionInfo
for _, histogramSelection := range warning.HistogramSelection {
var oneSelectionInfo []SelectionInfo
for k, v := range siteSelectionInfo {
if !strings.Contains(k, histogramSelection.Selection) {
continue
}
oneSelectionInfo = append(oneSelectionInfo, SelectionInfo{
Field: k,
Min: v[0],
Max: v[1],
Average: v[4],
StandardDeviation: math.Sqrt(v[5] / v[6]),
Num: v[3],
})
}
sort.Slice(oneSelectionInfo, func(i, j int) bool {
return oneSelectionInfo[i].Field < oneSelectionInfo[j].Field
})
selectionInfoArray = append(selectionInfoArray, oneSelectionInfo...)
}
for _, v := range selectionInfoArray {
field := strings.Split(v.Field, "_Site")[0]
limitLDecimal, _ := decimal.NewFromString(m[field]["LimitL"])
limitLFloat, _ := limitLDecimal.Float64()
limitUDecimal, _ := decimal.NewFromString(m[field]["LimitU"])
limitUFloat, _ := limitUDecimal.Float64()
selectionUnit[field] = m[field]["Unit"]
_ = f.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start+1), &[]interface{}{
v.Field, v.Min, v.Max, v.Average, v.StandardDeviation, v.Num, limitLFloat, limitUFloat, m[field]["Unit"]})
col++
}
for k, v := range selectionInfo {
if _, ok := subBatchDiff[k]; !ok {
subBatchDiff[k] = []float64{v[4], v[4], v[5] / v[6], v[5] / v[6]}
selectionUnit[k] = m[k]["Unit"]
} else {
if v[4] > subBatchDiff[k][0] {
subBatchDiff[k][0] = v[4]
}
if v[4] < subBatchDiff[k][1] {
subBatchDiff[k][1] = v[4]
}
if v[5]/v[6] > subBatchDiff[k][2] {
subBatchDiff[k][2] = v[5] / v[6]
}
if v[5]/v[6] < subBatchDiff[k][3] {
subBatchDiff[k][3] = v[5] / v[6]
}
}
}
_ = f.MergeCell(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
NormalSheetStyle(f))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+1),
TitleStyle(f))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start+2), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+6),
ActualLimitStyle(f))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start+7), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+9),
LimitStyle(f))
_ = f.SetColWidth(sheetName, "A", utils.NumToRow(strconv.Itoa(col-1)),
20)
start += 10
start += 1
}
start += 1
col := 2
_ = f.SetSheetCol(sheetName, "A"+strconv.Itoa(start), &[]interface{}{
"批次差异汇总"})
_ = f.SetSheetCol(sheetName, "A"+strconv.Itoa(start+1), &[]interface{}{
"", "平均值", "δ", "UNIT"})
for _, histogramSelection := range warning.HistogramSelection {
if len(subBatchDiff[histogramSelection.Selection]) != 0 {
_ = f.SetSheetCol(sheetName, utils.NumToRow(strconv.Itoa(col))+strconv.Itoa(start+1), &[]interface{}{
histogramSelection.Selection, subBatchDiff[histogramSelection.Selection][0] - subBatchDiff[histogramSelection.Selection][1],
subBatchDiff[histogramSelection.Selection][2] - subBatchDiff[histogramSelection.Selection][3],
selectionUnit[histogramSelection.Selection]})
col++
}
}
_ = f.MergeCell(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start),
NormalSheetStyle(f))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start+1), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+1),
TitleStyle(f))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start+2), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+3),
ActualLimitStyle(f))
_ = f.SetCellStyle(sheetName, "A"+strconv.Itoa(start+4), utils.NumToRow(strconv.Itoa(col-1))+strconv.Itoa(start+4),
LimitStyle(f))
}
func ExportFTScatterSheet(warning *model.Warning, ftList *model.FTList, f *excelize.File) {
var groups []string
global.PostGreSQL.Model(&model.FileHandled{}).Where("product = ? AND lot = ? AND pbi = ?",
ftList.Product, ftList.Lot, ftList.PBI).Group("sub_batch").Select("sub_batch").Find(&groups)
for _, group := range groups {
var datas [][]string
fieldMap := make(map[string]int)
datas, fieldMap = LotInAFile(ftList.Product, ftList.Lot, ftList.PBI, group, "", "FT")
if len(datas) == 0 {
continue
}
group = strings.ReplaceAll(group, "-", "_")
selectionPointsMap := make(map[string]map[string]int)
for _, data := range datas {
for _, scatterSelection := range warning.ScatterSelection {
var field string
field = scatterSelection.XSelection + "," + scatterSelection.YSelection
if _, ok := selectionPointsMap[field]; !ok {
selectionPointsMap[field] = map[string]int{}
}
selectionPointsMap[field][data[fieldMap[scatterSelection.XSelection]]+","+data[fieldMap[scatterSelection.YSelection]]]++
}
}
sheetName := ftList.Lot + "_" + group + "散点图"
f.NewSheet(sheetName)
selectionValueMap := make(map[string][]int)
rowIndex := 1
for _, scatterSelection := range warning.ScatterSelection {
for k := range selectionPointsMap {
if strings.Contains(k, scatterSelection.XSelection+","+scatterSelection.YSelection) {
sheetX := []interface{}{k, scatterSelection.XSelection}
sheetY := []interface{}{"", scatterSelection.YSelection}
for point := range selectionPointsMap[k] {
pointXY := strings.Split(point, ",")
xDecimal, _ := decimal.NewFromString(pointXY[0])
x, _ := xDecimal.Float64()
yDecimal, _ := decimal.NewFromString(pointXY[1])
y, _ := yDecimal.Float64()
sheetX = append(sheetX, x)
sheetY = append(sheetY, y)
}
for idx, row := range [][]interface{}{
sheetX,
sheetY,
} {
cell, err := excelize.CoordinatesToCellName(1, rowIndex+idx)
if err != nil {
fmt.Println(err)
}
if err = f.SetSheetRow(sheetName, cell, &row); err != nil {
fmt.Println(err)
}
}
selectionValueMap[k] = []int{rowIndex, len(sheetY) + 1}
rowIndex += 2
}
}
}
a := 1
for _, scatterSelection := range warning.ScatterSelection {
b := 1
for k, v := range selectionValueMap {
if strings.Contains(k, scatterSelection.XSelection+","+scatterSelection.YSelection) {
if err := f.AddChart(sheetName, utils.NumToRow(strconv.Itoa(b))+strconv.Itoa(a), &excelize.Chart{
Type: excelize.Scatter,
Series: []excelize.ChartSeries{
{
Name: sheetName + "!$A$1",
Categories: sheetName + "!$C$" + strconv.Itoa(v[0]) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]),
Values: sheetName + "!$C$" + strconv.Itoa(v[0]+1) + ":$" +
utils.NumToRow(strconv.Itoa(v[1])) + "$" + strconv.Itoa(v[0]+1),
Marker: excelize.ChartMarker{
Symbol: "circle", Size: 1,
},
},
},
Format: excelize.GraphicOptions{
ScaleX: 1,
ScaleY: 1,
OffsetX: 15,
OffsetY: 10,
},
Legend: excelize.ChartLegend{
Position: "bottom",
},
Title: []excelize.RichTextRun{
{
Text: k,
},
},
//PlotArea: excelize.ChartPlotArea{
// ShowCatName: false,
// ShowLeaderLines: false,
//},
ShowBlanksAs: "zero",
}); err != nil {
fmt.Println(err)
}
b += 9
}
}
a += 20
}
}
}