1.4.5.2
This commit is contained in:
114
EdgeUser/internal/web/actions/default/servers/packages/buy.go
Normal file
114
EdgeUser/internal/web/actions/default/servers/packages/buy.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type BuyAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *BuyAction) Init() {
|
||||
this.Nav("", "", "buy")
|
||||
}
|
||||
|
||||
func (this *BuyAction) RunGet(params struct{}) {
|
||||
// 检查权限
|
||||
config, err := configloaders.LoadCacheableUserPriceConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if config == nil || !config.IsOn || config.EnablePlans || !config.EnableTrafficPackages {
|
||||
this.WriteString("管理员未开启相关配置")
|
||||
return
|
||||
}
|
||||
|
||||
// 价格
|
||||
pricesResp, err := this.RPC().TrafficPackagePriceRPC().FindAllTrafficPackagePrices(this.UserContext(), &pb.FindAllTrafficPackagePricesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var priceMap = map[string]float64{} // packageId@regionId@periodId => price
|
||||
var allPackageIdMap = map[int64]bool{}
|
||||
var allRegionIdMap = map[int64]bool{}
|
||||
var allPeriodIdMap = map[int64]bool{}
|
||||
for _, price := range pricesResp.TrafficPackagePrices {
|
||||
if price.Price > 0 {
|
||||
allPackageIdMap[price.TrafficPackageId] = true
|
||||
allRegionIdMap[price.NodeRegionId] = true
|
||||
allPeriodIdMap[price.TrafficPackagePeriodId] = true
|
||||
|
||||
var key = types.String(price.TrafficPackageId) + "@" + types.String(price.NodeRegionId) + "@" + types.String(price.TrafficPackagePeriodId)
|
||||
priceMap[key] = price.Price
|
||||
}
|
||||
}
|
||||
this.Data["prices"] = priceMap
|
||||
|
||||
// 流量包
|
||||
var packageMaps = []maps.Map{}
|
||||
packagesResp, err := this.RPC().TrafficPackageRPC().FindAllAvailableTrafficPackages(this.UserContext(), &pb.FindAllAvailableTrafficPackagesRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, p := range packagesResp.TrafficPackages {
|
||||
_, hasPrice := allPackageIdMap[p.Id]
|
||||
if hasPrice {
|
||||
packageMaps = append(packageMaps, maps.Map{
|
||||
"id": p.Id,
|
||||
"size": p.Size,
|
||||
"unit": p.Unit,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["packages"] = packageMaps
|
||||
|
||||
// 区域
|
||||
var regionMaps = []maps.Map{}
|
||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.UserContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, region := range regionsResp.NodeRegions {
|
||||
_, hasPrice := allRegionIdMap[region.Id]
|
||||
if hasPrice {
|
||||
regionMaps = append(regionMaps, maps.Map{
|
||||
"id": region.Id,
|
||||
"name": region.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["regions"] = regionMaps
|
||||
|
||||
// 周期
|
||||
var periodMaps = []maps.Map{}
|
||||
periodResp, err := this.RPC().TrafficPackagePeriodRPC().FindAllAvailableTrafficPackagePeriods(this.UserContext(), &pb.FindAllAvailableTrafficPackagePeriodsRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, period := range periodResp.TrafficPackagePeriods {
|
||||
_, hasPrice := allPeriodIdMap[period.Id]
|
||||
if hasPrice {
|
||||
periodMaps = append(periodMaps, maps.Map{
|
||||
"id": period.Id,
|
||||
"count": period.Count,
|
||||
"unit": period.Unit,
|
||||
"unitName": userconfigs.TrafficPackagePeriodUnitName(period.Unit),
|
||||
})
|
||||
}
|
||||
}
|
||||
this.Data["periods"] = periodMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/default/finance/financeutils"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ConfirmAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *ConfirmAction) Init() {
|
||||
this.Nav("", "", "buy")
|
||||
}
|
||||
|
||||
func (this *ConfirmAction) RunGet(params struct {
|
||||
PackageId int64
|
||||
RegionId int64
|
||||
PeriodId int64
|
||||
Count int32
|
||||
}) {
|
||||
// parameters
|
||||
this.Data["packageId"] = params.PackageId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
this.Data["periodId"] = params.PeriodId
|
||||
|
||||
// 检查权限
|
||||
config, err := configloaders.LoadCacheableUserPriceConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if config == nil || !config.IsOn || config.EnablePlans || !config.EnableTrafficPackages {
|
||||
this.WriteString("管理员未开启相关配置")
|
||||
return
|
||||
}
|
||||
|
||||
// package
|
||||
packageResp, err := this.RPC().TrafficPackageRPC().FindTrafficPackage(this.UserContext(), &pb.FindTrafficPackageRequest{TrafficPackageId: params.PackageId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var p = packageResp.TrafficPackage
|
||||
if p == nil || !p.IsOn {
|
||||
this.NotFound("TrafficPackage", params.PackageId)
|
||||
return
|
||||
}
|
||||
this.Data["packageName"] = types.String(p.Size) + strings.ToUpper(p.Unit)
|
||||
|
||||
// region
|
||||
regionResp, err := this.RPC().NodeRegionRPC().FindEnabledNodeRegion(this.UserContext(), &pb.FindEnabledNodeRegionRequest{NodeRegionId: params.RegionId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var region = regionResp.NodeRegion
|
||||
if region == nil || !region.IsOn {
|
||||
this.NotFound("NodeRegion", params.RegionId)
|
||||
return
|
||||
}
|
||||
this.Data["regionName"] = region.Name
|
||||
|
||||
// period
|
||||
periodResp, err := this.RPC().TrafficPackagePeriodRPC().FindTrafficPackagePeriod(this.UserContext(), &pb.FindTrafficPackagePeriodRequest{TrafficPackagePeriodId: params.PeriodId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var period = periodResp.TrafficPackagePeriod
|
||||
if period == nil || !period.IsOn {
|
||||
this.NotFound("TrafficPackagePeriod", params.PeriodId)
|
||||
return
|
||||
}
|
||||
this.Data["periodName"] = types.String(period.Count) + userconfigs.TrafficPackagePeriodUnitName(period.Unit)
|
||||
|
||||
// count
|
||||
if params.Count <= 0 {
|
||||
this.ErrorPage(errors.New("invalid 'count' parameter"))
|
||||
return
|
||||
}
|
||||
this.Data["count"] = params.Count
|
||||
|
||||
// price
|
||||
priceResp, err := this.RPC().TrafficPackagePriceRPC().FindTrafficPackagePrice(this.UserContext(), &pb.FindTrafficPackagePriceRequest{
|
||||
TrafficPackageId: params.PackageId,
|
||||
NodeRegionId: params.RegionId,
|
||||
TrafficPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if priceResp.Price == 0 {
|
||||
this.ErrorPage(errors.New("invalid parameters: could not retrieve price"))
|
||||
return
|
||||
}
|
||||
this.Data["amount"] = priceResp.Amount
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *ConfirmAction) RunPost(params struct {
|
||||
PackageId int64
|
||||
RegionId int64
|
||||
PeriodId int64
|
||||
Count int32
|
||||
|
||||
MethodCode string
|
||||
}) {
|
||||
// 检查权限
|
||||
config, err := configloaders.LoadCacheableUserPriceConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if config == nil || !config.IsOn || config.EnablePlans || !config.EnableTrafficPackages {
|
||||
this.Fail("管理员未开启相关配置")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查参数
|
||||
if params.PackageId <= 0 {
|
||||
this.Fail("请选择流量包规格")
|
||||
return
|
||||
}
|
||||
if params.RegionId <= 0 {
|
||||
this.Fail("请选择区域")
|
||||
return
|
||||
}
|
||||
if params.PeriodId <= 0 {
|
||||
this.Fail("请选择有效期")
|
||||
return
|
||||
}
|
||||
if params.Count <= 0 {
|
||||
this.Fail("请选择数量")
|
||||
return
|
||||
}
|
||||
if params.Count > 20 {
|
||||
this.Fail("一次性最多只能购买20个")
|
||||
return
|
||||
}
|
||||
|
||||
// period
|
||||
periodResp, err := this.RPC().TrafficPackagePeriodRPC().FindTrafficPackagePeriod(this.UserContext(), &pb.FindTrafficPackagePeriodRequest{TrafficPackagePeriodId: params.PeriodId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var period = periodResp.TrafficPackagePeriod
|
||||
if period == nil || !period.IsOn {
|
||||
this.NotFound("TrafficPackagePeriod", params.PeriodId)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查价格
|
||||
priceResp, err := this.RPC().TrafficPackagePriceRPC().FindTrafficPackagePrice(this.UserContext(), &pb.FindTrafficPackagePriceRequest{
|
||||
TrafficPackageId: params.PackageId,
|
||||
NodeRegionId: params.RegionId,
|
||||
TrafficPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
if priceResp.Amount <= 0 {
|
||||
this.Fail("当前流量包没有设定价格,无法购买")
|
||||
return
|
||||
}
|
||||
var amount = priceResp.Amount
|
||||
|
||||
this.Data["packageId"] = params.PackageId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
this.Data["periodId"] = params.PeriodId
|
||||
this.Data["count"] = params.Count
|
||||
|
||||
// 使用余额购买
|
||||
this.Data["success"] = false
|
||||
this.Data["orderCode"] = ""
|
||||
if params.MethodCode == "@balance" {
|
||||
balance, err := financeutils.FindUserBalance(this.UserContext())
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if amount > balance {
|
||||
this.Fail("当前余额不足,需要:" + fmt.Sprintf("%.2f元", amount) + ",现有:" + fmt.Sprintf("%.2f元", balance) + " ,请充值后再试")
|
||||
return
|
||||
}
|
||||
|
||||
// 直接购买
|
||||
_, err = this.RPC().UserTrafficPackageRPC().BuyUserTrafficPackage(this.UserContext(), &pb.BuyUserTrafficPackageRequest{
|
||||
UserId: this.UserId(),
|
||||
TrafficPackageId: params.PackageId,
|
||||
NodeRegionId: params.RegionId,
|
||||
TrafficPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["success"] = true
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
// 生成订单
|
||||
var orderParams = &userconfigs.OrderTypeBuyTrafficPackageParams{
|
||||
PackageId: params.PackageId,
|
||||
RegionId: params.RegionId,
|
||||
PeriodId: params.PeriodId,
|
||||
PeriodCount: period.Count,
|
||||
PeriodUnit: period.Unit,
|
||||
Count: params.Count,
|
||||
}
|
||||
orderParamsJSON, err := json.Marshal(orderParams)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().UserOrderRPC().CreateUserOrder(this.UserContext(), &pb.CreateUserOrderRequest{
|
||||
Type: userconfigs.OrderTypeBuyTrafficPackage,
|
||||
OrderMethodCode: params.MethodCode,
|
||||
Amount: amount,
|
||||
ParamsJSON: orderParamsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["orderCode"] = resp.Code
|
||||
|
||||
this.Success()
|
||||
}
|
||||
104
EdgeUser/internal/web/actions/default/servers/packages/index.go
Normal file
104
EdgeUser/internal/web/actions/default/servers/packages/index.go
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/dateutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "index")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
Type string
|
||||
}) {
|
||||
this.Data["type"] = params.Type
|
||||
|
||||
// 检查权限
|
||||
config, err := configloaders.LoadCacheableUserPriceConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if config == nil || !config.IsOn || config.EnablePlans || !config.EnableTrafficPackages {
|
||||
this.WriteString("管理员未开启相关配置")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查有效的流量包数量
|
||||
countResp, err := this.RPC().UserTrafficPackageRPC().CountUserTrafficPackages(this.UserContext(), &pb.CountUserTrafficPackagesRequest{
|
||||
UserId: this.UserId(),
|
||||
AvailableOnly: params.Type == "",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
// 列表
|
||||
userPackagesResp, err := this.RPC().UserTrafficPackageRPC().ListUserTrafficPackages(this.UserContext(), &pb.ListUserTrafficPackagesRequest{
|
||||
UserId: this.UserId(),
|
||||
AvailableOnly: params.Type == "",
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var userPackageMaps = []maps.Map{}
|
||||
for _, userPackage := range userPackagesResp.UserTrafficPackages {
|
||||
// package
|
||||
var packageMap maps.Map
|
||||
if userPackage.TrafficPackage != nil {
|
||||
packageMap = maps.Map{
|
||||
"id": userPackage.TrafficPackage.Id,
|
||||
"size": userPackage.TrafficPackage.Size,
|
||||
"unit": userPackage.TrafficPackage.Unit,
|
||||
}
|
||||
}
|
||||
|
||||
// region
|
||||
var regionMap maps.Map
|
||||
if userPackage.NodeRegion != nil {
|
||||
regionMap = maps.Map{
|
||||
"id": userPackage.NodeRegion.Id,
|
||||
"name": userPackage.NodeRegion.Name,
|
||||
}
|
||||
}
|
||||
|
||||
userPackageMaps = append(userPackageMaps, maps.Map{
|
||||
"id": userPackage.Id,
|
||||
"dayFrom": dateutils.SplitYmd(userPackage.DayFrom),
|
||||
"dayTo": dateutils.SplitYmd(userPackage.DayTo),
|
||||
"package": packageMap,
|
||||
"region": regionMap,
|
||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", userPackage.CreatedAt),
|
||||
"periodCount": userPackage.TrafficPackagePeriodCount,
|
||||
"periodUnitName": userconfigs.TrafficPackagePeriodUnitName(userPackage.TrafficPackagePeriodUnit),
|
||||
"usedSize": numberutils.FormatBytes(userPackage.UsedBytes),
|
||||
"availableSize": numberutils.FormatBytes(userPackage.TotalBytes - userPackage.UsedBytes),
|
||||
"createTime": timeutil.FormatTime("Y-m-d H:i:s", userPackage.CreatedAt),
|
||||
"isExpired": userPackage.DayTo < timeutil.Format("Ymd"),
|
||||
"isUsedAll": userPackage.UsedBytes >= userPackage.TotalBytes,
|
||||
})
|
||||
}
|
||||
this.Data["userPackages"] = userPackageMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth("")).
|
||||
Data("teaMenu", "servers").
|
||||
Data("teaSubMenu", "trafficPackage").
|
||||
Prefix("/servers/packages").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/buy", new(BuyAction)).
|
||||
GetPost("/confirm", new(ConfirmAction)).
|
||||
Post("/price", new(PriceAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
|
||||
type PriceAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *PriceAction) RunPost(params struct {
|
||||
PackageId int64
|
||||
RegionId int64
|
||||
PeriodId int64
|
||||
Count int32
|
||||
}) {
|
||||
if params.PackageId <= 0 || params.RegionId <= 0 || params.PeriodId <= 0 || params.Count <= 0 {
|
||||
this.Data["price"] = 0
|
||||
this.Data["amount"] = 0
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := this.RPC().TrafficPackagePriceRPC().FindTrafficPackagePrice(this.UserContext(), &pb.FindTrafficPackagePriceRequest{
|
||||
TrafficPackageId: params.PackageId,
|
||||
NodeRegionId: params.RegionId,
|
||||
TrafficPackagePeriodId: params.PeriodId,
|
||||
Count: params.Count,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["price"] = resp.Price
|
||||
this.Data["amount"] = resp.Amount
|
||||
|
||||
this.Success()
|
||||
}
|
||||
Reference in New Issue
Block a user