feat: add super comment governance and finance oversight
This commit is contained in:
47
backend/app/http/super/v1/comments.go
Normal file
47
backend/app/http/super/v1/comments.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 comments struct{}
|
||||
|
||||
// List comments
|
||||
//
|
||||
// @Router /super/v1/comments [get]
|
||||
// @Summary List comments
|
||||
// @Description List comments across tenants
|
||||
// @Tags Content
|
||||
// @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.SuperCommentItem}
|
||||
// @Bind filter query
|
||||
func (c *comments) List(ctx fiber.Ctx, filter *dto.SuperCommentListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListComments(ctx, filter)
|
||||
}
|
||||
|
||||
// Delete comment
|
||||
//
|
||||
// @Router /super/v1/comments/:id<int>/delete [post]
|
||||
// @Summary Delete comment
|
||||
// @Description Soft delete a comment
|
||||
// @Tags Content
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Comment ID"
|
||||
// @Param form body dto.SuperCommentDeleteForm false "Delete form"
|
||||
// @Success 200 {string} string "Deleted"
|
||||
// @Bind user local key(__ctx_user)
|
||||
// @Bind id path
|
||||
// @Bind form body
|
||||
func (c *comments) Delete(ctx fiber.Ctx, user *models.User, id int64, form *dto.SuperCommentDeleteForm) error {
|
||||
return services.Super.DeleteComment(ctx, user.ID, id, form)
|
||||
}
|
||||
74
backend/app/http/super/v1/dto/super_comment.go
Normal file
74
backend/app/http/super/v1/dto/super_comment.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package dto
|
||||
|
||||
import "quyun/v2/app/requests"
|
||||
|
||||
// SuperCommentListFilter 超管评论列表过滤条件。
|
||||
type SuperCommentListFilter struct {
|
||||
requests.Pagination
|
||||
// ID 评论ID,精确匹配。
|
||||
ID *int64 `query:"id"`
|
||||
// TenantID 租户ID,精确匹配。
|
||||
TenantID *int64 `query:"tenant_id"`
|
||||
// TenantCode 租户编码,模糊匹配。
|
||||
TenantCode *string `query:"tenant_code"`
|
||||
// TenantName 租户名称,模糊匹配。
|
||||
TenantName *string `query:"tenant_name"`
|
||||
// ContentID 内容ID,精确匹配。
|
||||
ContentID *int64 `query:"content_id"`
|
||||
// ContentTitle 内容标题关键字,模糊匹配。
|
||||
ContentTitle *string `query:"content_title"`
|
||||
// UserID 评论用户ID,精确匹配。
|
||||
UserID *int64 `query:"user_id"`
|
||||
// Username 评论用户用户名/昵称,模糊匹配。
|
||||
Username *string `query:"username"`
|
||||
// Keyword 评论内容关键字,模糊匹配。
|
||||
Keyword *string `query:"keyword"`
|
||||
// Status 评论状态过滤(active/deleted/all)。
|
||||
Status *string `query:"status"`
|
||||
// CreatedAtFrom 创建时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 创建时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// Asc 升序字段(id/created_at/likes)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/created_at/likes)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperCommentItem 超管评论列表项。
|
||||
type SuperCommentItem 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"`
|
||||
// ContentID 内容ID。
|
||||
ContentID int64 `json:"content_id"`
|
||||
// ContentTitle 内容标题。
|
||||
ContentTitle string `json:"content_title"`
|
||||
// UserID 评论用户ID。
|
||||
UserID int64 `json:"user_id"`
|
||||
// Username 评论用户名称。
|
||||
Username string `json:"username"`
|
||||
// ReplyTo 回复评论ID(0 表示一级评论)。
|
||||
ReplyTo int64 `json:"reply_to"`
|
||||
// Content 评论内容。
|
||||
Content string `json:"content"`
|
||||
// Likes 评论点赞数。
|
||||
Likes int32 `json:"likes"`
|
||||
// IsDeleted 是否已删除。
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// DeletedAt 删除时间(RFC3339,未删除为空)。
|
||||
DeletedAt string `json:"deleted_at"`
|
||||
}
|
||||
|
||||
// SuperCommentDeleteForm 超管删除评论表单。
|
||||
type SuperCommentDeleteForm struct {
|
||||
// Reason 删除原因(可选,用于审计记录)。
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
177
backend/app/http/super/v1/dto/super_finance.go
Normal file
177
backend/app/http/super/v1/dto/super_finance.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/pkg/consts"
|
||||
)
|
||||
|
||||
// SuperLedgerListFilter 超管资金流水过滤条件。
|
||||
type SuperLedgerListFilter struct {
|
||||
requests.Pagination
|
||||
// ID 流水ID,精确匹配。
|
||||
ID *int64 `query:"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"`
|
||||
// OrderID 关联订单ID,精确匹配。
|
||||
OrderID *int64 `query:"order_id"`
|
||||
// Type 流水类型过滤。
|
||||
Type *consts.TenantLedgerType `query:"type"`
|
||||
// AmountMin 金额下限(分)。
|
||||
AmountMin *int64 `query:"amount_min"`
|
||||
// AmountMax 金额上限(分)。
|
||||
AmountMax *int64 `query:"amount_max"`
|
||||
// CreatedAtFrom 创建时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 创建时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// Asc 升序字段(id/created_at/amount)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/created_at/amount)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperLedgerItem 超管资金流水项。
|
||||
type SuperLedgerItem 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"`
|
||||
// OrderID 关联订单ID。
|
||||
OrderID int64 `json:"order_id"`
|
||||
// Type 流水类型。
|
||||
Type consts.TenantLedgerType `json:"type"`
|
||||
// TypeDescription 流水类型描述(用于展示)。
|
||||
TypeDescription string `json:"type_description"`
|
||||
// Amount 变动金额(分)。
|
||||
Amount int64 `json:"amount"`
|
||||
// BalanceBefore 变更前可用余额(分)。
|
||||
BalanceBefore int64 `json:"balance_before"`
|
||||
// BalanceAfter 变更后可用余额(分)。
|
||||
BalanceAfter int64 `json:"balance_after"`
|
||||
// FrozenBefore 变更前冻结余额(分)。
|
||||
FrozenBefore int64 `json:"frozen_before"`
|
||||
// FrozenAfter 变更后冻结余额(分)。
|
||||
FrozenAfter int64 `json:"frozen_after"`
|
||||
// Remark 流水备注说明。
|
||||
Remark string `json:"remark"`
|
||||
// OperatorUserID 操作者用户ID(0 表示系统)。
|
||||
OperatorUserID int64 `json:"operator_user_id"`
|
||||
// BizRefType 业务引用类型(可选)。
|
||||
BizRefType string `json:"biz_ref_type"`
|
||||
// BizRefID 业务引用ID(可选)。
|
||||
BizRefID int64 `json:"biz_ref_id"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// UpdatedAt 更新时间(RFC3339)。
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// SuperBalanceAnomalyFilter 余额异常筛选条件。
|
||||
type SuperBalanceAnomalyFilter struct {
|
||||
requests.Pagination
|
||||
// UserID 用户ID,精确匹配。
|
||||
UserID *int64 `query:"user_id"`
|
||||
// Username 用户名/昵称,模糊匹配。
|
||||
Username *string `query:"username"`
|
||||
// Issue 异常类型(negative_balance/negative_frozen)。
|
||||
Issue *string `query:"issue"`
|
||||
// Asc 升序字段(id/balance/balance_frozen)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/balance/balance_frozen)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperBalanceAnomalyItem 余额异常项。
|
||||
type SuperBalanceAnomalyItem struct {
|
||||
// UserID 用户ID。
|
||||
UserID int64 `json:"user_id"`
|
||||
// Username 用户名。
|
||||
Username string `json:"username"`
|
||||
// Balance 可用余额(分)。
|
||||
Balance int64 `json:"balance"`
|
||||
// BalanceFrozen 冻结余额(分)。
|
||||
BalanceFrozen int64 `json:"balance_frozen"`
|
||||
// Issue 异常类型标识。
|
||||
Issue string `json:"issue"`
|
||||
// IssueDescription 异常描述说明。
|
||||
IssueDescription string `json:"issue_description"`
|
||||
// CreatedAt 用户创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// SuperOrderAnomalyFilter 订单异常筛选条件。
|
||||
type SuperOrderAnomalyFilter struct {
|
||||
requests.Pagination
|
||||
// ID 订单ID,精确匹配。
|
||||
ID *int64 `query:"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"`
|
||||
// Type 订单类型过滤。
|
||||
Type *consts.OrderType `query:"type"`
|
||||
// Issue 异常类型(missing_paid_at/missing_refunded_at)。
|
||||
Issue *string `query:"issue"`
|
||||
// CreatedAtFrom 创建时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 创建时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// Asc 升序字段(id/created_at/amount_paid)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/created_at/amount_paid)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperOrderAnomalyItem 订单异常项。
|
||||
type SuperOrderAnomalyItem struct {
|
||||
// OrderID 订单ID。
|
||||
OrderID int64 `json:"order_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 consts.OrderType `json:"type"`
|
||||
// Status 订单状态。
|
||||
Status consts.OrderStatus `json:"status"`
|
||||
// AmountPaid 实付金额(分)。
|
||||
AmountPaid int64 `json:"amount_paid"`
|
||||
// Issue 异常类型标识。
|
||||
Issue string `json:"issue"`
|
||||
// IssueDescription 异常描述说明。
|
||||
IssueDescription string `json:"issue_description"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// PaidAt 支付时间(RFC3339)。
|
||||
PaidAt string `json:"paid_at"`
|
||||
// RefundedAt 退款时间(RFC3339)。
|
||||
RefundedAt string `json:"refunded_at"`
|
||||
}
|
||||
60
backend/app/http/super/v1/finance.go
Normal file
60
backend/app/http/super/v1/finance.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
dto "quyun/v2/app/http/super/v1/dto"
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/app/services"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type finance struct{}
|
||||
|
||||
// List ledgers
|
||||
//
|
||||
// @Router /super/v1/finance/ledgers [get]
|
||||
// @Summary List ledgers
|
||||
// @Description List tenant ledgers 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.SuperLedgerItem}
|
||||
// @Bind filter query
|
||||
func (c *finance) ListLedgers(ctx fiber.Ctx, filter *dto.SuperLedgerListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListLedgers(ctx, filter)
|
||||
}
|
||||
|
||||
// List balance anomalies
|
||||
//
|
||||
// @Router /super/v1/finance/anomalies/balances [get]
|
||||
// @Summary List balance anomalies
|
||||
// @Description List balance anomalies across users
|
||||
// @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.SuperBalanceAnomalyItem}
|
||||
// @Bind filter query
|
||||
func (c *finance) ListBalanceAnomalies(ctx fiber.Ctx, filter *dto.SuperBalanceAnomalyFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListBalanceAnomalies(ctx, filter)
|
||||
}
|
||||
|
||||
// List order anomalies
|
||||
//
|
||||
// @Router /super/v1/finance/anomalies/orders [get]
|
||||
// @Summary List order anomalies
|
||||
// @Description List order anomalies 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.SuperOrderAnomalyItem}
|
||||
// @Bind filter query
|
||||
func (c *finance) ListOrderAnomalies(ctx fiber.Ctx, filter *dto.SuperOrderAnomalyFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListOrderAnomalies(ctx, filter)
|
||||
}
|
||||
@@ -24,6 +24,13 @@ func Provide(opts ...opt.Option) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*comments, error) {
|
||||
obj := &comments{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*contents, error) {
|
||||
obj := &contents{}
|
||||
|
||||
@@ -52,6 +59,13 @@ func Provide(opts ...opt.Option) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*finance, error) {
|
||||
obj := &finance{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*notifications, error) {
|
||||
obj := ¬ifications{}
|
||||
|
||||
@@ -83,10 +97,12 @@ func Provide(opts ...opt.Option) error {
|
||||
if err := container.Container.Provide(func(
|
||||
assets *assets,
|
||||
auditLogs *auditLogs,
|
||||
comments *comments,
|
||||
contents *contents,
|
||||
coupons *coupons,
|
||||
creatorApplications *creatorApplications,
|
||||
creators *creators,
|
||||
finance *finance,
|
||||
middlewares *middlewares.Middlewares,
|
||||
notifications *notifications,
|
||||
orders *orders,
|
||||
@@ -100,10 +116,12 @@ func Provide(opts ...opt.Option) error {
|
||||
obj := &Routes{
|
||||
assets: assets,
|
||||
auditLogs: auditLogs,
|
||||
comments: comments,
|
||||
contents: contents,
|
||||
coupons: coupons,
|
||||
creatorApplications: creatorApplications,
|
||||
creators: creators,
|
||||
finance: finance,
|
||||
middlewares: middlewares,
|
||||
notifications: notifications,
|
||||
orders: orders,
|
||||
|
||||
@@ -27,10 +27,12 @@ type Routes struct {
|
||||
// Controller instances
|
||||
assets *assets
|
||||
auditLogs *auditLogs
|
||||
comments *comments
|
||||
contents *contents
|
||||
coupons *coupons
|
||||
creatorApplications *creatorApplications
|
||||
creators *creators
|
||||
finance *finance
|
||||
notifications *notifications
|
||||
orders *orders
|
||||
payoutAccounts *payoutAccounts
|
||||
@@ -79,6 +81,19 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
r.auditLogs.List,
|
||||
Query[dto.SuperAuditLogListFilter]("filter"),
|
||||
))
|
||||
// Register routes for controller: comments
|
||||
r.log.Debugf("Registering route: Get /super/v1/comments -> comments.List")
|
||||
router.Get("/super/v1/comments"[len(r.Path()):], DataFunc1(
|
||||
r.comments.List,
|
||||
Query[dto.SuperCommentListFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /super/v1/comments/:id<int>/delete -> comments.Delete")
|
||||
router.Post("/super/v1/comments/:id<int>/delete"[len(r.Path()):], Func3(
|
||||
r.comments.Delete,
|
||||
Local[*models.User]("__ctx_user"),
|
||||
PathParam[int64]("id"),
|
||||
Body[dto.SuperCommentDeleteForm]("form"),
|
||||
))
|
||||
// Register routes for controller: contents
|
||||
r.log.Debugf("Registering route: Get /super/v1/contents -> contents.List")
|
||||
router.Get("/super/v1/contents"[len(r.Path()):], DataFunc1(
|
||||
@@ -186,6 +201,22 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
r.creators.List,
|
||||
Query[dto.TenantListFilter]("filter"),
|
||||
))
|
||||
// Register routes for controller: finance
|
||||
r.log.Debugf("Registering route: Get /super/v1/finance/anomalies/balances -> finance.ListBalanceAnomalies")
|
||||
router.Get("/super/v1/finance/anomalies/balances"[len(r.Path()):], DataFunc1(
|
||||
r.finance.ListBalanceAnomalies,
|
||||
Query[dto.SuperBalanceAnomalyFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/finance/anomalies/orders -> finance.ListOrderAnomalies")
|
||||
router.Get("/super/v1/finance/anomalies/orders"[len(r.Path()):], DataFunc1(
|
||||
r.finance.ListOrderAnomalies,
|
||||
Query[dto.SuperOrderAnomalyFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/finance/ledgers -> finance.ListLedgers")
|
||||
router.Get("/super/v1/finance/ledgers"[len(r.Path()):], DataFunc1(
|
||||
r.finance.ListLedgers,
|
||||
Query[dto.SuperLedgerListFilter]("filter"),
|
||||
))
|
||||
// Register routes for controller: notifications
|
||||
r.log.Debugf("Registering route: Get /super/v1/notifications -> notifications.List")
|
||||
router.Get("/super/v1/notifications"[len(r.Path()):], DataFunc1(
|
||||
|
||||
Reference in New Issue
Block a user