mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	删除不需要的代码
This commit is contained in:
		@@ -98,10 +98,6 @@ func (this *RPCClient) NodeRegionRPC() pb.NodeRegionServiceClient {
 | 
			
		||||
	return pb.NewNodeRegionServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *RPCClient) NodePriceItemRPC() pb.NodePriceItemServiceClient {
 | 
			
		||||
	return pb.NewNodePriceItemServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *RPCClient) NodeIPAddressRPC() pb.NodeIPAddressServiceClient {
 | 
			
		||||
	return pb.NewNodeIPAddressServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
@@ -455,14 +451,6 @@ func (this *RPCClient) ServerStatBoardChartRPC() pb.ServerStatBoardChartServiceC
 | 
			
		||||
	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 {
 | 
			
		||||
	return pb.NewTrafficDailyStatServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,9 @@ package numberutils
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func FormatInt64(value int64) string {
 | 
			
		||||
@@ -28,35 +30,35 @@ func FormatBytes(bytes int64) string {
 | 
			
		||||
	if bytes < Pow1024(1) {
 | 
			
		||||
		return FormatInt64(bytes) + "B"
 | 
			
		||||
	} 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) {
 | 
			
		||||
		return fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2)))
 | 
			
		||||
		return TrimZeroSuffix(fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2))))
 | 
			
		||||
	} 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) {
 | 
			
		||||
		return fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4)))
 | 
			
		||||
		return TrimZeroSuffix(fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4))))
 | 
			
		||||
	} 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 {
 | 
			
		||||
		return fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6)))
 | 
			
		||||
		return TrimZeroSuffix(fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6))))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FormatBits(bits int64) string {
 | 
			
		||||
	if bits < Pow1024(1) {
 | 
			
		||||
		return FormatInt64(bits) + "Bps"
 | 
			
		||||
		return FormatInt64(bits) + "bps"
 | 
			
		||||
	} 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) {
 | 
			
		||||
		return fmt.Sprintf("%.4fMBps", float64(bits)/float64(Pow1024(2)))
 | 
			
		||||
		return TrimZeroSuffix(fmt.Sprintf("%.4fMbps", float64(bits)/float64(Pow1024(2))))
 | 
			
		||||
	} 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) {
 | 
			
		||||
		return fmt.Sprintf("%.4fTBps", float64(bits)/float64(Pow1024(4)))
 | 
			
		||||
		return TrimZeroSuffix(fmt.Sprintf("%.4fTbps", float64(bits)/float64(Pow1024(4))))
 | 
			
		||||
	} 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 {
 | 
			
		||||
		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 {
 | 
			
		||||
	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.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("/sort", new(SortAction)).
 | 
			
		||||
			GetPost("/selectPopup", new(SelectPopupAction)).
 | 
			
		||||
			GetPost("/prices", new(PricesAction)).
 | 
			
		||||
			GetPost("/updatePricePopup", new(UpdatePricePopupAction)).
 | 
			
		||||
			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
 | 
			
		||||
 | 
			
		||||
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{}}
 | 
			
		||||
	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
 | 
			
		||||
	this.initUserPlan(server)
 | 
			
		||||
 | 
			
		||||
	// 集群
 | 
			
		||||
	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.
 | 
			
		||||
//go:build !plus
 | 
			
		||||
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -17,33 +16,6 @@ func (this *PlansAction) RunPost(params struct {
 | 
			
		||||
	UserId   int64
 | 
			
		||||
	ServerId int64
 | 
			
		||||
}) {
 | 
			
		||||
	if !teaconst.IsPlus || params.UserId <= 0 {
 | 
			
		||||
		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.Data["plans"] = []maps.Map{}
 | 
			
		||||
	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/logs"
 | 
			
		||||
	_ "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"
 | 
			
		||||
 | 
			
		||||
	// 通用
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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) {
 | 
			
		||||
		bits = Math.ceil(bits);
 | 
			
		||||
		if (bits < Math.pow(1024, 1)) {
 | 
			
		||||
			return bits + "Bps";
 | 
			
		||||
			return bits + "bps";
 | 
			
		||||
		}
 | 
			
		||||
		if (bits < Math.pow(1024, 2)) {
 | 
			
		||||
			return (Math.round(bits * 10000 / Math.pow(1024, 1)) / 10000) + "Kbps";
 | 
			
		||||
@@ -230,7 +230,7 @@ window.teaweb = {
 | 
			
		||||
		let axis = this.bytesAxis(stats, countFunc)
 | 
			
		||||
		let unit = axis.unit
 | 
			
		||||
		if (unit == "B") {
 | 
			
		||||
			unit = "Bps"
 | 
			
		||||
			unit = "bps"
 | 
			
		||||
		} else {
 | 
			
		||||
			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}
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
 | 
			
		||||
<second-menu>
 | 
			
		||||
    <menu-item @click.prevent="createRegion()">创建</menu-item>
 | 
			
		||||
    <menu-item @click.prevent="createRegion()">[创建区域]</menu-item>
 | 
			
		||||
</second-menu>
 | 
			
		||||
 | 
			
		||||
<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