feat: add superadmin creator review and coupon governance
This commit is contained in:
@@ -29,6 +29,40 @@ func (c *coupons) List(ctx fiber.Ctx, filter *dto.SuperCouponListFilter) (*reque
|
||||
return services.Super.ListCoupons(ctx, filter)
|
||||
}
|
||||
|
||||
// List coupon grants
|
||||
//
|
||||
// @Router /super/v1/coupon-grants [get]
|
||||
// @Summary List coupon grants
|
||||
// @Description List coupon grant records across tenants
|
||||
// @Tags Coupon
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number"
|
||||
// @Param limit query int false "Page size"
|
||||
// @Success 200 {object} requests.Pager{items=[]dto.SuperCouponGrantItem}
|
||||
// @Bind filter query
|
||||
func (c *coupons) ListGrants(ctx fiber.Ctx, filter *dto.SuperCouponGrantListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListCouponGrants(ctx, filter)
|
||||
}
|
||||
|
||||
// Update coupon status
|
||||
//
|
||||
// @Router /super/v1/coupons/:id<int>/status [patch]
|
||||
// @Summary Update coupon status
|
||||
// @Description Update coupon status across tenants
|
||||
// @Tags Coupon
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Coupon ID"
|
||||
// @Param form body dto.SuperCouponStatusUpdateForm true "Update form"
|
||||
// @Success 200 {string} string "Updated"
|
||||
// @Bind user local key(__ctx_user)
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (c *coupons) UpdateStatus(ctx fiber.Ctx, user *models.User, id int64, form *dto.SuperCouponStatusUpdateForm) error {
|
||||
return services.Super.UpdateCouponStatus(ctx, user.ID, id, form)
|
||||
}
|
||||
|
||||
// Create coupon
|
||||
//
|
||||
// @Router /super/v1/tenants/:tenantID<int>/coupons [post]
|
||||
|
||||
47
backend/app/http/super/v1/creator_applications.go
Normal file
47
backend/app/http/super/v1/creator_applications.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
dto "quyun/v2/app/http/super/v1/dto"
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/app/services"
|
||||
"quyun/v2/database/models"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type creatorApplications struct{}
|
||||
|
||||
// List creator applications
|
||||
//
|
||||
// @Router /super/v1/creator-applications [get]
|
||||
// @Summary List creator applications
|
||||
// @Description List creator applications across tenants
|
||||
// @Tags Creator
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number"
|
||||
// @Param limit query int false "Page size"
|
||||
// @Success 200 {object} requests.Pager{items=[]dto.TenantItem}
|
||||
// @Bind filter query
|
||||
func (c *creatorApplications) List(ctx fiber.Ctx, filter *dto.TenantListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListCreatorApplications(ctx, filter)
|
||||
}
|
||||
|
||||
// Review creator application
|
||||
//
|
||||
// @Router /super/v1/creator-applications/:id<int>/review [post]
|
||||
// @Summary Review creator application
|
||||
// @Description Approve or reject creator application
|
||||
// @Tags Creator
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Tenant ID"
|
||||
// @Param form body dto.SuperCreatorApplicationReviewForm true "Review form"
|
||||
// @Success 200 {string} string "Reviewed"
|
||||
// @Bind user local key(__ctx_user)
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (c *creatorApplications) Review(ctx fiber.Ctx, user *models.User, id int64, form *dto.SuperCreatorApplicationReviewForm) error {
|
||||
return services.Super.ReviewCreatorApplication(ctx, user.ID, id, form)
|
||||
}
|
||||
@@ -79,3 +79,66 @@ type SuperCouponGrantResponse struct {
|
||||
// Granted 实际发放数量。
|
||||
Granted int `json:"granted"`
|
||||
}
|
||||
|
||||
// SuperCouponStatusUpdateForm 超管优惠券状态更新表单。
|
||||
type SuperCouponStatusUpdateForm struct {
|
||||
// Status 目标状态(frozen)。
|
||||
Status string `json:"status" validate:"required,oneof=frozen"`
|
||||
}
|
||||
|
||||
// SuperCouponGrantListFilter 超管优惠券发放记录过滤条件。
|
||||
type SuperCouponGrantListFilter struct {
|
||||
requests.Pagination
|
||||
// CouponID 优惠券ID过滤(精确匹配)。
|
||||
CouponID *int64 `query:"coupon_id"`
|
||||
// TenantID 租户ID过滤(精确匹配)。
|
||||
TenantID *int64 `query:"tenant_id"`
|
||||
// TenantCode 租户编码过滤(模糊匹配)。
|
||||
TenantCode *string `query:"tenant_code"`
|
||||
// TenantName 租户名称过滤(模糊匹配)。
|
||||
TenantName *string `query:"tenant_name"`
|
||||
// UserID 用户ID过滤(精确匹配)。
|
||||
UserID *int64 `query:"user_id"`
|
||||
// Username 用户名过滤(模糊匹配)。
|
||||
Username *string `query:"username"`
|
||||
// Status 用户券状态过滤(unused/used/expired)。
|
||||
Status *consts.UserCouponStatus `query:"status"`
|
||||
// CreatedAtFrom 领取时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 领取时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// UsedAtFrom 使用时间起始(RFC3339)。
|
||||
UsedAtFrom *string `query:"used_at_from"`
|
||||
// UsedAtTo 使用时间结束(RFC3339)。
|
||||
UsedAtTo *string `query:"used_at_to"`
|
||||
}
|
||||
|
||||
// SuperCouponGrantItem 超管优惠券发放记录项。
|
||||
type SuperCouponGrantItem struct {
|
||||
// ID 用户券ID。
|
||||
ID int64 `json:"id"`
|
||||
// CouponID 优惠券ID。
|
||||
CouponID int64 `json:"coupon_id"`
|
||||
// CouponTitle 优惠券标题。
|
||||
CouponTitle string `json:"coupon_title"`
|
||||
// TenantID 租户ID。
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
// TenantCode 租户编码。
|
||||
TenantCode string `json:"tenant_code"`
|
||||
// TenantName 租户名称。
|
||||
TenantName string `json:"tenant_name"`
|
||||
// UserID 用户ID。
|
||||
UserID int64 `json:"user_id"`
|
||||
// Username 用户名。
|
||||
Username string `json:"username"`
|
||||
// Status 用户券状态。
|
||||
Status consts.UserCouponStatus `json:"status"`
|
||||
// StatusDescription 状态描述(用于展示)。
|
||||
StatusDescription string `json:"status_description"`
|
||||
// OrderID 使用订单ID。
|
||||
OrderID int64 `json:"order_id"`
|
||||
// UsedAt 使用时间(RFC3339)。
|
||||
UsedAt string `json:"used_at"`
|
||||
// CreatedAt 领取时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
9
backend/app/http/super/v1/dto/super_creator.go
Normal file
9
backend/app/http/super/v1/dto/super_creator.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package dto
|
||||
|
||||
// SuperCreatorApplicationReviewForm 超管创作者申请审核表单。
|
||||
type SuperCreatorApplicationReviewForm struct {
|
||||
// Action 审核动作(approve/reject)。
|
||||
Action string `json:"action" validate:"required,oneof=approve reject"`
|
||||
// Reason 审核说明(可选,驳回时填写)。
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
52
backend/app/http/super/v1/dto/super_payout.go
Normal file
52
backend/app/http/super/v1/dto/super_payout.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package dto
|
||||
|
||||
import "quyun/v2/app/requests"
|
||||
|
||||
// SuperPayoutAccountListFilter 超管结算账户列表过滤条件。
|
||||
type SuperPayoutAccountListFilter struct {
|
||||
requests.Pagination
|
||||
// TenantID 租户ID过滤(精确匹配)。
|
||||
TenantID *int64 `query:"tenant_id"`
|
||||
// TenantCode 租户编码过滤(模糊匹配)。
|
||||
TenantCode *string `query:"tenant_code"`
|
||||
// TenantName 租户名称过滤(模糊匹配)。
|
||||
TenantName *string `query:"tenant_name"`
|
||||
// UserID 用户ID过滤(精确匹配)。
|
||||
UserID *int64 `query:"user_id"`
|
||||
// Username 用户名过滤(模糊匹配)。
|
||||
Username *string `query:"username"`
|
||||
// Type 账户类型过滤(bank/alipay)。
|
||||
Type *string `query:"type"`
|
||||
// CreatedAtFrom 创建时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 创建时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
}
|
||||
|
||||
// SuperPayoutAccountItem 超管结算账户列表项。
|
||||
type SuperPayoutAccountItem struct {
|
||||
// ID 结算账户ID。
|
||||
ID int64 `json:"id"`
|
||||
// TenantID 租户ID。
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
// TenantCode 租户编码。
|
||||
TenantCode string `json:"tenant_code"`
|
||||
// TenantName 租户名称。
|
||||
TenantName string `json:"tenant_name"`
|
||||
// UserID 用户ID。
|
||||
UserID int64 `json:"user_id"`
|
||||
// Username 用户名。
|
||||
Username string `json:"username"`
|
||||
// Type 账户类型。
|
||||
Type string `json:"type"`
|
||||
// Name 账户名称/开户行。
|
||||
Name string `json:"name"`
|
||||
// Account 收款账号。
|
||||
Account string `json:"account"`
|
||||
// Realname 收款人姓名。
|
||||
Realname string `json:"realname"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// UpdatedAt 更新时间(RFC3339)。
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
45
backend/app/http/super/v1/payout_accounts.go
Normal file
45
backend/app/http/super/v1/payout_accounts.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
dto "quyun/v2/app/http/super/v1/dto"
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/app/services"
|
||||
"quyun/v2/database/models"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type payoutAccounts struct{}
|
||||
|
||||
// List payout accounts
|
||||
//
|
||||
// @Router /super/v1/payout-accounts [get]
|
||||
// @Summary List payout accounts
|
||||
// @Description List payout accounts across tenants
|
||||
// @Tags Finance
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number"
|
||||
// @Param limit query int false "Page size"
|
||||
// @Success 200 {object} requests.Pager{items=[]dto.SuperPayoutAccountItem}
|
||||
// @Bind filter query
|
||||
func (c *payoutAccounts) List(ctx fiber.Ctx, filter *dto.SuperPayoutAccountListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListPayoutAccounts(ctx, filter)
|
||||
}
|
||||
|
||||
// Remove payout account
|
||||
//
|
||||
// @Router /super/v1/payout-accounts/:id<int> [delete]
|
||||
// @Summary Remove payout account
|
||||
// @Description Remove payout account across tenants
|
||||
// @Tags Finance
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Payout account ID"
|
||||
// @Success 200 {string} string "Removed"
|
||||
// @Bind user local key(__ctx_user)
|
||||
// @Bind id path
|
||||
func (c *payoutAccounts) Remove(ctx fiber.Ctx, user *models.User, id int64) error {
|
||||
return services.Super.RemovePayoutAccount(ctx, user.ID, id)
|
||||
}
|
||||
@@ -24,6 +24,13 @@ func Provide(opts ...opt.Option) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*creatorApplications, error) {
|
||||
obj := &creatorApplications{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*creators, error) {
|
||||
obj := &creators{}
|
||||
|
||||
@@ -38,6 +45,13 @@ func Provide(opts ...opt.Option) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*payoutAccounts, error) {
|
||||
obj := &payoutAccounts{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*reports, error) {
|
||||
obj := &reports{}
|
||||
|
||||
@@ -48,24 +62,28 @@ func Provide(opts ...opt.Option) error {
|
||||
if err := container.Container.Provide(func(
|
||||
contents *contents,
|
||||
coupons *coupons,
|
||||
creatorApplications *creatorApplications,
|
||||
creators *creators,
|
||||
middlewares *middlewares.Middlewares,
|
||||
orders *orders,
|
||||
payoutAccounts *payoutAccounts,
|
||||
reports *reports,
|
||||
tenants *tenants,
|
||||
users *users,
|
||||
withdrawals *withdrawals,
|
||||
) (contracts.HttpRoute, error) {
|
||||
obj := &Routes{
|
||||
contents: contents,
|
||||
coupons: coupons,
|
||||
creators: creators,
|
||||
middlewares: middlewares,
|
||||
orders: orders,
|
||||
reports: reports,
|
||||
tenants: tenants,
|
||||
users: users,
|
||||
withdrawals: withdrawals,
|
||||
contents: contents,
|
||||
coupons: coupons,
|
||||
creatorApplications: creatorApplications,
|
||||
creators: creators,
|
||||
middlewares: middlewares,
|
||||
orders: orders,
|
||||
payoutAccounts: payoutAccounts,
|
||||
reports: reports,
|
||||
tenants: tenants,
|
||||
users: users,
|
||||
withdrawals: withdrawals,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -25,14 +25,16 @@ type Routes struct {
|
||||
log *log.Entry `inject:"false"`
|
||||
middlewares *middlewares.Middlewares
|
||||
// Controller instances
|
||||
contents *contents
|
||||
coupons *coupons
|
||||
creators *creators
|
||||
orders *orders
|
||||
reports *reports
|
||||
tenants *tenants
|
||||
users *users
|
||||
withdrawals *withdrawals
|
||||
contents *contents
|
||||
coupons *coupons
|
||||
creatorApplications *creatorApplications
|
||||
creators *creators
|
||||
orders *orders
|
||||
payoutAccounts *payoutAccounts
|
||||
reports *reports
|
||||
tenants *tenants
|
||||
users *users
|
||||
withdrawals *withdrawals
|
||||
}
|
||||
|
||||
// Prepare initializes the routes provider with logging configuration.
|
||||
@@ -83,6 +85,11 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
Body[dto.SuperContentBatchReviewForm]("form"),
|
||||
))
|
||||
// Register routes for controller: coupons
|
||||
r.log.Debugf("Registering route: Get /super/v1/coupon-grants -> coupons.ListGrants")
|
||||
router.Get("/super/v1/coupon-grants"[len(r.Path()):], DataFunc1(
|
||||
r.coupons.ListGrants,
|
||||
Query[dto.SuperCouponGrantListFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/coupons -> coupons.List")
|
||||
router.Get("/super/v1/coupons"[len(r.Path()):], DataFunc1(
|
||||
r.coupons.List,
|
||||
@@ -94,6 +101,13 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
PathParam[int64]("tenantID"),
|
||||
PathParam[int64]("id"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Patch /super/v1/coupons/:id<int>/status -> coupons.UpdateStatus")
|
||||
router.Patch("/super/v1/coupons/:id<int>/status"[len(r.Path()):], Func3(
|
||||
r.coupons.UpdateStatus,
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.SuperCouponStatusUpdateForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /super/v1/tenants/:tenantID<int>/coupons -> coupons.Create")
|
||||
router.Post("/super/v1/tenants/:tenantID<int>/coupons"[len(r.Path()):], DataFunc3(
|
||||
r.coupons.Create,
|
||||
@@ -116,6 +130,19 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
PathParam[int64]("id"),
|
||||
Body[v1_dto.CouponUpdateForm]("form"),
|
||||
))
|
||||
// Register routes for controller: creatorApplications
|
||||
r.log.Debugf("Registering route: Get /super/v1/creator-applications -> creatorApplications.List")
|
||||
router.Get("/super/v1/creator-applications"[len(r.Path()):], DataFunc1(
|
||||
r.creatorApplications.List,
|
||||
Query[dto.TenantListFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /super/v1/creator-applications/:id<int>/review -> creatorApplications.Review")
|
||||
router.Post("/super/v1/creator-applications/:id<int>/review"[len(r.Path()):], Func3(
|
||||
r.creatorApplications.Review,
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.SuperCreatorApplicationReviewForm]("form"),
|
||||
))
|
||||
// Register routes for controller: creators
|
||||
r.log.Debugf("Registering route: Get /super/v1/creators -> creators.List")
|
||||
router.Get("/super/v1/creators"[len(r.Path()):], DataFunc1(
|
||||
@@ -143,6 +170,18 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.SuperOrderRefundForm]("form"),
|
||||
))
|
||||
// Register routes for controller: payoutAccounts
|
||||
r.log.Debugf("Registering route: Delete /super/v1/payout-accounts/:id<int> -> payoutAccounts.Remove")
|
||||
router.Delete("/super/v1/payout-accounts/:id<int>"[len(r.Path()):], Func2(
|
||||
r.payoutAccounts.Remove,
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/payout-accounts -> payoutAccounts.List")
|
||||
router.Get("/super/v1/payout-accounts"[len(r.Path()):], DataFunc1(
|
||||
r.payoutAccounts.List,
|
||||
Query[dto.SuperPayoutAccountListFilter]("filter"),
|
||||
))
|
||||
// Register routes for controller: reports
|
||||
r.log.Debugf("Registering route: Get /super/v1/reports/overview -> reports.Overview")
|
||||
router.Get("/super/v1/reports/overview"[len(r.Path()):], DataFunc1(
|
||||
|
||||
Reference in New Issue
Block a user