// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. package plans import ( "encoding/json" "github.com/TeaOSLab/EdgeCommon/pkg/langs/codes" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/TeaOSLab/EdgeUser/internal/configloaders" "github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/types" timeutil "github.com/iwind/TeaGo/utils/time" "time" ) type BuyAction struct { actionutils.ParentAction } func (this *BuyAction) Init() { this.Nav("", "", "buy") } func (this *BuyAction) RunGet(params struct { PlanId int64 }) { if !this.ValidateFeature(userconfigs.UserFeatureCodePlan, 0) { return } // 检查是否可以操作套餐 { priceConfig, err := configloaders.LoadUserPriceConfig() if err != nil { this.ErrorPage(err) return } if priceConfig != nil && !priceConfig.ShowPlansInUserSystem { this.ForbidPage() return } } this.Data["planId"] = params.PlanId this.Data["type"] = "" // 菜单统计数据 // 有效 { countResp, err := this.RPC().UserPlanRPC().CountAllEnabledUserPlans(this.UserContext(), &pb.CountAllEnabledUserPlansRequest{ IsAvailable: true, IsExpired: false, ExpiringDays: 0, }) if err != nil { this.ErrorPage(err) return } this.Data["countAvailable"] = countResp.Count } // 过期 { countResp, err := this.RPC().UserPlanRPC().CountAllEnabledUserPlans(this.UserContext(), &pb.CountAllEnabledUserPlansRequest{ IsAvailable: false, IsExpired: true, ExpiringDays: 0, }) if err != nil { this.ErrorPage(err) return } this.Data["countExpired"] = countResp.Count } // 7天过期 { countResp, err := this.RPC().UserPlanRPC().CountAllEnabledUserPlans(this.UserContext(), &pb.CountAllEnabledUserPlansRequest{ IsAvailable: false, IsExpired: false, ExpiringDays: 7, }) if err != nil { this.ErrorPage(err) return } this.Data["countExpiring7"] = countResp.Count } // 30天过期 { countResp, err := this.RPC().UserPlanRPC().CountAllEnabledUserPlans(this.UserContext(), &pb.CountAllEnabledUserPlansRequest{ IsAvailable: false, IsExpired: false, ExpiringDays: 30, }) if err != nil { this.ErrorPage(err) return } this.Data["countExpiring30"] = countResp.Count } // 所有功能 var allFeatureMaps = []maps.Map{} for _, feature := range userconfigs.FindAllUserFeatures() { if feature.SupportPlan { allFeatureMaps = append(allFeatureMaps, maps.Map{ "name": feature.Name, "code": feature.Code, }) } } this.Data["allFeatures"] = allFeatureMaps // 所有套餐 planResp, err := this.RPC().PlanRPC().FindAllAvailablePlans(this.UserContext(), &pb.FindAllAvailablePlansRequest{}) if err != nil { this.ErrorPage(err) return } var planMaps = []maps.Map{} for _, plan := range planResp.Plans { // 流量限制 var trafficLimitConfig = &serverconfigs.TrafficLimitConfig{} if len(plan.TrafficLimitJSON) > 0 { err = json.Unmarshal(plan.TrafficLimitJSON, trafficLimitConfig) if err != nil { this.ErrorPage(err) return } } // 带宽限制 // bandwidth limit var bandwidthLimitPerNode = &shared.SizeCapacity{} if len(plan.BandwidthLimitPerNodeJSON) > 0 { err = json.Unmarshal(plan.BandwidthLimitPerNodeJSON, bandwidthLimitPerNode) if err != nil { this.ErrorPage(err) return } } // 功能 var featureCodes = []string{} if len(plan.FeaturesJSON) > 0 { err = json.Unmarshal(plan.FeaturesJSON, &featureCodes) if err != nil { this.ErrorPage(err) return } } // max upload size var maxUploadSize = &shared.SizeCapacity{} if len(plan.MaxUploadSizeJSON) > 0 { err = json.Unmarshal(plan.MaxUploadSizeJSON, maxUploadSize) if err != nil { this.ErrorPage(err) return } } planMaps = append(planMaps, maps.Map{ "id": plan.Id, "name": plan.Name, "description": plan.Description, "priceType": plan.PriceType, "monthlyPrice": plan.MonthlyPrice, "seasonallyPrice": plan.SeasonallyPrice, "yearlyPrice": plan.YearlyPrice, "totalServers": plan.TotalServers, "totalServerNames": plan.TotalServerNames, "totalServerNamesPerServer": plan.TotalServerNamesPerServer, "dailyRequests": plan.DailyRequests, "monthlyRequests": plan.MonthlyRequests, "dailyWebsocketConnections": plan.DailyWebsocketConnections, "monthlyWebsocketConnections": plan.MonthlyWebsocketConnections, "trafficLimit": trafficLimitConfig, "bandwidthLimitPerNode": bandwidthLimitPerNode, "maxUploadSize": maxUploadSize, "hasFullFeatures": plan.HasFullFeatures, "featureCodes": featureCodes, }) } this.Data["plans"] = planMaps // 账户 accountResp, err := this.RPC().UserAccountRPC().FindEnabledUserAccountWithUserId(this.UserContext(), &pb.FindEnabledUserAccountWithUserIdRequest{UserId: this.UserId()}) if err != nil { this.ErrorPage(err) return } var account = accountResp.UserAccount if account == nil { this.Fail("找不到用户'" + types.String(this.UserId()) + "'的账户") } this.Data["userAccount"] = maps.Map{"total": account.Total} // 默认结束日期 this.Data["defaultDayTo"] = timeutil.Format("Y-m-d", time.Now().AddDate(20, 0, 0)) this.Show() } func (this *BuyAction) RunPost(params struct { PlanId int64 Name string Period string CountMonths int32 CountSeasons int32 CountYears int32 DayTo string Must *actions.Must CSRF *actionutils.CSRF }) { if !this.ValidateFeature(userconfigs.UserFeatureCodePlan, 0) { return } // 检查是否可以操作套餐 { priceConfig, err := configloaders.LoadUserPriceConfig() if err != nil { this.ErrorPage(err) return } if priceConfig != nil && !priceConfig.ShowPlansInUserSystem { this.ForbidPage() return } } defer this.CreateLogInfo(codes.UserPlan_LogBuyUserPlan, this.UserId()) params.Must. Field("planId", params.PlanId). Gt(0, "请选择套餐") // 检查余额 planResp, err := this.RPC().PlanRPC().FindEnabledPlan(this.UserContext(), &pb.FindEnabledPlanRequest{PlanId: params.PlanId}) if err != nil { this.ErrorPage(err) return } var plan = planResp.Plan if plan == nil { this.Fail("找不到要购买的套餐") } if len(params.Name) == 0 { params.Name = plan.Name } var countPeriod int32 if plan.PriceType == serverconfigs.PlanPriceTypePeriod { var cost float64 switch params.Period { case "monthly": countPeriod = params.CountMonths cost = plan.MonthlyPrice * float64(countPeriod) case "seasonally": countPeriod = params.CountSeasons cost = plan.SeasonallyPrice * float64(countPeriod) case "yearly": countPeriod = params.CountYears cost = plan.YearlyPrice * float64(countPeriod) default: this.Fail("invalid period '" + params.Period + "'") } // 账号 accountResp, err := this.RPC().UserAccountRPC().FindEnabledUserAccountWithUserId(this.UserContext(), &pb.FindEnabledUserAccountWithUserIdRequest{UserId: this.UserId()}) if err != nil { this.ErrorPage(err) return } var account = accountResp.UserAccount if account == nil { this.Fail("找不到用户'" + types.String(this.UserId()) + "'的账户") } if account.Total < cost { this.Fail("用户账户余额不足") } } else if plan.PriceType == serverconfigs.PlanPriceTypeTraffic { params.Must.Field("dayTo", params.DayTo). Match(`^\d+-\d+-\d+$`, "请输入正确的结束日期") } else if plan.PriceType == serverconfigs.PlanPriceTypeBandwidth { params.Must.Field("dayTo", params.DayTo). Match(`^\d+-\d+-\d+$`, "请输入正确的结束日期") } else { this.Fail("不支持的付款方式:" + plan.PriceType) } _, err = this.RPC().UserPlanRPC().BuyUserPlan(this.UserContext(), &pb.BuyUserPlanRequest{ UserId: this.UserId(), PlanId: params.PlanId, Name: params.Name, DayTo: params.DayTo, Period: params.Period, CountPeriod: countPeriod, }) if err != nil { this.ErrorPage(err) return } this.Success() }