animeic 2 years ago
parent
commit
ab89a94285

+ 328 - 228
boxcost/api/plan-cost-excel.go

@@ -4,36 +4,28 @@ import (
 	"fmt"
 
 	"github.com/xuri/excelize/v2"
-	"go.mongodb.org/mongo-driver/bson/primitive"
 )
 
 // 生产成本表
 type PlanCostExcel struct {
-	Offset int
-	Row    int
-
-	Title string //标题
-
-	Excel *excelize.File
-
-	SheetName string
-
+	Row              int
+	Title            string
+	Excel            *excelize.File
+	SheetName        string
 	AlignCenterStyle int
-
-	Content *SupplierPlanCost
+	Content          *SupplierPlanSummary
 }
 
 func (b *PlanCostExcel) drawTitle() error {
-	// tileIndex := b.Offset + 1
 	b.Row++
 	startCell := fmt.Sprintf("A%d", b.Row)
-	err := b.Excel.MergeCell(b.SheetName, startCell, fmt.Sprintf("N%d", b.Row))
+	err := b.Excel.MergeCell(b.SheetName, startCell, fmt.Sprintf("O%d", b.Row))
 	if err != nil {
 		return err
 	}
 
 	style, err := b.Excel.NewStyle(&excelize.Style{
-		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
 		Font:      &excelize.Font{Bold: true, Size: 18}})
 	if err != nil {
 		return err
@@ -48,11 +40,7 @@ func (b *PlanCostExcel) drawTitle() error {
 }
 
 func (b *PlanCostExcel) drawTableTitle() error {
-	// row := b.Offset + 2
 	b.Row++
-
-	//A采购项目 B规格(克) 尺寸C-D 数量E 单价F-G 交货时间H 备注I
-	// A产品名称
 	var drawCol = func(prefix string, value string) error {
 		left1Cell := fmt.Sprintf("%s%d", prefix, b.Row)
 		left2Cell := fmt.Sprintf("%s%d", prefix, b.Row+1)
@@ -97,7 +85,6 @@ func (b *PlanCostExcel) drawTableTitle() error {
 	}
 	var drawCol3 = func(prefix1 string, prefix2 string, prefix3 string, value1 string, value2 string, value3 string, value4 string) error {
 		left1Cell := fmt.Sprintf("%s%d", prefix1, b.Row)
-		// left2Cell := fmt.Sprintf("%s%d", prefix2, row)
 		left3Cell := fmt.Sprintf("%s%d", prefix3, b.Row)
 		err := b.Excel.MergeCell(b.SheetName, left1Cell, left3Cell)
 		if err != nil {
@@ -127,284 +114,398 @@ func (b *PlanCostExcel) drawTableTitle() error {
 		return nil
 	}
 
+	drawCol("A", "产品名称")
 	drawCol("A", "产品部件名称")
 	drawCol2("B", "C", "类型/项目", "类型", "项目")
-	drawCol("D", "供应商名称")
-	drawCol("E", "单价1")
-	drawCol3("F", "G", "H", "规格", "厚度(纸克)", "长", "宽")
-	drawCol("I", "单位")
-	drawCol("J", "下单数量")
-	drawCol("K", "实际数量")
-	drawCol("L", "单价") // ??? 下单单价
-	drawCol("M", "预算金额")
-	drawCol("N", "实际金额")
+	drawCol("D", "下单数量")
+	drawCol("E", "实际数量")
+	drawCol("F", "状态") // 生成订单状态 审核状态 发送状态 完成状态
+	drawCol("G", "供应商名称")
+	drawCol("H", "单价")
+	drawCol3("I", "J", "K", "规格", "厚度(纸克)", "长", "宽")
+	drawCol("L", "单位")
+	drawCol("M", "下单单价")
+	drawCol("N", "预算金额")
+	drawCol("O", "实际金额")
 	return nil
 }
 
 func (b *PlanCostExcel) drawRow(rowIndex int, values ...string) {
-	charas := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"}
+	charas := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"}
 	for i, c := range charas {
 		v := ""
 		if i < len(values) {
 			v = values[i]
 		}
 		b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("%s%d", c, rowIndex), v)
-
 		val2Cel := fmt.Sprintf("%s%d", c, rowIndex)
 		b.Excel.SetCellStyle(b.SheetName, val2Cel, val2Cel, b.AlignCenterStyle)
-
-		b.Excel.SetRowHeight(b.SheetName, rowIndex, 21)
+		b.Excel.SetRowHeight(b.SheetName, rowIndex, 32)
 	}
 
 }
 
-func (b *PlanCostExcel) drawSupplierContent() error {
+func (b *PlanCostExcel) drawAllContent() error {
 	b.Row += 2
-	supplierId, err := primitive.ObjectIDFromHex(b.Content.SupplierId)
-	if err != nil {
-		return err
-	}
-	supplier := ""
-	comps := b.Content.Pack.Components
+
+	// summaryPlans
 	// 预算金额汇总
 	var totalBudgetPrice float64 = 0.00
 	// 实际金额汇总
 	var totalRealPrice float64 = 0.00
-	if len(comps) > 0 {
-		for _, comp := range comps {
-			var perBudgetPrice float64 = 0.00
-			var perRealPrice float64 = 0.00
-
-			if len(comp.Stages) > 0 {
-				startRow := 0
-				cates := map[string][]int{}
-				for _, stage := range comp.Stages {
-					if stage.SupplierInfo != nil {
-						if supplierId == stage.SupplierInfo.Id {
-							supplier = stage.SupplierInfo.Name
-							// 材料
-							if startRow == 0 {
-								startRow = b.Row
 
-							}
+	for _, splan := range b.Content.Plans {
+		plan := splan.Plan
+		comps := plan.Pack.Components
+		// 预算金额汇总
+		var planBudgetPrice float64 = 0.00
+		// 实际金额汇总
+		var planRealPrice float64 = 0.00
+		if len(comps) > 0 {
+			for _, comp := range comps {
+				var perBudgetPrice float64 = 0.00
+				var perRealPrice float64 = 0.00
+				if len(comp.Stages) > 0 {
+					startRow := b.Row
+					cates := map[string][]int{}
+					for _, stage := range comp.Stages {
+						matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
+						b.FormatToEmpty(&matHeigth)
+						matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
+						b.FormatToEmpty(&matWidth)
+						orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
+						b.FormatToEmpty(&orderCount)
+
+						// 实际数量
+						realCount := fmt.Sprintf("%d", stage.ConfirmCount)
+						b.FormatToEmpty(&realCount)
+						// 单价
+						price := fmt.Sprintf("%.3f", stage.OrderPrice)
+						b.FormatToEmpty(&price)
+						// 预算金额
+						budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
+						perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
+						b.FormatToEmpty(&budgetPrice)
+						// 实际金额
+						perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
+						realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
+						b.FormatToEmpty(&realPrice)
+						unit := stage.Unit
+						if stage.Unit == "吨" || stage.Unit == "平方米" {
+							unit = "张"
+						}
 
-							matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
-							b.FormatToEmpty(&matHeigth)
-							matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
-							b.FormatToEmpty(&matWidth)
-							orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
-							b.FormatToEmpty(&orderCount)
-
-							// 实际数量
-							realCount := fmt.Sprintf("%d", stage.ConfirmCount)
-							b.FormatToEmpty(&realCount)
-							// 单价
-							price := fmt.Sprintf("%.3f", stage.OrderPrice)
-							b.FormatToEmpty(&price)
-							// 预算金额
-							budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
-							perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
-							b.FormatToEmpty(&budgetPrice)
-							// 实际金额
-							perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
-							realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
-							b.FormatToEmpty(&realPrice)
-							unit := stage.Unit
-							if stage.Unit == "吨" || stage.Unit == "平方米" {
-								unit = "张"
-							}
+						supplierName := ""
+						if stage.SupplierInfo != nil {
+							supplierName = stage.SupplierInfo.Name
+						}
+						stageType := ""
+						if stage.BillType > 0 {
+							stage.Type = stage.BillType
+						}
+						if stage.Type == 1 {
+							stageType = "材料采购"
+						}
+						if stage.Type == 2 {
+							stageType = "工艺"
+						}
+						if stage.Type == 3 {
+							stageType = "成品采购"
+						}
 
-							// 生成单据时已billType为准
-							stageType := ""
-							if stage.BillType > 0 {
-								stage.Type = stage.BillType
-							}
-							if stage.Type == 1 {
-								stageType = "材料采购"
-							}
-							if stage.Type == 2 {
-								stageType = "工艺"
+						// 状态
+						stop := false
+						stageStatus := ""
+						if len(stage.BillId) < 1 {
+							stageStatus = "未生成订单"
+							stop = true
+						}
+						// 审核状态
+						if !stop {
+							if splan.Reviewed[stage.BillId] == 1 {
+								stageStatus = "已审核"
+							} else {
+								stageStatus = "未审核"
+								stop = true
 							}
-							if stage.Type == 3 {
-								stageType = "成品采购"
+
+						}
+
+						// 接单状态
+						if !stop {
+							if splan.IsAck[stage.BillId] {
+								stageStatus = "已接单"
+							} else {
+								stageStatus = "未接单"
+								stop = true
 							}
-							b.drawRow(b.Row, "", stageType, stage.Name, "", fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, orderCount, realCount, price, budgetPrice, realPrice)
+
+						}
+
+						// 完成状态
+						if splan.State[stage.BillId] == "complete" {
+							stageStatus = "已完成"
+						} else if splan.State[stage.BillId] == "created" {
+							stageStatus = "进行中"
+						}
+
+						b.drawRow(b.Row, "", stageType, stage.Name, orderCount, realCount, stageStatus, supplierName, fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, price, budgetPrice, realPrice)
+						if stage.SupplierInfo != nil {
 							cates[stage.SupplierInfo.Name] = append(cates[stage.SupplierInfo.Name], b.Row)
-							b.Row++
+
 						}
+						b.Row++
+					}
 
+					for supplierName, cate := range cates {
+						mergeStartRow := cate[0]
+						mergeEndRow := cate[len(cate)-1]
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("G%d", mergeStartRow), fmt.Sprintf("G%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("G%d", mergeEndRow), supplierName)
 					}
-				}
 
-				// 合并同一供应商名
-				for supplierName, cate := range cates {
-					mergeStartRow := cate[0]
-					mergeEndRow := cate[len(cate)-1]
-					b.Excel.MergeCell(b.SheetName, fmt.Sprintf("D%d", mergeStartRow), fmt.Sprintf("D%d", mergeEndRow))
-					b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("D%d", mergeEndRow), supplierName)
-				}
-				if startRow != 0 {
 					endRow := b.Row - 1
 					// 组件名字
 					startACell := fmt.Sprintf("%s%d", "A", startRow)
 					endACell := fmt.Sprintf("%s%d", "A", endRow)
 					b.Excel.MergeCell(b.SheetName, startACell, endACell)
-
 					err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
 					if err != nil {
 						return err
 					}
 					b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
-
 				}
 
+				// 预算
+				planBudgetPrice += perBudgetPrice
+				// 实际金额
+				planRealPrice += perRealPrice
 			}
-			// 预算
-			totalBudgetPrice += perBudgetPrice
-			// 预算
-			totalRealPrice += perRealPrice
 		}
+		totalBudgetPrice += planBudgetPrice
+		totalRealPrice += planRealPrice
 
 	}
 
-	// 生产汇总金额
-	startACell := fmt.Sprintf("%s%d", "A", b.Row)
-	endLCell := fmt.Sprintf("%s%d", "L", b.Row)
-	MCell := fmt.Sprintf("%s%d", "M", b.Row)
-	NCell := fmt.Sprintf("%s%d", "N", b.Row)
-	b.Excel.MergeCell(b.SheetName, startACell, endLCell)
-	b.Excel.SetCellStyle(b.SheetName, startACell, endLCell, b.AlignCenterStyle)
-	b.Excel.SetCellValue(b.SheetName, startACell, fmt.Sprintf("【%s】生产计划汇总金额", supplier))
+	summaryEndRow := b.Row
+	startACell := fmt.Sprintf("%s%d", "A", summaryEndRow)
+	endMell := fmt.Sprintf("%s%d", "M", summaryEndRow)
+	NCell := fmt.Sprintf("%s%d", "N", summaryEndRow)
+	OCell := fmt.Sprintf("%s%d", "O", summaryEndRow)
+	b.Excel.MergeCell(b.SheetName, startACell, endMell)
+	b.Excel.SetCellStyle(b.SheetName, startACell, endMell, b.AlignCenterStyle)
+	b.Excel.SetCellValue(b.SheetName, startACell, "生产计划汇总金额")
 
 	// 生产预算汇总
-	b.Excel.SetCellStyle(b.SheetName, MCell, MCell, b.AlignCenterStyle)
-	planOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
-	b.FormatToEmpty(&planOrderRealPrice)
-	b.Excel.SetCellValue(b.SheetName, MCell, planOrderRealPrice)
 
-	// 生产实际汇总
 	b.Excel.SetCellStyle(b.SheetName, NCell, NCell, b.AlignCenterStyle)
-	planRealPrice := fmt.Sprintf("%.3f", totalRealPrice)
-	b.FormatToEmpty(&planRealPrice)
-	b.Excel.SetCellValue(b.SheetName, NCell, planRealPrice)
+	totalOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
+	b.FormatToEmpty(&totalOrderRealPrice)
+	b.Excel.SetCellValue(b.SheetName, NCell, totalOrderRealPrice)
+
+	// 生产实际汇总
+	b.Excel.SetCellStyle(b.SheetName, OCell, OCell, b.AlignCenterStyle)
+	totalRealPricef := fmt.Sprintf("%.3f", totalRealPrice)
+	b.FormatToEmpty(&totalRealPricef)
+	b.Excel.SetCellValue(b.SheetName, OCell, totalRealPricef)
 
 	return nil
 }
 
-// type merge
-
-func (b *PlanCostExcel) drawAllContent() error {
+func (b *PlanCostExcel) drawSupplierContent() error {
 	b.Row += 2
-	comps := b.Content.Pack.Components
+	supplier := ""
+	// summaryPlans
 	// 预算金额汇总
 	var totalBudgetPrice float64 = 0.00
 	// 实际金额汇总
 	var totalRealPrice float64 = 0.00
-	if len(comps) > 0 {
-		for _, comp := range comps {
-			var perBudgetPrice float64 = 0.00
-			var perRealPrice float64 = 0.00
-			if len(comp.Stages) > 0 {
-				startRow := b.Row
-				cates := map[string][]int{}
-				for _, stage := range comp.Stages {
-					matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
-					b.FormatToEmpty(&matHeigth)
-					matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
-					b.FormatToEmpty(&matWidth)
-					orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
-					b.FormatToEmpty(&orderCount)
-
-					// 实际数量
-					realCount := fmt.Sprintf("%d", stage.ConfirmCount)
-					b.FormatToEmpty(&realCount)
-					// 单价
-					price := fmt.Sprintf("%.3f", stage.OrderPrice)
-					b.FormatToEmpty(&price)
-					// 预算金额
-					budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
-					perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
-					b.FormatToEmpty(&budgetPrice)
-					// 实际金额
-					perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
-					realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
-					b.FormatToEmpty(&realPrice)
-					unit := stage.Unit
-					if stage.Unit == "吨" || stage.Unit == "平方米" {
-						unit = "张"
-					}
 
-					supplierName := ""
-					if stage.SupplierInfo != nil {
-						supplierName = stage.SupplierInfo.Name
-					}
-					stageType := ""
-					if stage.BillType > 0 {
-						stage.Type = stage.BillType
-					}
-					if stage.Type == 1 {
-						stageType = "材料采购"
-					}
-					if stage.Type == 2 {
-						stageType = "工艺"
-					}
-					if stage.Type == 3 {
-						stageType = "成品采购"
-					}
-					b.drawRow(b.Row, "", stageType, stage.Name, supplierName, fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, orderCount, realCount, price, budgetPrice, realPrice)
-					if stage.SupplierInfo != nil {
-						cates[stage.SupplierInfo.Name] = append(cates[stage.SupplierInfo.Name], b.Row)
+	for _, splan := range b.Content.Plans {
+		plan := splan.Plan
+		comps := plan.Pack.Components
+		// 预算金额汇总
+		var planBudgetPrice float64 = 0.00
+		// 实际金额汇总
+		var planRealPrice float64 = 0.00
+		if len(comps) > 0 {
+			for _, comp := range comps {
+				var perBudgetPrice float64 = 0.00
+				var perRealPrice float64 = 0.00
+				if len(comp.Stages) > 0 {
+					startRow := 0
+					cates := map[string][]int{}
+					for _, stage := range comp.Stages {
+						if stage.SupplierInfo != nil {
+							if b.Content.SupplierId == stage.SupplierInfo.Id {
+								supplier = stage.SupplierInfo.Name
+								// 材料
+								if startRow == 0 {
+									startRow = b.Row
+
+								}
+
+								matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
+								b.FormatToEmpty(&matHeigth)
+								matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
+								b.FormatToEmpty(&matWidth)
+								orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
+								b.FormatToEmpty(&orderCount)
+
+								// 实际数量
+								realCount := fmt.Sprintf("%d", stage.ConfirmCount)
+								b.FormatToEmpty(&realCount)
+								// 单价
+								price := fmt.Sprintf("%.3f", stage.OrderPrice)
+								b.FormatToEmpty(&price)
+								// 预算金额
+								budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
+								perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
+								b.FormatToEmpty(&budgetPrice)
+								// 实际金额
+								perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
+								realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
+								b.FormatToEmpty(&realPrice)
+								unit := stage.Unit
+								if stage.Unit == "吨" || stage.Unit == "平方米" {
+									unit = "张"
+								}
+
+								supplierName := ""
+								if stage.SupplierInfo != nil {
+									supplierName = stage.SupplierInfo.Name
+								}
+								stageType := ""
+								if stage.BillType > 0 {
+									stage.Type = stage.BillType
+								}
+								if stage.Type == 1 {
+									stageType = "材料采购"
+								}
+								if stage.Type == 2 {
+									stageType = "工艺"
+								}
+								if stage.Type == 3 {
+									stageType = "成品采购"
+								}
+
+								// 状态
+								stop := false
+								stageStatus := ""
+								if len(stage.BillId) < 1 {
+									stageStatus = "未生成订单"
+									stop = true
+								}
+								// 审核状态
+								if !stop {
+									if splan.Reviewed[stage.BillId] == 1 {
+										stageStatus = "已审核"
+									} else {
+										stageStatus = "未审核"
+										stop = true
+									}
+
+								}
+
+								// 接单状态
+								if !stop {
+									if splan.IsAck[stage.BillId] {
+										stageStatus = "已接单"
+									} else {
+										stageStatus = "未接单"
+										stop = true
+									}
+
+								}
+
+								// 完成状态
+								if splan.State[stage.BillId] == "complete" {
+									stageStatus = "已完成"
+								} else if splan.State[stage.BillId] == "created" {
+									stageStatus = "进行中"
+								}
+
+								b.drawRow(b.Row, "", stageType, stage.Name, orderCount, realCount, stageStatus, supplierName, fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, price, budgetPrice, realPrice)
+								if stage.SupplierInfo != nil {
+									cates[stage.SupplierInfo.Name] = append(cates[stage.SupplierInfo.Name], b.Row)
+
+								}
+								b.Row++
+							}
 
+						}
 					}
 
-					b.Row++
-
-				}
+					// 合并同一供应商名
+					for supplierName, cate := range cates {
+						mergeStartRow := cate[0]
+						mergeEndRow := cate[len(cate)-1]
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("G%d", mergeStartRow), fmt.Sprintf("G%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("G%d", mergeEndRow), supplierName)
+					}
+					if startRow != 0 {
+						endRow := b.Row - 1
+						// 组件名字
+						startACell := fmt.Sprintf("%s%d", "A", startRow)
+						endACell := fmt.Sprintf("%s%d", "A", endRow)
+						b.Excel.MergeCell(b.SheetName, startACell, endACell)
+
+						err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
+						if err != nil {
+							return err
+						}
+						b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
 
-				for supplierName, cate := range cates {
-					mergeStartRow := cate[0]
-					mergeEndRow := cate[len(cate)-1]
-					b.Excel.MergeCell(b.SheetName, fmt.Sprintf("D%d", mergeStartRow), fmt.Sprintf("D%d", mergeEndRow))
-					b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("D%d", mergeEndRow), supplierName)
-				}
+					}
 
-				endRow := b.Row - 1
-				// 组件名字
-				startACell := fmt.Sprintf("%s%d", "A", startRow)
-				endACell := fmt.Sprintf("%s%d", "A", endRow)
-				b.Excel.MergeCell(b.SheetName, startACell, endACell)
-				err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
-				if err != nil {
-					return err
 				}
-				b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
+				// 预算
+				totalBudgetPrice += perBudgetPrice
+				// 预算
+				totalRealPrice += perRealPrice
 			}
 
-			// 预算
-			totalBudgetPrice += perBudgetPrice
-			// 实际金额
-			totalRealPrice += perRealPrice
 		}
+
+		totalBudgetPrice += planBudgetPrice
+		totalRealPrice += planRealPrice
 	}
-	startACell := fmt.Sprintf("%s%d", "A", b.Row)
-	endLCell := fmt.Sprintf("%s%d", "L", b.Row)
-	MCell := fmt.Sprintf("%s%d", "M", b.Row)
-	NCell := fmt.Sprintf("%s%d", "N", b.Row)
-	b.Excel.MergeCell(b.SheetName, startACell, endLCell)
-	b.Excel.SetCellStyle(b.SheetName, startACell, endLCell, b.AlignCenterStyle)
+
+	summaryEndRow := b.Row
+	startACell := fmt.Sprintf("%s%d", "A", summaryEndRow)
+	endMell := fmt.Sprintf("%s%d", "M", summaryEndRow)
+	NCell := fmt.Sprintf("%s%d", "N", summaryEndRow)
+	OCell := fmt.Sprintf("%s%d", "O", summaryEndRow)
+	b.Excel.MergeCell(b.SheetName, startACell, endMell)
+	b.Excel.SetCellStyle(b.SheetName, startACell, endMell, b.AlignCenterStyle)
 	b.Excel.SetCellValue(b.SheetName, startACell, "生产计划汇总金额")
 
 	// 生产预算汇总
-	b.Excel.SetCellStyle(b.SheetName, MCell, MCell, b.AlignCenterStyle)
-	planOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
-	b.FormatToEmpty(&planOrderRealPrice)
-	b.Excel.SetCellValue(b.SheetName, MCell, planOrderRealPrice)
 
-	// 生产实际汇总
 	b.Excel.SetCellStyle(b.SheetName, NCell, NCell, b.AlignCenterStyle)
-	planRealPrice := fmt.Sprintf("%.3f", totalRealPrice)
-	b.FormatToEmpty(&planRealPrice)
-	b.Excel.SetCellValue(b.SheetName, NCell, planRealPrice)
+	totalOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
+	b.FormatToEmpty(&totalOrderRealPrice)
+	b.Excel.SetCellValue(b.SheetName, NCell, totalOrderRealPrice)
+
+	// 生产实际汇总
+	b.Excel.SetCellStyle(b.SheetName, OCell, OCell, b.AlignCenterStyle)
+	totalRealPricef := fmt.Sprintf("%.3f", totalRealPrice)
+	b.FormatToEmpty(&totalRealPricef)
+	b.Excel.SetCellValue(b.SheetName, OCell, totalRealPricef)
+
+	// 供应商名字标题
+	style, err := b.Excel.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+	})
+	if err != nil {
+		return err
+	}
+	err = b.Excel.SetCellStyle(b.SheetName, "A1", "G1", style)
+	if err != nil {
+		return err
+	}
+	b.Excel.SetRowHeight(b.SheetName, 1, 32)
+	b.Excel.SetCellValue(b.SheetName, "A1", fmt.Sprintf("【%s】-生产成本表", supplier))
 
 	return nil
 }
@@ -412,7 +513,7 @@ func (b *PlanCostExcel) drawAllContent() error {
 func (b *PlanCostExcel) Draws() {
 	b.drawTitle()
 	b.drawTableTitle()
-	if b.Content.SupplierId != "" {
+	if !b.Content.SupplierId.IsZero() {
 		b.drawSupplierContent()
 	} else {
 		b.drawAllContent()
@@ -430,7 +531,7 @@ func NewPlanCostExcel(f *excelize.File) *PlanCostExcel {
 	}
 
 	styleLeft, _ := f.NewStyle(&excelize.Style{
-		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
 		Border:    border,
 		Font:      &excelize.Font{Size: 10},
 	})
@@ -439,16 +540,15 @@ func NewPlanCostExcel(f *excelize.File) *PlanCostExcel {
 		Title:            "生产成本表",
 		SheetName:        "Sheet1",
 		Excel:            f,
-		Offset:           0,
 		AlignCenterStyle: styleLeft,
 	}
 
-	f.SetColWidth(b.SheetName, "A", "B", 12)
-	f.SetColWidth(b.SheetName, "C", "C", 16)
-	f.SetColWidth(b.SheetName, "D", "D", 25)
-	f.SetColWidth(b.SheetName, "E", "E", 15)
-	f.SetColWidth(b.SheetName, "F", "F", 16)
-	f.SetColWidth(b.SheetName, "F", "N", 12)
+	f.SetColWidth(b.SheetName, "A", "D", 16)
+	f.SetColWidth(b.SheetName, "E", "F", 12)
+	f.SetColWidth(b.SheetName, "G", "G", 25)
+	f.SetColWidth(b.SheetName, "H", "K", 16)
+	f.SetColWidth(b.SheetName, "L", "L", 10)
+	f.SetColWidth(b.SheetName, "M", "O", 16)
 	f.SetPageMargins(b.SheetName, excelize.PageMarginTop(0), excelize.PageMarginLeft(0), excelize.PageMarginRight(0))
 	return b
 }

+ 356 - 233
boxcost/api/plan-summary-excel.go

@@ -1,24 +1,11 @@
 package api
 
 import (
-	"box-cost/db/model"
 	"fmt"
 
 	"github.com/xuri/excelize/v2"
-	"go.mongodb.org/mongo-driver/bson/primitive"
 )
 
-type SupplierPlanSummay struct {
-	Plans      []*PlanSummay
-	SupplierId primitive.ObjectID
-}
-type PlanSummay struct {
-	*model.ProductPlan
-	IsSend, IsAck bool
-	Reviewed      int32
-	State         string
-}
-
 // 生产成本表
 type PlanSummaryExcel struct {
 	Row              int
@@ -26,19 +13,19 @@ type PlanSummaryExcel struct {
 	Excel            *excelize.File
 	SheetName        string
 	AlignCenterStyle int
-	Content          *SupplierPlanCost
+	Content          *SupplierPlanSummary
 }
 
 func (b *PlanSummaryExcel) drawTitle() error {
 	b.Row++
 	startCell := fmt.Sprintf("A%d", b.Row)
-	err := b.Excel.MergeCell(b.SheetName, startCell, fmt.Sprintf("N%d", b.Row))
+	err := b.Excel.MergeCell(b.SheetName, startCell, fmt.Sprintf("P%d", b.Row))
 	if err != nil {
 		return err
 	}
 
 	style, err := b.Excel.NewStyle(&excelize.Style{
-		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
 		Font:      &excelize.Font{Bold: true, Size: 18}})
 	if err != nil {
 		return err
@@ -48,16 +35,12 @@ func (b *PlanSummaryExcel) drawTitle() error {
 		return err
 	}
 	b.Excel.SetRowHeight(b.SheetName, b.Row, 23)
-	b.Excel.SetCellValue(b.SheetName, startCell, b.Title)
+	b.Excel.SetCellValue(b.SheetName, startCell, "汇总表")
 	return nil
 }
 
 func (b *PlanSummaryExcel) drawTableTitle() error {
-	// row := b.Offset + 2
 	b.Row++
-
-	//A采购项目 B规格(克) 尺寸C-D 数量E 单价F-G 交货时间H 备注I
-	// A产品名称
 	var drawCol = func(prefix string, value string) error {
 		left1Cell := fmt.Sprintf("%s%d", prefix, b.Row)
 		left2Cell := fmt.Sprintf("%s%d", prefix, b.Row+1)
@@ -102,7 +85,6 @@ func (b *PlanSummaryExcel) drawTableTitle() error {
 	}
 	var drawCol3 = func(prefix1 string, prefix2 string, prefix3 string, value1 string, value2 string, value3 string, value4 string) error {
 		left1Cell := fmt.Sprintf("%s%d", prefix1, b.Row)
-		// left2Cell := fmt.Sprintf("%s%d", prefix2, row)
 		left3Cell := fmt.Sprintf("%s%d", prefix3, b.Row)
 		err := b.Excel.MergeCell(b.SheetName, left1Cell, left3Cell)
 		if err != nil {
@@ -132,284 +114,425 @@ func (b *PlanSummaryExcel) drawTableTitle() error {
 		return nil
 	}
 
-	drawCol("A", "产品部件名称")
-	drawCol2("B", "C", "类型/项目", "类型", "项目")
-	drawCol("D", "供应商名称")
-	drawCol("E", "单价1")
-	drawCol3("F", "G", "H", "规格", "厚度(纸克)", "长", "宽")
-	drawCol("I", "单位")
-	drawCol("J", "下单数量")
-	drawCol("K", "实际数量")
-	drawCol("L", "单价") // ??? 下单单价
-	drawCol("M", "预算金额")
-	drawCol("N", "实际金额")
+	drawCol("A", "产品名称")
+	drawCol("B", "产品部件名称")
+	drawCol2("C", "D", "类型/项目", "类型", "项目")
+	drawCol("E", "下单数量")
+	drawCol("F", "实际数量")
+	drawCol("G", "状态") // 生成订单状态 审核状态 发送状态 完成状态
+	drawCol("H", "供应商名称")
+	drawCol("I", "单价")
+	drawCol3("J", "K", "L", "规格", "厚度(纸克)", "长", "宽")
+	drawCol("M", "单位")
+	drawCol("N", "下单单价")
+	drawCol("O", "预算金额")
+	drawCol("P", "实际金额")
 	return nil
 }
 
 func (b *PlanSummaryExcel) drawRow(rowIndex int, values ...string) {
-	charas := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"}
+	charas := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"}
 	for i, c := range charas {
 		v := ""
 		if i < len(values) {
 			v = values[i]
 		}
 		b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("%s%d", c, rowIndex), v)
-
 		val2Cel := fmt.Sprintf("%s%d", c, rowIndex)
 		b.Excel.SetCellStyle(b.SheetName, val2Cel, val2Cel, b.AlignCenterStyle)
-
-		b.Excel.SetRowHeight(b.SheetName, rowIndex, 21)
+		b.Excel.SetRowHeight(b.SheetName, rowIndex, 32)
 	}
 
 }
 
-func (b *PlanSummaryExcel) drawSupplierContent() error {
+func (b *PlanSummaryExcel) drawAllContent() error {
 	b.Row += 2
-	supplierId, err := primitive.ObjectIDFromHex(b.Content.SupplierId)
-	if err != nil {
-		return err
-	}
-	supplier := ""
-	comps := b.Content.Pack.Components
+
+	// summaryPlans
 	// 预算金额汇总
 	var totalBudgetPrice float64 = 0.00
 	// 实际金额汇总
 	var totalRealPrice float64 = 0.00
-	if len(comps) > 0 {
-		for _, comp := range comps {
-			var perBudgetPrice float64 = 0.00
-			var perRealPrice float64 = 0.00
-
-			if len(comp.Stages) > 0 {
-				startRow := 0
-				cates := map[string][]int{}
-				for _, stage := range comp.Stages {
-					if stage.SupplierInfo != nil {
-						if supplierId == stage.SupplierInfo.Id {
-							supplier = stage.SupplierInfo.Name
-							// 材料
-							if startRow == 0 {
-								startRow = b.Row
 
-							}
+	for _, splan := range b.Content.Plans {
+		planStartRow := b.Row
+		plan := splan.Plan
+		comps := plan.Pack.Components
+		// 预算金额汇总
+		var planBudgetPrice float64 = 0.00
+		// 实际金额汇总
+		var planRealPrice float64 = 0.00
+		if len(comps) > 0 {
+			for _, comp := range comps {
+				var perBudgetPrice float64 = 0.00
+				var perRealPrice float64 = 0.00
+				if len(comp.Stages) > 0 {
+					startRow := b.Row
+					cates := map[string][]int{}
+					for _, stage := range comp.Stages {
+						matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
+						b.FormatToEmpty(&matHeigth)
+						matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
+						b.FormatToEmpty(&matWidth)
+						orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
+						b.FormatToEmpty(&orderCount)
+
+						// 实际数量
+						realCount := fmt.Sprintf("%d", stage.ConfirmCount)
+						b.FormatToEmpty(&realCount)
+						// 单价
+						price := fmt.Sprintf("%.3f", stage.OrderPrice)
+						b.FormatToEmpty(&price)
+						// 预算金额
+						budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
+						perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
+						b.FormatToEmpty(&budgetPrice)
+						// 实际金额
+						perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
+						realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
+						b.FormatToEmpty(&realPrice)
+						unit := stage.Unit
+						if stage.Unit == "吨" || stage.Unit == "平方米" {
+							unit = "张"
+						}
 
-							matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
-							b.FormatToEmpty(&matHeigth)
-							matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
-							b.FormatToEmpty(&matWidth)
-							orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
-							b.FormatToEmpty(&orderCount)
-
-							// 实际数量
-							realCount := fmt.Sprintf("%d", stage.ConfirmCount)
-							b.FormatToEmpty(&realCount)
-							// 单价
-							price := fmt.Sprintf("%.3f", stage.OrderPrice)
-							b.FormatToEmpty(&price)
-							// 预算金额
-							budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
-							perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
-							b.FormatToEmpty(&budgetPrice)
-							// 实际金额
-							perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
-							realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
-							b.FormatToEmpty(&realPrice)
-							unit := stage.Unit
-							if stage.Unit == "吨" || stage.Unit == "平方米" {
-								unit = "张"
-							}
+						supplierName := ""
+						if stage.SupplierInfo != nil {
+							supplierName = stage.SupplierInfo.Name
+						}
+						stageType := ""
+						if stage.BillType > 0 {
+							stage.Type = stage.BillType
+						}
+						if stage.Type == 1 {
+							stageType = "材料采购"
+						}
+						if stage.Type == 2 {
+							stageType = "工艺"
+						}
+						if stage.Type == 3 {
+							stageType = "成品采购"
+						}
 
-							// 生成单据时已billType为准
-							stageType := ""
-							if stage.BillType > 0 {
-								stage.Type = stage.BillType
-							}
-							if stage.Type == 1 {
-								stageType = "材料采购"
-							}
-							if stage.Type == 2 {
-								stageType = "工艺"
+						// 状态
+						stop := false
+						stageStatus := ""
+						if len(stage.BillId) < 1 {
+							stageStatus = "未生成订单"
+							stop = true
+						}
+						// 审核状态
+						if !stop {
+							if splan.Reviewed[stage.BillId] == 1 {
+								stageStatus = "已审核"
+							} else {
+								stageStatus = "未审核"
+								stop = true
 							}
-							if stage.Type == 3 {
-								stageType = "成品采购"
+
+						}
+
+						// 接单状态
+						if !stop {
+							if splan.IsAck[stage.BillId] {
+								stageStatus = "已接单"
+							} else {
+								stageStatus = "未接单"
+								stop = true
 							}
-							b.drawRow(b.Row, "", stageType, stage.Name, "", fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, orderCount, realCount, price, budgetPrice, realPrice)
+
+						}
+
+						// 完成状态
+						if splan.State[stage.BillId] == "complete" {
+							stageStatus = "已完成"
+						} else if splan.State[stage.BillId] == "created" {
+							stageStatus = "进行中"
+						}
+
+						b.drawRow(b.Row, "", "", stageType, stage.Name, orderCount, realCount, stageStatus, supplierName, fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, price, budgetPrice, realPrice)
+						if stage.SupplierInfo != nil {
 							cates[stage.SupplierInfo.Name] = append(cates[stage.SupplierInfo.Name], b.Row)
-							b.Row++
+
 						}
+						b.Row++
+					}
 
+					for supplierName, cate := range cates {
+						mergeStartRow := cate[0]
+						mergeEndRow := cate[len(cate)-1]
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("H%d", mergeStartRow), fmt.Sprintf("H%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("H%d", mergeEndRow), supplierName)
 					}
-				}
 
-				// 合并同一供应商名
-				for supplierName, cate := range cates {
-					mergeStartRow := cate[0]
-					mergeEndRow := cate[len(cate)-1]
-					b.Excel.MergeCell(b.SheetName, fmt.Sprintf("D%d", mergeStartRow), fmt.Sprintf("D%d", mergeEndRow))
-					b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("D%d", mergeEndRow), supplierName)
-				}
-				if startRow != 0 {
 					endRow := b.Row - 1
 					// 组件名字
-					startACell := fmt.Sprintf("%s%d", "A", startRow)
-					endACell := fmt.Sprintf("%s%d", "A", endRow)
+					startACell := fmt.Sprintf("%s%d", "B", startRow)
+					endACell := fmt.Sprintf("%s%d", "B", endRow)
 					b.Excel.MergeCell(b.SheetName, startACell, endACell)
-
 					err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
 					if err != nil {
 						return err
 					}
 					b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
-
 				}
 
+				// 预算
+				planBudgetPrice += perBudgetPrice
+				// 实际金额
+				planRealPrice += perRealPrice
 			}
-			// 预算
-			totalBudgetPrice += perBudgetPrice
-			// 预算
-			totalRealPrice += perRealPrice
 		}
+		totalBudgetPrice += planBudgetPrice
+		totalRealPrice += planRealPrice
+
+		// plan
+		// b.row +2 分割每个计划
+		planEndRow := b.Row
+		planStartACell := fmt.Sprintf("%s%d", "A", planStartRow)
+		planEndACell := fmt.Sprintf("%s%d", "A", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartACell, planEndACell)
+		err := b.Excel.SetCellStyle(b.SheetName, planStartACell, planEndACell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartACell, plan.Name)
+		// b.Row += 2
 
 	}
 
-	// 生产汇总金额
-	startACell := fmt.Sprintf("%s%d", "A", b.Row)
-	endLCell := fmt.Sprintf("%s%d", "L", b.Row)
-	MCell := fmt.Sprintf("%s%d", "M", b.Row)
-	NCell := fmt.Sprintf("%s%d", "N", b.Row)
-	b.Excel.MergeCell(b.SheetName, startACell, endLCell)
-	b.Excel.SetCellStyle(b.SheetName, startACell, endLCell, b.AlignCenterStyle)
-	b.Excel.SetCellValue(b.SheetName, startACell, fmt.Sprintf("【%s】生产计划汇总金额", supplier))
+	summaryEndRow := b.Row
+	startACell := fmt.Sprintf("%s%d", "A", summaryEndRow)
+	endNell := fmt.Sprintf("%s%d", "N", summaryEndRow)
+	OCell := fmt.Sprintf("%s%d", "O", summaryEndRow)
+	PCell := fmt.Sprintf("%s%d", "P", summaryEndRow)
+	b.Excel.MergeCell(b.SheetName, startACell, endNell)
+	b.Excel.SetCellStyle(b.SheetName, startACell, endNell, b.AlignCenterStyle)
+	b.Excel.SetCellValue(b.SheetName, startACell, "生产计划汇总金额")
 
 	// 生产预算汇总
-	b.Excel.SetCellStyle(b.SheetName, MCell, MCell, b.AlignCenterStyle)
-	planOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
-	b.FormatToEmpty(&planOrderRealPrice)
-	b.Excel.SetCellValue(b.SheetName, MCell, planOrderRealPrice)
+
+	b.Excel.SetCellStyle(b.SheetName, OCell, OCell, b.AlignCenterStyle)
+	totalOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
+	b.FormatToEmpty(&totalOrderRealPrice)
+	b.Excel.SetCellValue(b.SheetName, OCell, totalOrderRealPrice)
 
 	// 生产实际汇总
-	b.Excel.SetCellStyle(b.SheetName, NCell, NCell, b.AlignCenterStyle)
-	planRealPrice := fmt.Sprintf("%.3f", totalRealPrice)
-	b.FormatToEmpty(&planRealPrice)
-	b.Excel.SetCellValue(b.SheetName, NCell, planRealPrice)
+	b.Excel.SetCellStyle(b.SheetName, PCell, PCell, b.AlignCenterStyle)
+	totalRealPricef := fmt.Sprintf("%.3f", totalRealPrice)
+	b.FormatToEmpty(&totalRealPricef)
+	b.Excel.SetCellValue(b.SheetName, PCell, totalRealPricef)
 
 	return nil
 }
 
-// type merge
-
-func (b *PlanSummaryExcel) drawAllContent() error {
+func (b *PlanSummaryExcel) drawSupplierContent() error {
 	b.Row += 2
-	comps := b.Content.Pack.Components
+	supplier := ""
+	// summaryPlans
 	// 预算金额汇总
 	var totalBudgetPrice float64 = 0.00
 	// 实际金额汇总
 	var totalRealPrice float64 = 0.00
-	if len(comps) > 0 {
-		for _, comp := range comps {
-			var perBudgetPrice float64 = 0.00
-			var perRealPrice float64 = 0.00
-			if len(comp.Stages) > 0 {
-				startRow := b.Row
-				cates := map[string][]int{}
-				for _, stage := range comp.Stages {
-					matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
-					b.FormatToEmpty(&matHeigth)
-					matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
-					b.FormatToEmpty(&matWidth)
-					orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
-					b.FormatToEmpty(&orderCount)
-
-					// 实际数量
-					realCount := fmt.Sprintf("%d", stage.ConfirmCount)
-					b.FormatToEmpty(&realCount)
-					// 单价
-					price := fmt.Sprintf("%.3f", stage.OrderPrice)
-					b.FormatToEmpty(&price)
-					// 预算金额
-					budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
-					perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
-					b.FormatToEmpty(&budgetPrice)
-					// 实际金额
-					perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
-					realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
-					b.FormatToEmpty(&realPrice)
-					unit := stage.Unit
-					if stage.Unit == "吨" || stage.Unit == "平方米" {
-						unit = "张"
-					}
 
-					supplierName := ""
-					if stage.SupplierInfo != nil {
-						supplierName = stage.SupplierInfo.Name
-					}
-					stageType := ""
-					if stage.BillType > 0 {
-						stage.Type = stage.BillType
-					}
-					if stage.Type == 1 {
-						stageType = "材料采购"
-					}
-					if stage.Type == 2 {
-						stageType = "工艺"
-					}
-					if stage.Type == 3 {
-						stageType = "成品采购"
+	for _, splan := range b.Content.Plans {
+		planStartRow := b.Row
+		plan := splan.Plan
+		comps := plan.Pack.Components
+		// 预算金额汇总
+		var planBudgetPrice float64 = 0.00
+		// 实际金额汇总
+		var planRealPrice float64 = 0.00
+		if len(comps) > 0 {
+			for _, comp := range comps {
+				var perBudgetPrice float64 = 0.00
+				var perRealPrice float64 = 0.00
+				if len(comp.Stages) > 0 {
+					startRow := 0
+					cates := map[string][]int{}
+					for _, stage := range comp.Stages {
+						if stage.SupplierInfo != nil {
+							if b.Content.SupplierId == stage.SupplierInfo.Id {
+								supplier = stage.SupplierInfo.Name
+								// 材料
+								if startRow == 0 {
+									startRow = b.Row
+
+								}
+
+								matHeigth := fmt.Sprintf("%d", stage.BatchSizeHeight)
+								b.FormatToEmpty(&matHeigth)
+								matWidth := fmt.Sprintf("%d", stage.BatchSizeWidth)
+								b.FormatToEmpty(&matWidth)
+								orderCount := fmt.Sprintf("%d", int(stage.OrderCount))
+								b.FormatToEmpty(&orderCount)
+
+								// 实际数量
+								realCount := fmt.Sprintf("%d", stage.ConfirmCount)
+								b.FormatToEmpty(&realCount)
+								// 单价
+								price := fmt.Sprintf("%.3f", stage.OrderPrice)
+								b.FormatToEmpty(&price)
+								// 预算金额
+								budgetPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.OrderCount))
+								perBudgetPrice += stage.OrderPrice * float64(stage.OrderCount)
+								b.FormatToEmpty(&budgetPrice)
+								// 实际金额
+								perRealPrice += stage.OrderPrice * float64(stage.ConfirmCount)
+								realPrice := fmt.Sprintf("%.3f", stage.OrderPrice*float64(stage.ConfirmCount))
+								b.FormatToEmpty(&realPrice)
+								unit := stage.Unit
+								if stage.Unit == "吨" || stage.Unit == "平方米" {
+									unit = "张"
+								}
+
+								supplierName := ""
+								if stage.SupplierInfo != nil {
+									supplierName = stage.SupplierInfo.Name
+								}
+								stageType := ""
+								if stage.BillType > 0 {
+									stage.Type = stage.BillType
+								}
+								if stage.Type == 1 {
+									stageType = "材料采购"
+								}
+								if stage.Type == 2 {
+									stageType = "工艺"
+								}
+								if stage.Type == 3 {
+									stageType = "成品采购"
+								}
+
+								// 状态
+								stop := false
+								stageStatus := ""
+								if len(stage.BillId) < 1 {
+									stageStatus = "未生成订单"
+									stop = true
+								}
+								// 审核状态
+								if !stop {
+									if splan.Reviewed[stage.BillId] == 1 {
+										stageStatus = "已审核"
+									} else {
+										stageStatus = "未审核"
+										stop = true
+									}
+
+								}
+
+								// 接单状态
+								if !stop {
+									if splan.IsAck[stage.BillId] {
+										stageStatus = "已接单"
+									} else {
+										stageStatus = "未接单"
+										stop = true
+									}
+
+								}
+
+								// 完成状态
+								if splan.State[stage.BillId] == "complete" {
+									stageStatus = "已完成"
+								} else if splan.State[stage.BillId] == "created" {
+									stageStatus = "进行中"
+								}
+
+								b.drawRow(b.Row, "", "", stageType, stage.Name, orderCount, realCount, stageStatus, supplierName, fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, price, budgetPrice, realPrice)
+								if stage.SupplierInfo != nil {
+									cates[stage.SupplierInfo.Name] = append(cates[stage.SupplierInfo.Name], b.Row)
+
+								}
+								b.Row++
+							}
+
+						}
 					}
-					b.drawRow(b.Row, "", stageType, stage.Name, supplierName, fmt.Sprintf("%.3f元/%s", stage.Price, stage.Unit), stage.Norm, matHeigth, matWidth, unit, orderCount, realCount, price, budgetPrice, realPrice)
-					if stage.SupplierInfo != nil {
-						cates[stage.SupplierInfo.Name] = append(cates[stage.SupplierInfo.Name], b.Row)
 
+					// 合并同一供应商名
+					for supplierName, cate := range cates {
+						mergeStartRow := cate[0]
+						mergeEndRow := cate[len(cate)-1]
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("H%d", mergeStartRow), fmt.Sprintf("H%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("H%d", mergeEndRow), supplierName)
 					}
+					if startRow != 0 {
+						endRow := b.Row - 1
+						// 组件名字
+						startACell := fmt.Sprintf("%s%d", "B", startRow)
+						endACell := fmt.Sprintf("%s%d", "B", endRow)
+						b.Excel.MergeCell(b.SheetName, startACell, endACell)
+
+						err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
+						if err != nil {
+							return err
+						}
+						b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
 
-					b.Row++
+					}
 
 				}
+				// 预算
+				totalBudgetPrice += perBudgetPrice
+				// 预算
+				totalRealPrice += perRealPrice
+			}
 
-				for supplierName, cate := range cates {
-					mergeStartRow := cate[0]
-					mergeEndRow := cate[len(cate)-1]
-					b.Excel.MergeCell(b.SheetName, fmt.Sprintf("D%d", mergeStartRow), fmt.Sprintf("D%d", mergeEndRow))
-					b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("D%d", mergeEndRow), supplierName)
-				}
+		}
 
-				endRow := b.Row - 1
-				// 组件名字
-				startACell := fmt.Sprintf("%s%d", "A", startRow)
-				endACell := fmt.Sprintf("%s%d", "A", endRow)
-				b.Excel.MergeCell(b.SheetName, startACell, endACell)
-				err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
-				if err != nil {
-					return err
-				}
-				b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
-			}
+		totalBudgetPrice += planBudgetPrice
+		totalRealPrice += planRealPrice
 
-			// 预算
-			totalBudgetPrice += perBudgetPrice
-			// 实际金额
-			totalRealPrice += perRealPrice
+		// plan
+		// b.row +2 分割每个计划
+		planEndRow := b.Row
+		planStartACell := fmt.Sprintf("%s%d", "A", planStartRow)
+		planEndACell := fmt.Sprintf("%s%d", "A", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartACell, planEndACell)
+		err := b.Excel.SetCellStyle(b.SheetName, planStartACell, planEndACell, b.AlignCenterStyle)
+		if err != nil {
+			return err
 		}
+		b.Excel.SetCellValue(b.SheetName, planStartACell, plan.Name)
 	}
-	startACell := fmt.Sprintf("%s%d", "A", b.Row)
-	endLCell := fmt.Sprintf("%s%d", "L", b.Row)
-	MCell := fmt.Sprintf("%s%d", "M", b.Row)
-	NCell := fmt.Sprintf("%s%d", "N", b.Row)
-	b.Excel.MergeCell(b.SheetName, startACell, endLCell)
-	b.Excel.SetCellStyle(b.SheetName, startACell, endLCell, b.AlignCenterStyle)
-	b.Excel.SetCellValue(b.SheetName, startACell, "生产计划汇总金额")
+
+	summaryEndRow := b.Row
+	startACell := fmt.Sprintf("%s%d", "A", summaryEndRow)
+	endNell := fmt.Sprintf("%s%d", "N", summaryEndRow)
+	OCell := fmt.Sprintf("%s%d", "O", summaryEndRow)
+	PCell := fmt.Sprintf("%s%d", "P", summaryEndRow)
+	b.Excel.MergeCell(b.SheetName, startACell, endNell)
+	b.Excel.SetCellStyle(b.SheetName, startACell, endNell, b.AlignCenterStyle)
+	b.Excel.SetCellValue(b.SheetName, startACell, fmt.Sprintf("【%s】生产计划汇总金额", supplier))
 
 	// 生产预算汇总
-	b.Excel.SetCellStyle(b.SheetName, MCell, MCell, b.AlignCenterStyle)
-	planOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
-	b.FormatToEmpty(&planOrderRealPrice)
-	b.Excel.SetCellValue(b.SheetName, MCell, planOrderRealPrice)
+
+	b.Excel.SetCellStyle(b.SheetName, OCell, OCell, b.AlignCenterStyle)
+	totalOrderRealPrice := fmt.Sprintf("%.3f", totalBudgetPrice)
+	b.FormatToEmpty(&totalOrderRealPrice)
+	b.Excel.SetCellValue(b.SheetName, OCell, totalOrderRealPrice)
 
 	// 生产实际汇总
-	b.Excel.SetCellStyle(b.SheetName, NCell, NCell, b.AlignCenterStyle)
-	planRealPrice := fmt.Sprintf("%.3f", totalRealPrice)
-	b.FormatToEmpty(&planRealPrice)
-	b.Excel.SetCellValue(b.SheetName, NCell, planRealPrice)
+	b.Excel.SetCellStyle(b.SheetName, PCell, PCell, b.AlignCenterStyle)
+	totalRealPricef := fmt.Sprintf("%.3f", totalRealPrice)
+	b.FormatToEmpty(&totalRealPricef)
+	b.Excel.SetCellValue(b.SheetName, PCell, totalRealPricef)
+
+	// 供应商名字标题
+	style, err := b.Excel.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+	})
+	if err != nil {
+		return err
+	}
+	err = b.Excel.SetCellStyle(b.SheetName, "A1", "G1", style)
+	if err != nil {
+		return err
+	}
+	b.Excel.SetRowHeight(b.SheetName, 1, 32)
+	b.Excel.SetCellValue(b.SheetName, "A1", fmt.Sprintf("【%s】-汇总表", supplier))
 
 	return nil
 }
@@ -417,7 +540,7 @@ func (b *PlanSummaryExcel) drawAllContent() error {
 func (b *PlanSummaryExcel) Draws() {
 	b.drawTitle()
 	b.drawTableTitle()
-	if b.Content.SupplierId != "" {
+	if !b.Content.SupplierId.IsZero() {
 		b.drawSupplierContent()
 	} else {
 		b.drawAllContent()
@@ -435,7 +558,7 @@ func NewPlanSummaryExcel(f *excelize.File) *PlanSummaryExcel {
 	}
 
 	styleLeft, _ := f.NewStyle(&excelize.Style{
-		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
 		Border:    border,
 		Font:      &excelize.Font{Size: 10},
 	})
@@ -447,12 +570,12 @@ func NewPlanSummaryExcel(f *excelize.File) *PlanSummaryExcel {
 		AlignCenterStyle: styleLeft,
 	}
 
-	f.SetColWidth(b.SheetName, "A", "B", 12)
-	f.SetColWidth(b.SheetName, "C", "C", 16)
-	f.SetColWidth(b.SheetName, "D", "D", 25)
-	f.SetColWidth(b.SheetName, "E", "E", 15)
-	f.SetColWidth(b.SheetName, "F", "F", 16)
-	f.SetColWidth(b.SheetName, "F", "N", 12)
+	f.SetColWidth(b.SheetName, "A", "D", 16)
+	f.SetColWidth(b.SheetName, "E", "G", 12)
+	f.SetColWidth(b.SheetName, "H", "H", 25)
+	f.SetColWidth(b.SheetName, "I", "L", 16)
+	f.SetColWidth(b.SheetName, "M", "M", 10)
+	f.SetColWidth(b.SheetName, "N", "P", 16)
 	f.SetPageMargins(b.SheetName, excelize.PageMarginTop(0), excelize.PageMarginLeft(0), excelize.PageMarginRight(0))
 	return b
 }

+ 16 - 8
boxcost/api/plan.go

@@ -155,12 +155,12 @@ type SupplierPlanCost struct {
 
 func DownLoadPlanCost(c *gin.Context, apictx *ApiSession) (interface{}, error) {
 	_planId := c.Query("id")
-	supplierId := c.Query("supplierId")
+	_supplierId := c.Query("supplierId")
+	supplierId, _ := primitive.ObjectIDFromHex(_supplierId)
 	planId, _ := primitive.ObjectIDFromHex(_planId)
 	if planId.IsZero() {
 		return nil, errors.New("planId错误")
 	}
-	supplierPlanCost := &SupplierPlanCost{}
 
 	plan := model.ProductPlan{}
 	found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
@@ -170,17 +170,25 @@ func DownLoadPlanCost(c *gin.Context, apictx *ApiSession) (interface{}, error) {
 	if !found || err != nil {
 		return nil, errors.New("数据未找到")
 	}
-	supplierPlanCost.ProductPlan = &plan
-	supplierPlanCost.SupplierId = supplierId
+	summaryPlans := []*PlanSummary{}
+	summaryPlan := GetPlanStatus(&plan, apictx)
+	summaryPlans = append(summaryPlans, summaryPlan)
+	if len(summaryPlans) < 1 {
+		return nil, errors.New("数据不存在")
+	}
 
 	f := excelize.NewFile()
 	index := f.NewSheet("Sheet1")
 	f.SetActiveSheet(index)
 	f.SetDefaultFont("宋体")
-	planCostExcel := NewPlanCostExcel(f)
-	planCostExcel.Title = fmt.Sprintf("生产成本表(%s)%d盒", plan.Name, plan.Total)
-	planCostExcel.Content = supplierPlanCost
-	planCostExcel.Draws()
+	planSummaryExcel := NewPlanCostExcel(f)
+	planSummaryExcel.Content = &SupplierPlanSummary{
+		Plans:      summaryPlans,
+		SupplierId: supplierId,
+	}
+	// 绘制表格
+	planSummaryExcel.Title = fmt.Sprintf("生产成本表(%s)%d盒", plan.Name, plan.Total)
+	planSummaryExcel.Draws()
 
 	c.Header("Content-Type", "application/octet-stream")
 	c.Header("Content-Disposition", "attachment; filename="+"planCost.xlsx")

+ 3 - 0
boxcost/api/router.go

@@ -58,6 +58,9 @@ func RegRouters(svc *Service) {
 	// 成品采购管理
 	Product(boxcost)
 
+	// 计划汇总
+	Summary(boxcost)
+
 	boxcost.GET("/apk/version", func(c *gin.Context, apictx *ApiSession) (interface{}, error) {
 		out, err := repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
 			CollectName: "versions",

+ 441 - 0
boxcost/api/summary-sample-excel.go

@@ -0,0 +1,441 @@
+package api
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/xuri/excelize/v2"
+)
+
+// 生产成本表
+type SummarySampleExcel struct {
+	Row              int
+	Title            string
+	Excel            *excelize.File
+	SheetName        string
+	AlignCenterStyle int
+	Content          *SupplierPlanSummary
+}
+
+func (b *SummarySampleExcel) drawTitle() error {
+	b.Row++
+	startCell := fmt.Sprintf("A%d", b.Row)
+	err := b.Excel.MergeCell(b.SheetName, startCell, fmt.Sprintf("G%d", b.Row))
+	if err != nil {
+		return err
+	}
+
+	style, err := b.Excel.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+		Font:      &excelize.Font{Bold: true, Size: 18}})
+	if err != nil {
+		return err
+	}
+	err = b.Excel.SetCellStyle(b.SheetName, startCell, startCell, style)
+	if err != nil {
+		return err
+	}
+	b.Excel.SetRowHeight(b.SheetName, b.Row, 23)
+	b.Excel.SetCellValue(b.SheetName, startCell, "追踪表")
+	return nil
+}
+
+func (b *SummarySampleExcel) drawTableTitle() error {
+	b.Row++
+	var drawCol = func(prefix string, value string) error {
+		left1Cell := fmt.Sprintf("%s%d", prefix, b.Row)
+		left2Cell := fmt.Sprintf("%s%d", prefix, b.Row+1)
+
+		err := b.Excel.MergeCell(b.SheetName, left1Cell, left2Cell)
+		if err != nil {
+			return err
+		}
+		err = b.Excel.SetCellStyle(b.SheetName, left1Cell, left2Cell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+
+		return b.Excel.SetCellValue(b.SheetName, left1Cell, value)
+	}
+
+	drawCol("A", "序号")
+	drawCol("B", "产品名称")
+	drawCol("C", "产品部件名称")
+	drawCol("D", "下单日期")
+	drawCol("E", "交货日期")
+	drawCol("F", "工序")
+	drawCol("G", "备注")
+	return nil
+}
+
+func (b *SummarySampleExcel) drawRow(rowIndex int, values ...string) {
+	charas := []string{"A", "B", "C", "D", "E", "F", "G"}
+	for i, c := range charas {
+		v := ""
+		if i < len(values) {
+			v = values[i]
+		}
+		b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("%s%d", c, rowIndex), v)
+		val2Cel := fmt.Sprintf("%s%d", c, rowIndex)
+		b.Excel.SetCellStyle(b.SheetName, val2Cel, val2Cel, b.AlignCenterStyle)
+		if c == "F" {
+
+			border := []excelize.Border{
+				{Type: "top", Style: 1, Color: "000000"},
+				{Type: "left", Style: 1, Color: "000000"},
+				{Type: "right", Style: 1, Color: "000000"},
+				{Type: "bottom", Style: 1, Color: "000000"},
+			}
+			styleLeft, _ := b.Excel.NewStyle(&excelize.Style{
+				Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center", WrapText: true},
+				Font:      &excelize.Font{Size: 11},
+				Border:    border})
+			b.Excel.SetCellStyle(b.SheetName, val2Cel, val2Cel, styleLeft)
+
+		}
+		b.Excel.SetRowHeight(b.SheetName, rowIndex, 32)
+	}
+
+}
+
+func (b *SummarySampleExcel) drawAllContent() error {
+	b.Row += 2
+	// summaryPlans
+	index := 0
+	for _, splan := range b.Content.Plans {
+		index++
+		planStartRow := b.Row
+		plan := splan.Plan
+		comps := plan.Pack.Components
+		if len(comps) > 0 {
+			for _, comp := range comps {
+				if len(comp.Stages) > 0 {
+					startRow := b.Row
+					cates := map[string][]int{}
+					for _, stage := range comp.Stages {
+						// 状态
+						stop := false
+						stageStatus := ""
+						statusMark := "【x】"
+
+						if len(stage.BillId) < 1 {
+							stageStatus = "未生成订单"
+							stop = true
+						}
+						// 审核状态
+						if !stop {
+							if splan.Reviewed[stage.BillId] == 1 {
+								stageStatus = "已审核"
+							} else {
+								stageStatus = "未审核"
+								stop = true
+							}
+
+						}
+
+						// 接单状态
+						if !stop {
+							if splan.IsAck[stage.BillId] {
+								stageStatus = "已接单"
+							} else {
+								stageStatus = "未接单"
+								stop = true
+							}
+
+						}
+
+						// 完成状态
+						if !stop {
+							if splan.State[stage.BillId] == "complete" {
+								stageStatus = "已完成"
+								statusMark = "【v】"
+							} else if splan.State[stage.BillId] == "created" {
+								stageStatus = "进行中"
+							}
+
+						}
+						fmt.Println(stageStatus)
+						createTime := splan.CreateTimes[stage.BillId].Local().Format("2006-01-02")
+						deliveryTime := stage.DeliveryTime.Local().Format("2006-01-02")
+						stageNmae := fmt.Sprintf("%s %s", statusMark, stage.Name)
+
+						b.drawRow(b.Row, "", "", "", createTime, deliveryTime, stageNmae, "")
+
+						cates[fmt.Sprintf("%s,%s,%s", createTime, deliveryTime, stageNmae)] = append(cates[fmt.Sprintf("%s,%s,%s", createTime, deliveryTime, stageNmae)], b.Row)
+						b.Row++
+					}
+
+					for stageInfo, cate := range cates {
+						sf := strings.Split(stageInfo, ",")
+						fmt.Println(sf)
+						mergeStartRow := cate[0]
+						mergeEndRow := cate[len(cate)-1]
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("D%d", mergeStartRow), fmt.Sprintf("D%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("D%d", mergeEndRow), sf[0])
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("E%d", mergeStartRow), fmt.Sprintf("E%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("E%d", mergeEndRow), sf[1])
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("F%d", mergeStartRow), fmt.Sprintf("F%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("F%d", mergeEndRow), sf[2])
+
+					}
+
+					endRow := b.Row - 1
+					// 组件名字
+					startACell := fmt.Sprintf("%s%d", "C", startRow)
+					endACell := fmt.Sprintf("%s%d", "C", endRow)
+					b.Excel.MergeCell(b.SheetName, startACell, endACell)
+					err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
+					if err != nil {
+						return err
+					}
+					b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
+				}
+
+			}
+		}
+
+		// 序号
+		planEndRow := b.Row
+		planStartACell := fmt.Sprintf("%s%d", "A", planStartRow)
+		planEndACell := fmt.Sprintf("%s%d", "A", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartACell, planEndACell)
+		err := b.Excel.SetCellStyle(b.SheetName, planStartACell, planEndACell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartACell, index)
+
+		// 产品名
+		planStartBCell := fmt.Sprintf("%s%d", "B", planStartRow)
+		planEndBCell := fmt.Sprintf("%s%d", "B", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartBCell, planEndBCell)
+		err = b.Excel.SetCellStyle(b.SheetName, planStartBCell, planEndBCell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartBCell, plan.Name)
+
+		// 备注
+		planStartFCell := fmt.Sprintf("%s%d", "G", planStartRow)
+		planEndFCell := fmt.Sprintf("%s%d", "G", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartFCell, planEndFCell)
+		err = b.Excel.SetCellStyle(b.SheetName, planStartFCell, planEndFCell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartFCell, "")
+
+	}
+
+	return nil
+}
+
+func (b *SummarySampleExcel) drawSupplierContent() error {
+	b.Row += 2
+	index := 0
+	supplier := ""
+	// summaryPlans
+	for _, splan := range b.Content.Plans {
+		index++
+		planStartRow := b.Row
+		plan := splan.Plan
+		comps := plan.Pack.Components
+		if len(comps) > 0 {
+			for _, comp := range comps {
+				if len(comp.Stages) > 0 {
+					startRow := 0
+					cates := map[string][]int{}
+					for _, stage := range comp.Stages {
+						if stage.SupplierInfo != nil {
+							if b.Content.SupplierId == stage.SupplierInfo.Id {
+								supplier = stage.SupplierInfo.Name
+								// 材料
+								if startRow == 0 {
+									startRow = b.Row
+
+								}
+
+								// 状态
+								stop := false
+								stageStatus := ""
+								statusMark := "【x】"
+
+								if len(stage.BillId) < 1 {
+									stageStatus = "未生成订单"
+									stop = true
+								}
+								// 审核状态
+								if !stop {
+									if splan.Reviewed[stage.BillId] == 1 {
+										stageStatus = "已审核"
+									} else {
+										stageStatus = "未审核"
+										stop = true
+									}
+
+								}
+
+								// 接单状态
+								if !stop {
+									if splan.IsAck[stage.BillId] {
+										stageStatus = "已接单"
+									} else {
+										stageStatus = "未接单"
+										stop = true
+									}
+
+								}
+
+								// 完成状态
+								if !stop {
+									if splan.State[stage.BillId] == "complete" {
+										stageStatus = "已完成"
+										statusMark = "【v】"
+									} else if splan.State[stage.BillId] == "created" {
+										stageStatus = "进行中"
+									}
+
+								}
+								fmt.Println(stageStatus)
+								createTime := splan.CreateTimes[stage.BillId].Local().Format("2006-01-02")
+								deliveryTime := stage.DeliveryTime.Local().Format("2006-01-02")
+								stageNmae := fmt.Sprintf("%s %s", statusMark, stage.Name)
+
+								b.drawRow(b.Row, "", "", "", createTime, deliveryTime, stageNmae, "")
+
+								cates[fmt.Sprintf("%s,%s,%s", createTime, deliveryTime, stageNmae)] = append(cates[fmt.Sprintf("%s,%s,%s", createTime, deliveryTime, stageNmae)], b.Row)
+								b.Row++
+							}
+
+						}
+					}
+
+					for stageInfo, cate := range cates {
+						sf := strings.Split(stageInfo, ",")
+						fmt.Println(sf)
+						mergeStartRow := cate[0]
+						mergeEndRow := cate[len(cate)-1]
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("D%d", mergeStartRow), fmt.Sprintf("D%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("D%d", mergeEndRow), sf[0])
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("E%d", mergeStartRow), fmt.Sprintf("E%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("E%d", mergeEndRow), sf[1])
+						b.Excel.MergeCell(b.SheetName, fmt.Sprintf("F%d", mergeStartRow), fmt.Sprintf("F%d", mergeEndRow))
+						b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("F%d", mergeEndRow), sf[2])
+
+					}
+
+					if startRow != 0 {
+						endRow := b.Row - 1
+						// 组件名字
+						startACell := fmt.Sprintf("%s%d", "C", startRow)
+						endACell := fmt.Sprintf("%s%d", "C", endRow)
+						b.Excel.MergeCell(b.SheetName, startACell, endACell)
+						err := b.Excel.SetCellStyle(b.SheetName, startACell, endACell, b.AlignCenterStyle)
+						if err != nil {
+							return err
+						}
+						b.Excel.SetCellValue(b.SheetName, startACell, comp.Name)
+
+					}
+
+				}
+
+			}
+
+		}
+
+		// 序号
+		planEndRow := b.Row
+		planStartACell := fmt.Sprintf("%s%d", "A", planStartRow)
+		planEndACell := fmt.Sprintf("%s%d", "A", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartACell, planEndACell)
+		err := b.Excel.SetCellStyle(b.SheetName, planStartACell, planEndACell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartACell, index)
+
+		// 产品名
+		planStartBCell := fmt.Sprintf("%s%d", "B", planStartRow)
+		planEndBCell := fmt.Sprintf("%s%d", "B", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartBCell, planEndBCell)
+		err = b.Excel.SetCellStyle(b.SheetName, planStartBCell, planEndBCell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartBCell, plan.Name)
+
+		// 备注
+		planStartFCell := fmt.Sprintf("%s%d", "G", planStartRow)
+		planEndFCell := fmt.Sprintf("%s%d", "G", planEndRow-1)
+		b.Excel.MergeCell(b.SheetName, planStartFCell, planEndFCell)
+		err = b.Excel.SetCellStyle(b.SheetName, planStartFCell, planEndFCell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+		b.Excel.SetCellValue(b.SheetName, planStartFCell, "")
+	}
+	// 供应商名字标题
+	style, err := b.Excel.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+	})
+	if err != nil {
+		return err
+	}
+	err = b.Excel.SetCellStyle(b.SheetName, "A1", "G1", style)
+	if err != nil {
+		return err
+	}
+	b.Excel.SetRowHeight(b.SheetName, 1, 32)
+	b.Excel.SetCellValue(b.SheetName, "A1", fmt.Sprintf("【%s】-追踪表", supplier))
+
+	return nil
+}
+
+func (b *SummarySampleExcel) Draws() {
+	b.drawTitle()
+	b.drawTableTitle()
+	if !b.Content.SupplierId.IsZero() {
+		b.drawSupplierContent()
+	} else {
+		b.drawAllContent()
+	}
+
+}
+
+func NewSummarySampleExcel(f *excelize.File) *SummarySampleExcel {
+
+	border := []excelize.Border{
+		{Type: "top", Style: 1, Color: "000000"},
+		{Type: "left", Style: 1, Color: "000000"},
+		{Type: "right", Style: 1, Color: "000000"},
+		{Type: "bottom", Style: 1, Color: "000000"},
+	}
+
+	styleLeft, _ := f.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+		Border:    border,
+		Font:      &excelize.Font{Size: 10},
+	})
+
+	b := &SummarySampleExcel{
+		Title:            "生产成本表",
+		SheetName:        "Sheet1",
+		Excel:            f,
+		AlignCenterStyle: styleLeft,
+	}
+
+	f.SetColWidth(b.SheetName, "A", "A", 6)
+	f.SetColWidth(b.SheetName, "B", "E", 16)
+	f.SetColWidth(b.SheetName, "F", "F", 20)
+	f.SetColWidth(b.SheetName, "G", "G", 16)
+	f.SetPageMargins(b.SheetName, excelize.PageMarginTop(0), excelize.PageMarginLeft(0), excelize.PageMarginRight(0))
+	return b
+}
+
+func (b *SummarySampleExcel) FormatToEmpty(str *string) {
+	if *str == "0" || *str == "0.000" {
+		*str = ""
+	}
+
+}

+ 246 - 0
boxcost/api/summary.go

@@ -0,0 +1,246 @@
+package api
+
+import (
+	"box-cost/db/model"
+	"box-cost/db/repo"
+	"errors"
+	"strings"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/xuri/excelize/v2"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+// 汇总
+func Summary(r *GinRouter) {
+
+	// 下载详细汇总
+	r.GET("/summary/download", SummaryDownload)
+	// 下载简单汇总
+	r.GET("/summary/sample/download", SummarySampleDownload)
+}
+
+type SupplierPlanSummary struct {
+	Plans      []*PlanSummary
+	SupplierId primitive.ObjectID
+}
+type PlanSummary struct {
+	Plan          *model.ProductPlan
+	IsSend, IsAck map[string]bool
+	Reviewed      map[string]int32
+	State         map[string]string
+	CreateTimes   map[string]time.Time
+}
+
+// /summary/download?planIds=id1,id2&supplierId=xxx
+func SummaryDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 获取planIds supplierId
+	_planIds := c.Query("planIds")       // id1,id2...
+	_supplierId := c.Query("supplierId") // 供应商id
+	planIds := strings.Split(_planIds, ",")
+
+	planIds = filter(planIds, func(s string) bool {
+		return s != ""
+	})
+
+	supplierId, _ := primitive.ObjectIDFromHex(_supplierId)
+
+	// 获取详情
+	if len(planIds) < 1 {
+		return nil, errors.New("数据不存在")
+	}
+	summaryPlans := []*PlanSummary{}
+	for _, _planId := range planIds {
+		id, err := primitive.ObjectIDFromHex(_planId)
+		if err != nil {
+			return nil, errors.New("非法id")
+		}
+		plan := &model.ProductPlan{}
+
+		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
+			CollectName: repo.CollectionProductPlan,
+			Query:       repo.Map{"_id": id},
+		}, plan)
+		if !found || err != nil {
+			continue
+		}
+
+		summaryPlan := GetPlanStatus(plan, apictx)
+		summaryPlans = append(summaryPlans, summaryPlan)
+
+	}
+	if len(summaryPlans) < 1 {
+		return nil, errors.New("数据不存在")
+	}
+
+	// 实例化表格,传入数据
+	f := excelize.NewFile()
+	index := f.NewSheet("Sheet1")
+	f.SetActiveSheet(index)
+	f.SetDefaultFont("宋体")
+	planSummaryExcel := NewPlanSummaryExcel(f)
+	planSummaryExcel.Content = &SupplierPlanSummary{
+		Plans:      summaryPlans,
+		SupplierId: supplierId,
+	}
+	// 绘制表格
+	planSummaryExcel.Draws()
+	c.Header("Content-Type", "application/octet-stream")
+	c.Header("Content-Disposition", "attachment; filename="+"planSummary.xlsx")
+	c.Header("Content-Transfer-Encoding", "binary")
+
+	err := f.Write(c.Writer)
+	if err != nil {
+		return nil, err
+	}
+
+	return nil, nil
+}
+
+// /summary/sample/download?planIds=id1,id2&supplierId=xxx
+func SummarySampleDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	// 获取planIds supplierId
+	_planIds := c.Query("planIds")       // id1,id2...
+	_supplierId := c.Query("supplierId") // 供应商id
+	planIds := strings.Split(_planIds, ",")
+
+	planIds = filter(planIds, func(s string) bool {
+		return s != ""
+	})
+
+	supplierId, _ := primitive.ObjectIDFromHex(_supplierId)
+
+	// 获取详情
+	if len(planIds) < 1 {
+		return nil, errors.New("数据不存在")
+	}
+	summaryPlans := []*PlanSummary{}
+	for _, _planId := range planIds {
+		id, err := primitive.ObjectIDFromHex(_planId)
+		if err != nil {
+			return nil, errors.New("非法id")
+		}
+		plan := &model.ProductPlan{}
+
+		found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
+			CollectName: repo.CollectionProductPlan,
+			Query:       repo.Map{"_id": id},
+		}, plan)
+		if !found || err != nil {
+			continue
+		}
+
+		summaryPlan := GetPlanStatus(plan, apictx)
+		summaryPlans = append(summaryPlans, summaryPlan)
+
+	}
+	if len(summaryPlans) < 1 {
+		return nil, errors.New("数据不存在")
+	}
+
+	// 实例化表格,传入数据
+	f := excelize.NewFile()
+	index := f.NewSheet("Sheet1")
+	f.SetActiveSheet(index)
+	f.SetDefaultFont("宋体")
+	planSummaryExcel := NewSummarySampleExcel(f)
+	planSummaryExcel.Content = &SupplierPlanSummary{
+		Plans:      summaryPlans,
+		SupplierId: supplierId,
+	}
+	// 绘制表格
+	planSummaryExcel.Draws()
+	c.Header("Content-Type", "application/octet-stream")
+	c.Header("Content-Disposition", "attachment; filename="+"planSummary.xlsx")
+	c.Header("Content-Transfer-Encoding", "binary")
+
+	err := f.Write(c.Writer)
+	if err != nil {
+		return nil, err
+	}
+
+	return nil, nil
+
+}
+
+func filter(arr []string, f func(string) bool) []string {
+	var filtered []string
+	for _, s := range arr {
+		if f(s) {
+			filtered = append(filtered, s)
+		}
+	}
+	return filtered
+}
+
+func GetPlanStatus(plan *model.ProductPlan, apictx *ApiSession) *PlanSummary {
+	billStates := map[string]string{}
+	billIsSend := map[string]bool{}
+	billReviewed := map[string]int32{}
+	billIsAck := map[string]bool{}
+	billCreateTimes := map[string]time.Time{}
+	if plan.Pack != nil && plan.Pack.Components != nil {
+		for _, comp := range plan.Pack.Components {
+			if comp.Stages != nil {
+				for _, stage := range comp.Stages {
+
+					if len(stage.BillId) > 0 {
+						collectName := ""
+						// 材料
+						if stage.BillType == 1 {
+							collectName = repo.CollectionBillPurchase
+						}
+						// 工艺
+						if stage.BillType == 2 {
+							collectName = repo.CollectionBillProduce
+						}
+						// 成品
+						if stage.BillType == 3 {
+							collectName = repo.CollectionBillProduct
+						}
+
+						ok, state := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
+							CollectName: collectName,
+							Query:       repo.Map{"_id": stage.BillId},
+							Project:     []string{"status", "isSend", "reviewed", "isAck", "serialNumber", "remark", "createTime"}})
+						if ok {
+							billStates[stage.BillId] = state["status"].(string)
+							if v, ok := state["isSend"]; ok {
+								billIsSend[stage.BillId] = v.(bool)
+
+							} else {
+								billIsSend[stage.BillId] = false
+							}
+							if v, ok := state["reviewed"]; ok {
+								billReviewed[stage.BillId] = v.(int32)
+							} else {
+								billReviewed[stage.BillId] = -1
+							}
+							if v, ok := state["isAck"]; ok {
+								billIsAck[stage.BillId] = v.(bool)
+
+							} else {
+								billIsAck[stage.BillId] = false
+							}
+							if v, ok := state["createTime"]; ok {
+								billCreateTimes[stage.BillId] = v.(primitive.DateTime).Time()
+
+							}
+
+						}
+					}
+
+				}
+			}
+		}
+	}
+	return &PlanSummary{
+		Plan:        plan,
+		IsSend:      billIsSend,
+		IsAck:       billIsAck,
+		Reviewed:    billReviewed,
+		State:       billStates,
+		CreateTimes: billCreateTimes,
+	}
+}

BIN
boxcost/thunder-file_0394cf77.xlsx