enhance(meter):部署抄表模板下载功能。
This commit is contained in:
parent
542efdac86
commit
e2a61d58ac
|
@ -37,6 +37,9 @@ func InitializeMeterHandlers(router *fiber.App) {
|
||||||
router.Get("/meter/choice", security.EnterpriseAuthorize, listUnboundMeters)
|
router.Get("/meter/choice", security.EnterpriseAuthorize, listUnboundMeters)
|
||||||
router.Get("/meter/choice/tenement", security.EnterpriseAuthorize, listUnboundTenementMeters)
|
router.Get("/meter/choice/tenement", security.EnterpriseAuthorize, listUnboundTenementMeters)
|
||||||
router.Get("/reading/:pid", security.EnterpriseAuthorize, queryMeterReadings)
|
router.Get("/reading/:pid", security.EnterpriseAuthorize, queryMeterReadings)
|
||||||
|
router.Post("/reading/:pid/:code", security.EnterpriseAuthorize, recordMeterReading)
|
||||||
|
router.Put("/reading/:pid/:code/:reading", security.EnterpriseAuthorize, updateMeterReading)
|
||||||
|
router.Get("/reading/:pid/template", security.EnterpriseAuthorize, downloadMeterReadingsTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询指定园区下的表计信息
|
// 查询指定园区下的表计信息
|
||||||
|
@ -170,13 +173,19 @@ func downloadMeterArchiveTemplate(c *fiber.Ctx) error {
|
||||||
meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err))
|
meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err))
|
||||||
return result.NotFound(fmt.Sprintf("无法生成表计登记模板,%s", err.Error()))
|
return result.NotFound(fmt.Sprintf("无法生成表计登记模板,%s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
templateGenerator := excel.NewMeterArchiveExcelTemplateGenerator()
|
||||||
|
defer templateGenerator.Close()
|
||||||
|
err = templateGenerator.WriteTemplateData(buildings)
|
||||||
|
if err != nil {
|
||||||
|
meterLog.Error("无法下载指定的园区表计登记模板,无法生成表计登记模板", zap.Error(err))
|
||||||
|
return result.Error(fiber.StatusInternalServerError, fmt.Sprintf("无法生成表计登记模板,%s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
c.Status(fiber.StatusOK)
|
c.Status(fiber.StatusOK)
|
||||||
c.Set(fiber.HeaderContentType, fiber.MIMEOctetStream)
|
c.Set(fiber.HeaderContentType, fiber.MIMEOctetStream)
|
||||||
c.Set("Content-Transfer-Encoding", "binary")
|
c.Set("Content-Transfer-Encoding", "binary")
|
||||||
c.Set(fiber.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s-表计登记模板.xlsx", parkDetail.Name))
|
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())
|
templateGenerator.WriteTo(c.Response().BodyWriter())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -564,7 +573,44 @@ func updateMeterReading(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载指定园区的表计抄表模板
|
// 下载指定园区的表计抄表模板
|
||||||
func downlongMeterReadingTemplate(c *fiber.Ctx) error {
|
func downloadMeterReadingsTemplate(c *fiber.Ctx) error {
|
||||||
|
parkId := c.Params("pid")
|
||||||
|
meterLog.Info("下载指定的园区表计抄表模板", zap.String("park id", parkId))
|
||||||
|
result := response.NewResult(c)
|
||||||
|
session, err := _retreiveSession(c)
|
||||||
|
if err != nil {
|
||||||
|
meterLog.Error("无法下载指定的园区表计抄表模板,无法获取当前用户会话", zap.Error(err))
|
||||||
|
return result.Unauthorized(err.Error())
|
||||||
|
}
|
||||||
|
if ok, err := checkParkBelongs(meterLog, parkId, session, &result); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
parkDetail, err := repository.ParkRepository.RetrieveParkDetail(parkId)
|
||||||
|
if err != nil {
|
||||||
|
meterLog.Error("无法下载指定的园区表计登记模板,无法获取园区信息", zap.Error(err))
|
||||||
|
return result.NotFound(err.Error())
|
||||||
|
}
|
||||||
|
meterDocs, err := repository.MeterRepository.ListMeterDocForTemplate(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()))
|
||||||
|
}
|
||||||
|
templateGenerator := excel.NewMeterReadingsExcelTemplateGenerator()
|
||||||
|
defer templateGenerator.Close()
|
||||||
|
err = templateGenerator.WriteTemplateData(meterDocs)
|
||||||
|
if err != nil {
|
||||||
|
meterLog.Error("无法下载指定的园区表计抄表模板,无法生成表计抄表模板", zap.Error(err))
|
||||||
|
return result.Error(fiber.StatusInternalServerError, 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.WriteTo(c.Response().BodyWriter())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package excel
|
package excel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"electricity_bill_calc/logger"
|
||||||
"electricity_bill_calc/model"
|
"electricity_bill_calc/model"
|
||||||
|
"electricity_bill_calc/tools"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/xuri/excelize/v2"
|
"github.com/xuri/excelize/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
var meterReadingsRecognizers = []*ColumnRecognizer{
|
var meterReadingsRecognizers = []*ColumnRecognizer{
|
||||||
|
@ -22,10 +26,117 @@ func NewMeterReadingsExcelAnalyzer(file io.Reader) (*ExcelAnalyzer[model.Reading
|
||||||
|
|
||||||
type MeterReadingsExcelTemplateGenerator struct {
|
type MeterReadingsExcelTemplateGenerator struct {
|
||||||
file *excelize.File
|
file *excelize.File
|
||||||
|
log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMeterReadingsExcelTemplateGenerator() *MeterReadingsExcelTemplateGenerator {
|
func NewMeterReadingsExcelTemplateGenerator() *MeterReadingsExcelTemplateGenerator {
|
||||||
return &MeterReadingsExcelTemplateGenerator{
|
return &MeterReadingsExcelTemplateGenerator{
|
||||||
file: excelize.NewFile(),
|
file: excelize.NewFile(),
|
||||||
|
log: logger.Named("Excel", "MeterReadings"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (MeterReadingsExcelTemplateGenerator) titles() *[]interface{} {
|
||||||
|
return &[]interface{}{
|
||||||
|
"抄表序号",
|
||||||
|
"抄表时间",
|
||||||
|
"表计编号",
|
||||||
|
"表计名称",
|
||||||
|
"商户名称",
|
||||||
|
"倍率",
|
||||||
|
"有功(总)",
|
||||||
|
"有功(尖)",
|
||||||
|
"有功(峰)",
|
||||||
|
"有功(谷)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g MeterReadingsExcelTemplateGenerator) Close() {
|
||||||
|
g.file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g MeterReadingsExcelTemplateGenerator) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return g.file.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g MeterReadingsExcelTemplateGenerator) WriteTemplateData(meters []*model.SimpleMeterDocument) error {
|
||||||
|
var err error
|
||||||
|
defaultSheet := g.file.GetSheetName(0)
|
||||||
|
g.log.Debug("选定默认输出表格", zap.String("sheet", defaultSheet))
|
||||||
|
err = g.file.SetColWidth(defaultSheet, "A", "E", 30)
|
||||||
|
if err != nil {
|
||||||
|
g.log.Error("未能设定长型单元格的宽度。", zap.Error(err))
|
||||||
|
return fmt.Errorf("未能设定长型单元格的宽度,%w", err)
|
||||||
|
}
|
||||||
|
err = g.file.SetColWidth(defaultSheet, "F", "F", 10)
|
||||||
|
if err != nil {
|
||||||
|
g.log.Error("未能设定倍率单元格的宽度。", zap.Error(err))
|
||||||
|
return fmt.Errorf("未能设定倍率单元格的宽度,%w", err)
|
||||||
|
}
|
||||||
|
err = g.file.SetColWidth(defaultSheet, "G", "J", 20)
|
||||||
|
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, 30)
|
||||||
|
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, "B2", "B1048576", 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, "F2", "J1048576", numColStyle)
|
||||||
|
|
||||||
|
stream, err := g.file.NewStreamWriter(defaultSheet)
|
||||||
|
if err != nil {
|
||||||
|
g.log.Error("未能创建流式写入器。", zap.Error(err))
|
||||||
|
return fmt.Errorf("未能创建流式写入器,%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, meter := range meters {
|
||||||
|
startCell, err := excelize.CoordinatesToCellName(1, i+2)
|
||||||
|
if err != nil {
|
||||||
|
g.log.Error("未能定位输出数据的起始单元格。", zap.Error(err))
|
||||||
|
return fmt.Errorf("未能定位输出数据的起始单元格,%w", err)
|
||||||
|
}
|
||||||
|
if err := stream.SetRow(startCell, []interface{}{
|
||||||
|
meter.Seq,
|
||||||
|
"",
|
||||||
|
meter.Code,
|
||||||
|
tools.DefaultTo(meter.Address, ""),
|
||||||
|
tools.DefaultTo(meter.TenementName, ""),
|
||||||
|
meter.Ratio,
|
||||||
|
}); err != nil {
|
||||||
|
g.log.Error("向模板写入数据出现错误。", zap.Error(err))
|
||||||
|
return fmt.Errorf("向模板写入数据出现错误,%w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = stream.Flush(); err != nil {
|
||||||
|
g.log.Error("未能刷新流式写入器。", zap.Error(err))
|
||||||
|
return fmt.Errorf("未能刷新流式写入器,%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user