package services import ( "context" "errors" "time" "quyun/v2/app/errorx" creator_dto "quyun/v2/app/http/v1/dto" "quyun/v2/database/models" "quyun/v2/pkg/consts" "github.com/google/uuid" "github.com/spf13/cast" "go.ipao.vip/gen/types" "gorm.io/gorm" ) // @provider type creator struct{} func (s *creator) Apply(ctx context.Context, form *creator_dto.ApplyForm) error { userID := ctx.Value(consts.CtxKeyUser) if userID == nil { return errorx.ErrUnauthorized } uid := cast.ToInt64(userID) tbl, q := models.TenantQuery.QueryContext(ctx) // Check if already has a tenant count, _ := q.Where(tbl.UserID.Eq(uid)).Count() if count > 0 { return errorx.ErrBadRequest.WithMsg("您已是创作者") } // Create Tenant tenant := &models.Tenant{ UserID: uid, Name: form.Name, // Bio/Avatar in config Code: uuid.NewString()[:8], // Generate random code UUID: types.UUID(uuid.New()), Status: consts.TenantStatusPendingVerify, } if err := q.Create(tenant); err != nil { return errorx.ErrDatabaseError } // Also add user as tenant_admin in tenant_users tu := &models.TenantUser{ TenantID: tenant.ID, UserID: uid, Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleTenantAdmin}, Status: consts.UserStatusVerified, } if err := models.TenantUserQuery.WithContext(ctx).Create(tu); err != nil { return errorx.ErrDatabaseError } return nil } func (s *creator) Dashboard(ctx context.Context) (*creator_dto.DashboardStats, error) { tid, err := s.getTenantID(ctx) if err != nil { return nil, err } // Mock stats for now or query // Followers: count tenant_users followers, _ := models.TenantUserQuery.WithContext(ctx).Where(models.TenantUserQuery.TenantID.Eq(tid)).Count() stats := &creator_dto.DashboardStats{ TotalFollowers: creator_dto.IntStatItem{Value: int(followers)}, TotalRevenue: creator_dto.FloatStatItem{Value: 0}, PendingRefunds: 0, NewMessages: 0, } return stats, nil } func (s *creator) ListContents(ctx context.Context, status, genre, keyword string) ([]creator_dto.ContentItem, error) { tid, err := s.getTenantID(ctx) if err != nil { return nil, err } tbl, q := models.ContentQuery.QueryContext(ctx) q = q.Where(tbl.TenantID.Eq(tid)) if status != "" { q = q.Where(tbl.Status.Eq(consts.ContentStatus(status))) } if genre != "" { q = q.Where(tbl.Genre.Eq(genre)) } if keyword != "" { q = q.Where(tbl.Title.Like("%" + keyword + "%")) } list, err := q.Order(tbl.CreatedAt.Desc()).Find() if err != nil { return nil, errorx.ErrDatabaseError } var data []creator_dto.ContentItem for _, item := range list { data = append(data, creator_dto.ContentItem{ ID: cast.ToString(item.ID), Title: item.Title, Genre: item.Genre, Views: int(item.Views), Likes: int(item.Likes), IsPurchased: false, }) } return data, nil } func (s *creator) CreateContent(ctx context.Context, form *creator_dto.ContentCreateForm) error { tid, err := s.getTenantID(ctx) if err != nil { return err } uid := cast.ToInt64(ctx.Value(consts.CtxKeyUser)) return models.Q.Transaction(func(tx *models.Query) error { // 1. Create Content content := &models.Content{ TenantID: tid, UserID: uid, Title: form.Title, Genre: form.Genre, Status: consts.ContentStatusPublished, } if err := tx.Content.WithContext(ctx).Create(content); err != nil { return err } // 2. Link Assets if len(form.MediaIDs) > 0 { var assets []*models.ContentAsset for i, mid := range form.MediaIDs { assets = append(assets, &models.ContentAsset{ TenantID: tid, UserID: uid, ContentID: content.ID, AssetID: cast.ToInt64(mid), Sort: int32(i), Role: consts.ContentAssetRoleMain, }) } if err := tx.ContentAsset.WithContext(ctx).Create(assets...); err != nil { return err } } // 3. Set Price price := &models.ContentPrice{ TenantID: tid, UserID: uid, ContentID: content.ID, PriceAmount: int64(form.Price * 100), // Convert to cents Currency: consts.CurrencyCNY, } if err := tx.ContentPrice.WithContext(ctx).Create(price); err != nil { return err } return nil }) } func (s *creator) UpdateContent(ctx context.Context, id string, form *creator_dto.ContentUpdateForm) error { return nil } func (s *creator) DeleteContent(ctx context.Context, id string) error { cid := cast.ToInt64(id) tid, err := s.getTenantID(ctx) if err != nil { return err } _, err = models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(cid), models.ContentQuery.TenantID.Eq(tid)).Delete() if err != nil { return errorx.ErrDatabaseError } return nil } func (s *creator) ListOrders(ctx context.Context, status, keyword string) ([]creator_dto.Order, error) { tid, err := s.getTenantID(ctx) if err != nil { return nil, err } tbl, q := models.OrderQuery.QueryContext(ctx) q = q.Where(tbl.TenantID.Eq(tid)) // Filters... list, err := q.Order(tbl.CreatedAt.Desc()).Find() if err != nil { return nil, errorx.ErrDatabaseError } var data []creator_dto.Order for _, o := range list { data = append(data, creator_dto.Order{ ID: cast.ToString(o.ID), Status: string(o.Status), // Enum conversion Amount: float64(o.AmountPaid) / 100.0, CreateTime: o.CreatedAt.Format(time.RFC3339), }) } return data, nil } func (s *creator) ProcessRefund(ctx context.Context, id string, form *creator_dto.RefundForm) error { return nil } func (s *creator) GetSettings(ctx context.Context) (*creator_dto.Settings, error) { tid, err := s.getTenantID(ctx) if err != nil { return nil, err } t, err := models.TenantQuery.WithContext(ctx).Where(models.TenantQuery.ID.Eq(tid)).First() if err != nil { return nil, errorx.ErrRecordNotFound } // Extract from t.Config return &creator_dto.Settings{ Name: t.Name, // Bio/Avatar from Config }, nil } func (s *creator) UpdateSettings(ctx context.Context, form *creator_dto.Settings) error { return nil } func (s *creator) ListPayoutAccounts(ctx context.Context) ([]creator_dto.PayoutAccount, error) { return []creator_dto.PayoutAccount{}, nil } func (s *creator) AddPayoutAccount(ctx context.Context, form *creator_dto.PayoutAccount) error { return nil } func (s *creator) RemovePayoutAccount(ctx context.Context, id string) error { return nil } func (s *creator) Withdraw(ctx context.Context, form *creator_dto.WithdrawForm) error { return nil } // Helpers func (s *creator) getTenantID(ctx context.Context) (int64, error) { userID := ctx.Value(consts.CtxKeyUser) if userID == nil { return 0, errorx.ErrUnauthorized } uid := cast.ToInt64(userID) // Simple check: User owns tenant t, err := models.TenantQuery.WithContext(ctx).Where(models.TenantQuery.UserID.Eq(uid)).First() if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return 0, errorx.ErrPermissionDenied.WithMsg("非创作者") } return 0, errorx.ErrDatabaseError } return t.ID, nil }