mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-09 16:50:26 +08:00
实现带宽计费套餐
This commit is contained in:
@@ -386,6 +386,10 @@ func (this *RPCClient) UserBillRPC() pb.UserBillServiceClient {
|
|||||||
return pb.NewUserBillServiceClient(this.pickConn())
|
return pb.NewUserBillServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) ServerBillRPC() pb.ServerBillServiceClient {
|
||||||
|
return pb.NewServerBillServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) UserAccountRPC() pb.UserAccountServiceClient {
|
func (this *RPCClient) UserAccountRPC() pb.UserAccountServiceClient {
|
||||||
return pb.NewUserAccountServiceClient(this.pickConn())
|
return pb.NewUserAccountServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
139
web/public/js/components/plans/plan-bandwidth-ranges.js
Normal file
139
web/public/js/components/plans/plan-bandwidth-ranges.js
Normal file
@@ -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: `<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> 价格:{{range.pricePerMB}}元/MB
|
||||||
|
<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 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>
|
||||||
|
</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,12 +1,13 @@
|
|||||||
// 套餐价格配置
|
// 套餐价格配置
|
||||||
Vue.component("plan-price-config-box", {
|
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 () {
|
data: function () {
|
||||||
let priceType = this.vPriceType
|
let priceType = this.vPriceType
|
||||||
if (priceType == null) {
|
if (priceType == null) {
|
||||||
priceType = "period"
|
priceType = "period"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按时间周期计费
|
||||||
let monthlyPriceNumber = 0
|
let monthlyPriceNumber = 0
|
||||||
let monthlyPrice = this.vMonthlyPrice
|
let monthlyPrice = this.vMonthlyPrice
|
||||||
if (monthlyPrice == null || monthlyPrice <= 0) {
|
if (monthlyPrice == null || monthlyPrice <= 0) {
|
||||||
@@ -43,6 +44,7 @@ Vue.component("plan-price-config-box", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按流量计费
|
||||||
let trafficPrice = this.vTrafficPrice
|
let trafficPrice = this.vTrafficPrice
|
||||||
let trafficPriceBaseNumber = 0
|
let trafficPriceBaseNumber = 0
|
||||||
if (trafficPrice != null) {
|
if (trafficPrice != null) {
|
||||||
@@ -57,6 +59,17 @@ Vue.component("plan-price-config-box", {
|
|||||||
trafficPriceBase = trafficPriceBaseNumber.toString()
|
trafficPriceBase = trafficPriceBaseNumber.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按带宽计费
|
||||||
|
let bandwidthPrice = this.vBandwidthPrice
|
||||||
|
if (bandwidthPrice == null) {
|
||||||
|
bandwidthPrice = {
|
||||||
|
percentile: 95,
|
||||||
|
ranges: []
|
||||||
|
}
|
||||||
|
} else if (bandwidthPrice.ranges == null) {
|
||||||
|
bandwidthPrice.ranges = []
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
priceType: priceType,
|
priceType: priceType,
|
||||||
monthlyPrice: monthlyPrice,
|
monthlyPrice: monthlyPrice,
|
||||||
@@ -68,7 +81,15 @@ Vue.component("plan-price-config-box", {
|
|||||||
yearlyPriceNumber: yearlyPriceNumber,
|
yearlyPriceNumber: yearlyPriceNumber,
|
||||||
|
|
||||||
trafficPriceBase: trafficPriceBase,
|
trafficPriceBase: trafficPriceBase,
|
||||||
trafficPrice: trafficPrice
|
trafficPrice: trafficPrice,
|
||||||
|
|
||||||
|
bandwidthPrice: bandwidthPrice,
|
||||||
|
bandwidthPercentile: bandwidthPrice.percentile
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeBandwidthPriceRanges: function (ranges) {
|
||||||
|
this.bandwidthPrice.ranges = ranges
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -99,6 +120,15 @@ Vue.component("plan-price-config-box", {
|
|||||||
price = 0
|
price = 0
|
||||||
}
|
}
|
||||||
this.trafficPrice.base = price
|
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>
|
template: `<div>
|
||||||
@@ -107,10 +137,12 @@ Vue.component("plan-price-config-box", {
|
|||||||
<input type="hidden" name="seasonallyPrice" :value="seasonallyPriceNumber"/>
|
<input type="hidden" name="seasonallyPrice" :value="seasonallyPriceNumber"/>
|
||||||
<input type="hidden" name="yearlyPrice" :value="yearlyPriceNumber"/>
|
<input type="hidden" name="yearlyPrice" :value="yearlyPriceNumber"/>
|
||||||
<input type="hidden" name="trafficPriceJSON" :value="JSON.stringify(trafficPrice)"/>
|
<input type="hidden" name="trafficPriceJSON" :value="JSON.stringify(trafficPrice)"/>
|
||||||
|
<input type="hidden" name="bandwidthPriceJSON" :value="JSON.stringify(bandwidthPrice)"/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<radio :v-value="'period'" :value="priceType" v-model="priceType"> 按时间周期</radio>
|
<radio :v-value="'period'" :value="priceType" v-model="priceType"> 按时间周期</radio>
|
||||||
<radio :v-value="'traffic'" :value="priceType" v-model="priceType"> 按流量</radio>
|
<radio :v-value="'traffic'" :value="priceType" v-model="priceType"> 按流量</radio>
|
||||||
|
<radio :v-value="'bandwidth'" :value="priceType" v-model="priceType"> 按带宽</radio>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 按时间周期 -->
|
<!-- 按时间周期 -->
|
||||||
@@ -152,7 +184,7 @@ Vue.component("plan-price-config-box", {
|
|||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<table class="ui table">
|
<table class="ui table">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">基础流量费用</td>
|
<td class="title">基础流量费用 *</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui input right labeled">
|
<div class="ui input right labeled">
|
||||||
<input type="text" v-model="trafficPriceBase" maxlength="10" style="width: 7em"/>
|
<input type="text" v-model="trafficPriceBase" maxlength="10" style="width: 7em"/>
|
||||||
@@ -162,5 +194,27 @@ Vue.component("plan-price-config-box", {
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</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>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -7,12 +7,28 @@ Vue.component("plan-price-view", {
|
|||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<span v-if="plan.priceType == 'period'">
|
<span v-if="plan.priceType == 'period'">
|
||||||
|
按时间周期计费
|
||||||
|
<div>
|
||||||
|
<span class="grey small">
|
||||||
<span v-if="plan.monthlyPrice > 0">月度:¥{{plan.monthlyPrice}}元<br/></span>
|
<span v-if="plan.monthlyPrice > 0">月度:¥{{plan.monthlyPrice}}元<br/></span>
|
||||||
<span v-if="plan.seasonallyPrice > 0">季度:¥{{plan.seasonallyPrice}}元<br/></span>
|
<span v-if="plan.seasonallyPrice > 0">季度:¥{{plan.seasonallyPrice}}元<br/></span>
|
||||||
<span v-if="plan.yearlyPrice > 0">年度:¥{{plan.yearlyPrice}}元</span>
|
<span v-if="plan.yearlyPrice > 0">年度:¥{{plan.yearlyPrice}}元</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="plan.priceType == 'traffic'">
|
</div>
|
||||||
基础价格:¥{{plan.trafficPrice.base}}元/GB
|
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="plan.priceType == 'traffic'">
|
||||||
|
按流量计费
|
||||||
|
<div>
|
||||||
|
<span class="grey small">基础价格:¥{{plan.trafficPrice.base}}元/GB</span>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<div v-if="plan.priceType == 'bandwidth' && plan.bandwidthPrice != null && plan.bandwidthPrice.percentile > 0">
|
||||||
|
按{{plan.bandwidthPrice.percentile}}th带宽计费
|
||||||
|
<div>
|
||||||
|
<div v-for="range in plan.bandwidthPrice.ranges">
|
||||||
|
<span class="small grey">{{range.minMB}} - <span v-if="range.maxMB > 0">{{range.maxMB}}MB</span><span v-else>∞</span>: {{range.pricePerMB}}元/MB</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user