mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-15 04:41:25 +08:00
删除不需要的代码
This commit is contained in:
@@ -98,10 +98,6 @@ func (this *RPCClient) NodeRegionRPC() pb.NodeRegionServiceClient {
|
|||||||
return pb.NewNodeRegionServiceClient(this.pickConn())
|
return pb.NewNodeRegionServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCClient) NodePriceItemRPC() pb.NodePriceItemServiceClient {
|
|
||||||
return pb.NewNodePriceItemServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NodeIPAddressRPC() pb.NodeIPAddressServiceClient {
|
func (this *RPCClient) NodeIPAddressRPC() pb.NodeIPAddressServiceClient {
|
||||||
return pb.NewNodeIPAddressServiceClient(this.pickConn())
|
return pb.NewNodeIPAddressServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -455,14 +451,6 @@ func (this *RPCClient) ServerStatBoardChartRPC() pb.ServerStatBoardChartServiceC
|
|||||||
return pb.NewServerStatBoardChartServiceClient(this.pickConn())
|
return pb.NewServerStatBoardChartServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCClient) PlanRPC() pb.PlanServiceClient {
|
|
||||||
return pb.NewPlanServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) UserPlanRPC() pb.UserPlanServiceClient {
|
|
||||||
return pb.NewUserPlanServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) TrafficDailyStatRPC() pb.TrafficDailyStatServiceClient {
|
func (this *RPCClient) TrafficDailyStatRPC() pb.TrafficDailyStatServiceClient {
|
||||||
return pb.NewTrafficDailyStatServiceClient(this.pickConn())
|
return pb.NewTrafficDailyStatServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package numberutils
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FormatInt64(value int64) string {
|
func FormatInt64(value int64) string {
|
||||||
@@ -28,35 +30,35 @@ func FormatBytes(bytes int64) string {
|
|||||||
if bytes < Pow1024(1) {
|
if bytes < Pow1024(1) {
|
||||||
return FormatInt64(bytes) + "B"
|
return FormatInt64(bytes) + "B"
|
||||||
} else if bytes < Pow1024(2) {
|
} else if bytes < Pow1024(2) {
|
||||||
return fmt.Sprintf("%.2fKB", float64(bytes)/float64(Pow1024(1)))
|
return TrimZeroSuffix(fmt.Sprintf("%.2fKB", float64(bytes)/float64(Pow1024(1))))
|
||||||
} else if bytes < Pow1024(3) {
|
} else if bytes < Pow1024(3) {
|
||||||
return fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2)))
|
return TrimZeroSuffix(fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2))))
|
||||||
} else if bytes < Pow1024(4) {
|
} else if bytes < Pow1024(4) {
|
||||||
return fmt.Sprintf("%.2fGB", float64(bytes)/float64(Pow1024(3)))
|
return TrimZeroSuffix(fmt.Sprintf("%.2fGB", float64(bytes)/float64(Pow1024(3))))
|
||||||
} else if bytes < Pow1024(5) {
|
} else if bytes < Pow1024(5) {
|
||||||
return fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4)))
|
return TrimZeroSuffix(fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4))))
|
||||||
} else if bytes < Pow1024(6) {
|
} else if bytes < Pow1024(6) {
|
||||||
return fmt.Sprintf("%.2fPB", float64(bytes)/float64(Pow1024(5)))
|
return TrimZeroSuffix(fmt.Sprintf("%.2fPB", float64(bytes)/float64(Pow1024(5))))
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6)))
|
return TrimZeroSuffix(fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatBits(bits int64) string {
|
func FormatBits(bits int64) string {
|
||||||
if bits < Pow1024(1) {
|
if bits < Pow1024(1) {
|
||||||
return FormatInt64(bits) + "Bps"
|
return FormatInt64(bits) + "bps"
|
||||||
} else if bits < Pow1024(2) {
|
} else if bits < Pow1024(2) {
|
||||||
return fmt.Sprintf("%.4fKBps", float64(bits)/float64(Pow1024(1)))
|
return TrimZeroSuffix(fmt.Sprintf("%.4fKbps", float64(bits)/float64(Pow1024(1))))
|
||||||
} else if bits < Pow1024(3) {
|
} else if bits < Pow1024(3) {
|
||||||
return fmt.Sprintf("%.4fMBps", float64(bits)/float64(Pow1024(2)))
|
return TrimZeroSuffix(fmt.Sprintf("%.4fMbps", float64(bits)/float64(Pow1024(2))))
|
||||||
} else if bits < Pow1024(4) {
|
} else if bits < Pow1024(4) {
|
||||||
return fmt.Sprintf("%.4fGBps", float64(bits)/float64(Pow1024(3)))
|
return TrimZeroSuffix(fmt.Sprintf("%.4fGbps", float64(bits)/float64(Pow1024(3))))
|
||||||
} else if bits < Pow1024(5) {
|
} else if bits < Pow1024(5) {
|
||||||
return fmt.Sprintf("%.4fTBps", float64(bits)/float64(Pow1024(4)))
|
return TrimZeroSuffix(fmt.Sprintf("%.4fTbps", float64(bits)/float64(Pow1024(4))))
|
||||||
} else if bits < Pow1024(6) {
|
} else if bits < Pow1024(6) {
|
||||||
return fmt.Sprintf("%.4fPBps", float64(bits)/float64(Pow1024(5)))
|
return TrimZeroSuffix(fmt.Sprintf("%.4fPbps", float64(bits)/float64(Pow1024(5))))
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%.4fEBps", float64(bits)/float64(Pow1024(6)))
|
return TrimZeroSuffix(fmt.Sprintf("%.4fEbps", float64(bits)/float64(Pow1024(6))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,3 +94,14 @@ func FormatFloat(f interface{}, decimal int) string {
|
|||||||
func FormatFloat2(f interface{}) string {
|
func FormatFloat2(f interface{}) string {
|
||||||
return FormatFloat(f, 2)
|
return FormatFloat(f, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var decimalReg = regexp.MustCompile(`^(\d+\.\d+)([a-zA-Z]+)?$`)
|
||||||
|
|
||||||
|
// TrimZeroSuffix 去除小数数字尾部多余的0
|
||||||
|
func TrimZeroSuffix(s string) string {
|
||||||
|
var matches = decimalReg.FindStringSubmatch(s)
|
||||||
|
if len(matches) < 3 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strings.TrimRight(strings.TrimRight(matches[1], "0"), ".") + matches[2]
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,3 +34,20 @@ func TestFormatFloat(t *testing.T) {
|
|||||||
t.Log(numberutils.FormatFloat(100.000023, 2))
|
t.Log(numberutils.FormatFloat(100.000023, 2))
|
||||||
t.Log(numberutils.FormatFloat(100.012, 2))
|
t.Log(numberutils.FormatFloat(100.012, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrimZeroSuffix(t *testing.T) {
|
||||||
|
for _, s := range []string{
|
||||||
|
"1",
|
||||||
|
"1.0000",
|
||||||
|
"1.10",
|
||||||
|
"100",
|
||||||
|
"100.0000",
|
||||||
|
"100.0",
|
||||||
|
"100.0123",
|
||||||
|
"100.0010",
|
||||||
|
"100.000KB",
|
||||||
|
"100.010MB",
|
||||||
|
} {
|
||||||
|
t.Log(s, "=>", numberutils.TrimZeroSuffix(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ func init() {
|
|||||||
Post("/delete", new(DeleteAction)).
|
Post("/delete", new(DeleteAction)).
|
||||||
Post("/sort", new(SortAction)).
|
Post("/sort", new(SortAction)).
|
||||||
GetPost("/selectPopup", new(SelectPopupAction)).
|
GetPost("/selectPopup", new(SelectPopupAction)).
|
||||||
GetPost("/prices", new(PricesAction)).
|
|
||||||
GetPost("/updatePricePopup", new(UpdatePricePopupAction)).
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
package items
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions/regionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CreatePopupAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *CreatePopupAction) Init() {
|
|
||||||
this.Nav("", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *CreatePopupAction) RunGet(params struct{}) {
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *CreatePopupAction) RunPost(params struct {
|
|
||||||
Name string
|
|
||||||
BitsFrom int64
|
|
||||||
BitsTo int64
|
|
||||||
|
|
||||||
Must *actions.Must
|
|
||||||
CSRF *actionutils.CSRF
|
|
||||||
}) {
|
|
||||||
params.Must.
|
|
||||||
Field("name", params.Name).
|
|
||||||
Require("请输入名称").
|
|
||||||
Field("bitsFrom", params.BitsFrom).
|
|
||||||
Gte(0, "请输入不小于0的整数").
|
|
||||||
Field("bitsTo", params.BitsTo).
|
|
||||||
Gte(0, "请输入不小于0的整数")
|
|
||||||
|
|
||||||
createResp, err := this.RPC().NodePriceItemRPC().CreateNodePriceItem(this.AdminContext(), &pb.CreateNodePriceItemRequest{
|
|
||||||
Name: params.Name,
|
|
||||||
Type: regionutils.PriceTypeTraffic,
|
|
||||||
BitsFrom: params.BitsFrom * 1000 * 1000,
|
|
||||||
BitsTo: params.BitsTo * 1000 * 1000,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer this.CreateLogInfo("创建流量价格项目", createResp.NodePriceItemId)
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package items
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeleteAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *DeleteAction) RunPost(params struct {
|
|
||||||
ItemId int64
|
|
||||||
}) {
|
|
||||||
defer this.CreateLogInfo("删除流量价格项目 %d", params.ItemId)
|
|
||||||
|
|
||||||
_, err := this.RPC().NodePriceItemRPC().DeleteNodePriceItem(this.AdminContext(), &pb.DeleteNodePriceItemRequest{NodePriceItemId: params.ItemId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package items
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
|
||||||
"github.com/iwind/TeaGo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
|
||||||
server.
|
|
||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
|
|
||||||
Data("teaMenu", "clusters").
|
|
||||||
Data("teaSubMenu", "region").
|
|
||||||
Prefix("/clusters/regions/items").
|
|
||||||
GetPost("/createPopup", new(CreatePopupAction)).
|
|
||||||
GetPost("/updatePopup", new(UpdatePopupAction)).
|
|
||||||
Post("/delete", new(DeleteAction)).
|
|
||||||
EndAll()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package items
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UpdatePopupAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpdatePopupAction) Init() {
|
|
||||||
this.Nav("", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpdatePopupAction) RunGet(params struct {
|
|
||||||
ItemId int64
|
|
||||||
}) {
|
|
||||||
itemResp, err := this.RPC().NodePriceItemRPC().FindEnabledNodePriceItem(this.AdminContext(), &pb.FindEnabledNodePriceItemRequest{NodePriceItemId: params.ItemId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
item := itemResp.NodePriceItem
|
|
||||||
if item == nil {
|
|
||||||
this.NotFound("nodePriceItem", params.ItemId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["item"] = maps.Map{
|
|
||||||
"id": item.Id,
|
|
||||||
"name": item.Name,
|
|
||||||
"bitsFrom": item.BitsFrom,
|
|
||||||
"bitsTo": item.BitsTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpdatePopupAction) RunPost(params struct {
|
|
||||||
ItemId int64
|
|
||||||
Name string
|
|
||||||
BitsFrom int64
|
|
||||||
BitsTo int64
|
|
||||||
|
|
||||||
Must *actions.Must
|
|
||||||
CSRF *actionutils.CSRF
|
|
||||||
}) {
|
|
||||||
defer this.CreateLogInfo("修改流量价格项目 %d", params.ItemId)
|
|
||||||
|
|
||||||
params.Must.
|
|
||||||
Field("name", params.Name).
|
|
||||||
Require("请输入名称").
|
|
||||||
Field("bitsFrom", params.BitsFrom).
|
|
||||||
Gte(0, "请输入不小于0的整数").
|
|
||||||
Field("bitsTo", params.BitsTo).
|
|
||||||
Gte(0, "请输入不小于0的整数")
|
|
||||||
|
|
||||||
_, err := this.RPC().NodePriceItemRPC().UpdateNodePriceItem(this.AdminContext(), &pb.UpdateNodePriceItemRequest{
|
|
||||||
NodePriceItemId: params.ItemId,
|
|
||||||
Name: params.Name,
|
|
||||||
BitsFrom: params.BitsFrom * 1000 * 1000,
|
|
||||||
BitsTo: params.BitsTo * 1000 * 1000,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
package regions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions/regionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PricesAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *PricesAction) Init() {
|
|
||||||
this.Nav("", "", "price")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *PricesAction) RunGet(params struct{}) {
|
|
||||||
// 所有价格项目
|
|
||||||
itemsResp, err := this.RPC().NodePriceItemRPC().FindAllAvailableNodePriceItems(this.AdminContext(), &pb.FindAllAvailableNodePriceItemsRequest{Type: regionutils.PriceTypeTraffic})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
itemMaps := []maps.Map{}
|
|
||||||
for _, item := range itemsResp.NodePriceItems {
|
|
||||||
|
|
||||||
itemMaps = append(itemMaps, maps.Map{
|
|
||||||
"id": item.Id,
|
|
||||||
"name": item.Name,
|
|
||||||
"bitsFromString": this.formatBits(item.BitsFrom),
|
|
||||||
"bitsToString": this.formatBits(item.BitsTo),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["items"] = itemMaps
|
|
||||||
|
|
||||||
// 所有区域
|
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledNodeRegions(this.AdminContext(), &pb.FindAllEnabledNodeRegionsRequest{})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
regionMaps := []maps.Map{}
|
|
||||||
for _, region := range regionsResp.NodeRegions {
|
|
||||||
pricesMap := map[string]float32{}
|
|
||||||
if len(region.PricesJSON) > 0 {
|
|
||||||
err = json.Unmarshal(region.PricesJSON, &pricesMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
regionMaps = append(regionMaps, maps.Map{
|
|
||||||
"id": region.Id,
|
|
||||||
"isOn": region.IsOn,
|
|
||||||
"name": region.Name,
|
|
||||||
"prices": pricesMap,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["regions"] = regionMaps
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *PricesAction) formatBits(bits int64) string {
|
|
||||||
sizeHuman := ""
|
|
||||||
if bits < 1000 {
|
|
||||||
sizeHuman = numberutils.FormatInt64(bits) + "BPS"
|
|
||||||
} else if bits < 1_000_000 {
|
|
||||||
sizeHuman = fmt.Sprintf("%.2fKBPS", float64(bits)/1000)
|
|
||||||
} else if bits < 1_000_000_000 {
|
|
||||||
sizeHuman = fmt.Sprintf("%.2fMBPS", float64(bits)/1000/1000)
|
|
||||||
} else if bits < 1_000_000_000_000 {
|
|
||||||
sizeHuman = fmt.Sprintf("%.2fGBPS", float64(bits)/1000/1000/1000)
|
|
||||||
} else if bits < 1_000_000_000_000_000 {
|
|
||||||
sizeHuman = fmt.Sprintf("%.2fTBPS", float64(bits)/1000/1000/1000/1000)
|
|
||||||
} else if bits < 1_000_000_000_000_000_000 {
|
|
||||||
sizeHuman = fmt.Sprintf("%.2fPBPS", float64(bits)/1000/1000/1000/1000/1000)
|
|
||||||
} else {
|
|
||||||
sizeHuman = fmt.Sprintf("%.2fEBPS", float64(bits)/1000/1000/1000/1000/1000/1000)
|
|
||||||
}
|
|
||||||
return sizeHuman
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package regionutils
|
package regionutils
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PriceTypeTraffic = "traffic"
|
PriceTypeTraffic = "traffic"
|
||||||
|
PriceTypeBandwidth = "bandwidth"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
package regions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UpdatePricePopupAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpdatePricePopupAction) Init() {
|
|
||||||
this.Nav("", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpdatePricePopupAction) RunGet(params struct {
|
|
||||||
RegionId int64
|
|
||||||
ItemId int64
|
|
||||||
}) {
|
|
||||||
// 区域
|
|
||||||
regionResp, err := this.RPC().NodeRegionRPC().FindEnabledNodeRegion(this.AdminContext(), &pb.FindEnabledNodeRegionRequest{NodeRegionId: params.RegionId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
region := regionResp.NodeRegion
|
|
||||||
if region == nil {
|
|
||||||
this.NotFound("nodeRegion", params.RegionId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.Data["region"] = maps.Map{
|
|
||||||
"id": region.Id,
|
|
||||||
"isOn": region.IsOn,
|
|
||||||
"name": region.Name,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前价格
|
|
||||||
pricesMap := map[string]float32{}
|
|
||||||
if len(region.PricesJSON) > 0 {
|
|
||||||
err = json.Unmarshal(region.PricesJSON, &pricesMap)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.Data["price"] = pricesMap[numberutils.FormatInt64(params.ItemId)]
|
|
||||||
|
|
||||||
// 价格项
|
|
||||||
itemResp, err := this.RPC().NodePriceItemRPC().FindEnabledNodePriceItem(this.AdminContext(), &pb.FindEnabledNodePriceItemRequest{NodePriceItemId: params.ItemId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
item := itemResp.NodePriceItem
|
|
||||||
if item == nil {
|
|
||||||
this.NotFound("nodePriceItem", params.ItemId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["item"] = maps.Map{
|
|
||||||
"id": item.Id,
|
|
||||||
"name": item.Name,
|
|
||||||
"bitsFrom": item.BitsFrom,
|
|
||||||
"bitsTo": item.BitsTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpdatePricePopupAction) RunPost(params struct {
|
|
||||||
RegionId int64
|
|
||||||
ItemId int64
|
|
||||||
Price float32
|
|
||||||
|
|
||||||
Must *actions.Must
|
|
||||||
CSRF *actionutils.CSRF
|
|
||||||
}) {
|
|
||||||
defer this.CreateLogInfo("修改区域 %d-价格项 %d 的价格", params.RegionId, params.ItemId)
|
|
||||||
|
|
||||||
_, err := this.RPC().NodeRegionRPC().UpdateNodeRegionPrice(this.AdminContext(), &pb.UpdateNodeRegionPriceRequest{
|
|
||||||
NodeRegionId: params.RegionId,
|
|
||||||
NodeItemId: params.ItemId,
|
|
||||||
Price: params.Price,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -65,34 +65,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 套餐
|
// 套餐
|
||||||
var userPlanMap = maps.Map{"id": server.UserPlanId, "dayTo": "", "plan": maps.Map{}}
|
this.initUserPlan(server)
|
||||||
if server.UserPlanId > 0 {
|
|
||||||
userPlanResp, err := this.RPC().UserPlanRPC().FindEnabledUserPlan(this.AdminContext(), &pb.FindEnabledUserPlanRequest{UserPlanId: server.UserPlanId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var userPlan = userPlanResp.UserPlan
|
|
||||||
if userPlan != nil {
|
|
||||||
planResp, err := this.RPC().PlanRPC().FindEnabledPlan(this.AdminContext(), &pb.FindEnabledPlanRequest{PlanId: userPlan.PlanId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var plan = planResp.Plan
|
|
||||||
if plan != nil {
|
|
||||||
userPlanMap = maps.Map{
|
|
||||||
"id": userPlan.Id,
|
|
||||||
"dayTo": userPlan.DayTo,
|
|
||||||
"plan": maps.Map{
|
|
||||||
"id": plan.Id,
|
|
||||||
"name": plan.Name,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.Data["userPlan"] = userPlanMap
|
|
||||||
|
|
||||||
// 集群
|
// 集群
|
||||||
clusterId := int64(0)
|
clusterId := int64(0)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *IndexAction) initUserPlan(server *pb.Server) {
|
||||||
|
var userPlanMap = maps.Map{"id": server.UserPlanId, "dayTo": "", "plan": maps.Map{}}
|
||||||
|
this.Data["userPlan"] = userPlanMap
|
||||||
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
package users
|
package users
|
||||||
|
|
||||||
import (
|
import (
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,33 +16,6 @@ func (this *PlansAction) RunPost(params struct {
|
|||||||
UserId int64
|
UserId int64
|
||||||
ServerId int64
|
ServerId int64
|
||||||
}) {
|
}) {
|
||||||
if !teaconst.IsPlus || params.UserId <= 0 {
|
this.Data["plans"] = []maps.Map{}
|
||||||
this.Data["plans"] = []maps.Map{}
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 优化用户套餐查询
|
|
||||||
userPlansResp, err := this.RPC().UserPlanRPC().FindAllEnabledUserPlansForServer(this.AdminContext(), &pb.FindAllEnabledUserPlansForServerRequest{
|
|
||||||
UserId: params.UserId,
|
|
||||||
ServerId: params.ServerId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var userPlanMaps = []maps.Map{}
|
|
||||||
for _, userPlan := range userPlansResp.UserPlans {
|
|
||||||
if userPlan.Plan == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
userPlanMaps = append(userPlanMaps, maps.Map{
|
|
||||||
"id": userPlan.Id,
|
|
||||||
"name": userPlan.Plan.Name,
|
|
||||||
"dayTo": userPlan.DayTo,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["plans"] = userPlanMaps
|
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/logs"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/logs"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/regions/items"
|
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/tasks"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/tasks"
|
||||||
|
|
||||||
// 通用
|
// 通用
|
||||||
|
|||||||
1
web/public/js/components/.gitignore
vendored
Normal file
1
web/public/js/components/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*-plus.js
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
Vue.component("plan-bandwidth-ranges", {
|
|
||||||
props: ["v-ranges"],
|
|
||||||
data: function () {
|
|
||||||
let ranges = this.vRanges
|
|
||||||
if (ranges == null) {
|
|
||||||
ranges = []
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
ranges: ranges,
|
|
||||||
isAdding: false,
|
|
||||||
|
|
||||||
minMB: "",
|
|
||||||
maxMB: "",
|
|
||||||
pricePerMB: "",
|
|
||||||
totalPrice: "",
|
|
||||||
addingRange: {
|
|
||||||
minMB: 0,
|
|
||||||
maxMB: 0,
|
|
||||||
pricePerMB: 0,
|
|
||||||
totalPrice: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
add: function () {
|
|
||||||
this.isAdding = !this.isAdding
|
|
||||||
let that = this
|
|
||||||
setTimeout(function () {
|
|
||||||
that.$refs.minMB.focus()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
cancelAdding: function () {
|
|
||||||
this.isAdding = false
|
|
||||||
},
|
|
||||||
confirm: function () {
|
|
||||||
this.isAdding = false
|
|
||||||
this.minMB = ""
|
|
||||||
this.maxMB = ""
|
|
||||||
this.pricePerMB = ""
|
|
||||||
this.totalPrice = ""
|
|
||||||
this.ranges.push(this.addingRange)
|
|
||||||
this.ranges.$sort(function (v1, v2) {
|
|
||||||
if (v1.minMB < v2.minMB) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if (v1.minMB == v2.minMB) {
|
|
||||||
if (v2.maxMB == 0 || v1.maxMB < v2.maxMB) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
})
|
|
||||||
this.change()
|
|
||||||
this.addingRange = {
|
|
||||||
minMB: 0,
|
|
||||||
maxMB: 0,
|
|
||||||
pricePerMB: 0,
|
|
||||||
totalPrice: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remove: function (index) {
|
|
||||||
this.ranges.$remove(index)
|
|
||||||
this.change()
|
|
||||||
},
|
|
||||||
change: function () {
|
|
||||||
this.$emit("change", this.ranges)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
minMB: function (v) {
|
|
||||||
let minMB = parseInt(v.toString())
|
|
||||||
if (isNaN(minMB) || minMB < 0) {
|
|
||||||
minMB = 0
|
|
||||||
}
|
|
||||||
this.addingRange.minMB = minMB
|
|
||||||
},
|
|
||||||
maxMB: function (v) {
|
|
||||||
let maxMB = parseInt(v.toString())
|
|
||||||
if (isNaN(maxMB) || maxMB < 0) {
|
|
||||||
maxMB = 0
|
|
||||||
}
|
|
||||||
this.addingRange.maxMB = maxMB
|
|
||||||
},
|
|
||||||
pricePerMB: function (v) {
|
|
||||||
let pricePerMB = parseFloat(v.toString())
|
|
||||||
if (isNaN(pricePerMB) || pricePerMB < 0) {
|
|
||||||
pricePerMB = 0
|
|
||||||
}
|
|
||||||
this.addingRange.pricePerMB = pricePerMB
|
|
||||||
},
|
|
||||||
totalPrice: function (v) {
|
|
||||||
let totalPrice = parseFloat(v.toString())
|
|
||||||
if (isNaN(totalPrice) || totalPrice < 0) {
|
|
||||||
totalPrice = 0
|
|
||||||
}
|
|
||||||
this.addingRange.totalPrice = totalPrice
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `<div>
|
|
||||||
<!-- 已有价格 -->
|
|
||||||
<div v-if="ranges.length > 0">
|
|
||||||
<div class="ui label basic small" v-for="(range, index) in ranges" style="margin-bottom: 0.5em">
|
|
||||||
{{range.minMB}}MB - <span v-if="range.maxMB > 0">{{range.maxMB}}MB</span><span v-else>∞</span> 价格:<span v-if="range.totalPrice > 0">{{range.totalPrice}}元</span><span v-else="">{{range.pricePerMB}}元/MB</span>
|
|
||||||
<a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
|
||||||
</div>
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 添加 -->
|
|
||||||
<div v-if="isAdding">
|
|
||||||
<table class="ui table">
|
|
||||||
<tr>
|
|
||||||
<td class="title">带宽下限 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" placeholder="最小带宽" style="width: 7em" maxlength="10" ref="minMB" @keyup.enter="confirm()" @keypress.enter.prevent="1" v-model="minMB"/>
|
|
||||||
<span class="ui label">MB</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="title">带宽上限 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" placeholder="最大带宽" style="width: 7em" maxlength="10" @keyup.enter="confirm()" @keypress.enter.prevent="1" v-model="maxMB"/>
|
|
||||||
<span class="ui label">MB</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">如果填0,表示上不封顶。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>总价格</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" placeholder="总价格" style="width: 7em" maxlength="10" @keyup.enter="confirm()" @keypress.enter.prevent="1" v-model="totalPrice"/>
|
|
||||||
<span class="ui label">元/MB</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">和单位价格二选一。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="title">单位价格</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" placeholder="单位价格" style="width: 7em" maxlength="10" @keyup.enter="confirm()" @keypress.enter.prevent="1" v-model="pricePerMB"/>
|
|
||||||
<span class="ui label">元/MB</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 带宽"。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<button class="ui button small" type="button" @click.prevent="confirm">确定</button>
|
|
||||||
<a href="" title="取消" @click.prevent="cancelAdding"><i class="icon remove small"></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按钮 -->
|
|
||||||
<div v-if="!isAdding">
|
|
||||||
<button class="ui button small" type="button" @click.prevent="add">+</button>
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
})
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
// 套餐价格配置
|
|
||||||
Vue.component("plan-price-config-box", {
|
|
||||||
props: ["v-price-type", "v-monthly-price", "v-seasonally-price", "v-yearly-price", "v-traffic-price", "v-bandwidth-price", "v-disable-period"],
|
|
||||||
data: function () {
|
|
||||||
let priceType = this.vPriceType
|
|
||||||
if (priceType == null) {
|
|
||||||
priceType = "bandwidth"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按时间周期计费
|
|
||||||
let monthlyPriceNumber = 0
|
|
||||||
let monthlyPrice = this.vMonthlyPrice
|
|
||||||
if (monthlyPrice == null || monthlyPrice <= 0) {
|
|
||||||
monthlyPrice = ""
|
|
||||||
} else {
|
|
||||||
monthlyPrice = monthlyPrice.toString()
|
|
||||||
monthlyPriceNumber = parseFloat(monthlyPrice)
|
|
||||||
if (isNaN(monthlyPriceNumber)) {
|
|
||||||
monthlyPriceNumber = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let seasonallyPriceNumber = 0
|
|
||||||
let seasonallyPrice = this.vSeasonallyPrice
|
|
||||||
if (seasonallyPrice == null || seasonallyPrice <= 0) {
|
|
||||||
seasonallyPrice = ""
|
|
||||||
} else {
|
|
||||||
seasonallyPrice = seasonallyPrice.toString()
|
|
||||||
seasonallyPriceNumber = parseFloat(seasonallyPrice)
|
|
||||||
if (isNaN(seasonallyPriceNumber)) {
|
|
||||||
seasonallyPriceNumber = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let yearlyPriceNumber = 0
|
|
||||||
let yearlyPrice = this.vYearlyPrice
|
|
||||||
if (yearlyPrice == null || yearlyPrice <= 0) {
|
|
||||||
yearlyPrice = ""
|
|
||||||
} else {
|
|
||||||
yearlyPrice = yearlyPrice.toString()
|
|
||||||
yearlyPriceNumber = parseFloat(yearlyPrice)
|
|
||||||
if (isNaN(yearlyPriceNumber)) {
|
|
||||||
yearlyPriceNumber = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按流量计费
|
|
||||||
let trafficPrice = this.vTrafficPrice
|
|
||||||
let trafficPriceBaseNumber = 0
|
|
||||||
if (trafficPrice != null) {
|
|
||||||
trafficPriceBaseNumber = trafficPrice.base
|
|
||||||
} else {
|
|
||||||
trafficPrice = {
|
|
||||||
base: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let trafficPriceBase = ""
|
|
||||||
if (trafficPriceBaseNumber > 0) {
|
|
||||||
trafficPriceBase = trafficPriceBaseNumber.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按带宽计费
|
|
||||||
let bandwidthPrice = this.vBandwidthPrice
|
|
||||||
if (bandwidthPrice == null) {
|
|
||||||
bandwidthPrice = {
|
|
||||||
percentile: 95,
|
|
||||||
ranges: []
|
|
||||||
}
|
|
||||||
} else if (bandwidthPrice.ranges == null) {
|
|
||||||
bandwidthPrice.ranges = []
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
priceType: priceType,
|
|
||||||
monthlyPrice: monthlyPrice,
|
|
||||||
seasonallyPrice: seasonallyPrice,
|
|
||||||
yearlyPrice: yearlyPrice,
|
|
||||||
|
|
||||||
monthlyPriceNumber: monthlyPriceNumber,
|
|
||||||
seasonallyPriceNumber: seasonallyPriceNumber,
|
|
||||||
yearlyPriceNumber: yearlyPriceNumber,
|
|
||||||
|
|
||||||
trafficPriceBase: trafficPriceBase,
|
|
||||||
trafficPrice: trafficPrice,
|
|
||||||
|
|
||||||
bandwidthPrice: bandwidthPrice,
|
|
||||||
bandwidthPercentile: bandwidthPrice.percentile
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeBandwidthPriceRanges: function (ranges) {
|
|
||||||
this.bandwidthPrice.ranges = ranges
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
monthlyPrice: function (v) {
|
|
||||||
let price = parseFloat(v)
|
|
||||||
if (isNaN(price)) {
|
|
||||||
price = 0
|
|
||||||
}
|
|
||||||
this.monthlyPriceNumber = price
|
|
||||||
},
|
|
||||||
seasonallyPrice: function (v) {
|
|
||||||
let price = parseFloat(v)
|
|
||||||
if (isNaN(price)) {
|
|
||||||
price = 0
|
|
||||||
}
|
|
||||||
this.seasonallyPriceNumber = price
|
|
||||||
},
|
|
||||||
yearlyPrice: function (v) {
|
|
||||||
let price = parseFloat(v)
|
|
||||||
if (isNaN(price)) {
|
|
||||||
price = 0
|
|
||||||
}
|
|
||||||
this.yearlyPriceNumber = price
|
|
||||||
},
|
|
||||||
trafficPriceBase: function (v) {
|
|
||||||
let price = parseFloat(v)
|
|
||||||
if (isNaN(price)) {
|
|
||||||
price = 0
|
|
||||||
}
|
|
||||||
this.trafficPrice.base = price
|
|
||||||
},
|
|
||||||
bandwidthPercentile: function (v) {
|
|
||||||
let percentile = parseInt(v)
|
|
||||||
if (isNaN(percentile) || percentile <= 0) {
|
|
||||||
percentile = 95
|
|
||||||
} else if (percentile > 100) {
|
|
||||||
percentile = 100
|
|
||||||
}
|
|
||||||
this.bandwidthPrice.percentile = percentile
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `<div>
|
|
||||||
<input type="hidden" name="priceType" :value="priceType"/>
|
|
||||||
<input type="hidden" name="monthlyPrice" :value="monthlyPriceNumber"/>
|
|
||||||
<input type="hidden" name="seasonallyPrice" :value="seasonallyPriceNumber"/>
|
|
||||||
<input type="hidden" name="yearlyPrice" :value="yearlyPriceNumber"/>
|
|
||||||
<input type="hidden" name="trafficPriceJSON" :value="JSON.stringify(trafficPrice)"/>
|
|
||||||
<input type="hidden" name="bandwidthPriceJSON" :value="JSON.stringify(bandwidthPrice)"/>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<radio :v-value="'bandwidth'" :value="priceType" v-model="priceType"> 按带宽</radio>
|
|
||||||
<radio :v-value="'traffic'" :value="priceType" v-model="priceType"> 按流量</radio>
|
|
||||||
<radio :v-value="'period'" :value="priceType" v-model="priceType" v-show="typeof(vDisablePeriod) != 'boolean' || !vDisablePeriod"> 按时间周期</radio>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按时间周期 -->
|
|
||||||
<div v-show="priceType == 'period'">
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
<table class="ui table">
|
|
||||||
<tr>
|
|
||||||
<td class="title">月度价格</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" style="width: 7em" maxlength="10" v-model="monthlyPrice"/>
|
|
||||||
<span class="ui label">元</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="title">季度价格</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" style="width: 7em" maxlength="10" v-model="seasonallyPrice"/>
|
|
||||||
<span class="ui label">元</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="title">年度价格</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" style="width: 7em" maxlength="10" v-model="yearlyPrice"/>
|
|
||||||
<span class="ui label">元</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按流量 -->
|
|
||||||
<div v-show="priceType =='traffic'">
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
<table class="ui table">
|
|
||||||
<tr>
|
|
||||||
<td class="title">基础流量费用 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" v-model="trafficPriceBase" maxlength="10" style="width: 7em"/>
|
|
||||||
<span class="ui label">元/GB</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按带宽 -->
|
|
||||||
<div v-show="priceType == 'bandwidth'">
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
<table class="ui table">
|
|
||||||
<tr>
|
|
||||||
<td class="title">带宽百分位 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" style="width: 4em" maxlength="3" v-model="bandwidthPercentile"/>
|
|
||||||
<span class="ui label">th</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>带宽价格</td>
|
|
||||||
<td>
|
|
||||||
<plan-bandwidth-ranges :v-ranges="bandwidthPrice.ranges" @change="changeBandwidthPriceRanges"></plan-bandwidth-ranges>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
})
|
|
||||||
@@ -138,7 +138,7 @@ window.teaweb = {
|
|||||||
formatBits: function (bits) {
|
formatBits: function (bits) {
|
||||||
bits = Math.ceil(bits);
|
bits = Math.ceil(bits);
|
||||||
if (bits < Math.pow(1024, 1)) {
|
if (bits < Math.pow(1024, 1)) {
|
||||||
return bits + "Bps";
|
return bits + "bps";
|
||||||
}
|
}
|
||||||
if (bits < Math.pow(1024, 2)) {
|
if (bits < Math.pow(1024, 2)) {
|
||||||
return (Math.round(bits * 10000 / Math.pow(1024, 1)) / 10000) + "Kbps";
|
return (Math.round(bits * 10000 / Math.pow(1024, 1)) / 10000) + "Kbps";
|
||||||
@@ -230,7 +230,7 @@ window.teaweb = {
|
|||||||
let axis = this.bytesAxis(stats, countFunc)
|
let axis = this.bytesAxis(stats, countFunc)
|
||||||
let unit = axis.unit
|
let unit = axis.unit
|
||||||
if (unit == "B") {
|
if (unit == "B") {
|
||||||
unit = "Bps"
|
unit = "bps"
|
||||||
} else {
|
} else {
|
||||||
unit += "bps"
|
unit += "bps"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<first-menu>
|
|
||||||
<menu-item href="/clusters/regions" code="region">区域</menu-item>
|
|
||||||
<menu-item href="/clusters/regions/prices" code="price" v-if="teaShowFinance">价格</menu-item>
|
|
||||||
<span class="item" v-if="teaShowFinance">|</span>
|
|
||||||
<menu-item v-if="teaShowFinance"><tip-icon content="可以设置节点所属区域,从而利用区域设置进行不同的价格设定。"></tip-icon></menu-item>
|
|
||||||
</first-menu>
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
{$template "menu"}
|
|
||||||
|
|
||||||
<second-menu>
|
<second-menu>
|
||||||
<menu-item @click.prevent="createRegion()">创建</menu-item>
|
<menu-item @click.prevent="createRegion()">[创建区域]</menu-item>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
|
|
||||||
<p class="comment" v-if="regions.length == 0">暂时还没有区域。</p>
|
<p class="comment" v-if="regions.length == 0">暂时还没有区域。</p>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
{$layout "layout_popup"}
|
|
||||||
|
|
||||||
<h3>添加价格项</h3>
|
|
||||||
|
|
||||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
|
||||||
<csrf-token></csrf-token>
|
|
||||||
<table class="ui table definition selectable">
|
|
||||||
<tr>
|
|
||||||
<td class="title">名称 *</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="name" maxlength="100" ref="focus"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>最低流量 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" name="bitsFrom" maxlength="16" style="width:10em" v-model="bitsFrom" autocomplete="off"/>
|
|
||||||
<span class="ui label">MBPS</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">采用1000进制<span v-if="bitsFromMB.length > 0">,相当于{{bitsFromMB}}</span>。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>最高流量 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" name="bitsTo" maxlength="16" style="width:10em" v-model="bitsTo" autocomplete="off"/>
|
|
||||||
<span class="ui label">MBPS</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">采用1000进制<span v-if="bitsToMB.length > 0">,相当于{{bitsToMB}}</span>。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<submit-btn></submit-btn>
|
|
||||||
</form>
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
Tea.context(function () {
|
|
||||||
this.bitsFrom = 0
|
|
||||||
this.bitsFromMB = ""
|
|
||||||
|
|
||||||
this.bitsTo = 0
|
|
||||||
this.bitsToMB = ""
|
|
||||||
|
|
||||||
this.$delay(function () {
|
|
||||||
let that = this
|
|
||||||
this.$watch("bitsFrom", function (v) {
|
|
||||||
this.bitsFromMB = that.formatBits(v)
|
|
||||||
})
|
|
||||||
this.$watch("bitsTo", function (v) {
|
|
||||||
this.bitsToMB = that.formatBits(v)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
this.formatBits = function (bits) {
|
|
||||||
bits = parseInt(bits)
|
|
||||||
if (isNaN(bits)) {
|
|
||||||
bits = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000) {
|
|
||||||
return bits + "MB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000) {
|
|
||||||
return (bits / 1000) + "GB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000 * 1000) {
|
|
||||||
return (bits / 1000 / 1000) + "TB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000 * 1000 * 1000) {
|
|
||||||
return (bits / 1000 / 1000 / 1000) + "PB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000 * 1000 * 1000 * 1000) {
|
|
||||||
return (bits / 1000 / 1000 / 1000 / 1000) + "EB"
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{$layout "layout_popup"}
|
|
||||||
|
|
||||||
<h3>修改价格项</h3>
|
|
||||||
|
|
||||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
|
||||||
<csrf-token></csrf-token>
|
|
||||||
<input type="hidden" name="itemId" :value="item.id"/>
|
|
||||||
<table class="ui table definition selectable">
|
|
||||||
<tr>
|
|
||||||
<td class="title">名称 *</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="name" maxlength="100" ref="focus" v-model="item.name"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>最低流量 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" name="bitsFrom" maxlength="16" style="width:10em" v-model="bitsFrom" autocomplete="off"/>
|
|
||||||
<span class="ui label">MBPS</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">采用1000进制<span v-if="bitsFromMB.length > 0">,相当于{{bitsFromMB}}</span>。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>最高流量 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" name="bitsTo" maxlength="16" style="width:10em" v-model="bitsTo" autocomplete="off"/>
|
|
||||||
<span class="ui label">MBPS</span>
|
|
||||||
</div>
|
|
||||||
<p class="comment">采用1000进制<span v-if="bitsToMB.length > 0">,相当于{{bitsToMB}}</span>。</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<submit-btn></submit-btn>
|
|
||||||
</form>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
Tea.context(function () {
|
|
||||||
this.bitsFrom = this.item.bitsFrom / 1000 / 1000
|
|
||||||
this.bitsFromMB = ""
|
|
||||||
|
|
||||||
this.bitsTo = this.item.bitsTo / 1000 / 1000
|
|
||||||
this.bitsToMB = ""
|
|
||||||
|
|
||||||
this.$delay(function () {
|
|
||||||
let that = this
|
|
||||||
this.$watch("bitsFrom", function (v) {
|
|
||||||
this.bitsFromMB = that.formatBits(v)
|
|
||||||
})
|
|
||||||
this.$watch("bitsTo", function (v) {
|
|
||||||
this.bitsToMB = that.formatBits(v)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.bitsFromMB = that.formatBits(this.bitsFrom)
|
|
||||||
this.bitsToMB = that.formatBits(this.bitsTo)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.formatBits = function (bits) {
|
|
||||||
bits = parseInt(bits)
|
|
||||||
if (isNaN(bits)) {
|
|
||||||
bits = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000) {
|
|
||||||
return bits + "MB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000) {
|
|
||||||
return (bits / 1000) + "GB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000 * 1000) {
|
|
||||||
return (bits / 1000 / 1000) + "TB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000 * 1000 * 1000) {
|
|
||||||
return (bits / 1000 / 1000 / 1000) + "PB"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits < 1000 * 1000 * 1000 * 1000 * 1000) {
|
|
||||||
return (bits / 1000 / 1000 / 1000 / 1000) + "EB"
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
th span {
|
|
||||||
font-size: 0.9em;
|
|
||||||
font-weight: normal;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
th a {
|
|
||||||
font-weight: normal;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
th:hover a {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
td a {
|
|
||||||
visibility: hidden;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
td:hover a {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
/*# sourceMappingURL=prices.css.map */
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"sources":["prices.less"],"names":[],"mappings":"AAAA,EACC;EACC,gBAAA;EACA,mBAAA;EACA,WAAA;;AAJF,EAOC;EACC,mBAAA;EACA,kBAAA;;AAIF,EAAE,MACD;EACC,mBAAA;;AAIF,EACC;EACC,kBAAA;EACA,gBAAA;;AAIF,EAAE,MACD;EACC,mBAAA","file":"prices.css"}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{$layout}
|
|
||||||
{$template "menu"}
|
|
||||||
|
|
||||||
<p class="comment" v-if="regions.length == 0">暂时还没有区域。</p>
|
|
||||||
|
|
||||||
<table class="ui table selectable small definition celled">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style="width: 7em; border-left: 1px solid rgba(34,36,38,.15); border-top: 1px solid rgba(34,36,38,.15)">区域\范围</th>
|
|
||||||
<th v-for="item in items" class="center">
|
|
||||||
{{item.name}}
|
|
||||||
<br/>
|
|
||||||
<span>{{item.bitsFromString}}-{{item.bitsToString}}</span>
|
|
||||||
<br/>
|
|
||||||
<a href="" title="修改" @click.prevent="updateItem(item.id)"><i class="icon pencil small"></i></a>
|
|
||||||
<a href="" title="删除" @click.prevent="deleteItem(item.id)"><i class="icon remove small"></i></a>
|
|
||||||
</th>
|
|
||||||
<th class="width10 center">
|
|
||||||
<a href="" @click.prevent="createItem" style="visibility: visible">[+添加价格项]</a>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr v-for="region in regions">
|
|
||||||
<td class="">{{region.name}}</td>
|
|
||||||
<td v-for="item in items" class="center">
|
|
||||||
<div>
|
|
||||||
<span v-if="region.prices[item.id.toString()] != null">¥{{region.prices[item.id.toString()]}}元/GB </span>
|
|
||||||
<span v-else> </span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="" title="修改单位价格" @click.prevent="updatePrice(region.id, item.id)">[设置]</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
Tea.context(function () {
|
|
||||||
this.createItem = function () {
|
|
||||||
teaweb.popup(Tea.url(".items.createPopup"), {
|
|
||||||
callback: function () {
|
|
||||||
teaweb.success("保存成功", function () {
|
|
||||||
teaweb.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateItem = function (itemId) {
|
|
||||||
teaweb.popup(Tea.url(".items.updatePopup", {itemId: itemId}), {
|
|
||||||
callback: function () {
|
|
||||||
teaweb.success("保存成功", function () {
|
|
||||||
teaweb.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.deleteItem = function (itemId) {
|
|
||||||
let that = this
|
|
||||||
teaweb.confirm("确定要删除此价格项吗?", function () {
|
|
||||||
that.$post(".items.delete")
|
|
||||||
.params({
|
|
||||||
itemId: itemId
|
|
||||||
})
|
|
||||||
.refresh()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updatePrice = function (regionId, itemId) {
|
|
||||||
teaweb.popup(Tea.url(".updatePricePopup", {regionId: regionId, itemId: itemId}), {
|
|
||||||
callback: function () {
|
|
||||||
teaweb.success("保存成功", function () {
|
|
||||||
teaweb.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
th {
|
|
||||||
span {
|
|
||||||
font-size: 0.9em;
|
|
||||||
font-weight: normal;
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: normal;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
th:hover {
|
|
||||||
a {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
a {
|
|
||||||
visibility: hidden;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td:hover {
|
|
||||||
a {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{$layout "layout_popup"}
|
|
||||||
|
|
||||||
<h3>修改价格</h3>
|
|
||||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
|
|
||||||
<csrf-token></csrf-token>
|
|
||||||
<input type="hidden" name="regionId" :value="region.id"/>
|
|
||||||
<input type="hidden" name="itemId" :value="item.id"/>
|
|
||||||
|
|
||||||
<table class="ui table definition selectable">
|
|
||||||
<tr>
|
|
||||||
<td class="title">区域</td>
|
|
||||||
<td>{{region.name}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>价格项</td>
|
|
||||||
<td>{{item.name}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="title">单位价格 *</td>
|
|
||||||
<td>
|
|
||||||
<div class="ui input right labeled">
|
|
||||||
<input type="text" name="price" maxlength="10" style="width:6em" ref="focus" v-model="price"/>
|
|
||||||
<span class="ui label">元/GB</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<submit-btn></submit-btn>
|
|
||||||
</form>
|
|
||||||
Reference in New Issue
Block a user