feat: tenant content publish
This commit is contained in:
@@ -95,6 +95,44 @@ func (*contentAdmin) create(ctx fiber.Ctx, tenant *models.Tenant, tenantUser *mo
|
||||
return services.Content.Create(ctx, tenant.ID, tenantUser.UserID, form)
|
||||
}
|
||||
|
||||
// publish
|
||||
//
|
||||
// @Summary 内容发布(创建+绑定资源+定价)
|
||||
// @Tags Tenant
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param tenantCode path string true "Tenant Code"
|
||||
// @Param form body dto.ContentPublishForm true "Form"
|
||||
// @Success 200 {object} dto.ContentPublishResponse
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/admin/contents/publish [post]
|
||||
// @Bind tenant local key(tenant)
|
||||
// @Bind tenantUser local key(tenant_user)
|
||||
// @Bind form body
|
||||
func (*contentAdmin) publish(ctx fiber.Ctx, tenant *models.Tenant, tenantUser *models.TenantUser, form *dto.ContentPublishForm) (*dto.ContentPublishResponse, error) {
|
||||
if err := requireTenantAdmin(tenantUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tenant_id": tenant.ID,
|
||||
"user_id": tenantUser.UserID,
|
||||
}).Info("tenant.admin.contents.publish")
|
||||
|
||||
res, err := services.Content.Publish(ctx.Context(), tenant.ID, tenantUser.UserID, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.ContentPublishResponse{
|
||||
Content: res.Content,
|
||||
Price: res.Price,
|
||||
CoverAssets: res.CoverAssets,
|
||||
MainAssets: res.MainAssets,
|
||||
ContentTypes: res.ContentTypes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// update
|
||||
//
|
||||
// @Summary 更新内容(标题/描述/状态等)
|
||||
|
||||
55
backend/app/http/tenant/dto/content_admin_publish.go
Normal file
55
backend/app/http/tenant/dto/content_admin_publish.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"quyun/v2/database/models"
|
||||
"quyun/v2/pkg/consts"
|
||||
)
|
||||
|
||||
// ContentPublishForm 租户管理员提交“内容发布”表单(创建内容 + 绑定资源 + 定价)。
|
||||
// 说明:
|
||||
// - 内容类型支持组合:文字/音频/视频/多图可同时存在;
|
||||
// - 文字内容通过 Detail 是否为空来判断;
|
||||
// - 音频/视频/多图通过对应资源列表是否为空来判断(资源需为 ready 且属于当前租户)。
|
||||
type ContentPublishForm struct {
|
||||
// Title 标题:用于列表展示与搜索;必填。
|
||||
Title string `json:"title,omitempty"`
|
||||
// Summary 简介:用于列表/卡片展示的短文本;可选,建议 <= 256 字符。
|
||||
Summary string `json:"summary,omitempty"`
|
||||
// Detail 详细:用于详情页的长文本;可选;当非空时视为“文字内容”类型存在。
|
||||
Detail string `json:"detail,omitempty"`
|
||||
// Tags 标签:用于分类/检索;字符串数组;会做 trim/去重;可为空。
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
|
||||
// CoverAssetIDs 展示图(封面图)资源 ID 列表:1-3 张;每个资源必须为 image/main/ready。
|
||||
CoverAssetIDs []int64 `json:"cover_asset_ids,omitempty"`
|
||||
// AudioAssetIDs 音频资源 ID 列表:可为空;每个资源必须为 audio/main/ready。
|
||||
AudioAssetIDs []int64 `json:"audio_asset_ids,omitempty"`
|
||||
// VideoAssetIDs 视频资源 ID 列表:可为空;每个资源必须为 video/main/ready。
|
||||
VideoAssetIDs []int64 `json:"video_asset_ids,omitempty"`
|
||||
// ImageAssetIDs 多图内容资源 ID 列表:可为空;每个资源必须为 image/main/ready;数量 >= 2 时视为“多图内容”类型存在。
|
||||
ImageAssetIDs []int64 `json:"image_asset_ids,omitempty"`
|
||||
|
||||
// PriceAmount 价格:单位为分;0 表示免费;必填(前端可默认填 0)。
|
||||
PriceAmount int64 `json:"price_amount,omitempty"`
|
||||
// Currency 币种:当前固定为 CNY;可不传(后端默认 CNY)。
|
||||
Currency consts.Currency `json:"currency,omitempty"`
|
||||
|
||||
// Visibility 可见性:控制“详情页”可见范围;默认 tenant_only。
|
||||
Visibility consts.ContentVisibility `json:"visibility,omitempty"`
|
||||
// PreviewSeconds 试看秒数:仅对 preview 资源生效;默认 60;必须为正整数。
|
||||
PreviewSeconds *int32 `json:"preview_seconds,omitempty"`
|
||||
}
|
||||
|
||||
// ContentPublishResponse 内容发布结果(便于前端一次性拿到核心信息)。
|
||||
type ContentPublishResponse struct {
|
||||
// Content 内容主体(包含标题/简介/详细/状态等)。
|
||||
Content *models.Content `json:"content"`
|
||||
// Price 定价信息(单位分)。
|
||||
Price *models.ContentPrice `json:"price"`
|
||||
// CoverAssets 封面图绑定结果(role=cover)。
|
||||
CoverAssets []*models.ContentAsset `json:"cover_assets,omitempty"`
|
||||
// MainAssets 主资源绑定结果(role=main;可能包含音频/视频/图片)。
|
||||
MainAssets []*models.ContentAsset `json:"main_assets,omitempty"`
|
||||
// ContentTypes 内容类型列表:text/audio/video/image/multi_image(用于前端展示)。
|
||||
ContentTypes []string `json:"content_types,omitempty"`
|
||||
}
|
||||
@@ -112,6 +112,13 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
PathParam[int64]("contentID"),
|
||||
Body[dto.ContentAssetAttachForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/admin/contents/publish -> contentAdmin.publish")
|
||||
router.Post("/t/:tenantCode/v1/admin/contents/publish"[len(r.Path()):], DataFunc3(
|
||||
r.contentAdmin.publish,
|
||||
Local[*models.Tenant]("tenant"),
|
||||
Local[*models.TenantUser]("tenant_user"),
|
||||
Body[dto.ContentPublishForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Put /t/:tenantCode/v1/admin/contents/:contentID/price -> contentAdmin.upsertPrice")
|
||||
router.Put("/t/:tenantCode/v1/admin/contents/:contentID/price"[len(r.Path()):], DataFunc4(
|
||||
r.contentAdmin.upsertPrice,
|
||||
|
||||
Reference in New Issue
Block a user