feat: add superadmin assets and notifications
This commit is contained in:
63
backend/app/http/super/v1/assets.go
Normal file
63
backend/app/http/super/v1/assets.go
Normal file
@@ -0,0 +1,63 @@
|
||||
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 assets struct{}
|
||||
|
||||
// List assets
|
||||
//
|
||||
// @Router /super/v1/assets [get]
|
||||
// @Summary List assets
|
||||
// @Description List assets across tenants
|
||||
// @Tags Asset
|
||||
// @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.SuperAssetItem}
|
||||
// @Bind filter query
|
||||
func (c *assets) List(ctx fiber.Ctx, filter *dto.SuperAssetListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListAssets(ctx, filter)
|
||||
}
|
||||
|
||||
// Asset usage
|
||||
//
|
||||
// @Router /super/v1/assets/usage [get]
|
||||
// @Summary Asset usage
|
||||
// @Description Asset usage statistics
|
||||
// @Tags Asset
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} dto.SuperAssetUsageResponse
|
||||
// @Bind filter query
|
||||
func (c *assets) Usage(ctx fiber.Ctx, filter *dto.SuperAssetUsageFilter) (*dto.SuperAssetUsageResponse, error) {
|
||||
return services.Super.AssetUsage(ctx, filter)
|
||||
}
|
||||
|
||||
// Delete asset
|
||||
//
|
||||
// @Router /super/v1/assets/:id<int> [delete]
|
||||
// @Summary Delete asset
|
||||
// @Description Delete asset
|
||||
// @Tags Asset
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int64 true "Asset ID"
|
||||
// @Param force query bool false "Force delete"
|
||||
// @Success 200 {string} string "Deleted"
|
||||
// @Bind id path
|
||||
// @Bind query query
|
||||
func (c *assets) Delete(ctx fiber.Ctx, id int64, query *dto.SuperAssetDeleteQuery) error {
|
||||
force := false
|
||||
if query != nil && query.Force != nil {
|
||||
force = *query.Force
|
||||
}
|
||||
return services.Super.DeleteAsset(ctx, id, force)
|
||||
}
|
||||
119
backend/app/http/super/v1/dto/super_asset.go
Normal file
119
backend/app/http/super/v1/dto/super_asset.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/pkg/consts"
|
||||
)
|
||||
|
||||
// SuperAssetListFilter 超管资产列表查询条件。
|
||||
type SuperAssetListFilter 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.MediaAssetType `query:"type"`
|
||||
// Status 处理状态过滤。
|
||||
Status *consts.MediaAssetStatus `query:"status"`
|
||||
// Provider 存储提供方过滤。
|
||||
Provider *string `query:"provider"`
|
||||
// ObjectKey 对象Key关键字,模糊匹配。
|
||||
ObjectKey *string `query:"object_key"`
|
||||
// CreatedAtFrom 上传时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 上传时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// SizeMin 文件大小下限(字节)。
|
||||
SizeMin *int64 `query:"size_min"`
|
||||
// SizeMax 文件大小上限(字节)。
|
||||
SizeMax *int64 `query:"size_max"`
|
||||
// Asc 升序字段(id/created_at)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/created_at)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperAssetUsageFilter 超管资产用量统计查询条件。
|
||||
type SuperAssetUsageFilter struct {
|
||||
// TenantID 租户ID(不传代表全平台)。
|
||||
TenantID *int64 `query:"tenant_id"`
|
||||
}
|
||||
|
||||
// SuperAssetDeleteQuery 超管资产删除参数。
|
||||
type SuperAssetDeleteQuery struct {
|
||||
// Force 是否强制删除(忽略被内容引用的限制)。
|
||||
Force *bool `query:"force"`
|
||||
}
|
||||
|
||||
// SuperAssetItem 超管资产条目。
|
||||
type SuperAssetItem 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 consts.MediaAssetType `json:"type"`
|
||||
// Status 处理状态。
|
||||
Status consts.MediaAssetStatus `json:"status"`
|
||||
// Provider 存储提供方。
|
||||
Provider string `json:"provider"`
|
||||
// Bucket 存储桶名称。
|
||||
Bucket string `json:"bucket"`
|
||||
// ObjectKey 对象Key。
|
||||
ObjectKey string `json:"object_key"`
|
||||
// URL 访问URL(若可用)。
|
||||
URL string `json:"url"`
|
||||
// Filename 原始文件名。
|
||||
Filename string `json:"filename"`
|
||||
// Size 文件大小(字节)。
|
||||
Size int64 `json:"size"`
|
||||
// Hash 文件哈希(MD5)。
|
||||
Hash string `json:"hash"`
|
||||
// Variant 媒体变体(main/preview/cover 等)。
|
||||
Variant consts.MediaAssetVariant `json:"variant"`
|
||||
// SourceAssetID 源资产ID(用于变体关联)。
|
||||
SourceAssetID int64 `json:"source_asset_id"`
|
||||
// UsedCount 被内容引用次数。
|
||||
UsedCount int64 `json:"used_count"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// UpdatedAt 更新时间(RFC3339)。
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// SuperAssetUsageResponse 超管资产用量统计响应。
|
||||
type SuperAssetUsageResponse struct {
|
||||
// TotalCount 资产总量。
|
||||
TotalCount int64 `json:"total_count"`
|
||||
// TotalSize 资产总大小(字节)。
|
||||
TotalSize int64 `json:"total_size"`
|
||||
// ByType 按媒体类型汇总的用量统计。
|
||||
ByType []SuperAssetUsageItem `json:"by_type"`
|
||||
}
|
||||
|
||||
// SuperAssetUsageItem 资产类型用量统计条目。
|
||||
type SuperAssetUsageItem struct {
|
||||
// Type 媒体类型。
|
||||
Type consts.MediaAssetType `json:"type"`
|
||||
// Count 该类型资产数量。
|
||||
Count int64 `json:"count"`
|
||||
// TotalSize 该类型资产大小总和(字节)。
|
||||
TotalSize int64 `json:"total_size"`
|
||||
}
|
||||
140
backend/app/http/super/v1/dto/super_notification.go
Normal file
140
backend/app/http/super/v1/dto/super_notification.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/pkg/consts"
|
||||
)
|
||||
|
||||
// SuperNotificationListFilter 超管通知列表查询条件。
|
||||
type SuperNotificationListFilter 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.NotificationType `query:"type"`
|
||||
// IsRead 是否已读过滤。
|
||||
IsRead *bool `query:"is_read"`
|
||||
// Keyword 标题或内容关键词,模糊匹配。
|
||||
Keyword *string `query:"keyword"`
|
||||
// CreatedAtFrom 创建时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 创建时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// Asc 升序字段(id/created_at)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/created_at)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperNotificationBroadcastForm 超管通知群发参数。
|
||||
type SuperNotificationBroadcastForm struct {
|
||||
// TenantID 租户ID(选填,用于指定租户成员)。
|
||||
TenantID *int64 `json:"tenant_id"`
|
||||
// UserIDs 指定接收用户ID列表(优先级高于 TenantID)。
|
||||
UserIDs []int64 `json:"user_ids"`
|
||||
// Type 通知类型(system/order/audit/interaction)。
|
||||
Type consts.NotificationType `json:"type"`
|
||||
// Title 通知标题。
|
||||
Title string `json:"title"`
|
||||
// Content 通知内容。
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// SuperNotificationItem 超管通知条目。
|
||||
type SuperNotificationItem 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 consts.NotificationType `json:"type"`
|
||||
// Title 通知标题。
|
||||
Title string `json:"title"`
|
||||
// Content 通知内容。
|
||||
Content string `json:"content"`
|
||||
// IsRead 是否已读。
|
||||
IsRead bool `json:"is_read"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// SuperNotificationTemplateListFilter 超管通知模板列表查询条件。
|
||||
type SuperNotificationTemplateListFilter struct {
|
||||
requests.Pagination
|
||||
// TenantID 租户ID(不传代表全平台模板)。
|
||||
TenantID *int64 `query:"tenant_id"`
|
||||
// Keyword 模板名称或标题关键字,模糊匹配。
|
||||
Keyword *string `query:"keyword"`
|
||||
// Type 通知类型过滤。
|
||||
Type *consts.NotificationType `query:"type"`
|
||||
// IsActive 是否启用过滤。
|
||||
IsActive *bool `query:"is_active"`
|
||||
// CreatedAtFrom 创建时间起始(RFC3339)。
|
||||
CreatedAtFrom *string `query:"created_at_from"`
|
||||
// CreatedAtTo 创建时间结束(RFC3339)。
|
||||
CreatedAtTo *string `query:"created_at_to"`
|
||||
// Asc 升序字段(id/created_at)。
|
||||
Asc *string `query:"asc"`
|
||||
// Desc 降序字段(id/created_at)。
|
||||
Desc *string `query:"desc"`
|
||||
}
|
||||
|
||||
// SuperNotificationTemplateCreateForm 超管通知模板创建参数。
|
||||
type SuperNotificationTemplateCreateForm struct {
|
||||
// TenantID 租户ID(不传代表全平台模板)。
|
||||
TenantID *int64 `json:"tenant_id"`
|
||||
// Name 模板名称(用于识别用途)。
|
||||
Name string `json:"name"`
|
||||
// Type 通知类型(system/order/audit/interaction)。
|
||||
Type consts.NotificationType `json:"type"`
|
||||
// Title 通知标题。
|
||||
Title string `json:"title"`
|
||||
// Content 通知内容。
|
||||
Content string `json:"content"`
|
||||
// IsActive 是否启用(不传默认启用)。
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
// SuperNotificationTemplateItem 超管通知模板条目。
|
||||
type SuperNotificationTemplateItem 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"`
|
||||
// Name 模板名称。
|
||||
Name string `json:"name"`
|
||||
// Type 通知类型。
|
||||
Type consts.NotificationType `json:"type"`
|
||||
// Title 模板标题。
|
||||
Title string `json:"title"`
|
||||
// Content 模板内容。
|
||||
Content string `json:"content"`
|
||||
// IsActive 是否启用。
|
||||
IsActive bool `json:"is_active"`
|
||||
// CreatedAt 创建时间(RFC3339)。
|
||||
CreatedAt string `json:"created_at"`
|
||||
// UpdatedAt 更新时间(RFC3339)。
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
72
backend/app/http/super/v1/notifications.go
Normal file
72
backend/app/http/super/v1/notifications.go
Normal file
@@ -0,0 +1,72 @@
|
||||
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 notifications struct{}
|
||||
|
||||
// List notifications
|
||||
//
|
||||
// @Router /super/v1/notifications [get]
|
||||
// @Summary List notifications
|
||||
// @Description List notifications across tenants
|
||||
// @Tags Notification
|
||||
// @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.SuperNotificationItem}
|
||||
// @Bind filter query
|
||||
func (c *notifications) List(ctx fiber.Ctx, filter *dto.SuperNotificationListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListNotifications(ctx, filter)
|
||||
}
|
||||
|
||||
// Broadcast notification
|
||||
//
|
||||
// @Router /super/v1/notifications/broadcast [post]
|
||||
// @Summary Broadcast notification
|
||||
// @Description Broadcast notification to users or tenant members
|
||||
// @Tags Notification
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param form body dto.SuperNotificationBroadcastForm true "Broadcast form"
|
||||
// @Success 200 {string} string "Sent"
|
||||
// @Bind form body
|
||||
func (c *notifications) Broadcast(ctx fiber.Ctx, form *dto.SuperNotificationBroadcastForm) error {
|
||||
return services.Super.BroadcastNotifications(ctx, form)
|
||||
}
|
||||
|
||||
// List notification templates
|
||||
//
|
||||
// @Router /super/v1/notifications/templates [get]
|
||||
// @Summary List notification templates
|
||||
// @Description List notification templates
|
||||
// @Tags Notification
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} requests.Pager{items=[]dto.SuperNotificationTemplateItem}
|
||||
// @Bind filter query
|
||||
func (c *notifications) ListTemplates(ctx fiber.Ctx, filter *dto.SuperNotificationTemplateListFilter) (*requests.Pager, error) {
|
||||
return services.Super.ListNotificationTemplates(ctx, filter)
|
||||
}
|
||||
|
||||
// Create notification template
|
||||
//
|
||||
// @Router /super/v1/notifications/templates [post]
|
||||
// @Summary Create notification template
|
||||
// @Description Create notification template
|
||||
// @Tags Notification
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param form body dto.SuperNotificationTemplateCreateForm true "Template form"
|
||||
// @Success 200 {object} dto.SuperNotificationTemplateItem
|
||||
// @Bind form body
|
||||
func (c *notifications) CreateTemplate(ctx fiber.Ctx, form *dto.SuperNotificationTemplateCreateForm) (*dto.SuperNotificationTemplateItem, error) {
|
||||
return services.Super.CreateNotificationTemplate(ctx, form)
|
||||
}
|
||||
@@ -10,6 +10,13 @@ import (
|
||||
)
|
||||
|
||||
func Provide(opts ...opt.Option) error {
|
||||
if err := container.Container.Provide(func() (*assets, error) {
|
||||
obj := &assets{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*contents, error) {
|
||||
obj := &contents{}
|
||||
|
||||
@@ -38,6 +45,13 @@ func Provide(opts ...opt.Option) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*notifications, error) {
|
||||
obj := ¬ifications{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*orders, error) {
|
||||
obj := &orders{}
|
||||
|
||||
@@ -60,11 +74,13 @@ func Provide(opts ...opt.Option) error {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func(
|
||||
assets *assets,
|
||||
contents *contents,
|
||||
coupons *coupons,
|
||||
creatorApplications *creatorApplications,
|
||||
creators *creators,
|
||||
middlewares *middlewares.Middlewares,
|
||||
notifications *notifications,
|
||||
orders *orders,
|
||||
payoutAccounts *payoutAccounts,
|
||||
reports *reports,
|
||||
@@ -73,11 +89,13 @@ func Provide(opts ...opt.Option) error {
|
||||
withdrawals *withdrawals,
|
||||
) (contracts.HttpRoute, error) {
|
||||
obj := &Routes{
|
||||
assets: assets,
|
||||
contents: contents,
|
||||
coupons: coupons,
|
||||
creatorApplications: creatorApplications,
|
||||
creators: creators,
|
||||
middlewares: middlewares,
|
||||
notifications: notifications,
|
||||
orders: orders,
|
||||
payoutAccounts: payoutAccounts,
|
||||
reports: reports,
|
||||
|
||||
@@ -25,10 +25,12 @@ type Routes struct {
|
||||
log *log.Entry `inject:"false"`
|
||||
middlewares *middlewares.Middlewares
|
||||
// Controller instances
|
||||
assets *assets
|
||||
contents *contents
|
||||
coupons *coupons
|
||||
creatorApplications *creatorApplications
|
||||
creators *creators
|
||||
notifications *notifications
|
||||
orders *orders
|
||||
payoutAccounts *payoutAccounts
|
||||
reports *reports
|
||||
@@ -52,6 +54,23 @@ func (r *Routes) Name() string {
|
||||
// Register registers all HTTP routes with the provided fiber router.
|
||||
// Each route is registered with its corresponding controller action and parameter bindings.
|
||||
func (r *Routes) Register(router fiber.Router) {
|
||||
// Register routes for controller: assets
|
||||
r.log.Debugf("Registering route: Delete /super/v1/assets/:id<int> -> assets.Delete")
|
||||
router.Delete("/super/v1/assets/:id<int>"[len(r.Path()):], Func2(
|
||||
r.assets.Delete,
|
||||
PathParam[int64]("id"),
|
||||
Query[dto.SuperAssetDeleteQuery]("query"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/assets -> assets.List")
|
||||
router.Get("/super/v1/assets"[len(r.Path()):], DataFunc1(
|
||||
r.assets.List,
|
||||
Query[dto.SuperAssetListFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/assets/usage -> assets.Usage")
|
||||
router.Get("/super/v1/assets/usage"[len(r.Path()):], DataFunc1(
|
||||
r.assets.Usage,
|
||||
Query[dto.SuperAssetUsageFilter]("filter"),
|
||||
))
|
||||
// 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(
|
||||
@@ -154,6 +173,27 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
r.creators.List,
|
||||
Query[dto.TenantListFilter]("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(
|
||||
r.notifications.List,
|
||||
Query[dto.SuperNotificationListFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Get /super/v1/notifications/templates -> notifications.ListTemplates")
|
||||
router.Get("/super/v1/notifications/templates"[len(r.Path()):], DataFunc1(
|
||||
r.notifications.ListTemplates,
|
||||
Query[dto.SuperNotificationTemplateListFilter]("filter"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /super/v1/notifications/broadcast -> notifications.Broadcast")
|
||||
router.Post("/super/v1/notifications/broadcast"[len(r.Path()):], Func1(
|
||||
r.notifications.Broadcast,
|
||||
Body[dto.SuperNotificationBroadcastForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /super/v1/notifications/templates -> notifications.CreateTemplate")
|
||||
router.Post("/super/v1/notifications/templates"[len(r.Path()):], DataFunc1(
|
||||
r.notifications.CreateTemplate,
|
||||
Body[dto.SuperNotificationTemplateCreateForm]("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(
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -2127,6 +2128,784 @@ func (s *super) ContentStatistics(ctx context.Context, filter *super_dto.SuperCo
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) ListAssets(ctx context.Context, filter *super_dto.SuperAssetListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperAssetListFilter{}
|
||||
}
|
||||
|
||||
tbl, q := models.MediaAssetQuery.QueryContext(ctx)
|
||||
|
||||
if filter.ID != nil && *filter.ID > 0 {
|
||||
q = q.Where(tbl.ID.Eq(*filter.ID))
|
||||
}
|
||||
if filter.TenantID != nil && *filter.TenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(*filter.TenantID))
|
||||
}
|
||||
if filter.UserID != nil && *filter.UserID > 0 {
|
||||
q = q.Where(tbl.UserID.Eq(*filter.UserID))
|
||||
}
|
||||
if filter.Type != nil && *filter.Type != "" {
|
||||
q = q.Where(tbl.Type.Eq(*filter.Type))
|
||||
}
|
||||
if filter.Status != nil && *filter.Status != "" {
|
||||
q = q.Where(tbl.Status.Eq(*filter.Status))
|
||||
}
|
||||
if filter.Provider != nil && strings.TrimSpace(*filter.Provider) != "" {
|
||||
q = q.Where(tbl.Provider.Eq(strings.TrimSpace(*filter.Provider)))
|
||||
}
|
||||
if filter.ObjectKey != nil && strings.TrimSpace(*filter.ObjectKey) != "" {
|
||||
keyword := "%" + strings.TrimSpace(*filter.ObjectKey) + "%"
|
||||
q = q.Where(tbl.ObjectKey.Like(keyword))
|
||||
}
|
||||
|
||||
tenantIDs, tenantFilter, err := s.lookupTenantIDs(ctx, filter.TenantCode, filter.TenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tenantFilter {
|
||||
if len(tenantIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.TenantID.In(tenantIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
userIDs, userFilter, err := s.lookupUserIDs(ctx, filter.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userFilter {
|
||||
if len(userIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.UserID.In(userIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
if filter.CreatedAtFrom != nil {
|
||||
from, err := s.parseFilterTime(filter.CreatedAtFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from != nil {
|
||||
q = q.Where(tbl.CreatedAt.Gte(*from))
|
||||
}
|
||||
}
|
||||
if filter.CreatedAtTo != nil {
|
||||
to, err := s.parseFilterTime(filter.CreatedAtTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to != nil {
|
||||
q = q.Where(tbl.CreatedAt.Lte(*to))
|
||||
}
|
||||
}
|
||||
|
||||
if filter.SizeMin != nil {
|
||||
// JSONB 元信息内的 size 需要使用原生表达式过滤。
|
||||
q = q.Where(field.NewUnsafeFieldRaw("coalesce((meta->>'size')::bigint,0) >= ?", *filter.SizeMin))
|
||||
}
|
||||
if filter.SizeMax != nil {
|
||||
// JSONB 元信息内的 size 需要使用原生表达式过滤。
|
||||
q = q.Where(field.NewUnsafeFieldRaw("coalesce((meta->>'size')::bigint,0) <= ?", *filter.SizeMax))
|
||||
}
|
||||
|
||||
orderApplied := false
|
||||
if filter.Desc != nil && strings.TrimSpace(*filter.Desc) != "" {
|
||||
switch strings.TrimSpace(*filter.Desc) {
|
||||
case "id":
|
||||
q = q.Order(tbl.ID.Desc())
|
||||
case "created_at":
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
}
|
||||
orderApplied = true
|
||||
} else if filter.Asc != nil && strings.TrimSpace(*filter.Asc) != "" {
|
||||
switch strings.TrimSpace(*filter.Asc) {
|
||||
case "id":
|
||||
q = q.Order(tbl.ID)
|
||||
case "created_at":
|
||||
q = q.Order(tbl.CreatedAt)
|
||||
}
|
||||
orderApplied = true
|
||||
}
|
||||
if !orderApplied {
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
}
|
||||
|
||||
filter.Pagination.Format()
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: []super_dto.SuperAssetItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
tenantSet := make(map[int64]struct{})
|
||||
userSet := make(map[int64]struct{})
|
||||
assetIDs := make([]int64, 0, len(list))
|
||||
for _, asset := range list {
|
||||
assetIDs = append(assetIDs, asset.ID)
|
||||
if asset.TenantID > 0 {
|
||||
tenantSet[asset.TenantID] = struct{}{}
|
||||
}
|
||||
if asset.UserID > 0 {
|
||||
userSet[asset.UserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
tenantMap := make(map[int64]*models.Tenant, len(tenantSet))
|
||||
if len(tenantSet) > 0 {
|
||||
ids := make([]int64, 0, len(tenantSet))
|
||||
for id := range tenantSet {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenants, err := tenantQuery.Where(tenantTbl.ID.In(ids...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tenant := range tenants {
|
||||
tenantMap[tenant.ID] = tenant
|
||||
}
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*models.User, len(userSet))
|
||||
if len(userSet) > 0 {
|
||||
ids := make([]int64, 0, len(userSet))
|
||||
for id := range userSet {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
userTbl, userQuery := models.UserQuery.QueryContext(ctx)
|
||||
users, err := userQuery.Where(userTbl.ID.In(ids...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, user := range users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
}
|
||||
|
||||
usedCountMap := make(map[int64]int64)
|
||||
if len(assetIDs) > 0 {
|
||||
type assetUseRow struct {
|
||||
AssetID int64 `gorm:"column:asset_id"`
|
||||
Count int64 `gorm:"column:count"`
|
||||
}
|
||||
rows := make([]assetUseRow, 0)
|
||||
query := models.ContentAssetQuery.WithContext(ctx).
|
||||
UnderlyingDB().
|
||||
Model(&models.ContentAsset{}).
|
||||
Select("asset_id, count(*) as count").
|
||||
Where("asset_id in ?", assetIDs).
|
||||
Group("asset_id")
|
||||
if err := query.Scan(&rows).Error; err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, row := range rows {
|
||||
usedCountMap[row.AssetID] = row.Count
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]super_dto.SuperAssetItem, 0, len(list))
|
||||
for _, asset := range list {
|
||||
meta := asset.Meta.Data()
|
||||
filename := strings.TrimSpace(meta.Filename)
|
||||
if filename == "" {
|
||||
filename = filepath.Base(asset.ObjectKey)
|
||||
}
|
||||
url := ""
|
||||
if Common != nil {
|
||||
url = Common.GetAssetURL(asset.ObjectKey)
|
||||
}
|
||||
item := super_dto.SuperAssetItem{
|
||||
ID: asset.ID,
|
||||
TenantID: asset.TenantID,
|
||||
UserID: asset.UserID,
|
||||
Type: asset.Type,
|
||||
Status: asset.Status,
|
||||
Provider: asset.Provider,
|
||||
Bucket: asset.Bucket,
|
||||
ObjectKey: asset.ObjectKey,
|
||||
URL: url,
|
||||
Filename: filename,
|
||||
Size: meta.Size,
|
||||
Hash: asset.Hash,
|
||||
Variant: asset.Variant,
|
||||
SourceAssetID: asset.SourceAssetID,
|
||||
UsedCount: usedCountMap[asset.ID],
|
||||
CreatedAt: s.formatTime(asset.CreatedAt),
|
||||
UpdatedAt: s.formatTime(asset.UpdatedAt),
|
||||
}
|
||||
if tenant := tenantMap[asset.TenantID]; tenant != nil {
|
||||
item.TenantCode = tenant.Code
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
if user := userMap[asset.UserID]; user != nil {
|
||||
item.Username = user.Username
|
||||
} else if asset.UserID > 0 {
|
||||
item.Username = "ID:" + strconv.FormatInt(asset.UserID, 10)
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) AssetUsage(ctx context.Context, filter *super_dto.SuperAssetUsageFilter) (*super_dto.SuperAssetUsageResponse, error) {
|
||||
tenantID := int64(0)
|
||||
if filter != nil && filter.TenantID != nil {
|
||||
tenantID = *filter.TenantID
|
||||
}
|
||||
|
||||
tbl, q := models.MediaAssetQuery.QueryContext(ctx)
|
||||
if tenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
var totalSize int64
|
||||
sizeQuery := models.MediaAssetQuery.WithContext(ctx).
|
||||
UnderlyingDB().
|
||||
Model(&models.MediaAsset{}).
|
||||
Select("coalesce(sum((meta->>'size')::bigint), 0) as size")
|
||||
if tenantID > 0 {
|
||||
sizeQuery = sizeQuery.Where("tenant_id = ?", tenantID)
|
||||
}
|
||||
if err := sizeQuery.Scan(&totalSize).Error; err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
type usageRow struct {
|
||||
Type string `gorm:"column:type"`
|
||||
Count int64 `gorm:"column:count"`
|
||||
Size int64 `gorm:"column:size"`
|
||||
}
|
||||
rows := make([]usageRow, 0)
|
||||
typeQuery := models.MediaAssetQuery.WithContext(ctx).
|
||||
UnderlyingDB().
|
||||
Model(&models.MediaAsset{}).
|
||||
Select("type, count(*) as count, coalesce(sum((meta->>'size')::bigint), 0) as size").
|
||||
Group("type")
|
||||
if tenantID > 0 {
|
||||
typeQuery = typeQuery.Where("tenant_id = ?", tenantID)
|
||||
}
|
||||
if err := typeQuery.Scan(&rows).Error; err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
byType := make([]super_dto.SuperAssetUsageItem, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
byType = append(byType, super_dto.SuperAssetUsageItem{
|
||||
Type: consts.MediaAssetType(row.Type),
|
||||
Count: row.Count,
|
||||
TotalSize: row.Size,
|
||||
})
|
||||
}
|
||||
|
||||
return &super_dto.SuperAssetUsageResponse{
|
||||
TotalCount: total,
|
||||
TotalSize: totalSize,
|
||||
ByType: byType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) DeleteAsset(ctx context.Context, assetID int64, force bool) error {
|
||||
if assetID <= 0 {
|
||||
return errorx.ErrBadRequest.WithMsg("资产ID不能为空")
|
||||
}
|
||||
|
||||
tbl, q := models.MediaAssetQuery.QueryContext(ctx)
|
||||
asset, err := q.Where(tbl.ID.Eq(assetID)).First()
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errorx.ErrRecordNotFound.WithMsg("资产不存在")
|
||||
}
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
useTbl, useQuery := models.ContentAssetQuery.QueryContext(ctx)
|
||||
usedCount, err := useQuery.Where(useTbl.AssetID.Eq(assetID)).Count()
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if usedCount > 0 && !force {
|
||||
return errorx.ErrStatusConflict.WithMsg("资产已被内容引用,无法删除")
|
||||
}
|
||||
if usedCount > 0 && force {
|
||||
// 强制删除时先清理引用关系,避免残留无效关联。
|
||||
if _, err := useQuery.Where(useTbl.AssetID.Eq(assetID)).Delete(); err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := q.Where(tbl.ID.Eq(assetID)).Delete(); err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
if Common != nil && asset.ObjectKey != "" {
|
||||
count, err := models.MediaAssetQuery.WithContext(ctx).
|
||||
Where(models.MediaAssetQuery.ObjectKey.Eq(asset.ObjectKey)).
|
||||
Count()
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if count == 0 && Common.storage != nil {
|
||||
_ = Common.storage.Delete(asset.ObjectKey)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *super) ListNotifications(ctx context.Context, filter *super_dto.SuperNotificationListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperNotificationListFilter{}
|
||||
}
|
||||
|
||||
tbl, q := models.NotificationQuery.QueryContext(ctx)
|
||||
|
||||
if filter.ID != nil && *filter.ID > 0 {
|
||||
q = q.Where(tbl.ID.Eq(*filter.ID))
|
||||
}
|
||||
if filter.TenantID != nil && *filter.TenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(*filter.TenantID))
|
||||
}
|
||||
if filter.UserID != nil && *filter.UserID > 0 {
|
||||
q = q.Where(tbl.UserID.Eq(*filter.UserID))
|
||||
}
|
||||
if filter.Type != nil && *filter.Type != "" {
|
||||
q = q.Where(tbl.Type.Eq(filter.Type.String()))
|
||||
}
|
||||
if filter.IsRead != nil {
|
||||
q = q.Where(tbl.IsRead.Is(*filter.IsRead))
|
||||
}
|
||||
if filter.Keyword != nil && strings.TrimSpace(*filter.Keyword) != "" {
|
||||
keyword := "%" + strings.TrimSpace(*filter.Keyword) + "%"
|
||||
q = q.Where(field.Or(tbl.Title.Like(keyword), tbl.Content.Like(keyword)))
|
||||
}
|
||||
|
||||
tenantIDs, tenantFilter, err := s.lookupTenantIDs(ctx, filter.TenantCode, filter.TenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tenantFilter {
|
||||
if len(tenantIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.TenantID.In(tenantIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
userIDs, userFilter, err := s.lookupUserIDs(ctx, filter.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userFilter {
|
||||
if len(userIDs) == 0 {
|
||||
q = q.Where(tbl.ID.Eq(-1))
|
||||
} else {
|
||||
q = q.Where(tbl.UserID.In(userIDs...))
|
||||
}
|
||||
}
|
||||
|
||||
if filter.CreatedAtFrom != nil {
|
||||
from, err := s.parseFilterTime(filter.CreatedAtFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from != nil {
|
||||
q = q.Where(tbl.CreatedAt.Gte(*from))
|
||||
}
|
||||
}
|
||||
if filter.CreatedAtTo != nil {
|
||||
to, err := s.parseFilterTime(filter.CreatedAtTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to != nil {
|
||||
q = q.Where(tbl.CreatedAt.Lte(*to))
|
||||
}
|
||||
}
|
||||
|
||||
orderApplied := false
|
||||
if filter.Desc != nil && strings.TrimSpace(*filter.Desc) != "" {
|
||||
switch strings.TrimSpace(*filter.Desc) {
|
||||
case "id":
|
||||
q = q.Order(tbl.ID.Desc())
|
||||
case "created_at":
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
}
|
||||
orderApplied = true
|
||||
} else if filter.Asc != nil && strings.TrimSpace(*filter.Asc) != "" {
|
||||
switch strings.TrimSpace(*filter.Asc) {
|
||||
case "id":
|
||||
q = q.Order(tbl.ID)
|
||||
case "created_at":
|
||||
q = q.Order(tbl.CreatedAt)
|
||||
}
|
||||
orderApplied = true
|
||||
}
|
||||
if !orderApplied {
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
}
|
||||
|
||||
filter.Pagination.Format()
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: []super_dto.SuperNotificationItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
tenantSet := make(map[int64]struct{})
|
||||
userSet := make(map[int64]struct{})
|
||||
for _, n := range list {
|
||||
if n.TenantID > 0 {
|
||||
tenantSet[n.TenantID] = struct{}{}
|
||||
}
|
||||
if n.UserID > 0 {
|
||||
userSet[n.UserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
tenantMap := make(map[int64]*models.Tenant, len(tenantSet))
|
||||
if len(tenantSet) > 0 {
|
||||
ids := make([]int64, 0, len(tenantSet))
|
||||
for id := range tenantSet {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenants, err := tenantQuery.Where(tenantTbl.ID.In(ids...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tenant := range tenants {
|
||||
tenantMap[tenant.ID] = tenant
|
||||
}
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*models.User, len(userSet))
|
||||
if len(userSet) > 0 {
|
||||
ids := make([]int64, 0, len(userSet))
|
||||
for id := range userSet {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
userTbl, userQuery := models.UserQuery.QueryContext(ctx)
|
||||
users, err := userQuery.Where(userTbl.ID.In(ids...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, user := range users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]super_dto.SuperNotificationItem, 0, len(list))
|
||||
for _, n := range list {
|
||||
item := super_dto.SuperNotificationItem{
|
||||
ID: n.ID,
|
||||
TenantID: n.TenantID,
|
||||
UserID: n.UserID,
|
||||
Type: consts.NotificationType(n.Type),
|
||||
Title: n.Title,
|
||||
Content: n.Content,
|
||||
IsRead: n.IsRead,
|
||||
CreatedAt: s.formatTime(n.CreatedAt),
|
||||
}
|
||||
if tenant := tenantMap[n.TenantID]; tenant != nil {
|
||||
item.TenantCode = tenant.Code
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
if user := userMap[n.UserID]; user != nil {
|
||||
item.Username = user.Username
|
||||
} else if n.UserID > 0 {
|
||||
item.Username = "ID:" + strconv.FormatInt(n.UserID, 10)
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) BroadcastNotifications(ctx context.Context, form *super_dto.SuperNotificationBroadcastForm) error {
|
||||
if form == nil {
|
||||
return errorx.ErrBadRequest.WithMsg("群发参数不能为空")
|
||||
}
|
||||
|
||||
title := strings.TrimSpace(form.Title)
|
||||
content := strings.TrimSpace(form.Content)
|
||||
if title == "" || content == "" {
|
||||
return errorx.ErrBadRequest.WithMsg("通知标题和内容不能为空")
|
||||
}
|
||||
if !form.Type.IsValid() {
|
||||
return errorx.ErrBadRequest.WithMsg("通知类型非法")
|
||||
}
|
||||
|
||||
tenantID := int64(0)
|
||||
if form.TenantID != nil {
|
||||
tenantID = *form.TenantID
|
||||
}
|
||||
|
||||
userSet := make(map[int64]struct{})
|
||||
for _, id := range form.UserIDs {
|
||||
if id <= 0 {
|
||||
continue
|
||||
}
|
||||
userSet[id] = struct{}{}
|
||||
}
|
||||
|
||||
if len(userSet) == 0 && tenantID <= 0 {
|
||||
return errorx.ErrBadRequest.WithMsg("请指定租户或用户")
|
||||
}
|
||||
|
||||
if len(userSet) == 0 && tenantID > 0 {
|
||||
// 仅向该租户的已验证成员发送。
|
||||
tbl, q := models.TenantUserQuery.QueryContext(ctx)
|
||||
list, err := q.Where(tbl.TenantID.Eq(tenantID), tbl.Status.Eq(consts.UserStatusVerified)).Find()
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tu := range list {
|
||||
if tu.UserID > 0 {
|
||||
userSet[tu.UserID] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(userSet) == 0 {
|
||||
return errorx.ErrRecordNotFound.WithMsg("未找到可通知的用户")
|
||||
}
|
||||
if Notification == nil {
|
||||
return errorx.ErrInternalError.WithMsg("通知服务不可用")
|
||||
}
|
||||
|
||||
typ := form.Type.String()
|
||||
for userID := range userSet {
|
||||
if err := Notification.Send(ctx, tenantID, userID, typ, title, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *super) ListNotificationTemplates(ctx context.Context, filter *super_dto.SuperNotificationTemplateListFilter) (*requests.Pager, error) {
|
||||
if filter == nil {
|
||||
filter = &super_dto.SuperNotificationTemplateListFilter{}
|
||||
}
|
||||
|
||||
tbl, q := models.NotificationTemplateQuery.QueryContext(ctx)
|
||||
|
||||
if filter.TenantID != nil && *filter.TenantID >= 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(*filter.TenantID))
|
||||
}
|
||||
if filter.Type != nil && *filter.Type != "" {
|
||||
q = q.Where(tbl.Type.Eq(*filter.Type))
|
||||
}
|
||||
if filter.IsActive != nil {
|
||||
q = q.Where(tbl.IsActive.Is(*filter.IsActive))
|
||||
}
|
||||
if filter.Keyword != nil && strings.TrimSpace(*filter.Keyword) != "" {
|
||||
keyword := "%" + strings.TrimSpace(*filter.Keyword) + "%"
|
||||
q = q.Where(field.Or(tbl.Name.Like(keyword), tbl.Title.Like(keyword)))
|
||||
}
|
||||
|
||||
if filter.CreatedAtFrom != nil {
|
||||
from, err := s.parseFilterTime(filter.CreatedAtFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from != nil {
|
||||
q = q.Where(tbl.CreatedAt.Gte(*from))
|
||||
}
|
||||
}
|
||||
if filter.CreatedAtTo != nil {
|
||||
to, err := s.parseFilterTime(filter.CreatedAtTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to != nil {
|
||||
q = q.Where(tbl.CreatedAt.Lte(*to))
|
||||
}
|
||||
}
|
||||
|
||||
orderApplied := false
|
||||
if filter.Desc != nil && strings.TrimSpace(*filter.Desc) != "" {
|
||||
switch strings.TrimSpace(*filter.Desc) {
|
||||
case "id":
|
||||
q = q.Order(tbl.ID.Desc())
|
||||
case "created_at":
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
}
|
||||
orderApplied = true
|
||||
} else if filter.Asc != nil && strings.TrimSpace(*filter.Asc) != "" {
|
||||
switch strings.TrimSpace(*filter.Asc) {
|
||||
case "id":
|
||||
q = q.Order(tbl.ID)
|
||||
case "created_at":
|
||||
q = q.Order(tbl.CreatedAt)
|
||||
}
|
||||
orderApplied = true
|
||||
}
|
||||
if !orderApplied {
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
}
|
||||
|
||||
filter.Pagination.Format()
|
||||
total, err := q.Count()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: []super_dto.SuperNotificationTemplateItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
tenantSet := make(map[int64]struct{})
|
||||
for _, tmpl := range list {
|
||||
if tmpl.TenantID > 0 {
|
||||
tenantSet[tmpl.TenantID] = struct{}{}
|
||||
}
|
||||
}
|
||||
tenantMap := make(map[int64]*models.Tenant, len(tenantSet))
|
||||
if len(tenantSet) > 0 {
|
||||
ids := make([]int64, 0, len(tenantSet))
|
||||
for id := range tenantSet {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenants, err := tenantQuery.Where(tenantTbl.ID.In(ids...)).Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
for _, tenant := range tenants {
|
||||
tenantMap[tenant.ID] = tenant
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]super_dto.SuperNotificationTemplateItem, 0, len(list))
|
||||
for _, tmpl := range list {
|
||||
item := super_dto.SuperNotificationTemplateItem{
|
||||
ID: tmpl.ID,
|
||||
TenantID: tmpl.TenantID,
|
||||
Name: tmpl.Name,
|
||||
Type: tmpl.Type,
|
||||
Title: tmpl.Title,
|
||||
Content: tmpl.Content,
|
||||
IsActive: tmpl.IsActive,
|
||||
CreatedAt: s.formatTime(tmpl.CreatedAt),
|
||||
UpdatedAt: s.formatTime(tmpl.UpdatedAt),
|
||||
}
|
||||
if tenant := tenantMap[tmpl.TenantID]; tenant != nil {
|
||||
item.TenantCode = tenant.Code
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &requests.Pager{
|
||||
Pagination: filter.Pagination,
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *super) CreateNotificationTemplate(ctx context.Context, form *super_dto.SuperNotificationTemplateCreateForm) (*super_dto.SuperNotificationTemplateItem, error) {
|
||||
if form == nil {
|
||||
return nil, errorx.ErrBadRequest.WithMsg("模板参数不能为空")
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(form.Name)
|
||||
title := strings.TrimSpace(form.Title)
|
||||
content := strings.TrimSpace(form.Content)
|
||||
if name == "" || title == "" || content == "" {
|
||||
return nil, errorx.ErrBadRequest.WithMsg("模板名称、标题和内容不能为空")
|
||||
}
|
||||
if !form.Type.IsValid() {
|
||||
return nil, errorx.ErrBadRequest.WithMsg("通知类型非法")
|
||||
}
|
||||
|
||||
tenantID := int64(0)
|
||||
if form.TenantID != nil {
|
||||
tenantID = *form.TenantID
|
||||
}
|
||||
isActive := true
|
||||
if form.IsActive != nil {
|
||||
isActive = *form.IsActive
|
||||
}
|
||||
|
||||
tmpl := &models.NotificationTemplate{
|
||||
TenantID: tenantID,
|
||||
Name: name,
|
||||
Type: form.Type,
|
||||
Title: title,
|
||||
Content: content,
|
||||
IsActive: isActive,
|
||||
}
|
||||
if err := models.NotificationTemplateQuery.WithContext(ctx).Create(tmpl); err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
|
||||
item := &super_dto.SuperNotificationTemplateItem{
|
||||
ID: tmpl.ID,
|
||||
TenantID: tmpl.TenantID,
|
||||
Name: tmpl.Name,
|
||||
Type: tmpl.Type,
|
||||
Title: tmpl.Title,
|
||||
Content: tmpl.Content,
|
||||
IsActive: tmpl.IsActive,
|
||||
CreatedAt: s.formatTime(tmpl.CreatedAt),
|
||||
UpdatedAt: s.formatTime(tmpl.UpdatedAt),
|
||||
}
|
||||
if tmpl.TenantID > 0 {
|
||||
tenantTbl, tenantQuery := models.TenantQuery.QueryContext(ctx)
|
||||
tenant, err := tenantQuery.Where(tenantTbl.ID.Eq(tmpl.TenantID)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if tenant != nil {
|
||||
item.TenantCode = tenant.Code
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (s *super) ListOrders(ctx context.Context, filter *super_dto.SuperOrderListFilter) (*requests.Pager, error) {
|
||||
tbl, q := models.OrderQuery.QueryContext(ctx)
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ field_type:
|
||||
type: consts.CouponType
|
||||
user_coupons:
|
||||
status: consts.UserCouponStatus
|
||||
notification_templates:
|
||||
type: consts.NotificationType
|
||||
field_relate:
|
||||
contents:
|
||||
Author:
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS notification_templates (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
type VARCHAR(32) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE notification_templates IS '通知模板:用于超管/运营预置通知内容,便于批量触达与统一管理。';
|
||||
COMMENT ON COLUMN notification_templates.id IS '模板主键ID,用于后台检索与引用。';
|
||||
COMMENT ON COLUMN notification_templates.tenant_id IS '归属租户ID(0 表示平台级模板);用于限制模板适用范围。';
|
||||
COMMENT ON COLUMN notification_templates.name IS '模板名称,用于后台识别用途(如“提现提醒”“内容审核通过”),不直接下发给用户。';
|
||||
COMMENT ON COLUMN notification_templates.type IS '通知类型(system/order/audit/interaction),需与前端枚举一致,用于分类与筛选。';
|
||||
COMMENT ON COLUMN notification_templates.title IS '通知标题,直接展示给用户的标题文本。';
|
||||
COMMENT ON COLUMN notification_templates.content IS '通知内容,直接展示给用户的正文,可包含简要说明与行动提示。';
|
||||
COMMENT ON COLUMN notification_templates.is_active IS '是否启用;禁用模板不可用于发送,便于临时下架或停用。';
|
||||
COMMENT ON COLUMN notification_templates.created_at IS '创建时间,按时间排序与审计使用。';
|
||||
COMMENT ON COLUMN notification_templates.updated_at IS '更新时间,记录最近一次编辑时间。';
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS notification_templates;
|
||||
@@ -40,9 +40,9 @@ type Content struct {
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp with time zone" json:"deleted_at"`
|
||||
Key string `gorm:"column:key;type:character varying(32);comment:Musical key/tone" json:"key"` // Musical key/tone
|
||||
IsPinned bool `gorm:"column:is_pinned;type:boolean;comment:Whether content is pinned/featured" json:"is_pinned"` // Whether content is pinned/featured
|
||||
Comments []*Comment `gorm:"foreignKey:ContentID;references:ID" json:"comments,omitempty"`
|
||||
Author *User `gorm:"foreignKey:UserID;references:ID" json:"author,omitempty"`
|
||||
ContentAssets []*ContentAsset `gorm:"foreignKey:ContentID;references:ID" json:"content_assets,omitempty"`
|
||||
Comments []*Comment `gorm:"foreignKey:ContentID;references:ID" json:"comments,omitempty"`
|
||||
}
|
||||
|
||||
// Quick operations without importing query package
|
||||
|
||||
@@ -46,12 +46,6 @@ func newContent(db *gorm.DB, opts ...gen.DOOption) contentQuery {
|
||||
_contentQuery.DeletedAt = field.NewField(tableName, "deleted_at")
|
||||
_contentQuery.Key = field.NewString(tableName, "key")
|
||||
_contentQuery.IsPinned = field.NewBool(tableName, "is_pinned")
|
||||
_contentQuery.Comments = contentQueryHasManyComments{
|
||||
db: db.Session(&gorm.Session{}),
|
||||
|
||||
RelationField: field.NewRelation("Comments", "Comment"),
|
||||
}
|
||||
|
||||
_contentQuery.Author = contentQueryBelongsToAuthor{
|
||||
db: db.Session(&gorm.Session{}),
|
||||
|
||||
@@ -64,6 +58,12 @@ func newContent(db *gorm.DB, opts ...gen.DOOption) contentQuery {
|
||||
RelationField: field.NewRelation("ContentAssets", "ContentAsset"),
|
||||
}
|
||||
|
||||
_contentQuery.Comments = contentQueryHasManyComments{
|
||||
db: db.Session(&gorm.Session{}),
|
||||
|
||||
RelationField: field.NewRelation("Comments", "Comment"),
|
||||
}
|
||||
|
||||
_contentQuery.fillFieldMap()
|
||||
|
||||
return _contentQuery
|
||||
@@ -94,12 +94,12 @@ type contentQuery struct {
|
||||
DeletedAt field.Field
|
||||
Key field.String // Musical key/tone
|
||||
IsPinned field.Bool // Whether content is pinned/featured
|
||||
Comments contentQueryHasManyComments
|
||||
|
||||
Author contentQueryBelongsToAuthor
|
||||
Author contentQueryBelongsToAuthor
|
||||
|
||||
ContentAssets contentQueryHasManyContentAssets
|
||||
|
||||
Comments contentQueryHasManyComments
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
}
|
||||
|
||||
@@ -195,104 +195,23 @@ func (c *contentQuery) fillFieldMap() {
|
||||
|
||||
func (c contentQuery) clone(db *gorm.DB) contentQuery {
|
||||
c.contentQueryDo.ReplaceConnPool(db.Statement.ConnPool)
|
||||
c.Comments.db = db.Session(&gorm.Session{Initialized: true})
|
||||
c.Comments.db.Statement.ConnPool = db.Statement.ConnPool
|
||||
c.Author.db = db.Session(&gorm.Session{Initialized: true})
|
||||
c.Author.db.Statement.ConnPool = db.Statement.ConnPool
|
||||
c.ContentAssets.db = db.Session(&gorm.Session{Initialized: true})
|
||||
c.ContentAssets.db.Statement.ConnPool = db.Statement.ConnPool
|
||||
c.Comments.db = db.Session(&gorm.Session{Initialized: true})
|
||||
c.Comments.db.Statement.ConnPool = db.Statement.ConnPool
|
||||
return c
|
||||
}
|
||||
|
||||
func (c contentQuery) replaceDB(db *gorm.DB) contentQuery {
|
||||
c.contentQueryDo.ReplaceDB(db)
|
||||
c.Comments.db = db.Session(&gorm.Session{})
|
||||
c.Author.db = db.Session(&gorm.Session{})
|
||||
c.ContentAssets.db = db.Session(&gorm.Session{})
|
||||
c.Comments.db = db.Session(&gorm.Session{})
|
||||
return c
|
||||
}
|
||||
|
||||
type contentQueryHasManyComments struct {
|
||||
db *gorm.DB
|
||||
|
||||
field.RelationField
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Where(conds ...field.Expr) *contentQueryHasManyComments {
|
||||
if len(conds) == 0 {
|
||||
return &a
|
||||
}
|
||||
|
||||
exprs := make([]clause.Expression, 0, len(conds))
|
||||
for _, cond := range conds {
|
||||
exprs = append(exprs, cond.BeCond().(clause.Expression))
|
||||
}
|
||||
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) WithContext(ctx context.Context) *contentQueryHasManyComments {
|
||||
a.db = a.db.WithContext(ctx)
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Session(session *gorm.Session) *contentQueryHasManyComments {
|
||||
a.db = a.db.Session(session)
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Model(m *Content) *contentQueryHasManyCommentsTx {
|
||||
return &contentQueryHasManyCommentsTx{a.db.Model(m).Association(a.Name())}
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Unscoped() *contentQueryHasManyComments {
|
||||
a.db = a.db.Unscoped()
|
||||
return &a
|
||||
}
|
||||
|
||||
type contentQueryHasManyCommentsTx struct{ tx *gorm.Association }
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Find() (result []*Comment, err error) {
|
||||
return result, a.tx.Find(&result)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Append(values ...*Comment) (err error) {
|
||||
targetValues := make([]interface{}, len(values))
|
||||
for i, v := range values {
|
||||
targetValues[i] = v
|
||||
}
|
||||
return a.tx.Append(targetValues...)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Replace(values ...*Comment) (err error) {
|
||||
targetValues := make([]interface{}, len(values))
|
||||
for i, v := range values {
|
||||
targetValues[i] = v
|
||||
}
|
||||
return a.tx.Replace(targetValues...)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Delete(values ...*Comment) (err error) {
|
||||
targetValues := make([]interface{}, len(values))
|
||||
for i, v := range values {
|
||||
targetValues[i] = v
|
||||
}
|
||||
return a.tx.Delete(targetValues...)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Clear() error {
|
||||
return a.tx.Clear()
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Count() int64 {
|
||||
return a.tx.Count()
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Unscoped() *contentQueryHasManyCommentsTx {
|
||||
a.tx = a.tx.Unscoped()
|
||||
return &a
|
||||
}
|
||||
|
||||
type contentQueryBelongsToAuthor struct {
|
||||
db *gorm.DB
|
||||
|
||||
@@ -455,6 +374,87 @@ func (a contentQueryHasManyContentAssetsTx) Unscoped() *contentQueryHasManyConte
|
||||
return &a
|
||||
}
|
||||
|
||||
type contentQueryHasManyComments struct {
|
||||
db *gorm.DB
|
||||
|
||||
field.RelationField
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Where(conds ...field.Expr) *contentQueryHasManyComments {
|
||||
if len(conds) == 0 {
|
||||
return &a
|
||||
}
|
||||
|
||||
exprs := make([]clause.Expression, 0, len(conds))
|
||||
for _, cond := range conds {
|
||||
exprs = append(exprs, cond.BeCond().(clause.Expression))
|
||||
}
|
||||
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) WithContext(ctx context.Context) *contentQueryHasManyComments {
|
||||
a.db = a.db.WithContext(ctx)
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Session(session *gorm.Session) *contentQueryHasManyComments {
|
||||
a.db = a.db.Session(session)
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Model(m *Content) *contentQueryHasManyCommentsTx {
|
||||
return &contentQueryHasManyCommentsTx{a.db.Model(m).Association(a.Name())}
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyComments) Unscoped() *contentQueryHasManyComments {
|
||||
a.db = a.db.Unscoped()
|
||||
return &a
|
||||
}
|
||||
|
||||
type contentQueryHasManyCommentsTx struct{ tx *gorm.Association }
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Find() (result []*Comment, err error) {
|
||||
return result, a.tx.Find(&result)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Append(values ...*Comment) (err error) {
|
||||
targetValues := make([]interface{}, len(values))
|
||||
for i, v := range values {
|
||||
targetValues[i] = v
|
||||
}
|
||||
return a.tx.Append(targetValues...)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Replace(values ...*Comment) (err error) {
|
||||
targetValues := make([]interface{}, len(values))
|
||||
for i, v := range values {
|
||||
targetValues[i] = v
|
||||
}
|
||||
return a.tx.Replace(targetValues...)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Delete(values ...*Comment) (err error) {
|
||||
targetValues := make([]interface{}, len(values))
|
||||
for i, v := range values {
|
||||
targetValues[i] = v
|
||||
}
|
||||
return a.tx.Delete(targetValues...)
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Clear() error {
|
||||
return a.tx.Clear()
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Count() int64 {
|
||||
return a.tx.Count()
|
||||
}
|
||||
|
||||
func (a contentQueryHasManyCommentsTx) Unscoped() *contentQueryHasManyCommentsTx {
|
||||
a.tx = a.tx.Unscoped()
|
||||
return &a
|
||||
}
|
||||
|
||||
type contentQueryDo struct{ gen.DO }
|
||||
|
||||
func (c contentQueryDo) Debug() *contentQueryDo {
|
||||
|
||||
65
backend/database/models/notification_templates.gen.go
Normal file
65
backend/database/models/notification_templates.gen.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Code generated by go.ipao.vip/gen. DO NOT EDIT.
|
||||
// Code generated by go.ipao.vip/gen. DO NOT EDIT.
|
||||
// Code generated by go.ipao.vip/gen. DO NOT EDIT.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"quyun/v2/pkg/consts"
|
||||
|
||||
"go.ipao.vip/gen"
|
||||
)
|
||||
|
||||
const TableNameNotificationTemplate = "notification_templates"
|
||||
|
||||
// NotificationTemplate mapped from table <notification_templates>
|
||||
type NotificationTemplate struct {
|
||||
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true;comment:模板主键ID,用于后台检索与引用。" json:"id"` // 模板主键ID,用于后台检索与引用。
|
||||
TenantID int64 `gorm:"column:tenant_id;type:bigint;not null;comment:归属租户ID(0 表示平台级模板);用于限制模板适用范围。" json:"tenant_id"` // 归属租户ID(0 表示平台级模板);用于限制模板适用范围。
|
||||
Name string `gorm:"column:name;type:character varying(128);not null;comment:模板名称,用于后台识别用途(如“提现提醒”“内容审核通过”),不直接下发给用户。" json:"name"` // 模板名称,用于后台识别用途(如“提现提醒”“内容审核通过”),不直接下发给用户。
|
||||
Type consts.NotificationType `gorm:"column:type;type:character varying(32);not null;comment:通知类型(system/order/audit/interaction),需与前端枚举一致,用于分类与筛选。" json:"type"` // 通知类型(system/order/audit/interaction),需与前端枚举一致,用于分类与筛选。
|
||||
Title string `gorm:"column:title;type:character varying(255);not null;comment:通知标题,直接展示给用户的标题文本。" json:"title"` // 通知标题,直接展示给用户的标题文本。
|
||||
Content string `gorm:"column:content;type:text;not null;comment:通知内容,直接展示给用户的正文,可包含简要说明与行动提示。" json:"content"` // 通知内容,直接展示给用户的正文,可包含简要说明与行动提示。
|
||||
IsActive bool `gorm:"column:is_active;type:boolean;not null;default:true;comment:是否启用;禁用模板不可用于发送,便于临时下架或停用。" json:"is_active"` // 是否启用;禁用模板不可用于发送,便于临时下架或停用。
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now();comment:创建时间,按时间排序与审计使用。" json:"created_at"` // 创建时间,按时间排序与审计使用。
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:now();comment:更新时间,记录最近一次编辑时间。" json:"updated_at"` // 更新时间,记录最近一次编辑时间。
|
||||
}
|
||||
|
||||
// Quick operations without importing query package
|
||||
// Update applies changed fields to the database using the default DB.
|
||||
func (m *NotificationTemplate) Update(ctx context.Context) (gen.ResultInfo, error) {
|
||||
return Q.NotificationTemplate.WithContext(ctx).Updates(m)
|
||||
}
|
||||
|
||||
// Save upserts the model using the default DB.
|
||||
func (m *NotificationTemplate) Save(ctx context.Context) error {
|
||||
return Q.NotificationTemplate.WithContext(ctx).Save(m)
|
||||
}
|
||||
|
||||
// Create inserts the model using the default DB.
|
||||
func (m *NotificationTemplate) Create(ctx context.Context) error {
|
||||
return Q.NotificationTemplate.WithContext(ctx).Create(m)
|
||||
}
|
||||
|
||||
// Delete removes the row represented by the model using the default DB.
|
||||
func (m *NotificationTemplate) Delete(ctx context.Context) (gen.ResultInfo, error) {
|
||||
return Q.NotificationTemplate.WithContext(ctx).Delete(m)
|
||||
}
|
||||
|
||||
// ForceDelete permanently deletes the row (ignores soft delete) using the default DB.
|
||||
func (m *NotificationTemplate) ForceDelete(ctx context.Context) (gen.ResultInfo, error) {
|
||||
return Q.NotificationTemplate.WithContext(ctx).Unscoped().Delete(m)
|
||||
}
|
||||
|
||||
// Reload reloads the model from database by its primary key and overwrites current fields.
|
||||
func (m *NotificationTemplate) Reload(ctx context.Context) error {
|
||||
fresh, err := Q.NotificationTemplate.WithContext(ctx).GetByID(m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = *fresh
|
||||
return nil
|
||||
}
|
||||
495
backend/database/models/notification_templates.query.gen.go
Normal file
495
backend/database/models/notification_templates.query.gen.go
Normal file
@@ -0,0 +1,495 @@
|
||||
// Code generated by go.ipao.vip/gen. DO NOT EDIT.
|
||||
// Code generated by go.ipao.vip/gen. DO NOT EDIT.
|
||||
// Code generated by go.ipao.vip/gen. DO NOT EDIT.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"gorm.io/gorm/schema"
|
||||
|
||||
"go.ipao.vip/gen"
|
||||
"go.ipao.vip/gen/field"
|
||||
|
||||
"gorm.io/plugin/dbresolver"
|
||||
)
|
||||
|
||||
func newNotificationTemplate(db *gorm.DB, opts ...gen.DOOption) notificationTemplateQuery {
|
||||
_notificationTemplateQuery := notificationTemplateQuery{}
|
||||
|
||||
_notificationTemplateQuery.notificationTemplateQueryDo.UseDB(db, opts...)
|
||||
_notificationTemplateQuery.notificationTemplateQueryDo.UseModel(&NotificationTemplate{})
|
||||
|
||||
tableName := _notificationTemplateQuery.notificationTemplateQueryDo.TableName()
|
||||
_notificationTemplateQuery.ALL = field.NewAsterisk(tableName)
|
||||
_notificationTemplateQuery.ID = field.NewInt64(tableName, "id")
|
||||
_notificationTemplateQuery.TenantID = field.NewInt64(tableName, "tenant_id")
|
||||
_notificationTemplateQuery.Name = field.NewString(tableName, "name")
|
||||
_notificationTemplateQuery.Type = field.NewField(tableName, "type")
|
||||
_notificationTemplateQuery.Title = field.NewString(tableName, "title")
|
||||
_notificationTemplateQuery.Content = field.NewString(tableName, "content")
|
||||
_notificationTemplateQuery.IsActive = field.NewBool(tableName, "is_active")
|
||||
_notificationTemplateQuery.CreatedAt = field.NewTime(tableName, "created_at")
|
||||
_notificationTemplateQuery.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||
|
||||
_notificationTemplateQuery.fillFieldMap()
|
||||
|
||||
return _notificationTemplateQuery
|
||||
}
|
||||
|
||||
type notificationTemplateQuery struct {
|
||||
notificationTemplateQueryDo notificationTemplateQueryDo
|
||||
|
||||
ALL field.Asterisk
|
||||
ID field.Int64 // 模板主键ID,用于后台检索与引用。
|
||||
TenantID field.Int64 // 归属租户ID(0 表示平台级模板);用于限制模板适用范围。
|
||||
Name field.String // 模板名称,用于后台识别用途(如“提现提醒”“内容审核通过”),不直接下发给用户。
|
||||
Type field.Field // 通知类型(system/order/audit/interaction),需与前端枚举一致,用于分类与筛选。
|
||||
Title field.String // 通知标题,直接展示给用户的标题文本。
|
||||
Content field.String // 通知内容,直接展示给用户的正文,可包含简要说明与行动提示。
|
||||
IsActive field.Bool // 是否启用;禁用模板不可用于发送,便于临时下架或停用。
|
||||
CreatedAt field.Time // 创建时间,按时间排序与审计使用。
|
||||
UpdatedAt field.Time // 更新时间,记录最近一次编辑时间。
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
}
|
||||
|
||||
func (n notificationTemplateQuery) Table(newTableName string) *notificationTemplateQuery {
|
||||
n.notificationTemplateQueryDo.UseTable(newTableName)
|
||||
return n.updateTableName(newTableName)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQuery) As(alias string) *notificationTemplateQuery {
|
||||
n.notificationTemplateQueryDo.DO = *(n.notificationTemplateQueryDo.As(alias).(*gen.DO))
|
||||
return n.updateTableName(alias)
|
||||
}
|
||||
|
||||
func (n *notificationTemplateQuery) updateTableName(table string) *notificationTemplateQuery {
|
||||
n.ALL = field.NewAsterisk(table)
|
||||
n.ID = field.NewInt64(table, "id")
|
||||
n.TenantID = field.NewInt64(table, "tenant_id")
|
||||
n.Name = field.NewString(table, "name")
|
||||
n.Type = field.NewField(table, "type")
|
||||
n.Title = field.NewString(table, "title")
|
||||
n.Content = field.NewString(table, "content")
|
||||
n.IsActive = field.NewBool(table, "is_active")
|
||||
n.CreatedAt = field.NewTime(table, "created_at")
|
||||
n.UpdatedAt = field.NewTime(table, "updated_at")
|
||||
|
||||
n.fillFieldMap()
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *notificationTemplateQuery) QueryContext(ctx context.Context) (*notificationTemplateQuery, *notificationTemplateQueryDo) {
|
||||
return n, n.notificationTemplateQueryDo.WithContext(ctx)
|
||||
}
|
||||
|
||||
func (n *notificationTemplateQuery) WithContext(ctx context.Context) *notificationTemplateQueryDo {
|
||||
return n.notificationTemplateQueryDo.WithContext(ctx)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQuery) TableName() string {
|
||||
return n.notificationTemplateQueryDo.TableName()
|
||||
}
|
||||
|
||||
func (n notificationTemplateQuery) Alias() string { return n.notificationTemplateQueryDo.Alias() }
|
||||
|
||||
func (n notificationTemplateQuery) Columns(cols ...field.Expr) gen.Columns {
|
||||
return n.notificationTemplateQueryDo.Columns(cols...)
|
||||
}
|
||||
|
||||
func (n *notificationTemplateQuery) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
||||
_f, ok := n.fieldMap[fieldName]
|
||||
if !ok || _f == nil {
|
||||
return nil, false
|
||||
}
|
||||
_oe, ok := _f.(field.OrderExpr)
|
||||
return _oe, ok
|
||||
}
|
||||
|
||||
func (n *notificationTemplateQuery) fillFieldMap() {
|
||||
n.fieldMap = make(map[string]field.Expr, 9)
|
||||
n.fieldMap["id"] = n.ID
|
||||
n.fieldMap["tenant_id"] = n.TenantID
|
||||
n.fieldMap["name"] = n.Name
|
||||
n.fieldMap["type"] = n.Type
|
||||
n.fieldMap["title"] = n.Title
|
||||
n.fieldMap["content"] = n.Content
|
||||
n.fieldMap["is_active"] = n.IsActive
|
||||
n.fieldMap["created_at"] = n.CreatedAt
|
||||
n.fieldMap["updated_at"] = n.UpdatedAt
|
||||
}
|
||||
|
||||
func (n notificationTemplateQuery) clone(db *gorm.DB) notificationTemplateQuery {
|
||||
n.notificationTemplateQueryDo.ReplaceConnPool(db.Statement.ConnPool)
|
||||
return n
|
||||
}
|
||||
|
||||
func (n notificationTemplateQuery) replaceDB(db *gorm.DB) notificationTemplateQuery {
|
||||
n.notificationTemplateQueryDo.ReplaceDB(db)
|
||||
return n
|
||||
}
|
||||
|
||||
type notificationTemplateQueryDo struct{ gen.DO }
|
||||
|
||||
func (n notificationTemplateQueryDo) Debug() *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Debug())
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) WithContext(ctx context.Context) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.WithContext(ctx))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) ReadDB() *notificationTemplateQueryDo {
|
||||
return n.Clauses(dbresolver.Read)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) WriteDB() *notificationTemplateQueryDo {
|
||||
return n.Clauses(dbresolver.Write)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Session(config *gorm.Session) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Session(config))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Clauses(conds ...clause.Expression) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Clauses(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Returning(value interface{}, columns ...string) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Returning(value, columns...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Not(conds ...gen.Condition) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Not(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Or(conds ...gen.Condition) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Or(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Select(conds ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Select(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Where(conds ...gen.Condition) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Where(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Order(conds ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Order(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Distinct(cols ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Distinct(cols...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Omit(cols ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Omit(cols...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Join(table schema.Tabler, on ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Join(table, on...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) LeftJoin(table schema.Tabler, on ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.LeftJoin(table, on...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) RightJoin(table schema.Tabler, on ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.RightJoin(table, on...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Group(cols ...field.Expr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Group(cols...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Having(conds ...gen.Condition) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Having(conds...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Limit(limit int) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Limit(limit))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Offset(offset int) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Offset(offset))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Scopes(funcs...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Unscoped() *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Unscoped())
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Create(values ...*NotificationTemplate) error {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
return n.DO.Create(values)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) CreateInBatches(values []*NotificationTemplate, batchSize int) error {
|
||||
return n.DO.CreateInBatches(values, batchSize)
|
||||
}
|
||||
|
||||
// Save : !!! underlying implementation is different with GORM
|
||||
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||
func (n notificationTemplateQueryDo) Save(values ...*NotificationTemplate) error {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
return n.DO.Save(values)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) First() (*NotificationTemplate, error) {
|
||||
if result, err := n.DO.First(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*NotificationTemplate), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Take() (*NotificationTemplate, error) {
|
||||
if result, err := n.DO.Take(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*NotificationTemplate), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Last() (*NotificationTemplate, error) {
|
||||
if result, err := n.DO.Last(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*NotificationTemplate), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Find() ([]*NotificationTemplate, error) {
|
||||
result, err := n.DO.Find()
|
||||
return result.([]*NotificationTemplate), err
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*NotificationTemplate, err error) {
|
||||
buf := make([]*NotificationTemplate, 0, batchSize)
|
||||
err = n.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
|
||||
defer func() { results = append(results, buf...) }()
|
||||
return fc(tx, batch)
|
||||
})
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) FindInBatches(result *[]*NotificationTemplate, batchSize int, fc func(tx gen.Dao, batch int) error) error {
|
||||
return n.DO.FindInBatches(result, batchSize, fc)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Attrs(attrs ...field.AssignExpr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Attrs(attrs...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Assign(attrs ...field.AssignExpr) *notificationTemplateQueryDo {
|
||||
return n.withDO(n.DO.Assign(attrs...))
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Joins(fields ...field.RelationField) *notificationTemplateQueryDo {
|
||||
for _, _f := range fields {
|
||||
n = *n.withDO(n.DO.Joins(_f))
|
||||
}
|
||||
return &n
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Preload(fields ...field.RelationField) *notificationTemplateQueryDo {
|
||||
for _, _f := range fields {
|
||||
n = *n.withDO(n.DO.Preload(_f))
|
||||
}
|
||||
return &n
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) FirstOrInit() (*NotificationTemplate, error) {
|
||||
if result, err := n.DO.FirstOrInit(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*NotificationTemplate), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) FirstOrCreate() (*NotificationTemplate, error) {
|
||||
if result, err := n.DO.FirstOrCreate(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*NotificationTemplate), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) FindByPage(offset int, limit int) (result []*NotificationTemplate, count int64, err error) {
|
||||
result, err = n.Offset(offset).Limit(limit).Find()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if size := len(result); 0 < limit && 0 < size && size < limit {
|
||||
count = int64(size + offset)
|
||||
return
|
||||
}
|
||||
|
||||
count, err = n.Offset(-1).Limit(-1).Count()
|
||||
return
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
|
||||
count, err = n.Count()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = n.Offset(offset).Limit(limit).Scan(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Scan(result interface{}) (err error) {
|
||||
return n.DO.Scan(result)
|
||||
}
|
||||
|
||||
func (n notificationTemplateQueryDo) Delete(models ...*NotificationTemplate) (result gen.ResultInfo, err error) {
|
||||
return n.DO.Delete(models)
|
||||
}
|
||||
|
||||
// ForceDelete performs a permanent delete (ignores soft-delete) for current scope.
|
||||
func (n notificationTemplateQueryDo) ForceDelete() (gen.ResultInfo, error) {
|
||||
return n.Unscoped().Delete()
|
||||
}
|
||||
|
||||
// Inc increases the given column by step for current scope.
|
||||
func (n notificationTemplateQueryDo) Inc(column field.Expr, step int64) (gen.ResultInfo, error) {
|
||||
// column = column + step
|
||||
e := field.NewUnsafeFieldRaw("?+?", column.RawExpr(), step)
|
||||
return n.DO.UpdateColumn(column, e)
|
||||
}
|
||||
|
||||
// Dec decreases the given column by step for current scope.
|
||||
func (n notificationTemplateQueryDo) Dec(column field.Expr, step int64) (gen.ResultInfo, error) {
|
||||
// column = column - step
|
||||
e := field.NewUnsafeFieldRaw("?-?", column.RawExpr(), step)
|
||||
return n.DO.UpdateColumn(column, e)
|
||||
}
|
||||
|
||||
// Sum returns SUM(column) for current scope.
|
||||
func (n notificationTemplateQueryDo) Sum(column field.Expr) (float64, error) {
|
||||
var _v float64
|
||||
agg := field.NewUnsafeFieldRaw("SUM(?)", column.RawExpr())
|
||||
if err := n.Select(agg).Scan(&_v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return _v, nil
|
||||
}
|
||||
|
||||
// Avg returns AVG(column) for current scope.
|
||||
func (n notificationTemplateQueryDo) Avg(column field.Expr) (float64, error) {
|
||||
var _v float64
|
||||
agg := field.NewUnsafeFieldRaw("AVG(?)", column.RawExpr())
|
||||
if err := n.Select(agg).Scan(&_v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return _v, nil
|
||||
}
|
||||
|
||||
// Min returns MIN(column) for current scope.
|
||||
func (n notificationTemplateQueryDo) Min(column field.Expr) (float64, error) {
|
||||
var _v float64
|
||||
agg := field.NewUnsafeFieldRaw("MIN(?)", column.RawExpr())
|
||||
if err := n.Select(agg).Scan(&_v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return _v, nil
|
||||
}
|
||||
|
||||
// Max returns MAX(column) for current scope.
|
||||
func (n notificationTemplateQueryDo) Max(column field.Expr) (float64, error) {
|
||||
var _v float64
|
||||
agg := field.NewUnsafeFieldRaw("MAX(?)", column.RawExpr())
|
||||
if err := n.Select(agg).Scan(&_v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return _v, nil
|
||||
}
|
||||
|
||||
// PluckMap returns a map[key]value for selected key/value expressions within current scope.
|
||||
func (n notificationTemplateQueryDo) PluckMap(key, val field.Expr) (map[interface{}]interface{}, error) {
|
||||
do := n.Select(key, val)
|
||||
rows, err := do.DO.Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
mm := make(map[interface{}]interface{})
|
||||
for rows.Next() {
|
||||
var k interface{}
|
||||
var v interface{}
|
||||
if err := rows.Scan(&k, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mm[k] = v
|
||||
}
|
||||
return mm, rows.Err()
|
||||
}
|
||||
|
||||
// Exists returns true if any record matches the given conditions.
|
||||
func (n notificationTemplateQueryDo) Exists(conds ...gen.Condition) (bool, error) {
|
||||
cnt, err := n.Where(conds...).Count()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return cnt > 0, nil
|
||||
}
|
||||
|
||||
// PluckIDs returns all primary key values under current scope.
|
||||
func (n notificationTemplateQueryDo) PluckIDs() ([]int64, error) {
|
||||
ids := make([]int64, 0, 16)
|
||||
pk := field.NewInt64(n.TableName(), "id")
|
||||
if err := n.DO.Pluck(pk, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// GetByID finds a single record by primary key.
|
||||
func (n notificationTemplateQueryDo) GetByID(id int64) (*NotificationTemplate, error) {
|
||||
pk := field.NewInt64(n.TableName(), "id")
|
||||
return n.Where(pk.Eq(id)).First()
|
||||
}
|
||||
|
||||
// GetByIDs finds records by primary key list.
|
||||
func (n notificationTemplateQueryDo) GetByIDs(ids ...int64) ([]*NotificationTemplate, error) {
|
||||
if len(ids) == 0 {
|
||||
return []*NotificationTemplate{}, nil
|
||||
}
|
||||
pk := field.NewInt64(n.TableName(), "id")
|
||||
return n.Where(pk.In(ids...)).Find()
|
||||
}
|
||||
|
||||
// DeleteByID deletes records by primary key.
|
||||
func (n notificationTemplateQueryDo) DeleteByID(id int64) (gen.ResultInfo, error) {
|
||||
pk := field.NewInt64(n.TableName(), "id")
|
||||
return n.Where(pk.Eq(id)).Delete()
|
||||
}
|
||||
|
||||
// DeleteByIDs deletes records by a list of primary keys.
|
||||
func (n notificationTemplateQueryDo) DeleteByIDs(ids ...int64) (gen.ResultInfo, error) {
|
||||
if len(ids) == 0 {
|
||||
return gen.ResultInfo{RowsAffected: 0, Error: nil}, nil
|
||||
}
|
||||
pk := field.NewInt64(n.TableName(), "id")
|
||||
return n.Where(pk.In(ids...)).Delete()
|
||||
}
|
||||
|
||||
func (n *notificationTemplateQueryDo) withDO(do gen.Dao) *notificationTemplateQueryDo {
|
||||
n.DO = *do.(*gen.DO)
|
||||
return n
|
||||
}
|
||||
@@ -16,27 +16,28 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
Q = new(Query)
|
||||
CommentQuery *commentQuery
|
||||
ContentQuery *contentQuery
|
||||
ContentAccessQuery *contentAccessQuery
|
||||
ContentAssetQuery *contentAssetQuery
|
||||
ContentPriceQuery *contentPriceQuery
|
||||
CouponQuery *couponQuery
|
||||
MediaAssetQuery *mediaAssetQuery
|
||||
NotificationQuery *notificationQuery
|
||||
OrderQuery *orderQuery
|
||||
OrderItemQuery *orderItemQuery
|
||||
PayoutAccountQuery *payoutAccountQuery
|
||||
TenantQuery *tenantQuery
|
||||
TenantInviteQuery *tenantInviteQuery
|
||||
TenantJoinRequestQuery *tenantJoinRequestQuery
|
||||
TenantLedgerQuery *tenantLedgerQuery
|
||||
TenantUserQuery *tenantUserQuery
|
||||
UserQuery *userQuery
|
||||
UserCommentActionQuery *userCommentActionQuery
|
||||
UserContentActionQuery *userContentActionQuery
|
||||
UserCouponQuery *userCouponQuery
|
||||
Q = new(Query)
|
||||
CommentQuery *commentQuery
|
||||
ContentQuery *contentQuery
|
||||
ContentAccessQuery *contentAccessQuery
|
||||
ContentAssetQuery *contentAssetQuery
|
||||
ContentPriceQuery *contentPriceQuery
|
||||
CouponQuery *couponQuery
|
||||
MediaAssetQuery *mediaAssetQuery
|
||||
NotificationQuery *notificationQuery
|
||||
NotificationTemplateQuery *notificationTemplateQuery
|
||||
OrderQuery *orderQuery
|
||||
OrderItemQuery *orderItemQuery
|
||||
PayoutAccountQuery *payoutAccountQuery
|
||||
TenantQuery *tenantQuery
|
||||
TenantInviteQuery *tenantInviteQuery
|
||||
TenantJoinRequestQuery *tenantJoinRequestQuery
|
||||
TenantLedgerQuery *tenantLedgerQuery
|
||||
TenantUserQuery *tenantUserQuery
|
||||
UserQuery *userQuery
|
||||
UserCommentActionQuery *userCommentActionQuery
|
||||
UserContentActionQuery *userContentActionQuery
|
||||
UserCouponQuery *userCouponQuery
|
||||
)
|
||||
|
||||
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
||||
@@ -49,6 +50,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
||||
CouponQuery = &Q.Coupon
|
||||
MediaAssetQuery = &Q.MediaAsset
|
||||
NotificationQuery = &Q.Notification
|
||||
NotificationTemplateQuery = &Q.NotificationTemplate
|
||||
OrderQuery = &Q.Order
|
||||
OrderItemQuery = &Q.OrderItem
|
||||
PayoutAccountQuery = &Q.PayoutAccount
|
||||
@@ -65,80 +67,83 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
||||
|
||||
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
|
||||
return &Query{
|
||||
db: db,
|
||||
Comment: newComment(db, opts...),
|
||||
Content: newContent(db, opts...),
|
||||
ContentAccess: newContentAccess(db, opts...),
|
||||
ContentAsset: newContentAsset(db, opts...),
|
||||
ContentPrice: newContentPrice(db, opts...),
|
||||
Coupon: newCoupon(db, opts...),
|
||||
MediaAsset: newMediaAsset(db, opts...),
|
||||
Notification: newNotification(db, opts...),
|
||||
Order: newOrder(db, opts...),
|
||||
OrderItem: newOrderItem(db, opts...),
|
||||
PayoutAccount: newPayoutAccount(db, opts...),
|
||||
Tenant: newTenant(db, opts...),
|
||||
TenantInvite: newTenantInvite(db, opts...),
|
||||
TenantJoinRequest: newTenantJoinRequest(db, opts...),
|
||||
TenantLedger: newTenantLedger(db, opts...),
|
||||
TenantUser: newTenantUser(db, opts...),
|
||||
User: newUser(db, opts...),
|
||||
UserCommentAction: newUserCommentAction(db, opts...),
|
||||
UserContentAction: newUserContentAction(db, opts...),
|
||||
UserCoupon: newUserCoupon(db, opts...),
|
||||
db: db,
|
||||
Comment: newComment(db, opts...),
|
||||
Content: newContent(db, opts...),
|
||||
ContentAccess: newContentAccess(db, opts...),
|
||||
ContentAsset: newContentAsset(db, opts...),
|
||||
ContentPrice: newContentPrice(db, opts...),
|
||||
Coupon: newCoupon(db, opts...),
|
||||
MediaAsset: newMediaAsset(db, opts...),
|
||||
Notification: newNotification(db, opts...),
|
||||
NotificationTemplate: newNotificationTemplate(db, opts...),
|
||||
Order: newOrder(db, opts...),
|
||||
OrderItem: newOrderItem(db, opts...),
|
||||
PayoutAccount: newPayoutAccount(db, opts...),
|
||||
Tenant: newTenant(db, opts...),
|
||||
TenantInvite: newTenantInvite(db, opts...),
|
||||
TenantJoinRequest: newTenantJoinRequest(db, opts...),
|
||||
TenantLedger: newTenantLedger(db, opts...),
|
||||
TenantUser: newTenantUser(db, opts...),
|
||||
User: newUser(db, opts...),
|
||||
UserCommentAction: newUserCommentAction(db, opts...),
|
||||
UserContentAction: newUserContentAction(db, opts...),
|
||||
UserCoupon: newUserCoupon(db, opts...),
|
||||
}
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
db *gorm.DB
|
||||
|
||||
Comment commentQuery
|
||||
Content contentQuery
|
||||
ContentAccess contentAccessQuery
|
||||
ContentAsset contentAssetQuery
|
||||
ContentPrice contentPriceQuery
|
||||
Coupon couponQuery
|
||||
MediaAsset mediaAssetQuery
|
||||
Notification notificationQuery
|
||||
Order orderQuery
|
||||
OrderItem orderItemQuery
|
||||
PayoutAccount payoutAccountQuery
|
||||
Tenant tenantQuery
|
||||
TenantInvite tenantInviteQuery
|
||||
TenantJoinRequest tenantJoinRequestQuery
|
||||
TenantLedger tenantLedgerQuery
|
||||
TenantUser tenantUserQuery
|
||||
User userQuery
|
||||
UserCommentAction userCommentActionQuery
|
||||
UserContentAction userContentActionQuery
|
||||
UserCoupon userCouponQuery
|
||||
Comment commentQuery
|
||||
Content contentQuery
|
||||
ContentAccess contentAccessQuery
|
||||
ContentAsset contentAssetQuery
|
||||
ContentPrice contentPriceQuery
|
||||
Coupon couponQuery
|
||||
MediaAsset mediaAssetQuery
|
||||
Notification notificationQuery
|
||||
NotificationTemplate notificationTemplateQuery
|
||||
Order orderQuery
|
||||
OrderItem orderItemQuery
|
||||
PayoutAccount payoutAccountQuery
|
||||
Tenant tenantQuery
|
||||
TenantInvite tenantInviteQuery
|
||||
TenantJoinRequest tenantJoinRequestQuery
|
||||
TenantLedger tenantLedgerQuery
|
||||
TenantUser tenantUserQuery
|
||||
User userQuery
|
||||
UserCommentAction userCommentActionQuery
|
||||
UserContentAction userContentActionQuery
|
||||
UserCoupon userCouponQuery
|
||||
}
|
||||
|
||||
func (q *Query) Available() bool { return q.db != nil }
|
||||
|
||||
func (q *Query) clone(db *gorm.DB) *Query {
|
||||
return &Query{
|
||||
db: db,
|
||||
Comment: q.Comment.clone(db),
|
||||
Content: q.Content.clone(db),
|
||||
ContentAccess: q.ContentAccess.clone(db),
|
||||
ContentAsset: q.ContentAsset.clone(db),
|
||||
ContentPrice: q.ContentPrice.clone(db),
|
||||
Coupon: q.Coupon.clone(db),
|
||||
MediaAsset: q.MediaAsset.clone(db),
|
||||
Notification: q.Notification.clone(db),
|
||||
Order: q.Order.clone(db),
|
||||
OrderItem: q.OrderItem.clone(db),
|
||||
PayoutAccount: q.PayoutAccount.clone(db),
|
||||
Tenant: q.Tenant.clone(db),
|
||||
TenantInvite: q.TenantInvite.clone(db),
|
||||
TenantJoinRequest: q.TenantJoinRequest.clone(db),
|
||||
TenantLedger: q.TenantLedger.clone(db),
|
||||
TenantUser: q.TenantUser.clone(db),
|
||||
User: q.User.clone(db),
|
||||
UserCommentAction: q.UserCommentAction.clone(db),
|
||||
UserContentAction: q.UserContentAction.clone(db),
|
||||
UserCoupon: q.UserCoupon.clone(db),
|
||||
db: db,
|
||||
Comment: q.Comment.clone(db),
|
||||
Content: q.Content.clone(db),
|
||||
ContentAccess: q.ContentAccess.clone(db),
|
||||
ContentAsset: q.ContentAsset.clone(db),
|
||||
ContentPrice: q.ContentPrice.clone(db),
|
||||
Coupon: q.Coupon.clone(db),
|
||||
MediaAsset: q.MediaAsset.clone(db),
|
||||
Notification: q.Notification.clone(db),
|
||||
NotificationTemplate: q.NotificationTemplate.clone(db),
|
||||
Order: q.Order.clone(db),
|
||||
OrderItem: q.OrderItem.clone(db),
|
||||
PayoutAccount: q.PayoutAccount.clone(db),
|
||||
Tenant: q.Tenant.clone(db),
|
||||
TenantInvite: q.TenantInvite.clone(db),
|
||||
TenantJoinRequest: q.TenantJoinRequest.clone(db),
|
||||
TenantLedger: q.TenantLedger.clone(db),
|
||||
TenantUser: q.TenantUser.clone(db),
|
||||
User: q.User.clone(db),
|
||||
UserCommentAction: q.UserCommentAction.clone(db),
|
||||
UserContentAction: q.UserContentAction.clone(db),
|
||||
UserCoupon: q.UserCoupon.clone(db),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,75 +157,78 @@ func (q *Query) WriteDB() *Query {
|
||||
|
||||
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
|
||||
return &Query{
|
||||
db: db,
|
||||
Comment: q.Comment.replaceDB(db),
|
||||
Content: q.Content.replaceDB(db),
|
||||
ContentAccess: q.ContentAccess.replaceDB(db),
|
||||
ContentAsset: q.ContentAsset.replaceDB(db),
|
||||
ContentPrice: q.ContentPrice.replaceDB(db),
|
||||
Coupon: q.Coupon.replaceDB(db),
|
||||
MediaAsset: q.MediaAsset.replaceDB(db),
|
||||
Notification: q.Notification.replaceDB(db),
|
||||
Order: q.Order.replaceDB(db),
|
||||
OrderItem: q.OrderItem.replaceDB(db),
|
||||
PayoutAccount: q.PayoutAccount.replaceDB(db),
|
||||
Tenant: q.Tenant.replaceDB(db),
|
||||
TenantInvite: q.TenantInvite.replaceDB(db),
|
||||
TenantJoinRequest: q.TenantJoinRequest.replaceDB(db),
|
||||
TenantLedger: q.TenantLedger.replaceDB(db),
|
||||
TenantUser: q.TenantUser.replaceDB(db),
|
||||
User: q.User.replaceDB(db),
|
||||
UserCommentAction: q.UserCommentAction.replaceDB(db),
|
||||
UserContentAction: q.UserContentAction.replaceDB(db),
|
||||
UserCoupon: q.UserCoupon.replaceDB(db),
|
||||
db: db,
|
||||
Comment: q.Comment.replaceDB(db),
|
||||
Content: q.Content.replaceDB(db),
|
||||
ContentAccess: q.ContentAccess.replaceDB(db),
|
||||
ContentAsset: q.ContentAsset.replaceDB(db),
|
||||
ContentPrice: q.ContentPrice.replaceDB(db),
|
||||
Coupon: q.Coupon.replaceDB(db),
|
||||
MediaAsset: q.MediaAsset.replaceDB(db),
|
||||
Notification: q.Notification.replaceDB(db),
|
||||
NotificationTemplate: q.NotificationTemplate.replaceDB(db),
|
||||
Order: q.Order.replaceDB(db),
|
||||
OrderItem: q.OrderItem.replaceDB(db),
|
||||
PayoutAccount: q.PayoutAccount.replaceDB(db),
|
||||
Tenant: q.Tenant.replaceDB(db),
|
||||
TenantInvite: q.TenantInvite.replaceDB(db),
|
||||
TenantJoinRequest: q.TenantJoinRequest.replaceDB(db),
|
||||
TenantLedger: q.TenantLedger.replaceDB(db),
|
||||
TenantUser: q.TenantUser.replaceDB(db),
|
||||
User: q.User.replaceDB(db),
|
||||
UserCommentAction: q.UserCommentAction.replaceDB(db),
|
||||
UserContentAction: q.UserContentAction.replaceDB(db),
|
||||
UserCoupon: q.UserCoupon.replaceDB(db),
|
||||
}
|
||||
}
|
||||
|
||||
type queryCtx struct {
|
||||
Comment *commentQueryDo
|
||||
Content *contentQueryDo
|
||||
ContentAccess *contentAccessQueryDo
|
||||
ContentAsset *contentAssetQueryDo
|
||||
ContentPrice *contentPriceQueryDo
|
||||
Coupon *couponQueryDo
|
||||
MediaAsset *mediaAssetQueryDo
|
||||
Notification *notificationQueryDo
|
||||
Order *orderQueryDo
|
||||
OrderItem *orderItemQueryDo
|
||||
PayoutAccount *payoutAccountQueryDo
|
||||
Tenant *tenantQueryDo
|
||||
TenantInvite *tenantInviteQueryDo
|
||||
TenantJoinRequest *tenantJoinRequestQueryDo
|
||||
TenantLedger *tenantLedgerQueryDo
|
||||
TenantUser *tenantUserQueryDo
|
||||
User *userQueryDo
|
||||
UserCommentAction *userCommentActionQueryDo
|
||||
UserContentAction *userContentActionQueryDo
|
||||
UserCoupon *userCouponQueryDo
|
||||
Comment *commentQueryDo
|
||||
Content *contentQueryDo
|
||||
ContentAccess *contentAccessQueryDo
|
||||
ContentAsset *contentAssetQueryDo
|
||||
ContentPrice *contentPriceQueryDo
|
||||
Coupon *couponQueryDo
|
||||
MediaAsset *mediaAssetQueryDo
|
||||
Notification *notificationQueryDo
|
||||
NotificationTemplate *notificationTemplateQueryDo
|
||||
Order *orderQueryDo
|
||||
OrderItem *orderItemQueryDo
|
||||
PayoutAccount *payoutAccountQueryDo
|
||||
Tenant *tenantQueryDo
|
||||
TenantInvite *tenantInviteQueryDo
|
||||
TenantJoinRequest *tenantJoinRequestQueryDo
|
||||
TenantLedger *tenantLedgerQueryDo
|
||||
TenantUser *tenantUserQueryDo
|
||||
User *userQueryDo
|
||||
UserCommentAction *userCommentActionQueryDo
|
||||
UserContentAction *userContentActionQueryDo
|
||||
UserCoupon *userCouponQueryDo
|
||||
}
|
||||
|
||||
func (q *Query) WithContext(ctx context.Context) *queryCtx {
|
||||
return &queryCtx{
|
||||
Comment: q.Comment.WithContext(ctx),
|
||||
Content: q.Content.WithContext(ctx),
|
||||
ContentAccess: q.ContentAccess.WithContext(ctx),
|
||||
ContentAsset: q.ContentAsset.WithContext(ctx),
|
||||
ContentPrice: q.ContentPrice.WithContext(ctx),
|
||||
Coupon: q.Coupon.WithContext(ctx),
|
||||
MediaAsset: q.MediaAsset.WithContext(ctx),
|
||||
Notification: q.Notification.WithContext(ctx),
|
||||
Order: q.Order.WithContext(ctx),
|
||||
OrderItem: q.OrderItem.WithContext(ctx),
|
||||
PayoutAccount: q.PayoutAccount.WithContext(ctx),
|
||||
Tenant: q.Tenant.WithContext(ctx),
|
||||
TenantInvite: q.TenantInvite.WithContext(ctx),
|
||||
TenantJoinRequest: q.TenantJoinRequest.WithContext(ctx),
|
||||
TenantLedger: q.TenantLedger.WithContext(ctx),
|
||||
TenantUser: q.TenantUser.WithContext(ctx),
|
||||
User: q.User.WithContext(ctx),
|
||||
UserCommentAction: q.UserCommentAction.WithContext(ctx),
|
||||
UserContentAction: q.UserContentAction.WithContext(ctx),
|
||||
UserCoupon: q.UserCoupon.WithContext(ctx),
|
||||
Comment: q.Comment.WithContext(ctx),
|
||||
Content: q.Content.WithContext(ctx),
|
||||
ContentAccess: q.ContentAccess.WithContext(ctx),
|
||||
ContentAsset: q.ContentAsset.WithContext(ctx),
|
||||
ContentPrice: q.ContentPrice.WithContext(ctx),
|
||||
Coupon: q.Coupon.WithContext(ctx),
|
||||
MediaAsset: q.MediaAsset.WithContext(ctx),
|
||||
Notification: q.Notification.WithContext(ctx),
|
||||
NotificationTemplate: q.NotificationTemplate.WithContext(ctx),
|
||||
Order: q.Order.WithContext(ctx),
|
||||
OrderItem: q.OrderItem.WithContext(ctx),
|
||||
PayoutAccount: q.PayoutAccount.WithContext(ctx),
|
||||
Tenant: q.Tenant.WithContext(ctx),
|
||||
TenantInvite: q.TenantInvite.WithContext(ctx),
|
||||
TenantJoinRequest: q.TenantJoinRequest.WithContext(ctx),
|
||||
TenantLedger: q.TenantLedger.WithContext(ctx),
|
||||
TenantUser: q.TenantUser.WithContext(ctx),
|
||||
User: q.User.WithContext(ctx),
|
||||
UserCommentAction: q.UserCommentAction.WithContext(ctx),
|
||||
UserContentAction: q.UserContentAction.WithContext(ctx),
|
||||
UserCoupon: q.UserCoupon.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,120 @@ const docTemplate = `{
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/super/v1/assets": {
|
||||
"get": {
|
||||
"description": "List assets across tenants",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"summary": "List assets",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/requests.Pager"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperAssetItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/assets/usage": {
|
||||
"get": {
|
||||
"description": "Asset usage statistics",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"summary": "Asset usage",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperAssetUsageResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/assets/{id}": {
|
||||
"delete": {
|
||||
"description": "Delete asset",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"summary": "Delete asset",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Asset ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "Force delete",
|
||||
"name": "force",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Deleted",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/auth/login": {
|
||||
"post": {
|
||||
"description": "Login",
|
||||
@@ -524,6 +638,162 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/notifications": {
|
||||
"get": {
|
||||
"description": "List notifications across tenants",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "List notifications",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/requests.Pager"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/notifications/broadcast": {
|
||||
"post": {
|
||||
"description": "Broadcast notification to users or tenant members",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "Broadcast notification",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Broadcast form",
|
||||
"name": "form",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationBroadcastForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Sent",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/notifications/templates": {
|
||||
"get": {
|
||||
"description": "List notification templates",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "List notification templates",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/requests.Pager"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationTemplateItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Create notification template",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "Create notification template",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Template form",
|
||||
"name": "form",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationTemplateCreateForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationTemplateItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/orders": {
|
||||
"get": {
|
||||
"description": "List orders",
|
||||
@@ -4976,6 +5246,62 @@ const docTemplate = `{
|
||||
"GenderSecret"
|
||||
]
|
||||
},
|
||||
"consts.MediaAssetStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"uploaded",
|
||||
"processing",
|
||||
"ready",
|
||||
"failed",
|
||||
"deleted"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"MediaAssetStatusUploaded",
|
||||
"MediaAssetStatusProcessing",
|
||||
"MediaAssetStatusReady",
|
||||
"MediaAssetStatusFailed",
|
||||
"MediaAssetStatusDeleted"
|
||||
]
|
||||
},
|
||||
"consts.MediaAssetType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"video",
|
||||
"audio",
|
||||
"image"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"MediaAssetTypeVideo",
|
||||
"MediaAssetTypeAudio",
|
||||
"MediaAssetTypeImage"
|
||||
]
|
||||
},
|
||||
"consts.MediaAssetVariant": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"main",
|
||||
"preview"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"MediaAssetVariantMain",
|
||||
"MediaAssetVariantPreview"
|
||||
]
|
||||
},
|
||||
"consts.NotificationType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"system",
|
||||
"order",
|
||||
"audit",
|
||||
"interaction"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"NotificationTypeSystem",
|
||||
"NotificationTypeOrder",
|
||||
"NotificationTypeAudit",
|
||||
"NotificationTypeInteraction"
|
||||
]
|
||||
},
|
||||
"consts.OrderStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -6348,6 +6674,144 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperAssetItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket": {
|
||||
"description": "Bucket 存储桶名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"description": "CreatedAt 创建时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"filename": {
|
||||
"description": "Filename 原始文件名。",
|
||||
"type": "string"
|
||||
},
|
||||
"hash": {
|
||||
"description": "Hash 文件哈希(MD5)。",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID 资产ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"object_key": {
|
||||
"description": "ObjectKey 对象Key。",
|
||||
"type": "string"
|
||||
},
|
||||
"provider": {
|
||||
"description": "Provider 存储提供方。",
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"description": "Size 文件大小(字节)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"source_asset_id": {
|
||||
"description": "SourceAssetID 源资产ID(用于变体关联)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"description": "Status 处理状态。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetStatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tenant_code": {
|
||||
"description": "TenantCode 租户编码。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"tenant_name": {
|
||||
"description": "TenantName 租户名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 媒体类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated_at": {
|
||||
"description": "UpdatedAt 更新时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"description": "URL 访问URL(若可用)。",
|
||||
"type": "string"
|
||||
},
|
||||
"used_count": {
|
||||
"description": "UsedCount 被内容引用次数。",
|
||||
"type": "integer"
|
||||
},
|
||||
"user_id": {
|
||||
"description": "UserID 上传用户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"description": "Username 上传用户名/昵称。",
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"description": "Variant 媒体变体(main/preview/cover 等)。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetVariant"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperAssetUsageItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"description": "Count 该类型资产数量。",
|
||||
"type": "integer"
|
||||
},
|
||||
"total_size": {
|
||||
"description": "TotalSize 该类型资产大小总和(字节)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 媒体类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetType"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperAssetUsageResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"by_type": {
|
||||
"description": "ByType 按媒体类型汇总的用量统计。",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperAssetUsageItem"
|
||||
}
|
||||
},
|
||||
"total_count": {
|
||||
"description": "TotalCount 资产总量。",
|
||||
"type": "integer"
|
||||
},
|
||||
"total_size": {
|
||||
"description": "TotalSize 资产总大小(字节)。",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperContentBatchReviewForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -6633,6 +7097,177 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationBroadcastForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 通知内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID(选填,用于指定租户成员)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 通知标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型(system/order/audit/interaction)。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_ids": {
|
||||
"description": "UserIDs 指定接收用户ID列表(优先级高于 TenantID)。",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 通知内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"description": "CreatedAt 创建时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID 通知ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"is_read": {
|
||||
"description": "IsRead 是否已读。",
|
||||
"type": "boolean"
|
||||
},
|
||||
"tenant_code": {
|
||||
"description": "TenantCode 租户编码。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"tenant_name": {
|
||||
"description": "TenantName 租户名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 通知标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_id": {
|
||||
"description": "UserID 用户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"description": "Username 用户名/昵称。",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationTemplateCreateForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 通知内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"description": "IsActive 是否启用(不传默认启用)。",
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name 模板名称(用于识别用途)。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID(不传代表全平台模板)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 通知标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型(system/order/audit/interaction)。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationTemplateItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 模板内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"description": "CreatedAt 创建时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID 模板ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"description": "IsActive 是否启用。",
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name 模板名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_code": {
|
||||
"description": "TenantCode 租户编码。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"tenant_name": {
|
||||
"description": "TenantName 租户名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 模板标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated_at": {
|
||||
"description": "UpdatedAt 更新时间(RFC3339)。",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperOrderDetail": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -18,6 +18,120 @@
|
||||
"host": "localhost:8080",
|
||||
"basePath": "/",
|
||||
"paths": {
|
||||
"/super/v1/assets": {
|
||||
"get": {
|
||||
"description": "List assets across tenants",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"summary": "List assets",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/requests.Pager"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperAssetItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/assets/usage": {
|
||||
"get": {
|
||||
"description": "Asset usage statistics",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"summary": "Asset usage",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperAssetUsageResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/assets/{id}": {
|
||||
"delete": {
|
||||
"description": "Delete asset",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"summary": "Delete asset",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Asset ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "Force delete",
|
||||
"name": "force",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Deleted",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/auth/login": {
|
||||
"post": {
|
||||
"description": "Login",
|
||||
@@ -518,6 +632,162 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/notifications": {
|
||||
"get": {
|
||||
"description": "List notifications across tenants",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "List notifications",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/requests.Pager"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/notifications/broadcast": {
|
||||
"post": {
|
||||
"description": "Broadcast notification to users or tenant members",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "Broadcast notification",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Broadcast form",
|
||||
"name": "form",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationBroadcastForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Sent",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/notifications/templates": {
|
||||
"get": {
|
||||
"description": "List notification templates",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "List notification templates",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/requests.Pager"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationTemplateItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Create notification template",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Notification"
|
||||
],
|
||||
"summary": "Create notification template",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Template form",
|
||||
"name": "form",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationTemplateCreateForm"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SuperNotificationTemplateItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/super/v1/orders": {
|
||||
"get": {
|
||||
"description": "List orders",
|
||||
@@ -4970,6 +5240,62 @@
|
||||
"GenderSecret"
|
||||
]
|
||||
},
|
||||
"consts.MediaAssetStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"uploaded",
|
||||
"processing",
|
||||
"ready",
|
||||
"failed",
|
||||
"deleted"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"MediaAssetStatusUploaded",
|
||||
"MediaAssetStatusProcessing",
|
||||
"MediaAssetStatusReady",
|
||||
"MediaAssetStatusFailed",
|
||||
"MediaAssetStatusDeleted"
|
||||
]
|
||||
},
|
||||
"consts.MediaAssetType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"video",
|
||||
"audio",
|
||||
"image"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"MediaAssetTypeVideo",
|
||||
"MediaAssetTypeAudio",
|
||||
"MediaAssetTypeImage"
|
||||
]
|
||||
},
|
||||
"consts.MediaAssetVariant": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"main",
|
||||
"preview"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"MediaAssetVariantMain",
|
||||
"MediaAssetVariantPreview"
|
||||
]
|
||||
},
|
||||
"consts.NotificationType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"system",
|
||||
"order",
|
||||
"audit",
|
||||
"interaction"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"NotificationTypeSystem",
|
||||
"NotificationTypeOrder",
|
||||
"NotificationTypeAudit",
|
||||
"NotificationTypeInteraction"
|
||||
]
|
||||
},
|
||||
"consts.OrderStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -6342,6 +6668,144 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperAssetItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket": {
|
||||
"description": "Bucket 存储桶名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"description": "CreatedAt 创建时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"filename": {
|
||||
"description": "Filename 原始文件名。",
|
||||
"type": "string"
|
||||
},
|
||||
"hash": {
|
||||
"description": "Hash 文件哈希(MD5)。",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID 资产ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"object_key": {
|
||||
"description": "ObjectKey 对象Key。",
|
||||
"type": "string"
|
||||
},
|
||||
"provider": {
|
||||
"description": "Provider 存储提供方。",
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"description": "Size 文件大小(字节)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"source_asset_id": {
|
||||
"description": "SourceAssetID 源资产ID(用于变体关联)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"description": "Status 处理状态。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetStatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tenant_code": {
|
||||
"description": "TenantCode 租户编码。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"tenant_name": {
|
||||
"description": "TenantName 租户名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 媒体类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated_at": {
|
||||
"description": "UpdatedAt 更新时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"description": "URL 访问URL(若可用)。",
|
||||
"type": "string"
|
||||
},
|
||||
"used_count": {
|
||||
"description": "UsedCount 被内容引用次数。",
|
||||
"type": "integer"
|
||||
},
|
||||
"user_id": {
|
||||
"description": "UserID 上传用户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"description": "Username 上传用户名/昵称。",
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"description": "Variant 媒体变体(main/preview/cover 等)。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetVariant"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperAssetUsageItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"description": "Count 该类型资产数量。",
|
||||
"type": "integer"
|
||||
},
|
||||
"total_size": {
|
||||
"description": "TotalSize 该类型资产大小总和(字节)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 媒体类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.MediaAssetType"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperAssetUsageResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"by_type": {
|
||||
"description": "ByType 按媒体类型汇总的用量统计。",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.SuperAssetUsageItem"
|
||||
}
|
||||
},
|
||||
"total_count": {
|
||||
"description": "TotalCount 资产总量。",
|
||||
"type": "integer"
|
||||
},
|
||||
"total_size": {
|
||||
"description": "TotalSize 资产总大小(字节)。",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperContentBatchReviewForm": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -6627,6 +7091,177 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationBroadcastForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 通知内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID(选填,用于指定租户成员)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 通知标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型(system/order/audit/interaction)。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_ids": {
|
||||
"description": "UserIDs 指定接收用户ID列表(优先级高于 TenantID)。",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 通知内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"description": "CreatedAt 创建时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID 通知ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"is_read": {
|
||||
"description": "IsRead 是否已读。",
|
||||
"type": "boolean"
|
||||
},
|
||||
"tenant_code": {
|
||||
"description": "TenantCode 租户编码。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"tenant_name": {
|
||||
"description": "TenantName 租户名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 通知标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_id": {
|
||||
"description": "UserID 用户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"username": {
|
||||
"description": "Username 用户名/昵称。",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationTemplateCreateForm": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 通知内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"description": "IsActive 是否启用(不传默认启用)。",
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name 模板名称(用于识别用途)。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID(不传代表全平台模板)。",
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 通知标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型(system/order/audit/interaction)。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperNotificationTemplateItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "Content 模板内容。",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"description": "CreatedAt 创建时间(RFC3339)。",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID 模板ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"description": "IsActive 是否启用。",
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"description": "Name 模板名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_code": {
|
||||
"description": "TenantCode 租户编码。",
|
||||
"type": "string"
|
||||
},
|
||||
"tenant_id": {
|
||||
"description": "TenantID 租户ID。",
|
||||
"type": "integer"
|
||||
},
|
||||
"tenant_name": {
|
||||
"description": "TenantName 租户名称。",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "Title 模板标题。",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type 通知类型。",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/consts.NotificationType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated_at": {
|
||||
"description": "UpdatedAt 更新时间(RFC3339)。",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SuperOrderDetail": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -38,6 +38,50 @@ definitions:
|
||||
- GenderMale
|
||||
- GenderFemale
|
||||
- GenderSecret
|
||||
consts.MediaAssetStatus:
|
||||
enum:
|
||||
- uploaded
|
||||
- processing
|
||||
- ready
|
||||
- failed
|
||||
- deleted
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- MediaAssetStatusUploaded
|
||||
- MediaAssetStatusProcessing
|
||||
- MediaAssetStatusReady
|
||||
- MediaAssetStatusFailed
|
||||
- MediaAssetStatusDeleted
|
||||
consts.MediaAssetType:
|
||||
enum:
|
||||
- video
|
||||
- audio
|
||||
- image
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- MediaAssetTypeVideo
|
||||
- MediaAssetTypeAudio
|
||||
- MediaAssetTypeImage
|
||||
consts.MediaAssetVariant:
|
||||
enum:
|
||||
- main
|
||||
- preview
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- MediaAssetVariantMain
|
||||
- MediaAssetVariantPreview
|
||||
consts.NotificationType:
|
||||
enum:
|
||||
- system
|
||||
- order
|
||||
- audit
|
||||
- interaction
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- NotificationTypeSystem
|
||||
- NotificationTypeOrder
|
||||
- NotificationTypeAudit
|
||||
- NotificationTypeInteraction
|
||||
consts.OrderStatus:
|
||||
enum:
|
||||
- created
|
||||
@@ -1013,6 +1057,99 @@ definitions:
|
||||
description: Likes 累计点赞数。
|
||||
type: integer
|
||||
type: object
|
||||
dto.SuperAssetItem:
|
||||
properties:
|
||||
bucket:
|
||||
description: Bucket 存储桶名称。
|
||||
type: string
|
||||
created_at:
|
||||
description: CreatedAt 创建时间(RFC3339)。
|
||||
type: string
|
||||
filename:
|
||||
description: Filename 原始文件名。
|
||||
type: string
|
||||
hash:
|
||||
description: Hash 文件哈希(MD5)。
|
||||
type: string
|
||||
id:
|
||||
description: ID 资产ID。
|
||||
type: integer
|
||||
object_key:
|
||||
description: ObjectKey 对象Key。
|
||||
type: string
|
||||
provider:
|
||||
description: Provider 存储提供方。
|
||||
type: string
|
||||
size:
|
||||
description: Size 文件大小(字节)。
|
||||
type: integer
|
||||
source_asset_id:
|
||||
description: SourceAssetID 源资产ID(用于变体关联)。
|
||||
type: integer
|
||||
status:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.MediaAssetStatus'
|
||||
description: Status 处理状态。
|
||||
tenant_code:
|
||||
description: TenantCode 租户编码。
|
||||
type: string
|
||||
tenant_id:
|
||||
description: TenantID 租户ID。
|
||||
type: integer
|
||||
tenant_name:
|
||||
description: TenantName 租户名称。
|
||||
type: string
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.MediaAssetType'
|
||||
description: Type 媒体类型。
|
||||
updated_at:
|
||||
description: UpdatedAt 更新时间(RFC3339)。
|
||||
type: string
|
||||
url:
|
||||
description: URL 访问URL(若可用)。
|
||||
type: string
|
||||
used_count:
|
||||
description: UsedCount 被内容引用次数。
|
||||
type: integer
|
||||
user_id:
|
||||
description: UserID 上传用户ID。
|
||||
type: integer
|
||||
username:
|
||||
description: Username 上传用户名/昵称。
|
||||
type: string
|
||||
variant:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.MediaAssetVariant'
|
||||
description: Variant 媒体变体(main/preview/cover 等)。
|
||||
type: object
|
||||
dto.SuperAssetUsageItem:
|
||||
properties:
|
||||
count:
|
||||
description: Count 该类型资产数量。
|
||||
type: integer
|
||||
total_size:
|
||||
description: TotalSize 该类型资产大小总和(字节)。
|
||||
type: integer
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.MediaAssetType'
|
||||
description: Type 媒体类型。
|
||||
type: object
|
||||
dto.SuperAssetUsageResponse:
|
||||
properties:
|
||||
by_type:
|
||||
description: ByType 按媒体类型汇总的用量统计。
|
||||
items:
|
||||
$ref: '#/definitions/dto.SuperAssetUsageItem'
|
||||
type: array
|
||||
total_count:
|
||||
description: TotalCount 资产总量。
|
||||
type: integer
|
||||
total_size:
|
||||
description: TotalSize 资产总大小(字节)。
|
||||
type: integer
|
||||
type: object
|
||||
dto.SuperContentBatchReviewForm:
|
||||
properties:
|
||||
action:
|
||||
@@ -1214,6 +1351,123 @@ definitions:
|
||||
required:
|
||||
- action
|
||||
type: object
|
||||
dto.SuperNotificationBroadcastForm:
|
||||
properties:
|
||||
content:
|
||||
description: Content 通知内容。
|
||||
type: string
|
||||
tenant_id:
|
||||
description: TenantID 租户ID(选填,用于指定租户成员)。
|
||||
type: integer
|
||||
title:
|
||||
description: Title 通知标题。
|
||||
type: string
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.NotificationType'
|
||||
description: Type 通知类型(system/order/audit/interaction)。
|
||||
user_ids:
|
||||
description: UserIDs 指定接收用户ID列表(优先级高于 TenantID)。
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
type: object
|
||||
dto.SuperNotificationItem:
|
||||
properties:
|
||||
content:
|
||||
description: Content 通知内容。
|
||||
type: string
|
||||
created_at:
|
||||
description: CreatedAt 创建时间(RFC3339)。
|
||||
type: string
|
||||
id:
|
||||
description: ID 通知ID。
|
||||
type: integer
|
||||
is_read:
|
||||
description: IsRead 是否已读。
|
||||
type: boolean
|
||||
tenant_code:
|
||||
description: TenantCode 租户编码。
|
||||
type: string
|
||||
tenant_id:
|
||||
description: TenantID 租户ID。
|
||||
type: integer
|
||||
tenant_name:
|
||||
description: TenantName 租户名称。
|
||||
type: string
|
||||
title:
|
||||
description: Title 通知标题。
|
||||
type: string
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.NotificationType'
|
||||
description: Type 通知类型。
|
||||
user_id:
|
||||
description: UserID 用户ID。
|
||||
type: integer
|
||||
username:
|
||||
description: Username 用户名/昵称。
|
||||
type: string
|
||||
type: object
|
||||
dto.SuperNotificationTemplateCreateForm:
|
||||
properties:
|
||||
content:
|
||||
description: Content 通知内容。
|
||||
type: string
|
||||
is_active:
|
||||
description: IsActive 是否启用(不传默认启用)。
|
||||
type: boolean
|
||||
name:
|
||||
description: Name 模板名称(用于识别用途)。
|
||||
type: string
|
||||
tenant_id:
|
||||
description: TenantID 租户ID(不传代表全平台模板)。
|
||||
type: integer
|
||||
title:
|
||||
description: Title 通知标题。
|
||||
type: string
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.NotificationType'
|
||||
description: Type 通知类型(system/order/audit/interaction)。
|
||||
type: object
|
||||
dto.SuperNotificationTemplateItem:
|
||||
properties:
|
||||
content:
|
||||
description: Content 模板内容。
|
||||
type: string
|
||||
created_at:
|
||||
description: CreatedAt 创建时间(RFC3339)。
|
||||
type: string
|
||||
id:
|
||||
description: ID 模板ID。
|
||||
type: integer
|
||||
is_active:
|
||||
description: IsActive 是否启用。
|
||||
type: boolean
|
||||
name:
|
||||
description: Name 模板名称。
|
||||
type: string
|
||||
tenant_code:
|
||||
description: TenantCode 租户编码。
|
||||
type: string
|
||||
tenant_id:
|
||||
description: TenantID 租户ID。
|
||||
type: integer
|
||||
tenant_name:
|
||||
description: TenantName 租户名称。
|
||||
type: string
|
||||
title:
|
||||
description: Title 模板标题。
|
||||
type: string
|
||||
type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/consts.NotificationType'
|
||||
description: Type 通知类型。
|
||||
updated_at:
|
||||
description: UpdatedAt 更新时间(RFC3339)。
|
||||
type: string
|
||||
type: object
|
||||
dto.SuperOrderDetail:
|
||||
properties:
|
||||
buyer:
|
||||
@@ -2402,6 +2656,78 @@ info:
|
||||
title: ApiDoc
|
||||
version: "1.0"
|
||||
paths:
|
||||
/super/v1/assets:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: List assets across tenants
|
||||
parameters:
|
||||
- description: Page number
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: Page size
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/requests.Pager'
|
||||
- properties:
|
||||
items:
|
||||
items:
|
||||
$ref: '#/definitions/dto.SuperAssetItem'
|
||||
type: array
|
||||
type: object
|
||||
summary: List assets
|
||||
tags:
|
||||
- Asset
|
||||
/super/v1/assets/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Delete asset
|
||||
parameters:
|
||||
- description: Asset ID
|
||||
format: int64
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: Force delete
|
||||
in: query
|
||||
name: force
|
||||
type: boolean
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Deleted
|
||||
schema:
|
||||
type: string
|
||||
summary: Delete asset
|
||||
tags:
|
||||
- Asset
|
||||
/super/v1/assets/usage:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Asset usage statistics
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SuperAssetUsageResponse'
|
||||
summary: Asset usage
|
||||
tags:
|
||||
- Asset
|
||||
/super/v1/auth/login:
|
||||
post:
|
||||
consumes:
|
||||
@@ -2715,6 +3041,102 @@ paths:
|
||||
summary: List creators
|
||||
tags:
|
||||
- Creator
|
||||
/super/v1/notifications:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: List notifications across tenants
|
||||
parameters:
|
||||
- description: Page number
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: Page size
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/requests.Pager'
|
||||
- properties:
|
||||
items:
|
||||
items:
|
||||
$ref: '#/definitions/dto.SuperNotificationItem'
|
||||
type: array
|
||||
type: object
|
||||
summary: List notifications
|
||||
tags:
|
||||
- Notification
|
||||
/super/v1/notifications/broadcast:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Broadcast notification to users or tenant members
|
||||
parameters:
|
||||
- description: Broadcast form
|
||||
in: body
|
||||
name: form
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SuperNotificationBroadcastForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Sent
|
||||
schema:
|
||||
type: string
|
||||
summary: Broadcast notification
|
||||
tags:
|
||||
- Notification
|
||||
/super/v1/notifications/templates:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: List notification templates
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/requests.Pager'
|
||||
- properties:
|
||||
items:
|
||||
items:
|
||||
$ref: '#/definitions/dto.SuperNotificationTemplateItem'
|
||||
type: array
|
||||
type: object
|
||||
summary: List notification templates
|
||||
tags:
|
||||
- Notification
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Create notification template
|
||||
parameters:
|
||||
- description: Template form
|
||||
in: body
|
||||
name: form
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SuperNotificationTemplateCreateForm'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SuperNotificationTemplateItem'
|
||||
summary: Create notification template
|
||||
tags:
|
||||
- Notification
|
||||
/super/v1/orders:
|
||||
get:
|
||||
consumes:
|
||||
|
||||
Reference in New Issue
Block a user