package ai import ( "context" "encoding/csv" "fmt" "net/http" "time" "github.com/youruser/base/internal/svc" "github.com/youruser/base/internal/types" "github.com/youruser/base/model" "github.com/zeromicro/go-zero/core/logx" ) type AiUsageExportLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewAiUsageExportLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AiUsageExportLogic { return &AiUsageExportLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *AiUsageExportLogic) AiUsageExport(req *types.AIUsageRecordListRequest, w http.ResponseWriter) error { // Get current user from context userId := req.UserId if userId == 0 { if uid, ok := l.ctx.Value("userId").(int64); ok { userId = uid } else if uidJson, ok2 := l.ctx.Value("userId").(float64); ok2 { userId = int64(uidJson) } } // Fetch all records (large page size for export) records, _, err := model.AIUsageRecordFindList(l.ctx, l.svcCtx.DB, userId, req.ModelId, req.Status, 1, 10000) if err != nil { return err } // Build lookup caches userMap := make(map[int64]string) providerMap := make(map[int64]string) for _, r := range records { if _, ok := userMap[r.UserId]; !ok { user, err := model.FindOne(l.ctx, l.svcCtx.DB, r.UserId) if err == nil { userMap[r.UserId] = user.Username } } if _, ok := providerMap[r.ProviderId]; !ok { p, err := model.AIProviderFindOne(l.ctx, l.svcCtx.DB, r.ProviderId) if err == nil { providerMap[r.ProviderId] = p.DisplayName } } } // Write CSV response filename := fmt.Sprintf("ai-usage-%s.csv", time.Now().Format("20060102")) w.Header().Set("Content-Type", "text/csv; charset=utf-8") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) // BOM for Excel UTF-8 support w.Write([]byte{0xEF, 0xBB, 0xBF}) writer := csv.NewWriter(w) defer writer.Flush() // Header row writer.Write([]string{"时间", "用户", "平台", "模型", "输入Tokens", "输出Tokens", "费用(¥)", "延迟(ms)", "状态", "错误信息"}) for _, r := range records { writer.Write([]string{ r.CreatedAt.Format("2006-01-02 15:04:05"), userMap[r.UserId], providerMap[r.ProviderId], r.ModelId, fmt.Sprintf("%d", r.InputTokens), fmt.Sprintf("%d", r.OutputTokens), fmt.Sprintf("%.4f", r.Cost), fmt.Sprintf("%d", r.LatencyMs), r.Status, r.ErrorMessage, }) } return nil }