package service import ( "context" "encoding/json" "errors" "fmt" "github.com/xuri/excelize/v2" "io" "kra/internal/biz" "sort" ) type ExportService struct{ uc *biz.ExportUsecase } func NewExportService(uc *biz.ExportUsecase) *ExportService { return &ExportService{uc: uc} } func exportDTO(v *biz.ExportTemplate) map[string]any { conditions := make([]map[string]any, 0, len(v.Conditions)) for _, x := range v.Conditions { conditions = append(conditions, map[string]any{"from": x.From, "column": x.Column, "operator": x.Operator}) } joins := make([]map[string]any, 0, len(v.Joins)) for _, x := range v.Joins { joins = append(joins, map[string]any{"joins": x.Join, "table": x.Table, "on": x.On}) } return map[string]any{"ID": v.ID, "CreatedAt": v.CreatedAt, "UpdatedAt": v.UpdatedAt, "DeletedAt": nil, "dbName": v.DBName, "name": v.Name, "tableName": v.TableName, "templateID": v.TemplateID, "templateInfo": v.TemplateInfo, "sql": v.SQL, "importSql": v.ImportSQL, "limit": v.Limit, "order": v.Order, "conditions": conditions, "joinTemplate": joins} } func (s *ExportService) Create(ctx context.Context, v *biz.ExportTemplate) error { return s.uc.Repo().CreateExportTemplate(ctx, v) } func (s *ExportService) Update(ctx context.Context, v *biz.ExportTemplate) error { return s.uc.Repo().UpdateExportTemplate(ctx, v) } func (s *ExportService) Delete(ctx context.Context, ids []uint) error { return s.uc.Repo().DeleteExportTemplates(ctx, ids) } func (s *ExportService) Template(ctx context.Context, id uint, tid string) (map[string]any, error) { v, err := s.uc.Repo().FindExportTemplate(ctx, id, tid) if err != nil { return nil, err } return exportDTO(v), nil } func (s *ExportService) Templates(ctx context.Context, page, size int, q *biz.ExportTemplate) ([]map[string]any, int64, error) { items, total, err := s.uc.Repo().ListExportTemplates(ctx, page, size, q) if err != nil { return nil, 0, err } out := make([]map[string]any, 0, len(items)) for _, v := range items { out = append(out, exportDTO(v)) } return out, total, nil } func templateColumns(raw string) ([]string, map[string]string, error) { labels := map[string]string{} if err := json.Unmarshal([]byte(raw), &labels); err != nil { return nil, nil, err } keys := make([]string, 0, len(labels)) for key := range labels { keys = append(keys, key) } sort.Strings(keys) return keys, labels, nil } func (s *ExportService) Export(ctx context.Context, tid string, params map[string]string) ([]byte, string, error) { template, err := s.uc.Repo().FindExportTemplate(ctx, 0, tid) if err != nil { return nil, "", err } rows, _, err := s.uc.Repo().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.Repo().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.Repo().FindExportTemplate(ctx, 0, tid) if err != nil { return "", err } _, sql, err := s.uc.Repo().QueryExport(ctx, template, params) return sql, err } func (s *ExportService) Import(ctx context.Context, tid string, reader io.Reader) error { template, err := s.uc.Repo().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 nil } 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 rowIndex, row := range rows[1:] { item := map[string]any{} empty := true for column, value := range row { if column >= len(headers) { continue } key := reverse[headers[column]] if key != "" { item[key] = value if value != "" { empty = false } } } if !empty { items = append(items, item) } _ = rowIndex } if err = s.uc.Repo().ImportExportRows(ctx, template, items); err != nil { return fmt.Errorf("导入失败: %w", err) } return nil }