package report import ( "fmt" "strings" "text/template" "time" ) // ============================ // 模板渲染(80mm 热敏纸适配) // ============================ // TemplateConfig 模板渲染配置 type TemplateConfig struct { Width int // 行宽(字符数),80mm 热敏纸建议 42 } // DefaultTemplateConfig 默认配置(80mm 热敏纸) func DefaultTemplateConfig() TemplateConfig { return TemplateConfig{Width: 42} } // RenderTemplate 使用 Go template 渲染报告 // tpl 为模板内容,data 为报告数据 func RenderTemplate(tpl string, data interface{}, cfg TemplateConfig) (string, error) { if cfg.Width <= 0 { cfg.Width = 42 } funcMap := template.FuncMap{ // 格式化辅助 "timeFmt": func(t time.Time) string { return t.Format("2006-01-02 15:04:05") }, // 字符串截断/填充到固定宽度 "trunc": func(s string, n int) string { r := []rune(s) if len(r) <= n { return string(r) } return string(r[:n-1]) + "…" }, // 左侧填充(右对齐) "padRight": func(s string, n int) string { r := []rune(s) if len(r) >= n { return string(r[:n]) } return s + strings.Repeat(" ", n-len(r)) }, // 分隔线 "hr": func(sharp rune) string { return strings.Repeat(string(sharp), cfg.Width) }, } t, err := template.New("report").Funcs(funcMap).Parse(tpl) if err != nil { return "", fmt.Errorf("解析模板失败: %w", err) } var sb strings.Builder if err := t.Execute(&sb, data); err != nil { return "", fmt.Errorf("渲染模板失败: %w", err) } return sb.String(), nil }