diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go
index b39278b1..ecf8e7f7 100644
--- a/internal/rpc/rpc_client.go
+++ b/internal/rpc/rpc_client.go
@@ -386,6 +386,10 @@ func (this *RPCClient) UserBillRPC() pb.UserBillServiceClient {
return pb.NewUserBillServiceClient(this.pickConn())
}
+func (this *RPCClient) ServerBillRPC() pb.ServerBillServiceClient {
+ return pb.NewServerBillServiceClient(this.pickConn())
+}
+
func (this *RPCClient) UserAccountRPC() pb.UserAccountServiceClient {
return pb.NewUserAccountServiceClient(this.pickConn())
}
diff --git a/web/public/js/components/plans/plan-bandwidth-ranges.js b/web/public/js/components/plans/plan-bandwidth-ranges.js
new file mode 100644
index 00000000..7d373136
--- /dev/null
+++ b/web/public/js/components/plans/plan-bandwidth-ranges.js
@@ -0,0 +1,139 @@
+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: "",
+ 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.ranges.push(this.addingRange)
+ this.ranges.$sort(function (v1, v2) {
+ if (v1.minMB < v2.minMB) {
+ return -1
+ }
+ if (v1.minMB == v2.minMB) {
+ 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
+ }
+ },
+ template: `
+
+
+
+ {{range.minMB}}MB -
{{range.maxMB}}MB∞ 价格:{{range.pricePerMB}}元/MB
+
+
+
+
+
+
+
+
+
+
+
+
+
`
+})
\ No newline at end of file
diff --git a/web/public/js/components/plans/plan-price-config-box.js b/web/public/js/components/plans/plan-price-config-box.js
index 8b5a87bc..f56bb39b 100644
--- a/web/public/js/components/plans/plan-price-config-box.js
+++ b/web/public/js/components/plans/plan-price-config-box.js
@@ -1,12 +1,13 @@
// 套餐价格配置
Vue.component("plan-price-config-box", {
- props: ["v-price-type", "v-monthly-price", "v-seasonally-price", "v-yearly-price", "v-traffic-price"],
+ props: ["v-price-type", "v-monthly-price", "v-seasonally-price", "v-yearly-price", "v-traffic-price", "v-bandwidth-price"],
data: function () {
let priceType = this.vPriceType
if (priceType == null) {
priceType = "period"
}
+ // 按时间周期计费
let monthlyPriceNumber = 0
let monthlyPrice = this.vMonthlyPrice
if (monthlyPrice == null || monthlyPrice <= 0) {
@@ -43,6 +44,7 @@ Vue.component("plan-price-config-box", {
}
}
+ // 按流量计费
let trafficPrice = this.vTrafficPrice
let trafficPriceBaseNumber = 0
if (trafficPrice != null) {
@@ -57,6 +59,17 @@ Vue.component("plan-price-config-box", {
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,
@@ -68,7 +81,15 @@ Vue.component("plan-price-config-box", {
yearlyPriceNumber: yearlyPriceNumber,
trafficPriceBase: trafficPriceBase,
- trafficPrice: trafficPrice
+ trafficPrice: trafficPrice,
+
+ bandwidthPrice: bandwidthPrice,
+ bandwidthPercentile: bandwidthPrice.percentile
+ }
+ },
+ methods: {
+ changeBandwidthPriceRanges: function (ranges) {
+ this.bandwidthPrice.ranges = ranges
}
},
watch: {
@@ -99,6 +120,15 @@ Vue.component("plan-price-config-box", {
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: `
@@ -107,10 +137,12 @@ Vue.component("plan-price-config-box", {
+
按时间周期
- 按流量
+ 按流量
+ 按带宽
@@ -152,7 +184,7 @@ Vue.component("plan-price-config-box", {
+
+
+
`
})
\ No newline at end of file
diff --git a/web/public/js/components/plans/plan-price-view.js b/web/public/js/components/plans/plan-price-view.js
index 58a8913b..fbc2c2b1 100644
--- a/web/public/js/components/plans/plan-price-view.js
+++ b/web/public/js/components/plans/plan-price-view.js
@@ -7,12 +7,28 @@ Vue.component("plan-price-view", {
},
template: `
- 月度:¥{{plan.monthlyPrice}}元
- 季度:¥{{plan.seasonallyPrice}}元
- 年度:¥{{plan.yearlyPrice}}元
+ 按时间周期计费
+
+
+ 月度:¥{{plan.monthlyPrice}}元
+ 季度:¥{{plan.seasonallyPrice}}元
+ 年度:¥{{plan.yearlyPrice}}元
+
+
- 基础价格:¥{{plan.trafficPrice.base}}元/GB
+ 按流量计费
+
+ 基础价格:¥{{plan.trafficPrice.base}}元/GB
+
+
+ 按{{plan.bandwidthPrice.percentile}}th带宽计费
+
+
+ {{range.minMB}} - {{range.maxMB}}MB∞: {{range.pricePerMB}}元/MB
+
+
+
`
})
\ No newline at end of file