Files
platform/web/handlers/resource.go

698 lines
19 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handlers
import (
"platform/pkg/u"
"platform/web/auth"
"platform/web/core"
g "platform/web/globals"
m "platform/web/models"
q "platform/web/queries"
s "platform/web/services"
"time"
"gorm.io/gen/field"
"github.com/gofiber/fiber/v2"
)
// PageResourceShort 分页查询当前用户短效套餐
func PageResourceShort(c *fiber.Ctx) error {
// 检查权限
authCtx, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
// 解析请求参数
req := new(PageResourceShortReq)
if err := c.BodyParser(req); err != nil {
return err
}
// 查询套餐列表
do := q.Resource.Where(
q.Resource.UserID.Eq(authCtx.User.ID),
q.Resource.Type.Eq(int(m.ResourceTypeShort)),
)
if req.ResourceNo != nil && *req.ResourceNo != "" {
do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
}
if req.Active != nil {
do.Where(q.Resource.Active.Is(*req.Active))
}
if req.Type != nil {
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).Type.Eq(*req.Type))
}
if req.CreateAfter != nil {
do.Where(q.Resource.CreatedAt.Gte(*req.CreateAfter))
}
if req.CreateBefore != nil {
do.Where(q.Resource.CreatedAt.Lte(*req.CreateBefore))
}
if req.ExpireAfter != nil {
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).ExpireAt.Gte(*req.ExpireAfter))
}
if req.ExpireBefore != nil {
do.Where(q.ResourceShort.As(q.Resource.Short.Name()).ExpireAt.Lte(*req.ExpireBefore))
}
if req.Status != nil {
var short = q.ResourceShort.As(q.Resource.Short.Name())
switch *req.Status {
case 1:
var timeCond = q.Resource.Where(short.Type.Eq(int(m.ResourceModeTime)), short.ExpireAt.Gte(time.Now()))
var quotaCond = q.Resource.Where(short.Type.Eq(int(m.ResourceModeQuota)), short.Quota.GtCol(short.Used))
do.Where(q.Resource.Where(timeCond).Or(quotaCond))
case 2:
var timeCond = q.Resource.Where(short.Type.Eq(int(m.ResourceModeTime)), short.ExpireAt.Lte(time.Now()))
var quotaCond = q.Resource.Where(short.Type.Eq(int(m.ResourceModeQuota)), short.Quota.LteCol(short.Used))
do.Where(q.Resource.Where(timeCond).Or(quotaCond))
}
}
resource, err := q.Resource.Where(do).
Joins(q.Resource.Short).
Order(q.Resource.CreatedAt.Desc()).
Offset(req.GetOffset()).
Limit(req.GetLimit()).
Find()
if err != nil {
return err
}
var total int64
if len(resource) < req.GetLimit() {
total = int64(len(resource) + req.GetOffset())
} else {
total, err = q.Resource.
Where(do).
Count()
if err != nil {
return err
}
}
return c.JSON(core.PageResp{
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
List: resource,
})
}
type PageResourceShortReq struct {
core.PageReq
ResourceNo *string `json:"resource_no"`
Active *bool `json:"active"`
Type *int `json:"type"`
CreateAfter *time.Time `json:"create_after"`
CreateBefore *time.Time `json:"create_before"`
ExpireAfter *time.Time `json:"expire_after"`
ExpireBefore *time.Time `json:"expire_before"`
Status *int `json:"status"` // 0 - 全部1 - 有效2 - 过期
}
// PageResourceLong 分页查询当前用户长效套餐
func PageResourceLong(c *fiber.Ctx) error {
// 检查权限
authCtx, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
// 解析请求参数
req := new(PageResourceLongReq)
if err := c.BodyParser(req); err != nil {
return err
}
// 查询套餐列表
do := q.Resource.Where(
q.Resource.UserID.Eq(authCtx.User.ID),
q.Resource.Type.Eq(int(m.ResourceTypeLong)),
)
if req.ResourceNo != nil && *req.ResourceNo != "" {
do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
}
if req.Active != nil {
do.Where(q.Resource.Active.Is(*req.Active))
}
if req.Type != nil {
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).Type.Eq(int(*req.Type)))
}
if req.CreateAfter != nil {
do.Where(q.Resource.CreatedAt.Gte(*req.CreateAfter))
}
if req.CreateBefore != nil {
do.Where(q.Resource.CreatedAt.Lte(*req.CreateBefore))
}
if req.ExpireAfter != nil {
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).ExpireAt.Gte(*req.ExpireAfter))
}
if req.ExpireBefore != nil {
do.Where(q.ResourceLong.As(q.Resource.Long.Name()).ExpireAt.Lte(*req.ExpireBefore))
}
if req.Status != nil {
var long = q.ResourceLong.As(q.Resource.Long.Name())
switch *req.Status {
case 1:
var timeCond = q.Resource.Where(long.Type.Eq(int(m.ResourceModeTime)), long.ExpireAt.Gte(time.Now()))
var quotaCond = q.Resource.Where(long.Type.Eq(int(m.ResourceModeQuota)), long.Quota.GtCol(long.Used))
do.Where(q.Resource.Where(timeCond).Or(quotaCond))
case 2:
var timeCond = q.Resource.Where(long.Type.Eq(int(m.ResourceModeTime)), long.ExpireAt.Lte(time.Now()))
var quotaCond = q.Resource.Where(long.Type.Eq(int(m.ResourceModeQuota)), long.Quota.LteCol(long.Used))
do.Where(q.Resource.Where(timeCond).Or(quotaCond))
}
}
resource, err := q.Resource.Where(do).
Joins(q.Resource.Long).
Order(q.Resource.CreatedAt.Desc()).
Offset(req.GetOffset()).
Limit(req.GetLimit()).
Find()
if err != nil {
return err
}
var total int64
if len(resource) < req.GetLimit() {
total = int64(len(resource) + req.GetOffset())
} else {
total, err = q.Resource.
Where(do).
Count()
if err != nil {
return err
}
}
return c.JSON(core.PageResp{
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
List: resource,
})
}
type PageResourceLongReq struct {
core.PageReq
ResourceNo *string `json:"resource_no"`
Active *bool `json:"active"`
Type *int `json:"type"`
CreateAfter *time.Time `json:"create_after"`
CreateBefore *time.Time `json:"create_before"`
ExpireAfter *time.Time `json:"expire_after"`
ExpireBefore *time.Time `json:"expire_before"`
Status *int `json:"status"` // 0 - 全部1 - 有效2 - 过期
}
// PageResourceShortByAdmin 分页查询全部短效套餐
func PageResourceShortByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceRead)
if err != nil {
return err
}
var req PageResourceShortByAdminReq
if err = g.Validator.ParseBody(c, &req); err != nil {
return err
}
do := q.Resource.Where()
if req.UserPhone != nil {
do = do.Where(q.User.As("User").Phone.Eq(*req.UserPhone))
}
if req.ResourceNo != nil {
do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
}
if req.Active != nil {
do = do.Where(q.Resource.Active.Is(*req.Active))
}
if req.Mode != nil {
do = do.Where(q.ResourceShort.As("Short").Type.Eq(int(*req.Mode)))
}
if req.CreatedAtStart != nil {
time := u.DateHead(*req.CreatedAtStart)
do = do.Where(q.Resource.CreatedAt.Gte(time))
}
if req.CreatedAtEnd != nil {
time := u.DateTail(*req.CreatedAtEnd)
do = do.Where(q.Resource.CreatedAt.Lte(time))
}
if req.Expired != nil {
if *req.Expired {
do = do.Where(q.Resource.Where(
q.ResourceShort.As("Short").Type.Eq(int(m.ResourceModeTime)),
q.ResourceShort.As("Short").ExpireAt.Lte(time.Now()),
).Or(
q.ResourceShort.As("Short").Type.Eq(int(m.ResourceModeQuota)),
q.ResourceShort.As("Short").Quota.LteCol(q.ResourceShort.As("Short").Used),
))
} else {
do = do.Where(q.Resource.Where(
q.ResourceShort.As("Short").Type.Eq(int(m.ResourceModeTime)),
q.ResourceShort.As("Short").ExpireAt.Gt(time.Now()),
).Or(
q.ResourceShort.As("Short").Type.Eq(int(m.ResourceModeQuota)),
q.ResourceShort.As("Short").Quota.GtCol(q.ResourceShort.As("Short").Used),
))
}
}
list, total, err := q.Resource.Debug().
Joins(q.Resource.User, q.Resource.Short, q.Resource.Short.Sku).
Select(
q.Resource.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
q.ResourceShort.As("Short").Type.As("Short__type"),
q.ResourceShort.As("Short").Live.As("Short__live"),
q.ResourceShort.As("Short").Quota.As("Short__quota"),
q.ResourceShort.As("Short").Used.As("Short__used"),
q.ResourceShort.As("Short").Daily.As("Short__daily"),
q.ResourceShort.As("Short").LastAt.As("Short__last_at"),
q.ResourceShort.As("Short").ExpireAt.As("Short__expire_at"),
q.ProductSku.As("Short__Sku").Name.As("Short__Sku__name"),
).
Where(q.Resource.Type.Eq(int(m.ResourceTypeShort)), do).
Order(q.Resource.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageResourceShortByAdminReq struct {
core.PageReq
UserPhone *string `json:"user_phone" form:"user_phone"`
ResourceNo *string `json:"resource_no" form:"resource_no"`
Active *bool `json:"active" form:"active"`
Mode *int `json:"mode" form:"mode"`
CreatedAtStart *time.Time `json:"created_at_start" form:"created_at_start"`
CreatedAtEnd *time.Time `json:"created_at_end" form:"created_at_end"`
Expired *bool `json:"expired" form:"expired"`
}
// PageResourceLongByAdmin 分页查询全部长效套餐
func PageResourceLongByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceRead)
if err != nil {
return err
}
var req PageResourceLongByAdminReq
if err = g.Validator.ParseBody(c, &req); err != nil {
return err
}
do := q.Resource.Where()
if req.UserPhone != nil {
do = do.Where(q.User.As("User").Phone.Eq(*req.UserPhone))
}
if req.ResourceNo != nil {
do = do.Where(q.Resource.ResourceNo.Eq(*req.ResourceNo))
}
if req.Active != nil {
do = do.Where(q.Resource.Active.Is(*req.Active))
}
if req.Mode != nil {
do = do.Where(q.ResourceLong.As("Long").Type.Eq(*req.Mode))
}
if req.CreatedAtStart != nil {
do = do.Where(q.Resource.CreatedAt.Gte(*req.CreatedAtStart))
}
if req.CreatedAtEnd != nil {
do = do.Where(q.Resource.CreatedAt.Lte(*req.CreatedAtEnd))
}
if req.Expired != nil {
if *req.Expired {
do = do.Where(q.Resource.Where(
q.ResourceLong.As("Long").Type.Eq(int(m.ResourceModeTime)),
q.ResourceLong.As("Long").ExpireAt.Lte(time.Now()),
).Or(
q.ResourceLong.As("Long").Type.Eq(int(m.ResourceModeQuota)),
q.ResourceLong.As("Long").Quota.LteCol(q.ResourceLong.As("Long").Used),
))
} else {
do = do.Where(q.Resource.Where(
q.ResourceLong.As("Long").Type.Eq(int(m.ResourceModeTime)),
q.ResourceLong.As("Long").ExpireAt.Gt(time.Now()),
).Or(
q.ResourceLong.As("Long").Type.Eq(int(m.ResourceModeQuota)),
q.ResourceLong.As("Long").Quota.GtCol(q.ResourceLong.As("Long").Used),
))
}
}
list, total, err := q.Resource.Debug().
Joins(q.Resource.User, q.Resource.Long, q.Resource.Long.Sku).
Select(
q.Resource.ALL,
q.User.As("User").Phone.As("User__phone"),
q.User.As("User").Name.As("User__name"),
q.ResourceLong.As("Long").Type.As("Long__type"),
q.ResourceLong.As("Long").Live.As("Long__live"),
q.ResourceLong.As("Long").Quota.As("Long__quota"),
q.ResourceLong.As("Long").Used.As("Long__used"),
q.ResourceLong.As("Long").Daily.As("Long__daily"),
q.ResourceLong.As("Long").LastAt.As("Long__last_at"),
q.ResourceLong.As("Long").ExpireAt.As("Long__expire_at"),
q.ProductSku.As("Long__Sku").Name.As("Long__Sku__name"),
).
Where(q.Resource.Type.Eq(int(m.ResourceTypeLong)), do).
Order(q.Resource.CreatedAt.Desc()).
FindByPage(req.GetOffset(), req.GetLimit())
if err != nil {
return err
}
return c.JSON(core.PageResp{
List: list,
Total: int(total),
Page: req.GetPage(),
Size: req.GetSize(),
})
}
type PageResourceLongByAdminReq struct {
core.PageReq
UserPhone *string `json:"user_phone" form:"user_phone"`
ResourceNo *string `json:"resource_no" form:"resource_no"`
Active *bool `json:"active" form:"active"`
Mode *int `json:"mode" form:"mode"`
CreatedAtStart *time.Time `json:"created_at_start" form:"created_at_start"`
CreatedAtEnd *time.Time `json:"created_at_end" form:"created_at_end"`
Expired *bool `json:"expired" form:"expired"`
}
// AllActiveResource 所有可用套餐
func AllActiveResource(c *fiber.Ctx) error {
// 检查权限
authCtx, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
// 查询套餐列表
var now = time.Now()
var short = q.ResourceShort.As(q.Resource.Short.Name())
var long = q.ResourceLong.As(q.Resource.Long.Name())
resources, err := q.Resource.
Joins(
q.Resource.Short,
q.Resource.Long,
).
Where(
q.Resource.UserID.Eq(authCtx.User.ID),
q.Resource.Active.Is(true),
q.Resource.Where(
q.Resource.Type.Eq(int(m.ResourceTypeShort)),
q.ResourceShort.As(q.Resource.Short.Name()).Where(
short.Type.Eq(int(m.ResourceModeTime)),
short.ExpireAt.Gte(now),
q.ResourceShort.As(q.Resource.Short.Name()).
Where(short.LastAt.Lt(u.Today())).
Or(short.Quota.GtCol(short.Daily)),
).Or(
short.Type.Eq(int(m.ResourceModeQuota)),
short.Quota.GtCol(short.Used),
),
).Or(
q.Resource.Type.Eq(int(m.ResourceTypeLong)),
q.ResourceLong.As(q.Resource.Long.Name()).Where(
long.Type.Eq(int(m.ResourceModeTime)),
long.ExpireAt.Gte(now),
q.ResourceLong.As(q.Resource.Long.Name()).
Where(long.LastAt.Lt(u.Today())).
Or(long.Quota.GtCol(long.Daily)),
).Or(
long.Type.Eq(int(m.ResourceModeQuota)),
long.Quota.GtCol(long.Used),
),
),
).
Order(q.Resource.CreatedAt.Desc()).
Find()
if err != nil {
return err
}
return c.JSON(resources)
}
type AllResourceReq struct {
}
func UpdateResourceByAdmin(c *fiber.Ctx) error {
_, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceWrite)
if err != nil {
return err
}
var req s.UpdateResourceData
if err := c.BodyParser(&req); err != nil {
return err
}
if err := s.Resource.Update(&req); err != nil {
return err
}
return c.JSON(nil)
}
// StatisticResourceFree 统计每日可用
func StatisticResourceFree(c *fiber.Ctx) error {
// 检查权限
authCtx, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
// 统计套餐剩余数量
resources, err := q.Resource.
Preload(
q.Resource.Short,
q.Resource.Long,
).
Where(
q.Resource.UserID.Eq(authCtx.User.ID),
q.Resource.Active.Is(true),
).
Select(q.Resource.ID, q.Resource.Type).
Find()
if err != nil {
return err
}
var shortCount, shortQuotaSum, shortDailyFreeSum int
var longCount, longQuotaSum, longDailyFreeSum int
for _, resource := range resources {
switch {
// 短效包量
case resource.Type == m.ResourceTypeShort && resource.Short.Type == m.ResourceModeQuota:
if resource.Short.Quota > resource.Short.Used {
shortCount++
shortQuotaSum += int(resource.Short.Quota - resource.Short.Used)
}
// 长效包量
case resource.Type == m.ResourceTypeLong && resource.Long.Type == m.ResourceModeQuota:
if resource.Long.Quota > resource.Long.Used {
longCount++
longQuotaSum += int(resource.Long.Quota - resource.Long.Used)
}
// 短效包时
case resource.Type == m.ResourceTypeShort && resource.Short.Type == m.ResourceModeTime:
if time.Time(*resource.Short.ExpireAt).After(time.Now()) {
if resource.Short.LastAt == nil || u.IsToday(time.Time(*resource.Short.LastAt)) == false {
shortCount++
shortDailyFreeSum += int(resource.Short.Quota)
} else if resource.Short.Quota > resource.Short.Daily {
shortCount++
shortDailyFreeSum += int(resource.Short.Quota - resource.Short.Daily)
}
}
// 长效包时
case resource.Type == m.ResourceTypeLong && resource.Long.Type == m.ResourceModeTime:
if time.Time(*resource.Long.ExpireAt).After(time.Now()) {
if resource.Long.LastAt == nil || u.IsToday(time.Time(*resource.Long.LastAt)) == false {
longCount++
longDailyFreeSum += int(resource.Long.Quota)
} else if resource.Long.Quota > resource.Long.Daily {
longCount++
longDailyFreeSum += int(resource.Long.Quota - resource.Long.Daily)
}
}
}
}
return c.JSON(StatisticPersonalResp{
Short: StatisticShort{
ResourceCount: shortCount,
ResourceQuotaSum: shortQuotaSum,
ResourceDailyFreeSum: shortDailyFreeSum,
},
Long: StatisticLong{
ResourceCount: longCount,
ResourceQuotaSum: longQuotaSum,
ResourceDailyFreeSum: longDailyFreeSum,
},
})
}
type StatisticPersonalResp struct {
Short StatisticShort `json:"short"`
Long StatisticLong `json:"long"`
}
type StatisticShort struct {
ResourceCount int `json:"resource_count"`
ResourceQuotaSum int `json:"resource_quota_sum"`
ResourceDailyFreeSum int `json:"resource_daily_free_sum"`
}
type StatisticLong struct {
ResourceCount int `json:"resource_count"`
ResourceQuotaSum int `json:"resource_quota_sum"`
ResourceDailyFreeSum int `json:"resource_daily_free_sum"`
}
// StatisticResourceUsage 统计每日用量
func StatisticResourceUsage(c *fiber.Ctx) error {
// 检查权限
authCtx, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
// 解析请求参数
var req = new(StatisticResourceUsageReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 统计套餐提取数量
do := q.LogsUserUsage.Where(
q.LogsUserUsage.UserID.Eq(authCtx.User.ID),
)
if req.TimeAfter != nil {
do.Where(q.LogsUserUsage.Time.Gte(*req.TimeAfter))
}
if req.TimeBefore != nil {
do.Where(q.LogsUserUsage.Time.Lte(*req.TimeBefore))
}
var data = new(StatisticResourceUsageResp)
err = q.LogsUserUsage.
Select(
q.LogsUserUsage.Count_.Sum().As("count"),
field.NewUnsafeFieldRaw("date_trunc('day', time)").As("date"),
).
Where(do).
Group(
field.NewField("", "date"),
).
Order(
field.NewField("", "date").Desc(),
).
Scan(&data)
if err != nil {
return err
}
return c.JSON(data)
}
type StatisticResourceUsageReq struct {
TimeAfter *time.Time `json:"time_start"`
TimeBefore *time.Time `json:"time_end"`
}
type StatisticResourceUsageResp []struct {
Date time.Time `json:"date"`
Count int `json:"count"`
}
// CreateResource 创建套餐
func CreateResource(c *fiber.Ctx) error {
// 检查权限
authCtx, err := auth.GetAuthCtx(c).PermitUser()
if err != nil {
return err
}
// 解析请求参数
var req = new(CreateResourceReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return err
}
// 创建套餐
err = s.Resource.CreateResourceByBalance(authCtx.User, req.CreateResourceData)
if err != nil {
return err
}
return nil
}
type CreateResourceReq struct {
*s.CreateResourceData
}
// ResourcePrice 套餐价格
func ResourcePrice(c *fiber.Ctx) error {
// 检查权限
_, err := auth.GetAuthCtx(c).PermitSecretClient()
if err != nil {
return err
}
// 解析请求参数
var req = new(CreateResourceReq)
if err := g.Validator.ParseBody(c, req); err != nil {
return core.NewBizErr("接口参数解析异常", err)
}
// 获取套餐价格
// sku, err := s.Resource.GetSku(req.CreateResourceData.Code())
// if err != nil {
// return err
// }
// _, amount, discounted, couponApplied, err := s.Resource.GetPrice(sku, req.Count(), nil, nil)
// if err != nil {
// return err
// }
detail, err := req.TradeDetail(nil)
if err != nil {
return err
}
// 计算折扣
return c.JSON(ResourcePriceResp{
Price: detail.Amount.StringFixed(2),
Discounted: detail.Actual.StringFixed(2),
})
}
type ResourcePriceResp struct {
Price string `json:"price"`
Discounted string `json:"discounted_price"`
}