feat: add super admin health review

This commit is contained in:
2026-01-13 15:02:05 +08:00
parent 19b15bf20a
commit 5ac2ea028c
10 changed files with 1208 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ 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"
)
@@ -67,3 +68,21 @@ func (c *contents) ListTenantContents(ctx fiber.Ctx, tenantID int64, filter *dto
func (c *contents) UpdateStatus(ctx fiber.Ctx, tenantID, contentID int64, form *dto.SuperTenantContentStatusUpdateForm) error {
return services.Super.UpdateContentStatus(ctx, tenantID, contentID, form)
}
// Review content
//
// @Router /super/v1/contents/:id<int>/review [post]
// @Summary Review content
// @Description Review content
// @Tags Content
// @Accept json
// @Produce json
// @Param id path int64 true "Content ID"
// @Param form body dto.SuperContentReviewForm true "Review form"
// @Success 200 {string} string "Reviewed"
// @Bind user local key(__ctx_user)
// @Bind id path
// @Bind form body
func (c *contents) Review(ctx fiber.Ctx, user *models.User, id int64, form *dto.SuperContentReviewForm) error {
return services.Super.ReviewContent(ctx, user.ID, id, form)
}

View File

@@ -294,6 +294,43 @@ type TenantItem struct {
Users []*SuperUserLite `json:"users"`
}
type TenantHealthItem struct {
// TenantID 租户ID。
TenantID int64 `json:"tenant_id"`
// Code 租户编码。
Code string `json:"code"`
// Name 租户名称。
Name string `json:"name"`
// Status 租户状态。
Status consts.TenantStatus `json:"status"`
// StatusDescription 租户状态描述(用于展示)。
StatusDescription string `json:"status_description"`
// Owner 租户所有者信息。
Owner *TenantOwnerUserLite `json:"owner"`
// MemberCount 租户成员数量(包含管理员)。
MemberCount int64 `json:"member_count"`
// ContentCount 内容总数。
ContentCount int64 `json:"content_count"`
// PublishedContentCount 已发布内容数量。
PublishedContentCount int64 `json:"published_content_count"`
// PaidOrders 已支付订单数(内容购买)。
PaidOrders int64 `json:"paid_orders"`
// PaidAmount 已支付金额(分)。
PaidAmount int64 `json:"paid_amount"`
// RefundOrders 已退款订单数(内容购买)。
RefundOrders int64 `json:"refund_orders"`
// RefundAmount 已退款金额(分)。
RefundAmount int64 `json:"refund_amount"`
// RefundRate 退款率(退款订单数 / 已支付订单数)。
RefundRate float64 `json:"refund_rate"`
// LastPaidAt 最近成交时间RFC3339空代表暂无成交
LastPaidAt string `json:"last_paid_at"`
// HealthLevel 健康等级healthy/warning/risk
HealthLevel string `json:"health_level"`
// Alerts 异常提示列表(用于运营侧提示)。
Alerts []string `json:"alerts"`
}
type TenantOwnerUserLite struct {
// ID 用户ID。
ID int64 `json:"id"`
@@ -347,6 +384,13 @@ type SuperTenantContentStatusUpdateForm struct {
Status consts.ContentStatus `json:"status" validate:"required,oneof=unpublished blocked"`
}
type SuperContentReviewForm struct {
// Action 审核动作approve/reject
Action string `json:"action" validate:"required,oneof=approve reject"`
// Reason 审核说明(驳回时填写,便于作者修正)。
Reason string `json:"reason"`
}
type SuperTenantUserItem struct {
// User 用户信息。
User *SuperUserLite `json:"user"`

View File

@@ -7,6 +7,7 @@ package v1
import (
dto "quyun/v2/app/http/super/v1/dto"
"quyun/v2/app/middlewares"
"quyun/v2/database/models"
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
@@ -63,6 +64,13 @@ func (r *Routes) Register(router fiber.Router) {
PathParam[int64]("contentID"),
Body[dto.SuperTenantContentStatusUpdateForm]("form"),
))
r.log.Debugf("Registering route: Post /super/v1/contents/:id<int>/review -> contents.Review")
router.Post("/super/v1/contents/:id<int>/review"[len(r.Path()):], Func3(
r.contents.Review,
Local[*models.User]("__ctx_user"),
PathParam[int64]("id"),
Body[dto.SuperContentReviewForm]("form"),
))
// Register routes for controller: orders
r.log.Debugf("Registering route: Get /super/v1/orders -> orders.List")
router.Get("/super/v1/orders"[len(r.Path()):], DataFunc1(
@@ -101,6 +109,11 @@ func (r *Routes) Register(router fiber.Router) {
PathParam[int64]("tenantID"),
Query[dto.SuperTenantUserListFilter]("filter"),
))
r.log.Debugf("Registering route: Get /super/v1/tenants/health -> tenants.Health")
router.Get("/super/v1/tenants/health"[len(r.Path()):], DataFunc1(
r.tenants.Health,
Query[dto.TenantListFilter]("filter"),
))
r.log.Debugf("Registering route: Get /super/v1/tenants/statuses -> tenants.Statuses")
router.Get("/super/v1/tenants/statuses"[len(r.Path()):], DataFunc0(
r.tenants.Statuses,

View File

@@ -28,6 +28,22 @@ func (c *tenants) List(ctx fiber.Ctx, filter *dto.TenantListFilter) (*requests.P
return services.Super.ListTenants(ctx, filter)
}
// Tenant health overview
//
// @Router /super/v1/tenants/health [get]
// @Summary Tenant health overview
// @Description Tenant health overview
// @Tags Tenant
// @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.TenantHealthItem}
// @Bind filter query
func (c *tenants) Health(ctx fiber.Ctx, filter *dto.TenantListFilter) (*requests.Pager, error) {
return services.Super.TenantHealth(ctx, filter)
}
// List tenant users
//
// @Router /super/v1/tenants/:tenantID<int>/users [get]