package excel import ( "electricity_bill_calc/logger" "electricity_bill_calc/model" "fmt" "io" "github.com/samber/lo" "github.com/xuri/excelize/v2" "go.uber.org/zap" ) var meterArchiveRecognizers = []*ColumnRecognizer{ {Pattern: [][]string{{"表号"}}, Tag: "code", MatchIndex: -1, MustFill: true}, {Pattern: [][]string{{"表址", "地址", "户址"}}, Tag: "address", MatchIndex: -1}, {Pattern: [][]string{{"类型"}}, Tag: "meterType", MatchIndex: -1, MustFill: true}, {Pattern: [][]string{{"建筑"}}, Tag: "building", MatchIndex: -1}, {Pattern: [][]string{{"楼层"}}, Tag: "onFloor", MatchIndex: -1}, {Pattern: [][]string{{"面积"}}, Tag: "area", MatchIndex: -1}, {Pattern: [][]string{{"倍率"}}, Tag: "ratio", MatchIndex: -1, MustFill: true}, {Pattern: [][]string{{"序号"}}, Tag: "seq", MatchIndex: -1, MustFill: true}, {Pattern: [][]string{{"抄表"}, {"时间", "日期"}}, Tag: "readAt", MatchIndex: -1, MustFill: true}, {Pattern: [][]string{{"有功", "表底", "底数"}, {"总"}}, Tag: "overall", MatchIndex: -1, MustFill: true}, {Pattern: [][]string{{"有功", "表底", "底数"}, {"尖"}}, Tag: "critical", MatchIndex: -1}, {Pattern: [][]string{{"有功", "表底", "底数"}, {"峰"}}, Tag: "peak", MatchIndex: -1}, {Pattern: [][]string{{"有功", "表底", "底数"}, {"平"}}, Tag: "flat", MatchIndex: -1}, {Pattern: [][]string{{"有功", "表底", "底数"}, {"谷"}}, Tag: "valley", MatchIndex: -1}, } func NewMeterArchiveExcelAnalyzer(file io.Reader) (*ExcelAnalyzer[model.MeterImportRow], error) { return NewExcelAnalyzer[model.MeterImportRow](file, meterArchiveRecognizers) } type MeterArchiveExcelTemplateGenerator struct { file *excelize.File log *zap.Logger } func NewMeterArchiveExcelTemplateGenerator() *MeterArchiveExcelTemplateGenerator { return &MeterArchiveExcelTemplateGenerator{ file: excelize.NewFile(), log: logger.Named("Excel", "MeterArchive"), } } func (MeterArchiveExcelTemplateGenerator) titles() *[]interface{} { return &[]interface{}{ "序号", "表址", "表号", "表计类型", "倍率", "所在建筑", "所在楼层", "辖盖面积", "抄表时间", "有功(总)", "有功(尖)", "有功(峰)", "有功(平)", "有功(谷)", } } func (g *MeterArchiveExcelTemplateGenerator) Close() { g.file.Close() } func (g MeterArchiveExcelTemplateGenerator) WriteTo(w io.Writer) (int64, error) { return g.file.WriteTo(w) } func (g *MeterArchiveExcelTemplateGenerator) WriteTemplateData(buildings []*model.ParkBuilding) error { var err error defaultSheet := g.file.GetSheetName(0) g.log.Debug("选定默认输出表格", zap.String("sheet", defaultSheet)) err = g.file.SetColWidth(defaultSheet, "B", "I", 20) if err != nil { g.log.Error("未能设定长型列宽。", zap.Error(err)) return fmt.Errorf("未能设定长型列宽,%w", err) } err = g.file.SetColWidth(defaultSheet, "J", "N", 15) if err != nil { g.log.Error("未能设定短型列宽。", zap.Error(err)) return fmt.Errorf("未能设定短型列宽,%w", err) } err = g.file.SetSheetRow(defaultSheet, "A1", g.titles()) if err != nil { g.log.Error("未能输出模板标题。", zap.Error(err)) return fmt.Errorf("未能输出模板标题,%w", err) } err = g.file.SetRowHeight(defaultSheet, 1, 20) if err != nil { g.log.Error("未能设定标题行高度。", zap.Error(err)) return fmt.Errorf("未能设定标题行高度,%w", err) } dateTimeExp := "yyyy-mm-dd hh:mm;@" dateTimeColStyle, err := g.file.NewStyle(&excelize.Style{ CustomNumFmt: &dateTimeExp, }) if err != nil { g.log.Error("未能创建日期时间格式。", zap.Error(err)) return fmt.Errorf("未能创建日期时间格式,%w", err) } g.file.SetCellStyle(defaultSheet, "I2", "I1048576", dateTimeColStyle) numExp := "0.0000;@" numColStyle, err := g.file.NewStyle(&excelize.Style{ CustomNumFmt: &numExp, }) if err != nil { g.log.Error("未能创建抄表数字格式。", zap.Error(err)) return fmt.Errorf("未能创建抄表数字格式,%w", err) } g.file.SetCellStyle(defaultSheet, "J2", "N1048576", numColStyle) meterInstallationTypeValidation := excelize.NewDataValidation(false) meterInstallationTypeValidation.SetDropList([]string{"商户表", "公共表", "楼道表"}) meterInstallationTypeValidation.Sqref = "D2:D1048576" err = g.file.AddDataValidation(defaultSheet, meterInstallationTypeValidation) if err != nil { g.log.Error("未能设定表计类型选择器。", zap.Error(err)) return fmt.Errorf("未能设定表计类型选择器,%w", err) } buildingValidation := excelize.NewDataValidation(true) buildingNames := lo.Map(buildings, func(b *model.ParkBuilding, _ int) string { return b.Name }) buildingValidation.SetDropList(buildingNames) buildingValidation.Sqref = "F2:F1048576" err = g.file.AddDataValidation(defaultSheet, buildingValidation) if err != nil { g.log.Error("未能设定所在建筑选择器。", zap.Error(err)) return fmt.Errorf("未能设定所在建筑选择器,%w", err) } return nil }