package service import ( "context" "encoding/json" "errors" "fmt" "io" "strings" "github.com/xuri/excelize/v2" ) func templateColumns(raw string) ([]string, map[string]string, error) { labels := map[string]string{} decoder := json.NewDecoder(strings.NewReader(raw)) token, err := decoder.Token() if err != nil || token != json.Delim('{') { return nil, nil, err } keys := make([]string, 0) for decoder.More() { keyToken, tokenErr := decoder.Token() if tokenErr != nil { return nil, nil, tokenErr } key := keyToken.(string) var label string if tokenErr = decoder.Decode(&label); tokenErr != nil { return nil, nil, tokenErr } keys = append(keys, key) labels[key] = label } if _, err = decoder.Token(); err != nil { return nil, nil, err } return keys, labels, nil } func (s *ExportService) Export(ctx context.Context, tid string, params map[string]string) ([]byte, string, error) { template, err := s.uc.FindExportTemplate(ctx, 0, tid) if err != nil { return nil, "", err } rows, _, err := s.uc.QueryExport(ctx, template, params) if err != nil { return nil, "", err } keys, labels, err := templateColumns(template.TemplateInfo) if err != nil { return nil, "", err } file := excelize.NewFile() sheet := file.GetSheetName(0) for column, key := range keys { cell, _ := excelize.CoordinatesToCellName(column+1, 1) _ = file.SetCellValue(sheet, cell, labels[key]) } for rowIndex, row := range rows { for column, key := range keys { cell, _ := excelize.CoordinatesToCellName(column+1, rowIndex+2) _ = file.SetCellValue(sheet, cell, row[key]) } } buffer, err := file.WriteToBuffer() _ = file.Close() if err != nil { return nil, "", err } return buffer.Bytes(), template.Name + ".xlsx", nil } func (s *ExportService) ExportBlankTemplate(ctx context.Context, tid string) ([]byte, string, error) { template, err := s.uc.FindExportTemplate(ctx, 0, tid) if err != nil { return nil, "", err } keys, labels, err := templateColumns(template.TemplateInfo) if err != nil { return nil, "", err } file := excelize.NewFile() sheet := file.GetSheetName(0) for column, key := range keys { cell, _ := excelize.CoordinatesToCellName(column+1, 1) _ = file.SetCellValue(sheet, cell, labels[key]) } buffer, err := file.WriteToBuffer() _ = file.Close() if err != nil { return nil, "", err } return buffer.Bytes(), template.Name + "_template.xlsx", nil } func (s *ExportService) Preview(ctx context.Context, tid string, params map[string]string) (string, error) { template, err := s.uc.FindExportTemplate(ctx, 0, tid) if err != nil { return "", err } return s.uc.PreviewExport(ctx, template, params) } func (s *ExportService) Import(ctx context.Context, tid string, reader io.Reader) error { template, err := s.uc.FindExportTemplate(ctx, 0, tid) if err != nil { return err } file, err := excelize.OpenReader(reader) if err != nil { return err } defer file.Close() sheets := file.GetSheetList() if len(sheets) == 0 { return errors.New("工作簿没有工作表") } rows, err := file.GetRows(sheets[0]) if err != nil { return err } if len(rows) < 2 { return errors.New("Excel data is not enough.\nIt should contain title row and data") } keys, labels, err := templateColumns(template.TemplateInfo) if err != nil { return err } reverse := map[string]string{} for _, key := range keys { reverse[labels[key]] = key } headers := rows[0] items := make([]map[string]any, 0, len(rows)-1) for _, row := range rows[1:] { item := map[string]any{} for column, value := range row { if column >= len(headers) { continue } key := reverse[headers[column]] if key != "" { item[key] = value } } items = append(items, item) } if err = s.uc.ImportExportRows(ctx, template, items); err != nil { return fmt.Errorf("导入失败: %w", err) } return nil }