package export import ( "database/sql" "io" "github.com/xuri/excelize/v2" ) // flatSheet 是「全部成绩(单页)」唯一那张表的表名。 const flatSheet = "全部成绩" // FlatWorkbook 是「全部成绩(单页)」的内容:所有小项、所有成绩平铺在一张表里。 // 与「全部」多 sheet 工作簿同源(都来自 LoadEventWorkbook),只是排版方式不同。 type FlatWorkbook struct { Meta Meta Sheets []EventSheet } // flatColumns 是单页表的列:在分项成绩列前补「大项 / 小项 / 组别」三列, // 让每行脱离 sheet 标题也能自解释;后 8 列直接复用 eventColumns,避免两处口径漂移。 var flatColumns = append([]column{ {"大项", 14, kindText}, {"小项", 18, kindText}, {"组别", 14, kindText}, }, eventColumns...) // ExportFlatXLSX 导出「全部成绩(单页)」到 dst。 // 仅测试使用(生产走 Load* + Write* 直接写响应体,不落盘)——见 saveWorkbook 的说明。 func ExportFlatXLSX(db *sql.DB, dst string, opts Options) error { wb, err := LoadFlatWorkbook(db, opts) if err != nil { return err } f, err := flatFile(wb) if err != nil { return err } return saveWorkbook(f, dst) } // WriteFlatXLSX 把「全部成绩(单页)」写成 xlsx 流,供 HTTP 直接响应下载。 func WriteFlatXLSX(w io.Writer, wb FlatWorkbook) error { f, err := flatFile(wb) if err != nil { return err } return f.Write(w) } // LoadFlatWorkbook 读取全部小项(eventID = 0)的成绩,保留「全部」多 sheet 版里的小项顺序。 func LoadFlatWorkbook(db *sql.DB, opts Options) (FlatWorkbook, error) { events, err := LoadEventWorkbook(db, 0, opts) if err != nil { return FlatWorkbook{}, err } return FlatWorkbook{Meta: events.Meta, Sheets: events.Sheets}, nil } func flatFile(wb FlatWorkbook) (*excelize.File, error) { return buildWorkbook(flatSheet, func(f *excelize.File, st *styleSet) error { meta := wb.Meta.normalized() name := sanitizeSheetName(flatSheet) if err := addSheet(f, name); err != nil { return err } return writeSheet(f, st, name, meta, sheetTitle(meta, flatSheet), flatColumns, flatRows(wb.Sheets)) }) } // flatRows 把小项 sheet 按原顺序拼成一份平铺行,每行前面补上所属的大项 / 小项 / 组别。 // 大项、小项、组别直接取 EventSheet 的结构化字段(LoadEventWorkbook 建 sheet 时已填好), // 不去解析 sheet 标题字符串。 func flatRows(sheets []EventSheet) [][]any { var out [][]any for _, sh := range sheets { ctx := []any{sh.SportName, sh.EventName, sh.Category} for _, row := range eventRows(sh.Rows) { out = append(out, append(append([]any{}, ctx...), row...)) } } return out }