forked from free-lancers/electricity_bill_calc_service
		
	refactor(meter):表计档案模板的下载改为使用Excel 生成的方法实现。
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							| @@ -1,6 +1,7 @@ | ||||
| package controller | ||||
|  | ||||
| import ( | ||||
| 	"electricity_bill_calc/excel" | ||||
| 	"electricity_bill_calc/logger" | ||||
| 	"electricity_bill_calc/model" | ||||
| 	"electricity_bill_calc/repository" | ||||
| @@ -160,10 +161,24 @@ func downloadMeterArchiveTemplate(c *fiber.Ctx) error { | ||||
| 		meterLog.Error("无法下载指定的园区表计登记模板,无法获取园区信息", zap.Error(err)) | ||||
| 		return result.NotFound(err.Error()) | ||||
| 	} | ||||
| 	return c.Download( | ||||
| 		"./assets/meter_04kv_template.xlsx", | ||||
| 		fmt.Sprintf("%s_表计档案.xlsx", parkDetail.Name), | ||||
| 	) | ||||
| 	buildings, err := repository.ParkRepository.RetrieveParkBuildings(parkId) | ||||
| 	if err != nil { | ||||
| 		meterLog.Error("无法下载指定的园区表计登记模板,无法获取园区建筑列表", zap.Error(err)) | ||||
| 		return result.NotFound(fmt.Sprintf("无法获取园区建筑列表,%s", err.Error())) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err)) | ||||
| 		return result.NotFound(fmt.Sprintf("无法生成表计登记模板,%s", err.Error())) | ||||
| 	} | ||||
| 	c.Status(fiber.StatusOK) | ||||
| 	c.Set(fiber.HeaderContentType, fiber.MIMEOctetStream) | ||||
| 	c.Set("Content-Transfer-Encoding", "binary") | ||||
| 	c.Set(fiber.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s-表计登记模板.xlsx", parkDetail.Name)) | ||||
| 	templateGenerator := excel.NewMeterArchiveExcelTemplateGenerator() | ||||
| 	defer templateGenerator.Close() | ||||
| 	err = templateGenerator.WriteTemplateData(buildings) | ||||
| 	templateGenerator.WriteTo(c.Response().BodyWriter()) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // 从Excel文件中导入表计档案 | ||||
|   | ||||
| @@ -1,8 +1,14 @@ | ||||
| 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{ | ||||
| @@ -25,3 +31,89 @@ var meterArchiveRecognizers = []*ColumnRecognizer{ | ||||
| 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("Select default template sheet", 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) | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,8 @@ package excel | ||||
| import ( | ||||
| 	"electricity_bill_calc/model" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/xuri/excelize/v2" | ||||
| ) | ||||
|  | ||||
| var meterReadingsRecognizers = []*ColumnRecognizer{ | ||||
| @@ -17,3 +19,13 @@ var meterReadingsRecognizers = []*ColumnRecognizer{ | ||||
| func NewMeterReadingsExcelAnalyzer(file io.Reader) (*ExcelAnalyzer[model.ReadingImportRow], error) { | ||||
| 	return NewExcelAnalyzer[model.ReadingImportRow](file, meterReadingsRecognizers) | ||||
| } | ||||
|  | ||||
| type MeterReadingsExcelTemplateGenerator struct { | ||||
| 	file *excelize.File | ||||
| } | ||||
|  | ||||
| func NewMeterReadingsExcelTemplateGenerator() *MeterReadingsExcelTemplateGenerator { | ||||
| 	return &MeterReadingsExcelTemplateGenerator{ | ||||
| 		file: excelize.NewFile(), | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -660,6 +660,12 @@ func (ms _MeterService) RecordReading(pid, meterCode string, form *vo.MeterReadi | ||||
|  | ||||
| // 获取指定园区的全部待抄表计列表,并将其输出到Excel文件模板中,提供生成文件的二进制内容 | ||||
| func (ms _MeterService) GenerateParkMeterReadingTemplate(pid string, meters []*model.SimpleMeterDocument) ([]byte, error) { | ||||
| 	// 步骤1:复制公用模板文件到临时文件夹,文件以园区ID命名 | ||||
|  | ||||
| 	// 步骤2:打开复制后的园区文件 | ||||
| 	// 步骤3:获取园区中需要抄表的表计列表 | ||||
| 	// 步骤4:循环表计列表,将表计信息写入到Excel文件中 | ||||
| 	// 步骤5:将生成的临时文件的具体二进制内容返回给调用者 | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user