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.ScopeResourceShortRead) 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. 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.ScopeResourceLongRead) 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. 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"` } // PageResourceShortOfUserByAdmin 分页查询指定用户的短效套餐 func PageResourceShortOfUserByAdmin(c *fiber.Ctx) error { _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceShortReadOfUser) if err != nil { return err } var req PageResourceShortOfUserByAdminReq if err = g.Validator.ParseBody(c, &req); err != nil { return err } do := q.Resource.Where(q.Resource.UserID.Eq(req.UserID)) 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 { t := u.DateHead(*req.CreatedAtStart) do = do.Where(q.Resource.CreatedAt.Gte(t)) } if req.CreatedAtEnd != nil { t := u.DateTail(*req.CreatedAtEnd) do = do.Where(q.Resource.CreatedAt.Lte(t)) } list, total, err := q.Resource. 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 PageResourceShortOfUserByAdminReq struct { core.PageReq UserID int32 `json:"user_id" validate:"required"` ResourceNo *string `json:"resource_no"` Active *bool `json:"active"` Mode *int `json:"mode"` CreatedAtStart *time.Time `json:"created_at_start"` CreatedAtEnd *time.Time `json:"created_at_end"` } // PageResourceLongOfUserByAdmin 分页查询指定用户的长效套餐 func PageResourceLongOfUserByAdmin(c *fiber.Ctx) error { _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeResourceLongReadOfUser) if err != nil { return err } var req PageResourceLongOfUserByAdminReq if err = g.Validator.ParseBody(c, &req); err != nil { return err } do := q.Resource.Where(q.Resource.UserID.Eq(req.UserID)) 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 { t := u.DateHead(*req.CreatedAtStart) do = do.Where(q.Resource.CreatedAt.Gte(t)) } if req.CreatedAtEnd != nil { t := u.DateTail(*req.CreatedAtEnd) do = do.Where(q.Resource.CreatedAt.Lte(t)) } list, total, err := q.Resource. 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 PageResourceLongOfUserByAdminReq struct { core.PageReq UserID int32 `json:"user_id" validate:"required"` ResourceNo *string `json:"resource_no"` Active *bool `json:"active"` Mode *int `json:"mode"` CreatedAtStart *time.Time `json:"created_at_start"` CreatedAtEnd *time.Time `json:"created_at_end"` } // 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) } 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) } // 获取套餐价格 detail, err := req.TradeDetail(nil) if err != nil { return err } // 计算折扣 return c.JSON(ResourcePriceResp{ Price: detail.Amount.StringFixed(2), Discounted: detail.Discounted.StringFixed(2), Actual: detail.Actual.StringFixed(2), }) } type ResourcePriceResp struct { Price string `json:"price"` Discounted string `json:"discounted"` Actual string `json:"actual"` }